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(">")
+ case '<':
+ dst.WriteString("<")
+ case '&':
+ dst.WriteString("&")
+ 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
+fmt.Sprintf and methods like String and Error. The flags -unusedfuncs
+and -unusedstringmethods control the set.
+
+Shifts
+
+Flag: -shift
+
+Shifts equal to or longer than the variable's length.
+
+Other flags
+
+These flags configure the behavior of vet:
+
+ -all (default true)
+ Check everything; disabled if any explicit check is requested.
+ -v
+ Verbose mode
+ -printfuncs
+ A comma-separated list of print-like functions to supplement
+ the standard list. Each entry is in the form Name:N where N
+ is the zero-based argument position of the first argument
+ involved in the print: either the format or the first print
+ argument for non-formatted prints. For example,
+ if you have Warn and Warnf functions that take an
+ io.Writer as their first argument, like Fprintf,
+ -printfuncs=Warn:1,Warnf:1
+ -shadowstrict
+ Whether to be strict about shadowing; can be noisy.
+ -test
+ For testing only: sets -all and -shadow.
+*/
+package main // import "golang.org/x/tools/cmd/vet"
diff --git a/cmd/vet/main.go b/cmd/vet/main.go
new file mode 100644
index 0000000..e4b6877
--- /dev/null
+++ b/cmd/vet/main.go
@@ -0,0 +1,488 @@
+// 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 is a simple checker for static errors in Go source code.
+// See doc.go for more information.
+package main
+
+import (
+ "bytes"
+ "flag"
+ "fmt"
+ "go/ast"
+ "go/build"
+ "go/parser"
+ "go/printer"
+ "go/token"
+ "io/ioutil"
+ "os"
+ "path/filepath"
+ "strconv"
+ "strings"
+
+ _ "golang.org/x/tools/go/gcimporter"
+ "golang.org/x/tools/go/types"
+)
+
+var (
+ verbose = flag.Bool("v", false, "verbose")
+ testFlag = flag.Bool("test", false, "for testing only: sets -all and -shadow")
+ tags = flag.String("tags", "", "comma-separated list of build tags to apply when parsing")
+ tagList = []string{} // exploded version of tags flag; set in main
+)
+
+var exitCode = 0
+
+// "all" is here only for the appearance of backwards compatibility.
+// It has no effect; the triState flags do the work.
+var all = flag.Bool("all", true, "check everything; disabled if any explicit check is requested")
+
+// Flags to control which individual checks to perform.
+var report = map[string]*triState{
+ // Only unusual checks are written here.
+ // Most checks that operate during the AST walk are added by register.
+ "asmdecl": triStateFlag("asmdecl", unset, "check assembly against Go declarations"),
+ "buildtags": triStateFlag("buildtags", unset, "check that +build tags are valid"),
+}
+
+// experimental records the flags enabling experimental features. These must be
+// requested explicitly; they are not enabled by -all.
+var experimental = map[string]bool{}
+
+// setTrueCount record how many flags are explicitly set to true.
+var setTrueCount int
+
+// A triState is a boolean that knows whether it has been set to either true or false.
+// It is used to identify if a flag appears; the standard boolean flag cannot
+// distinguish missing from unset. It also satisfies flag.Value.
+type triState int
+
+const (
+ unset triState = iota
+ setTrue
+ setFalse
+)
+
+func triStateFlag(name string, value triState, usage string) *triState {
+ flag.Var(&value, name, usage)
+ return &value
+}
+
+// triState implements flag.Value, flag.Getter, and flag.boolFlag.
+// They work like boolean flags: we can say vet -printf as well as vet -printf=true
+func (ts *triState) Get() interface{} {
+ return *ts == setTrue
+}
+
+func (ts triState) isTrue() bool {
+ return ts == setTrue
+}
+
+func (ts *triState) Set(value string) error {
+ b, err := strconv.ParseBool(value)
+ if err != nil {
+ return err
+ }
+ if b {
+ *ts = setTrue
+ setTrueCount++
+ } else {
+ *ts = setFalse
+ }
+ return nil
+}
+
+func (ts *triState) String() string {
+ switch *ts {
+ case unset:
+ return "unset"
+ case setTrue:
+ return "true"
+ case setFalse:
+ return "false"
+ }
+ panic("not reached")
+}
+
+func (ts triState) IsBoolFlag() bool {
+ return true
+}
+
+// vet tells whether to report errors for the named check, a flag name.
+func vet(name string) bool {
+ if *testFlag {
+ return true
+ }
+ return report[name].isTrue()
+}
+
+// setExit sets the value for os.Exit when it is called, later. It
+// remembers the highest value.
+func setExit(err int) {
+ if err > exitCode {
+ exitCode = err
+ }
+}
+
+var (
+ // Each of these vars has a corresponding case in (*File).Visit.
+ assignStmt *ast.AssignStmt
+ binaryExpr *ast.BinaryExpr
+ callExpr *ast.CallExpr
+ compositeLit *ast.CompositeLit
+ exprStmt *ast.ExprStmt
+ field *ast.Field
+ funcDecl *ast.FuncDecl
+ funcLit *ast.FuncLit
+ genDecl *ast.GenDecl
+ interfaceType *ast.InterfaceType
+ rangeStmt *ast.RangeStmt
+
+ // checkers is a two-level map.
+ // The outer level is keyed by a nil pointer, one of the AST vars above.
+ // The inner level is keyed by checker name.
+ checkers = make(map[ast.Node]map[string]func(*File, ast.Node))
+)
+
+func register(name, usage string, fn func(*File, ast.Node), types ...ast.Node) {
+ report[name] = triStateFlag(name, unset, usage)
+ for _, typ := range types {
+ m := checkers[typ]
+ if m == nil {
+ m = make(map[string]func(*File, ast.Node))
+ checkers[typ] = m
+ }
+ m[name] = fn
+ }
+}
+
+// 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, "\tvet [flags] directory...\n")
+ fmt.Fprintf(os.Stderr, "\tvet [flags] files... # Must be a single package\n")
+ fmt.Fprintf(os.Stderr, "For more information run\n")
+ fmt.Fprintf(os.Stderr, "\tgodoc golang.org/x/tools/cmd/vet\n\n")
+ fmt.Fprintf(os.Stderr, "Flags:\n")
+ flag.PrintDefaults()
+ os.Exit(2)
+}
+
+// File is a wrapper for the state of a file used in the parser.
+// The parse tree walkers are all methods of this type.
+type File struct {
+ pkg *Package
+ fset *token.FileSet
+ name string
+ content []byte
+ file *ast.File
+ b bytes.Buffer // for use by methods
+
+ // The objects that are receivers of a "String() string" method.
+ // This is used by the recursiveStringer method in print.go.
+ stringers map[*ast.Object]bool
+
+ // Registered checkers to run.
+ checkers map[ast.Node][]func(*File, ast.Node)
+}
+
+func main() {
+ flag.Usage = Usage
+ flag.Parse()
+
+ // If any flag is set, we run only those checks requested.
+ // If no flags are set true, set all the non-experimental ones not explicitly set (in effect, set the "-all" flag).
+ if setTrueCount == 0 {
+ for name, setting := range report {
+ if *setting == unset && !experimental[name] {
+ *setting = setTrue
+ }
+ }
+ }
+
+ tagList = strings.Split(*tags, ",")
+
+ initPrintFlags()
+ initUnusedFlags()
+
+ if flag.NArg() == 0 {
+ Usage()
+ }
+ dirs := false
+ files := false
+ for _, name := range flag.Args() {
+ // Is it a directory?
+ fi, err := os.Stat(name)
+ if err != nil {
+ warnf("error walking tree: %s", err)
+ continue
+ }
+ if fi.IsDir() {
+ dirs = true
+ } else {
+ files = true
+ }
+ }
+ if dirs && files {
+ Usage()
+ }
+ if dirs {
+ for _, name := range flag.Args() {
+ walkDir(name)
+ }
+ os.Exit(exitCode)
+ }
+ if !doPackage(".", flag.Args()) {
+ warnf("no files checked")
+ }
+ os.Exit(exitCode)
+}
+
+// prefixDirectory places the directory name on the beginning of each name in the list.
+func prefixDirectory(directory string, names []string) {
+ if directory != "." {
+ for i, name := range names {
+ names[i] = filepath.Join(directory, name)
+ }
+ }
+}
+
+// doPackageDir analyzes the single package found in the directory, if there is one,
+// plus a test package, if there is one.
+func doPackageDir(directory string) {
+ context := build.Default
+ if len(context.BuildTags) != 0 {
+ warnf("build tags %s previously set", context.BuildTags)
+ }
+ context.BuildTags = append(tagList, context.BuildTags...)
+
+ pkg, err := context.ImportDir(directory, 0)
+ if err != nil {
+ // If it's just that there are no go source files, that's fine.
+ if _, nogo := err.(*build.NoGoError); nogo {
+ return
+ }
+ // Non-fatal: we are doing a recursive walk and there may be other directories.
+ warnf("cannot process directory %s: %s", directory, err)
+ return
+ }
+ var names []string
+ names = append(names, pkg.GoFiles...)
+ names = append(names, pkg.CgoFiles...)
+ names = append(names, pkg.TestGoFiles...) // These are also in the "foo" package.
+ names = append(names, pkg.SFiles...)
+ prefixDirectory(directory, names)
+ doPackage(directory, names)
+ // Is there also a "foo_test" package? If so, do that one as well.
+ if len(pkg.XTestGoFiles) > 0 {
+ names = pkg.XTestGoFiles
+ prefixDirectory(directory, names)
+ doPackage(directory, names)
+ }
+}
+
+type Package struct {
+ path string
+ defs map[*ast.Ident]types.Object
+ uses map[*ast.Ident]types.Object
+ selectors map[*ast.SelectorExpr]*types.Selection
+ types map[ast.Expr]types.TypeAndValue
+ spans map[types.Object]Span
+ files []*File
+ typesPkg *types.Package
+}
+
+// doPackage analyzes the single package constructed from the named files.
+// It returns whether any files were checked.
+func doPackage(directory string, names []string) bool {
+ var files []*File
+ var astFiles []*ast.File
+ fs := token.NewFileSet()
+ for _, name := range names {
+ data, err := ioutil.ReadFile(name)
+ if err != nil {
+ // Warn but continue to next package.
+ warnf("%s: %s", name, err)
+ return false
+ }
+ checkBuildTag(name, data)
+ var parsedFile *ast.File
+ if strings.HasSuffix(name, ".go") {
+ parsedFile, err = parser.ParseFile(fs, name, data, 0)
+ if err != nil {
+ warnf("%s: %s", name, err)
+ return false
+ }
+ astFiles = append(astFiles, parsedFile)
+ }
+ files = append(files, &File{fset: fs, content: data, name: name, file: parsedFile})
+ }
+ if len(astFiles) == 0 {
+ return false
+ }
+ pkg := new(Package)
+ pkg.path = astFiles[0].Name.Name
+ pkg.files = files
+ // Type check the package.
+ err := pkg.check(fs, astFiles)
+ if err != nil && *verbose {
+ warnf("%s", err)
+ }
+
+ // Check.
+ chk := make(map[ast.Node][]func(*File, ast.Node))
+ for typ, set := range checkers {
+ for name, fn := range set {
+ if vet(name) {
+ chk[typ] = append(chk[typ], fn)
+ }
+ }
+ }
+ for _, file := range files {
+ file.pkg = pkg
+ file.checkers = chk
+ if file.file != nil {
+ file.walkFile(file.name, file.file)
+ }
+ }
+ asmCheck(pkg)
+ return true
+}
+
+func visit(path string, f os.FileInfo, err error) error {
+ if err != nil {
+ warnf("walk error: %s", err)
+ return err
+ }
+ // One package per directory. Ignore the files themselves.
+ if !f.IsDir() {
+ return nil
+ }
+ doPackageDir(path)
+ return nil
+}
+
+func (pkg *Package) hasFileWithSuffix(suffix string) bool {
+ for _, f := range pkg.files {
+ if strings.HasSuffix(f.name, suffix) {
+ return true
+ }
+ }
+ return false
+}
+
+// walkDir recursively walks the tree looking for Go packages.
+func walkDir(root string) {
+ filepath.Walk(root, visit)
+}
+
+// errorf formats the error to standard error, adding program
+// identification and a newline, and exits.
+func errorf(format string, args ...interface{}) {
+ fmt.Fprintf(os.Stderr, "vet: "+format+"\n", args...)
+ os.Exit(2)
+}
+
+// warnf formats the error to standard error, adding program
+// identification and a newline, but does not exit.
+func warnf(format string, args ...interface{}) {
+ fmt.Fprintf(os.Stderr, "vet: "+format+"\n", args...)
+ setExit(1)
+}
+
+// Println is fmt.Println guarded by -v.
+func Println(args ...interface{}) {
+ if !*verbose {
+ return
+ }
+ fmt.Println(args...)
+}
+
+// Printf is fmt.Printf guarded by -v.
+func Printf(format string, args ...interface{}) {
+ if !*verbose {
+ return
+ }
+ fmt.Printf(format+"\n", args...)
+}
+
+// Bad reports an error and sets the exit code..
+func (f *File) Bad(pos token.Pos, args ...interface{}) {
+ f.Warn(pos, args...)
+ setExit(1)
+}
+
+// Badf reports a formatted error and sets the exit code.
+func (f *File) Badf(pos token.Pos, format string, args ...interface{}) {
+ f.Warnf(pos, format, args...)
+ setExit(1)
+}
+
+// loc returns a formatted representation of the position.
+func (f *File) loc(pos token.Pos) string {
+ if pos == token.NoPos {
+ return ""
+ }
+ // Do not print columns. Because the pos often points to the start of an
+ // expression instead of the inner part with the actual error, the
+ // precision can mislead.
+ posn := f.fset.Position(pos)
+ return fmt.Sprintf("%s:%d: ", posn.Filename, posn.Line)
+}
+
+// Warn reports an error but does not set the exit code.
+func (f *File) Warn(pos token.Pos, args ...interface{}) {
+ fmt.Fprint(os.Stderr, f.loc(pos)+fmt.Sprintln(args...))
+}
+
+// Warnf reports a formatted error but does not set the exit code.
+func (f *File) Warnf(pos token.Pos, format string, args ...interface{}) {
+ fmt.Fprintf(os.Stderr, f.loc(pos)+format+"\n", args...)
+}
+
+// walkFile walks the file's tree.
+func (f *File) walkFile(name string, file *ast.File) {
+ Println("Checking file", name)
+ ast.Walk(f, file)
+}
+
+// Visit implements the ast.Visitor interface.
+func (f *File) Visit(node ast.Node) ast.Visitor {
+ var key ast.Node
+ switch node.(type) {
+ case *ast.AssignStmt:
+ key = assignStmt
+ case *ast.BinaryExpr:
+ key = binaryExpr
+ case *ast.CallExpr:
+ key = callExpr
+ case *ast.CompositeLit:
+ key = compositeLit
+ case *ast.ExprStmt:
+ key = exprStmt
+ case *ast.Field:
+ key = field
+ case *ast.FuncDecl:
+ key = funcDecl
+ case *ast.FuncLit:
+ key = funcLit
+ case *ast.GenDecl:
+ key = genDecl
+ case *ast.InterfaceType:
+ key = interfaceType
+ case *ast.RangeStmt:
+ key = rangeStmt
+ }
+ for _, fn := range f.checkers[key] {
+ fn(f, node)
+ }
+ return f
+}
+
+// gofmt returns a string representation of the expression.
+func (f *File) gofmt(x ast.Expr) string {
+ f.b.Reset()
+ printer.Fprint(&f.b, f.fset, x)
+ return f.b.String()
+}
diff --git a/cmd/vet/method.go b/cmd/vet/method.go
new file mode 100644
index 0000000..00949df
--- /dev/null
+++ b/cmd/vet/method.go
@@ -0,0 +1,182 @@
+// 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.
+
+// This file contains the code to check canonical methods.
+
+package main
+
+import (
+ "fmt"
+ "go/ast"
+ "go/printer"
+ "strings"
+)
+
+func init() {
+ register("methods",
+ "check that canonically named methods are canonically defined",
+ checkCanonicalMethod,
+ funcDecl, interfaceType)
+}
+
+type MethodSig struct {
+ args []string
+ results []string
+}
+
+// canonicalMethods lists the input and output types for Go methods
+// that are checked using dynamic interface checks. Because the
+// checks are dynamic, such methods would not cause a compile error
+// if they have the wrong signature: instead the dynamic check would
+// fail, sometimes mysteriously. If a method is found with a name listed
+// here but not the input/output types listed here, vet complains.
+//
+// A few of the canonical methods have very common names.
+// For example, a type might implement a Scan method that
+// has nothing to do with fmt.Scanner, but we still want to check
+// the methods that are intended to implement fmt.Scanner.
+// To do that, the arguments that have a = prefix are treated as
+// signals that the canonical meaning is intended: if a Scan
+// method doesn't have a fmt.ScanState as its first argument,
+// we let it go. But if it does have a fmt.ScanState, then the
+// rest has to match.
+var canonicalMethods = map[string]MethodSig{
+ // "Flush": {{}, {"error"}}, // http.Flusher and jpeg.writer conflict
+ "Format": {[]string{"=fmt.State", "rune"}, []string{}}, // fmt.Formatter
+ "GobDecode": {[]string{"[]byte"}, []string{"error"}}, // gob.GobDecoder
+ "GobEncode": {[]string{}, []string{"[]byte", "error"}}, // gob.GobEncoder
+ "MarshalJSON": {[]string{}, []string{"[]byte", "error"}}, // json.Marshaler
+ "MarshalXML": {[]string{"*xml.Encoder", "xml.StartElement"}, []string{"error"}}, // xml.Marshaler
+ "Peek": {[]string{"=int"}, []string{"[]byte", "error"}}, // image.reader (matching bufio.Reader)
+ "ReadByte": {[]string{}, []string{"byte", "error"}}, // io.ByteReader
+ "ReadFrom": {[]string{"=io.Reader"}, []string{"int64", "error"}}, // io.ReaderFrom
+ "ReadRune": {[]string{}, []string{"rune", "int", "error"}}, // io.RuneReader
+ "Scan": {[]string{"=fmt.ScanState", "rune"}, []string{"error"}}, // fmt.Scanner
+ "Seek": {[]string{"=int64", "int"}, []string{"int64", "error"}}, // io.Seeker
+ "UnmarshalJSON": {[]string{"[]byte"}, []string{"error"}}, // json.Unmarshaler
+ "UnmarshalXML": {[]string{"*xml.Decoder", "xml.StartElement"}, []string{"error"}}, // xml.Unmarshaler
+ "UnreadByte": {[]string{}, []string{"error"}},
+ "UnreadRune": {[]string{}, []string{"error"}},
+ "WriteByte": {[]string{"byte"}, []string{"error"}}, // jpeg.writer (matching bufio.Writer)
+ "WriteTo": {[]string{"=io.Writer"}, []string{"int64", "error"}}, // io.WriterTo
+}
+
+func checkCanonicalMethod(f *File, node ast.Node) {
+ switch n := node.(type) {
+ case *ast.FuncDecl:
+ if n.Recv != nil {
+ canonicalMethod(f, n.Name, n.Type)
+ }
+ case *ast.InterfaceType:
+ for _, field := range n.Methods.List {
+ for _, id := range field.Names {
+ canonicalMethod(f, id, field.Type.(*ast.FuncType))
+ }
+ }
+ }
+}
+
+func canonicalMethod(f *File, id *ast.Ident, t *ast.FuncType) {
+ // Expected input/output.
+ expect, ok := canonicalMethods[id.Name]
+ if !ok {
+ return
+ }
+
+ // Actual input/output
+ args := typeFlatten(t.Params.List)
+ var results []ast.Expr
+ if t.Results != nil {
+ results = typeFlatten(t.Results.List)
+ }
+
+ // Do the =s (if any) all match?
+ if !f.matchParams(expect.args, args, "=") || !f.matchParams(expect.results, results, "=") {
+ return
+ }
+
+ // Everything must match.
+ if !f.matchParams(expect.args, args, "") || !f.matchParams(expect.results, results, "") {
+ expectFmt := id.Name + "(" + argjoin(expect.args) + ")"
+ if len(expect.results) == 1 {
+ expectFmt += " " + argjoin(expect.results)
+ } else if len(expect.results) > 1 {
+ expectFmt += " (" + argjoin(expect.results) + ")"
+ }
+
+ f.b.Reset()
+ if err := printer.Fprint(&f.b, f.fset, t); err != nil {
+ fmt.Fprintf(&f.b, "<%s>", err)
+ }
+ actual := f.b.String()
+ actual = strings.TrimPrefix(actual, "func")
+ actual = id.Name + actual
+
+ f.Badf(id.Pos(), "method %s should have signature %s", actual, expectFmt)
+ }
+}
+
+func argjoin(x []string) string {
+ y := make([]string, len(x))
+ for i, s := range x {
+ if s[0] == '=' {
+ s = s[1:]
+ }
+ y[i] = s
+ }
+ return strings.Join(y, ", ")
+}
+
+// Turn parameter list into slice of types
+// (in the ast, types are Exprs).
+// Have to handle f(int, bool) and f(x, y, z int)
+// so not a simple 1-to-1 conversion.
+func typeFlatten(l []*ast.Field) []ast.Expr {
+ var t []ast.Expr
+ for _, f := range l {
+ if len(f.Names) == 0 {
+ t = append(t, f.Type)
+ continue
+ }
+ for _ = range f.Names {
+ t = append(t, f.Type)
+ }
+ }
+ return t
+}
+
+// Does each type in expect with the given prefix match the corresponding type in actual?
+func (f *File) matchParams(expect []string, actual []ast.Expr, prefix string) bool {
+ for i, x := range expect {
+ if !strings.HasPrefix(x, prefix) {
+ continue
+ }
+ if i >= len(actual) {
+ return false
+ }
+ if !f.matchParamType(x, actual[i]) {
+ return false
+ }
+ }
+ if prefix == "" && len(actual) > len(expect) {
+ return false
+ }
+ return true
+}
+
+// Does this one type match?
+func (f *File) matchParamType(expect string, actual ast.Expr) bool {
+ if strings.HasPrefix(expect, "=") {
+ expect = expect[1:]
+ }
+ // Strip package name if we're in that package.
+ if n := len(f.file.Name.Name); len(expect) > n && expect[:n] == f.file.Name.Name && expect[n] == '.' {
+ expect = expect[n+1:]
+ }
+
+ // Overkill but easy.
+ f.b.Reset()
+ printer.Fprint(&f.b, f.fset, actual)
+ return f.b.String() == expect
+}
diff --git a/cmd/vet/nilfunc.go b/cmd/vet/nilfunc.go
new file mode 100644
index 0000000..fa1bac7
--- /dev/null
+++ b/cmd/vet/nilfunc.go
@@ -0,0 +1,68 @@
+// 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 function comparisons.
+A useless comparison is one like f == nil as opposed to f() == nil.
+*/
+
+package main
+
+import (
+ "go/ast"
+ "go/token"
+
+ "golang.org/x/tools/go/types"
+)
+
+func init() {
+ register("nilfunc",
+ "check for comparisons between functions and nil",
+ checkNilFuncComparison,
+ binaryExpr)
+}
+
+func checkNilFuncComparison(f *File, node ast.Node) {
+ e := node.(*ast.BinaryExpr)
+
+ // Only want == or != comparisons.
+ if e.Op != token.EQL && e.Op != token.NEQ {
+ return
+ }
+
+ // Only want comparisons with a nil identifier on one side.
+ var e2 ast.Expr
+ switch {
+ case f.isNil(e.X):
+ e2 = e.Y
+ case f.isNil(e.Y):
+ e2 = e.X
+ default:
+ return
+ }
+
+ // Only want identifiers or selector expressions.
+ var obj types.Object
+ switch v := e2.(type) {
+ case *ast.Ident:
+ obj = f.pkg.uses[v]
+ case *ast.SelectorExpr:
+ obj = f.pkg.uses[v.Sel]
+ default:
+ return
+ }
+
+ // Only want functions.
+ if _, ok := obj.(*types.Func); !ok {
+ return
+ }
+
+ f.Badf(e.Pos(), "comparison of function %v %v nil is always %v", obj.Name(), e.Op, e.Op == token.NEQ)
+}
+
+// isNil reports whether the provided expression is the built-in nil
+// identifier.
+func (f *File) isNil(e ast.Expr) bool {
+ return f.pkg.types[e].Type == types.Typ[types.UntypedNil]
+}
diff --git a/cmd/vet/print.go b/cmd/vet/print.go
new file mode 100644
index 0000000..b20d935
--- /dev/null
+++ b/cmd/vet/print.go
@@ -0,0 +1,587 @@
+// 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.
+
+// This file contains the printf-checker.
+
+package main
+
+import (
+ "bytes"
+ "flag"
+ "go/ast"
+ "go/token"
+ "strconv"
+ "strings"
+ "unicode/utf8"
+
+ "golang.org/x/tools/go/exact"
+ "golang.org/x/tools/go/types"
+)
+
+var printfuncs = flag.String("printfuncs", "", "comma-separated list of print function names to check")
+
+func init() {
+ register("printf",
+ "check printf-like invocations",
+ checkFmtPrintfCall,
+ funcDecl, callExpr)
+}
+
+func initPrintFlags() {
+ if *printfuncs == "" {
+ return
+ }
+ for _, name := range strings.Split(*printfuncs, ",") {
+ if len(name) == 0 {
+ flag.Usage()
+ }
+ skip := 0
+ if colon := strings.LastIndex(name, ":"); colon > 0 {
+ var err error
+ skip, err = strconv.Atoi(name[colon+1:])
+ if err != nil {
+ errorf(`illegal format for "Func:N" argument %q; %s`, name, err)
+ }
+ name = name[:colon]
+ }
+ name = strings.ToLower(name)
+ if name[len(name)-1] == 'f' {
+ printfList[name] = skip
+ } else {
+ printList[name] = skip
+ }
+ }
+}
+
+// printfList records the formatted-print functions. The value is the location
+// of the format parameter. Names are lower-cased so the lookup is
+// case insensitive.
+var printfList = map[string]int{
+ "errorf": 0,
+ "fatalf": 0,
+ "fprintf": 1,
+ "logf": 0,
+ "panicf": 0,
+ "printf": 0,
+ "sprintf": 0,
+}
+
+// printList records the unformatted-print functions. The value is the location
+// of the first parameter to be printed. Names are lower-cased so the lookup is
+// case insensitive.
+var printList = map[string]int{
+ "error": 0,
+ "fatal": 0,
+ "fprint": 1, "fprintln": 1,
+ "log": 0,
+ "panic": 0, "panicln": 0,
+ "print": 0, "println": 0,
+ "sprint": 0, "sprintln": 0,
+}
+
+// checkCall triggers the print-specific checks if the call invokes a print function.
+func checkFmtPrintfCall(f *File, node ast.Node) {
+ if d, ok := node.(*ast.FuncDecl); ok && isStringer(f, d) {
+ // Remember we saw this.
+ if f.stringers == nil {
+ f.stringers = make(map[*ast.Object]bool)
+ }
+ if l := d.Recv.List; len(l) == 1 {
+ if n := l[0].Names; len(n) == 1 {
+ f.stringers[n[0].Obj] = true
+ }
+ }
+ return
+ }
+
+ call, ok := node.(*ast.CallExpr)
+ if !ok {
+ return
+ }
+ var Name string
+ switch x := call.Fun.(type) {
+ case *ast.Ident:
+ Name = x.Name
+ case *ast.SelectorExpr:
+ Name = x.Sel.Name
+ default:
+ return
+ }
+
+ name := strings.ToLower(Name)
+ if skip, ok := printfList[name]; ok {
+ f.checkPrintf(call, Name, skip)
+ return
+ }
+ if skip, ok := printList[name]; ok {
+ f.checkPrint(call, Name, skip)
+ return
+ }
+}
+
+// isStringer returns true if the provided declaration is a "String() string"
+// method, an implementation of fmt.Stringer.
+func isStringer(f *File, d *ast.FuncDecl) bool {
+ return d.Recv != nil && d.Name.Name == "String" && d.Type.Results != nil &&
+ len(d.Type.Params.List) == 0 && len(d.Type.Results.List) == 1 &&
+ f.pkg.types[d.Type.Results.List[0].Type].Type == types.Typ[types.String]
+}
+
+// formatState holds the parsed representation of a printf directive such as "%3.*[4]d".
+// It is constructed by parsePrintfVerb.
+type formatState struct {
+ verb rune // the format verb: 'd' for "%d"
+ format string // the full format directive from % through verb, "%.3d".
+ name string // Printf, Sprintf etc.
+ flags []byte // the list of # + etc.
+ argNums []int // the successive argument numbers that are consumed, adjusted to refer to actual arg in call
+ indexed bool // whether an indexing expression appears: %[1]d.
+ firstArg int // Index of first argument after the format in the Printf call.
+ // Used only during parse.
+ file *File
+ call *ast.CallExpr
+ argNum int // Which argument we're expecting to format now.
+ indexPending bool // Whether we have an indexed argument that has not resolved.
+ nbytes int // number of bytes of the format string consumed.
+}
+
+// checkPrintf checks a call to a formatted print routine such as Printf.
+// call.Args[formatIndex] is (well, should be) the format argument.
+func (f *File) checkPrintf(call *ast.CallExpr, name string, formatIndex int) {
+ if formatIndex >= len(call.Args) {
+ f.Bad(call.Pos(), "too few arguments in call to", name)
+ return
+ }
+ lit := f.pkg.types[call.Args[formatIndex]].Value
+ if lit == nil {
+ if *verbose {
+ f.Warn(call.Pos(), "can't check non-constant format in call to", name)
+ }
+ return
+ }
+ if lit.Kind() != exact.String {
+ f.Badf(call.Pos(), "constant %v not a string in call to %s", lit, name)
+ return
+ }
+ format := exact.StringVal(lit)
+ firstArg := formatIndex + 1 // Arguments are immediately after format string.
+ if !strings.Contains(format, "%") {
+ if len(call.Args) > firstArg {
+ f.Badf(call.Pos(), "no formatting directive in %s call", name)
+ }
+ return
+ }
+ // Hard part: check formats against args.
+ argNum := firstArg
+ indexed := false
+ for i, w := 0, 0; i < len(format); i += w {
+ w = 1
+ if format[i] == '%' {
+ state := f.parsePrintfVerb(call, name, format[i:], firstArg, argNum)
+ if state == nil {
+ return
+ }
+ w = len(state.format)
+ if state.indexed {
+ indexed = true
+ }
+ if !f.okPrintfArg(call, state) { // One error per format is enough.
+ return
+ }
+ if len(state.argNums) > 0 {
+ // Continue with the next sequential argument.
+ argNum = state.argNums[len(state.argNums)-1] + 1
+ }
+ }
+ }
+ // Dotdotdot is hard.
+ if call.Ellipsis.IsValid() && argNum >= len(call.Args)-1 {
+ return
+ }
+ // If the arguments were direct indexed, we assume the programmer knows what's up.
+ // Otherwise, there should be no leftover arguments.
+ if !indexed && argNum != len(call.Args) {
+ expect := argNum - firstArg
+ numArgs := len(call.Args) - firstArg
+ f.Badf(call.Pos(), "wrong number of args for format in %s call: %d needed but %d args", name, expect, numArgs)
+ }
+}
+
+// parseFlags accepts any printf flags.
+func (s *formatState) parseFlags() {
+ for s.nbytes < len(s.format) {
+ switch c := s.format[s.nbytes]; c {
+ case '#', '0', '+', '-', ' ':
+ s.flags = append(s.flags, c)
+ s.nbytes++
+ default:
+ return
+ }
+ }
+}
+
+// scanNum advances through a decimal number if present.
+func (s *formatState) scanNum() {
+ for ; s.nbytes < len(s.format); s.nbytes++ {
+ c := s.format[s.nbytes]
+ if c < '0' || '9' < c {
+ return
+ }
+ }
+}
+
+// parseIndex scans an index expression. It returns false if there is a syntax error.
+func (s *formatState) parseIndex() bool {
+ if s.nbytes == len(s.format) || s.format[s.nbytes] != '[' {
+ return true
+ }
+ // Argument index present.
+ s.indexed = true
+ s.nbytes++ // skip '['
+ start := s.nbytes
+ s.scanNum()
+ if s.nbytes == len(s.format) || s.nbytes == start || s.format[s.nbytes] != ']' {
+ s.file.Badf(s.call.Pos(), "illegal syntax for printf argument index")
+ return false
+ }
+ arg32, err := strconv.ParseInt(s.format[start:s.nbytes], 10, 32)
+ if err != nil {
+ s.file.Badf(s.call.Pos(), "illegal syntax for printf argument index: %s", err)
+ return false
+ }
+ s.nbytes++ // skip ']'
+ arg := int(arg32)
+ arg += s.firstArg - 1 // We want to zero-index the actual arguments.
+ s.argNum = arg
+ s.indexPending = true
+ return true
+}
+
+// parseNum scans a width or precision (or *). It returns false if there's a bad index expression.
+func (s *formatState) parseNum() bool {
+ if s.nbytes < len(s.format) && s.format[s.nbytes] == '*' {
+ if s.indexPending { // Absorb it.
+ s.indexPending = false
+ }
+ s.nbytes++
+ s.argNums = append(s.argNums, s.argNum)
+ s.argNum++
+ } else {
+ s.scanNum()
+ }
+ return true
+}
+
+// parsePrecision scans for a precision. It returns false if there's a bad index expression.
+func (s *formatState) parsePrecision() bool {
+ // If there's a period, there may be a precision.
+ if s.nbytes < len(s.format) && s.format[s.nbytes] == '.' {
+ s.flags = append(s.flags, '.') // Treat precision as a flag.
+ s.nbytes++
+ if !s.parseIndex() {
+ return false
+ }
+ if !s.parseNum() {
+ return false
+ }
+ }
+ return true
+}
+
+// parsePrintfVerb looks the formatting directive that begins the format string
+// and returns a formatState that encodes what the directive wants, without looking
+// at the actual arguments present in the call. The result is nil if there is an error.
+func (f *File) parsePrintfVerb(call *ast.CallExpr, name, format string, firstArg, argNum int) *formatState {
+ state := &formatState{
+ format: format,
+ name: name,
+ flags: make([]byte, 0, 5),
+ argNum: argNum,
+ argNums: make([]int, 0, 1),
+ nbytes: 1, // There's guaranteed to be a percent sign.
+ indexed: false,
+ firstArg: firstArg,
+ file: f,
+ call: call,
+ }
+ // There may be flags.
+ state.parseFlags()
+ indexPending := false
+ // There may be an index.
+ if !state.parseIndex() {
+ return nil
+ }
+ // There may be a width.
+ if !state.parseNum() {
+ return nil
+ }
+ // There may be a precision.
+ if !state.parsePrecision() {
+ return nil
+ }
+ // Now a verb, possibly prefixed by an index (which we may already have).
+ if !indexPending && !state.parseIndex() {
+ return nil
+ }
+ if state.nbytes == len(state.format) {
+ f.Badf(call.Pos(), "missing verb at end of format string in %s call", name)
+ return nil
+ }
+ verb, w := utf8.DecodeRuneInString(state.format[state.nbytes:])
+ state.verb = verb
+ state.nbytes += w
+ if verb != '%' {
+ state.argNums = append(state.argNums, state.argNum)
+ }
+ state.format = state.format[:state.nbytes]
+ return state
+}
+
+// printfArgType encodes the types of expressions a printf verb accepts. It is a bitmask.
+type printfArgType int
+
+const (
+ argBool printfArgType = 1 << iota
+ argInt
+ argRune
+ argString
+ argFloat
+ argComplex
+ argPointer
+ anyType printfArgType = ^0
+)
+
+type printVerb struct {
+ verb rune // User may provide verb through Formatter; could be a rune.
+ flags string // known flags are all ASCII
+ typ printfArgType
+}
+
+// Common flag sets for printf verbs.
+const (
+ noFlag = ""
+ numFlag = " -+.0"
+ sharpNumFlag = " -+.0#"
+ allFlags = " -+.0#"
+)
+
+// printVerbs identifies which flags are known to printf for each verb.
+// TODO: A type that implements Formatter may do what it wants, and vet
+// will complain incorrectly.
+var printVerbs = []printVerb{
+ // '-' is a width modifier, always valid.
+ // '.' is a precision for float, max width for strings.
+ // '+' is required sign for numbers, Go format for %v.
+ // '#' is alternate format for several verbs.
+ // ' ' is spacer for numbers
+ {'%', noFlag, 0},
+ {'b', numFlag, argInt | argFloat | argComplex},
+ {'c', "-", argRune | argInt},
+ {'d', numFlag, argInt},
+ {'e', numFlag, argFloat | argComplex},
+ {'E', numFlag, argFloat | argComplex},
+ {'f', numFlag, argFloat | argComplex},
+ {'F', numFlag, argFloat | argComplex},
+ {'g', numFlag, argFloat | argComplex},
+ {'G', numFlag, argFloat | argComplex},
+ {'o', sharpNumFlag, argInt},
+ {'p', "-#", argPointer},
+ {'q', " -+.0#", argRune | argInt | argString},
+ {'s', " -+.0", argString},
+ {'t', "-", argBool},
+ {'T', "-", anyType},
+ {'U', "-#", argRune | argInt},
+ {'v', allFlags, anyType},
+ {'x', sharpNumFlag, argRune | argInt | argString},
+ {'X', sharpNumFlag, argRune | argInt | argString},
+}
+
+// okPrintfArg compares the formatState to the arguments actually present,
+// reporting any discrepancies it can discern. If the final argument is ellipsissed,
+// there's little it can do for that.
+func (f *File) okPrintfArg(call *ast.CallExpr, state *formatState) (ok bool) {
+ var v printVerb
+ found := false
+ // Linear scan is fast enough for a small list.
+ for _, v = range printVerbs {
+ if v.verb == state.verb {
+ found = true
+ break
+ }
+ }
+ if !found {
+ f.Badf(call.Pos(), "unrecognized printf verb %q", state.verb)
+ return false
+ }
+ for _, flag := range state.flags {
+ if !strings.ContainsRune(v.flags, rune(flag)) {
+ f.Badf(call.Pos(), "unrecognized printf flag for verb %q: %q", state.verb, flag)
+ return false
+ }
+ }
+ // Verb is good. If len(state.argNums)>trueArgs, we have something like %.*s and all
+ // but the final arg must be an integer.
+ trueArgs := 1
+ if state.verb == '%' {
+ trueArgs = 0
+ }
+ nargs := len(state.argNums)
+ for i := 0; i < nargs-trueArgs; i++ {
+ argNum := state.argNums[i]
+ if !f.argCanBeChecked(call, i, true, state) {
+ return
+ }
+ arg := call.Args[argNum]
+ if !f.matchArgType(argInt, nil, arg) {
+ f.Badf(call.Pos(), "arg %s for * in printf format not of type int", f.gofmt(arg))
+ return false
+ }
+ }
+ if state.verb == '%' {
+ return true
+ }
+ argNum := state.argNums[len(state.argNums)-1]
+ if !f.argCanBeChecked(call, len(state.argNums)-1, false, state) {
+ return false
+ }
+ arg := call.Args[argNum]
+ if !f.matchArgType(v.typ, nil, arg) {
+ typeString := ""
+ if typ := f.pkg.types[arg].Type; typ != nil {
+ typeString = typ.String()
+ }
+ f.Badf(call.Pos(), "arg %s for printf verb %%%c of wrong type: %s", f.gofmt(arg), state.verb, typeString)
+ return false
+ }
+ if v.typ&argString != 0 && v.verb != 'T' && !bytes.Contains(state.flags, []byte{'#'}) && f.recursiveStringer(arg) {
+ f.Badf(call.Pos(), "arg %s for printf causes recursive call to String method", f.gofmt(arg))
+ return false
+ }
+ return true
+}
+
+// recursiveStringer reports whether the provided argument is r or &r for the
+// fmt.Stringer receiver identifier r.
+func (f *File) recursiveStringer(e ast.Expr) bool {
+ if len(f.stringers) == 0 {
+ return false
+ }
+ var obj *ast.Object
+ switch e := e.(type) {
+ case *ast.Ident:
+ obj = e.Obj
+ case *ast.UnaryExpr:
+ if id, ok := e.X.(*ast.Ident); ok && e.Op == token.AND {
+ obj = id.Obj
+ }
+ }
+
+ // It's unlikely to be a recursive stringer if it has a Format method.
+ if typ := f.pkg.types[e].Type; typ != nil {
+ // Not a perfect match; see issue 6259.
+ if f.hasMethod(typ, "Format") {
+ return false
+ }
+ }
+
+ // We compare the underlying Object, which checks that the identifier
+ // is the one we declared as the receiver for the String method in
+ // which this printf appears.
+ return f.stringers[obj]
+}
+
+// argCanBeChecked reports whether the specified argument is statically present;
+// it may be beyond the list of arguments or in a terminal slice... argument, which
+// means we can't see it.
+func (f *File) argCanBeChecked(call *ast.CallExpr, formatArg int, isStar bool, state *formatState) bool {
+ argNum := state.argNums[formatArg]
+ if argNum < 0 {
+ // Shouldn't happen, so catch it with prejudice.
+ panic("negative arg num")
+ }
+ if argNum == 0 {
+ f.Badf(call.Pos(), `index value [0] for %s("%s"); indexes start at 1`, state.name, state.format)
+ return false
+ }
+ if argNum < len(call.Args)-1 {
+ return true // Always OK.
+ }
+ if call.Ellipsis.IsValid() {
+ return false // We just can't tell; there could be many more arguments.
+ }
+ if argNum < len(call.Args) {
+ return true
+ }
+ // There are bad indexes in the format or there are fewer arguments than the format needs.
+ // This is the argument number relative to the format: Printf("%s", "hi") will give 1 for the "hi".
+ arg := argNum - state.firstArg + 1 // People think of arguments as 1-indexed.
+ f.Badf(call.Pos(), `missing argument for %s("%s"): format reads arg %d, have only %d args`, state.name, state.format, arg, len(call.Args)-state.firstArg)
+ return false
+}
+
+// checkPrint checks a call to an unformatted print routine such as Println.
+// call.Args[firstArg] is the first argument to be printed.
+func (f *File) checkPrint(call *ast.CallExpr, name string, firstArg int) {
+ isLn := strings.HasSuffix(name, "ln")
+ isF := strings.HasPrefix(name, "F")
+ args := call.Args
+ if name == "Log" && len(args) > 0 {
+ // Special case: Don't complain about math.Log or cmplx.Log.
+ // Not strictly necessary because the only complaint likely is for Log("%d")
+ // but it feels wrong to check that math.Log is a good print function.
+ if sel, ok := args[0].(*ast.SelectorExpr); ok {
+ if x, ok := sel.X.(*ast.Ident); ok {
+ if x.Name == "math" || x.Name == "cmplx" {
+ return
+ }
+ }
+ }
+ }
+ // check for Println(os.Stderr, ...)
+ if firstArg == 0 && !isF && len(args) > 0 {
+ if sel, ok := args[0].(*ast.SelectorExpr); ok {
+ if x, ok := sel.X.(*ast.Ident); ok {
+ if x.Name == "os" && strings.HasPrefix(sel.Sel.Name, "Std") {
+ f.Badf(call.Pos(), "first argument to %s is %s.%s", name, x.Name, sel.Sel.Name)
+ }
+ }
+ }
+ }
+ if len(args) <= firstArg {
+ // If we have a call to a method called Error that satisfies the Error interface,
+ // then it's ok. Otherwise it's something like (*T).Error from the testing package
+ // and we need to check it.
+ if name == "Error" && f.isErrorMethodCall(call) {
+ return
+ }
+ // If it's an Error call now, it's probably for printing errors.
+ if !isLn {
+ // Check the signature to be sure: there are niladic functions called "error".
+ if firstArg != 0 || f.numArgsInSignature(call) != firstArg {
+ f.Badf(call.Pos(), "no args in %s call", name)
+ }
+ }
+ return
+ }
+ arg := args[firstArg]
+ if lit, ok := arg.(*ast.BasicLit); ok && lit.Kind == token.STRING {
+ if strings.Contains(lit.Value, "%") {
+ f.Badf(call.Pos(), "possible formatting directive in %s call", name)
+ }
+ }
+ if isLn {
+ // The last item, if a string, should not have a newline.
+ arg = args[len(call.Args)-1]
+ if lit, ok := arg.(*ast.BasicLit); ok && lit.Kind == token.STRING {
+ if strings.HasSuffix(lit.Value, `\n"`) {
+ f.Badf(call.Pos(), "%s call ends with newline", name)
+ }
+ }
+ }
+ for _, arg := range args {
+ if f.recursiveStringer(arg) {
+ f.Badf(call.Pos(), "arg %s for print causes recursive call to String method", f.gofmt(arg))
+ }
+ }
+}
diff --git a/cmd/vet/rangeloop.go b/cmd/vet/rangeloop.go
new file mode 100644
index 0000000..96e2ca8
--- /dev/null
+++ b/cmd/vet/rangeloop.go
@@ -0,0 +1,70 @@
+// 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 code to check range loop variables bound inside function
+literals that are deferred or launched in new goroutines. We only check
+instances where the defer or go statement is the last statement in the loop
+body, as otherwise we would need whole program analysis.
+
+For example:
+
+ for i, v := range s {
+ go func() {
+ println(i, v) // not what you might expect
+ }()
+ }
+
+See: http://golang.org/doc/go_faq.html#closures_and_goroutines
+*/
+
+package main
+
+import "go/ast"
+
+func init() {
+ register("rangeloops",
+ "check that range loop variables are used correctly",
+ checkRangeLoop,
+ rangeStmt)
+}
+
+// checkRangeLoop walks the body of the provided range statement, checking if
+// its index or value variables are used unsafely inside goroutines or deferred
+// function literals.
+func checkRangeLoop(f *File, node ast.Node) {
+ n := node.(*ast.RangeStmt)
+ key, _ := n.Key.(*ast.Ident)
+ val, _ := n.Value.(*ast.Ident)
+ if key == nil && val == nil {
+ return
+ }
+ sl := n.Body.List
+ if len(sl) == 0 {
+ return
+ }
+ var last *ast.CallExpr
+ switch s := sl[len(sl)-1].(type) {
+ case *ast.GoStmt:
+ last = s.Call
+ case *ast.DeferStmt:
+ last = s.Call
+ default:
+ return
+ }
+ lit, ok := last.Fun.(*ast.FuncLit)
+ if !ok {
+ return
+ }
+ ast.Inspect(lit.Body, func(n ast.Node) bool {
+ id, ok := n.(*ast.Ident)
+ if !ok || id.Obj == nil {
+ return true
+ }
+ if key != nil && id.Obj == key.Obj || val != nil && id.Obj == val.Obj {
+ f.Bad(id.Pos(), "range variable", id.Name, "captured by func literal")
+ }
+ return true
+ })
+}
diff --git a/cmd/vet/shadow.go b/cmd/vet/shadow.go
new file mode 100644
index 0000000..fa680a0
--- /dev/null
+++ b/cmd/vet/shadow.go
@@ -0,0 +1,245 @@
+// 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 shadowed variables.
+A shadowed variable is a variable declared in an inner scope
+with the same name and type as a variable in an outer scope,
+and where the outer variable is mentioned after the inner one
+is declared.
+
+(This definition can be refined; the module generates too many
+false positives and is not yet enabled by default.)
+
+For example:
+
+ func BadRead(f *os.File, buf []byte) error {
+ var err error
+ for {
+ n, err := f.Read(buf) // shadows the function variable 'err'
+ if err != nil {
+ break // causes return of wrong value
+ }
+ foo(buf)
+ }
+ return err
+ }
+
+*/
+
+package main
+
+import (
+ "flag"
+ "go/ast"
+ "go/token"
+
+ "golang.org/x/tools/go/types"
+)
+
+var strictShadowing = flag.Bool("shadowstrict", false, "whether to be strict about shadowing; can be noisy")
+
+func init() {
+ register("shadow",
+ "check for shadowed variables (experimental; must be set explicitly)",
+ checkShadow,
+ assignStmt, genDecl)
+ experimental["shadow"] = true
+}
+
+func checkShadow(f *File, node ast.Node) {
+ switch n := node.(type) {
+ case *ast.AssignStmt:
+ checkShadowAssignment(f, n)
+ case *ast.GenDecl:
+ checkShadowDecl(f, n)
+ }
+}
+
+// Span stores the minimum range of byte positions in the file in which a
+// given variable (types.Object) is mentioned. It is lexically defined: it spans
+// from the beginning of its first mention to the end of its last mention.
+// A variable is considered shadowed (if *strictShadowing is off) only if the
+// shadowing variable is declared within the span of the shadowed variable.
+// In other words, if a variable is shadowed but not used after the shadowed
+// variable is declared, it is inconsequential and not worth complaining about.
+// This simple check dramatically reduces the nuisance rate for the shadowing
+// check, at least until something cleverer comes along.
+//
+// One wrinkle: A "naked return" is a silent use of a variable that the Span
+// will not capture, but the compilers catch naked returns of shadowed
+// variables so we don't need to.
+//
+// Cases this gets wrong (TODO):
+// - If a for loop's continuation statement mentions a variable redeclared in
+// the block, we should complain about it but don't.
+// - A variable declared inside a function literal can falsely be identified
+// as shadowing a variable in the outer function.
+//
+type Span struct {
+ min token.Pos
+ max token.Pos
+}
+
+// contains reports whether the position is inside the span.
+func (s Span) contains(pos token.Pos) bool {
+ return s.min <= pos && pos < s.max
+}
+
+// growSpan expands the span for the object to contain the instance represented
+// by the identifier.
+func (pkg *Package) growSpan(ident *ast.Ident, obj types.Object) {
+ if *strictShadowing {
+ return // No need
+ }
+ pos := ident.Pos()
+ end := ident.End()
+ span, ok := pkg.spans[obj]
+ if ok {
+ if span.min > pos {
+ span.min = pos
+ }
+ if span.max < end {
+ span.max = end
+ }
+ } else {
+ span = Span{pos, end}
+ }
+ pkg.spans[obj] = span
+}
+
+// checkShadowAssignment checks for shadowing in a short variable declaration.
+func checkShadowAssignment(f *File, a *ast.AssignStmt) {
+ if a.Tok != token.DEFINE {
+ return
+ }
+ if f.idiomaticShortRedecl(a) {
+ return
+ }
+ for _, expr := range a.Lhs {
+ ident, ok := expr.(*ast.Ident)
+ if !ok {
+ f.Badf(expr.Pos(), "invalid AST: short variable declaration of non-identifier")
+ return
+ }
+ checkShadowing(f, ident)
+ }
+}
+
+// idiomaticShortRedecl reports whether this short declaration can be ignored for
+// the purposes of shadowing, that is, that any redeclarations it contains are deliberate.
+func (f *File) idiomaticShortRedecl(a *ast.AssignStmt) bool {
+ // Don't complain about deliberate redeclarations of the form
+ // i := i
+ // Such constructs are idiomatic in range loops to create a new variable
+ // for each iteration. Another example is
+ // switch n := n.(type)
+ if len(a.Rhs) != len(a.Lhs) {
+ return false
+ }
+ // We know it's an assignment, so the LHS must be all identifiers. (We check anyway.)
+ for i, expr := range a.Lhs {
+ lhs, ok := expr.(*ast.Ident)
+ if !ok {
+ f.Badf(expr.Pos(), "invalid AST: short variable declaration of non-identifier")
+ return true // Don't do any more processing.
+ }
+ switch rhs := a.Rhs[i].(type) {
+ case *ast.Ident:
+ if lhs.Name != rhs.Name {
+ return false
+ }
+ case *ast.TypeAssertExpr:
+ if id, ok := rhs.X.(*ast.Ident); ok {
+ if lhs.Name != id.Name {
+ return false
+ }
+ }
+ }
+ }
+ return true
+}
+
+// idiomaticRedecl reports whether this declaration spec can be ignored for
+// the purposes of shadowing, that is, that any redeclarations it contains are deliberate.
+func (f *File) idiomaticRedecl(d *ast.ValueSpec) bool {
+ // Don't complain about deliberate redeclarations of the form
+ // var i, j = i, j
+ if len(d.Names) != len(d.Values) {
+ return false
+ }
+ for i, lhs := range d.Names {
+ if rhs, ok := d.Values[i].(*ast.Ident); ok {
+ if lhs.Name != rhs.Name {
+ return false
+ }
+ }
+ }
+ return true
+}
+
+// checkShadowDecl checks for shadowing in a general variable declaration.
+func checkShadowDecl(f *File, d *ast.GenDecl) {
+ if d.Tok != token.VAR {
+ return
+ }
+ for _, spec := range d.Specs {
+ valueSpec, ok := spec.(*ast.ValueSpec)
+ if !ok {
+ f.Badf(spec.Pos(), "invalid AST: var GenDecl not ValueSpec")
+ return
+ }
+ // Don't complain about deliberate redeclarations of the form
+ // var i = i
+ if f.idiomaticRedecl(valueSpec) {
+ return
+ }
+ for _, ident := range valueSpec.Names {
+ checkShadowing(f, ident)
+ }
+ }
+}
+
+// checkShadowing checks whether the identifier shadows an identifier in an outer scope.
+func checkShadowing(f *File, ident *ast.Ident) {
+ if ident.Name == "_" {
+ // Can't shadow the blank identifier.
+ return
+ }
+ obj := f.pkg.defs[ident]
+ if obj == nil {
+ return
+ }
+ // obj.Parent.Parent is the surrounding scope. If we can find another declaration
+ // starting from there, we have a shadowed identifier.
+ _, shadowed := obj.Parent().Parent().LookupParent(obj.Name(), obj.Pos())
+ if shadowed == nil {
+ return
+ }
+ // Don't complain if it's shadowing a universe-declared identifier; that's fine.
+ if shadowed.Parent() == types.Universe {
+ return
+ }
+ if *strictShadowing {
+ // The shadowed identifier must appear before this one to be an instance of shadowing.
+ if shadowed.Pos() > ident.Pos() {
+ return
+ }
+ } else {
+ // Don't complain if the span of validity of the shadowed identifier doesn't include
+ // the shadowing identifier.
+ span, ok := f.pkg.spans[shadowed]
+ if !ok {
+ f.Badf(ident.Pos(), "internal error: no range for %s", ident.Name)
+ return
+ }
+ if !span.contains(ident.Pos()) {
+ return
+ }
+ }
+ // Don't complain if the types differ: that implies the programmer really wants two different things.
+ if types.Identical(obj.Type(), shadowed.Type()) {
+ f.Badf(ident.Pos(), "declaration of %s shadows declaration at %s", obj.Name(), f.loc(shadowed.Pos()))
+ }
+}
diff --git a/cmd/vet/shift.go b/cmd/vet/shift.go
new file mode 100644
index 0000000..2385c23
--- /dev/null
+++ b/cmd/vet/shift.go
@@ -0,0 +1,83 @@
+// 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 the code to check for suspicious shifts.
+*/
+
+package main
+
+import (
+ "go/ast"
+ "go/token"
+
+ "golang.org/x/tools/go/exact"
+ "golang.org/x/tools/go/types"
+)
+
+func init() {
+ register("shift",
+ "check for useless shifts",
+ checkShift,
+ binaryExpr, assignStmt)
+}
+
+func checkShift(f *File, node ast.Node) {
+ switch node := node.(type) {
+ case *ast.BinaryExpr:
+ if node.Op == token.SHL || node.Op == token.SHR {
+ checkLongShift(f, node, node.X, node.Y)
+ }
+ case *ast.AssignStmt:
+ if len(node.Lhs) != 1 || len(node.Rhs) != 1 {
+ return
+ }
+ if node.Tok == token.SHL_ASSIGN || node.Tok == token.SHR_ASSIGN {
+ checkLongShift(f, node, node.Lhs[0], node.Rhs[0])
+ }
+ }
+}
+
+// checkLongShift checks if shift or shift-assign operations shift by more than
+// the length of the underlying variable.
+func checkLongShift(f *File, node ast.Node, x, y ast.Expr) {
+ v := f.pkg.types[y].Value
+ if v == nil {
+ return
+ }
+ amt, ok := exact.Int64Val(v)
+ if !ok {
+ return
+ }
+ t := f.pkg.types[x].Type
+ if t == nil {
+ return
+ }
+ b, ok := t.Underlying().(*types.Basic)
+ if !ok {
+ return
+ }
+ var size int64
+ var msg string
+ switch b.Kind() {
+ case types.Uint8, types.Int8:
+ size = 8
+ case types.Uint16, types.Int16:
+ size = 16
+ case types.Uint32, types.Int32:
+ size = 32
+ case types.Uint64, types.Int64:
+ size = 64
+ case types.Int, types.Uint, types.Uintptr:
+ // These types may be as small as 32 bits, but no smaller.
+ size = 32
+ msg = "might be "
+ default:
+ return
+ }
+ if amt >= size {
+ ident := f.gofmt(x)
+ f.Badf(node.Pos(), "%s %stoo small for shift of %d", ident, msg, amt)
+ }
+}
diff --git a/cmd/vet/structtag.go b/cmd/vet/structtag.go
new file mode 100644
index 0000000..e8164a4
--- /dev/null
+++ b/cmd/vet/structtag.go
@@ -0,0 +1,122 @@
+// 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.
+
+// This file contains the test for canonical struct tags.
+
+package main
+
+import (
+ "errors"
+ "go/ast"
+ "reflect"
+ "strconv"
+)
+
+func init() {
+ register("structtags",
+ "check that struct field tags have canonical format and apply to exported fields as needed",
+ checkCanonicalFieldTag,
+ field)
+}
+
+// checkCanonicalFieldTag checks a struct field tag.
+func checkCanonicalFieldTag(f *File, node ast.Node) {
+ field := node.(*ast.Field)
+ if field.Tag == nil {
+ return
+ }
+
+ tag, err := strconv.Unquote(field.Tag.Value)
+ if err != nil {
+ f.Badf(field.Pos(), "unable to read struct tag %s", field.Tag.Value)
+ return
+ }
+
+ if err := validateStructTag(tag); err != nil {
+ f.Badf(field.Pos(), "struct field tag %s not compatible with reflect.StructTag.Get: %s", field.Tag.Value, err)
+ }
+
+ // Check for use of json or xml tags with unexported fields.
+
+ // Embedded struct. Nothing to do for now, but that
+ // may change, depending on what happens with issue 7363.
+ if len(field.Names) == 0 {
+ return
+ }
+
+ if field.Names[0].IsExported() {
+ return
+ }
+
+ st := reflect.StructTag(tag)
+ for _, enc := range [...]string{"json", "xml"} {
+ if st.Get(enc) != "" {
+ f.Badf(field.Pos(), "struct field %s has %s tag but is not exported", field.Names[0].Name, enc)
+ return
+ }
+ }
+}
+
+var (
+ errTagSyntax = errors.New("bad syntax for struct tag pair")
+ errTagKeySyntax = errors.New("bad syntax for struct tag key")
+ errTagValueSyntax = errors.New("bad syntax for struct tag value")
+)
+
+// validateStructTag parses the struct tag and returns an error if it is not
+// in the canonical format, which is a space-separated list of key:"value"
+// settings. The value may contain spaces.
+func validateStructTag(tag string) error {
+ // This code is based on the StructTag.Get code in package reflect.
+
+ for tag != "" {
+ // Skip leading space.
+ i := 0
+ for i < len(tag) && tag[i] == ' ' {
+ i++
+ }
+ tag = tag[i:]
+ if tag == "" {
+ break
+ }
+
+ // Scan to colon. A space, a quote or a control character is a syntax error.
+ // Strictly speaking, control chars include the range [0x7f, 0x9f], not just
+ // [0x00, 0x1f], but in practice, we ignore the multi-byte control characters
+ // as it is simpler to inspect the tag's bytes than the tag's runes.
+ i = 0
+ for i < len(tag) && tag[i] > ' ' && tag[i] != ':' && tag[i] != '"' && tag[i] != 0x7f {
+ i++
+ }
+ if i == 0 {
+ return errTagKeySyntax
+ }
+ if i+1 >= len(tag) || tag[i] != ':' {
+ return errTagSyntax
+ }
+ if tag[i+1] != '"' {
+ return errTagValueSyntax
+ }
+ tag = tag[i+1:]
+
+ // Scan quoted string to find value.
+ i = 1
+ for i < len(tag) && tag[i] != '"' {
+ if tag[i] == '\\' {
+ i++
+ }
+ i++
+ }
+ if i >= len(tag) {
+ return errTagValueSyntax
+ }
+ qvalue := string(tag[:i+1])
+ tag = tag[i+1:]
+
+ if _, err := strconv.Unquote(qvalue); err != nil {
+ return errTagValueSyntax
+ }
+ }
+ return nil
+}
diff --git a/cmd/vet/testdata/asm.go b/cmd/vet/testdata/asm.go
new file mode 100644
index 0000000..9a3d531
--- /dev/null
+++ b/cmd/vet/testdata/asm.go
@@ -0,0 +1,33 @@
+// 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.
+
+// +build ignore
+
+// This file contains declarations to test the assembly in test_asm.s.
+
+package testdata
+
+func arg1(x int8, y uint8)
+func arg2(x int16, y uint16)
+func arg4(x int32, y uint32)
+func arg8(x int64, y uint64)
+func argint(x int, y uint)
+func argptr(x *byte, y *byte, c chan int, m map[int]int, f func())
+func argstring(x, y string)
+func argslice(x, y []string)
+func argiface(x interface{}, y interface {
+ m()
+})
+func returnint() int
+func returnbyte(x int) byte
+func returnnamed(x byte) (r1 int, r2 int16, r3 string, r4 byte)
+func returnintmissing() int
+func leaf(x, y int) int
+
+func noprof(x int)
+func dupok(x int)
+func nosplit(x int)
+func rodata(x int)
+func noptr(x int)
+func wrapper(x int)
diff --git a/cmd/vet/testdata/asm1.s b/cmd/vet/testdata/asm1.s
new file mode 100644
index 0000000..62f423c
--- /dev/null
+++ b/cmd/vet/testdata/asm1.s
@@ -0,0 +1,254 @@
+// 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 amd64
+// +build vet_test
+
+TEXT ·arg1(SB),0,$0-2
+ MOVB x+0(FP), AX
+ // MOVB x+0(FP), AX // commented out instructions used to panic
+ MOVB y+1(FP), BX
+ MOVW x+0(FP), AX // ERROR "\[amd64\] arg1: invalid MOVW of x\+0\(FP\); int8 is 1-byte value"
+ MOVW y+1(FP), AX // ERROR "invalid MOVW of y\+1\(FP\); uint8 is 1-byte value"
+ MOVL x+0(FP), AX // ERROR "invalid MOVL of x\+0\(FP\); int8 is 1-byte value"
+ MOVL y+1(FP), AX // ERROR "invalid MOVL of y\+1\(FP\); uint8 is 1-byte value"
+ MOVQ x+0(FP), AX // ERROR "invalid MOVQ of x\+0\(FP\); int8 is 1-byte value"
+ MOVQ y+1(FP), AX // ERROR "invalid MOVQ of y\+1\(FP\); uint8 is 1-byte value"
+ MOVB x+1(FP), AX // ERROR "invalid offset x\+1\(FP\); expected x\+0\(FP\)"
+ MOVB y+2(FP), AX // ERROR "invalid offset y\+2\(FP\); expected y\+1\(FP\)"
+ TESTB x+0(FP), AX
+ TESTB y+1(FP), BX
+ TESTW x+0(FP), AX // ERROR "invalid TESTW of x\+0\(FP\); int8 is 1-byte value"
+ TESTW y+1(FP), AX // ERROR "invalid TESTW of y\+1\(FP\); uint8 is 1-byte value"
+ TESTL x+0(FP), AX // ERROR "invalid TESTL of x\+0\(FP\); int8 is 1-byte value"
+ TESTL y+1(FP), AX // ERROR "invalid TESTL of y\+1\(FP\); uint8 is 1-byte value"
+ TESTQ x+0(FP), AX // ERROR "invalid TESTQ of x\+0\(FP\); int8 is 1-byte value"
+ TESTQ y+1(FP), AX // ERROR "invalid TESTQ of y\+1\(FP\); uint8 is 1-byte value"
+ TESTB x+1(FP), AX // ERROR "invalid offset x\+1\(FP\); expected x\+0\(FP\)"
+ TESTB y+2(FP), AX // ERROR "invalid offset y\+2\(FP\); expected y\+1\(FP\)"
+ MOVB 8(SP), AX // ERROR "8\(SP\) should be x\+0\(FP\)"
+ MOVB 9(SP), AX // ERROR "9\(SP\) should be y\+1\(FP\)"
+ MOVB 10(SP), AX // ERROR "use of 10\(SP\) points beyond argument frame"
+ RET
+
+TEXT ·arg2(SB),0,$0-4
+ MOVB x+0(FP), AX // ERROR "arg2: invalid MOVB of x\+0\(FP\); int16 is 2-byte value"
+ MOVB y+2(FP), AX // ERROR "invalid MOVB of y\+2\(FP\); uint16 is 2-byte value"
+ MOVW x+0(FP), AX
+ MOVW y+2(FP), BX
+ MOVL x+0(FP), AX // ERROR "invalid MOVL of x\+0\(FP\); int16 is 2-byte value"
+ MOVL y+2(FP), AX // ERROR "invalid MOVL of y\+2\(FP\); uint16 is 2-byte value"
+ MOVQ x+0(FP), AX // ERROR "invalid MOVQ of x\+0\(FP\); int16 is 2-byte value"
+ MOVQ y+2(FP), AX // ERROR "invalid MOVQ of y\+2\(FP\); uint16 is 2-byte value"
+ MOVW x+2(FP), AX // ERROR "invalid offset x\+2\(FP\); expected x\+0\(FP\)"
+ MOVW y+0(FP), AX // ERROR "invalid offset y\+0\(FP\); expected y\+2\(FP\)"
+ TESTB x+0(FP), AX // ERROR "invalid TESTB of x\+0\(FP\); int16 is 2-byte value"
+ TESTB y+2(FP), AX // ERROR "invalid TESTB of y\+2\(FP\); uint16 is 2-byte value"
+ TESTW x+0(FP), AX
+ TESTW y+2(FP), BX
+ TESTL x+0(FP), AX // ERROR "invalid TESTL of x\+0\(FP\); int16 is 2-byte value"
+ TESTL y+2(FP), AX // ERROR "invalid TESTL of y\+2\(FP\); uint16 is 2-byte value"
+ TESTQ x+0(FP), AX // ERROR "invalid TESTQ of x\+0\(FP\); int16 is 2-byte value"
+ TESTQ y+2(FP), AX // ERROR "invalid TESTQ of y\+2\(FP\); uint16 is 2-byte value"
+ TESTW x+2(FP), AX // ERROR "invalid offset x\+2\(FP\); expected x\+0\(FP\)"
+ TESTW y+0(FP), AX // ERROR "invalid offset y\+0\(FP\); expected y\+2\(FP\)"
+ RET
+
+TEXT ·arg4(SB),0,$0-2 // ERROR "arg4: wrong argument size 2; expected \$\.\.\.-8"
+ MOVB x+0(FP), AX // ERROR "invalid MOVB of x\+0\(FP\); int32 is 4-byte value"
+ MOVB y+4(FP), BX // ERROR "invalid MOVB of y\+4\(FP\); uint32 is 4-byte value"
+ MOVW x+0(FP), AX // ERROR "invalid MOVW of x\+0\(FP\); int32 is 4-byte value"
+ MOVW y+4(FP), AX // ERROR "invalid MOVW of y\+4\(FP\); uint32 is 4-byte value"
+ MOVL x+0(FP), AX
+ MOVL y+4(FP), AX
+ MOVQ x+0(FP), AX // ERROR "invalid MOVQ of x\+0\(FP\); int32 is 4-byte value"
+ MOVQ y+4(FP), AX // ERROR "invalid MOVQ of y\+4\(FP\); uint32 is 4-byte value"
+ MOVL x+4(FP), AX // ERROR "invalid offset x\+4\(FP\); expected x\+0\(FP\)"
+ MOVL y+2(FP), AX // ERROR "invalid offset y\+2\(FP\); expected y\+4\(FP\)"
+ TESTB x+0(FP), AX // ERROR "invalid TESTB of x\+0\(FP\); int32 is 4-byte value"
+ TESTB y+4(FP), BX // ERROR "invalid TESTB of y\+4\(FP\); uint32 is 4-byte value"
+ TESTW x+0(FP), AX // ERROR "invalid TESTW of x\+0\(FP\); int32 is 4-byte value"
+ TESTW y+4(FP), AX // ERROR "invalid TESTW of y\+4\(FP\); uint32 is 4-byte value"
+ TESTL x+0(FP), AX
+ TESTL y+4(FP), AX
+ TESTQ x+0(FP), AX // ERROR "invalid TESTQ of x\+0\(FP\); int32 is 4-byte value"
+ TESTQ y+4(FP), AX // ERROR "invalid TESTQ of y\+4\(FP\); uint32 is 4-byte value"
+ TESTL x+4(FP), AX // ERROR "invalid offset x\+4\(FP\); expected x\+0\(FP\)"
+ TESTL y+2(FP), AX // ERROR "invalid offset y\+2\(FP\); expected y\+4\(FP\)"
+ RET
+
+TEXT ·arg8(SB),7,$0-2 // ERROR "wrong argument size 2; expected \$\.\.\.-16"
+ MOVB x+0(FP), AX // ERROR "invalid MOVB of x\+0\(FP\); int64 is 8-byte value"
+ MOVB y+8(FP), BX // ERROR "invalid MOVB of y\+8\(FP\); uint64 is 8-byte value"
+ MOVW x+0(FP), AX // ERROR "invalid MOVW of x\+0\(FP\); int64 is 8-byte value"
+ MOVW y+8(FP), AX // ERROR "invalid MOVW of y\+8\(FP\); uint64 is 8-byte value"
+ MOVL x+0(FP), AX // ERROR "invalid MOVL of x\+0\(FP\); int64 is 8-byte value"
+ MOVL y+8(FP), AX // ERROR "invalid MOVL of y\+8\(FP\); uint64 is 8-byte value"
+ MOVQ x+0(FP), AX
+ MOVQ y+8(FP), AX
+ MOVQ x+8(FP), AX // ERROR "invalid offset x\+8\(FP\); expected x\+0\(FP\)"
+ MOVQ y+2(FP), AX // ERROR "invalid offset y\+2\(FP\); expected y\+8\(FP\)"
+ TESTB x+0(FP), AX // ERROR "invalid TESTB of x\+0\(FP\); int64 is 8-byte value"
+ TESTB y+8(FP), BX // ERROR "invalid TESTB of y\+8\(FP\); uint64 is 8-byte value"
+ TESTW x+0(FP), AX // ERROR "invalid TESTW of x\+0\(FP\); int64 is 8-byte value"
+ TESTW y+8(FP), AX // ERROR "invalid TESTW of y\+8\(FP\); uint64 is 8-byte value"
+ TESTL x+0(FP), AX // ERROR "invalid TESTL of x\+0\(FP\); int64 is 8-byte value"
+ TESTL y+8(FP), AX // ERROR "invalid TESTL of y\+8\(FP\); uint64 is 8-byte value"
+ TESTQ x+0(FP), AX
+ TESTQ y+8(FP), AX
+ TESTQ x+8(FP), AX // ERROR "invalid offset x\+8\(FP\); expected x\+0\(FP\)"
+ TESTQ y+2(FP), AX // ERROR "invalid offset y\+2\(FP\); expected y\+8\(FP\)"
+ RET
+
+TEXT ·argint(SB),0,$0-2 // ERROR "wrong argument size 2; expected \$\.\.\.-16"
+ MOVB x+0(FP), AX // ERROR "invalid MOVB of x\+0\(FP\); int is 8-byte value"
+ MOVB y+8(FP), BX // ERROR "invalid MOVB of y\+8\(FP\); uint is 8-byte value"
+ MOVW x+0(FP), AX // ERROR "invalid MOVW of x\+0\(FP\); int is 8-byte value"
+ MOVW y+8(FP), AX // ERROR "invalid MOVW of y\+8\(FP\); uint is 8-byte value"
+ MOVL x+0(FP), AX // ERROR "invalid MOVL of x\+0\(FP\); int is 8-byte value"
+ MOVL y+8(FP), AX // ERROR "invalid MOVL of y\+8\(FP\); uint is 8-byte value"
+ MOVQ x+0(FP), AX
+ MOVQ y+8(FP), AX
+ MOVQ x+8(FP), AX // ERROR "invalid offset x\+8\(FP\); expected x\+0\(FP\)"
+ MOVQ y+2(FP), AX // ERROR "invalid offset y\+2\(FP\); expected y\+8\(FP\)"
+ TESTB x+0(FP), AX // ERROR "invalid TESTB of x\+0\(FP\); int is 8-byte value"
+ TESTB y+8(FP), BX // ERROR "invalid TESTB of y\+8\(FP\); uint is 8-byte value"
+ TESTW x+0(FP), AX // ERROR "invalid TESTW of x\+0\(FP\); int is 8-byte value"
+ TESTW y+8(FP), AX // ERROR "invalid TESTW of y\+8\(FP\); uint is 8-byte value"
+ TESTL x+0(FP), AX // ERROR "invalid TESTL of x\+0\(FP\); int is 8-byte value"
+ TESTL y+8(FP), AX // ERROR "invalid TESTL of y\+8\(FP\); uint is 8-byte value"
+ TESTQ x+0(FP), AX
+ TESTQ y+8(FP), AX
+ TESTQ x+8(FP), AX // ERROR "invalid offset x\+8\(FP\); expected x\+0\(FP\)"
+ TESTQ y+2(FP), AX // ERROR "invalid offset y\+2\(FP\); expected y\+8\(FP\)"
+ RET
+
+TEXT ·argptr(SB),7,$0-2 // ERROR "wrong argument size 2; expected \$\.\.\.-40"
+ MOVB x+0(FP), AX // ERROR "invalid MOVB of x\+0\(FP\); \*byte is 8-byte value"
+ MOVB y+8(FP), BX // ERROR "invalid MOVB of y\+8\(FP\); \*byte is 8-byte value"
+ MOVW x+0(FP), AX // ERROR "invalid MOVW of x\+0\(FP\); \*byte is 8-byte value"
+ MOVW y+8(FP), AX // ERROR "invalid MOVW of y\+8\(FP\); \*byte is 8-byte value"
+ MOVL x+0(FP), AX // ERROR "invalid MOVL of x\+0\(FP\); \*byte is 8-byte value"
+ MOVL y+8(FP), AX // ERROR "invalid MOVL of y\+8\(FP\); \*byte is 8-byte value"
+ MOVQ x+0(FP), AX
+ MOVQ y+8(FP), AX
+ MOVQ x+8(FP), AX // ERROR "invalid offset x\+8\(FP\); expected x\+0\(FP\)"
+ MOVQ y+2(FP), AX // ERROR "invalid offset y\+2\(FP\); expected y\+8\(FP\)"
+ TESTB x+0(FP), AX // ERROR "invalid TESTB of x\+0\(FP\); \*byte is 8-byte value"
+ TESTB y+8(FP), BX // ERROR "invalid TESTB of y\+8\(FP\); \*byte is 8-byte value"
+ TESTW x+0(FP), AX // ERROR "invalid TESTW of x\+0\(FP\); \*byte is 8-byte value"
+ TESTW y+8(FP), AX // ERROR "invalid TESTW of y\+8\(FP\); \*byte is 8-byte value"
+ TESTL x+0(FP), AX // ERROR "invalid TESTL of x\+0\(FP\); \*byte is 8-byte value"
+ TESTL y+8(FP), AX // ERROR "invalid TESTL of y\+8\(FP\); \*byte is 8-byte value"
+ TESTQ x+0(FP), AX
+ TESTQ y+8(FP), AX
+ TESTQ x+8(FP), AX // ERROR "invalid offset x\+8\(FP\); expected x\+0\(FP\)"
+ TESTQ y+2(FP), AX // ERROR "invalid offset y\+2\(FP\); expected y\+8\(FP\)"
+ MOVL c+16(FP), AX // ERROR "invalid MOVL of c\+16\(FP\); chan int is 8-byte value"
+ MOVL m+24(FP), AX // ERROR "invalid MOVL of m\+24\(FP\); map\[int\]int is 8-byte value"
+ MOVL f+32(FP), AX // ERROR "invalid MOVL of f\+32\(FP\); func\(\) is 8-byte value"
+ RET
+
+TEXT ·argstring(SB),0,$32 // ERROR "wrong argument size 0; expected \$\.\.\.-32"
+ MOVW x+0(FP), AX // ERROR "invalid MOVW of x\+0\(FP\); string base is 8-byte value"
+ MOVL x+0(FP), AX // ERROR "invalid MOVL of x\+0\(FP\); string base is 8-byte value"
+ MOVQ x+0(FP), AX
+ MOVW x_base+0(FP), AX // ERROR "invalid MOVW of x_base\+0\(FP\); string base is 8-byte value"
+ MOVL x_base+0(FP), AX // ERROR "invalid MOVL of x_base\+0\(FP\); string base is 8-byte value"
+ MOVQ x_base+0(FP), AX
+ MOVW x_len+0(FP), AX // ERROR "invalid offset x_len\+0\(FP\); expected x_len\+8\(FP\)"
+ MOVL x_len+0(FP), AX // ERROR "invalid offset x_len\+0\(FP\); expected x_len\+8\(FP\)"
+ MOVQ x_len+0(FP), AX // ERROR "invalid offset x_len\+0\(FP\); expected x_len\+8\(FP\)"
+ MOVW x_len+8(FP), AX // ERROR "invalid MOVW of x_len\+8\(FP\); string len is 8-byte value"
+ MOVL x_len+8(FP), AX // ERROR "invalid MOVL of x_len\+8\(FP\); string len is 8-byte value"
+ MOVQ x_len+8(FP), AX
+ MOVQ y+0(FP), AX // ERROR "invalid offset y\+0\(FP\); expected y\+16\(FP\)"
+ MOVQ y_len+8(FP), AX // ERROR "invalid offset y_len\+8\(FP\); expected y_len\+24\(FP\)"
+ RET
+
+TEXT ·argslice(SB),0,$48 // ERROR "wrong argument size 0; expected \$\.\.\.-48"
+ MOVW x+0(FP), AX // ERROR "invalid MOVW of x\+0\(FP\); slice base is 8-byte value"
+ MOVL x+0(FP), AX // ERROR "invalid MOVL of x\+0\(FP\); slice base is 8-byte value"
+ MOVQ x+0(FP), AX
+ MOVW x_base+0(FP), AX // ERROR "invalid MOVW of x_base\+0\(FP\); slice base is 8-byte value"
+ MOVL x_base+0(FP), AX // ERROR "invalid MOVL of x_base\+0\(FP\); slice base is 8-byte value"
+ MOVQ x_base+0(FP), AX
+ MOVW x_len+0(FP), AX // ERROR "invalid offset x_len\+0\(FP\); expected x_len\+8\(FP\)"
+ MOVL x_len+0(FP), AX // ERROR "invalid offset x_len\+0\(FP\); expected x_len\+8\(FP\)"
+ MOVQ x_len+0(FP), AX // ERROR "invalid offset x_len\+0\(FP\); expected x_len\+8\(FP\)"
+ MOVW x_len+8(FP), AX // ERROR "invalid MOVW of x_len\+8\(FP\); slice len is 8-byte value"
+ MOVL x_len+8(FP), AX // ERROR "invalid MOVL of x_len\+8\(FP\); slice len is 8-byte value"
+ MOVQ x_len+8(FP), AX
+ MOVW x_cap+0(FP), AX // ERROR "invalid offset x_cap\+0\(FP\); expected x_cap\+16\(FP\)"
+ MOVL x_cap+0(FP), AX // ERROR "invalid offset x_cap\+0\(FP\); expected x_cap\+16\(FP\)"
+ MOVQ x_cap+0(FP), AX // ERROR "invalid offset x_cap\+0\(FP\); expected x_cap\+16\(FP\)"
+ MOVW x_cap+16(FP), AX // ERROR "invalid MOVW of x_cap\+16\(FP\); slice cap is 8-byte value"
+ MOVL x_cap+16(FP), AX // ERROR "invalid MOVL of x_cap\+16\(FP\); slice cap is 8-byte value"
+ MOVQ x_cap+16(FP), AX
+ MOVQ y+0(FP), AX // ERROR "invalid offset y\+0\(FP\); expected y\+24\(FP\)"
+ MOVQ y_len+8(FP), AX // ERROR "invalid offset y_len\+8\(FP\); expected y_len\+32\(FP\)"
+ MOVQ y_cap+16(FP), AX // ERROR "invalid offset y_cap\+16\(FP\); expected y_cap\+40\(FP\)"
+ RET
+
+TEXT ·argiface(SB),0,$0-32
+ MOVW x+0(FP), AX // ERROR "invalid MOVW of x\+0\(FP\); interface type is 8-byte value"
+ MOVL x+0(FP), AX // ERROR "invalid MOVL of x\+0\(FP\); interface type is 8-byte value"
+ MOVQ x+0(FP), AX
+ MOVW x_type+0(FP), AX // ERROR "invalid MOVW of x_type\+0\(FP\); interface type is 8-byte value"
+ MOVL x_type+0(FP), AX // ERROR "invalid MOVL of x_type\+0\(FP\); interface type is 8-byte value"
+ MOVQ x_type+0(FP), AX
+ MOVQ x_itable+0(FP), AX // ERROR "unknown variable x_itable; offset 0 is x_type\+0\(FP\)"
+ MOVQ x_itable+1(FP), AX // ERROR "unknown variable x_itable; offset 1 is x_type\+0\(FP\)"
+ MOVW x_data+0(FP), AX // ERROR "invalid offset x_data\+0\(FP\); expected x_data\+8\(FP\)"
+ MOVL x_data+0(FP), AX // ERROR "invalid offset x_data\+0\(FP\); expected x_data\+8\(FP\)"
+ MOVQ x_data+0(FP), AX // ERROR "invalid offset x_data\+0\(FP\); expected x_data\+8\(FP\)"
+ MOVW x_data+8(FP), AX // ERROR "invalid MOVW of x_data\+8\(FP\); interface data is 8-byte value"
+ MOVL x_data+8(FP), AX // ERROR "invalid MOVL of x_data\+8\(FP\); interface data is 8-byte value"
+ MOVQ x_data+8(FP), AX
+ MOVW y+16(FP), AX // ERROR "invalid MOVW of y\+16\(FP\); interface itable is 8-byte value"
+ MOVL y+16(FP), AX // ERROR "invalid MOVL of y\+16\(FP\); interface itable is 8-byte value"
+ MOVQ y+16(FP), AX
+ MOVW y_itable+16(FP), AX // ERROR "invalid MOVW of y_itable\+16\(FP\); interface itable is 8-byte value"
+ MOVL y_itable+16(FP), AX // ERROR "invalid MOVL of y_itable\+16\(FP\); interface itable is 8-byte value"
+ MOVQ y_itable+16(FP), AX
+ MOVQ y_type+16(FP), AX // ERROR "unknown variable y_type; offset 16 is y_itable\+16\(FP\)"
+ MOVW y_data+16(FP), AX // ERROR "invalid offset y_data\+16\(FP\); expected y_data\+24\(FP\)"
+ MOVL y_data+16(FP), AX // ERROR "invalid offset y_data\+16\(FP\); expected y_data\+24\(FP\)"
+ MOVQ y_data+16(FP), AX // ERROR "invalid offset y_data\+16\(FP\); expected y_data\+24\(FP\)"
+ MOVW y_data+24(FP), AX // ERROR "invalid MOVW of y_data\+24\(FP\); interface data is 8-byte value"
+ MOVL y_data+24(FP), AX // ERROR "invalid MOVL of y_data\+24\(FP\); interface data is 8-byte value"
+ MOVQ y_data+24(FP), AX
+ RET
+
+TEXT ·returnint(SB),0,$0-8
+ MOVB AX, ret+0(FP) // ERROR "invalid MOVB of ret\+0\(FP\); int is 8-byte value"
+ MOVW AX, ret+0(FP) // ERROR "invalid MOVW of ret\+0\(FP\); int is 8-byte value"
+ MOVL AX, ret+0(FP) // ERROR "invalid MOVL of ret\+0\(FP\); int is 8-byte value"
+ MOVQ AX, ret+0(FP)
+ MOVQ AX, ret+1(FP) // ERROR "invalid offset ret\+1\(FP\); expected ret\+0\(FP\)"
+ MOVQ AX, r+0(FP) // ERROR "unknown variable r; offset 0 is ret\+0\(FP\)"
+ RET
+
+TEXT ·returnbyte(SB),0,$0-9
+ MOVQ x+0(FP), AX
+ MOVB AX, ret+8(FP)
+ MOVW AX, ret+8(FP) // ERROR "invalid MOVW of ret\+8\(FP\); byte is 1-byte value"
+ MOVL AX, ret+8(FP) // ERROR "invalid MOVL of ret\+8\(FP\); byte is 1-byte value"
+ MOVQ AX, ret+8(FP) // ERROR "invalid MOVQ of ret\+8\(FP\); byte is 1-byte value"
+ MOVB AX, ret+7(FP) // ERROR "invalid offset ret\+7\(FP\); expected ret\+8\(FP\)"
+ RET
+
+TEXT ·returnnamed(SB),0,$0-41
+ MOVB x+0(FP), AX
+ MOVQ AX, r1+8(FP)
+ MOVW AX, r2+16(FP)
+ MOVQ AX, r3+24(FP)
+ MOVQ AX, r3_base+24(FP)
+ MOVQ AX, r3_len+32(FP)
+ MOVB AX, r4+40(FP)
+ MOVL AX, r1+8(FP) // ERROR "invalid MOVL of r1\+8\(FP\); int is 8-byte value"
+ RET
+
+TEXT ·returnintmissing(SB),0,$0-8
+ RET // ERROR "RET without writing to 8-byte ret\+0\(FP\)"
diff --git a/cmd/vet/testdata/asm2.s b/cmd/vet/testdata/asm2.s
new file mode 100644
index 0000000..c33c02a
--- /dev/null
+++ b/cmd/vet/testdata/asm2.s
@@ -0,0 +1,257 @@
+// 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 386
+// +build vet_test
+
+TEXT ·arg1(SB),0,$0-2
+ MOVB x+0(FP), AX
+ MOVB y+1(FP), BX
+ MOVW x+0(FP), AX // ERROR "\[386\] arg1: invalid MOVW of x\+0\(FP\); int8 is 1-byte value"
+ MOVW y+1(FP), AX // ERROR "invalid MOVW of y\+1\(FP\); uint8 is 1-byte value"
+ MOVL x+0(FP), AX // ERROR "invalid MOVL of x\+0\(FP\); int8 is 1-byte value"
+ MOVL y+1(FP), AX // ERROR "invalid MOVL of y\+1\(FP\); uint8 is 1-byte value"
+ MOVQ x+0(FP), AX // ERROR "invalid MOVQ of x\+0\(FP\); int8 is 1-byte value"
+ MOVQ y+1(FP), AX // ERROR "invalid MOVQ of y\+1\(FP\); uint8 is 1-byte value"
+ MOVB x+1(FP), AX // ERROR "invalid offset x\+1\(FP\); expected x\+0\(FP\)"
+ MOVB y+2(FP), AX // ERROR "invalid offset y\+2\(FP\); expected y\+1\(FP\)"
+ TESTB x+0(FP), AX
+ TESTB y+1(FP), BX
+ TESTW x+0(FP), AX // ERROR "invalid TESTW of x\+0\(FP\); int8 is 1-byte value"
+ TESTW y+1(FP), AX // ERROR "invalid TESTW of y\+1\(FP\); uint8 is 1-byte value"
+ TESTL x+0(FP), AX // ERROR "invalid TESTL of x\+0\(FP\); int8 is 1-byte value"
+ TESTL y+1(FP), AX // ERROR "invalid TESTL of y\+1\(FP\); uint8 is 1-byte value"
+ TESTQ x+0(FP), AX // ERROR "invalid TESTQ of x\+0\(FP\); int8 is 1-byte value"
+ TESTQ y+1(FP), AX // ERROR "invalid TESTQ of y\+1\(FP\); uint8 is 1-byte value"
+ TESTB x+1(FP), AX // ERROR "invalid offset x\+1\(FP\); expected x\+0\(FP\)"
+ TESTB y+2(FP), AX // ERROR "invalid offset y\+2\(FP\); expected y\+1\(FP\)"
+ MOVB 4(SP), AX // ERROR "4\(SP\) should be x\+0\(FP\)"
+ MOVB 5(SP), AX // ERROR "5\(SP\) should be y\+1\(FP\)"
+ MOVB 6(SP), AX // ERROR "use of 6\(SP\) points beyond argument frame"
+ RET
+
+TEXT ·arg2(SB),0,$0-4
+ MOVB x+0(FP), AX // ERROR "arg2: invalid MOVB of x\+0\(FP\); int16 is 2-byte value"
+ MOVB y+2(FP), AX // ERROR "invalid MOVB of y\+2\(FP\); uint16 is 2-byte value"
+ MOVW x+0(FP), AX
+ MOVW y+2(FP), BX
+ MOVL x+0(FP), AX // ERROR "invalid MOVL of x\+0\(FP\); int16 is 2-byte value"
+ MOVL y+2(FP), AX // ERROR "invalid MOVL of y\+2\(FP\); uint16 is 2-byte value"
+ MOVQ x+0(FP), AX // ERROR "invalid MOVQ of x\+0\(FP\); int16 is 2-byte value"
+ MOVQ y+2(FP), AX // ERROR "invalid MOVQ of y\+2\(FP\); uint16 is 2-byte value"
+ MOVW x+2(FP), AX // ERROR "invalid offset x\+2\(FP\); expected x\+0\(FP\)"
+ MOVW y+0(FP), AX // ERROR "invalid offset y\+0\(FP\); expected y\+2\(FP\)"
+ TESTB x+0(FP), AX // ERROR "invalid TESTB of x\+0\(FP\); int16 is 2-byte value"
+ TESTB y+2(FP), AX // ERROR "invalid TESTB of y\+2\(FP\); uint16 is 2-byte value"
+ TESTW x+0(FP), AX
+ TESTW y+2(FP), BX
+ TESTL x+0(FP), AX // ERROR "invalid TESTL of x\+0\(FP\); int16 is 2-byte value"
+ TESTL y+2(FP), AX // ERROR "invalid TESTL of y\+2\(FP\); uint16 is 2-byte value"
+ TESTQ x+0(FP), AX // ERROR "invalid TESTQ of x\+0\(FP\); int16 is 2-byte value"
+ TESTQ y+2(FP), AX // ERROR "invalid TESTQ of y\+2\(FP\); uint16 is 2-byte value"
+ TESTW x+2(FP), AX // ERROR "invalid offset x\+2\(FP\); expected x\+0\(FP\)"
+ TESTW y+0(FP), AX // ERROR "invalid offset y\+0\(FP\); expected y\+2\(FP\)"
+ RET
+
+TEXT ·arg4(SB),0,$0-2 // ERROR "arg4: wrong argument size 2; expected \$\.\.\.-8"
+ MOVB x+0(FP), AX // ERROR "invalid MOVB of x\+0\(FP\); int32 is 4-byte value"
+ MOVB y+4(FP), BX // ERROR "invalid MOVB of y\+4\(FP\); uint32 is 4-byte value"
+ MOVW x+0(FP), AX // ERROR "invalid MOVW of x\+0\(FP\); int32 is 4-byte value"
+ MOVW y+4(FP), AX // ERROR "invalid MOVW of y\+4\(FP\); uint32 is 4-byte value"
+ MOVL x+0(FP), AX
+ MOVL y+4(FP), AX
+ MOVQ x+0(FP), AX // ERROR "invalid MOVQ of x\+0\(FP\); int32 is 4-byte value"
+ MOVQ y+4(FP), AX // ERROR "invalid MOVQ of y\+4\(FP\); uint32 is 4-byte value"
+ MOVL x+4(FP), AX // ERROR "invalid offset x\+4\(FP\); expected x\+0\(FP\)"
+ MOVL y+2(FP), AX // ERROR "invalid offset y\+2\(FP\); expected y\+4\(FP\)"
+ TESTB x+0(FP), AX // ERROR "invalid TESTB of x\+0\(FP\); int32 is 4-byte value"
+ TESTB y+4(FP), BX // ERROR "invalid TESTB of y\+4\(FP\); uint32 is 4-byte value"
+ TESTW x+0(FP), AX // ERROR "invalid TESTW of x\+0\(FP\); int32 is 4-byte value"
+ TESTW y+4(FP), AX // ERROR "invalid TESTW of y\+4\(FP\); uint32 is 4-byte value"
+ TESTL x+0(FP), AX
+ TESTL y+4(FP), AX
+ TESTQ x+0(FP), AX // ERROR "invalid TESTQ of x\+0\(FP\); int32 is 4-byte value"
+ TESTQ y+4(FP), AX // ERROR "invalid TESTQ of y\+4\(FP\); uint32 is 4-byte value"
+ TESTL x+4(FP), AX // ERROR "invalid offset x\+4\(FP\); expected x\+0\(FP\)"
+ TESTL y+2(FP), AX // ERROR "invalid offset y\+2\(FP\); expected y\+4\(FP\)"
+ RET
+
+TEXT ·arg8(SB),7,$0-2 // ERROR "wrong argument size 2; expected \$\.\.\.-16"
+ MOVB x+0(FP), AX // ERROR "invalid MOVB of x\+0\(FP\); int64 is 8-byte value"
+ MOVB y+8(FP), BX // ERROR "invalid MOVB of y\+8\(FP\); uint64 is 8-byte value"
+ MOVW x+0(FP), AX // ERROR "invalid MOVW of x\+0\(FP\); int64 is 8-byte value"
+ MOVW y+8(FP), AX // ERROR "invalid MOVW of y\+8\(FP\); uint64 is 8-byte value"
+ MOVL x+0(FP), AX // ERROR "invalid MOVL of x\+0\(FP\); int64 is 8-byte value containing x_lo\+0\(FP\) and x_hi\+4\(FP\)"
+ MOVL x_lo+0(FP), AX
+ MOVL x_hi+4(FP), AX
+ MOVL y+8(FP), AX // ERROR "invalid MOVL of y\+8\(FP\); uint64 is 8-byte value containing y_lo\+8\(FP\) and y_hi\+12\(FP\)"
+ MOVL y_lo+8(FP), AX
+ MOVL y_hi+12(FP), AX
+ MOVQ x+0(FP), AX
+ MOVQ y+8(FP), AX
+ MOVQ x+8(FP), AX // ERROR "invalid offset x\+8\(FP\); expected x\+0\(FP\)"
+ MOVQ y+2(FP), AX // ERROR "invalid offset y\+2\(FP\); expected y\+8\(FP\)"
+ TESTB x+0(FP), AX // ERROR "invalid TESTB of x\+0\(FP\); int64 is 8-byte value"
+ TESTB y+8(FP), BX // ERROR "invalid TESTB of y\+8\(FP\); uint64 is 8-byte value"
+ TESTW x+0(FP), AX // ERROR "invalid TESTW of x\+0\(FP\); int64 is 8-byte value"
+ TESTW y+8(FP), AX // ERROR "invalid TESTW of y\+8\(FP\); uint64 is 8-byte value"
+ TESTL x+0(FP), AX // ERROR "invalid TESTL of x\+0\(FP\); int64 is 8-byte value containing x_lo\+0\(FP\) and x_hi\+4\(FP\)"
+ TESTL y+8(FP), AX // ERROR "invalid TESTL of y\+8\(FP\); uint64 is 8-byte value containing y_lo\+8\(FP\) and y_hi\+12\(FP\)"
+ TESTQ x+0(FP), AX
+ TESTQ y+8(FP), AX
+ TESTQ x+8(FP), AX // ERROR "invalid offset x\+8\(FP\); expected x\+0\(FP\)"
+ TESTQ y+2(FP), AX // ERROR "invalid offset y\+2\(FP\); expected y\+8\(FP\)"
+ RET
+
+TEXT ·argint(SB),0,$0-2 // ERROR "wrong argument size 2; expected \$\.\.\.-8"
+ MOVB x+0(FP), AX // ERROR "invalid MOVB of x\+0\(FP\); int is 4-byte value"
+ MOVB y+4(FP), BX // ERROR "invalid MOVB of y\+4\(FP\); uint is 4-byte value"
+ MOVW x+0(FP), AX // ERROR "invalid MOVW of x\+0\(FP\); int is 4-byte value"
+ MOVW y+4(FP), AX // ERROR "invalid MOVW of y\+4\(FP\); uint is 4-byte value"
+ MOVL x+0(FP), AX
+ MOVL y+4(FP), AX
+ MOVQ x+0(FP), AX // ERROR "invalid MOVQ of x\+0\(FP\); int is 4-byte value"
+ MOVQ y+4(FP), AX // ERROR "invalid MOVQ of y\+4\(FP\); uint is 4-byte value"
+ MOVQ x+4(FP), AX // ERROR "invalid offset x\+4\(FP\); expected x\+0\(FP\)"
+ MOVQ y+2(FP), AX // ERROR "invalid offset y\+2\(FP\); expected y\+4\(FP\)"
+ TESTB x+0(FP), AX // ERROR "invalid TESTB of x\+0\(FP\); int is 4-byte value"
+ TESTB y+4(FP), BX // ERROR "invalid TESTB of y\+4\(FP\); uint is 4-byte value"
+ TESTW x+0(FP), AX // ERROR "invalid TESTW of x\+0\(FP\); int is 4-byte value"
+ TESTW y+4(FP), AX // ERROR "invalid TESTW of y\+4\(FP\); uint is 4-byte value"
+ TESTL x+0(FP), AX
+ TESTL y+4(FP), AX
+ TESTQ x+0(FP), AX // ERROR "invalid TESTQ of x\+0\(FP\); int is 4-byte value"
+ TESTQ y+4(FP), AX // ERROR "invalid TESTQ of y\+4\(FP\); uint is 4-byte value"
+ TESTQ x+4(FP), AX // ERROR "invalid offset x\+4\(FP\); expected x\+0\(FP\)"
+ TESTQ y+2(FP), AX // ERROR "invalid offset y\+2\(FP\); expected y\+4\(FP\)"
+ RET
+
+TEXT ·argptr(SB),7,$0-2 // ERROR "wrong argument size 2; expected \$\.\.\.-20"
+ MOVB x+0(FP), AX // ERROR "invalid MOVB of x\+0\(FP\); \*byte is 4-byte value"
+ MOVB y+4(FP), BX // ERROR "invalid MOVB of y\+4\(FP\); \*byte is 4-byte value"
+ MOVW x+0(FP), AX // ERROR "invalid MOVW of x\+0\(FP\); \*byte is 4-byte value"
+ MOVW y+4(FP), AX // ERROR "invalid MOVW of y\+4\(FP\); \*byte is 4-byte value"
+ MOVL x+0(FP), AX
+ MOVL y+4(FP), AX
+ MOVQ x+0(FP), AX // ERROR "invalid MOVQ of x\+0\(FP\); \*byte is 4-byte value"
+ MOVQ y+4(FP), AX // ERROR "invalid MOVQ of y\+4\(FP\); \*byte is 4-byte value"
+ MOVQ x+4(FP), AX // ERROR "invalid offset x\+4\(FP\); expected x\+0\(FP\)"
+ MOVQ y+2(FP), AX // ERROR "invalid offset y\+2\(FP\); expected y\+4\(FP\)"
+ TESTB x+0(FP), AX // ERROR "invalid TESTB of x\+0\(FP\); \*byte is 4-byte value"
+ TESTB y+4(FP), BX // ERROR "invalid TESTB of y\+4\(FP\); \*byte is 4-byte value"
+ TESTW x+0(FP), AX // ERROR "invalid TESTW of x\+0\(FP\); \*byte is 4-byte value"
+ TESTW y+4(FP), AX // ERROR "invalid TESTW of y\+4\(FP\); \*byte is 4-byte value"
+ TESTL x+0(FP), AX
+ TESTL y+4(FP), AX
+ TESTQ x+0(FP), AX // ERROR "invalid TESTQ of x\+0\(FP\); \*byte is 4-byte value"
+ TESTQ y+4(FP), AX // ERROR "invalid TESTQ of y\+4\(FP\); \*byte is 4-byte value"
+ TESTQ x+4(FP), AX // ERROR "invalid offset x\+4\(FP\); expected x\+0\(FP\)"
+ TESTQ y+2(FP), AX // ERROR "invalid offset y\+2\(FP\); expected y\+4\(FP\)"
+ MOVW c+8(FP), AX // ERROR "invalid MOVW of c\+8\(FP\); chan int is 4-byte value"
+ MOVW m+12(FP), AX // ERROR "invalid MOVW of m\+12\(FP\); map\[int\]int is 4-byte value"
+ MOVW f+16(FP), AX // ERROR "invalid MOVW of f\+16\(FP\); func\(\) is 4-byte value"
+ RET
+
+TEXT ·argstring(SB),0,$16 // ERROR "wrong argument size 0; expected \$\.\.\.-16"
+ MOVW x+0(FP), AX // ERROR "invalid MOVW of x\+0\(FP\); string base is 4-byte value"
+ MOVL x+0(FP), AX
+ MOVQ x+0(FP), AX // ERROR "invalid MOVQ of x\+0\(FP\); string base is 4-byte value"
+ MOVW x_base+0(FP), AX // ERROR "invalid MOVW of x_base\+0\(FP\); string base is 4-byte value"
+ MOVL x_base+0(FP), AX
+ MOVQ x_base+0(FP), AX // ERROR "invalid MOVQ of x_base\+0\(FP\); string base is 4-byte value"
+ MOVW x_len+0(FP), AX // ERROR "invalid offset x_len\+0\(FP\); expected x_len\+4\(FP\)"
+ MOVL x_len+0(FP), AX // ERROR "invalid offset x_len\+0\(FP\); expected x_len\+4\(FP\)"
+ MOVQ x_len+0(FP), AX // ERROR "invalid offset x_len\+0\(FP\); expected x_len\+4\(FP\)"
+ MOVW x_len+4(FP), AX // ERROR "invalid MOVW of x_len\+4\(FP\); string len is 4-byte value"
+ MOVL x_len+4(FP), AX
+ MOVQ x_len+4(FP), AX // ERROR "invalid MOVQ of x_len\+4\(FP\); string len is 4-byte value"
+ MOVQ y+0(FP), AX // ERROR "invalid offset y\+0\(FP\); expected y\+8\(FP\)"
+ MOVQ y_len+4(FP), AX // ERROR "invalid offset y_len\+4\(FP\); expected y_len\+12\(FP\)"
+ RET
+
+TEXT ·argslice(SB),0,$24 // ERROR "wrong argument size 0; expected \$\.\.\.-24"
+ MOVW x+0(FP), AX // ERROR "invalid MOVW of x\+0\(FP\); slice base is 4-byte value"
+ MOVL x+0(FP), AX
+ MOVQ x+0(FP), AX // ERROR "invalid MOVQ of x\+0\(FP\); slice base is 4-byte value"
+ MOVW x_base+0(FP), AX // ERROR "invalid MOVW of x_base\+0\(FP\); slice base is 4-byte value"
+ MOVL x_base+0(FP), AX
+ MOVQ x_base+0(FP), AX // ERROR "invalid MOVQ of x_base\+0\(FP\); slice base is 4-byte value"
+ MOVW x_len+0(FP), AX // ERROR "invalid offset x_len\+0\(FP\); expected x_len\+4\(FP\)"
+ MOVL x_len+0(FP), AX // ERROR "invalid offset x_len\+0\(FP\); expected x_len\+4\(FP\)"
+ MOVQ x_len+0(FP), AX // ERROR "invalid offset x_len\+0\(FP\); expected x_len\+4\(FP\)"
+ MOVW x_len+4(FP), AX // ERROR "invalid MOVW of x_len\+4\(FP\); slice len is 4-byte value"
+ MOVL x_len+4(FP), AX
+ MOVQ x_len+4(FP), AX // ERROR "invalid MOVQ of x_len\+4\(FP\); slice len is 4-byte value"
+ MOVW x_cap+0(FP), AX // ERROR "invalid offset x_cap\+0\(FP\); expected x_cap\+8\(FP\)"
+ MOVL x_cap+0(FP), AX // ERROR "invalid offset x_cap\+0\(FP\); expected x_cap\+8\(FP\)"
+ MOVQ x_cap+0(FP), AX // ERROR "invalid offset x_cap\+0\(FP\); expected x_cap\+8\(FP\)"
+ MOVW x_cap+8(FP), AX // ERROR "invalid MOVW of x_cap\+8\(FP\); slice cap is 4-byte value"
+ MOVL x_cap+8(FP), AX
+ MOVQ x_cap+8(FP), AX // ERROR "invalid MOVQ of x_cap\+8\(FP\); slice cap is 4-byte value"
+ MOVQ y+0(FP), AX // ERROR "invalid offset y\+0\(FP\); expected y\+12\(FP\)"
+ MOVQ y_len+4(FP), AX // ERROR "invalid offset y_len\+4\(FP\); expected y_len\+16\(FP\)"
+ MOVQ y_cap+8(FP), AX // ERROR "invalid offset y_cap\+8\(FP\); expected y_cap\+20\(FP\)"
+ RET
+
+TEXT ·argiface(SB),0,$0-16
+ MOVW x+0(FP), AX // ERROR "invalid MOVW of x\+0\(FP\); interface type is 4-byte value"
+ MOVL x+0(FP), AX
+ MOVQ x+0(FP), AX // ERROR "invalid MOVQ of x\+0\(FP\); interface type is 4-byte value"
+ MOVW x_type+0(FP), AX // ERROR "invalid MOVW of x_type\+0\(FP\); interface type is 4-byte value"
+ MOVL x_type+0(FP), AX
+ MOVQ x_type+0(FP), AX // ERROR "invalid MOVQ of x_type\+0\(FP\); interface type is 4-byte value"
+ MOVQ x_itable+0(FP), AX // ERROR "unknown variable x_itable; offset 0 is x_type\+0\(FP\)"
+ MOVQ x_itable+1(FP), AX // ERROR "unknown variable x_itable; offset 1 is x_type\+0\(FP\)"
+ MOVW x_data+0(FP), AX // ERROR "invalid offset x_data\+0\(FP\); expected x_data\+4\(FP\)"
+ MOVL x_data+0(FP), AX // ERROR "invalid offset x_data\+0\(FP\); expected x_data\+4\(FP\)"
+ MOVQ x_data+0(FP), AX // ERROR "invalid offset x_data\+0\(FP\); expected x_data\+4\(FP\)"
+ MOVW x_data+4(FP), AX // ERROR "invalid MOVW of x_data\+4\(FP\); interface data is 4-byte value"
+ MOVL x_data+4(FP), AX
+ MOVQ x_data+4(FP), AX // ERROR "invalid MOVQ of x_data\+4\(FP\); interface data is 4-byte value"
+ MOVW y+8(FP), AX // ERROR "invalid MOVW of y\+8\(FP\); interface itable is 4-byte value"
+ MOVL y+8(FP), AX
+ MOVQ y+8(FP), AX // ERROR "invalid MOVQ of y\+8\(FP\); interface itable is 4-byte value"
+ MOVW y_itable+8(FP), AX // ERROR "invalid MOVW of y_itable\+8\(FP\); interface itable is 4-byte value"
+ MOVL y_itable+8(FP), AX
+ MOVQ y_itable+8(FP), AX // ERROR "invalid MOVQ of y_itable\+8\(FP\); interface itable is 4-byte value"
+ MOVQ y_type+8(FP), AX // ERROR "unknown variable y_type; offset 8 is y_itable\+8\(FP\)"
+ MOVW y_data+8(FP), AX // ERROR "invalid offset y_data\+8\(FP\); expected y_data\+12\(FP\)"
+ MOVL y_data+8(FP), AX // ERROR "invalid offset y_data\+8\(FP\); expected y_data\+12\(FP\)"
+ MOVQ y_data+8(FP), AX // ERROR "invalid offset y_data\+8\(FP\); expected y_data\+12\(FP\)"
+ MOVW y_data+12(FP), AX // ERROR "invalid MOVW of y_data\+12\(FP\); interface data is 4-byte value"
+ MOVL y_data+12(FP), AX
+ MOVQ y_data+12(FP), AX // ERROR "invalid MOVQ of y_data\+12\(FP\); interface data is 4-byte value"
+ RET
+
+TEXT ·returnint(SB),0,$0-4
+ MOVB AX, ret+0(FP) // ERROR "invalid MOVB of ret\+0\(FP\); int is 4-byte value"
+ MOVW AX, ret+0(FP) // ERROR "invalid MOVW of ret\+0\(FP\); int is 4-byte value"
+ MOVL AX, ret+0(FP)
+ MOVQ AX, ret+0(FP) // ERROR "invalid MOVQ of ret\+0\(FP\); int is 4-byte value"
+ MOVQ AX, ret+1(FP) // ERROR "invalid offset ret\+1\(FP\); expected ret\+0\(FP\)"
+ MOVQ AX, r+0(FP) // ERROR "unknown variable r; offset 0 is ret\+0\(FP\)"
+ RET
+
+TEXT ·returnbyte(SB),0,$0-5
+ MOVL x+0(FP), AX
+ MOVB AX, ret+4(FP)
+ MOVW AX, ret+4(FP) // ERROR "invalid MOVW of ret\+4\(FP\); byte is 1-byte value"
+ MOVL AX, ret+4(FP) // ERROR "invalid MOVL of ret\+4\(FP\); byte is 1-byte value"
+ MOVQ AX, ret+4(FP) // ERROR "invalid MOVQ of ret\+4\(FP\); byte is 1-byte value"
+ MOVB AX, ret+3(FP) // ERROR "invalid offset ret\+3\(FP\); expected ret\+4\(FP\)"
+ RET
+
+TEXT ·returnnamed(SB),0,$0-21
+ MOVB x+0(FP), AX
+ MOVL AX, r1+4(FP)
+ MOVW AX, r2+8(FP)
+ MOVL AX, r3+12(FP)
+ MOVL AX, r3_base+12(FP)
+ MOVL AX, r3_len+16(FP)
+ MOVB AX, r4+20(FP)
+ MOVQ AX, r1+4(FP) // ERROR "invalid MOVQ of r1\+4\(FP\); int is 4-byte value"
+ RET
+
+TEXT ·returnintmissing(SB),0,$0-4
+ RET // ERROR "RET without writing to 4-byte ret\+0\(FP\)"
diff --git a/cmd/vet/testdata/asm3.s b/cmd/vet/testdata/asm3.s
new file mode 100644
index 0000000..3d69356
--- /dev/null
+++ b/cmd/vet/testdata/asm3.s
@@ -0,0 +1,178 @@
+// 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 arm
+// +build vet_test
+
+TEXT ·arg1(SB),0,$0-2
+ MOVB x+0(FP), AX
+ MOVB y+1(FP), BX
+ MOVH x+0(FP), AX // ERROR "\[arm\] arg1: invalid MOVH of x\+0\(FP\); int8 is 1-byte value"
+ MOVH y+1(FP), AX // ERROR "invalid MOVH of y\+1\(FP\); uint8 is 1-byte value"
+ MOVW x+0(FP), AX // ERROR "invalid MOVW of x\+0\(FP\); int8 is 1-byte value"
+ MOVW y+1(FP), AX // ERROR "invalid MOVW of y\+1\(FP\); uint8 is 1-byte value"
+ MOVB x+1(FP), AX // ERROR "invalid offset x\+1\(FP\); expected x\+0\(FP\)"
+ MOVB y+2(FP), AX // ERROR "invalid offset y\+2\(FP\); expected y\+1\(FP\)"
+ MOVB 8(R13), AX // ERROR "8\(R13\) should be x\+0\(FP\)"
+ MOVB 9(R13), AX // ERROR "9\(R13\) should be y\+1\(FP\)"
+ MOVB 10(R13), AX // ERROR "use of 10\(R13\) points beyond argument frame"
+ RET
+
+TEXT ·arg2(SB),0,$0-4
+ MOVB x+0(FP), AX // ERROR "arg2: invalid MOVB of x\+0\(FP\); int16 is 2-byte value"
+ MOVB y+2(FP), AX // ERROR "invalid MOVB of y\+2\(FP\); uint16 is 2-byte value"
+ MOVH x+0(FP), AX
+ MOVH y+2(FP), BX
+ MOVW x+0(FP), AX // ERROR "invalid MOVW of x\+0\(FP\); int16 is 2-byte value"
+ MOVW y+2(FP), AX // ERROR "invalid MOVW of y\+2\(FP\); uint16 is 2-byte value"
+ MOVH x+2(FP), AX // ERROR "invalid offset x\+2\(FP\); expected x\+0\(FP\)"
+ MOVH y+0(FP), AX // ERROR "invalid offset y\+0\(FP\); expected y\+2\(FP\)"
+ RET
+
+TEXT ·arg4(SB),0,$0-2 // ERROR "arg4: wrong argument size 2; expected \$\.\.\.-8"
+ MOVB x+0(FP), AX // ERROR "invalid MOVB of x\+0\(FP\); int32 is 4-byte value"
+ MOVB y+4(FP), BX // ERROR "invalid MOVB of y\+4\(FP\); uint32 is 4-byte value"
+ MOVH x+0(FP), AX // ERROR "invalid MOVH of x\+0\(FP\); int32 is 4-byte value"
+ MOVH y+4(FP), AX // ERROR "invalid MOVH of y\+4\(FP\); uint32 is 4-byte value"
+ MOVW x+0(FP), AX
+ MOVW y+4(FP), AX
+ MOVW x+4(FP), AX // ERROR "invalid offset x\+4\(FP\); expected x\+0\(FP\)"
+ MOVW y+2(FP), AX // ERROR "invalid offset y\+2\(FP\); expected y\+4\(FP\)"
+ RET
+
+TEXT ·arg8(SB),7,$0-2 // ERROR "wrong argument size 2; expected \$\.\.\.-16"
+ MOVB x+0(FP), AX // ERROR "invalid MOVB of x\+0\(FP\); int64 is 8-byte value"
+ MOVB y+8(FP), BX // ERROR "invalid MOVB of y\+8\(FP\); uint64 is 8-byte value"
+ MOVH x+0(FP), AX // ERROR "invalid MOVH of x\+0\(FP\); int64 is 8-byte value"
+ MOVH y+8(FP), AX // ERROR "invalid MOVH of y\+8\(FP\); uint64 is 8-byte value"
+ MOVW x+0(FP), AX // ERROR "invalid MOVW of x\+0\(FP\); int64 is 8-byte value containing x_lo\+0\(FP\) and x_hi\+4\(FP\)"
+ MOVW x_lo+0(FP), AX
+ MOVW x_hi+4(FP), AX
+ MOVW y+8(FP), AX // ERROR "invalid MOVW of y\+8\(FP\); uint64 is 8-byte value containing y_lo\+8\(FP\) and y_hi\+12\(FP\)"
+ MOVW y_lo+8(FP), AX
+ MOVW y_hi+12(FP), AX
+ MOVQ x+0(FP), AX
+ MOVQ y+8(FP), AX
+ MOVQ x+8(FP), AX // ERROR "invalid offset x\+8\(FP\); expected x\+0\(FP\)"
+ MOVQ y+2(FP), AX // ERROR "invalid offset y\+2\(FP\); expected y\+8\(FP\)"
+ RET
+
+TEXT ·argint(SB),0,$0-2 // ERROR "wrong argument size 2; expected \$\.\.\.-8"
+ MOVB x+0(FP), AX // ERROR "invalid MOVB of x\+0\(FP\); int is 4-byte value"
+ MOVB y+4(FP), BX // ERROR "invalid MOVB of y\+4\(FP\); uint is 4-byte value"
+ MOVH x+0(FP), AX // ERROR "invalid MOVH of x\+0\(FP\); int is 4-byte value"
+ MOVH y+4(FP), AX // ERROR "invalid MOVH of y\+4\(FP\); uint is 4-byte value"
+ MOVW x+0(FP), AX
+ MOVW y+4(FP), AX
+ MOVQ x+4(FP), AX // ERROR "invalid offset x\+4\(FP\); expected x\+0\(FP\)"
+ MOVQ y+2(FP), AX // ERROR "invalid offset y\+2\(FP\); expected y\+4\(FP\)"
+ RET
+
+TEXT ·argptr(SB),7,$0-2 // ERROR "wrong argument size 2; expected \$\.\.\.-20"
+ MOVB x+0(FP), AX // ERROR "invalid MOVB of x\+0\(FP\); \*byte is 4-byte value"
+ MOVB y+4(FP), BX // ERROR "invalid MOVB of y\+4\(FP\); \*byte is 4-byte value"
+ MOVH x+0(FP), AX // ERROR "invalid MOVH of x\+0\(FP\); \*byte is 4-byte value"
+ MOVH y+4(FP), AX // ERROR "invalid MOVH of y\+4\(FP\); \*byte is 4-byte value"
+ MOVW x+0(FP), AX
+ MOVW y+4(FP), AX
+ MOVQ x+4(FP), AX // ERROR "invalid offset x\+4\(FP\); expected x\+0\(FP\)"
+ MOVQ y+2(FP), AX // ERROR "invalid offset y\+2\(FP\); expected y\+4\(FP\)"
+ MOVH c+8(FP), AX // ERROR "invalid MOVH of c\+8\(FP\); chan int is 4-byte value"
+ MOVH m+12(FP), AX // ERROR "invalid MOVH of m\+12\(FP\); map\[int\]int is 4-byte value"
+ MOVH f+16(FP), AX // ERROR "invalid MOVH of f\+16\(FP\); func\(\) is 4-byte value"
+ RET
+
+TEXT ·argstring(SB),0,$16 // ERROR "wrong argument size 0; expected \$\.\.\.-16"
+ MOVH x+0(FP), AX // ERROR "invalid MOVH of x\+0\(FP\); string base is 4-byte value"
+ MOVW x+0(FP), AX
+ MOVH x_base+0(FP), AX // ERROR "invalid MOVH of x_base\+0\(FP\); string base is 4-byte value"
+ MOVW x_base+0(FP), AX
+ MOVH x_len+0(FP), AX // ERROR "invalid offset x_len\+0\(FP\); expected x_len\+4\(FP\)"
+ MOVW x_len+0(FP), AX // ERROR "invalid offset x_len\+0\(FP\); expected x_len\+4\(FP\)"
+ MOVQ x_len+0(FP), AX // ERROR "invalid offset x_len\+0\(FP\); expected x_len\+4\(FP\)"
+ MOVH x_len+4(FP), AX // ERROR "invalid MOVH of x_len\+4\(FP\); string len is 4-byte value"
+ MOVW x_len+4(FP), AX
+ MOVQ y+0(FP), AX // ERROR "invalid offset y\+0\(FP\); expected y\+8\(FP\)"
+ MOVQ y_len+4(FP), AX // ERROR "invalid offset y_len\+4\(FP\); expected y_len\+12\(FP\)"
+ RET
+
+TEXT ·argslice(SB),0,$24 // ERROR "wrong argument size 0; expected \$\.\.\.-24"
+ MOVH x+0(FP), AX // ERROR "invalid MOVH of x\+0\(FP\); slice base is 4-byte value"
+ MOVW x+0(FP), AX
+ MOVH x_base+0(FP), AX // ERROR "invalid MOVH of x_base\+0\(FP\); slice base is 4-byte value"
+ MOVW x_base+0(FP), AX
+ MOVH x_len+0(FP), AX // ERROR "invalid offset x_len\+0\(FP\); expected x_len\+4\(FP\)"
+ MOVW x_len+0(FP), AX // ERROR "invalid offset x_len\+0\(FP\); expected x_len\+4\(FP\)"
+ MOVQ x_len+0(FP), AX // ERROR "invalid offset x_len\+0\(FP\); expected x_len\+4\(FP\)"
+ MOVH x_len+4(FP), AX // ERROR "invalid MOVH of x_len\+4\(FP\); slice len is 4-byte value"
+ MOVW x_len+4(FP), AX
+ MOVH x_cap+0(FP), AX // ERROR "invalid offset x_cap\+0\(FP\); expected x_cap\+8\(FP\)"
+ MOVW x_cap+0(FP), AX // ERROR "invalid offset x_cap\+0\(FP\); expected x_cap\+8\(FP\)"
+ MOVQ x_cap+0(FP), AX // ERROR "invalid offset x_cap\+0\(FP\); expected x_cap\+8\(FP\)"
+ MOVH x_cap+8(FP), AX // ERROR "invalid MOVH of x_cap\+8\(FP\); slice cap is 4-byte value"
+ MOVW x_cap+8(FP), AX
+ MOVQ y+0(FP), AX // ERROR "invalid offset y\+0\(FP\); expected y\+12\(FP\)"
+ MOVQ y_len+4(FP), AX // ERROR "invalid offset y_len\+4\(FP\); expected y_len\+16\(FP\)"
+ MOVQ y_cap+8(FP), AX // ERROR "invalid offset y_cap\+8\(FP\); expected y_cap\+20\(FP\)"
+ RET
+
+TEXT ·argiface(SB),0,$0-16
+ MOVH x+0(FP), AX // ERROR "invalid MOVH of x\+0\(FP\); interface type is 4-byte value"
+ MOVW x+0(FP), AX
+ MOVH x_type+0(FP), AX // ERROR "invalid MOVH of x_type\+0\(FP\); interface type is 4-byte value"
+ MOVW x_type+0(FP), AX
+ MOVQ x_itable+0(FP), AX // ERROR "unknown variable x_itable; offset 0 is x_type\+0\(FP\)"
+ MOVQ x_itable+1(FP), AX // ERROR "unknown variable x_itable; offset 1 is x_type\+0\(FP\)"
+ MOVH x_data+0(FP), AX // ERROR "invalid offset x_data\+0\(FP\); expected x_data\+4\(FP\)"
+ MOVW x_data+0(FP), AX // ERROR "invalid offset x_data\+0\(FP\); expected x_data\+4\(FP\)"
+ MOVQ x_data+0(FP), AX // ERROR "invalid offset x_data\+0\(FP\); expected x_data\+4\(FP\)"
+ MOVH x_data+4(FP), AX // ERROR "invalid MOVH of x_data\+4\(FP\); interface data is 4-byte value"
+ MOVW x_data+4(FP), AX
+ MOVH y+8(FP), AX // ERROR "invalid MOVH of y\+8\(FP\); interface itable is 4-byte value"
+ MOVW y+8(FP), AX
+ MOVH y_itable+8(FP), AX // ERROR "invalid MOVH of y_itable\+8\(FP\); interface itable is 4-byte value"
+ MOVW y_itable+8(FP), AX
+ MOVQ y_type+8(FP), AX // ERROR "unknown variable y_type; offset 8 is y_itable\+8\(FP\)"
+ MOVH y_data+8(FP), AX // ERROR "invalid offset y_data\+8\(FP\); expected y_data\+12\(FP\)"
+ MOVW y_data+8(FP), AX // ERROR "invalid offset y_data\+8\(FP\); expected y_data\+12\(FP\)"
+ MOVQ y_data+8(FP), AX // ERROR "invalid offset y_data\+8\(FP\); expected y_data\+12\(FP\)"
+ MOVH y_data+12(FP), AX // ERROR "invalid MOVH of y_data\+12\(FP\); interface data is 4-byte value"
+ MOVW y_data+12(FP), AX
+ RET
+
+TEXT ·returnint(SB),0,$0-4
+ MOVB AX, ret+0(FP) // ERROR "invalid MOVB of ret\+0\(FP\); int is 4-byte value"
+ MOVH AX, ret+0(FP) // ERROR "invalid MOVH of ret\+0\(FP\); int is 4-byte value"
+ MOVW AX, ret+0(FP)
+ MOVQ AX, ret+1(FP) // ERROR "invalid offset ret\+1\(FP\); expected ret\+0\(FP\)"
+ MOVQ AX, r+0(FP) // ERROR "unknown variable r; offset 0 is ret\+0\(FP\)"
+ RET
+
+TEXT ·returnbyte(SB),0,$0-5
+ MOVW x+0(FP), AX
+ MOVB AX, ret+4(FP)
+ MOVH AX, ret+4(FP) // ERROR "invalid MOVH of ret\+4\(FP\); byte is 1-byte value"
+ MOVW AX, ret+4(FP) // ERROR "invalid MOVW of ret\+4\(FP\); byte is 1-byte value"
+ MOVB AX, ret+3(FP) // ERROR "invalid offset ret\+3\(FP\); expected ret\+4\(FP\)"
+ RET
+
+TEXT ·returnnamed(SB),0,$0-21
+ MOVB x+0(FP), AX
+ MOVW AX, r1+4(FP)
+ MOVH AX, r2+8(FP)
+ MOVW AX, r3+12(FP)
+ MOVW AX, r3_base+12(FP)
+ MOVW AX, r3_len+16(FP)
+ MOVB AX, r4+20(FP)
+ MOVB AX, r1+4(FP) // ERROR "invalid MOVB of r1\+4\(FP\); int is 4-byte value"
+ RET
+
+TEXT ·returnintmissing(SB),0,$0-4
+ RET // ERROR "RET without writing to 4-byte ret\+0\(FP\)"
+
+TEXT ·leaf(SB),0,$-4-12
+ MOVW x+0(FP), AX
+ MOVW y+4(FP), AX
+ MOVW AX, ret+8(FP)
+ RET
diff --git a/cmd/vet/testdata/asm4.s b/cmd/vet/testdata/asm4.s
new file mode 100644
index 0000000..044b050
--- /dev/null
+++ b/cmd/vet/testdata/asm4.s
@@ -0,0 +1,26 @@
+// 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 amd64
+// +build vet_test
+
+// Test cases for symbolic NOSPLIT etc. on TEXT symbols.
+
+TEXT ·noprof(SB),NOPROF,$0-8
+ RET
+
+TEXT ·dupok(SB),DUPOK,$0-8
+ RET
+
+TEXT ·nosplit(SB),NOSPLIT,$0
+ RET
+
+TEXT ·rodata(SB),RODATA,$0-8
+ RET
+
+TEXT ·noptr(SB),NOPTR|NOSPLIT,$0
+ RET
+
+TEXT ·wrapper(SB),WRAPPER,$0-8
+ RET
diff --git a/cmd/vet/testdata/assign.go b/cmd/vet/testdata/assign.go
new file mode 100644
index 0000000..32ba868
--- /dev/null
+++ b/cmd/vet/testdata/assign.go
@@ -0,0 +1,18 @@
+// 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 tests for the useless-assignment checker.
+
+package testdata
+
+type ST struct {
+ x int
+}
+
+func (s *ST) SetX(x int) {
+ // Accidental self-assignment; it should be "s.x = x"
+ x = x // ERROR "self-assignment of x to x"
+ // Another mistake
+ s.x = s.x // ERROR "self-assignment of s.x to s.x"
+}
diff --git a/cmd/vet/testdata/atomic.go b/cmd/vet/testdata/atomic.go
new file mode 100644
index 0000000..1ba261d
--- /dev/null
+++ b/cmd/vet/testdata/atomic.go
@@ -0,0 +1,43 @@
+// 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 tests for the atomic checker.
+
+package testdata
+
+import (
+ "sync/atomic"
+)
+
+type Counter uint64
+
+func AtomicTests() {
+ x := uint64(1)
+ x = atomic.AddUint64(&x, 1) // ERROR "direct assignment to atomic value"
+ _, x = 10, atomic.AddUint64(&x, 1) // ERROR "direct assignment to atomic value"
+ x, _ = atomic.AddUint64(&x, 1), 10 // ERROR "direct assignment to atomic value"
+
+ y := &x
+ *y = atomic.AddUint64(y, 1) // ERROR "direct assignment to atomic value"
+
+ var su struct{ Counter uint64 }
+ su.Counter = atomic.AddUint64(&su.Counter, 1) // ERROR "direct assignment to atomic value"
+ z1 := atomic.AddUint64(&su.Counter, 1)
+ _ = z1 // Avoid err "z declared and not used"
+
+ var sp struct{ Counter *uint64 }
+ *sp.Counter = atomic.AddUint64(sp.Counter, 1) // ERROR "direct assignment to atomic value"
+ z2 := atomic.AddUint64(sp.Counter, 1)
+ _ = z2 // Avoid err "z declared and not used"
+
+ au := []uint64{10, 20}
+ au[0] = atomic.AddUint64(&au[0], 1) // ERROR "direct assignment to atomic value"
+ au[1] = atomic.AddUint64(&au[0], 1)
+
+ ap := []*uint64{&au[0], &au[1]}
+ *ap[0] = atomic.AddUint64(ap[0], 1) // ERROR "direct assignment to atomic value"
+ *ap[1] = atomic.AddUint64(ap[0], 1)
+
+ x = atomic.AddUint64() // Used to make vet crash; now silently ignored.
+}
diff --git a/cmd/vet/testdata/bool.go b/cmd/vet/testdata/bool.go
new file mode 100644
index 0000000..af6cc01
--- /dev/null
+++ b/cmd/vet/testdata/bool.go
@@ -0,0 +1,113 @@
+// 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 the bool checker.
+
+package testdata
+
+import "io"
+
+func RatherStupidConditions() {
+ var f, g func() int
+ if f() == 0 || f() == 0 { // OK f might have side effects
+ }
+ if v, w := f(), g(); v == w || v == w { // ERROR "redundant or: v == w || v == w"
+ }
+ _ = f == nil || f == nil // ERROR "redundant or: f == nil || f == nil"
+
+ _ = i == byte(1) || i == byte(1) // TODO conversions are treated as if they may have side effects
+
+ var c chan int
+ _ = 0 == <-c || 0 == <-c // OK subsequent receives may yield different values
+ for i, j := <-c, <-c; i == j || i == j; i, j = <-c, <-c { // ERROR "redundant or: i == j || i == j"
+ }
+
+ var i, j, k int
+ _ = i+1 == 1 || i+1 == 1 // ERROR "redundant or: i\+1 == 1 || i\+1 == 1"
+ _ = i == 1 || j+1 == i || i == 1 // ERROR "redundant or: i == 1 || i == 1"
+
+ _ = i == 1 || i == 1 || f() == 1 // ERROR "redundant or: i == 1 || i == 1"
+ _ = i == 1 || f() == 1 || i == 1 // OK f may alter i as a side effect
+ _ = f() == 1 || i == 1 || i == 1 // ERROR "redundant or: i == 1 || i == 1"
+
+ // Test partition edge cases
+ _ = f() == 1 || i == 1 || i == 1 || j == 1 // ERROR "redundant or: i == 1 || i == 1"
+ _ = f() == 1 || j == 1 || i == 1 || i == 1 // ERROR "redundant or: i == 1 || i == 1"
+ _ = i == 1 || f() == 1 || i == 1 || i == 1 // ERROR "redundant or: i == 1 || i == 1"
+ _ = i == 1 || i == 1 || f() == 1 || i == 1 // ERROR "redundant or: i == 1 || i == 1"
+ _ = i == 1 || i == 1 || j == 1 || f() == 1 // ERROR "redundant or: i == 1 || i == 1"
+ _ = j == 1 || i == 1 || i == 1 || f() == 1 // ERROR "redundant or: i == 1 || i == 1"
+ _ = i == 1 || f() == 1 || f() == 1 || i == 1
+
+ _ = i == 1 || (i == 1 || i == 2) // ERROR "redundant or: i == 1 || i == 1"
+ _ = i == 1 || (f() == 1 || i == 1) // OK f may alter i as a side effect
+ _ = i == 1 || (i == 1 || f() == 1) // ERROR "redundant or: i == 1 || i == 1"
+ _ = i == 1 || (i == 2 || (i == 1 || i == 3)) // ERROR "redundant or: i == 1 || i == 1"
+
+ var a, b bool
+ _ = i == 1 || (a || (i == 1 || b)) // ERROR "redundant or: i == 1 || i == 1"
+
+ // Check that all redundant ors are flagged
+ _ = j == 0 ||
+ i == 1 ||
+ f() == 1 ||
+ j == 0 || // ERROR "redundant or: j == 0 || j == 0"
+ i == 1 || // ERROR "redundant or: i == 1 || i == 1"
+ i == 1 || // ERROR "redundant or: i == 1 || i == 1"
+ i == 1 ||
+ j == 0 ||
+ k == 0
+
+ _ = i == 1*2*3 || i == 1*2*3 // ERROR "redundant or: i == 1\*2\*3 || i == 1\*2\*3"
+
+ // These test that redundant, suspect expressions do not trigger multiple errors.
+ _ = i != 0 || i != 0 // ERROR "redundant or: i != 0 || i != 0"
+ _ = i == 0 && i == 0 // ERROR "redundant and: i == 0 && i == 0"
+
+ // and is dual to or; check the basics and
+ // let the or tests pull the rest of the weight.
+ _ = 0 != <-c && 0 != <-c // OK subsequent receives may yield different values
+ _ = f() != 0 && f() != 0 // OK f might have side effects
+ _ = f != nil && f != nil // ERROR "redundant and: f != nil && f != nil"
+ _ = i != 1 && i != 1 && f() != 1 // ERROR "redundant and: i != 1 && i != 1"
+ _ = i != 1 && f() != 1 && i != 1 // OK f may alter i as a side effect
+ _ = f() != 1 && i != 1 && i != 1 // ERROR "redundant and: i != 1 && i != 1"
+}
+
+func RoyallySuspectConditions() {
+ var i, j int
+
+ _ = i == 0 || i == 1 // OK
+ _ = i != 0 || i != 1 // ERROR "suspect or: i != 0 || i != 1"
+ _ = i != 0 || 1 != i // ERROR "suspect or: i != 0 || 1 != i"
+ _ = 0 != i || 1 != i // ERROR "suspect or: 0 != i || 1 != i"
+ _ = 0 != i || i != 1 // ERROR "suspect or: 0 != i || i != 1"
+
+ _ = (0 != i) || i != 1 // ERROR "suspect or: 0 != i || i != 1"
+
+ _ = i+3 != 7 || j+5 == 0 || i+3 != 9 // ERROR "suspect or: i\+3 != 7 || i\+3 != 9"
+
+ _ = i != 0 || j == 0 || i != 1 // ERROR "suspect or: i != 0 || i != 1"
+
+ _ = i != 0 || i != 1<<4 // ERROR "suspect or: i != 0 || i != 1<<4"
+
+ _ = i != 0 || j != 0
+ _ = 0 != i || 0 != j
+
+ var s string
+ _ = s != "one" || s != "the other" // ERROR "suspect or: s != .one. || s != .the other."
+
+ _ = "et" != "alii" || "et" != "cetera" // ERROR "suspect or: .et. != .alii. || .et. != .cetera."
+ _ = "me gustas" != "tu" || "le gustas" != "tu" // OK we could catch this case, but it's not worth the code
+
+ var err error
+ _ = err != nil || err != io.EOF // TODO catch this case?
+
+ // Sanity check and.
+ _ = i != 0 && i != 1 // OK
+ _ = i == 0 && i == 1 // ERROR "suspect and: i == 0 && i == 1"
+ _ = i == 0 && 1 == i // ERROR "suspect and: i == 0 && 1 == i"
+ _ = 0 == i && 1 == i // ERROR "suspect and: 0 == i && 1 == i"
+ _ = 0 == i && i == 1 // ERROR "suspect and: 0 == i && i == 1"
+}
diff --git a/cmd/vet/testdata/buildtag.go b/cmd/vet/testdata/buildtag.go
new file mode 100644
index 0000000..eb36fd3
--- /dev/null
+++ b/cmd/vet/testdata/buildtag.go
@@ -0,0 +1,14 @@
+// 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 tests for the buildtag checker.
+
+// +builder // ERROR "possible malformed \+build comment"
+// +build !ignore
+
+package testdata
+
+// +build toolate // ERROR "build comment must appear before package clause and be followed by a blank line"
+
+var _ = 3
diff --git a/cmd/vet/testdata/buildtag_bad.go b/cmd/vet/testdata/buildtag_bad.go
new file mode 100644
index 0000000..fbe10cf
--- /dev/null
+++ b/cmd/vet/testdata/buildtag_bad.go
@@ -0,0 +1,15 @@
+// This file contains misplaced or malformed build constraints.
+// The Go tool will skip it, because the constraints are invalid.
+// It serves only to test the tag checker during make test.
+
+// Mention +build // ERROR "possible malformed \+build comment"
+
+// +build !!bang // ERROR "invalid double negative in build constraint"
+// +build @#$ // ERROR "invalid non-alphanumeric build constraint"
+
+// +build toolate // ERROR "build comment must appear before package clause and be followed by a blank line"
+package bad
+
+// This is package 'bad' rather than 'main' so the erroneous build
+// tag doesn't end up looking like a package doc for the vet command
+// when examined by godoc.
diff --git a/cmd/vet/testdata/composite.go b/cmd/vet/testdata/composite.go
new file mode 100644
index 0000000..69e7d7c
--- /dev/null
+++ b/cmd/vet/testdata/composite.go
@@ -0,0 +1,63 @@
+// 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 tests for the untagged struct literal checker.
+
+// This file contains the test for untagged struct literals.
+
+package testdata
+
+import (
+ "flag"
+ "go/scanner"
+)
+
+var Okay1 = []string{
+ "Name",
+ "Usage",
+ "DefValue",
+}
+
+var Okay2 = map[string]bool{
+ "Name": true,
+ "Usage": true,
+ "DefValue": true,
+}
+
+var Okay3 = struct {
+ X string
+ Y string
+ Z string
+}{
+ "Name",
+ "Usage",
+ "DefValue",
+}
+
+type MyStruct struct {
+ X string
+ Y string
+ Z string
+}
+
+var Okay4 = MyStruct{
+ "Name",
+ "Usage",
+ "DefValue",
+}
+
+// Testing is awkward because we need to reference things from a separate package
+// to trigger the warnings.
+
+var BadStructLiteralUsedInTests = flag.Flag{ // ERROR "unkeyed fields"
+ "Name",
+ "Usage",
+ nil, // Value
+ "DefValue",
+}
+
+// Used to test the check for slices and arrays: If that test is disabled and
+// vet is run with --compositewhitelist=false, this line triggers an error.
+// Clumsy but sufficient.
+var scannerErrorListTest = scanner.ErrorList{nil, nil}
diff --git a/cmd/vet/testdata/copylock_func.go b/cmd/vet/testdata/copylock_func.go
new file mode 100644
index 0000000..108c044
--- /dev/null
+++ b/cmd/vet/testdata/copylock_func.go
@@ -0,0 +1,90 @@
+// 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 tests for the copylock checker's
+// function declaration analysis.
+
+package testdata
+
+import "sync"
+
+func OkFunc(*sync.Mutex) {}
+func BadFunc(sync.Mutex) {} // ERROR "BadFunc passes Lock by value: sync.Mutex"
+func OkRet() *sync.Mutex {}
+func BadRet() sync.Mutex {} // ERROR "BadRet returns Lock by value: sync.Mutex"
+
+type EmbeddedRWMutex struct {
+ sync.RWMutex
+}
+
+func (*EmbeddedRWMutex) OkMeth() {}
+func (EmbeddedRWMutex) BadMeth() {} // ERROR "BadMeth passes Lock by value: testdata.EmbeddedRWMutex"
+func OkFunc(e *EmbeddedRWMutex) {}
+func BadFunc(EmbeddedRWMutex) {} // ERROR "BadFunc passes Lock by value: testdata.EmbeddedRWMutex"
+func OkRet() *EmbeddedRWMutex {}
+func BadRet() EmbeddedRWMutex {} // ERROR "BadRet returns Lock by value: testdata.EmbeddedRWMutex"
+
+type FieldMutex struct {
+ s sync.Mutex
+}
+
+func (*FieldMutex) OkMeth() {}
+func (FieldMutex) BadMeth() {} // ERROR "BadMeth passes Lock by value: testdata.FieldMutex contains sync.Mutex"
+func OkFunc(*FieldMutex) {}
+func BadFunc(FieldMutex, int) {} // ERROR "BadFunc passes Lock by value: testdata.FieldMutex contains sync.Mutex"
+
+type L0 struct {
+ L1
+}
+
+type L1 struct {
+ l L2
+}
+
+type L2 struct {
+ sync.Mutex
+}
+
+func (*L0) Ok() {}
+func (L0) Bad() {} // ERROR "Bad passes Lock by value: testdata.L0 contains testdata.L1 contains testdata.L2"
+
+type EmbeddedMutexPointer struct {
+ s *sync.Mutex // safe to copy this pointer
+}
+
+func (*EmbeddedMutexPointer) Ok() {}
+func (EmbeddedMutexPointer) AlsoOk() {}
+func StillOk(EmbeddedMutexPointer) {}
+func LookinGood() EmbeddedMutexPointer {}
+
+type EmbeddedLocker struct {
+ sync.Locker // safe to copy interface values
+}
+
+func (*EmbeddedLocker) Ok() {}
+func (EmbeddedLocker) AlsoOk() {}
+
+type CustomLock struct{}
+
+func (*CustomLock) Lock() {}
+func (*CustomLock) Unlock() {}
+
+func Ok(*CustomLock) {}
+func Bad(CustomLock) {} // ERROR "Bad passes Lock by value: testdata.CustomLock"
+
+// TODO: Unfortunate cases
+
+// Non-ideal error message:
+// Since we're looking for Lock methods, sync.Once's underlying
+// sync.Mutex gets called out, but without any reference to the sync.Once.
+type LocalOnce sync.Once
+
+func (LocalOnce) Bad() {} // ERROR "Bad passes Lock by value: testdata.LocalOnce contains sync.Mutex"
+
+// False negative:
+// LocalMutex doesn't have a Lock method.
+// Nevertheless, it is probably a bad idea to pass it by value.
+type LocalMutex sync.Mutex
+
+func (LocalMutex) Bad() {} // WANTED: An error here :(
diff --git a/cmd/vet/testdata/copylock_range.go b/cmd/vet/testdata/copylock_range.go
new file mode 100644
index 0000000..f95b025
--- /dev/null
+++ b/cmd/vet/testdata/copylock_range.go
@@ -0,0 +1,67 @@
+// 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 the copylock checker's
+// range statement analysis.
+
+package testdata
+
+import "sync"
+
+func rangeMutex() {
+ var mu sync.Mutex
+ var i int
+
+ var s []sync.Mutex
+ for range s {
+ }
+ for i = range s {
+ }
+ for i := range s {
+ }
+ for i, _ = range s {
+ }
+ for i, _ := range s {
+ }
+ for _, mu = range s { // ERROR "range var mu copies Lock: sync.Mutex"
+ }
+ for _, m := range s { // ERROR "range var m copies Lock: sync.Mutex"
+ }
+ for i, mu = range s { // ERROR "range var mu copies Lock: sync.Mutex"
+ }
+ for i, m := range s { // ERROR "range var m copies Lock: sync.Mutex"
+ }
+
+ var a [3]sync.Mutex
+ for _, m := range a { // ERROR "range var m copies Lock: sync.Mutex"
+ }
+
+ var m map[sync.Mutex]sync.Mutex
+ for k := range m { // ERROR "range var k copies Lock: sync.Mutex"
+ }
+ for mu, _ = range m { // ERROR "range var mu copies Lock: sync.Mutex"
+ }
+ for k, _ := range m { // ERROR "range var k copies Lock: sync.Mutex"
+ }
+ for _, mu = range m { // ERROR "range var mu copies Lock: sync.Mutex"
+ }
+ for _, v := range m { // ERROR "range var v copies Lock: sync.Mutex"
+ }
+
+ var c chan sync.Mutex
+ for range c {
+ }
+ for mu = range c { // ERROR "range var mu copies Lock: sync.Mutex"
+ }
+ for v := range c { // ERROR "range var v copies Lock: sync.Mutex"
+ }
+
+ // Test non-idents in range variables
+ var t struct {
+ i int
+ mu sync.Mutex
+ }
+ for t.i, t.mu = range s { // ERROR "range var t.mu copies Lock: sync.Mutex"
+ }
+}
diff --git a/cmd/vet/testdata/deadcode.go b/cmd/vet/testdata/deadcode.go
new file mode 100644
index 0000000..5370bc3
--- /dev/null
+++ b/cmd/vet/testdata/deadcode.go
@@ -0,0 +1,2125 @@
+// 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 ignore
+
+// This file contains tests for the dead code checker.
+
+package testdata
+
+type T int
+
+var x interface{}
+var c chan int
+
+func external() int // ok
+
+func _() int {
+}
+
+func _() int {
+ print(1)
+}
+
+func _() int {
+ print(1)
+ return 2
+ println() // ERROR "unreachable code"
+}
+
+func _() int {
+L:
+ print(1)
+ goto L
+ println() // ERROR "unreachable code"
+}
+
+func _() int {
+ print(1)
+ panic(2)
+ println() // ERROR "unreachable code"
+}
+
+// but only builtin panic
+func _() int {
+ var panic = func(int) {}
+ print(1)
+ panic(2)
+ println() // ok
+}
+
+func _() int {
+ {
+ print(1)
+ return 2
+ println() // ERROR "unreachable code"
+ }
+ println() // ok
+}
+
+func _() int {
+ {
+ print(1)
+ return 2
+ }
+ println() // ERROR "unreachable code"
+}
+
+func _() int {
+L:
+ {
+ print(1)
+ goto L
+ println() // ERROR "unreachable code"
+ }
+ println() // ok
+}
+
+func _() int {
+L:
+ {
+ print(1)
+ goto L
+ }
+ println() // ERROR "unreachable code"
+}
+
+func _() int {
+ print(1)
+ {
+ panic(2)
+ }
+}
+
+func _() int {
+ print(1)
+ {
+ panic(2)
+ println() // ERROR "unreachable code"
+ }
+}
+
+func _() int {
+ print(1)
+ {
+ panic(2)
+ }
+ println() // ERROR "unreachable code"
+}
+
+func _() int {
+ print(1)
+ return 2
+ { // ERROR "unreachable code"
+ }
+}
+
+func _() int {
+L:
+ print(1)
+ goto L
+ { // ERROR "unreachable code"
+ }
+}
+
+func _() int {
+ print(1)
+ panic(2)
+ { // ERROR "unreachable code"
+ }
+}
+
+func _() int {
+ {
+ print(1)
+ return 2
+ { // ERROR "unreachable code"
+ }
+ }
+}
+
+func _() int {
+L:
+ {
+ print(1)
+ goto L
+ { // ERROR "unreachable code"
+ }
+ }
+}
+
+func _() int {
+ print(1)
+ {
+ panic(2)
+ { // ERROR "unreachable code"
+ }
+ }
+}
+
+func _() int {
+ {
+ print(1)
+ return 2
+ }
+ { // ERROR "unreachable code"
+ }
+}
+
+func _() int {
+L:
+ {
+ print(1)
+ goto L
+ }
+ { // ERROR "unreachable code"
+ }
+}
+
+func _() int {
+ print(1)
+ {
+ panic(2)
+ }
+ { // ERROR "unreachable code"
+ }
+}
+
+func _() int {
+ print(1)
+ if x == nil {
+ panic(2)
+ } else {
+ panic(3)
+ }
+ println() // ERROR "unreachable code"
+}
+
+func _() int {
+L:
+ print(1)
+ if x == nil {
+ panic(2)
+ } else {
+ goto L
+ }
+ println() // ERROR "unreachable code"
+}
+
+func _() int {
+L:
+ print(1)
+ if x == nil {
+ panic(2)
+ } else if x == 1 {
+ return 0
+ } else if x != 2 {
+ panic(3)
+ } else {
+ goto L
+ }
+ println() // ERROR "unreachable code"
+}
+
+// if-else chain missing final else is not okay, even if the
+// conditions cover every possible case.
+
+func _() int {
+ print(1)
+ if x == nil {
+ panic(2)
+ } else if x != nil {
+ panic(3)
+ }
+ println() // ok
+}
+
+func _() int {
+ print(1)
+ if x == nil {
+ panic(2)
+ }
+ println() // ok
+}
+
+func _() int {
+L:
+ print(1)
+ if x == nil {
+ panic(2)
+ } else if x == 1 {
+ return 0
+ } else if x != 1 {
+ panic(3)
+ }
+ println() // ok
+}
+
+func _() int {
+ print(1)
+ for {
+ }
+ println() // ERROR "unreachable code"
+}
+
+func _() int {
+ for {
+ for {
+ break
+ }
+ }
+ println() // ERROR "unreachable code"
+}
+
+func _() int {
+ for {
+ for {
+ break
+ println() // ERROR "unreachable code"
+ }
+ }
+}
+
+func _() int {
+ for {
+ for {
+ continue
+ println() // ERROR "unreachable code"
+ }
+ }
+}
+
+func _() int {
+ for {
+ L:
+ for {
+ break L
+ }
+ }
+ println() // ERROR "unreachable code"
+}
+
+func _() int {
+ print(1)
+ for {
+ break
+ }
+ println() // ok
+}
+
+func _() int {
+ for {
+ for {
+ }
+ break // ERROR "unreachable code"
+ }
+ println() // ok
+}
+
+func _() int {
+L:
+ for {
+ for {
+ break L
+ }
+ }
+ println() // ok
+}
+
+func _() int {
+ print(1)
+ for x == nil {
+ }
+ println() // ok
+}
+
+func _() int {
+ for x == nil {
+ for {
+ break
+ }
+ }
+ println() // ok
+}
+
+func _() int {
+ for x == nil {
+ L:
+ for {
+ break L
+ }
+ }
+ println() // ok
+}
+
+func _() int {
+ print(1)
+ for true {
+ }
+ println() // ok
+}
+
+func _() int {
+ for true {
+ for {
+ break
+ }
+ }
+ println() // ok
+}
+
+func _() int {
+ for true {
+ L:
+ for {
+ break L
+ }
+ }
+ println() // ok
+}
+
+func _() int {
+ print(1)
+ select {}
+ println() // ERROR "unreachable code"
+}
+
+func _() int {
+ print(1)
+ select {
+ case <-c:
+ print(2)
+ panic("abc")
+ println() // ERROR "unreachable code"
+ }
+}
+
+func _() int {
+ print(1)
+ select {
+ case <-c:
+ print(2)
+ panic("abc")
+ }
+ println() // ERROR "unreachable code"
+}
+
+func _() int {
+ print(1)
+ select {
+ case <-c:
+ print(2)
+ for {
+ }
+ println() // ERROR "unreachable code"
+ }
+}
+
+func _() int {
+ print(1)
+ select {
+ case <-c:
+ print(2)
+ for {
+ }
+ }
+ println() // ERROR "unreachable code"
+}
+
+func _() int {
+L:
+ print(1)
+ select {
+ case <-c:
+ print(2)
+ panic("abc")
+ println() // ERROR "unreachable code"
+ case c <- 1:
+ print(2)
+ goto L
+ println() // ERROR "unreachable code"
+ }
+}
+
+func _() int {
+L:
+ print(1)
+ select {
+ case <-c:
+ print(2)
+ panic("abc")
+ case c <- 1:
+ print(2)
+ goto L
+ }
+ println() // ERROR "unreachable code"
+}
+
+func _() int {
+ print(1)
+ select {
+ case <-c:
+ print(2)
+ panic("abc")
+ println() // ERROR "unreachable code"
+ default:
+ select {}
+ println() // ERROR "unreachable code"
+ }
+}
+
+func _() int {
+ print(1)
+ select {
+ case <-c:
+ print(2)
+ panic("abc")
+ default:
+ select {}
+ }
+ println() // ERROR "unreachable code"
+}
+
+func _() int {
+ print(1)
+ select {
+ case <-c:
+ print(2)
+ }
+ println() // ok
+}
+
+func _() int {
+L:
+ print(1)
+ select {
+ case <-c:
+ print(2)
+ panic("abc")
+ goto L // ERROR "unreachable code"
+ case c <- 1:
+ print(2)
+ }
+ println() // ok
+}
+
+func _() int {
+ print(1)
+ select {
+ case <-c:
+ print(2)
+ panic("abc")
+ default:
+ print(2)
+ }
+ println() // ok
+}
+
+func _() int {
+ print(1)
+ select {
+ default:
+ break
+ }
+ println() // ok
+}
+
+func _() int {
+ print(1)
+ select {
+ case <-c:
+ print(2)
+ panic("abc")
+ break // ERROR "unreachable code"
+ }
+ println() // ok
+}
+
+func _() int {
+ print(1)
+L:
+ select {
+ case <-c:
+ print(2)
+ for {
+ break L
+ }
+ }
+ println() // ok
+}
+
+func _() int {
+ print(1)
+L:
+ select {
+ case <-c:
+ print(2)
+ panic("abc")
+ case c <- 1:
+ print(2)
+ break L
+ }
+ println() // ok
+}
+
+func _() int {
+ print(1)
+ select {
+ case <-c:
+ print(1)
+ panic("abc")
+ default:
+ select {}
+ break // ERROR "unreachable code"
+ }
+ println() // ok
+}
+
+func _() int {
+ print(1)
+ switch x {
+ case 1:
+ print(2)
+ panic(3)
+ println() // ERROR "unreachable code"
+ default:
+ return 4
+ println() // ERROR "unreachable code"
+ }
+}
+
+func _() int {
+ print(1)
+ switch x {
+ case 1:
+ print(2)
+ panic(3)
+ default:
+ return 4
+ }
+ println() // ERROR "unreachable code"
+}
+
+func _() int {
+ print(1)
+ switch x {
+ default:
+ return 4
+ println() // ERROR "unreachable code"
+ case 1:
+ print(2)
+ panic(3)
+ println() // ERROR "unreachable code"
+ }
+}
+
+func _() int {
+ print(1)
+ switch x {
+ default:
+ return 4
+ case 1:
+ print(2)
+ panic(3)
+ }
+ println() // ERROR "unreachable code"
+}
+
+func _() int {
+ print(1)
+ switch x {
+ case 1:
+ print(2)
+ fallthrough
+ default:
+ return 4
+ println() // ERROR "unreachable code"
+ }
+}
+
+func _() int {
+ print(1)
+ switch x {
+ case 1:
+ print(2)
+ fallthrough
+ default:
+ return 4
+ }
+ println() // ERROR "unreachable code"
+}
+
+func _() int {
+ print(1)
+ switch {
+ }
+ println() // ok
+}
+
+func _() int {
+ print(1)
+ switch x {
+ case 1:
+ print(2)
+ panic(3)
+ case 2:
+ return 4
+ }
+ println() // ok
+}
+
+func _() int {
+ print(1)
+ switch x {
+ case 2:
+ return 4
+ case 1:
+ print(2)
+ panic(3)
+ }
+ println() // ok
+}
+
+func _() int {
+ print(1)
+ switch x {
+ case 1:
+ print(2)
+ fallthrough
+ case 2:
+ return 4
+ }
+ println() // ok
+}
+
+func _() int {
+ print(1)
+ switch x {
+ case 1:
+ print(2)
+ panic(3)
+ }
+ println() // ok
+}
+
+func _() int {
+ print(1)
+L:
+ switch x {
+ case 1:
+ print(2)
+ panic(3)
+ break L // ERROR "unreachable code"
+ default:
+ return 4
+ }
+ println() // ok
+}
+
+func _() int {
+ print(1)
+ switch x {
+ default:
+ return 4
+ break // ERROR "unreachable code"
+ case 1:
+ print(2)
+ panic(3)
+ }
+ println() // ok
+}
+
+func _() int {
+ print(1)
+L:
+ switch x {
+ case 1:
+ print(2)
+ for {
+ break L
+ }
+ default:
+ return 4
+ }
+ println() // ok
+}
+
+func _() int {
+ print(1)
+ switch x.(type) {
+ case int:
+ print(2)
+ panic(3)
+ println() // ERROR "unreachable code"
+ default:
+ return 4
+ println() // ERROR "unreachable code"
+ }
+}
+
+func _() int {
+ print(1)
+ switch x.(type) {
+ case int:
+ print(2)
+ panic(3)
+ default:
+ return 4
+ }
+ println() // ERROR "unreachable code"
+}
+
+func _() int {
+ print(1)
+ switch x.(type) {
+ default:
+ return 4
+ println() // ERROR "unreachable code"
+ case int:
+ print(2)
+ panic(3)
+ println() // ERROR "unreachable code"
+ }
+}
+
+func _() int {
+ print(1)
+ switch x.(type) {
+ default:
+ return 4
+ case int:
+ print(2)
+ panic(3)
+ }
+ println() // ERROR "unreachable code"
+}
+
+func _() int {
+ print(1)
+ switch x.(type) {
+ case int:
+ print(2)
+ fallthrough
+ default:
+ return 4
+ println() // ERROR "unreachable code"
+ }
+}
+
+func _() int {
+ print(1)
+ switch x.(type) {
+ case int:
+ print(2)
+ fallthrough
+ default:
+ return 4
+ }
+ println() // ERROR "unreachable code"
+}
+
+func _() int {
+ print(1)
+ switch {
+ }
+ println() // ok
+}
+
+func _() int {
+ print(1)
+ switch x.(type) {
+ case int:
+ print(2)
+ panic(3)
+ case float64:
+ return 4
+ }
+ println() // ok
+}
+
+func _() int {
+ print(1)
+ switch x.(type) {
+ case float64:
+ return 4
+ case int:
+ print(2)
+ panic(3)
+ }
+ println() // ok
+}
+
+func _() int {
+ print(1)
+ switch x.(type) {
+ case int:
+ print(2)
+ fallthrough
+ case float64:
+ return 4
+ }
+ println() // ok
+}
+
+func _() int {
+ print(1)
+ switch x.(type) {
+ case int:
+ print(2)
+ panic(3)
+ }
+ println() // ok
+}
+
+func _() int {
+ print(1)
+L:
+ switch x.(type) {
+ case int:
+ print(2)
+ panic(3)
+ break L // ERROR "unreachable code"
+ default:
+ return 4
+ }
+ println() // ok
+}
+
+func _() int {
+ print(1)
+ switch x.(type) {
+ default:
+ return 4
+ break // ERROR "unreachable code"
+ case int:
+ print(2)
+ panic(3)
+ }
+ println() // ok
+}
+
+func _() int {
+ print(1)
+L:
+ switch x.(type) {
+ case int:
+ print(2)
+ for {
+ break L
+ }
+ default:
+ return 4
+ }
+ println() // ok
+}
+
+// again, but without the leading print(1).
+// testing that everything works when the terminating statement is first.
+
+func _() int {
+ println() // ok
+}
+
+func _() int {
+ return 2
+ println() // ERROR "unreachable code"
+}
+
+func _() int {
+L:
+ goto L
+ println() // ERROR "unreachable code"
+}
+
+func _() int {
+ panic(2)
+ println() // ERROR "unreachable code"
+}
+
+// but only builtin panic
+func _() int {
+ var panic = func(int) {}
+ panic(2)
+ println() // ok
+}
+
+func _() int {
+ {
+ return 2
+ println() // ERROR "unreachable code"
+ }
+}
+
+func _() int {
+ {
+ return 2
+ }
+ println() // ERROR "unreachable code"
+}
+
+func _() int {
+L:
+ {
+ goto L
+ println() // ERROR "unreachable code"
+ }
+}
+
+func _() int {
+L:
+ {
+ goto L
+ }
+ println() // ERROR "unreachable code"
+}
+
+func _() int {
+ {
+ panic(2)
+ println() // ERROR "unreachable code"
+ }
+}
+
+func _() int {
+ {
+ panic(2)
+ }
+ println() // ERROR "unreachable code"
+}
+
+func _() int {
+ return 2
+ { // ERROR "unreachable code"
+ }
+ println() // ok
+}
+
+func _() int {
+L:
+ goto L
+ { // ERROR "unreachable code"
+ }
+ println() // ok
+}
+
+func _() int {
+ panic(2)
+ { // ERROR "unreachable code"
+ }
+ println() // ok
+}
+
+func _() int {
+ {
+ return 2
+ { // ERROR "unreachable code"
+ }
+ }
+ println() // ok
+}
+
+func _() int {
+L:
+ {
+ goto L
+ { // ERROR "unreachable code"
+ }
+ }
+ println() // ok
+}
+
+func _() int {
+ {
+ panic(2)
+ { // ERROR "unreachable code"
+ }
+ }
+ println() // ok
+}
+
+func _() int {
+ {
+ return 2
+ }
+ { // ERROR "unreachable code"
+ }
+ println() // ok
+}
+
+func _() int {
+L:
+ {
+ goto L
+ }
+ { // ERROR "unreachable code"
+ }
+ println() // ok
+}
+
+func _() int {
+ {
+ panic(2)
+ }
+ { // ERROR "unreachable code"
+ }
+ println() // ok
+}
+
+// again, with func literals
+
+var _ = func() int {
+}
+
+var _ = func() int {
+ print(1)
+}
+
+var _ = func() int {
+ print(1)
+ return 2
+ println() // ERROR "unreachable code"
+}
+
+var _ = func() int {
+L:
+ print(1)
+ goto L
+ println() // ERROR "unreachable code"
+}
+
+var _ = func() int {
+ print(1)
+ panic(2)
+ println() // ERROR "unreachable code"
+}
+
+// but only builtin panic
+var _ = func() int {
+ var panic = func(int) {}
+ print(1)
+ panic(2)
+ println() // ok
+}
+
+var _ = func() int {
+ {
+ print(1)
+ return 2
+ println() // ERROR "unreachable code"
+ }
+ println() // ok
+}
+
+var _ = func() int {
+ {
+ print(1)
+ return 2
+ }
+ println() // ERROR "unreachable code"
+}
+
+var _ = func() int {
+L:
+ {
+ print(1)
+ goto L
+ println() // ERROR "unreachable code"
+ }
+ println() // ok
+}
+
+var _ = func() int {
+L:
+ {
+ print(1)
+ goto L
+ }
+ println() // ERROR "unreachable code"
+}
+
+var _ = func() int {
+ print(1)
+ {
+ panic(2)
+ }
+}
+
+var _ = func() int {
+ print(1)
+ {
+ panic(2)
+ println() // ERROR "unreachable code"
+ }
+}
+
+var _ = func() int {
+ print(1)
+ {
+ panic(2)
+ }
+ println() // ERROR "unreachable code"
+}
+
+var _ = func() int {
+ print(1)
+ return 2
+ { // ERROR "unreachable code"
+ }
+}
+
+var _ = func() int {
+L:
+ print(1)
+ goto L
+ { // ERROR "unreachable code"
+ }
+}
+
+var _ = func() int {
+ print(1)
+ panic(2)
+ { // ERROR "unreachable code"
+ }
+}
+
+var _ = func() int {
+ {
+ print(1)
+ return 2
+ { // ERROR "unreachable code"
+ }
+ }
+}
+
+var _ = func() int {
+L:
+ {
+ print(1)
+ goto L
+ { // ERROR "unreachable code"
+ }
+ }
+}
+
+var _ = func() int {
+ print(1)
+ {
+ panic(2)
+ { // ERROR "unreachable code"
+ }
+ }
+}
+
+var _ = func() int {
+ {
+ print(1)
+ return 2
+ }
+ { // ERROR "unreachable code"
+ }
+}
+
+var _ = func() int {
+L:
+ {
+ print(1)
+ goto L
+ }
+ { // ERROR "unreachable code"
+ }
+}
+
+var _ = func() int {
+ print(1)
+ {
+ panic(2)
+ }
+ { // ERROR "unreachable code"
+ }
+}
+
+var _ = func() int {
+ print(1)
+ if x == nil {
+ panic(2)
+ } else {
+ panic(3)
+ }
+ println() // ERROR "unreachable code"
+}
+
+var _ = func() int {
+L:
+ print(1)
+ if x == nil {
+ panic(2)
+ } else {
+ goto L
+ }
+ println() // ERROR "unreachable code"
+}
+
+var _ = func() int {
+L:
+ print(1)
+ if x == nil {
+ panic(2)
+ } else if x == 1 {
+ return 0
+ } else if x != 2 {
+ panic(3)
+ } else {
+ goto L
+ }
+ println() // ERROR "unreachable code"
+}
+
+// if-else chain missing final else is not okay, even if the
+// conditions cover every possible case.
+
+var _ = func() int {
+ print(1)
+ if x == nil {
+ panic(2)
+ } else if x != nil {
+ panic(3)
+ }
+ println() // ok
+}
+
+var _ = func() int {
+ print(1)
+ if x == nil {
+ panic(2)
+ }
+ println() // ok
+}
+
+var _ = func() int {
+L:
+ print(1)
+ if x == nil {
+ panic(2)
+ } else if x == 1 {
+ return 0
+ } else if x != 1 {
+ panic(3)
+ }
+ println() // ok
+}
+
+var _ = func() int {
+ print(1)
+ for {
+ }
+ println() // ERROR "unreachable code"
+}
+
+var _ = func() int {
+ for {
+ for {
+ break
+ }
+ }
+ println() // ERROR "unreachable code"
+}
+
+var _ = func() int {
+ for {
+ for {
+ break
+ println() // ERROR "unreachable code"
+ }
+ }
+}
+
+var _ = func() int {
+ for {
+ for {
+ continue
+ println() // ERROR "unreachable code"
+ }
+ }
+}
+
+var _ = func() int {
+ for {
+ L:
+ for {
+ break L
+ }
+ }
+ println() // ERROR "unreachable code"
+}
+
+var _ = func() int {
+ print(1)
+ for {
+ break
+ }
+ println() // ok
+}
+
+var _ = func() int {
+ for {
+ for {
+ }
+ break // ERROR "unreachable code"
+ }
+ println() // ok
+}
+
+var _ = func() int {
+L:
+ for {
+ for {
+ break L
+ }
+ }
+ println() // ok
+}
+
+var _ = func() int {
+ print(1)
+ for x == nil {
+ }
+ println() // ok
+}
+
+var _ = func() int {
+ for x == nil {
+ for {
+ break
+ }
+ }
+ println() // ok
+}
+
+var _ = func() int {
+ for x == nil {
+ L:
+ for {
+ break L
+ }
+ }
+ println() // ok
+}
+
+var _ = func() int {
+ print(1)
+ for true {
+ }
+ println() // ok
+}
+
+var _ = func() int {
+ for true {
+ for {
+ break
+ }
+ }
+ println() // ok
+}
+
+var _ = func() int {
+ for true {
+ L:
+ for {
+ break L
+ }
+ }
+ println() // ok
+}
+
+var _ = func() int {
+ print(1)
+ select {}
+ println() // ERROR "unreachable code"
+}
+
+var _ = func() int {
+ print(1)
+ select {
+ case <-c:
+ print(2)
+ panic("abc")
+ println() // ERROR "unreachable code"
+ }
+}
+
+var _ = func() int {
+ print(1)
+ select {
+ case <-c:
+ print(2)
+ panic("abc")
+ }
+ println() // ERROR "unreachable code"
+}
+
+var _ = func() int {
+ print(1)
+ select {
+ case <-c:
+ print(2)
+ for {
+ }
+ println() // ERROR "unreachable code"
+ }
+}
+
+var _ = func() int {
+ print(1)
+ select {
+ case <-c:
+ print(2)
+ for {
+ }
+ }
+ println() // ERROR "unreachable code"
+}
+
+var _ = func() int {
+L:
+ print(1)
+ select {
+ case <-c:
+ print(2)
+ panic("abc")
+ println() // ERROR "unreachable code"
+ case c <- 1:
+ print(2)
+ goto L
+ println() // ERROR "unreachable code"
+ }
+}
+
+var _ = func() int {
+L:
+ print(1)
+ select {
+ case <-c:
+ print(2)
+ panic("abc")
+ case c <- 1:
+ print(2)
+ goto L
+ }
+ println() // ERROR "unreachable code"
+}
+
+var _ = func() int {
+ print(1)
+ select {
+ case <-c:
+ print(2)
+ panic("abc")
+ println() // ERROR "unreachable code"
+ default:
+ select {}
+ println() // ERROR "unreachable code"
+ }
+}
+
+var _ = func() int {
+ print(1)
+ select {
+ case <-c:
+ print(2)
+ panic("abc")
+ default:
+ select {}
+ }
+ println() // ERROR "unreachable code"
+}
+
+var _ = func() int {
+ print(1)
+ select {
+ case <-c:
+ print(2)
+ }
+ println() // ok
+}
+
+var _ = func() int {
+L:
+ print(1)
+ select {
+ case <-c:
+ print(2)
+ panic("abc")
+ goto L // ERROR "unreachable code"
+ case c <- 1:
+ print(2)
+ }
+ println() // ok
+}
+
+var _ = func() int {
+ print(1)
+ select {
+ case <-c:
+ print(2)
+ panic("abc")
+ default:
+ print(2)
+ }
+ println() // ok
+}
+
+var _ = func() int {
+ print(1)
+ select {
+ default:
+ break
+ }
+ println() // ok
+}
+
+var _ = func() int {
+ print(1)
+ select {
+ case <-c:
+ print(2)
+ panic("abc")
+ break // ERROR "unreachable code"
+ }
+ println() // ok
+}
+
+var _ = func() int {
+ print(1)
+L:
+ select {
+ case <-c:
+ print(2)
+ for {
+ break L
+ }
+ }
+ println() // ok
+}
+
+var _ = func() int {
+ print(1)
+L:
+ select {
+ case <-c:
+ print(2)
+ panic("abc")
+ case c <- 1:
+ print(2)
+ break L
+ }
+ println() // ok
+}
+
+var _ = func() int {
+ print(1)
+ select {
+ case <-c:
+ print(1)
+ panic("abc")
+ default:
+ select {}
+ break // ERROR "unreachable code"
+ }
+ println() // ok
+}
+
+var _ = func() int {
+ print(1)
+ switch x {
+ case 1:
+ print(2)
+ panic(3)
+ println() // ERROR "unreachable code"
+ default:
+ return 4
+ println() // ERROR "unreachable code"
+ }
+}
+
+var _ = func() int {
+ print(1)
+ switch x {
+ case 1:
+ print(2)
+ panic(3)
+ default:
+ return 4
+ }
+ println() // ERROR "unreachable code"
+}
+
+var _ = func() int {
+ print(1)
+ switch x {
+ default:
+ return 4
+ println() // ERROR "unreachable code"
+ case 1:
+ print(2)
+ panic(3)
+ println() // ERROR "unreachable code"
+ }
+}
+
+var _ = func() int {
+ print(1)
+ switch x {
+ default:
+ return 4
+ case 1:
+ print(2)
+ panic(3)
+ }
+ println() // ERROR "unreachable code"
+}
+
+var _ = func() int {
+ print(1)
+ switch x {
+ case 1:
+ print(2)
+ fallthrough
+ default:
+ return 4
+ println() // ERROR "unreachable code"
+ }
+}
+
+var _ = func() int {
+ print(1)
+ switch x {
+ case 1:
+ print(2)
+ fallthrough
+ default:
+ return 4
+ }
+ println() // ERROR "unreachable code"
+}
+
+var _ = func() int {
+ print(1)
+ switch {
+ }
+ println() // ok
+}
+
+var _ = func() int {
+ print(1)
+ switch x {
+ case 1:
+ print(2)
+ panic(3)
+ case 2:
+ return 4
+ }
+ println() // ok
+}
+
+var _ = func() int {
+ print(1)
+ switch x {
+ case 2:
+ return 4
+ case 1:
+ print(2)
+ panic(3)
+ }
+ println() // ok
+}
+
+var _ = func() int {
+ print(1)
+ switch x {
+ case 1:
+ print(2)
+ fallthrough
+ case 2:
+ return 4
+ }
+ println() // ok
+}
+
+var _ = func() int {
+ print(1)
+ switch x {
+ case 1:
+ print(2)
+ panic(3)
+ }
+ println() // ok
+}
+
+var _ = func() int {
+ print(1)
+L:
+ switch x {
+ case 1:
+ print(2)
+ panic(3)
+ break L // ERROR "unreachable code"
+ default:
+ return 4
+ }
+ println() // ok
+}
+
+var _ = func() int {
+ print(1)
+ switch x {
+ default:
+ return 4
+ break // ERROR "unreachable code"
+ case 1:
+ print(2)
+ panic(3)
+ }
+ println() // ok
+}
+
+var _ = func() int {
+ print(1)
+L:
+ switch x {
+ case 1:
+ print(2)
+ for {
+ break L
+ }
+ default:
+ return 4
+ }
+ println() // ok
+}
+
+var _ = func() int {
+ print(1)
+ switch x.(type) {
+ case int:
+ print(2)
+ panic(3)
+ println() // ERROR "unreachable code"
+ default:
+ return 4
+ println() // ERROR "unreachable code"
+ }
+}
+
+var _ = func() int {
+ print(1)
+ switch x.(type) {
+ case int:
+ print(2)
+ panic(3)
+ default:
+ return 4
+ }
+ println() // ERROR "unreachable code"
+}
+
+var _ = func() int {
+ print(1)
+ switch x.(type) {
+ default:
+ return 4
+ println() // ERROR "unreachable code"
+ case int:
+ print(2)
+ panic(3)
+ println() // ERROR "unreachable code"
+ }
+}
+
+var _ = func() int {
+ print(1)
+ switch x.(type) {
+ default:
+ return 4
+ case int:
+ print(2)
+ panic(3)
+ }
+ println() // ERROR "unreachable code"
+}
+
+var _ = func() int {
+ print(1)
+ switch x.(type) {
+ case int:
+ print(2)
+ fallthrough
+ default:
+ return 4
+ println() // ERROR "unreachable code"
+ }
+}
+
+var _ = func() int {
+ print(1)
+ switch x.(type) {
+ case int:
+ print(2)
+ fallthrough
+ default:
+ return 4
+ }
+ println() // ERROR "unreachable code"
+}
+
+var _ = func() int {
+ print(1)
+ switch {
+ }
+ println() // ok
+}
+
+var _ = func() int {
+ print(1)
+ switch x.(type) {
+ case int:
+ print(2)
+ panic(3)
+ case float64:
+ return 4
+ }
+ println() // ok
+}
+
+var _ = func() int {
+ print(1)
+ switch x.(type) {
+ case float64:
+ return 4
+ case int:
+ print(2)
+ panic(3)
+ }
+ println() // ok
+}
+
+var _ = func() int {
+ print(1)
+ switch x.(type) {
+ case int:
+ print(2)
+ fallthrough
+ case float64:
+ return 4
+ }
+ println() // ok
+}
+
+var _ = func() int {
+ print(1)
+ switch x.(type) {
+ case int:
+ print(2)
+ panic(3)
+ }
+ println() // ok
+}
+
+var _ = func() int {
+ print(1)
+L:
+ switch x.(type) {
+ case int:
+ print(2)
+ panic(3)
+ break L // ERROR "unreachable code"
+ default:
+ return 4
+ }
+ println() // ok
+}
+
+var _ = func() int {
+ print(1)
+ switch x.(type) {
+ default:
+ return 4
+ break // ERROR "unreachable code"
+ case int:
+ print(2)
+ panic(3)
+ }
+ println() // ok
+}
+
+var _ = func() int {
+ print(1)
+L:
+ switch x.(type) {
+ case int:
+ print(2)
+ for {
+ break L
+ }
+ default:
+ return 4
+ }
+ println() // ok
+}
+
+// again, but without the leading print(1).
+// testing that everything works when the terminating statement is first.
+
+var _ = func() int {
+ println() // ok
+}
+
+var _ = func() int {
+ return 2
+ println() // ERROR "unreachable code"
+}
+
+var _ = func() int {
+L:
+ goto L
+ println() // ERROR "unreachable code"
+}
+
+var _ = func() int {
+ panic(2)
+ println() // ERROR "unreachable code"
+}
+
+// but only builtin panic
+var _ = func() int {
+ var panic = func(int) {}
+ panic(2)
+ println() // ok
+}
+
+var _ = func() int {
+ {
+ return 2
+ println() // ERROR "unreachable code"
+ }
+}
+
+var _ = func() int {
+ {
+ return 2
+ }
+ println() // ERROR "unreachable code"
+}
+
+var _ = func() int {
+L:
+ {
+ goto L
+ println() // ERROR "unreachable code"
+ }
+}
+
+var _ = func() int {
+L:
+ {
+ goto L
+ }
+ println() // ERROR "unreachable code"
+}
+
+var _ = func() int {
+ {
+ panic(2)
+ println() // ERROR "unreachable code"
+ }
+}
+
+var _ = func() int {
+ {
+ panic(2)
+ }
+ println() // ERROR "unreachable code"
+}
+
+var _ = func() int {
+ return 2
+ { // ERROR "unreachable code"
+ }
+ println() // ok
+}
+
+var _ = func() int {
+L:
+ goto L
+ { // ERROR "unreachable code"
+ }
+ println() // ok
+}
+
+var _ = func() int {
+ panic(2)
+ { // ERROR "unreachable code"
+ }
+ println() // ok
+}
+
+var _ = func() int {
+ {
+ return 2
+ { // ERROR "unreachable code"
+ }
+ }
+ println() // ok
+}
+
+var _ = func() int {
+L:
+ {
+ goto L
+ { // ERROR "unreachable code"
+ }
+ }
+ println() // ok
+}
+
+var _ = func() int {
+ {
+ panic(2)
+ { // ERROR "unreachable code"
+ }
+ }
+ println() // ok
+}
+
+var _ = func() int {
+ {
+ return 2
+ }
+ { // ERROR "unreachable code"
+ }
+ println() // ok
+}
+
+var _ = func() int {
+L:
+ {
+ goto L
+ }
+ { // ERROR "unreachable code"
+ }
+ println() // ok
+}
+
+var _ = func() int {
+ {
+ panic(2)
+ }
+ { // ERROR "unreachable code"
+ }
+ println() // ok
+}
+
+var _ = func() {
+ // goto without label used to panic
+ goto
+}
diff --git a/cmd/vet/testdata/method.go b/cmd/vet/testdata/method.go
new file mode 100644
index 0000000..52b500d
--- /dev/null
+++ b/cmd/vet/testdata/method.go
@@ -0,0 +1,22 @@
+// 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.
+
+// This file contains tests for the canonical method checker.
+
+// This file contains the code to check canonical methods.
+
+package testdata
+
+import (
+ "fmt"
+)
+
+type MethodTest int
+
+func (t *MethodTest) Scan(x fmt.ScanState, c byte) { // ERROR "should have signature Scan"
+}
+
+type MethodTestInterface interface {
+ ReadByte() byte // ERROR "should have signature ReadByte"
+}
diff --git a/cmd/vet/testdata/nilfunc.go b/cmd/vet/testdata/nilfunc.go
new file mode 100644
index 0000000..2ce7bc8
--- /dev/null
+++ b/cmd/vet/testdata/nilfunc.go
@@ -0,0 +1,35 @@
+// 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 testdata
+
+func F() {}
+
+type T struct {
+ F func()
+}
+
+func (T) M() {}
+
+var Fv = F
+
+func Comparison() {
+ var t T
+ var fn func()
+ if fn == nil || Fv == nil || t.F == nil {
+ // no error; these func vars or fields may be nil
+ }
+ if F == nil { // ERROR "comparison of function F == nil is always false"
+ panic("can't happen")
+ }
+ if t.M == nil { // ERROR "comparison of function M == nil is always false"
+ panic("can't happen")
+ }
+ if F != nil { // ERROR "comparison of function F != nil is always true"
+ if t.M != nil { // ERROR "comparison of function M != nil is always true"
+ return
+ }
+ }
+ panic("can't happen")
+}
diff --git a/cmd/vet/testdata/print.go b/cmd/vet/testdata/print.go
new file mode 100644
index 0000000..3390a31
--- /dev/null
+++ b/cmd/vet/testdata/print.go
@@ -0,0 +1,342 @@
+// 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.
+
+// This file contains tests for the printf checker.
+
+package testdata
+
+import (
+ "fmt"
+ "math"
+ "os"
+ "unsafe" // just for test case printing unsafe.Pointer
+)
+
+func UnsafePointerPrintfTest() {
+ var up unsafe.Pointer
+ fmt.Printf("%p, %x %X", up, up, up)
+}
+
+// Error methods that do not satisfy the Error interface and should be checked.
+type errorTest1 int
+
+func (errorTest1) Error(...interface{}) string {
+ return "hi"
+}
+
+type errorTest2 int // Analogous to testing's *T type.
+func (errorTest2) Error(...interface{}) {
+}
+
+type errorTest3 int
+
+func (errorTest3) Error() { // No return value.
+}
+
+type errorTest4 int
+
+func (errorTest4) Error() int { // Different return type.
+ return 3
+}
+
+type errorTest5 int
+
+func (errorTest5) error() { // niladic; don't complain if no args (was bug)
+}
+
+// This function never executes, but it serves as a simple test for the program.
+// Test with make test.
+func PrintfTests() {
+ var b bool
+ var i int
+ var r rune
+ var s string
+ var x float64
+ var p *int
+ var imap map[int]int
+ var fslice []float64
+ var c complex64
+ // Some good format/argtypes
+ fmt.Printf("")
+ fmt.Printf("%b %b %b", 3, i, x)
+ fmt.Printf("%c %c %c %c", 3, i, 'x', r)
+ fmt.Printf("%d %d %d", 3, i, imap)
+ fmt.Printf("%e %e %e %e", 3e9, x, fslice, c)
+ fmt.Printf("%E %E %E %E", 3e9, x, fslice, c)
+ fmt.Printf("%f %f %f %f", 3e9, x, fslice, c)
+ fmt.Printf("%F %F %F %F", 3e9, x, fslice, c)
+ fmt.Printf("%g %g %g %g", 3e9, x, fslice, c)
+ fmt.Printf("%G %G %G %G", 3e9, x, fslice, c)
+ fmt.Printf("%b %b %b %b", 3e9, x, fslice, c)
+ fmt.Printf("%o %o", 3, i)
+ fmt.Printf("%p %p", p, nil)
+ fmt.Printf("%q %q %q %q", 3, i, 'x', r)
+ fmt.Printf("%s %s %s", "hi", s, []byte{65})
+ fmt.Printf("%t %t", true, b)
+ fmt.Printf("%T %T", 3, i)
+ fmt.Printf("%U %U", 3, i)
+ fmt.Printf("%v %v", 3, i)
+ fmt.Printf("%x %x %x %x", 3, i, "hi", s)
+ fmt.Printf("%X %X %X %X", 3, i, "hi", s)
+ fmt.Printf("%.*s %d %g", 3, "hi", 23, 2.3)
+ fmt.Printf("%s", &stringerv)
+ fmt.Printf("%v", &stringerv)
+ fmt.Printf("%T", &stringerv)
+ fmt.Printf("%v", notstringerv)
+ fmt.Printf("%T", notstringerv)
+ fmt.Printf("%q", stringerarrayv)
+ fmt.Printf("%v", stringerarrayv)
+ fmt.Printf("%s", stringerarrayv)
+ fmt.Printf("%v", notstringerarrayv)
+ fmt.Printf("%T", notstringerarrayv)
+ fmt.Printf("%d", new(Formatter))
+ fmt.Printf("%*%", 2) // Ridiculous but allowed.
+ fmt.Printf("%s", interface{}(nil)) // Nothing useful we can say.
+
+ fmt.Printf("%g", 1+2i)
+ // Some bad format/argTypes
+ fmt.Printf("%b", "hi") // ERROR "arg .hi. for printf verb %b of wrong type"
+ fmt.Printf("%t", c) // ERROR "arg c for printf verb %t of wrong type"
+ fmt.Printf("%t", 1+2i) // ERROR "arg 1 \+ 2i for printf verb %t of wrong type"
+ fmt.Printf("%c", 2.3) // ERROR "arg 2.3 for printf verb %c of wrong type"
+ fmt.Printf("%d", 2.3) // ERROR "arg 2.3 for printf verb %d of wrong type"
+ fmt.Printf("%e", "hi") // ERROR "arg .hi. for printf verb %e of wrong type"
+ fmt.Printf("%E", true) // ERROR "arg true for printf verb %E of wrong type"
+ fmt.Printf("%f", "hi") // ERROR "arg .hi. for printf verb %f of wrong type"
+ fmt.Printf("%F", 'x') // ERROR "arg 'x' for printf verb %F of wrong type"
+ fmt.Printf("%g", "hi") // ERROR "arg .hi. for printf verb %g of wrong type"
+ fmt.Printf("%g", imap) // ERROR "arg imap for printf verb %g of wrong type"
+ fmt.Printf("%G", i) // ERROR "arg i for printf verb %G of wrong type"
+ fmt.Printf("%o", x) // ERROR "arg x for printf verb %o of wrong type"
+ fmt.Printf("%p", 23) // ERROR "arg 23 for printf verb %p of wrong type"
+ fmt.Printf("%q", x) // ERROR "arg x for printf verb %q of wrong type"
+ fmt.Printf("%s", b) // ERROR "arg b for printf verb %s of wrong type"
+ fmt.Printf("%s", byte(65)) // ERROR "arg byte\(65\) for printf verb %s of wrong type"
+ fmt.Printf("%t", 23) // ERROR "arg 23 for printf verb %t of wrong type"
+ fmt.Printf("%U", x) // ERROR "arg x for printf verb %U of wrong type"
+ fmt.Printf("%x", nil) // ERROR "arg nil for printf verb %x of wrong type"
+ fmt.Printf("%X", 2.3) // ERROR "arg 2.3 for printf verb %X of wrong type"
+ fmt.Printf("%s", stringerv) // ERROR "arg stringerv for printf verb %s of wrong type"
+ fmt.Printf("%t", stringerv) // ERROR "arg stringerv for printf verb %t of wrong type"
+ fmt.Printf("%q", notstringerv) // ERROR "arg notstringerv for printf verb %q of wrong type"
+ fmt.Printf("%t", notstringerv) // ERROR "arg notstringerv for printf verb %t of wrong type"
+ fmt.Printf("%t", stringerarrayv) // ERROR "arg stringerarrayv for printf verb %t of wrong type"
+ fmt.Printf("%t", notstringerarrayv) // ERROR "arg notstringerarrayv for printf verb %t of wrong type"
+ fmt.Printf("%q", notstringerarrayv) // ERROR "arg notstringerarrayv for printf verb %q of wrong type"
+ fmt.Printf("%d", Formatter(true)) // correct (the type is responsible for formatting)
+ fmt.Printf("%s", nonemptyinterface) // correct (the dynamic type of nonemptyinterface may be a stringer)
+ fmt.Printf("%.*s %d %g", 3, "hi", 23, 'x') // ERROR "arg 'x' for printf verb %g of wrong type"
+ fmt.Println() // not an error
+ fmt.Println("%s", "hi") // ERROR "possible formatting directive in Println call"
+ fmt.Printf("%s", "hi", 3) // ERROR "wrong number of args for format in Printf call"
+ _ = fmt.Sprintf("%"+("s"), "hi", 3) // ERROR "wrong number of args for format in Sprintf call"
+ fmt.Printf("%s%%%d", "hi", 3) // correct
+ fmt.Printf("%08s", "woo") // correct
+ fmt.Printf("% 8s", "woo") // correct
+ fmt.Printf("%.*d", 3, 3) // correct
+ fmt.Printf("%.*d", 3, 3, 3, 3) // ERROR "wrong number of args for format in Printf call.*4 args"
+ fmt.Printf("%.*d", "hi", 3) // ERROR "arg .hi. for \* in printf format not of type int"
+ fmt.Printf("%.*d", i, 3) // correct
+ fmt.Printf("%.*d", s, 3) // ERROR "arg s for \* in printf format not of type int"
+ fmt.Printf("%*%", 0.22) // ERROR "arg 0.22 for \* in printf format not of type int"
+ fmt.Printf("%q %q", multi()...) // ok
+ fmt.Printf("%#q", `blah`) // ok
+ printf("now is the time", "buddy") // ERROR "no formatting directive"
+ Printf("now is the time", "buddy") // ERROR "no formatting directive"
+ Printf("hi") // ok
+ const format = "%s %s\n"
+ Printf(format, "hi", "there")
+ Printf(format, "hi") // ERROR "missing argument for Printf..%s..: format reads arg 2, have only 1"
+ Printf("%s %d %.3v %q", "str", 4) // ERROR "missing argument for Printf..%.3v..: format reads arg 3, have only 2"
+ f := new(stringer)
+ f.Warn(0, "%s", "hello", 3) // ERROR "possible formatting directive in Warn call"
+ f.Warnf(0, "%s", "hello", 3) // ERROR "wrong number of args for format in Warnf call"
+ f.Warnf(0, "%r", "hello") // ERROR "unrecognized printf verb"
+ f.Warnf(0, "%#s", "hello") // ERROR "unrecognized printf flag"
+ Printf("d%", 2) // ERROR "missing verb at end of format string in Printf call"
+ Printf("%d", percentDV)
+ Printf("%d", &percentDV)
+ Printf("%d", notPercentDV) // ERROR "arg notPercentDV for printf verb %d of wrong type"
+ Printf("%d", ¬PercentDV) // ERROR "arg ¬PercentDV for printf verb %d of wrong type"
+ Printf("%p", ¬PercentDV) // Works regardless: we print it as a pointer.
+ Printf("%s", percentSV)
+ Printf("%s", &percentSV)
+ // Good argument reorderings.
+ Printf("%[1]d", 3)
+ Printf("%[1]*d", 3, 1)
+ Printf("%[2]*[1]d", 1, 3)
+ Printf("%[2]*.[1]*[3]d", 2, 3, 4)
+ fmt.Fprintf(os.Stderr, "%[2]*.[1]*[3]d", 2, 3, 4) // Use Fprintf to make sure we count arguments correctly.
+ // Bad argument reorderings.
+ Printf("%[xd", 3) // ERROR "illegal syntax for printf argument index"
+ Printf("%[x]d", 3) // ERROR "illegal syntax for printf argument index"
+ Printf("%[3]*s", "hi", 2) // ERROR "missing argument for Printf.* reads arg 3, have only 2"
+ _ = fmt.Sprintf("%[3]d", 2) // ERROR "missing argument for Sprintf.* reads arg 3, have only 1"
+ Printf("%[2]*.[1]*[3]d", 2, "hi", 4) // ERROR "arg .hi. for \* in printf format not of type int"
+ Printf("%[0]s", "arg1") // ERROR "index value \[0\] for Printf.*; indexes start at 1"
+ Printf("%[0]d", 1) // ERROR "index value \[0\] for Printf.*; indexes start at 1"
+ // Something that satisfies the error interface.
+ var e error
+ fmt.Println(e.Error()) // ok
+ // Something that looks like an error interface but isn't, such as the (*T).Error method
+ // in the testing package.
+ var et1 errorTest1
+ fmt.Println(et1.Error()) // ERROR "no args in Error call"
+ fmt.Println(et1.Error("hi")) // ok
+ fmt.Println(et1.Error("%d", 3)) // ERROR "possible formatting directive in Error call"
+ var et2 errorTest2
+ et2.Error() // ERROR "no args in Error call"
+ et2.Error("hi") // ok, not an error method.
+ et2.Error("%d", 3) // ERROR "possible formatting directive in Error call"
+ var et3 errorTest3
+ et3.Error() // ok, not an error method.
+ var et4 errorTest4
+ et4.Error() // ok, not an error method.
+ var et5 errorTest5
+ et5.error() // ok, not an error method.
+ // Bug: used to recur forever.
+ Printf("%p %x", recursiveStructV, recursiveStructV.next)
+ Printf("%p %x", recursiveStruct1V, recursiveStruct1V.next)
+ Printf("%p %x", recursiveSliceV, recursiveSliceV)
+ Printf("%p %x", recursiveMapV, recursiveMapV)
+ // Special handling for Log.
+ math.Log(3) // OK
+ Log(3) // OK
+ Log("%d", 3) // ERROR "possible formatting directive in Log call"
+ Logf("%d", 3)
+ Logf("%d", "hi") // ERROR "arg .hi. for printf verb %d of wrong type: untyped string"
+
+}
+
+// Printf is used by the test so we must declare it.
+func Printf(format string, args ...interface{}) {
+ panic("don't call - testing only")
+}
+
+// printf is used by the test so we must declare it.
+func printf(format string, args ...interface{}) {
+ panic("don't call - testing only")
+}
+
+// multi is used by the test.
+func multi() []interface{} {
+ panic("don't call - testing only")
+}
+
+type stringer float64
+
+var stringerv stringer
+
+func (*stringer) String() string {
+ return "string"
+}
+
+func (*stringer) Warn(int, ...interface{}) string {
+ return "warn"
+}
+
+func (*stringer) Warnf(int, string, ...interface{}) string {
+ return "warnf"
+}
+
+type notstringer struct {
+ f float64
+}
+
+var notstringerv notstringer
+
+type stringerarray [4]float64
+
+func (stringerarray) String() string {
+ return "string"
+}
+
+var stringerarrayv stringerarray
+
+type notstringerarray [4]float64
+
+var notstringerarrayv notstringerarray
+
+var nonemptyinterface = interface {
+ f()
+}(nil)
+
+// A data type we can print with "%d".
+type percentDStruct struct {
+ a int
+ b []byte
+ c *float64
+}
+
+var percentDV percentDStruct
+
+// A data type we cannot print correctly with "%d".
+type notPercentDStruct struct {
+ a int
+ b []byte
+ c bool
+}
+
+var notPercentDV notPercentDStruct
+
+// A data type we can print with "%s".
+type percentSStruct struct {
+ a string
+ b []byte
+ c stringerarray
+}
+
+var percentSV percentSStruct
+
+type recursiveStringer int
+
+func (s recursiveStringer) String() string {
+ _ = fmt.Sprintf("%d", s)
+ _ = fmt.Sprintf("%#v", s)
+ _ = fmt.Sprintf("%v", s) // ERROR "arg s for printf causes recursive call to String method"
+ _ = fmt.Sprintf("%v", &s) // ERROR "arg &s for printf causes recursive call to String method"
+ _ = fmt.Sprintf("%T", s) // ok; does not recursively call String
+ return fmt.Sprintln(s) // ERROR "arg s for print causes recursive call to String method"
+}
+
+type recursivePtrStringer int
+
+func (p *recursivePtrStringer) String() string {
+ _ = fmt.Sprintf("%v", *p)
+ return fmt.Sprintln(p) // ERROR "arg p for print causes recursive call to String method"
+}
+
+type Formatter bool
+
+func (*Formatter) Format(fmt.State, rune) {
+}
+
+type RecursiveSlice []RecursiveSlice
+
+var recursiveSliceV = &RecursiveSlice{}
+
+type RecursiveMap map[int]RecursiveMap
+
+var recursiveMapV = make(RecursiveMap)
+
+type RecursiveStruct struct {
+ next *RecursiveStruct
+}
+
+var recursiveStructV = &RecursiveStruct{}
+
+type RecursiveStruct1 struct {
+ next *Recursive2Struct
+}
+
+type RecursiveStruct2 struct {
+ next *Recursive1Struct
+}
+
+var recursiveStruct1V = &RecursiveStruct1{}
+
+// Fix for issue 7149: Missing return type on String method caused fault.
+func (int) String() {
+ return ""
+}
diff --git a/cmd/vet/testdata/rangeloop.go b/cmd/vet/testdata/rangeloop.go
new file mode 100644
index 0000000..37b5940
--- /dev/null
+++ b/cmd/vet/testdata/rangeloop.go
@@ -0,0 +1,59 @@
+// 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 tests for the rangeloop checker.
+
+package testdata
+
+func RangeLoopTests() {
+ var s []int
+ for i, v := range s {
+ go func() {
+ println(i) // ERROR "range variable i captured by func literal"
+ println(v) // ERROR "range variable v captured by func literal"
+ }()
+ }
+ for i, v := range s {
+ defer func() {
+ println(i) // ERROR "range variable i captured by func literal"
+ println(v) // ERROR "range variable v captured by func literal"
+ }()
+ }
+ for i := range s {
+ go func() {
+ println(i) // ERROR "range variable i captured by func literal"
+ }()
+ }
+ for _, v := range s {
+ go func() {
+ println(v) // ERROR "range variable v captured by func literal"
+ }()
+ }
+ for i, v := range s {
+ go func() {
+ println(i, v)
+ }()
+ println("unfortunately, we don't catch the error above because of this statement")
+ }
+ for i, v := range s {
+ go func(i, v int) {
+ println(i, v)
+ }(i, v)
+ }
+ for i, v := range s {
+ i, v := i, v
+ go func() {
+ println(i, v)
+ }()
+ }
+ // If the key of the range statement is not an identifier
+ // the code should not panic (it used to).
+ var x [2]int
+ var f int
+ for x[0], f = range s {
+ go func() {
+ _ = f // ERROR "range variable f captured by func literal"
+ }()
+ }
+}
diff --git a/cmd/vet/testdata/shadow.go b/cmd/vet/testdata/shadow.go
new file mode 100644
index 0000000..34a6806
--- /dev/null
+++ b/cmd/vet/testdata/shadow.go
@@ -0,0 +1,54 @@
+// 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 tests for the shadowed variable checker.
+// Some of these errors are caught by the compiler (shadowed return parameters for example)
+// but are nonetheless useful tests.
+
+package testdata
+
+import "os"
+
+func ShadowRead(f *os.File, buf []byte) (err error) {
+ var x int
+ if f != nil {
+ err := 3 // OK - different type.
+ _ = err
+ }
+ if f != nil {
+ _, err := f.Read(buf) // ERROR "declaration of err shadows declaration at testdata/shadow.go:13"
+ if err != nil {
+ return err
+ }
+ i := 3 // OK
+ _ = i
+ }
+ if f != nil {
+ var _, err = f.Read(buf) // ERROR "declaration of err shadows declaration at testdata/shadow.go:13"
+ if err != nil {
+ return err
+ }
+ }
+ for i := 0; i < 10; i++ {
+ i := i // OK: obviously intentional idiomatic redeclaration
+ go func() {
+ println(i)
+ }()
+ }
+ var shadowTemp interface{}
+ switch shadowTemp := shadowTemp.(type) { // OK: obviously intentional idiomatic redeclaration
+ case int:
+ println("OK")
+ _ = shadowTemp
+ }
+ if shadowTemp := shadowTemp; true { // OK: obviously intentional idiomatic redeclaration
+ var f *os.File // OK because f is not mentioned later in the function.
+ // The declaration of x is a shadow because x is mentioned below.
+ var x int // ERROR "declaration of x shadows declaration at testdata/shadow.go:14"
+ _, _, _ = x, f, shadowTemp
+ }
+ // Use a couple of variables to trigger shadowing errors.
+ _, _ = err, x
+ return
+}
diff --git a/cmd/vet/testdata/shift.go b/cmd/vet/testdata/shift.go
new file mode 100644
index 0000000..6624f09
--- /dev/null
+++ b/cmd/vet/testdata/shift.go
@@ -0,0 +1,78 @@
+// 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 the suspicious shift checker.
+
+package testdata
+
+func ShiftTest() {
+ var i8 int8
+ _ = i8 << 7
+ _ = (i8 + 1) << 8 // ERROR "\(i8 \+ 1\) too small for shift of 8"
+ _ = i8 << (7 + 1) // ERROR "i8 too small for shift of 8"
+ _ = i8 >> 8 // ERROR "i8 too small for shift of 8"
+ i8 <<= 8 // ERROR "i8 too small for shift of 8"
+ i8 >>= 8 // ERROR "i8 too small for shift of 8"
+ var i16 int16
+ _ = i16 << 15
+ _ = i16 << 16 // ERROR "i16 too small for shift of 16"
+ _ = i16 >> 16 // ERROR "i16 too small for shift of 16"
+ i16 <<= 16 // ERROR "i16 too small for shift of 16"
+ i16 >>= 16 // ERROR "i16 too small for shift of 16"
+ var i32 int32
+ _ = i32 << 31
+ _ = i32 << 32 // ERROR "i32 too small for shift of 32"
+ _ = i32 >> 32 // ERROR "i32 too small for shift of 32"
+ i32 <<= 32 // ERROR "i32 too small for shift of 32"
+ i32 >>= 32 // ERROR "i32 too small for shift of 32"
+ var i64 int64
+ _ = i64 << 63
+ _ = i64 << 64 // ERROR "i64 too small for shift of 64"
+ _ = i64 >> 64 // ERROR "i64 too small for shift of 64"
+ i64 <<= 64 // ERROR "i64 too small for shift of 64"
+ i64 >>= 64 // ERROR "i64 too small for shift of 64"
+ var u8 uint8
+ _ = u8 << 7
+ _ = u8 << 8 // ERROR "u8 too small for shift of 8"
+ _ = u8 >> 8 // ERROR "u8 too small for shift of 8"
+ u8 <<= 8 // ERROR "u8 too small for shift of 8"
+ u8 >>= 8 // ERROR "u8 too small for shift of 8"
+ var u16 uint16
+ _ = u16 << 15
+ _ = u16 << 16 // ERROR "u16 too small for shift of 16"
+ _ = u16 >> 16 // ERROR "u16 too small for shift of 16"
+ u16 <<= 16 // ERROR "u16 too small for shift of 16"
+ u16 >>= 16 // ERROR "u16 too small for shift of 16"
+ var u32 uint32
+ _ = u32 << 31
+ _ = u32 << 32 // ERROR "u32 too small for shift of 32"
+ _ = u32 >> 32 // ERROR "u32 too small for shift of 32"
+ u32 <<= 32 // ERROR "u32 too small for shift of 32"
+ u32 >>= 32 // ERROR "u32 too small for shift of 32"
+ var u64 uint64
+ _ = u64 << 63
+ _ = u64 << 64 // ERROR "u64 too small for shift of 64"
+ _ = u64 >> 64 // ERROR "u64 too small for shift of 64"
+ u64 <<= 64 // ERROR "u64 too small for shift of 64"
+ u64 >>= 64 // ERROR "u64 too small for shift of 64"
+ _ = u64 << u64 // Non-constant shifts should succeed.
+ var i int
+ _ = i << 31
+ _ = i << 32 // ERROR "i might be too small for shift of 32"
+ _ = i >> 32 // ERROR "i might be too small for shift of 32"
+ i <<= 32 // ERROR "i might be too small for shift of 32"
+ i >>= 32 // ERROR "i might be too small for shift of 32"
+ var u uint
+ _ = u << 31
+ _ = u << 32 // ERROR "u might be too small for shift of 32"
+ _ = u >> 32 // ERROR "u might be too small for shift of 32"
+ u <<= 32 // ERROR "u might be too small for shift of 32"
+ u >>= 32 // ERROR "u might be too small for shift of 32"
+ var p uintptr
+ _ = p << 31
+ _ = p << 32 // ERROR "p might be too small for shift of 32"
+ _ = p >> 32 // ERROR "p might be too small for shift of 32"
+ p <<= 32 // ERROR "p might be too small for shift of 32"
+ p >>= 32 // ERROR "p might be too small for shift of 32"
+}
diff --git a/cmd/vet/testdata/structtag.go b/cmd/vet/testdata/structtag.go
new file mode 100644
index 0000000..6878f56
--- /dev/null
+++ b/cmd/vet/testdata/structtag.go
@@ -0,0 +1,36 @@
+// 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.
+
+// This file contains the test for canonical struct tags.
+
+package testdata
+
+type StructTagTest struct {
+ A int "hello" // ERROR "not compatible with reflect.StructTag.Get: bad syntax for struct tag pair"
+ B int "\tx:\"y\"" // ERROR "not compatible with reflect.StructTag.Get: bad syntax for struct tag key"
+ C int "x:\"y\"\tx:\"y\"" // ERROR "not compatible with reflect.StructTag.Get"
+ D int "x:`y`" // ERROR "not compatible with reflect.StructTag.Get: bad syntax for struct tag value"
+ E int "ct\brl:\"char\"" // ERROR "not compatible with reflect.StructTag.Get: bad syntax for struct tag pair"
+ F int `:"emptykey"` // ERROR "not compatible with reflect.StructTag.Get: bad syntax for struct tag key"
+ G int `x:"noEndQuote` // ERROR "not compatible with reflect.StructTag.Get: bad syntax for struct tag value"
+ H int `x:"trunc\x0"` // ERROR "not compatible with reflect.StructTag.Get: bad syntax for struct tag value"
+ OK0 int `x:"y" u:"v" w:""`
+ OK1 int `x:"y:z" u:"v" w:""` // note multiple colons.
+ OK2 int "k0:\"values contain spaces\" k1:\"literal\ttabs\" k2:\"and\\tescaped\\tabs\""
+ OK3 int `under_scores:"and" CAPS:"ARE_OK"`
+}
+
+type UnexportedEncodingTagTest struct {
+ x int `json:"xx"` // ERROR "struct field x has json tag but is not exported"
+ y int `xml:"yy"` // ERROR "struct field y has xml tag but is not exported"
+ z int
+ A int `json:"aa" xml:"bb"`
+}
+
+type unexp struct{}
+
+type JSONEmbeddedField struct {
+ UnexportedEncodingTagTest `is:"embedded"`
+ unexp `is:"embedded,notexported" json:"unexp"` // OK for now, see issue 7363
+}
diff --git a/cmd/vet/testdata/tagtest/file1.go b/cmd/vet/testdata/tagtest/file1.go
new file mode 100644
index 0000000..22a1509
--- /dev/null
+++ b/cmd/vet/testdata/tagtest/file1.go
@@ -0,0 +1,10 @@
+// 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.
+
+// +build testtag
+
+package main
+
+func main() {
+}
diff --git a/cmd/vet/testdata/tagtest/file2.go b/cmd/vet/testdata/tagtest/file2.go
new file mode 100644
index 0000000..ba7dd91
--- /dev/null
+++ b/cmd/vet/testdata/tagtest/file2.go
@@ -0,0 +1,10 @@
+// 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.
+
+// +build !testtag
+
+package main
+
+func ignore() {
+}
diff --git a/cmd/vet/testdata/unsafeptr.go b/cmd/vet/testdata/unsafeptr.go
new file mode 100644
index 0000000..8f64030
--- /dev/null
+++ b/cmd/vet/testdata/unsafeptr.go
@@ -0,0 +1,61 @@
+// 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 testdata
+
+import (
+ "reflect"
+ "unsafe"
+)
+
+func f() {
+ var x unsafe.Pointer
+ var y uintptr
+ x = unsafe.Pointer(y) // ERROR "possible misuse of unsafe.Pointer"
+ y = uintptr(x)
+
+ // only allowed pointer arithmetic is ptr +/- num.
+ // num+ptr is technically okay but still flagged: write ptr+num instead.
+ x = unsafe.Pointer(uintptr(x) + 1)
+ x = unsafe.Pointer(1 + uintptr(x)) // ERROR "possible misuse of unsafe.Pointer"
+ x = unsafe.Pointer(uintptr(x) + uintptr(x)) // ERROR "possible misuse of unsafe.Pointer"
+ x = unsafe.Pointer(uintptr(x) - 1)
+ x = unsafe.Pointer(1 - uintptr(x)) // ERROR "possible misuse of unsafe.Pointer"
+
+ // certain uses of reflect are okay
+ var v reflect.Value
+ x = unsafe.Pointer(v.Pointer())
+ x = unsafe.Pointer(v.UnsafeAddr())
+ var s1 *reflect.StringHeader
+ x = unsafe.Pointer(s1.Data)
+ var s2 *reflect.SliceHeader
+ x = unsafe.Pointer(s2.Data)
+ var s3 reflect.StringHeader
+ x = unsafe.Pointer(s3.Data) // ERROR "possible misuse of unsafe.Pointer"
+ var s4 reflect.SliceHeader
+ x = unsafe.Pointer(s4.Data) // ERROR "possible misuse of unsafe.Pointer"
+
+ // but only in reflect
+ var vv V
+ x = unsafe.Pointer(vv.Pointer()) // ERROR "possible misuse of unsafe.Pointer"
+ x = unsafe.Pointer(vv.UnsafeAddr()) // ERROR "possible misuse of unsafe.Pointer"
+ var ss1 *StringHeader
+ x = unsafe.Pointer(ss1.Data) // ERROR "possible misuse of unsafe.Pointer"
+ var ss2 *SliceHeader
+ x = unsafe.Pointer(ss2.Data) // ERROR "possible misuse of unsafe.Pointer"
+
+}
+
+type V interface {
+ Pointer() uintptr
+ UnsafeAddr() uintptr
+}
+
+type StringHeader struct {
+ Data uintptr
+}
+
+type SliceHeader struct {
+ Data uintptr
+}
diff --git a/cmd/vet/testdata/unused.go b/cmd/vet/testdata/unused.go
new file mode 100644
index 0000000..d50f659
--- /dev/null
+++ b/cmd/vet/testdata/unused.go
@@ -0,0 +1,29 @@
+// 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.
+
+// This file contains tests for the unusedresult checker.
+
+package testdata
+
+import (
+ "bytes"
+ "errors"
+ "fmt"
+)
+
+func _() {
+ fmt.Errorf("") // ERROR "result of fmt.Errorf call not used"
+ _ = fmt.Errorf("")
+
+ errors.New("") // ERROR "result of errors.New call not used"
+
+ err := errors.New("")
+ err.Error() // ERROR "result of \(error\).Error call not used"
+
+ var buf bytes.Buffer
+ buf.String() // ERROR "result of \(bytes.Buffer\).String call not used"
+
+ fmt.Sprint("") // ERROR "result of fmt.Sprint call not used"
+ fmt.Sprintf("") // ERROR "result of fmt.Sprintf call not used"
+}
diff --git a/cmd/vet/types.go b/cmd/vet/types.go
new file mode 100644
index 0000000..084be85
--- /dev/null
+++ b/cmd/vet/types.go
@@ -0,0 +1,369 @@
+// 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.
+
+// This file contains the pieces of the tool that use typechecking from the go/types package.
+
+package main
+
+import (
+ "go/ast"
+ "go/token"
+
+ "golang.org/x/tools/go/types"
+)
+
+// imports is the canonical map of imported packages we need for typechecking.
+// It is created during initialization.
+var imports = make(map[string]*types.Package)
+
+var (
+ errorType *types.Interface
+ stringerType *types.Interface // possibly nil
+ formatterType *types.Interface // possibly nil
+)
+
+func init() {
+ errorType = types.Universe.Lookup("error").Type().Underlying().(*types.Interface)
+
+ if typ := importType("fmt", "Stringer"); typ != nil {
+ stringerType = typ.Underlying().(*types.Interface)
+ }
+
+ if typ := importType("fmt", "Formatter"); typ != nil {
+ formatterType = typ.Underlying().(*types.Interface)
+ }
+}
+
+// importType returns the type denoted by the qualified identifier
+// path.name, and adds the respective package to the imports map
+// as a side effect. In case of an error, importType returns nil.
+func importType(path, name string) types.Type {
+ pkg, err := types.DefaultImport(imports, path)
+ if err != nil {
+ // This can happen if the package at path hasn't been compiled yet.
+ warnf("import failed: %v", err)
+ return nil
+ }
+ if obj, ok := pkg.Scope().Lookup(name).(*types.TypeName); ok {
+ return obj.Type()
+ }
+ warnf("invalid type name %q", name)
+ return nil
+}
+
+func (pkg *Package) check(fs *token.FileSet, astFiles []*ast.File) error {
+ pkg.defs = make(map[*ast.Ident]types.Object)
+ pkg.uses = make(map[*ast.Ident]types.Object)
+ pkg.selectors = make(map[*ast.SelectorExpr]*types.Selection)
+ pkg.spans = make(map[types.Object]Span)
+ pkg.types = make(map[ast.Expr]types.TypeAndValue)
+ config := types.Config{
+ // We provide the same packages map for all imports to ensure
+ // that everybody sees identical packages for the given paths.
+ Packages: imports,
+ // By providing a Config with our own error function, it will continue
+ // past the first error. There is no need for that function to do anything.
+ Error: func(error) {},
+ }
+ info := &types.Info{
+ Selections: pkg.selectors,
+ Types: pkg.types,
+ Defs: pkg.defs,
+ Uses: pkg.uses,
+ }
+ typesPkg, err := config.Check(pkg.path, fs, astFiles, info)
+ pkg.typesPkg = typesPkg
+ // update spans
+ for id, obj := range pkg.defs {
+ pkg.growSpan(id, obj)
+ }
+ for id, obj := range pkg.uses {
+ pkg.growSpan(id, obj)
+ }
+ return err
+}
+
+// isStruct reports whether the composite literal c is a struct.
+// If it is not (probably a struct), it returns a printable form of the type.
+func (pkg *Package) isStruct(c *ast.CompositeLit) (bool, string) {
+ // Check that the CompositeLit's type is a slice or array (which needs no field keys), if possible.
+ typ := pkg.types[c].Type
+ // If it's a named type, pull out the underlying type. If it's not, the Underlying
+ // method returns the type itself.
+ actual := typ
+ if actual != nil {
+ actual = actual.Underlying()
+ }
+ if actual == nil {
+ // No type information available. Assume true, so we do the check.
+ return true, ""
+ }
+ switch actual.(type) {
+ case *types.Struct:
+ return true, typ.String()
+ default:
+ return false, ""
+ }
+}
+
+// matchArgType reports an error if printf verb t is not appropriate
+// for operand arg.
+//
+// typ is used only for recursive calls; external callers must supply nil.
+//
+// (Recursion arises from the compound types {map,chan,slice} which
+// may be printed with %d etc. if that is appropriate for their element
+// types.)
+func (f *File) matchArgType(t printfArgType, typ types.Type, arg ast.Expr) bool {
+ return f.matchArgTypeInternal(t, typ, arg, make(map[types.Type]bool))
+}
+
+// matchArgTypeInternal is the internal version of matchArgType. It carries a map
+// remembering what types are in progress so we don't recur when faced with recursive
+// types or mutually recursive types.
+func (f *File) matchArgTypeInternal(t printfArgType, typ types.Type, arg ast.Expr, inProgress map[types.Type]bool) bool {
+ // %v, %T accept any argument type.
+ if t == anyType {
+ return true
+ }
+ if typ == nil {
+ // external call
+ typ = f.pkg.types[arg].Type
+ if typ == nil {
+ return true // probably a type check problem
+ }
+ }
+ // If the type implements fmt.Formatter, we have nothing to check.
+ // formatterTyp may be nil - be conservative and check for Format method in that case.
+ if formatterType != nil && types.Implements(typ, formatterType) || f.hasMethod(typ, "Format") {
+ return true
+ }
+ // If we can use a string, might arg (dynamically) implement the Stringer or Error interface?
+ if t&argString != 0 {
+ if types.AssertableTo(errorType, typ) || stringerType != nil && types.AssertableTo(stringerType, typ) {
+ return true
+ }
+ }
+
+ typ = typ.Underlying()
+ if inProgress[typ] {
+ // We're already looking at this type. The call that started it will take care of it.
+ return true
+ }
+ inProgress[typ] = true
+
+ switch typ := typ.(type) {
+ case *types.Signature:
+ return t&argPointer != 0
+
+ case *types.Map:
+ // Recur: map[int]int matches %d.
+ return t&argPointer != 0 ||
+ (f.matchArgTypeInternal(t, typ.Key(), arg, inProgress) && f.matchArgTypeInternal(t, typ.Elem(), arg, inProgress))
+
+ case *types.Chan:
+ return t&argPointer != 0
+
+ case *types.Array:
+ // Same as slice.
+ if types.Identical(typ.Elem().Underlying(), types.Typ[types.Byte]) && t&argString != 0 {
+ return true // %s matches []byte
+ }
+ // Recur: []int matches %d.
+ return t&argPointer != 0 || f.matchArgTypeInternal(t, typ.Elem().Underlying(), arg, inProgress)
+
+ case *types.Slice:
+ // Same as array.
+ if types.Identical(typ.Elem().Underlying(), types.Typ[types.Byte]) && t&argString != 0 {
+ return true // %s matches []byte
+ }
+ // Recur: []int matches %d. But watch out for
+ // type T []T
+ // If the element is a pointer type (type T[]*T), it's handled fine by the Pointer case below.
+ return t&argPointer != 0 || f.matchArgTypeInternal(t, typ.Elem(), arg, inProgress)
+
+ case *types.Pointer:
+ // Ugly, but dealing with an edge case: a known pointer to an invalid type,
+ // probably something from a failed import.
+ if typ.Elem().String() == "invalid type" {
+ if *verbose {
+ f.Warnf(arg.Pos(), "printf argument %v is pointer to invalid or unknown type", f.gofmt(arg))
+ }
+ return true // special case
+ }
+ // If it's actually a pointer with %p, it prints as one.
+ if t == argPointer {
+ return true
+ }
+ // If it's pointer to struct, that's equivalent in our analysis to whether we can print the struct.
+ if str, ok := typ.Elem().Underlying().(*types.Struct); ok {
+ return f.matchStructArgType(t, str, arg, inProgress)
+ }
+ // The rest can print with %p as pointers, or as integers with %x etc.
+ return t&(argInt|argPointer) != 0
+
+ case *types.Struct:
+ return f.matchStructArgType(t, typ, arg, inProgress)
+
+ case *types.Interface:
+ // If the static type of the argument is empty interface, there's little we can do.
+ // Example:
+ // func f(x interface{}) { fmt.Printf("%s", x) }
+ // Whether x is valid for %s depends on the type of the argument to f. One day
+ // we will be able to do better. For now, we assume that empty interface is OK
+ // but non-empty interfaces, with Stringer and Error handled above, are errors.
+ return typ.NumMethods() == 0
+
+ case *types.Basic:
+ switch typ.Kind() {
+ case types.UntypedBool,
+ types.Bool:
+ return t&argBool != 0
+
+ case types.UntypedInt,
+ types.Int,
+ types.Int8,
+ types.Int16,
+ types.Int32,
+ types.Int64,
+ types.Uint,
+ types.Uint8,
+ types.Uint16,
+ types.Uint32,
+ types.Uint64,
+ types.Uintptr:
+ return t&argInt != 0
+
+ case types.UntypedFloat,
+ types.Float32,
+ types.Float64:
+ return t&argFloat != 0
+
+ case types.UntypedComplex,
+ types.Complex64,
+ types.Complex128:
+ return t&argComplex != 0
+
+ case types.UntypedString,
+ types.String:
+ return t&argString != 0
+
+ case types.UnsafePointer:
+ return t&(argPointer|argInt) != 0
+
+ case types.UntypedRune:
+ return t&(argInt|argRune) != 0
+
+ case types.UntypedNil:
+ return t&argPointer != 0 // TODO?
+
+ case types.Invalid:
+ if *verbose {
+ f.Warnf(arg.Pos(), "printf argument %v has invalid or unknown type", f.gofmt(arg))
+ }
+ return true // Probably a type check problem.
+ }
+ panic("unreachable")
+ }
+
+ return false
+}
+
+// hasBasicType reports whether x's type is a types.Basic with the given kind.
+func (f *File) hasBasicType(x ast.Expr, kind types.BasicKind) bool {
+ t := f.pkg.types[x].Type
+ if t != nil {
+ t = t.Underlying()
+ }
+ b, ok := t.(*types.Basic)
+ return ok && b.Kind() == kind
+}
+
+// matchStructArgType reports whether all the elements of the struct match the expected
+// type. For instance, with "%d" all the elements must be printable with the "%d" format.
+func (f *File) matchStructArgType(t printfArgType, typ *types.Struct, arg ast.Expr, inProgress map[types.Type]bool) bool {
+ for i := 0; i < typ.NumFields(); i++ {
+ if !f.matchArgTypeInternal(t, typ.Field(i).Type(), arg, inProgress) {
+ return false
+ }
+ }
+ return true
+}
+
+// numArgsInSignature tells how many formal arguments the function type
+// being called has.
+func (f *File) numArgsInSignature(call *ast.CallExpr) int {
+ // Check the type of the function or method declaration
+ typ := f.pkg.types[call.Fun].Type
+ if typ == nil {
+ return 0
+ }
+ // The type must be a signature, but be sure for safety.
+ sig, ok := typ.(*types.Signature)
+ if !ok {
+ return 0
+ }
+ return sig.Params().Len()
+}
+
+// isErrorMethodCall reports whether the call is of a method with signature
+// func Error() string
+// where "string" is the universe's string type. We know the method is called "Error".
+func (f *File) isErrorMethodCall(call *ast.CallExpr) bool {
+ typ := f.pkg.types[call].Type
+ if typ != nil {
+ // We know it's called "Error", so just check the function signature
+ // (stringerType has exactly one method, String).
+ if stringerType != nil && stringerType.NumMethods() == 1 {
+ return types.Identical(f.pkg.types[call.Fun].Type, stringerType.Method(0).Type())
+ }
+ }
+ // Without types, we can still check by hand.
+ // Is it a selector expression? Otherwise it's a function call, not a method call.
+ sel, ok := call.Fun.(*ast.SelectorExpr)
+ if !ok {
+ return false
+ }
+ // The package is type-checked, so if there are no arguments, we're done.
+ if len(call.Args) > 0 {
+ return false
+ }
+ // Check the type of the method declaration
+ typ = f.pkg.types[sel].Type
+ if typ == nil {
+ return false
+ }
+ // The type must be a signature, but be sure for safety.
+ sig, ok := typ.(*types.Signature)
+ if !ok {
+ return false
+ }
+ // There must be a receiver for it to be a method call. Otherwise it is
+ // a function, not something that satisfies the error interface.
+ if sig.Recv() == nil {
+ return false
+ }
+ // There must be no arguments. Already verified by type checking, but be thorough.
+ if sig.Params().Len() > 0 {
+ return false
+ }
+ // Finally the real questions.
+ // There must be one result.
+ if sig.Results().Len() != 1 {
+ return false
+ }
+ // It must have return type "string" from the universe.
+ return sig.Results().At(0).Type() == types.Typ[types.String]
+}
+
+// hasMethod reports whether the type contains a method with the given name.
+// It is part of the workaround for Formatters and should be deleted when
+// that workaround is no longer necessary.
+// TODO: This could be better once issue 6259 is fixed.
+func (f *File) hasMethod(typ types.Type, name string) bool {
+ // assume we have an addressable variable of type typ
+ obj, _, _ := types.LookupFieldOrMethod(typ, true, f.pkg.typesPkg, name)
+ _, ok := obj.(*types.Func)
+ return ok
+}
diff --git a/cmd/vet/unsafeptr.go b/cmd/vet/unsafeptr.go
new file mode 100644
index 0000000..ca15f72
--- /dev/null
+++ b/cmd/vet/unsafeptr.go
@@ -0,0 +1,98 @@
+// 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.
+
+// Check for invalid uintptr -> unsafe.Pointer conversions.
+
+package main
+
+import (
+ "go/ast"
+ "go/token"
+
+ "golang.org/x/tools/go/types"
+)
+
+func init() {
+ register("unsafeptr",
+ "check for misuse of unsafe.Pointer",
+ checkUnsafePointer,
+ callExpr)
+}
+
+func checkUnsafePointer(f *File, node ast.Node) {
+ x := node.(*ast.CallExpr)
+ if len(x.Args) != 1 {
+ return
+ }
+ if f.hasBasicType(x.Fun, types.UnsafePointer) && f.hasBasicType(x.Args[0], types.Uintptr) && !f.isSafeUintptr(x.Args[0]) {
+ f.Badf(x.Pos(), "possible misuse of unsafe.Pointer")
+ }
+}
+
+// isSafeUintptr reports whether x - already known to be a uintptr -
+// is safe to convert to unsafe.Pointer. It is safe if x is itself derived
+// directly from an unsafe.Pointer via conversion and pointer arithmetic
+// or if x is the result of reflect.Value.Pointer or reflect.Value.UnsafeAddr
+// or obtained from the Data field of a *reflect.SliceHeader or *reflect.StringHeader.
+func (f *File) isSafeUintptr(x ast.Expr) bool {
+ switch x := x.(type) {
+ case *ast.ParenExpr:
+ return f.isSafeUintptr(x.X)
+
+ case *ast.SelectorExpr:
+ switch x.Sel.Name {
+ case "Data":
+ // reflect.SliceHeader and reflect.StringHeader are okay,
+ // but only if they are pointing at a real slice or string.
+ // It's not okay to do:
+ // var x SliceHeader
+ // x.Data = uintptr(unsafe.Pointer(...))
+ // ... use x ...
+ // p := unsafe.Pointer(x.Data)
+ // because in the middle the garbage collector doesn't
+ // see x.Data as a pointer and so x.Data may be dangling
+ // by the time we get to the conversion at the end.
+ // For now approximate by saying that *Header is okay
+ // but Header is not.
+ pt, ok := f.pkg.types[x.X].Type.(*types.Pointer)
+ if ok {
+ t, ok := pt.Elem().(*types.Named)
+ if ok && t.Obj().Pkg().Path() == "reflect" {
+ switch t.Obj().Name() {
+ case "StringHeader", "SliceHeader":
+ return true
+ }
+ }
+ }
+ }
+
+ case *ast.CallExpr:
+ switch len(x.Args) {
+ case 0:
+ // maybe call to reflect.Value.Pointer or reflect.Value.UnsafeAddr.
+ sel, ok := x.Fun.(*ast.SelectorExpr)
+ if !ok {
+ break
+ }
+ switch sel.Sel.Name {
+ case "Pointer", "UnsafeAddr":
+ t, ok := f.pkg.types[sel.X].Type.(*types.Named)
+ if ok && t.Obj().Pkg().Path() == "reflect" && t.Obj().Name() == "Value" {
+ return true
+ }
+ }
+
+ case 1:
+ // maybe conversion of uintptr to unsafe.Pointer
+ return f.hasBasicType(x.Fun, types.Uintptr) && f.hasBasicType(x.Args[0], types.UnsafePointer)
+ }
+
+ case *ast.BinaryExpr:
+ switch x.Op {
+ case token.ADD, token.SUB:
+ return f.isSafeUintptr(x.X) && !f.isSafeUintptr(x.Y)
+ }
+ }
+ return false
+}
diff --git a/cmd/vet/unused.go b/cmd/vet/unused.go
new file mode 100644
index 0000000..b9d7b65
--- /dev/null
+++ b/cmd/vet/unused.go
@@ -0,0 +1,94 @@
+// 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.
+
+// This file defines the check for unused results of calls to certain
+// pure functions.
+
+package main
+
+import (
+ "flag"
+ "go/ast"
+ "go/token"
+ "strings"
+
+ "golang.org/x/tools/go/types"
+)
+
+var unusedFuncsFlag = flag.String("unusedfuncs",
+ "errors.New,fmt.Errorf,fmt.Sprintf,fmt.Sprint,sort.Reverse",
+ "comma-separated list of functions whose results must be used")
+
+var unusedStringMethodsFlag = flag.String("unusedstringmethods",
+ "Error,String",
+ "comma-separated list of names of methods of type func() string whose results must be used")
+
+func init() {
+ register("unusedresult",
+ "check for unused result of calls to functions in -unusedfuncs list and methods in -unusedstringmethods list",
+ checkUnusedResult,
+ exprStmt)
+}
+
+// func() string
+var sigNoArgsStringResult = types.NewSignature(nil, nil,
+ types.NewTuple(types.NewVar(token.NoPos, nil, "", types.Typ[types.String])),
+ false)
+
+var unusedFuncs = make(map[string]bool)
+var unusedStringMethods = make(map[string]bool)
+
+func initUnusedFlags() {
+ commaSplit := func(s string, m map[string]bool) {
+ if s != "" {
+ for _, name := range strings.Split(s, ",") {
+ if len(name) == 0 {
+ flag.Usage()
+ }
+ m[name] = true
+ }
+ }
+ }
+ commaSplit(*unusedFuncsFlag, unusedFuncs)
+ commaSplit(*unusedStringMethodsFlag, unusedStringMethods)
+}
+
+func checkUnusedResult(f *File, n ast.Node) {
+ call, ok := unparen(n.(*ast.ExprStmt).X).(*ast.CallExpr)
+ if !ok {
+ return // not a call statement
+ }
+ fun := unparen(call.Fun)
+
+ if f.pkg.types[fun].IsType() {
+ return // a conversion, not a call
+ }
+
+ selector, ok := fun.(*ast.SelectorExpr)
+ if !ok {
+ return // neither a method call nor a qualified ident
+ }
+
+ sel, ok := f.pkg.selectors[selector]
+ if ok && sel.Kind() == types.MethodVal {
+ // method (e.g. foo.String())
+ obj := sel.Obj().(*types.Func)
+ sig := sel.Type().(*types.Signature)
+ if types.Identical(sig, sigNoArgsStringResult) {
+ if unusedStringMethods[obj.Name()] {
+ f.Badf(call.Lparen, "result of (%s).%s call not used",
+ sig.Recv().Type(), obj.Name())
+ }
+ }
+ } else if !ok {
+ // package-qualified function (e.g. fmt.Errorf)
+ obj, _ := f.pkg.uses[selector.Sel]
+ if obj, ok := obj.(*types.Func); ok {
+ qname := obj.Pkg().Path() + "." + obj.Name()
+ if unusedFuncs[qname] {
+ f.Badf(call.Lparen, "result of %v call not used", qname)
+ }
+ }
+ }
+}
diff --git a/cmd/vet/vet_test.go b/cmd/vet/vet_test.go
new file mode 100644
index 0000000..6a09e3d
--- /dev/null
+++ b/cmd/vet/vet_test.go
@@ -0,0 +1,106 @@
+// 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"
+ "os"
+ "os/exec"
+ "path/filepath"
+ "runtime"
+ "testing"
+)
+
+const (
+ dataDir = "testdata"
+ binary = "testvet.exe"
+)
+
+// Run this shell script, but do it in Go so it can be run by "go test".
+// go build -o testvet
+// $(GOROOT)/test/errchk ./testvet -shadow -printfuncs='Warn:1,Warnf:1' testdata/*.go testdata/*.s
+// rm testvet
+//
+func TestVet(t *testing.T) {
+ // Plan 9 and Windows systems can't be guaranteed to have Perl and so can't run errchk.
+ switch runtime.GOOS {
+ case "plan9", "windows":
+ t.Skip("skipping test; no Perl on %q", runtime.GOOS)
+ }
+
+ // go build
+ cmd := exec.Command("go", "build", "-o", binary)
+ run(cmd, t)
+
+ // defer removal of vet
+ defer os.Remove(binary)
+
+ // errchk ./testvet
+ gos, err := filepath.Glob(filepath.Join(dataDir, "*.go"))
+ if err != nil {
+ t.Fatal(err)
+ }
+ asms, err := filepath.Glob(filepath.Join(dataDir, "*.s"))
+ if err != nil {
+ t.Fatal(err)
+ }
+ files := append(gos, asms...)
+ errchk := filepath.Join(runtime.GOROOT(), "test", "errchk")
+ flags := []string{
+ "./" + binary,
+ "-printfuncs=Warn:1,Warnf:1",
+ "-test", // TODO: Delete once -shadow is part of -all.
+ }
+ cmd = exec.Command(errchk, append(flags, files...)...)
+ if !run(cmd, t) {
+ t.Fatal("vet command failed")
+ }
+}
+
+func run(c *exec.Cmd, t *testing.T) bool {
+ output, err := c.CombinedOutput()
+ os.Stderr.Write(output)
+ if err != nil {
+ t.Fatal(err)
+ }
+ // Errchk delights by not returning non-zero status if it finds errors, so we look at the output.
+ // It prints "BUG" if there is a failure.
+ if !c.ProcessState.Success() {
+ return false
+ }
+ return !bytes.Contains(output, []byte("BUG"))
+}
+
+// TestTags verifies that the -tags argument controls which files to check.
+func TestTags(t *testing.T) {
+ // go build
+ cmd := exec.Command("go", "build", "-o", binary)
+ run(cmd, t)
+
+ // defer removal of vet
+ defer os.Remove(binary)
+
+ args := []string{
+ "-tags=testtag",
+ "-v", // We're going to look at the files it examines.
+ "testdata/tagtest",
+ }
+ cmd = exec.Command("./"+binary, args...)
+ output, err := cmd.CombinedOutput()
+ if err != nil {
+ t.Fatal(err)
+ }
+ // file1 has testtag and file2 has !testtag.
+ if !bytes.Contains(output, []byte(filepath.Join("tagtest", "file1.go"))) {
+ t.Error("file1 was excluded, should be included")
+ }
+ if bytes.Contains(output, []byte(filepath.Join("tagtest", "file2.go"))) {
+ t.Error("file2 was included, should be excluded")
+ }
+}
diff --git a/cmd/vet/whitelist/whitelist.go b/cmd/vet/whitelist/whitelist.go
new file mode 100644
index 0000000..d6f0dce
--- /dev/null
+++ b/cmd/vet/whitelist/whitelist.go
@@ -0,0 +1,53 @@
+// 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 whitelist defines exceptions for the vet tool.
+package whitelist // import "golang.org/x/tools/cmd/vet/whitelist"
+
+// UnkeyedLiteral are types that are actually slices, but
+// syntactically, we cannot tell whether the Typ in pkg.Typ{1, 2, 3}
+// is a slice or a struct, so we whitelist all the standard package
+// library's exported slice types.
+var UnkeyedLiteral = map[string]bool{
+ /*
+ find $GOROOT/src -type f | grep -v _test.go | xargs grep '^type.*\[\]' | \
+ grep -v ' map\[' | sed 's,/[^/]*go.type,,' | sed 's,.*src/,,' | \
+ sed 's, ,.,' | sed 's, .*,,' | grep -v '\.[a-z]' | \
+ sort | awk '{ print "\"" $0 "\": true," }'
+ */
+ "crypto/x509/pkix.RDNSequence": true,
+ "crypto/x509/pkix.RelativeDistinguishedNameSET": true,
+ "database/sql.RawBytes": true,
+ "debug/macho.LoadBytes": true,
+ "encoding/asn1.ObjectIdentifier": true,
+ "encoding/asn1.RawContent": true,
+ "encoding/json.RawMessage": true,
+ "encoding/xml.CharData": true,
+ "encoding/xml.Comment": true,
+ "encoding/xml.Directive": true,
+ "go/scanner.ErrorList": true,
+ "image/color.Palette": true,
+ "net.HardwareAddr": true,
+ "net.IP": true,
+ "net.IPMask": true,
+ "sort.Float64Slice": true,
+ "sort.IntSlice": true,
+ "sort.StringSlice": true,
+ "unicode.SpecialCase": true,
+
+ // These image and image/color struct types are frozen. We will never add fields to them.
+ "image/color.Alpha16": true,
+ "image/color.Alpha": true,
+ "image/color.CMYK": true,
+ "image/color.Gray16": true,
+ "image/color.Gray": true,
+ "image/color.NRGBA64": true,
+ "image/color.NRGBA": true,
+ "image/color.RGBA64": true,
+ "image/color.RGBA": true,
+ "image/color.YCbCr": true,
+ "image.Point": true,
+ "image.Rectangle": true,
+ "image.Uniform": true,
+}
diff --git a/codereview.cfg b/codereview.cfg
new file mode 100644
index 0000000..3f8b14b
--- /dev/null
+++ b/codereview.cfg
@@ -0,0 +1 @@
+issuerepo: golang/go
diff --git a/container/intsets/sparse.go b/container/intsets/sparse.go
new file mode 100644
index 0000000..8847feb
--- /dev/null
+++ b/container/intsets/sparse.go
@@ -0,0 +1,967 @@
+// 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 intsets provides Sparse, a compact and fast representation
+// for sparse sets of int values.
+//
+// The time complexity of the operations Len, Insert, Remove and Has
+// is in O(n) but in practice those methods are faster and more
+// space-efficient than equivalent operations on sets based on the Go
+// map type. The IsEmpty, Min, Max, Clear and TakeMin operations
+// require constant time.
+//
+package intsets // import "golang.org/x/tools/container/intsets"
+
+// TODO(adonovan):
+// - Add InsertAll(...int), RemoveAll(...int)
+// - Add 'bool changed' results for {Intersection,Difference}With too.
+//
+// TODO(adonovan): implement Dense, a dense bit vector with a similar API.
+// The space usage would be proportional to Max(), not Len(), and the
+// implementation would be based upon big.Int.
+//
+// TODO(adonovan): experiment with making the root block indirect (nil
+// iff IsEmpty). This would reduce the memory usage when empty and
+// might simplify the aliasing invariants.
+//
+// TODO(adonovan): opt: make UnionWith and Difference faster.
+// These are the hot-spots for go/pointer.
+
+import (
+ "bytes"
+ "fmt"
+)
+
+// A Sparse is a set of int values.
+// Sparse operations (even queries) are not concurrency-safe.
+//
+// The zero value for Sparse is a valid empty set.
+//
+// Sparse sets must be copied using the Copy method, not by assigning
+// a Sparse value.
+//
+type Sparse struct {
+ // An uninitialized Sparse represents an empty set.
+ // An empty set may also be represented by
+ // root.next == root.prev == &root.
+ // In a non-empty set, root.next points to the first block and
+ // root.prev to the last.
+ // root.offset and root.bits are unused.
+ root block
+}
+
+type word uintptr
+
+const (
+ _m = ^word(0)
+ bitsPerWord = 8 << (_m>>8&1 + _m>>16&1 + _m>>32&1)
+ bitsPerBlock = 256 // optimal value for go/pointer solver performance
+ wordsPerBlock = bitsPerBlock / bitsPerWord
+)
+
+// Limit values of implementation-specific int type.
+const (
+ MaxInt = int(^uint(0) >> 1)
+ MinInt = -MaxInt - 1
+)
+
+// -- block ------------------------------------------------------------
+
+// A set is represented as a circular doubly-linked list of blocks,
+// each containing an offset and a bit array of fixed size
+// bitsPerBlock; the blocks are ordered by increasing offset.
+//
+// The set contains an element x iff the block whose offset is x - (x
+// mod bitsPerBlock) has the bit (x mod bitsPerBlock) set, where mod
+// is the Euclidean remainder.
+//
+// A block may only be empty transiently.
+//
+type block struct {
+ offset int // offset mod bitsPerBlock == 0
+ bits [wordsPerBlock]word // contains at least one set bit
+ next, prev *block // doubly-linked list of blocks
+}
+
+// wordMask returns the word index (in block.bits)
+// and single-bit mask for the block's ith bit.
+func wordMask(i uint) (w uint, mask word) {
+ w = i / bitsPerWord
+ mask = 1 << (i % bitsPerWord)
+ return
+}
+
+// insert sets the block b's ith bit and
+// returns true if it was not already set.
+//
+func (b *block) insert(i uint) bool {
+ w, mask := wordMask(i)
+ if b.bits[w]&mask == 0 {
+ b.bits[w] |= mask
+ return true
+ }
+ return false
+}
+
+// remove clears the block's ith bit and
+// returns true if the bit was previously set.
+// NB: may leave the block empty.
+//
+func (b *block) remove(i uint) bool {
+ w, mask := wordMask(i)
+ if b.bits[w]&mask != 0 {
+ b.bits[w] &^= mask
+ return true
+ }
+ return false
+}
+
+// has reports whether the block's ith bit is set.
+func (b *block) has(i uint) bool {
+ w, mask := wordMask(i)
+ return b.bits[w]&mask != 0
+}
+
+// empty reports whether b.len()==0, but more efficiently.
+func (b *block) empty() bool {
+ for _, w := range b.bits {
+ if w != 0 {
+ return false
+ }
+ }
+ return true
+}
+
+// len returns the number of set bits in block b.
+func (b *block) len() int {
+ var l int
+ for _, w := range b.bits {
+ l += popcount(w)
+ }
+ return l
+}
+
+// max returns the maximum element of the block.
+// The block must not be empty.
+//
+func (b *block) max() int {
+ bi := b.offset + bitsPerBlock
+ // Decrement bi by number of high zeros in last.bits.
+ for i := len(b.bits) - 1; i >= 0; i-- {
+ if w := b.bits[i]; w != 0 {
+ return bi - nlz(w) - 1
+ }
+ bi -= bitsPerWord
+ }
+ panic("BUG: empty block")
+}
+
+// min returns the minimum element of the block,
+// and also removes it if take is set.
+// The block must not be initially empty.
+// NB: may leave the block empty.
+//
+func (b *block) min(take bool) int {
+ for i, w := range b.bits {
+ if w != 0 {
+ tz := ntz(w)
+ if take {
+ b.bits[i] = w &^ (1 << uint(tz))
+ }
+ return b.offset + int(i*bitsPerWord) + tz
+ }
+ }
+ panic("BUG: empty block")
+}
+
+// forEach calls f for each element of block b.
+// f must not mutate b's enclosing Sparse.
+func (b *block) forEach(f func(int)) {
+ for i, w := range b.bits {
+ offset := b.offset + i*bitsPerWord
+ for bi := 0; w != 0 && bi < bitsPerWord; bi++ {
+ if w&1 != 0 {
+ f(offset)
+ }
+ offset++
+ w >>= 1
+ }
+ }
+}
+
+// offsetAndBitIndex returns the offset of the block that would
+// contain x and the bit index of x within that block.
+//
+func offsetAndBitIndex(x int) (int, uint) {
+ mod := x % bitsPerBlock
+ if mod < 0 {
+ // Euclidean (non-negative) remainder
+ mod += bitsPerBlock
+ }
+ return x - mod, uint(mod)
+}
+
+// -- Sparse --------------------------------------------------------------
+
+// start returns the root's next block, which is the root block
+// (if s.IsEmpty()) or the first true block otherwise.
+// start has the side effect of ensuring that s is properly
+// initialized.
+//
+func (s *Sparse) start() *block {
+ root := &s.root
+ if root.next == nil {
+ root.next = root
+ root.prev = root
+ } else if root.next.prev != root {
+ // Copying a Sparse x leads to pernicious corruption: the
+ // new Sparse y shares the old linked list, but iteration
+ // on y will never encounter &y.root so it goes into a
+ // loop. Fail fast before this occurs.
+ panic("A Sparse has been copied without (*Sparse).Copy()")
+ }
+
+ return root.next
+}
+
+// IsEmpty reports whether the set s is empty.
+func (s *Sparse) IsEmpty() bool {
+ return s.start() == &s.root
+}
+
+// Len returns the number of elements in the set s.
+func (s *Sparse) Len() int {
+ var l int
+ for b := s.start(); b != &s.root; b = b.next {
+ l += b.len()
+ }
+ return l
+}
+
+// Max returns the maximum element of the set s, or MinInt if s is empty.
+func (s *Sparse) Max() int {
+ if s.IsEmpty() {
+ return MinInt
+ }
+ return s.root.prev.max()
+}
+
+// Min returns the minimum element of the set s, or MaxInt if s is empty.
+func (s *Sparse) Min() int {
+ if s.IsEmpty() {
+ return MaxInt
+ }
+ return s.root.next.min(false)
+}
+
+// block returns the block that would contain offset,
+// or nil if s contains no such block.
+//
+func (s *Sparse) block(offset int) *block {
+ b := s.start()
+ for b != &s.root && b.offset <= offset {
+ if b.offset == offset {
+ return b
+ }
+ b = b.next
+ }
+ return nil
+}
+
+// Insert adds x to the set s, and reports whether the set grew.
+func (s *Sparse) Insert(x int) bool {
+ offset, i := offsetAndBitIndex(x)
+ b := s.start()
+ for b != &s.root && b.offset <= offset {
+ if b.offset == offset {
+ return b.insert(i)
+ }
+ b = b.next
+ }
+
+ // Insert new block before b.
+ new := &block{offset: offset}
+ new.next = b
+ new.prev = b.prev
+ new.prev.next = new
+ new.next.prev = new
+ return new.insert(i)
+}
+
+func (s *Sparse) removeBlock(b *block) {
+ b.prev.next = b.next
+ b.next.prev = b.prev
+}
+
+// Remove removes x from the set s, and reports whether the set shrank.
+func (s *Sparse) Remove(x int) bool {
+ offset, i := offsetAndBitIndex(x)
+ if b := s.block(offset); b != nil {
+ if !b.remove(i) {
+ return false
+ }
+ if b.empty() {
+ s.removeBlock(b)
+ }
+ return true
+ }
+ return false
+}
+
+// Clear removes all elements from the set s.
+func (s *Sparse) Clear() {
+ s.root.next = &s.root
+ s.root.prev = &s.root
+}
+
+// If set s is non-empty, TakeMin sets *p to the minimum element of
+// the set s, removes that element from the set and returns true.
+// Otherwise, it returns false and *p is undefined.
+//
+// This method may be used for iteration over a worklist like so:
+//
+// var x int
+// for worklist.TakeMin(&x) { use(x) }
+//
+func (s *Sparse) TakeMin(p *int) bool {
+ head := s.start()
+ if head == &s.root {
+ return false
+ }
+ *p = head.min(true)
+ if head.empty() {
+ s.removeBlock(head)
+ }
+ return true
+}
+
+// Has reports whether x is an element of the set s.
+func (s *Sparse) Has(x int) bool {
+ offset, i := offsetAndBitIndex(x)
+ if b := s.block(offset); b != nil {
+ return b.has(i)
+ }
+ return false
+}
+
+// forEach applies function f to each element of the set s in order.
+//
+// f must not mutate s. Consequently, forEach is not safe to expose
+// to clients. In any case, using "range s.AppendTo()" allows more
+// natural control flow with continue/break/return.
+//
+func (s *Sparse) forEach(f func(int)) {
+ for b := s.start(); b != &s.root; b = b.next {
+ b.forEach(f)
+ }
+}
+
+// Copy sets s to the value of x.
+func (s *Sparse) Copy(x *Sparse) {
+ if s == x {
+ return
+ }
+
+ xb := x.start()
+ sb := s.start()
+ for xb != &x.root {
+ if sb == &s.root {
+ sb = s.insertBlockBefore(sb)
+ }
+ sb.offset = xb.offset
+ sb.bits = xb.bits
+ xb = xb.next
+ sb = sb.next
+ }
+ s.discardTail(sb)
+}
+
+// insertBlockBefore returns a new block, inserting it before next.
+func (s *Sparse) insertBlockBefore(next *block) *block {
+ b := new(block)
+ b.next = next
+ b.prev = next.prev
+ b.prev.next = b
+ next.prev = b
+ return b
+}
+
+// discardTail removes block b and all its successors from s.
+func (s *Sparse) discardTail(b *block) {
+ if b != &s.root {
+ b.prev.next = &s.root
+ s.root.prev = b.prev
+ }
+}
+
+// IntersectionWith sets s to the intersection s ∩ x.
+func (s *Sparse) IntersectionWith(x *Sparse) {
+ if s == x {
+ return
+ }
+
+ xb := x.start()
+ sb := s.start()
+ for xb != &x.root && sb != &s.root {
+ switch {
+ case xb.offset < sb.offset:
+ xb = xb.next
+
+ case xb.offset > sb.offset:
+ sb = sb.next
+ s.removeBlock(sb.prev)
+
+ default:
+ var sum word
+ for i := range sb.bits {
+ r := xb.bits[i] & sb.bits[i]
+ sb.bits[i] = r
+ sum |= r
+ }
+ if sum != 0 {
+ sb = sb.next
+ } else {
+ // sb will be overwritten or removed
+ }
+
+ xb = xb.next
+ }
+ }
+
+ s.discardTail(sb)
+}
+
+// Intersection sets s to the intersection x ∩ y.
+func (s *Sparse) Intersection(x, y *Sparse) {
+ switch {
+ case s == x:
+ s.IntersectionWith(y)
+ return
+ case s == y:
+ s.IntersectionWith(x)
+ return
+ case x == y:
+ s.Copy(x)
+ return
+ }
+
+ xb := x.start()
+ yb := y.start()
+ sb := s.start()
+ for xb != &x.root && yb != &y.root {
+ switch {
+ case xb.offset < yb.offset:
+ xb = xb.next
+ continue
+ case xb.offset > yb.offset:
+ yb = yb.next
+ continue
+ }
+
+ if sb == &s.root {
+ sb = s.insertBlockBefore(sb)
+ }
+ sb.offset = xb.offset
+
+ var sum word
+ for i := range sb.bits {
+ r := xb.bits[i] & yb.bits[i]
+ sb.bits[i] = r
+ sum |= r
+ }
+ if sum != 0 {
+ sb = sb.next
+ } else {
+ // sb will be overwritten or removed
+ }
+
+ xb = xb.next
+ yb = yb.next
+ }
+
+ s.discardTail(sb)
+}
+
+// Intersects reports whether s ∩ x ≠ ∅.
+func (s *Sparse) Intersects(x *Sparse) bool {
+ sb := s.start()
+ xb := x.start()
+ for sb != &s.root && xb != &x.root {
+ switch {
+ case xb.offset < sb.offset:
+ xb = xb.next
+ case xb.offset > sb.offset:
+ sb = sb.next
+ default:
+ for i := range sb.bits {
+ if sb.bits[i]&xb.bits[i] != 0 {
+ return true
+ }
+ }
+ sb = sb.next
+ xb = xb.next
+ }
+ }
+ return false
+}
+
+// UnionWith sets s to the union s ∪ x, and reports whether s grew.
+func (s *Sparse) UnionWith(x *Sparse) bool {
+ if s == x {
+ return false
+ }
+
+ var changed bool
+ xb := x.start()
+ sb := s.start()
+ for xb != &x.root {
+ if sb != &s.root && sb.offset == xb.offset {
+ for i := range xb.bits {
+ if sb.bits[i] != xb.bits[i] {
+ sb.bits[i] |= xb.bits[i]
+ changed = true
+ }
+ }
+ xb = xb.next
+ } else if sb == &s.root || sb.offset > xb.offset {
+ sb = s.insertBlockBefore(sb)
+ sb.offset = xb.offset
+ sb.bits = xb.bits
+ changed = true
+
+ xb = xb.next
+ }
+ sb = sb.next
+ }
+ return changed
+}
+
+// Union sets s to the union x ∪ y.
+func (s *Sparse) Union(x, y *Sparse) {
+ switch {
+ case x == y:
+ s.Copy(x)
+ return
+ case s == x:
+ s.UnionWith(y)
+ return
+ case s == y:
+ s.UnionWith(x)
+ return
+ }
+
+ xb := x.start()
+ yb := y.start()
+ sb := s.start()
+ for xb != &x.root || yb != &y.root {
+ if sb == &s.root {
+ sb = s.insertBlockBefore(sb)
+ }
+ switch {
+ case yb == &y.root || (xb != &x.root && xb.offset < yb.offset):
+ sb.offset = xb.offset
+ sb.bits = xb.bits
+ xb = xb.next
+
+ case xb == &x.root || (yb != &y.root && yb.offset < xb.offset):
+ sb.offset = yb.offset
+ sb.bits = yb.bits
+ yb = yb.next
+
+ default:
+ sb.offset = xb.offset
+ for i := range xb.bits {
+ sb.bits[i] = xb.bits[i] | yb.bits[i]
+ }
+ xb = xb.next
+ yb = yb.next
+ }
+ sb = sb.next
+ }
+
+ s.discardTail(sb)
+}
+
+// DifferenceWith sets s to the difference s ∖ x.
+func (s *Sparse) DifferenceWith(x *Sparse) {
+ if s == x {
+ s.Clear()
+ return
+ }
+
+ xb := x.start()
+ sb := s.start()
+ for xb != &x.root && sb != &s.root {
+ switch {
+ case xb.offset > sb.offset:
+ sb = sb.next
+
+ case xb.offset < sb.offset:
+ xb = xb.next
+
+ default:
+ var sum word
+ for i := range sb.bits {
+ r := sb.bits[i] & ^xb.bits[i]
+ sb.bits[i] = r
+ sum |= r
+ }
+ sb = sb.next
+ xb = xb.next
+
+ if sum == 0 {
+ s.removeBlock(sb.prev)
+ }
+ }
+ }
+}
+
+// Difference sets s to the difference x ∖ y.
+func (s *Sparse) Difference(x, y *Sparse) {
+ switch {
+ case x == y:
+ s.Clear()
+ return
+ case s == x:
+ s.DifferenceWith(y)
+ return
+ case s == y:
+ var y2 Sparse
+ y2.Copy(y)
+ s.Difference(x, &y2)
+ return
+ }
+
+ xb := x.start()
+ yb := y.start()
+ sb := s.start()
+ for xb != &x.root && yb != &y.root {
+ if xb.offset > yb.offset {
+ // y has block, x has none
+ yb = yb.next
+ continue
+ }
+
+ if sb == &s.root {
+ sb = s.insertBlockBefore(sb)
+ }
+ sb.offset = xb.offset
+
+ switch {
+ case xb.offset < yb.offset:
+ // x has block, y has none
+ sb.bits = xb.bits
+
+ sb = sb.next
+
+ default:
+ // x and y have corresponding blocks
+ var sum word
+ for i := range sb.bits {
+ r := xb.bits[i] & ^yb.bits[i]
+ sb.bits[i] = r
+ sum |= r
+ }
+ if sum != 0 {
+ sb = sb.next
+ } else {
+ // sb will be overwritten or removed
+ }
+
+ yb = yb.next
+ }
+ xb = xb.next
+ }
+
+ for xb != &x.root {
+ if sb == &s.root {
+ sb = s.insertBlockBefore(sb)
+ }
+ sb.offset = xb.offset
+ sb.bits = xb.bits
+ sb = sb.next
+
+ xb = xb.next
+ }
+
+ s.discardTail(sb)
+}
+
+// SymmetricDifferenceWith sets s to the symmetric difference s ∆ x.
+func (s *Sparse) SymmetricDifferenceWith(x *Sparse) {
+ if s == x {
+ s.Clear()
+ return
+ }
+
+ sb := s.start()
+ xb := x.start()
+ for xb != &x.root && sb != &s.root {
+ switch {
+ case sb.offset < xb.offset:
+ sb = sb.next
+ case xb.offset < sb.offset:
+ nb := s.insertBlockBefore(sb)
+ nb.offset = xb.offset
+ nb.bits = xb.bits
+ xb = xb.next
+ default:
+ var sum word
+ for i := range sb.bits {
+ r := sb.bits[i] ^ xb.bits[i]
+ sb.bits[i] = r
+ sum |= r
+ }
+ sb = sb.next
+ xb = xb.next
+ if sum == 0 {
+ s.removeBlock(sb.prev)
+ }
+ }
+ }
+
+ for xb != &x.root { // append the tail of x to s
+ sb = s.insertBlockBefore(sb)
+ sb.offset = xb.offset
+ sb.bits = xb.bits
+ sb = sb.next
+ xb = xb.next
+ }
+}
+
+// SymmetricDifference sets s to the symmetric difference x ∆ y.
+func (s *Sparse) SymmetricDifference(x, y *Sparse) {
+ switch {
+ case x == y:
+ s.Clear()
+ return
+ case s == x:
+ s.SymmetricDifferenceWith(y)
+ return
+ case s == y:
+ s.SymmetricDifferenceWith(x)
+ return
+ }
+
+ sb := s.start()
+ xb := x.start()
+ yb := y.start()
+ for xb != &x.root && yb != &y.root {
+ if sb == &s.root {
+ sb = s.insertBlockBefore(sb)
+ }
+ switch {
+ case yb.offset < xb.offset:
+ sb.offset = yb.offset
+ sb.bits = yb.bits
+ sb = sb.next
+ yb = yb.next
+ case xb.offset < yb.offset:
+ sb.offset = xb.offset
+ sb.bits = xb.bits
+ sb = sb.next
+ xb = xb.next
+ default:
+ var sum word
+ for i := range sb.bits {
+ r := xb.bits[i] ^ yb.bits[i]
+ sb.bits[i] = r
+ sum |= r
+ }
+ if sum != 0 {
+ sb.offset = xb.offset
+ sb = sb.next
+ }
+ xb = xb.next
+ yb = yb.next
+ }
+ }
+
+ for xb != &x.root { // append the tail of x to s
+ if sb == &s.root {
+ sb = s.insertBlockBefore(sb)
+ }
+ sb.offset = xb.offset
+ sb.bits = xb.bits
+ sb = sb.next
+ xb = xb.next
+ }
+
+ for yb != &y.root { // append the tail of y to s
+ if sb == &s.root {
+ sb = s.insertBlockBefore(sb)
+ }
+ sb.offset = yb.offset
+ sb.bits = yb.bits
+ sb = sb.next
+ yb = yb.next
+ }
+
+ s.discardTail(sb)
+}
+
+// SubsetOf reports whether s ∖ x = ∅.
+func (s *Sparse) SubsetOf(x *Sparse) bool {
+ if s == x {
+ return true
+ }
+
+ sb := s.start()
+ xb := x.start()
+ for sb != &s.root {
+ switch {
+ case xb == &x.root || xb.offset > sb.offset:
+ return false
+ case xb.offset < sb.offset:
+ xb = xb.next
+ default:
+ for i := range sb.bits {
+ if sb.bits[i]&^xb.bits[i] != 0 {
+ return false
+ }
+ }
+ sb = sb.next
+ xb = xb.next
+ }
+ }
+ return true
+}
+
+// Equals reports whether the sets s and t have the same elements.
+func (s *Sparse) Equals(t *Sparse) bool {
+ if s == t {
+ return true
+ }
+ sb := s.start()
+ tb := t.start()
+ for {
+ switch {
+ case sb == &s.root && tb == &t.root:
+ return true
+ case sb == &s.root || tb == &t.root:
+ return false
+ case sb.offset != tb.offset:
+ return false
+ case sb.bits != tb.bits:
+ return false
+ }
+
+ sb = sb.next
+ tb = tb.next
+ }
+}
+
+// String returns a human-readable description of the set s.
+func (s *Sparse) String() string {
+ var buf bytes.Buffer
+ buf.WriteByte('{')
+ s.forEach(func(x int) {
+ if buf.Len() > 1 {
+ buf.WriteByte(' ')
+ }
+ fmt.Fprintf(&buf, "%d", x)
+ })
+ buf.WriteByte('}')
+ return buf.String()
+}
+
+// BitString returns the set as a string of 1s and 0s denoting the sum
+// of the i'th powers of 2, for each i in s. A radix point, always
+// preceded by a digit, appears if the sum is non-integral.
+//
+// Examples:
+// {}.BitString() = "0"
+// {4,5}.BitString() = "110000"
+// {-3}.BitString() = "0.001"
+// {-3,0,4,5}.BitString() = "110001.001"
+//
+func (s *Sparse) BitString() string {
+ if s.IsEmpty() {
+ return "0"
+ }
+
+ min, max := s.Min(), s.Max()
+ var nbytes int
+ if max > 0 {
+ nbytes = max
+ }
+ nbytes++ // zero bit
+ radix := nbytes
+ if min < 0 {
+ nbytes += len(".") - min
+ }
+
+ b := make([]byte, nbytes)
+ for i := range b {
+ b[i] = '0'
+ }
+ if radix < nbytes {
+ b[radix] = '.'
+ }
+ s.forEach(func(x int) {
+ if x >= 0 {
+ x += len(".")
+ }
+ b[radix-x] = '1'
+ })
+ return string(b)
+}
+
+// GoString returns a string showing the internal representation of
+// the set s.
+//
+func (s *Sparse) GoString() string {
+ var buf bytes.Buffer
+ for b := s.start(); b != &s.root; b = b.next {
+ fmt.Fprintf(&buf, "block %p {offset=%d next=%p prev=%p",
+ b, b.offset, b.next, b.prev)
+ for _, w := range b.bits {
+ fmt.Fprintf(&buf, " 0%016x", w)
+ }
+ fmt.Fprintf(&buf, "}\n")
+ }
+ return buf.String()
+}
+
+// AppendTo returns the result of appending the elements of s to slice
+// in order.
+func (s *Sparse) AppendTo(slice []int) []int {
+ s.forEach(func(x int) {
+ slice = append(slice, x)
+ })
+ return slice
+}
+
+// -- Testing/debugging ------------------------------------------------
+
+// check returns an error if the representation invariants of s are violated.
+func (s *Sparse) check() error {
+ if !s.root.empty() {
+ return fmt.Errorf("non-empty root block")
+ }
+ if s.root.offset != 0 {
+ return fmt.Errorf("root block has non-zero offset %d", s.root.offset)
+ }
+ for b := s.start(); b != &s.root; b = b.next {
+ if b.offset%bitsPerBlock != 0 {
+ return fmt.Errorf("bad offset modulo: %d", b.offset)
+ }
+ if b.empty() {
+ return fmt.Errorf("empty block")
+ }
+ if b.prev.next != b {
+ return fmt.Errorf("bad prev.next link")
+ }
+ if b.next.prev != b {
+ return fmt.Errorf("bad next.prev link")
+ }
+ if b.prev != &s.root {
+ if b.offset <= b.prev.offset {
+ return fmt.Errorf("bad offset order: b.offset=%d, prev.offset=%d",
+ b.offset, b.prev.offset)
+ }
+ }
+ }
+ return nil
+}
diff --git a/container/intsets/sparse_test.go b/container/intsets/sparse_test.go
new file mode 100644
index 0000000..34b9a4e
--- /dev/null
+++ b/container/intsets/sparse_test.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.
+
+package intsets_test
+
+import (
+ "fmt"
+ "log"
+ "math/rand"
+ "sort"
+ "strings"
+ "testing"
+
+ "golang.org/x/tools/container/intsets"
+)
+
+func TestBasics(t *testing.T) {
+ var s intsets.Sparse
+ if len := s.Len(); len != 0 {
+ t.Errorf("Len({}): got %d, want 0", len)
+ }
+ if s := s.String(); s != "{}" {
+ t.Errorf("String({}): got %q, want \"{}\"", s)
+ }
+ if s.Has(3) {
+ t.Errorf("Has(3): got true, want false")
+ }
+ if err := s.Check(); err != nil {
+ t.Error(err)
+ }
+
+ if !s.Insert(3) {
+ t.Errorf("Insert(3): got false, want true")
+ }
+ if max := s.Max(); max != 3 {
+ t.Errorf("Max: got %d, want 3", max)
+ }
+
+ if !s.Insert(435) {
+ t.Errorf("Insert(435): got false, want true")
+ }
+ if s := s.String(); s != "{3 435}" {
+ t.Errorf("String({3 435}): got %q, want \"{3 435}\"", s)
+ }
+ if max := s.Max(); max != 435 {
+ t.Errorf("Max: got %d, want 435", max)
+ }
+ if len := s.Len(); len != 2 {
+ t.Errorf("Len: got %d, want 2", len)
+ }
+
+ if !s.Remove(435) {
+ t.Errorf("Remove(435): got false, want true")
+ }
+ if s := s.String(); s != "{3}" {
+ t.Errorf("String({3}): got %q, want \"{3}\"", s)
+ }
+}
+
+// Insert, Len, IsEmpty, Hash, Clear, AppendTo.
+func TestMoreBasics(t *testing.T) {
+ set := new(intsets.Sparse)
+ set.Insert(456)
+ set.Insert(123)
+ set.Insert(789)
+ if set.Len() != 3 {
+ t.Errorf("%s.Len: got %d, want 3", set, set.Len())
+ }
+ if set.IsEmpty() {
+ t.Errorf("%s.IsEmpty: got true", set)
+ }
+ if !set.Has(123) {
+ t.Errorf("%s.Has(123): got false", set)
+ }
+ if set.Has(1234) {
+ t.Errorf("%s.Has(1234): got true", set)
+ }
+ got := set.AppendTo([]int{-1})
+ if want := []int{-1, 123, 456, 789}; fmt.Sprint(got) != fmt.Sprint(want) {
+ t.Errorf("%s.AppendTo: got %v, want %v", set, got, want)
+ }
+
+ set.Clear()
+
+ if set.Len() != 0 {
+ t.Errorf("Clear: got %d, want 0", set.Len())
+ }
+ if !set.IsEmpty() {
+ t.Errorf("IsEmpty: got false")
+ }
+ if set.Has(123) {
+ t.Errorf("%s.Has: got false", set)
+ }
+}
+
+func TestTakeMin(t *testing.T) {
+ var set intsets.Sparse
+ set.Insert(456)
+ set.Insert(123)
+ set.Insert(789)
+ set.Insert(-123)
+ var got int
+ for i, want := range []int{-123, 123, 456, 789} {
+ if !set.TakeMin(&got) || got != want {
+ t.Errorf("TakeMin #%d: got %d, want %d", i, got, want)
+ }
+ }
+ if set.TakeMin(&got) {
+ t.Errorf("%s.TakeMin returned true", &set)
+ }
+ if err := set.Check(); err != nil {
+ t.Fatalf("check: %s: %#v", err, &set)
+ }
+}
+
+func TestMinAndMax(t *testing.T) {
+ values := []int{0, 456, 123, 789, -123} // elt 0 => empty set
+ wantMax := []int{intsets.MinInt, 456, 456, 789, 789}
+ wantMin := []int{intsets.MaxInt, 456, 123, 123, -123}
+
+ var set intsets.Sparse
+ for i, x := range values {
+ if i != 0 {
+ set.Insert(x)
+ }
+ if got, want := set.Min(), wantMin[i]; got != want {
+ t.Errorf("Min #%d: got %d, want %d", i, got, want)
+ }
+ if got, want := set.Max(), wantMax[i]; got != want {
+ t.Errorf("Max #%d: got %d, want %d", i, got, want)
+ }
+ }
+
+ set.Insert(intsets.MinInt)
+ if got, want := set.Min(), intsets.MinInt; got != want {
+ t.Errorf("Min: got %d, want %d", got, want)
+ }
+
+ set.Insert(intsets.MaxInt)
+ if got, want := set.Max(), intsets.MaxInt; got != want {
+ t.Errorf("Max: got %d, want %d", got, want)
+ }
+}
+
+func TestEquals(t *testing.T) {
+ var setX intsets.Sparse
+ setX.Insert(456)
+ setX.Insert(123)
+ setX.Insert(789)
+
+ if !setX.Equals(&setX) {
+ t.Errorf("Equals(%s, %s): got false", &setX, &setX)
+ }
+
+ var setY intsets.Sparse
+ setY.Insert(789)
+ setY.Insert(456)
+ setY.Insert(123)
+
+ if !setX.Equals(&setY) {
+ t.Errorf("Equals(%s, %s): got false", &setX, &setY)
+ }
+
+ setY.Insert(1)
+ if setX.Equals(&setY) {
+ t.Errorf("Equals(%s, %s): got true", &setX, &setY)
+ }
+
+ var empty intsets.Sparse
+ if setX.Equals(&empty) {
+ t.Errorf("Equals(%s, %s): got true", &setX, &empty)
+ }
+
+ // Edge case: some block (with offset=0) appears in X but not Y.
+ setY.Remove(123)
+ if setX.Equals(&setY) {
+ t.Errorf("Equals(%s, %s): got true", &setX, &setY)
+ }
+}
+
+// A pset is a parallel implementation of a set using both an intsets.Sparse
+// and a built-in hash map.
+type pset struct {
+ hash map[int]bool
+ bits intsets.Sparse
+}
+
+func makePset() *pset {
+ return &pset{hash: make(map[int]bool)}
+}
+
+func (set *pset) add(n int) {
+ prev := len(set.hash)
+ set.hash[n] = true
+ grewA := len(set.hash) > prev
+
+ grewB := set.bits.Insert(n)
+
+ if grewA != grewB {
+ panic(fmt.Sprintf("add(%d): grewA=%t grewB=%t", n, grewA, grewB))
+ }
+}
+
+func (set *pset) remove(n int) {
+ prev := len(set.hash)
+ delete(set.hash, n)
+ shrankA := len(set.hash) < prev
+
+ shrankB := set.bits.Remove(n)
+
+ if shrankA != shrankB {
+ panic(fmt.Sprintf("remove(%d): shrankA=%t shrankB=%t", n, shrankA, shrankB))
+ }
+}
+
+func (set *pset) check(t *testing.T, msg string) {
+ var eltsA []int
+ for elt := range set.hash {
+ eltsA = append(eltsA, int(elt))
+ }
+ sort.Ints(eltsA)
+
+ eltsB := set.bits.AppendTo(nil)
+
+ if a, b := fmt.Sprint(eltsA), fmt.Sprint(eltsB); a != b {
+ t.Errorf("check(%s): hash=%s bits=%s (%s)", msg, a, b, &set.bits)
+ }
+
+ if err := set.bits.Check(); err != nil {
+ t.Fatalf("Check(%s): %s: %#v", msg, err, &set.bits)
+ }
+}
+
+// randomPset returns a parallel set of random size and elements.
+func randomPset(prng *rand.Rand, maxSize int) *pset {
+ set := makePset()
+ size := int(prng.Int()) % maxSize
+ for i := 0; i < size; i++ {
+ // TODO(adonovan): benchmark how performance varies
+ // with this sparsity parameter.
+ n := int(prng.Int()) % 10000
+ set.add(n)
+ }
+ return set
+}
+
+// TestRandomMutations performs the same random adds/removes on two
+// set implementations and ensures that they compute the same result.
+func TestRandomMutations(t *testing.T) {
+ const debug = false
+
+ set := makePset()
+ prng := rand.New(rand.NewSource(0))
+ for i := 0; i < 10000; i++ {
+ n := int(prng.Int())%2000 - 1000
+ if i%2 == 0 {
+ if debug {
+ log.Printf("add %d", n)
+ }
+ set.add(n)
+ } else {
+ if debug {
+ log.Printf("remove %d", n)
+ }
+ set.remove(n)
+ }
+ if debug {
+ set.check(t, "post mutation")
+ }
+ }
+ set.check(t, "final")
+ if debug {
+ log.Print(&set.bits)
+ }
+}
+
+// TestSetOperations exercises classic set operations: ∩ , ∪, \.
+func TestSetOperations(t *testing.T) {
+ prng := rand.New(rand.NewSource(0))
+
+ // Use random sets of sizes from 0 to about 1000.
+ // For each operator, we test variations such as
+ // Z.op(X, Y), Z.op(X, Z) and Z.op(Z, Y) to exercise
+ // the degenerate cases of each method implementation.
+ for i := uint(0); i < 12; i++ {
+ X := randomPset(prng, 1<<i)
+ Y := randomPset(prng, 1<<i)
+
+ // TODO(adonovan): minimise dependencies between stanzas below.
+
+ // Copy(X)
+ C := makePset()
+ C.bits.Copy(&Y.bits) // no effect on result
+ C.bits.Copy(&X.bits)
+ C.hash = X.hash
+ C.check(t, "C.Copy(X)")
+ C.bits.Copy(&C.bits)
+ C.check(t, "C.Copy(C)")
+
+ // U.Union(X, Y)
+ U := makePset()
+ U.bits.Union(&X.bits, &Y.bits)
+ for n := range X.hash {
+ U.hash[n] = true
+ }
+ for n := range Y.hash {
+ U.hash[n] = true
+ }
+ U.check(t, "U.Union(X, Y)")
+
+ // U.Union(X, X)
+ U.bits.Union(&X.bits, &X.bits)
+ U.hash = X.hash
+ U.check(t, "U.Union(X, X)")
+
+ // U.Union(U, Y)
+ U = makePset()
+ U.bits.Copy(&X.bits)
+ U.bits.Union(&U.bits, &Y.bits)
+ for n := range X.hash {
+ U.hash[n] = true
+ }
+ for n := range Y.hash {
+ U.hash[n] = true
+ }
+ U.check(t, "U.Union(U, Y)")
+
+ // U.Union(X, U)
+ U.bits.Copy(&Y.bits)
+ U.bits.Union(&X.bits, &U.bits)
+ U.check(t, "U.Union(X, U)")
+
+ // U.UnionWith(U)
+ U.bits.UnionWith(&U.bits)
+ U.check(t, "U.UnionWith(U)")
+
+ // I.Intersection(X, Y)
+ I := makePset()
+ I.bits.Intersection(&X.bits, &Y.bits)
+ for n := range X.hash {
+ if Y.hash[n] {
+ I.hash[n] = true
+ }
+ }
+ I.check(t, "I.Intersection(X, Y)")
+
+ // I.Intersection(X, X)
+ I.bits.Intersection(&X.bits, &X.bits)
+ I.hash = X.hash
+ I.check(t, "I.Intersection(X, X)")
+
+ // I.Intersection(I, X)
+ I.bits.Intersection(&I.bits, &X.bits)
+ I.check(t, "I.Intersection(I, X)")
+
+ // I.Intersection(X, I)
+ I.bits.Intersection(&X.bits, &I.bits)
+ I.check(t, "I.Intersection(X, I)")
+
+ // I.Intersection(I, I)
+ I.bits.Intersection(&I.bits, &I.bits)
+ I.check(t, "I.Intersection(I, I)")
+
+ // D.Difference(X, Y)
+ D := makePset()
+ D.bits.Difference(&X.bits, &Y.bits)
+ for n := range X.hash {
+ if !Y.hash[n] {
+ D.hash[n] = true
+ }
+ }
+ D.check(t, "D.Difference(X, Y)")
+
+ // D.Difference(D, Y)
+ D.bits.Copy(&X.bits)
+ D.bits.Difference(&D.bits, &Y.bits)
+ D.check(t, "D.Difference(D, Y)")
+
+ // D.Difference(Y, D)
+ D.bits.Copy(&X.bits)
+ D.bits.Difference(&Y.bits, &D.bits)
+ D.hash = make(map[int]bool)
+ for n := range Y.hash {
+ if !X.hash[n] {
+ D.hash[n] = true
+ }
+ }
+ D.check(t, "D.Difference(Y, D)")
+
+ // D.Difference(X, X)
+ D.bits.Difference(&X.bits, &X.bits)
+ D.hash = nil
+ D.check(t, "D.Difference(X, X)")
+
+ // D.DifferenceWith(D)
+ D.bits.Copy(&X.bits)
+ D.bits.DifferenceWith(&D.bits)
+ D.check(t, "D.DifferenceWith(D)")
+
+ // SD.SymmetricDifference(X, Y)
+ SD := makePset()
+ SD.bits.SymmetricDifference(&X.bits, &Y.bits)
+ for n := range X.hash {
+ if !Y.hash[n] {
+ SD.hash[n] = true
+ }
+ }
+ for n := range Y.hash {
+ if !X.hash[n] {
+ SD.hash[n] = true
+ }
+ }
+ SD.check(t, "SD.SymmetricDifference(X, Y)")
+
+ // X.SymmetricDifferenceWith(Y)
+ SD.bits.Copy(&X.bits)
+ SD.bits.SymmetricDifferenceWith(&Y.bits)
+ SD.check(t, "X.SymmetricDifference(Y)")
+
+ // Y.SymmetricDifferenceWith(X)
+ SD.bits.Copy(&Y.bits)
+ SD.bits.SymmetricDifferenceWith(&X.bits)
+ SD.check(t, "Y.SymmetricDifference(X)")
+
+ // SD.SymmetricDifference(X, X)
+ SD.bits.SymmetricDifference(&X.bits, &X.bits)
+ SD.hash = nil
+ SD.check(t, "SD.SymmetricDifference(X, X)")
+
+ // SD.SymmetricDifference(X, Copy(X))
+ X2 := makePset()
+ X2.bits.Copy(&X.bits)
+ SD.bits.SymmetricDifference(&X.bits, &X2.bits)
+ SD.check(t, "SD.SymmetricDifference(X, Copy(X))")
+
+ // Copy(X).SymmetricDifferenceWith(X)
+ SD.bits.Copy(&X.bits)
+ SD.bits.SymmetricDifferenceWith(&X.bits)
+ SD.check(t, "Copy(X).SymmetricDifferenceWith(X)")
+ }
+}
+
+func TestIntersectionWith(t *testing.T) {
+ // Edge cases: the pairs (1,1), (1000,2000), (8000,4000)
+ // exercise the <, >, == cases in IntersectionWith that the
+ // TestSetOperations data is too dense to cover.
+ var X, Y intsets.Sparse
+ X.Insert(1)
+ X.Insert(1000)
+ X.Insert(8000)
+ Y.Insert(1)
+ Y.Insert(2000)
+ Y.Insert(4000)
+ X.IntersectionWith(&Y)
+ if got, want := X.String(), "{1}"; got != want {
+ t.Errorf("IntersectionWith: got %s, want %s", got, want)
+ }
+}
+
+func TestIntersects(t *testing.T) {
+ prng := rand.New(rand.NewSource(0))
+
+ for i := uint(0); i < 12; i++ {
+ X, Y := randomPset(prng, 1<<i), randomPset(prng, 1<<i)
+ x, y := &X.bits, &Y.bits
+
+ // test the slow way
+ var z intsets.Sparse
+ z.Copy(x)
+ z.IntersectionWith(y)
+
+ if got, want := x.Intersects(y), !z.IsEmpty(); got != want {
+ t.Errorf("Intersects: got %v, want %v", got, want)
+ }
+
+ // make it false
+ a := x.AppendTo(nil)
+ for _, v := range a {
+ y.Remove(v)
+ }
+
+ if got, want := x.Intersects(y), false; got != want {
+ t.Errorf("Intersects: got %v, want %v", got, want)
+ }
+
+ // make it true
+ if x.IsEmpty() {
+ continue
+ }
+ i := prng.Intn(len(a))
+ y.Insert(a[i])
+
+ if got, want := x.Intersects(y), true; got != want {
+ t.Errorf("Intersects: got %v, want %v", got, want)
+ }
+ }
+}
+
+func TestSubsetOf(t *testing.T) {
+ prng := rand.New(rand.NewSource(0))
+
+ for i := uint(0); i < 12; i++ {
+ X, Y := randomPset(prng, 1<<i), randomPset(prng, 1<<i)
+ x, y := &X.bits, &Y.bits
+
+ // test the slow way
+ var z intsets.Sparse
+ z.Copy(x)
+ z.DifferenceWith(y)
+
+ if got, want := x.SubsetOf(y), z.IsEmpty(); got != want {
+ t.Errorf("SubsetOf: got %v, want %v", got, want)
+ }
+
+ // make it true
+ y.UnionWith(x)
+
+ if got, want := x.SubsetOf(y), true; got != want {
+ t.Errorf("SubsetOf: got %v, want %v", got, want)
+ }
+
+ // make it false
+ if x.IsEmpty() {
+ continue
+ }
+ a := x.AppendTo(nil)
+ i := prng.Intn(len(a))
+ y.Remove(a[i])
+
+ if got, want := x.SubsetOf(y), false; got != want {
+ t.Errorf("SubsetOf: got %v, want %v", got, want)
+ }
+ }
+}
+
+func TestBitString(t *testing.T) {
+ for _, test := range []struct {
+ input []int
+ want string
+ }{
+ {nil, "0"},
+ {[]int{0}, "1"},
+ {[]int{0, 4, 5}, "110001"},
+ {[]int{0, 7, 177}, "1" + strings.Repeat("0", 169) + "10000001"},
+ {[]int{-3, 0, 4, 5}, "110001.001"},
+ {[]int{-3}, "0.001"},
+ } {
+ var set intsets.Sparse
+ for _, x := range test.input {
+ set.Insert(x)
+ }
+ if got := set.BitString(); got != test.want {
+ t.Errorf("BitString(%s) = %s, want %s", set.String(), got, test.want)
+ }
+ }
+}
+
+func TestFailFastOnShallowCopy(t *testing.T) {
+ var x intsets.Sparse
+ x.Insert(1)
+
+ y := x // shallow copy (breaks representation invariants)
+ defer func() {
+ got := fmt.Sprint(recover())
+ want := "A Sparse has been copied without (*Sparse).Copy()"
+ if got != want {
+ t.Errorf("shallow copy: recover() = %q, want %q", got, want)
+ }
+ }()
+ y.String() // panics
+ t.Error("didn't panic as expected")
+}
+
+// -- Benchmarks -------------------------------------------------------
+
+// TODO(adonovan):
+// - Add benchmarks of each method.
+// - Gather set distributions from pointer analysis.
+// - Measure memory usage.
+
+func BenchmarkSparseBitVector(b *testing.B) {
+ prng := rand.New(rand.NewSource(0))
+ for tries := 0; tries < b.N; tries++ {
+ var x, y, z intsets.Sparse
+ for i := 0; i < 1000; i++ {
+ n := int(prng.Int()) % 100000
+ if i%2 == 0 {
+ x.Insert(n)
+ } else {
+ y.Insert(n)
+ }
+ }
+ z.Union(&x, &y)
+ z.Difference(&x, &y)
+ }
+}
+
+func BenchmarkHashTable(b *testing.B) {
+ prng := rand.New(rand.NewSource(0))
+ for tries := 0; tries < b.N; tries++ {
+ x, y, z := make(map[int]bool), make(map[int]bool), make(map[int]bool)
+ for i := 0; i < 1000; i++ {
+ n := int(prng.Int()) % 100000
+ if i%2 == 0 {
+ x[n] = true
+ } else {
+ y[n] = true
+ }
+ }
+ // union
+ for n := range x {
+ z[n] = true
+ }
+ for n := range y {
+ z[n] = true
+ }
+ // difference
+ z = make(map[int]bool)
+ for n := range y {
+ if !x[n] {
+ z[n] = true
+ }
+ }
+ }
+}
+
+func BenchmarkAppendTo(b *testing.B) {
+ prng := rand.New(rand.NewSource(0))
+ var x intsets.Sparse
+ for i := 0; i < 1000; i++ {
+ x.Insert(int(prng.Int()) % 10000)
+ }
+ var space [1000]int
+ for tries := 0; tries < b.N; tries++ {
+ x.AppendTo(space[:0])
+ }
+}
diff --git a/container/intsets/util.go b/container/intsets/util.go
new file mode 100644
index 0000000..76e682c
--- /dev/null
+++ b/container/intsets/util.go
@@ -0,0 +1,75 @@
+// 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 intsets
+
+var a [1 << 8]byte
+
+func init() {
+ for i := range a {
+ var n byte
+ for x := i; x != 0; x >>= 1 {
+ if x&1 != 0 {
+ n++
+ }
+ }
+ a[i] = n
+ }
+}
+
+// popcount returns the population count (number of set bits) of x.
+func popcount(x word) int {
+ return int(a[byte(x>>(0*8))] +
+ a[byte(x>>(1*8))] +
+ a[byte(x>>(2*8))] +
+ a[byte(x>>(3*8))] +
+ a[byte(x>>(4*8))] +
+ a[byte(x>>(5*8))] +
+ a[byte(x>>(6*8))] +
+ a[byte(x>>(7*8))])
+}
+
+// nlz returns the number of leading zeros of x.
+// From Hacker's Delight, fig 5.11.
+func nlz(x word) int {
+ x |= (x >> 1)
+ x |= (x >> 2)
+ x |= (x >> 4)
+ x |= (x >> 8)
+ x |= (x >> 16)
+ x |= (x >> 32)
+ return popcount(^x)
+}
+
+// ntz returns the number of trailing zeros of x.
+// From Hacker's Delight, fig 5.13.
+func ntz(x word) int {
+ if x == 0 {
+ return bitsPerWord
+ }
+ n := 1
+ if bitsPerWord == 64 {
+ if (x & 0xffffffff) == 0 {
+ n = n + 32
+ x = x >> 32
+ }
+ }
+ if (x & 0x0000ffff) == 0 {
+ n = n + 16
+ x = x >> 16
+ }
+ if (x & 0x000000ff) == 0 {
+ n = n + 8
+ x = x >> 8
+ }
+ if (x & 0x0000000f) == 0 {
+ n = n + 4
+ x = x >> 4
+ }
+ if (x & 0x00000003) == 0 {
+ n = n + 2
+ x = x >> 2
+ }
+ return n - int(x&1)
+}
diff --git a/container/intsets/util_test.go b/container/intsets/util_test.go
new file mode 100644
index 0000000..92a4bc5
--- /dev/null
+++ b/container/intsets/util_test.go
@@ -0,0 +1,25 @@
+// 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 intsets
+
+import "testing"
+
+func TestNLZ(t *testing.T) {
+ // Test the platform-specific edge case.
+ // NB: v must be a var (not const) so that the word() conversion is dynamic.
+ // Otherwise the compiler will report an error.
+ v := uint64(0x0000801000000000)
+ n := nlz(word(v))
+ want := 32 // (on 32-bit)
+ if bitsPerWord == 64 {
+ want = 16
+ }
+ if n != want {
+ t.Errorf("%d-bit nlz(%d) = %d, want %d", bitsPerWord, v, n, want)
+ }
+}
+
+// Backdoor for testing.
+func (s *Sparse) Check() error { return s.check() }
diff --git a/cover/profile.go b/cover/profile.go
new file mode 100644
index 0000000..a53bf4e
--- /dev/null
+++ b/cover/profile.go
@@ -0,0 +1,190 @@
+// 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 cover provides support for parsing coverage profiles
+// generated by "go test -coverprofile=cover.out".
+package cover // import "golang.org/x/tools/cover"
+
+import (
+ "bufio"
+ "fmt"
+ "math"
+ "os"
+ "regexp"
+ "sort"
+ "strconv"
+ "strings"
+)
+
+// Profile represents the profiling data for a specific file.
+type Profile struct {
+ FileName string
+ Mode string
+ Blocks []ProfileBlock
+}
+
+// ProfileBlock represents a single block of profiling data.
+type ProfileBlock struct {
+ StartLine, StartCol int
+ EndLine, EndCol int
+ NumStmt, Count int
+}
+
+type byFileName []*Profile
+
+func (p byFileName) Len() int { return len(p) }
+func (p byFileName) Less(i, j int) bool { return p[i].FileName < p[j].FileName }
+func (p byFileName) Swap(i, j int) { p[i], p[j] = p[j], p[i] }
+
+// ParseProfiles parses profile data in the specified file and returns a
+// Profile for each source file described therein.
+func ParseProfiles(fileName string) ([]*Profile, error) {
+ pf, err := os.Open(fileName)
+ if err != nil {
+ return nil, err
+ }
+ defer pf.Close()
+
+ files := make(map[string]*Profile)
+ buf := bufio.NewReader(pf)
+ // First line is "mode: foo", where foo is "set", "count", or "atomic".
+ // Rest of file is in the format
+ // encoding/base64/base64.go:34.44,37.40 3 1
+ // where the fields are: name.go:line.column,line.column numberOfStatements count
+ s := bufio.NewScanner(buf)
+ mode := ""
+ for s.Scan() {
+ line := s.Text()
+ if mode == "" {
+ const p = "mode: "
+ if !strings.HasPrefix(line, p) || line == p {
+ return nil, fmt.Errorf("bad mode line: %v", line)
+ }
+ mode = line[len(p):]
+ continue
+ }
+ m := lineRe.FindStringSubmatch(line)
+ if m == nil {
+ return nil, fmt.Errorf("line %q doesn't match expected format: %v", m, lineRe)
+ }
+ fn := m[1]
+ p := files[fn]
+ if p == nil {
+ p = &Profile{
+ FileName: fn,
+ Mode: mode,
+ }
+ files[fn] = p
+ }
+ p.Blocks = append(p.Blocks, ProfileBlock{
+ StartLine: toInt(m[2]),
+ StartCol: toInt(m[3]),
+ EndLine: toInt(m[4]),
+ EndCol: toInt(m[5]),
+ NumStmt: toInt(m[6]),
+ Count: toInt(m[7]),
+ })
+ }
+ if err := s.Err(); err != nil {
+ return nil, err
+ }
+ for _, p := range files {
+ sort.Sort(blocksByStart(p.Blocks))
+ }
+ // Generate a sorted slice.
+ profiles := make([]*Profile, 0, len(files))
+ for _, profile := range files {
+ profiles = append(profiles, profile)
+ }
+ sort.Sort(byFileName(profiles))
+ return profiles, nil
+}
+
+type blocksByStart []ProfileBlock
+
+func (b blocksByStart) Len() int { return len(b) }
+func (b blocksByStart) Swap(i, j int) { b[i], b[j] = b[j], b[i] }
+func (b blocksByStart) Less(i, j int) bool {
+ bi, bj := b[i], b[j]
+ return bi.StartLine < bj.StartLine || bi.StartLine == bj.StartLine && bi.StartCol < bj.StartCol
+}
+
+var lineRe = regexp.MustCompile(`^(.+):([0-9]+).([0-9]+),([0-9]+).([0-9]+) ([0-9]+) ([0-9]+)$`)
+
+func toInt(s string) int {
+ i, err := strconv.Atoi(s)
+ if err != nil {
+ panic(err)
+ }
+ return i
+}
+
+// Boundary represents the position in a source file of the beginning or end of a
+// block as reported by the coverage profile. In HTML mode, it will correspond to
+// the opening or closing of a <span> tag and will be used to colorize the source
+type Boundary struct {
+ Offset int // Location as a byte offset in the source file.
+ Start bool // Is this the start of a block?
+ Count int // Event count from the cover profile.
+ Norm float64 // Count normalized to [0..1].
+}
+
+// Boundaries returns a Profile as a set of Boundary objects within the provided src.
+func (p *Profile) Boundaries(src []byte) (boundaries []Boundary) {
+ // Find maximum count.
+ max := 0
+ for _, b := range p.Blocks {
+ if b.Count > max {
+ max = b.Count
+ }
+ }
+ // Divisor for normalization.
+ divisor := math.Log(float64(max))
+
+ // boundary returns a Boundary, populating the Norm field with a normalized Count.
+ boundary := func(offset int, start bool, count int) Boundary {
+ b := Boundary{Offset: offset, Start: start, Count: count}
+ if !start || count == 0 {
+ return b
+ }
+ if max <= 1 {
+ b.Norm = 0.8 // Profile is in"set" mode; we want a heat map. Use cov8 in the CSS.
+ } else if count > 0 {
+ b.Norm = math.Log(float64(count)) / divisor
+ }
+ return b
+ }
+
+ line, col := 1, 2 // TODO: Why is this 2?
+ for si, bi := 0, 0; si < len(src) && bi < len(p.Blocks); {
+ b := p.Blocks[bi]
+ if b.StartLine == line && b.StartCol == col {
+ boundaries = append(boundaries, boundary(si, true, b.Count))
+ }
+ if b.EndLine == line && b.EndCol == col || line > b.EndLine {
+ boundaries = append(boundaries, boundary(si, false, 0))
+ bi++
+ continue // Don't advance through src; maybe the next block starts here.
+ }
+ if src[si] == '\n' {
+ line++
+ col = 0
+ }
+ col++
+ si++
+ }
+ sort.Sort(boundariesByPos(boundaries))
+ return
+}
+
+type boundariesByPos []Boundary
+
+func (b boundariesByPos) Len() int { return len(b) }
+func (b boundariesByPos) Swap(i, j int) { b[i], b[j] = b[j], b[i] }
+func (b boundariesByPos) Less(i, j int) bool {
+ if b[i].Offset == b[j].Offset {
+ return !b[i].Start && b[j].Start
+ }
+ return b[i].Offset < b[j].Offset
+}
diff --git a/go/ast/astutil/enclosing.go b/go/ast/astutil/enclosing.go
new file mode 100644
index 0000000..2de739e
--- /dev/null
+++ b/go/ast/astutil/enclosing.go
@@ -0,0 +1,625 @@
+// 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 astutil
+
+// This file defines utilities for working with source positions.
+
+import (
+ "fmt"
+ "go/ast"
+ "go/token"
+ "sort"
+)
+
+// PathEnclosingInterval returns the node that encloses the source
+// interval [start, end), and all its ancestors up to the AST root.
+//
+// The definition of "enclosing" used by this function considers
+// additional whitespace abutting a node to be enclosed by it.
+// In this example:
+//
+// z := x + y // add them
+// <-A->
+// <----B----->
+//
+// the ast.BinaryExpr(+) node is considered to enclose interval B
+// even though its [Pos()..End()) is actually only interval A.
+// This behaviour makes user interfaces more tolerant of imperfect
+// input.
+//
+// This function treats tokens as nodes, though they are not included
+// in the result. e.g. PathEnclosingInterval("+") returns the
+// enclosing ast.BinaryExpr("x + y").
+//
+// If start==end, the 1-char interval following start is used instead.
+//
+// The 'exact' result is true if the interval contains only path[0]
+// and perhaps some adjacent whitespace. It is false if the interval
+// overlaps multiple children of path[0], or if it contains only
+// interior whitespace of path[0].
+// In this example:
+//
+// z := x + y // add them
+// <--C--> <---E-->
+// ^
+// D
+//
+// intervals C, D and E are inexact. C is contained by the
+// z-assignment statement, because it spans three of its children (:=,
+// x, +). So too is the 1-char interval D, because it contains only
+// interior whitespace of the assignment. E is considered interior
+// whitespace of the BlockStmt containing the assignment.
+//
+// Precondition: [start, end) both lie within the same file as root.
+// TODO(adonovan): return (nil, false) in this case and remove precond.
+// Requires FileSet; see loader.tokenFileContainsPos.
+//
+// Postcondition: path is never nil; it always contains at least 'root'.
+//
+func PathEnclosingInterval(root *ast.File, start, end token.Pos) (path []ast.Node, exact bool) {
+ // fmt.Printf("EnclosingInterval %d %d\n", start, end) // debugging
+
+ // Precondition: node.[Pos..End) and adjoining whitespace contain [start, end).
+ var visit func(node ast.Node) bool
+ visit = func(node ast.Node) bool {
+ path = append(path, node)
+
+ nodePos := node.Pos()
+ nodeEnd := node.End()
+
+ // fmt.Printf("visit(%T, %d, %d)\n", node, nodePos, nodeEnd) // debugging
+
+ // Intersect [start, end) with interval of node.
+ if start < nodePos {
+ start = nodePos
+ }
+ if end > nodeEnd {
+ end = nodeEnd
+ }
+
+ // Find sole child that contains [start, end).
+ children := childrenOf(node)
+ l := len(children)
+ for i, child := range children {
+ // [childPos, childEnd) is unaugmented interval of child.
+ childPos := child.Pos()
+ childEnd := child.End()
+
+ // [augPos, augEnd) is whitespace-augmented interval of child.
+ augPos := childPos
+ augEnd := childEnd
+ if i > 0 {
+ augPos = children[i-1].End() // start of preceding whitespace
+ }
+ if i < l-1 {
+ nextChildPos := children[i+1].Pos()
+ // Does [start, end) lie between child and next child?
+ if start >= augEnd && end <= nextChildPos {
+ return false // inexact match
+ }
+ augEnd = nextChildPos // end of following whitespace
+ }
+
+ // fmt.Printf("\tchild %d: [%d..%d)\tcontains interval [%d..%d)?\n",
+ // i, augPos, augEnd, start, end) // debugging
+
+ // Does augmented child strictly contain [start, end)?
+ if augPos <= start && end <= augEnd {
+ _, isToken := child.(tokenNode)
+ return isToken || visit(child)
+ }
+
+ // Does [start, end) overlap multiple children?
+ // i.e. left-augmented child contains start
+ // but LR-augmented child does not contain end.
+ if start < childEnd && end > augEnd {
+ break
+ }
+ }
+
+ // No single child contained [start, end),
+ // so node is the result. Is it exact?
+
+ // (It's tempting to put this condition before the
+ // child loop, but it gives the wrong result in the
+ // case where a node (e.g. ExprStmt) and its sole
+ // child have equal intervals.)
+ if start == nodePos && end == nodeEnd {
+ return true // exact match
+ }
+
+ return false // inexact: overlaps multiple children
+ }
+
+ if start > end {
+ start, end = end, start
+ }
+
+ if start < root.End() && end > root.Pos() {
+ if start == end {
+ end = start + 1 // empty interval => interval of size 1
+ }
+ exact = visit(root)
+
+ // Reverse the path:
+ for i, l := 0, len(path); i < l/2; i++ {
+ path[i], path[l-1-i] = path[l-1-i], path[i]
+ }
+ } else {
+ // Selection lies within whitespace preceding the
+ // first (or following the last) declaration in the file.
+ // The result nonetheless always includes the ast.File.
+ path = append(path, root)
+ }
+
+ return
+}
+
+// tokenNode is a dummy implementation of ast.Node for a single token.
+// They are used transiently by PathEnclosingInterval but never escape
+// this package.
+//
+type tokenNode struct {
+ pos token.Pos
+ end token.Pos
+}
+
+func (n tokenNode) Pos() token.Pos {
+ return n.pos
+}
+
+func (n tokenNode) End() token.Pos {
+ return n.end
+}
+
+func tok(pos token.Pos, len int) ast.Node {
+ return tokenNode{pos, pos + token.Pos(len)}
+}
+
+// childrenOf returns the direct non-nil children of ast.Node n.
+// It may include fake ast.Node implementations for bare tokens.
+// it is not safe to call (e.g.) ast.Walk on such nodes.
+//
+func childrenOf(n ast.Node) []ast.Node {
+ var children []ast.Node
+
+ // First add nodes for all true subtrees.
+ ast.Inspect(n, func(node ast.Node) bool {
+ if node == n { // push n
+ return true // recur
+ }
+ if node != nil { // push child
+ children = append(children, node)
+ }
+ return false // no recursion
+ })
+
+ // Then add fake Nodes for bare tokens.
+ switch n := n.(type) {
+ case *ast.ArrayType:
+ children = append(children,
+ tok(n.Lbrack, len("[")),
+ tok(n.Elt.End(), len("]")))
+
+ case *ast.AssignStmt:
+ children = append(children,
+ tok(n.TokPos, len(n.Tok.String())))
+
+ case *ast.BasicLit:
+ children = append(children,
+ tok(n.ValuePos, len(n.Value)))
+
+ case *ast.BinaryExpr:
+ children = append(children, tok(n.OpPos, len(n.Op.String())))
+
+ case *ast.BlockStmt:
+ children = append(children,
+ tok(n.Lbrace, len("{")),
+ tok(n.Rbrace, len("}")))
+
+ case *ast.BranchStmt:
+ children = append(children,
+ tok(n.TokPos, len(n.Tok.String())))
+
+ case *ast.CallExpr:
+ children = append(children,
+ tok(n.Lparen, len("(")),
+ tok(n.Rparen, len(")")))
+ if n.Ellipsis != 0 {
+ children = append(children, tok(n.Ellipsis, len("...")))
+ }
+
+ case *ast.CaseClause:
+ if n.List == nil {
+ children = append(children,
+ tok(n.Case, len("default")))
+ } else {
+ children = append(children,
+ tok(n.Case, len("case")))
+ }
+ children = append(children, tok(n.Colon, len(":")))
+
+ case *ast.ChanType:
+ switch n.Dir {
+ case ast.RECV:
+ children = append(children, tok(n.Begin, len("<-chan")))
+ case ast.SEND:
+ children = append(children, tok(n.Begin, len("chan<-")))
+ case ast.RECV | ast.SEND:
+ children = append(children, tok(n.Begin, len("chan")))
+ }
+
+ case *ast.CommClause:
+ if n.Comm == nil {
+ children = append(children,
+ tok(n.Case, len("default")))
+ } else {
+ children = append(children,
+ tok(n.Case, len("case")))
+ }
+ children = append(children, tok(n.Colon, len(":")))
+
+ case *ast.Comment:
+ // nop
+
+ case *ast.CommentGroup:
+ // nop
+
+ case *ast.CompositeLit:
+ children = append(children,
+ tok(n.Lbrace, len("{")),
+ tok(n.Rbrace, len("{")))
+
+ case *ast.DeclStmt:
+ // nop
+
+ case *ast.DeferStmt:
+ children = append(children,
+ tok(n.Defer, len("defer")))
+
+ case *ast.Ellipsis:
+ children = append(children,
+ tok(n.Ellipsis, len("...")))
+
+ case *ast.EmptyStmt:
+ // nop
+
+ case *ast.ExprStmt:
+ // nop
+
+ case *ast.Field:
+ // TODO(adonovan): Field.{Doc,Comment,Tag}?
+
+ case *ast.FieldList:
+ children = append(children,
+ tok(n.Opening, len("(")),
+ tok(n.Closing, len(")")))
+
+ case *ast.File:
+ // TODO test: Doc
+ children = append(children,
+ tok(n.Package, len("package")))
+
+ case *ast.ForStmt:
+ children = append(children,
+ tok(n.For, len("for")))
+
+ case *ast.FuncDecl:
+ // TODO(adonovan): FuncDecl.Comment?
+
+ // Uniquely, FuncDecl breaks the invariant that
+ // preorder traversal yields tokens in lexical order:
+ // in fact, FuncDecl.Recv precedes FuncDecl.Type.Func.
+ //
+ // As a workaround, we inline the case for FuncType
+ // here and order things correctly.
+ //
+ children = nil // discard ast.Walk(FuncDecl) info subtrees
+ children = append(children, tok(n.Type.Func, len("func")))
+ if n.Recv != nil {
+ children = append(children, n.Recv)
+ }
+ children = append(children, n.Name)
+ if n.Type.Params != nil {
+ children = append(children, n.Type.Params)
+ }
+ if n.Type.Results != nil {
+ children = append(children, n.Type.Results)
+ }
+ if n.Body != nil {
+ children = append(children, n.Body)
+ }
+
+ case *ast.FuncLit:
+ // nop
+
+ case *ast.FuncType:
+ if n.Func != 0 {
+ children = append(children,
+ tok(n.Func, len("func")))
+ }
+
+ case *ast.GenDecl:
+ children = append(children,
+ tok(n.TokPos, len(n.Tok.String())))
+ if n.Lparen != 0 {
+ children = append(children,
+ tok(n.Lparen, len("(")),
+ tok(n.Rparen, len(")")))
+ }
+
+ case *ast.GoStmt:
+ children = append(children,
+ tok(n.Go, len("go")))
+
+ case *ast.Ident:
+ children = append(children,
+ tok(n.NamePos, len(n.Name)))
+
+ case *ast.IfStmt:
+ children = append(children,
+ tok(n.If, len("if")))
+
+ case *ast.ImportSpec:
+ // TODO(adonovan): ImportSpec.{Doc,EndPos}?
+
+ case *ast.IncDecStmt:
+ children = append(children,
+ tok(n.TokPos, len(n.Tok.String())))
+
+ case *ast.IndexExpr:
+ children = append(children,
+ tok(n.Lbrack, len("{")),
+ tok(n.Rbrack, len("}")))
+
+ case *ast.InterfaceType:
+ children = append(children,
+ tok(n.Interface, len("interface")))
+
+ case *ast.KeyValueExpr:
+ children = append(children,
+ tok(n.Colon, len(":")))
+
+ case *ast.LabeledStmt:
+ children = append(children,
+ tok(n.Colon, len(":")))
+
+ case *ast.MapType:
+ children = append(children,
+ tok(n.Map, len("map")))
+
+ case *ast.ParenExpr:
+ children = append(children,
+ tok(n.Lparen, len("(")),
+ tok(n.Rparen, len(")")))
+
+ case *ast.RangeStmt:
+ children = append(children,
+ tok(n.For, len("for")),
+ tok(n.TokPos, len(n.Tok.String())))
+
+ case *ast.ReturnStmt:
+ children = append(children,
+ tok(n.Return, len("return")))
+
+ case *ast.SelectStmt:
+ children = append(children,
+ tok(n.Select, len("select")))
+
+ case *ast.SelectorExpr:
+ // nop
+
+ case *ast.SendStmt:
+ children = append(children,
+ tok(n.Arrow, len("<-")))
+
+ case *ast.SliceExpr:
+ children = append(children,
+ tok(n.Lbrack, len("[")),
+ tok(n.Rbrack, len("]")))
+
+ case *ast.StarExpr:
+ children = append(children, tok(n.Star, len("*")))
+
+ case *ast.StructType:
+ children = append(children, tok(n.Struct, len("struct")))
+
+ case *ast.SwitchStmt:
+ children = append(children, tok(n.Switch, len("switch")))
+
+ case *ast.TypeAssertExpr:
+ children = append(children,
+ tok(n.Lparen-1, len(".")),
+ tok(n.Lparen, len("(")),
+ tok(n.Rparen, len(")")))
+
+ case *ast.TypeSpec:
+ // TODO(adonovan): TypeSpec.{Doc,Comment}?
+
+ case *ast.TypeSwitchStmt:
+ children = append(children, tok(n.Switch, len("switch")))
+
+ case *ast.UnaryExpr:
+ children = append(children, tok(n.OpPos, len(n.Op.String())))
+
+ case *ast.ValueSpec:
+ // TODO(adonovan): ValueSpec.{Doc,Comment}?
+
+ default:
+ // Includes *ast.BadDecl, *ast.BadExpr, *ast.BadStmt.
+ panic(fmt.Sprintf("unexpected node type %T", n))
+ }
+
+ // TODO(adonovan): opt: merge the logic of ast.Inspect() into
+ // the switch above so we can make interleaved callbacks for
+ // both Nodes and Tokens in the right order and avoid the need
+ // to sort.
+ sort.Sort(byPos(children))
+
+ return children
+}
+
+type byPos []ast.Node
+
+func (sl byPos) Len() int {
+ return len(sl)
+}
+func (sl byPos) Less(i, j int) bool {
+ return sl[i].Pos() < sl[j].Pos()
+}
+func (sl byPos) Swap(i, j int) {
+ sl[i], sl[j] = sl[j], sl[i]
+}
+
+// NodeDescription returns a description of the concrete type of n suitable
+// for a user interface.
+//
+// TODO(adonovan): in some cases (e.g. Field, FieldList, Ident,
+// StarExpr) we could be much more specific given the path to the AST
+// root. Perhaps we should do that.
+//
+func NodeDescription(n ast.Node) string {
+ switch n := n.(type) {
+ case *ast.ArrayType:
+ return "array type"
+ case *ast.AssignStmt:
+ return "assignment"
+ case *ast.BadDecl:
+ return "bad declaration"
+ case *ast.BadExpr:
+ return "bad expression"
+ case *ast.BadStmt:
+ return "bad statement"
+ case *ast.BasicLit:
+ return "basic literal"
+ case *ast.BinaryExpr:
+ return fmt.Sprintf("binary %s operation", n.Op)
+ case *ast.BlockStmt:
+ return "block"
+ case *ast.BranchStmt:
+ switch n.Tok {
+ case token.BREAK:
+ return "break statement"
+ case token.CONTINUE:
+ return "continue statement"
+ case token.GOTO:
+ return "goto statement"
+ case token.FALLTHROUGH:
+ return "fall-through statement"
+ }
+ case *ast.CallExpr:
+ return "function call (or conversion)"
+ case *ast.CaseClause:
+ return "case clause"
+ case *ast.ChanType:
+ return "channel type"
+ case *ast.CommClause:
+ return "communication clause"
+ case *ast.Comment:
+ return "comment"
+ case *ast.CommentGroup:
+ return "comment group"
+ case *ast.CompositeLit:
+ return "composite literal"
+ case *ast.DeclStmt:
+ return NodeDescription(n.Decl) + " statement"
+ case *ast.DeferStmt:
+ return "defer statement"
+ case *ast.Ellipsis:
+ return "ellipsis"
+ case *ast.EmptyStmt:
+ return "empty statement"
+ case *ast.ExprStmt:
+ return "expression statement"
+ case *ast.Field:
+ // Can be any of these:
+ // struct {x, y int} -- struct field(s)
+ // struct {T} -- anon struct field
+ // interface {I} -- interface embedding
+ // interface {f()} -- interface method
+ // func (A) func(B) C -- receiver, param(s), result(s)
+ return "field/method/parameter"
+ case *ast.FieldList:
+ return "field/method/parameter list"
+ case *ast.File:
+ return "source file"
+ case *ast.ForStmt:
+ return "for loop"
+ case *ast.FuncDecl:
+ return "function declaration"
+ case *ast.FuncLit:
+ return "function literal"
+ case *ast.FuncType:
+ return "function type"
+ case *ast.GenDecl:
+ switch n.Tok {
+ case token.IMPORT:
+ return "import declaration"
+ case token.CONST:
+ return "constant declaration"
+ case token.TYPE:
+ return "type declaration"
+ case token.VAR:
+ return "variable declaration"
+ }
+ case *ast.GoStmt:
+ return "go statement"
+ case *ast.Ident:
+ return "identifier"
+ case *ast.IfStmt:
+ return "if statement"
+ case *ast.ImportSpec:
+ return "import specification"
+ case *ast.IncDecStmt:
+ if n.Tok == token.INC {
+ return "increment statement"
+ }
+ return "decrement statement"
+ case *ast.IndexExpr:
+ return "index expression"
+ case *ast.InterfaceType:
+ return "interface type"
+ case *ast.KeyValueExpr:
+ return "key/value association"
+ case *ast.LabeledStmt:
+ return "statement label"
+ case *ast.MapType:
+ return "map type"
+ case *ast.Package:
+ return "package"
+ case *ast.ParenExpr:
+ return "parenthesized " + NodeDescription(n.X)
+ case *ast.RangeStmt:
+ return "range loop"
+ case *ast.ReturnStmt:
+ return "return statement"
+ case *ast.SelectStmt:
+ return "select statement"
+ case *ast.SelectorExpr:
+ return "selector"
+ case *ast.SendStmt:
+ return "channel send"
+ case *ast.SliceExpr:
+ return "slice expression"
+ case *ast.StarExpr:
+ return "*-operation" // load/store expr or pointer type
+ case *ast.StructType:
+ return "struct type"
+ case *ast.SwitchStmt:
+ return "switch statement"
+ case *ast.TypeAssertExpr:
+ return "type assertion"
+ case *ast.TypeSpec:
+ return "type specification"
+ case *ast.TypeSwitchStmt:
+ return "type switch"
+ case *ast.UnaryExpr:
+ return fmt.Sprintf("unary %s operation", n.Op)
+ case *ast.ValueSpec:
+ return "value specification"
+
+ }
+ panic(fmt.Sprintf("unexpected node type: %T", n))
+}
diff --git a/go/ast/astutil/enclosing_test.go b/go/ast/astutil/enclosing_test.go
new file mode 100644
index 0000000..107f87c
--- /dev/null
+++ b/go/ast/astutil/enclosing_test.go
@@ -0,0 +1,195 @@
+// 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 astutil_test
+
+// This file defines tests of PathEnclosingInterval.
+
+// TODO(adonovan): exhaustive tests that run over the whole input
+// tree, not just handcrafted examples.
+
+import (
+ "bytes"
+ "fmt"
+ "go/ast"
+ "go/parser"
+ "go/token"
+ "strings"
+ "testing"
+
+ "golang.org/x/tools/go/ast/astutil"
+)
+
+// pathToString returns a string containing the concrete types of the
+// nodes in path.
+func pathToString(path []ast.Node) string {
+ var buf bytes.Buffer
+ fmt.Fprint(&buf, "[")
+ for i, n := range path {
+ if i > 0 {
+ fmt.Fprint(&buf, " ")
+ }
+ fmt.Fprint(&buf, strings.TrimPrefix(fmt.Sprintf("%T", n), "*ast."))
+ }
+ fmt.Fprint(&buf, "]")
+ return buf.String()
+}
+
+// findInterval parses input and returns the [start, end) positions of
+// the first occurrence of substr in input. f==nil indicates failure;
+// an error has already been reported in that case.
+//
+func findInterval(t *testing.T, fset *token.FileSet, input, substr string) (f *ast.File, start, end token.Pos) {
+ f, err := parser.ParseFile(fset, "<input>", input, 0)
+ if err != nil {
+ t.Errorf("parse error: %s", err)
+ return
+ }
+
+ i := strings.Index(input, substr)
+ if i < 0 {
+ t.Errorf("%q is not a substring of input", substr)
+ f = nil
+ return
+ }
+
+ filePos := fset.File(f.Package)
+ return f, filePos.Pos(i), filePos.Pos(i + len(substr))
+}
+
+// Common input for following tests.
+const input = `
+// Hello.
+package main
+import "fmt"
+func f() {}
+func main() {
+ z := (x + y) // add them
+ f() // NB: ExprStmt and its CallExpr have same Pos/End
+}
+`
+
+func TestPathEnclosingInterval_Exact(t *testing.T) {
+ // For the exact tests, we check that a substring is mapped to
+ // the canonical string for the node it denotes.
+ tests := []struct {
+ substr string // first occurrence of this string indicates interval
+ node string // complete text of expected containing node
+ }{
+ {"package",
+ input[11 : len(input)-1]},
+ {"\npack",
+ input[11 : len(input)-1]},
+ {"main",
+ "main"},
+ {"import",
+ "import \"fmt\""},
+ {"\"fmt\"",
+ "\"fmt\""},
+ {"\nfunc f() {}\n",
+ "func f() {}"},
+ {"x ",
+ "x"},
+ {" y",
+ "y"},
+ {"z",
+ "z"},
+ {" + ",
+ "x + y"},
+ {" :=",
+ "z := (x + y)"},
+ {"x + y",
+ "x + y"},
+ {"(x + y)",
+ "(x + y)"},
+ {" (x + y) ",
+ "(x + y)"},
+ {" (x + y) // add",
+ "(x + y)"},
+ {"func",
+ "func f() {}"},
+ {"func f() {}",
+ "func f() {}"},
+ {"\nfun",
+ "func f() {}"},
+ {" f",
+ "f"},
+ }
+ for _, test := range tests {
+ f, start, end := findInterval(t, new(token.FileSet), input, test.substr)
+ if f == nil {
+ continue
+ }
+
+ path, exact := astutil.PathEnclosingInterval(f, start, end)
+ if !exact {
+ t.Errorf("PathEnclosingInterval(%q) not exact", test.substr)
+ continue
+ }
+
+ if len(path) == 0 {
+ if test.node != "" {
+ t.Errorf("PathEnclosingInterval(%q).path: got [], want %q",
+ test.substr, test.node)
+ }
+ continue
+ }
+
+ if got := input[path[0].Pos():path[0].End()]; got != test.node {
+ t.Errorf("PathEnclosingInterval(%q): got %q, want %q (path was %s)",
+ test.substr, got, test.node, pathToString(path))
+ continue
+ }
+ }
+}
+
+func TestPathEnclosingInterval_Paths(t *testing.T) {
+ // For these tests, we check only the path of the enclosing
+ // node, but not its complete text because it's often quite
+ // large when !exact.
+ tests := []struct {
+ substr string // first occurrence of this string indicates interval
+ path string // the pathToString(),exact of the expected path
+ }{
+ {"// add",
+ "[BlockStmt FuncDecl File],false"},
+ {"(x + y",
+ "[ParenExpr AssignStmt BlockStmt FuncDecl File],false"},
+ {"x +",
+ "[BinaryExpr ParenExpr AssignStmt BlockStmt FuncDecl File],false"},
+ {"z := (x",
+ "[AssignStmt BlockStmt FuncDecl File],false"},
+ {"func f",
+ "[FuncDecl File],false"},
+ {"func f()",
+ "[FuncDecl File],false"},
+ {" f()",
+ "[FuncDecl File],false"},
+ {"() {}",
+ "[FuncDecl File],false"},
+ {"// Hello",
+ "[File],false"},
+ {" f",
+ "[Ident FuncDecl File],true"},
+ {"func ",
+ "[FuncDecl File],true"},
+ {"mai",
+ "[Ident File],true"},
+ {"f() // NB",
+ "[CallExpr ExprStmt BlockStmt FuncDecl File],true"},
+ }
+ for _, test := range tests {
+ f, start, end := findInterval(t, new(token.FileSet), input, test.substr)
+ if f == nil {
+ continue
+ }
+
+ path, exact := astutil.PathEnclosingInterval(f, start, end)
+ if got := fmt.Sprintf("%s,%v", pathToString(path), exact); got != test.path {
+ t.Errorf("PathEnclosingInterval(%q): got %q, want %q",
+ test.substr, got, test.path)
+ continue
+ }
+ }
+}
diff --git a/go/ast/astutil/imports.go b/go/ast/astutil/imports.go
new file mode 100644
index 0000000..7f9b162
--- /dev/null
+++ b/go/ast/astutil/imports.go
@@ -0,0 +1,359 @@
+// 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 astutil contains common utilities for working with the Go AST.
+package astutil // import "golang.org/x/tools/go/ast/astutil"
+
+import (
+ "fmt"
+ "go/ast"
+ "go/token"
+ "strconv"
+ "strings"
+)
+
+// AddImport adds the import path to the file f, if absent.
+func AddImport(fset *token.FileSet, f *ast.File, ipath string) (added bool) {
+ return AddNamedImport(fset, f, "", ipath)
+}
+
+// AddNamedImport adds the import path to the file f, if absent.
+// If name is not empty, it is used to rename the import.
+//
+// For example, calling
+// AddNamedImport(fset, f, "pathpkg", "path")
+// adds
+// import pathpkg "path"
+func AddNamedImport(fset *token.FileSet, f *ast.File, name, ipath string) (added bool) {
+ if imports(f, ipath) {
+ return false
+ }
+
+ newImport := &ast.ImportSpec{
+ Path: &ast.BasicLit{
+ Kind: token.STRING,
+ Value: strconv.Quote(ipath),
+ },
+ }
+ if name != "" {
+ newImport.Name = &ast.Ident{Name: name}
+ }
+
+ // Find an import decl to add to.
+ // The goal is to find an existing import
+ // whose import path has the longest shared
+ // prefix with ipath.
+ var (
+ bestMatch = -1 // length of longest shared prefix
+ lastImport = -1 // index in f.Decls of the file's final import decl
+ impDecl *ast.GenDecl // import decl containing the best match
+ impIndex = -1 // spec index in impDecl containing the best match
+ )
+ for i, decl := range f.Decls {
+ gen, ok := decl.(*ast.GenDecl)
+ if ok && gen.Tok == token.IMPORT {
+ lastImport = i
+ // Do not add to import "C", to avoid disrupting the
+ // association with its doc comment, breaking cgo.
+ if declImports(gen, "C") {
+ continue
+ }
+
+ // Match an empty import decl if that's all that is available.
+ if len(gen.Specs) == 0 && bestMatch == -1 {
+ impDecl = gen
+ }
+
+ // Compute longest shared prefix with imports in this group.
+ for j, spec := range gen.Specs {
+ impspec := spec.(*ast.ImportSpec)
+ n := matchLen(importPath(impspec), ipath)
+ if n > bestMatch {
+ bestMatch = n
+ impDecl = gen
+ impIndex = j
+ }
+ }
+ }
+ }
+
+ // If no import decl found, add one after the last import.
+ if impDecl == nil {
+ impDecl = &ast.GenDecl{
+ Tok: token.IMPORT,
+ }
+ if lastImport >= 0 {
+ impDecl.TokPos = f.Decls[lastImport].End()
+ } else {
+ // There are no existing imports.
+ // Our new import goes after the package declaration and after
+ // the comment, if any, that starts on the same line as the
+ // package declaration.
+ impDecl.TokPos = f.Package
+
+ file := fset.File(f.Package)
+ pkgLine := file.Line(f.Package)
+ for _, c := range f.Comments {
+ if file.Line(c.Pos()) > pkgLine {
+ break
+ }
+ impDecl.TokPos = c.End()
+ }
+ }
+ f.Decls = append(f.Decls, nil)
+ copy(f.Decls[lastImport+2:], f.Decls[lastImport+1:])
+ f.Decls[lastImport+1] = impDecl
+ }
+
+ // Insert new import at insertAt.
+ insertAt := 0
+ if impIndex >= 0 {
+ // insert after the found import
+ insertAt = impIndex + 1
+ }
+ impDecl.Specs = append(impDecl.Specs, nil)
+ copy(impDecl.Specs[insertAt+1:], impDecl.Specs[insertAt:])
+ impDecl.Specs[insertAt] = newImport
+ pos := impDecl.Pos()
+ if insertAt > 0 {
+ // Assign same position as the previous import,
+ // so that the sorter sees it as being in the same block.
+ pos = impDecl.Specs[insertAt-1].Pos()
+ }
+ if newImport.Name != nil {
+ newImport.Name.NamePos = pos
+ }
+ newImport.Path.ValuePos = pos
+ newImport.EndPos = pos
+
+ // Clean up parens. impDecl contains at least one spec.
+ if len(impDecl.Specs) == 1 {
+ // Remove unneeded parens.
+ impDecl.Lparen = token.NoPos
+ } else if !impDecl.Lparen.IsValid() {
+ // impDecl needs parens added.
+ impDecl.Lparen = impDecl.Specs[0].Pos()
+ }
+
+ f.Imports = append(f.Imports, newImport)
+ return true
+}
+
+// DeleteImport deletes the import path from the file f, if present.
+func DeleteImport(fset *token.FileSet, f *ast.File, path string) (deleted bool) {
+ var delspecs []*ast.ImportSpec
+
+ // Find the import nodes that import path, if any.
+ for i := 0; i < len(f.Decls); i++ {
+ decl := f.Decls[i]
+ gen, ok := decl.(*ast.GenDecl)
+ if !ok || gen.Tok != token.IMPORT {
+ continue
+ }
+ for j := 0; j < len(gen.Specs); j++ {
+ spec := gen.Specs[j]
+ impspec := spec.(*ast.ImportSpec)
+ if importPath(impspec) != path {
+ continue
+ }
+
+ // We found an import spec that imports path.
+ // Delete it.
+ delspecs = append(delspecs, impspec)
+ deleted = true
+ copy(gen.Specs[j:], gen.Specs[j+1:])
+ gen.Specs = gen.Specs[:len(gen.Specs)-1]
+
+ // If this was the last import spec in this decl,
+ // delete the decl, too.
+ if len(gen.Specs) == 0 {
+ copy(f.Decls[i:], f.Decls[i+1:])
+ f.Decls = f.Decls[:len(f.Decls)-1]
+ i--
+ break
+ } else if len(gen.Specs) == 1 {
+ gen.Lparen = token.NoPos // drop parens
+ }
+ if j > 0 {
+ lastImpspec := gen.Specs[j-1].(*ast.ImportSpec)
+ lastLine := fset.Position(lastImpspec.Path.ValuePos).Line
+ line := fset.Position(impspec.Path.ValuePos).Line
+
+ // We deleted an entry but now there may be
+ // a blank line-sized hole where the import was.
+ if line-lastLine > 1 {
+ // There was a blank line immediately preceding the deleted import,
+ // so there's no need to close the hole.
+ // Do nothing.
+ } else {
+ // There was no blank line. Close the hole.
+ fset.File(gen.Rparen).MergeLine(line)
+ }
+ }
+ j--
+ }
+ }
+
+ // Delete them from f.Imports.
+ for i := 0; i < len(f.Imports); i++ {
+ imp := f.Imports[i]
+ for j, del := range delspecs {
+ if imp == del {
+ copy(f.Imports[i:], f.Imports[i+1:])
+ f.Imports = f.Imports[:len(f.Imports)-1]
+ copy(delspecs[j:], delspecs[j+1:])
+ delspecs = delspecs[:len(delspecs)-1]
+ i--
+ break
+ }
+ }
+ }
+
+ if len(delspecs) > 0 {
+ panic(fmt.Sprintf("deleted specs from Decls but not Imports: %v", delspecs))
+ }
+
+ return
+}
+
+// RewriteImport rewrites any import of path oldPath to path newPath.
+func RewriteImport(fset *token.FileSet, f *ast.File, oldPath, newPath string) (rewrote bool) {
+ for _, imp := range f.Imports {
+ if importPath(imp) == oldPath {
+ rewrote = true
+ // record old End, because the default is to compute
+ // it using the length of imp.Path.Value.
+ imp.EndPos = imp.End()
+ imp.Path.Value = strconv.Quote(newPath)
+ }
+ }
+ return
+}
+
+// UsesImport reports whether a given import is used.
+func UsesImport(f *ast.File, path string) (used bool) {
+ spec := importSpec(f, path)
+ if spec == nil {
+ return
+ }
+
+ name := spec.Name.String()
+ switch name {
+ case "<nil>":
+ // If the package name is not explicitly specified,
+ // make an educated guess. This is not guaranteed to be correct.
+ lastSlash := strings.LastIndex(path, "/")
+ if lastSlash == -1 {
+ name = path
+ } else {
+ name = path[lastSlash+1:]
+ }
+ case "_", ".":
+ // Not sure if this import is used - err on the side of caution.
+ return true
+ }
+
+ ast.Walk(visitFn(func(n ast.Node) {
+ sel, ok := n.(*ast.SelectorExpr)
+ if ok && isTopName(sel.X, name) {
+ used = true
+ }
+ }), f)
+
+ return
+}
+
+type visitFn func(node ast.Node)
+
+func (fn visitFn) Visit(node ast.Node) ast.Visitor {
+ fn(node)
+ return fn
+}
+
+// imports returns true if f imports path.
+func imports(f *ast.File, path string) bool {
+ return importSpec(f, path) != nil
+}
+
+// importSpec returns the import spec if f imports path,
+// or nil otherwise.
+func importSpec(f *ast.File, path string) *ast.ImportSpec {
+ for _, s := range f.Imports {
+ if importPath(s) == path {
+ return s
+ }
+ }
+ return nil
+}
+
+// importPath returns the unquoted import path of s,
+// or "" if the path is not properly quoted.
+func importPath(s *ast.ImportSpec) string {
+ t, err := strconv.Unquote(s.Path.Value)
+ if err == nil {
+ return t
+ }
+ return ""
+}
+
+// declImports reports whether gen contains an import of path.
+func declImports(gen *ast.GenDecl, path string) bool {
+ if gen.Tok != token.IMPORT {
+ return false
+ }
+ for _, spec := range gen.Specs {
+ impspec := spec.(*ast.ImportSpec)
+ if importPath(impspec) == path {
+ return true
+ }
+ }
+ return false
+}
+
+// matchLen returns the length of the longest path segment prefix shared by x and y.
+func matchLen(x, y string) int {
+ n := 0
+ for i := 0; i < len(x) && i < len(y) && x[i] == y[i]; i++ {
+ if x[i] == '/' {
+ n++
+ }
+ }
+ return n
+}
+
+// isTopName returns true if n is a top-level unresolved identifier with the given name.
+func isTopName(n ast.Expr, name string) bool {
+ id, ok := n.(*ast.Ident)
+ return ok && id.Name == name && id.Obj == nil
+}
+
+// Imports returns the file imports grouped by paragraph.
+func Imports(fset *token.FileSet, f *ast.File) [][]*ast.ImportSpec {
+ var groups [][]*ast.ImportSpec
+
+ for _, decl := range f.Decls {
+ genDecl, ok := decl.(*ast.GenDecl)
+ if !ok || genDecl.Tok != token.IMPORT {
+ break
+ }
+
+ group := []*ast.ImportSpec{}
+
+ var lastLine int
+ for _, spec := range genDecl.Specs {
+ importSpec := spec.(*ast.ImportSpec)
+ pos := importSpec.Path.ValuePos
+ line := fset.Position(pos).Line
+ if lastLine > 0 && pos > 0 && line-lastLine > 1 {
+ groups = append(groups, group)
+ group = []*ast.ImportSpec{}
+ }
+ group = append(group, importSpec)
+ lastLine = line
+ }
+ groups = append(groups, group)
+ }
+
+ return groups
+}
diff --git a/go/ast/astutil/imports_test.go b/go/ast/astutil/imports_test.go
new file mode 100644
index 0000000..9134b19
--- /dev/null
+++ b/go/ast/astutil/imports_test.go
@@ -0,0 +1,946 @@
+// 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 astutil
+
+import (
+ "bytes"
+ "go/ast"
+ "go/format"
+ "go/parser"
+ "go/token"
+ "reflect"
+ "strconv"
+ "testing"
+)
+
+var fset = token.NewFileSet()
+
+func parse(t *testing.T, name, in string) *ast.File {
+ file, err := parser.ParseFile(fset, name, in, parser.ParseComments)
+ if err != nil {
+ t.Fatalf("%s parse: %v", name, err)
+ }
+ return file
+}
+
+func print(t *testing.T, name string, f *ast.File) string {
+ var buf bytes.Buffer
+ if err := format.Node(&buf, fset, f); err != nil {
+ t.Fatalf("%s gofmt: %v", name, err)
+ }
+ return string(buf.Bytes())
+}
+
+type test struct {
+ name string
+ renamedPkg string
+ pkg string
+ in string
+ out string
+ broken bool // known broken
+}
+
+var addTests = []test{
+ {
+ name: "leave os alone",
+ pkg: "os",
+ in: `package main
+
+import (
+ "os"
+)
+`,
+ out: `package main
+
+import (
+ "os"
+)
+`,
+ },
+ {
+ name: "import.1",
+ pkg: "os",
+ in: `package main
+`,
+ out: `package main
+
+import "os"
+`,
+ },
+ {
+ name: "import.2",
+ pkg: "os",
+ in: `package main
+
+// Comment
+import "C"
+`,
+ out: `package main
+
+// Comment
+import "C"
+import "os"
+`,
+ },
+ {
+ name: "import.3",
+ pkg: "os",
+ in: `package main
+
+// Comment
+import "C"
+
+import (
+ "io"
+ "utf8"
+)
+`,
+ out: `package main
+
+// Comment
+import "C"
+
+import (
+ "io"
+ "os"
+ "utf8"
+)
+`,
+ },
+ {
+ name: "import.17",
+ pkg: "x/y/z",
+ in: `package main
+
+// Comment
+import "C"
+
+import (
+ "a"
+ "b"
+
+ "x/w"
+
+ "d/f"
+)
+`,
+ out: `package main
+
+// Comment
+import "C"
+
+import (
+ "a"
+ "b"
+
+ "x/w"
+ "x/y/z"
+
+ "d/f"
+)
+`,
+ },
+ {
+ name: "import into singular group",
+ pkg: "bytes",
+ in: `package main
+
+import "os"
+
+`,
+ out: `package main
+
+import (
+ "bytes"
+ "os"
+)
+`,
+ },
+ {
+ name: "import into singular group with comment",
+ pkg: "bytes",
+ in: `package main
+
+import /* why */ /* comment here? */ "os"
+
+`,
+ out: `package main
+
+import /* why */ /* comment here? */ (
+ "bytes"
+ "os"
+)
+`,
+ },
+ {
+ name: "import into group with leading comment",
+ pkg: "strings",
+ in: `package main
+
+import (
+ // comment before bytes
+ "bytes"
+ "os"
+)
+
+`,
+ out: `package main
+
+import (
+ // comment before bytes
+ "bytes"
+ "os"
+ "strings"
+)
+`,
+ },
+ {
+ name: "",
+ renamedPkg: "fmtpkg",
+ pkg: "fmt",
+ in: `package main
+
+import "os"
+
+`,
+ out: `package main
+
+import (
+ fmtpkg "fmt"
+ "os"
+)
+`,
+ },
+ {
+ name: "struct comment",
+ pkg: "time",
+ in: `package main
+
+// This is a comment before a struct.
+type T struct {
+ t time.Time
+}
+`,
+ out: `package main
+
+import "time"
+
+// This is a comment before a struct.
+type T struct {
+ t time.Time
+}
+`,
+ },
+ {
+ name: "issue 8729 import C",
+ pkg: "time",
+ in: `package main
+
+import "C"
+
+// comment
+type T time.Time
+`,
+ out: `package main
+
+import "C"
+import "time"
+
+// comment
+type T time.Time
+`,
+ },
+ {
+ name: "issue 8729 empty import",
+ pkg: "time",
+ in: `package main
+
+import ()
+
+// comment
+type T time.Time
+`,
+ out: `package main
+
+import "time"
+
+// comment
+type T time.Time
+`,
+ },
+ {
+ name: "issue 8729 comment on package line",
+ pkg: "time",
+ in: `package main // comment
+
+type T time.Time
+`,
+ out: `package main // comment
+import "time"
+
+type T time.Time
+`,
+ },
+ {
+ name: "issue 8729 comment after package",
+ pkg: "time",
+ in: `package main
+// comment
+
+type T time.Time
+`,
+ out: `package main
+
+import "time"
+
+// comment
+
+type T time.Time
+`,
+ },
+ {
+ name: "issue 8729 comment before and on package line",
+ pkg: "time",
+ in: `// comment before
+package main // comment on
+
+type T time.Time
+`,
+ out: `// comment before
+package main // comment on
+import "time"
+
+type T time.Time
+`,
+ },
+
+ // Issue 9961: Match prefixes using path segments rather than bytes
+ {
+ name: "issue 9961",
+ pkg: "regexp",
+ in: `package main
+
+import (
+ "flag"
+ "testing"
+
+ "rsc.io/p"
+)
+`,
+ out: `package main
+
+import (
+ "flag"
+ "regexp"
+ "testing"
+
+ "rsc.io/p"
+)
+`,
+ },
+}
+
+func TestAddImport(t *testing.T) {
+ for _, test := range addTests {
+ file := parse(t, test.name, test.in)
+ var before bytes.Buffer
+ ast.Fprint(&before, fset, file, nil)
+ AddNamedImport(fset, file, test.renamedPkg, test.pkg)
+ if got := print(t, test.name, file); got != test.out {
+ if test.broken {
+ t.Logf("%s is known broken:\ngot: %s\nwant: %s", test.name, got, test.out)
+ } else {
+ t.Errorf("%s:\ngot: %s\nwant: %s", test.name, got, test.out)
+ }
+ var after bytes.Buffer
+ ast.Fprint(&after, fset, file, nil)
+
+ t.Logf("AST before:\n%s\nAST after:\n%s\n", before.String(), after.String())
+ }
+ }
+}
+
+func TestDoubleAddImport(t *testing.T) {
+ file := parse(t, "doubleimport", "package main\n")
+ AddImport(fset, file, "os")
+ AddImport(fset, file, "bytes")
+ want := `package main
+
+import (
+ "bytes"
+ "os"
+)
+`
+ if got := print(t, "doubleimport", file); got != want {
+ t.Errorf("got: %s\nwant: %s", got, want)
+ }
+}
+
+func TestDoubleAddNamedImport(t *testing.T) {
+ file := parse(t, "doublenamedimport", "package main\n")
+ AddNamedImport(fset, file, "o", "os")
+ AddNamedImport(fset, file, "i", "io")
+ want := `package main
+
+import (
+ i "io"
+ o "os"
+)
+`
+ if got := print(t, "doublenamedimport", file); got != want {
+ t.Errorf("got: %s\nwant: %s", got, want)
+ }
+}
+
+// Part of issue 8729.
+func TestDoubleAddImportWithDeclComment(t *testing.T) {
+ file := parse(t, "doubleimport", `package main
+
+import (
+)
+
+// comment
+type I int
+`)
+ // The AddImport order here matters.
+ AddImport(fset, file, "golang.org/x/tools/go/ast/astutil")
+ AddImport(fset, file, "os")
+ want := `package main
+
+import (
+ "golang.org/x/tools/go/ast/astutil"
+ "os"
+)
+
+// comment
+type I int
+`
+ if got := print(t, "doubleimport_with_decl_comment", file); got != want {
+ t.Errorf("got: %s\nwant: %s", got, want)
+ }
+}
+
+var deleteTests = []test{
+ {
+ name: "import.4",
+ pkg: "os",
+ in: `package main
+
+import (
+ "os"
+)
+`,
+ out: `package main
+`,
+ },
+ {
+ name: "import.5",
+ pkg: "os",
+ in: `package main
+
+// Comment
+import "C"
+import "os"
+`,
+ out: `package main
+
+// Comment
+import "C"
+`,
+ },
+ {
+ name: "import.6",
+ pkg: "os",
+ in: `package main
+
+// Comment
+import "C"
+
+import (
+ "io"
+ "os"
+ "utf8"
+)
+`,
+ out: `package main
+
+// Comment
+import "C"
+
+import (
+ "io"
+ "utf8"
+)
+`,
+ },
+ {
+ name: "import.7",
+ pkg: "io",
+ in: `package main
+
+import (
+ "io" // a
+ "os" // b
+ "utf8" // c
+)
+`,
+ out: `package main
+
+import (
+ // a
+ "os" // b
+ "utf8" // c
+)
+`,
+ },
+ {
+ name: "import.8",
+ pkg: "os",
+ in: `package main
+
+import (
+ "io" // a
+ "os" // b
+ "utf8" // c
+)
+`,
+ out: `package main
+
+import (
+ "io" // a
+ // b
+ "utf8" // c
+)
+`,
+ },
+ {
+ name: "import.9",
+ pkg: "utf8",
+ in: `package main
+
+import (
+ "io" // a
+ "os" // b
+ "utf8" // c
+)
+`,
+ out: `package main
+
+import (
+ "io" // a
+ "os" // b
+ // c
+)
+`,
+ },
+ {
+ name: "import.10",
+ pkg: "io",
+ in: `package main
+
+import (
+ "io"
+ "os"
+ "utf8"
+)
+`,
+ out: `package main
+
+import (
+ "os"
+ "utf8"
+)
+`,
+ },
+ {
+ name: "import.11",
+ pkg: "os",
+ in: `package main
+
+import (
+ "io"
+ "os"
+ "utf8"
+)
+`,
+ out: `package main
+
+import (
+ "io"
+ "utf8"
+)
+`,
+ },
+ {
+ name: "import.12",
+ pkg: "utf8",
+ in: `package main
+
+import (
+ "io"
+ "os"
+ "utf8"
+)
+`,
+ out: `package main
+
+import (
+ "io"
+ "os"
+)
+`,
+ },
+ {
+ name: "handle.raw.quote.imports",
+ pkg: "os",
+ in: "package main\n\nimport `os`",
+ out: `package main
+`,
+ },
+ {
+ name: "import.13",
+ pkg: "io",
+ in: `package main
+
+import (
+ "fmt"
+
+ "io"
+ "os"
+ "utf8"
+
+ "go/format"
+)
+`,
+ out: `package main
+
+import (
+ "fmt"
+
+ "os"
+ "utf8"
+
+ "go/format"
+)
+`,
+ },
+ {
+ name: "import.14",
+ pkg: "io",
+ in: `package main
+
+import (
+ "fmt" // a
+
+ "io" // b
+ "os" // c
+ "utf8" // d
+
+ "go/format" // e
+)
+`,
+ out: `package main
+
+import (
+ "fmt" // a
+
+ // b
+ "os" // c
+ "utf8" // d
+
+ "go/format" // e
+)
+`,
+ },
+ {
+ name: "import.15",
+ pkg: "double",
+ in: `package main
+
+import (
+ "double"
+ "double"
+)
+`,
+ out: `package main
+`,
+ },
+ {
+ name: "import.16",
+ pkg: "bubble",
+ in: `package main
+
+import (
+ "toil"
+ "bubble"
+ "bubble"
+ "trouble"
+)
+`,
+ out: `package main
+
+import (
+ "toil"
+ "trouble"
+)
+`,
+ },
+ {
+ name: "import.17",
+ pkg: "quad",
+ in: `package main
+
+import (
+ "quad"
+ "quad"
+)
+
+import (
+ "quad"
+ "quad"
+)
+`,
+ out: `package main
+`,
+ },
+}
+
+func TestDeleteImport(t *testing.T) {
+ for _, test := range deleteTests {
+ file := parse(t, test.name, test.in)
+ DeleteImport(fset, file, test.pkg)
+ if got := print(t, test.name, file); got != test.out {
+ t.Errorf("%s:\ngot: %s\nwant: %s", test.name, got, test.out)
+ }
+ }
+}
+
+type rewriteTest struct {
+ name string
+ srcPkg string
+ dstPkg string
+ in string
+ out string
+}
+
+var rewriteTests = []rewriteTest{
+ {
+ name: "import.13",
+ srcPkg: "utf8",
+ dstPkg: "encoding/utf8",
+ in: `package main
+
+import (
+ "io"
+ "os"
+ "utf8" // thanks ken
+)
+`,
+ out: `package main
+
+import (
+ "encoding/utf8" // thanks ken
+ "io"
+ "os"
+)
+`,
+ },
+ {
+ name: "import.14",
+ srcPkg: "asn1",
+ dstPkg: "encoding/asn1",
+ in: `package main
+
+import (
+ "asn1"
+ "crypto"
+ "crypto/rsa"
+ _ "crypto/sha1"
+ "crypto/x509"
+ "crypto/x509/pkix"
+ "time"
+)
+
+var x = 1
+`,
+ out: `package main
+
+import (
+ "crypto"
+ "crypto/rsa"
+ _ "crypto/sha1"
+ "crypto/x509"
+ "crypto/x509/pkix"
+ "encoding/asn1"
+ "time"
+)
+
+var x = 1
+`,
+ },
+ {
+ name: "import.15",
+ srcPkg: "url",
+ dstPkg: "net/url",
+ in: `package main
+
+import (
+ "bufio"
+ "net"
+ "path"
+ "url"
+)
+
+var x = 1 // comment on x, not on url
+`,
+ out: `package main
+
+import (
+ "bufio"
+ "net"
+ "net/url"
+ "path"
+)
+
+var x = 1 // comment on x, not on url
+`,
+ },
+ {
+ name: "import.16",
+ srcPkg: "http",
+ dstPkg: "net/http",
+ in: `package main
+
+import (
+ "flag"
+ "http"
+ "log"
+ "text/template"
+)
+
+var addr = flag.String("addr", ":1718", "http service address") // Q=17, R=18
+`,
+ out: `package main
+
+import (
+ "flag"
+ "log"
+ "net/http"
+ "text/template"
+)
+
+var addr = flag.String("addr", ":1718", "http service address") // Q=17, R=18
+`,
+ },
+}
+
+func TestRewriteImport(t *testing.T) {
+ for _, test := range rewriteTests {
+ file := parse(t, test.name, test.in)
+ RewriteImport(fset, file, test.srcPkg, test.dstPkg)
+ if got := print(t, test.name, file); got != test.out {
+ t.Errorf("%s:\ngot: %s\nwant: %s", test.name, got, test.out)
+ }
+ }
+}
+
+var importsTests = []struct {
+ name string
+ in string
+ want [][]string
+}{
+ {
+ name: "no packages",
+ in: `package foo
+`,
+ want: nil,
+ },
+ {
+ name: "one group",
+ in: `package foo
+
+import (
+ "fmt"
+ "testing"
+)
+`,
+ want: [][]string{{"fmt", "testing"}},
+ },
+ {
+ name: "four groups",
+ in: `package foo
+
+import "C"
+import (
+ "fmt"
+ "testing"
+
+ "appengine"
+
+ "myproject/mylib1"
+ "myproject/mylib2"
+)
+`,
+ want: [][]string{
+ {"C"},
+ {"fmt", "testing"},
+ {"appengine"},
+ {"myproject/mylib1", "myproject/mylib2"},
+ },
+ },
+ {
+ name: "multiple factored groups",
+ in: `package foo
+
+import (
+ "fmt"
+ "testing"
+
+ "appengine"
+)
+import (
+ "reflect"
+
+ "bytes"
+)
+`,
+ want: [][]string{
+ {"fmt", "testing"},
+ {"appengine"},
+ {"reflect"},
+ {"bytes"},
+ },
+ },
+}
+
+func unquote(s string) string {
+ res, err := strconv.Unquote(s)
+ if err != nil {
+ return "could_not_unquote"
+ }
+ return res
+}
+
+func TestImports(t *testing.T) {
+ fset := token.NewFileSet()
+ for _, test := range importsTests {
+ f, err := parser.ParseFile(fset, "test.go", test.in, 0)
+ if err != nil {
+ t.Errorf("%s: %v", test.name, err)
+ continue
+ }
+ var got [][]string
+ for _, group := range Imports(fset, f) {
+ var b []string
+ for _, spec := range group {
+ b = append(b, unquote(spec.Path.Value))
+ }
+ got = append(got, b)
+ }
+ if !reflect.DeepEqual(got, test.want) {
+ t.Errorf("Imports(%s)=%v, want %v", test.name, got, test.want)
+ }
+ }
+}
diff --git a/go/ast/astutil/util.go b/go/ast/astutil/util.go
new file mode 100644
index 0000000..7630629
--- /dev/null
+++ b/go/ast/astutil/util.go
@@ -0,0 +1,14 @@
+package astutil
+
+import "go/ast"
+
+// 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/go/buildutil/allpackages.go b/go/buildutil/allpackages.go
new file mode 100644
index 0000000..0f909ee
--- /dev/null
+++ b/go/buildutil/allpackages.go
@@ -0,0 +1,123 @@
+// 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 buildutil provides utilities related to the go/build
+// package in the standard library.
+//
+// All I/O is done via the build.Context file system interface, which must
+// be concurrency-safe.
+package buildutil // import "golang.org/x/tools/go/buildutil"
+
+import (
+ "go/build"
+ "os"
+ "path/filepath"
+ "sort"
+ "strings"
+ "sync"
+)
+
+// AllPackages returns the import path of each Go package in any source
+// directory of the specified build context (e.g. $GOROOT or an element
+// of $GOPATH). Errors are ignored. The results are sorted.
+//
+// The result may include import paths for directories that contain no
+// *.go files, such as "archive" (in $GOROOT/src).
+//
+// All I/O is done via the build.Context file system interface,
+// which must be concurrency-safe.
+//
+func AllPackages(ctxt *build.Context) []string {
+ var list []string
+ ForEachPackage(ctxt, func(pkg string, _ error) {
+ list = append(list, pkg)
+ })
+ sort.Strings(list)
+ return list
+}
+
+// ForEachPackage calls the found function with the import path of
+// each Go package it finds in any source directory of the specified
+// build context (e.g. $GOROOT or an element of $GOPATH).
+//
+// If the package directory exists but could not be read, the second
+// argument to the found function provides the error.
+//
+// All I/O is done via the build.Context file system interface,
+// which must be concurrency-safe.
+//
+func ForEachPackage(ctxt *build.Context, found func(importPath string, err error)) {
+ // We use a counting semaphore to limit
+ // the number of parallel calls to ReadDir.
+ sema := make(chan bool, 20)
+
+ ch := make(chan item)
+
+ var wg sync.WaitGroup
+ for _, root := range ctxt.SrcDirs() {
+ root := root
+ wg.Add(1)
+ go func() {
+ allPackages(ctxt, sema, root, ch)
+ wg.Done()
+ }()
+ }
+ go func() {
+ wg.Wait()
+ close(ch)
+ }()
+
+ // All calls to found occur in the caller's goroutine.
+ for i := range ch {
+ found(i.importPath, i.err)
+ }
+}
+
+type item struct {
+ importPath string
+ err error // (optional)
+}
+
+func allPackages(ctxt *build.Context, sema chan bool, root string, ch chan<- item) {
+ root = filepath.Clean(root) + string(os.PathSeparator)
+
+ var wg sync.WaitGroup
+
+ var walkDir func(dir string)
+ walkDir = func(dir string) {
+ // Avoid .foo, _foo, and testdata directory trees.
+ base := filepath.Base(dir)
+ if base == "" || base[0] == '.' || base[0] == '_' || base == "testdata" {
+ return
+ }
+
+ pkg := filepath.ToSlash(strings.TrimPrefix(dir, root))
+
+ // Prune search if we encounter any of these import paths.
+ switch pkg {
+ case "builtin":
+ return
+ }
+
+ sema <- true
+ files, err := ReadDir(ctxt, dir)
+ <-sema
+ if pkg != "" || err != nil {
+ ch <- item{pkg, err}
+ }
+ for _, fi := range files {
+ fi := fi
+ if fi.IsDir() {
+ wg.Add(1)
+ go func() {
+ walkDir(filepath.Join(dir, fi.Name()))
+ wg.Done()
+ }()
+ }
+ }
+ }
+
+ walkDir(root)
+ wg.Wait()
+}
diff --git a/go/buildutil/allpackages_test.go b/go/buildutil/allpackages_test.go
new file mode 100644
index 0000000..d5bd964
--- /dev/null
+++ b/go/buildutil/allpackages_test.go
@@ -0,0 +1,36 @@
+// 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.
+
+// Incomplete source tree on Android.
+
+// +build !android
+
+package buildutil_test
+
+import (
+ "go/build"
+ "testing"
+
+ "golang.org/x/tools/go/buildutil"
+)
+
+func TestAllPackages(t *testing.T) {
+ all := buildutil.AllPackages(&build.Default)
+
+ set := make(map[string]bool)
+ for _, pkg := range all {
+ set[pkg] = true
+ }
+
+ const wantAtLeast = 250
+ if len(all) < wantAtLeast {
+ t.Errorf("Found only %d packages, want at least %d", len(all), wantAtLeast)
+ }
+
+ for _, want := range []string{"fmt", "crypto/sha256", "golang.org/x/tools/go/buildutil"} {
+ if !set[want] {
+ t.Errorf("Package %q not found; got %s", want, all)
+ }
+ }
+}
diff --git a/go/buildutil/fakecontext.go b/go/buildutil/fakecontext.go
new file mode 100644
index 0000000..24cbcbe
--- /dev/null
+++ b/go/buildutil/fakecontext.go
@@ -0,0 +1,108 @@
+package buildutil
+
+import (
+ "fmt"
+ "go/build"
+ "io"
+ "io/ioutil"
+ "os"
+ "path"
+ "path/filepath"
+ "sort"
+ "strings"
+ "time"
+)
+
+// FakeContext returns a build.Context for the fake file tree specified
+// by pkgs, which maps package import paths to a mapping from file base
+// names to contents.
+//
+// The fake Context has a GOROOT of "/go" and no GOPATH, and overrides
+// the necessary file access methods to read from memory instead of the
+// real file system.
+//
+// Unlike a real file tree, the fake one has only two levels---packages
+// and files---so ReadDir("/go/src/") returns all packages under
+// /go/src/ including, for instance, "math" and "math/big".
+// ReadDir("/go/src/math/big") would return all the files in the
+// "math/big" package.
+//
+func FakeContext(pkgs map[string]map[string]string) *build.Context {
+ clean := func(filename string) string {
+ f := path.Clean(filepath.ToSlash(filename))
+ // Removing "/go/src" while respecting segment
+ // boundaries has this unfortunate corner case:
+ if f == "/go/src" {
+ return ""
+ }
+ return strings.TrimPrefix(f, "/go/src/")
+ }
+
+ ctxt := build.Default // copy
+ ctxt.GOROOT = "/go"
+ ctxt.GOPATH = ""
+ ctxt.IsDir = func(dir string) bool {
+ dir = clean(dir)
+ if dir == "" {
+ return true // needed by (*build.Context).SrcDirs
+ }
+ return pkgs[dir] != nil
+ }
+ ctxt.ReadDir = func(dir string) ([]os.FileInfo, error) {
+ dir = clean(dir)
+ var fis []os.FileInfo
+ if dir == "" {
+ // enumerate packages
+ for importPath := range pkgs {
+ fis = append(fis, fakeDirInfo(importPath))
+ }
+ } else {
+ // enumerate files of package
+ for basename := range pkgs[dir] {
+ fis = append(fis, fakeFileInfo(basename))
+ }
+ }
+ sort.Sort(byName(fis))
+ return fis, nil
+ }
+ ctxt.OpenFile = func(filename string) (io.ReadCloser, error) {
+ filename = clean(filename)
+ dir, base := path.Split(filename)
+ content, ok := pkgs[path.Clean(dir)][base]
+ if !ok {
+ return nil, fmt.Errorf("file not found: %s", filename)
+ }
+ return ioutil.NopCloser(strings.NewReader(content)), nil
+ }
+ ctxt.IsAbsPath = func(path string) bool {
+ path = filepath.ToSlash(path)
+ // Don't rely on the default (filepath.Path) since on
+ // Windows, it reports virtual paths as non-absolute.
+ return strings.HasPrefix(path, "/")
+ }
+ return &ctxt
+}
+
+type byName []os.FileInfo
+
+func (s byName) Len() int { return len(s) }
+func (s byName) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
+func (s byName) Less(i, j int) bool { return s[i].Name() < s[j].Name() }
+
+type fakeFileInfo string
+
+func (fi fakeFileInfo) Name() string { return string(fi) }
+func (fakeFileInfo) Sys() interface{} { return nil }
+func (fakeFileInfo) ModTime() time.Time { return time.Time{} }
+func (fakeFileInfo) IsDir() bool { return false }
+func (fakeFileInfo) Size() int64 { return 0 }
+func (fakeFileInfo) Mode() os.FileMode { return 0644 }
+
+type fakeDirInfo string
+
+func (fd fakeDirInfo) Name() string { return string(fd) }
+func (fakeDirInfo) Sys() interface{} { return nil }
+func (fakeDirInfo) ModTime() time.Time { return time.Time{} }
+func (fakeDirInfo) IsDir() bool { return true }
+func (fakeDirInfo) Size() int64 { return 0 }
+func (fakeDirInfo) Mode() os.FileMode { return 0755 }
diff --git a/go/buildutil/tags.go b/go/buildutil/tags.go
new file mode 100644
index 0000000..9735094
--- /dev/null
+++ b/go/buildutil/tags.go
@@ -0,0 +1,73 @@
+package buildutil
+
+// This logic was copied from stringsFlag from $GOROOT/src/cmd/go/build.go.
+
+import "fmt"
+
+const TagsFlagDoc = "a list of `build tags` to consider satisfied during the build. " +
+ "For more information about build tags, see the description of " +
+ "build constraints in the documentation for the go/build package"
+
+// TagsFlag is an implementation of the flag.Value interface that parses
+// a flag value in the same manner as go build's -tags flag and
+// populates a []string slice.
+//
+// See $GOROOT/src/go/build/doc.go for description of build tags.
+// See $GOROOT/src/cmd/go/doc.go for description of 'go build -tags' flag.
+//
+// Example:
+// flag.Var((*buildutil.TagsFlag)(&build.Default.BuildTags), "tags", buildutil.TagsDoc)
+type TagsFlag []string
+
+func (v *TagsFlag) Set(s string) error {
+ var err error
+ *v, err = splitQuotedFields(s)
+ if *v == nil {
+ *v = []string{}
+ }
+ return err
+}
+
+func splitQuotedFields(s string) ([]string, error) {
+ // Split fields allowing '' or "" around elements.
+ // Quotes further inside the string do not count.
+ var f []string
+ for len(s) > 0 {
+ for len(s) > 0 && isSpaceByte(s[0]) {
+ s = s[1:]
+ }
+ if len(s) == 0 {
+ break
+ }
+ // Accepted quoted string. No unescaping inside.
+ if s[0] == '"' || s[0] == '\'' {
+ quote := s[0]
+ s = s[1:]
+ i := 0
+ for i < len(s) && s[i] != quote {
+ i++
+ }
+ if i >= len(s) {
+ return nil, fmt.Errorf("unterminated %c string", quote)
+ }
+ f = append(f, s[:i])
+ s = s[i+1:]
+ continue
+ }
+ i := 0
+ for i < len(s) && !isSpaceByte(s[i]) {
+ i++
+ }
+ f = append(f, s[:i])
+ s = s[i:]
+ }
+ return f, nil
+}
+
+func (v *TagsFlag) String() string {
+ return "<tagsFlag>"
+}
+
+func isSpaceByte(c byte) bool {
+ return c == ' ' || c == '\t' || c == '\n' || c == '\r'
+}
diff --git a/go/buildutil/tags_test.go b/go/buildutil/tags_test.go
new file mode 100644
index 0000000..0fc2618
--- /dev/null
+++ b/go/buildutil/tags_test.go
@@ -0,0 +1,28 @@
+package buildutil_test
+
+import (
+ "flag"
+ "go/build"
+ "reflect"
+ "testing"
+
+ "golang.org/x/tools/go/buildutil"
+)
+
+func TestTags(t *testing.T) {
+ f := flag.NewFlagSet("TestTags", flag.PanicOnError)
+ var ctxt build.Context
+ f.Var((*buildutil.TagsFlag)(&ctxt.BuildTags), "tags", buildutil.TagsFlagDoc)
+ f.Parse([]string{"-tags", ` 'one'"two" 'three "four"'`, "rest"})
+
+ // BuildTags
+ want := []string{"one", "two", "three \"four\""}
+ if !reflect.DeepEqual(ctxt.BuildTags, want) {
+ t.Errorf("BuildTags = %q, want %q", ctxt.BuildTags, want)
+ }
+
+ // Args()
+ if want := []string{"rest"}; !reflect.DeepEqual(f.Args(), want) {
+ t.Errorf("f.Args() = %q, want %q", f.Args(), want)
+ }
+}
diff --git a/go/buildutil/util.go b/go/buildutil/util.go
new file mode 100644
index 0000000..60eeae2
--- /dev/null
+++ b/go/buildutil/util.go
@@ -0,0 +1,158 @@
+// 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 buildutil
+
+import (
+ "fmt"
+ "go/ast"
+ "go/build"
+ "go/parser"
+ "go/token"
+ "io"
+ "io/ioutil"
+ "os"
+ "path"
+ "path/filepath"
+ "strings"
+)
+
+// ParseFile behaves like parser.ParseFile,
+// but uses the build context's file system interface, if any.
+//
+// If file is not absolute (as defined by IsAbsPath), the (dir, file)
+// components are joined using JoinPath; dir must be absolute.
+//
+// The displayPath function, if provided, is used to transform the
+// filename that will be attached to the ASTs.
+//
+// TODO(adonovan): call this from go/loader.parseFiles when the tree thaws.
+//
+func ParseFile(fset *token.FileSet, ctxt *build.Context, displayPath func(string) string, dir string, file string, mode parser.Mode) (*ast.File, error) {
+ if !IsAbsPath(ctxt, file) {
+ file = JoinPath(ctxt, dir, file)
+ }
+ rd, err := OpenFile(ctxt, file)
+ if err != nil {
+ return nil, err
+ }
+ defer rd.Close() // ignore error
+ if displayPath != nil {
+ file = displayPath(file)
+ }
+ return parser.ParseFile(fset, file, rd, mode)
+}
+
+// ContainingPackage returns the package containing filename.
+//
+// If filename is not absolute, it is interpreted relative to working directory dir.
+// All I/O is via the build context's file system interface, if any.
+//
+// The '...Files []string' fields of the resulting build.Package are not
+// populated (build.FindOnly mode).
+//
+// TODO(adonovan): call this from oracle when the tree thaws.
+//
+func ContainingPackage(ctxt *build.Context, dir, filename string) (*build.Package, error) {
+ if !IsAbsPath(ctxt, filename) {
+ filename = JoinPath(ctxt, dir, filename)
+ }
+
+ // We must not assume the file tree uses
+ // "/" always,
+ // `\` always,
+ // or os.PathSeparator (which varies by platform),
+ // but to make any progress, we are forced to assume that
+ // paths will not use `\` unless the PathSeparator
+ // is also `\`, thus we can rely on filepath.ToSlash for some sanity.
+
+ dirSlash := path.Dir(filepath.ToSlash(filename)) + "/"
+
+ // We assume that no source root (GOPATH[i] or GOROOT) contains any other.
+ for _, srcdir := range ctxt.SrcDirs() {
+ srcdirSlash := filepath.ToSlash(srcdir) + "/"
+ if strings.HasPrefix(dirSlash, srcdirSlash) {
+ importPath := dirSlash[len(srcdirSlash) : len(dirSlash)-len("/")]
+ return ctxt.Import(importPath, dir, build.FindOnly)
+ }
+ }
+
+ return nil, fmt.Errorf("can't find package containing %s", filename)
+}
+
+// -- Effective methods of file system interface -------------------------
+
+// (go/build.Context defines these as methods, but does not export them.)
+
+// TODO(adonovan): HasSubdir?
+
+// FileExists returns true if the specified file exists,
+// using the build context's file system interface.
+func FileExists(ctxt *build.Context, path string) bool {
+ if ctxt.OpenFile != nil {
+ r, err := ctxt.OpenFile(path)
+ if err != nil {
+ return false
+ }
+ r.Close() // ignore error
+ return true
+ }
+ _, err := os.Stat(path)
+ return err == nil
+}
+
+// OpenFile behaves like os.Open,
+// but uses the build context's file system interface, if any.
+func OpenFile(ctxt *build.Context, path string) (io.ReadCloser, error) {
+ if ctxt.OpenFile != nil {
+ return ctxt.OpenFile(path)
+ }
+ return os.Open(path)
+}
+
+// IsAbsPath behaves like filepath.IsAbs,
+// but uses the build context's file system interface, if any.
+func IsAbsPath(ctxt *build.Context, path string) bool {
+ if ctxt.IsAbsPath != nil {
+ return ctxt.IsAbsPath(path)
+ }
+ return filepath.IsAbs(path)
+}
+
+// JoinPath behaves like filepath.Join,
+// but uses the build context's file system interface, if any.
+func JoinPath(ctxt *build.Context, path ...string) string {
+ if ctxt.JoinPath != nil {
+ return ctxt.JoinPath(path...)
+ }
+ return filepath.Join(path...)
+}
+
+// IsDir behaves like os.Stat plus IsDir,
+// but uses the build context's file system interface, if any.
+func IsDir(ctxt *build.Context, path string) bool {
+ if ctxt.IsDir != nil {
+ return ctxt.IsDir(path)
+ }
+ fi, err := os.Stat(path)
+ return err == nil && fi.IsDir()
+}
+
+// ReadDir behaves like ioutil.ReadDir,
+// but uses the build context's file system interface, if any.
+func ReadDir(ctxt *build.Context, path string) ([]os.FileInfo, error) {
+ if ctxt.ReadDir != nil {
+ return ctxt.ReadDir(path)
+ }
+ return ioutil.ReadDir(path)
+}
+
+// SplitPathList behaves like filepath.SplitList,
+// but uses the build context's file system interface, if any.
+func SplitPathList(ctxt *build.Context, s string) []string {
+ if ctxt.SplitPathList != nil {
+ return ctxt.SplitPathList(s)
+ }
+ return filepath.SplitList(s)
+}
diff --git a/go/buildutil/util_test.go b/go/buildutil/util_test.go
new file mode 100644
index 0000000..10dae17
--- /dev/null
+++ b/go/buildutil/util_test.go
@@ -0,0 +1,45 @@
+// 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.
+
+// Incomplete source tree on Android.
+
+// +build !android
+
+package buildutil_test
+
+import (
+ "go/build"
+ "os"
+ "path/filepath"
+ "runtime"
+ "testing"
+
+ "golang.org/x/tools/go/buildutil"
+)
+
+func TestContainingPackage(t *testing.T) {
+ // unvirtualized:
+ goroot := runtime.GOROOT()
+ gopath := filepath.SplitList(os.Getenv("GOPATH"))[0]
+
+ for _, test := range [][2]string{
+ {goroot + "/src/fmt/print.go", "fmt"},
+ {goroot + "/src/encoding/json/foo.go", "encoding/json"},
+ {goroot + "/src/encoding/missing/foo.go", "(not found)"},
+ {gopath + "/src/golang.org/x/tools/go/buildutil/util_test.go",
+ "golang.org/x/tools/go/buildutil"},
+ } {
+ file, want := test[0], test[1]
+ bp, err := buildutil.ContainingPackage(&build.Default, ".", file)
+ got := bp.ImportPath
+ if err != nil {
+ got = "(not found)"
+ }
+ if got != want {
+ t.Errorf("ContainingPackage(%q) = %s, want %s", file, got, want)
+ }
+ }
+
+ // TODO(adonovan): test on virtualized GOPATH too.
+}
diff --git a/go/callgraph/callgraph.go b/go/callgraph/callgraph.go
new file mode 100644
index 0000000..707a319
--- /dev/null
+++ b/go/callgraph/callgraph.go
@@ -0,0 +1,129 @@
+// 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 callgraph defines the call graph and various algorithms
+and utilities to operate on it.
+
+A call graph is a labelled directed graph whose nodes represent
+functions and whose edge labels represent syntactic function call
+sites. The presence of a labelled edge (caller, site, callee)
+indicates that caller may call callee at the specified call site.
+
+A call graph is a multigraph: it may contain multiple edges (caller,
+*, callee) connecting the same pair of nodes, so long as the edges
+differ by label; this occurs when one function calls another function
+from multiple call sites. Also, it may contain multiple edges
+(caller, site, *) that differ only by callee; this indicates a
+polymorphic call.
+
+A SOUND call graph is one that overapproximates the dynamic calling
+behaviors of the program in all possible executions. One call graph
+is more PRECISE than another if it is a smaller overapproximation of
+the dynamic behavior.
+
+All call graphs have a synthetic root node which is responsible for
+calling main() and init().
+
+Calls to built-in functions (e.g. panic, println) are not represented
+in the call graph; they are treated like built-in operators of the
+language.
+
+*/
+package callgraph // import "golang.org/x/tools/go/callgraph"
+
+// TODO(adonovan): add a function to eliminate wrappers from the
+// callgraph, preserving topology.
+// More generally, we could eliminate "uninteresting" nodes such as
+// nodes from packages we don't care about.
+
+import (
+ "fmt"
+ "go/token"
+
+ "golang.org/x/tools/go/ssa"
+)
+
+// A Graph represents a call graph.
+//
+// A graph may contain nodes that are not reachable from the root.
+// If the call graph is sound, such nodes indicate unreachable
+// functions.
+//
+type Graph struct {
+ Root *Node // the distinguished root node
+ Nodes map[*ssa.Function]*Node // all nodes by function
+}
+
+// New returns a new Graph with the specified root node.
+func New(root *ssa.Function) *Graph {
+ g := &Graph{Nodes: make(map[*ssa.Function]*Node)}
+ g.Root = g.CreateNode(root)
+ return g
+}
+
+// CreateNode returns the Node for fn, creating it if not present.
+func (g *Graph) CreateNode(fn *ssa.Function) *Node {
+ n, ok := g.Nodes[fn]
+ if !ok {
+ n = &Node{Func: fn, ID: len(g.Nodes)}
+ g.Nodes[fn] = n
+ }
+ return n
+}
+
+// A Node represents a node in a call graph.
+type Node struct {
+ Func *ssa.Function // the function this node represents
+ ID int // 0-based sequence number
+ In []*Edge // unordered set of incoming call edges (n.In[*].Callee == n)
+ Out []*Edge // unordered set of outgoing call edges (n.Out[*].Caller == n)
+}
+
+func (n *Node) String() string {
+ return fmt.Sprintf("n%d:%s", n.ID, n.Func)
+}
+
+// A Edge represents an edge in the call graph.
+//
+// Site is nil for edges originating in synthetic or intrinsic
+// functions, e.g. reflect.Call or the root of the call graph.
+type Edge struct {
+ Caller *Node
+ Site ssa.CallInstruction
+ Callee *Node
+}
+
+func (e Edge) String() string {
+ return fmt.Sprintf("%s --> %s", e.Caller, e.Callee)
+}
+
+func (e Edge) Description() string {
+ var prefix string
+ switch e.Site.(type) {
+ case nil:
+ return "synthetic call"
+ case *ssa.Go:
+ prefix = "concurrent "
+ case *ssa.Defer:
+ prefix = "deferred "
+ }
+ return prefix + e.Site.Common().Description()
+}
+
+func (e Edge) Pos() token.Pos {
+ if e.Site == nil {
+ return token.NoPos
+ }
+ return e.Site.Pos()
+}
+
+// AddEdge adds the edge (caller, site, callee) to the call graph.
+// Elimination of duplicate edges is the caller's responsibility.
+func AddEdge(caller *Node, site ssa.CallInstruction, callee *Node) {
+ e := &Edge{caller, site, callee}
+ callee.In = append(callee.In, e)
+ caller.Out = append(caller.Out, e)
+}
diff --git a/go/callgraph/cha/cha.go b/go/callgraph/cha/cha.go
new file mode 100644
index 0000000..fcdf686
--- /dev/null
+++ b/go/callgraph/cha/cha.go
@@ -0,0 +1,120 @@
+// Package cha computes the call graph of a Go program using the Class
+// Hierarchy Analysis (CHA) algorithm.
+//
+// CHA was first described in "Optimization of Object-Oriented Programs
+// Using Static Class Hierarchy Analysis", Jeffrey Dean, David Grove,
+// and Craig Chambers, ECOOP'95.
+//
+// CHA is related to RTA (see go/callgraph/rta); the difference is that
+// CHA conservatively computes the entire "implements" relation between
+// interfaces and concrete types ahead of time, whereas RTA uses dynamic
+// programming to construct it on the fly as it encounters new functions
+// reachable from main. CHA may thus include spurious call edges for
+// types that haven't been instantiated yet, or types that are never
+// instantiated.
+//
+// Since CHA conservatively assumes that all functions are address-taken
+// and all concrete types are put into interfaces, it is sound to run on
+// partial programs, such as libraries without a main or test function.
+//
+package cha // import "golang.org/x/tools/go/callgraph/cha"
+
+import (
+ "golang.org/x/tools/go/callgraph"
+ "golang.org/x/tools/go/ssa"
+ "golang.org/x/tools/go/ssa/ssautil"
+ "golang.org/x/tools/go/types"
+ "golang.org/x/tools/go/types/typeutil"
+)
+
+// CallGraph computes the call graph of the specified program using the
+// Class Hierarchy Analysis algorithm.
+//
+func CallGraph(prog *ssa.Program) *callgraph.Graph {
+ cg := callgraph.New(nil) // TODO(adonovan) eliminate concept of rooted callgraph
+
+ allFuncs := ssautil.AllFunctions(prog)
+
+ // funcsBySig contains all functions, keyed by signature. It is
+ // the effective set of address-taken functions used to resolve
+ // a dynamic call of a particular signature.
+ var funcsBySig typeutil.Map // value is []*ssa.Function
+
+ // methodsByName contains all methods,
+ // grouped by name for efficient lookup.
+ methodsByName := make(map[string][]*ssa.Function)
+
+ // methodsMemo records, for every abstract method call call I.f on
+ // interface type I, the set of concrete methods C.f of all
+ // types C that satisfy interface I.
+ methodsMemo := make(map[*types.Func][]*ssa.Function)
+ lookupMethods := func(m *types.Func) []*ssa.Function {
+ methods, ok := methodsMemo[m]
+ if !ok {
+ I := m.Type().(*types.Signature).Recv().Type().Underlying().(*types.Interface)
+ for _, f := range methodsByName[m.Name()] {
+ C := f.Signature.Recv().Type() // named or *named
+ if types.Implements(C, I) {
+ methods = append(methods, f)
+ }
+ }
+ methodsMemo[m] = methods
+ }
+ return methods
+ }
+
+ for f := range allFuncs {
+ if f.Signature.Recv() == nil {
+ // Package initializers can never be address-taken.
+ if f.Name() == "init" && f.Synthetic == "package initializer" {
+ continue
+ }
+ funcs, _ := funcsBySig.At(f.Signature).([]*ssa.Function)
+ funcs = append(funcs, f)
+ funcsBySig.Set(f.Signature, funcs)
+ } else {
+ methodsByName[f.Name()] = append(methodsByName[f.Name()], f)
+ }
+ }
+
+ addEdge := func(fnode *callgraph.Node, site ssa.CallInstruction, g *ssa.Function) {
+ gnode := cg.CreateNode(g)
+ callgraph.AddEdge(fnode, site, gnode)
+ }
+
+ addEdges := func(fnode *callgraph.Node, site ssa.CallInstruction, callees []*ssa.Function) {
+ // Because every call to a highly polymorphic and
+ // frequently used abstract method such as
+ // (io.Writer).Write is assumed to call every concrete
+ // Write method in the program, the call graph can
+ // contain a lot of duplication.
+ //
+ // TODO(adonovan): opt: consider factoring the callgraph
+ // API so that the Callers component of each edge is a
+ // slice of nodes, not a singleton.
+ for _, g := range callees {
+ addEdge(fnode, site, g)
+ }
+ }
+
+ for f := range allFuncs {
+ fnode := cg.CreateNode(f)
+ for _, b := range f.Blocks {
+ for _, instr := range b.Instrs {
+ if site, ok := instr.(ssa.CallInstruction); ok {
+ call := site.Common()
+ if call.IsInvoke() {
+ addEdges(fnode, site, lookupMethods(call.Method))
+ } else if g := call.StaticCallee(); g != nil {
+ addEdge(fnode, site, g)
+ } else if _, ok := call.Value.(*ssa.Builtin); !ok {
+ callees, _ := funcsBySig.At(call.Signature()).([]*ssa.Function)
+ addEdges(fnode, site, callees)
+ }
+ }
+ }
+ }
+ }
+
+ return cg
+}
diff --git a/go/callgraph/cha/cha_test.go b/go/callgraph/cha/cha_test.go
new file mode 100644
index 0000000..38348c0
--- /dev/null
+++ b/go/callgraph/cha/cha_test.go
@@ -0,0 +1,110 @@
+// 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 cha_test
+
+import (
+ "bytes"
+ "fmt"
+ "go/ast"
+ "go/parser"
+ "go/token"
+ "io/ioutil"
+ "sort"
+ "strings"
+ "testing"
+
+ "golang.org/x/tools/go/callgraph"
+ "golang.org/x/tools/go/callgraph/cha"
+ "golang.org/x/tools/go/loader"
+ "golang.org/x/tools/go/ssa/ssautil"
+ "golang.org/x/tools/go/types"
+)
+
+var inputs = []string{
+ "testdata/func.go",
+ "testdata/iface.go",
+ "testdata/recv.go",
+}
+
+func expectation(f *ast.File) (string, token.Pos) {
+ for _, c := range f.Comments {
+ text := strings.TrimSpace(c.Text())
+ if t := strings.TrimPrefix(text, "WANT:\n"); t != text {
+ return t, c.Pos()
+ }
+ }
+ return "", token.NoPos
+}
+
+// TestCHA runs CHA on each file in inputs, prints the dynamic edges of
+// the call graph, and compares it with the golden results embedded in
+// the WANT comment at the end of the file.
+//
+func TestCHA(t *testing.T) {
+ for _, filename := range inputs {
+ content, err := ioutil.ReadFile(filename)
+ if err != nil {
+ t.Errorf("couldn't read file '%s': %s", filename, err)
+ continue
+ }
+
+ conf := loader.Config{
+ ParserMode: parser.ParseComments,
+ }
+ f, err := conf.ParseFile(filename, content)
+ if err != nil {
+ t.Error(err)
+ continue
+ }
+
+ want, pos := expectation(f)
+ if pos == token.NoPos {
+ t.Errorf("No WANT: comment in %s", filename)
+ continue
+ }
+
+ conf.CreateFromFiles("main", f)
+ iprog, err := conf.Load()
+ if err != nil {
+ t.Error(err)
+ continue
+ }
+
+ prog := ssautil.CreateProgram(iprog, 0)
+ mainPkg := prog.Package(iprog.Created[0].Pkg)
+ prog.BuildAll()
+
+ cg := cha.CallGraph(prog)
+
+ if got := printGraph(cg, mainPkg.Object); got != want {
+ t.Errorf("%s: got:\n%s\nwant:\n%s",
+ prog.Fset.Position(pos), got, want)
+ }
+ }
+}
+
+func printGraph(cg *callgraph.Graph, from *types.Package) string {
+ var edges []string
+ callgraph.GraphVisitEdges(cg, func(e *callgraph.Edge) error {
+ if strings.Contains(e.Description(), "dynamic") {
+ edges = append(edges, fmt.Sprintf("%s --> %s",
+ e.Caller.Func.RelString(from),
+ e.Callee.Func.RelString(from)))
+ }
+ return nil
+ })
+ sort.Strings(edges)
+
+ var buf bytes.Buffer
+ buf.WriteString("Dynamic calls\n")
+ for _, edge := range edges {
+ fmt.Fprintf(&buf, " %s\n", edge)
+ }
+ return strings.TrimSpace(buf.String())
+}
diff --git a/go/callgraph/cha/testdata/func.go b/go/callgraph/cha/testdata/func.go
new file mode 100644
index 0000000..ad483f1
--- /dev/null
+++ b/go/callgraph/cha/testdata/func.go
@@ -0,0 +1,23 @@
+//+build ignore
+
+package main
+
+// Test of dynamic function calls; no interfaces.
+
+func A(int) {}
+
+var (
+ B = func(int) {}
+ C = func(int) {}
+)
+
+func f() {
+ pfn := B
+ pfn(0) // calls A, B, C, even though A is not even address-taken
+}
+
+// WANT:
+// Dynamic calls
+// f --> A
+// f --> init$1
+// f --> init$2
diff --git a/go/callgraph/cha/testdata/iface.go b/go/callgraph/cha/testdata/iface.go
new file mode 100644
index 0000000..1622ec1
--- /dev/null
+++ b/go/callgraph/cha/testdata/iface.go
@@ -0,0 +1,65 @@
+//+build ignore
+
+package main
+
+// Test of interface calls. None of the concrete types are ever
+// instantiated or converted to interfaces.
+
+type I interface {
+ f()
+}
+
+type J interface {
+ f()
+ g()
+}
+
+type C int // implements I
+
+func (*C) f()
+
+type D int // implements I and J
+
+func (*D) f()
+func (*D) g()
+
+func one(i I, j J) {
+ i.f() // calls *C and *D
+}
+
+func two(i I, j J) {
+ j.f() // calls *D (but not *C, even though it defines method f)
+}
+
+func three(i I, j J) {
+ j.g() // calls *D
+}
+
+func four(i I, j J) {
+ Jf := J.f
+ if unknown {
+ Jf = nil // suppress SSA constant propagation
+ }
+ Jf(nil) // calls *D
+}
+
+func five(i I, j J) {
+ jf := j.f
+ if unknown {
+ jf = nil // suppress SSA constant propagation
+ }
+ jf() // calls *D
+}
+
+var unknown bool
+
+// WANT:
+// Dynamic calls
+// (J).f$bound --> (*D).f
+// (J).f$thunk --> (*D).f
+// five --> (J).f$bound
+// four --> (J).f$thunk
+// one --> (*C).f
+// one --> (*D).f
+// three --> (*D).g
+// two --> (*D).f
diff --git a/go/callgraph/cha/testdata/recv.go b/go/callgraph/cha/testdata/recv.go
new file mode 100644
index 0000000..5ba48e9
--- /dev/null
+++ b/go/callgraph/cha/testdata/recv.go
@@ -0,0 +1,37 @@
+//+build ignore
+
+package main
+
+type I interface {
+ f()
+}
+
+type J interface {
+ g()
+}
+
+type C int // C and *C implement I; *C implements J
+
+func (C) f()
+func (*C) g()
+
+type D int // *D implements I and J
+
+func (*D) f()
+func (*D) g()
+
+func f(i I) {
+ i.f() // calls C, *C, *D
+}
+
+func g(j J) {
+ j.g() // calls *C, *D
+}
+
+// WANT:
+// Dynamic calls
+// f --> (*C).f
+// f --> (*D).f
+// f --> (C).f
+// g --> (*C).g
+// g --> (*D).g
diff --git a/go/callgraph/rta/rta.go b/go/callgraph/rta/rta.go
new file mode 100644
index 0000000..8d22da6
--- /dev/null
+++ b/go/callgraph/rta/rta.go
@@ -0,0 +1,459 @@
+// 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 package provides Rapid Type Analysis (RTA) for Go, a fast
+// algorithm for call graph construction and discovery of reachable code
+// (and hence dead code) and runtime types. The algorithm was first
+// described in:
+//
+// David F. Bacon and Peter F. Sweeney. 1996.
+// Fast static analysis of C++ virtual function calls. (OOPSLA '96)
+// http://doi.acm.org/10.1145/236337.236371
+//
+// The algorithm uses dynamic programming to tabulate the cross-product
+// of the set of known "address taken" functions with the set of known
+// dynamic calls of the same type. As each new address-taken function
+// is discovered, call graph edges are added from each known callsite,
+// and as each new call site is discovered, call graph edges are added
+// from it to each known address-taken function.
+//
+// A similar approach is used for dynamic calls via interfaces: it
+// tabulates the cross-product of the set of known "runtime types",
+// i.e. types that may appear in an interface value, or be derived from
+// one via reflection, with the set of known "invoke"-mode dynamic
+// calls. As each new "runtime type" is discovered, call edges are
+// added from the known call sites, and as each new call site is
+// discovered, call graph edges are added to each compatible
+// method.
+//
+// In addition, we must consider all exported methods of any runtime type
+// as reachable, since they may be called via reflection.
+//
+// Each time a newly added call edge causes a new function to become
+// reachable, the code of that function is analyzed for more call sites,
+// address-taken functions, and runtime types. The process continues
+// until a fixed point is achieved.
+//
+// The resulting call graph is less precise than one produced by pointer
+// analysis, but the algorithm is much faster. For example, running the
+// cmd/callgraph tool on its own source takes ~2.1s for RTA and ~5.4s
+// for points-to analysis.
+//
+package rta // import "golang.org/x/tools/go/callgraph/rta"
+
+// TODO(adonovan): test it by connecting it to the interpreter and
+// replacing all "unreachable" functions by a special intrinsic, and
+// ensure that that intrinsic is never called.
+
+import (
+ "fmt"
+
+ "golang.org/x/tools/go/callgraph"
+ "golang.org/x/tools/go/ssa"
+ "golang.org/x/tools/go/types"
+ "golang.org/x/tools/go/types/typeutil"
+)
+
+// A Result holds the results of Rapid Type Analysis, which includes the
+// set of reachable functions/methods, runtime types, and the call graph.
+//
+type Result struct {
+ // CallGraph is the discovered callgraph.
+ // It does not include edges for calls made via reflection.
+ CallGraph *callgraph.Graph
+
+ // Reachable contains the set of reachable functions and methods.
+ // This includes exported methods of runtime types, since
+ // they may be accessed via reflection.
+ // The value indicates whether the function is address-taken.
+ //
+ // (We wrap the bool in a struct to avoid inadvertent use of
+ // "if Reachable[f] {" to test for set membership.)
+ Reachable map[*ssa.Function]struct{ AddrTaken bool }
+
+ // RuntimeTypes contains the set of types that are needed at
+ // runtime, for interfaces or reflection.
+ //
+ // The value indicates whether the type is inaccessible to reflection.
+ // Consider:
+ // type A struct{B}
+ // fmt.Println(new(A))
+ // Types *A, A and B are accessible to reflection, but the unnamed
+ // type struct{B} is not.
+ RuntimeTypes typeutil.Map
+}
+
+// Working state of the RTA algorithm.
+type rta struct {
+ result *Result
+
+ prog *ssa.Program
+
+ worklist []*ssa.Function // list of functions to visit
+
+ // addrTakenFuncsBySig contains all address-taken *Functions, grouped by signature.
+ // Keys are *types.Signature, values are map[*ssa.Function]bool sets.
+ addrTakenFuncsBySig typeutil.Map
+
+ // dynCallSites contains all dynamic "call"-mode call sites, grouped by signature.
+ // Keys are *types.Signature, values are unordered []ssa.CallInstruction.
+ dynCallSites typeutil.Map
+
+ // invokeSites contains all "invoke"-mode call sites, grouped by interface.
+ // Keys are *types.Interface (never *types.Named),
+ // Values are unordered []ssa.CallInstruction sets.
+ invokeSites typeutil.Map
+
+ // The following two maps together define the subset of the
+ // m:n "implements" relation needed by the algorithm.
+
+ // concreteTypes maps each concrete type to the set of interfaces that it implements.
+ // Keys are types.Type, values are unordered []*types.Interface.
+ // Only concrete types used as MakeInterface operands are included.
+ concreteTypes typeutil.Map
+
+ // interfaceTypes maps each interface type to
+ // the set of concrete types that implement it.
+ // Keys are *types.Interface, values are unordered []types.Type.
+ // Only interfaces used in "invoke"-mode CallInstructions are included.
+ interfaceTypes typeutil.Map
+}
+
+// addReachable marks a function as potentially callable at run-time,
+// and ensures that it gets processed.
+func (r *rta) addReachable(f *ssa.Function, addrTaken bool) {
+ reachable := r.result.Reachable
+ n := len(reachable)
+ v := reachable[f]
+ if addrTaken {
+ v.AddrTaken = true
+ }
+ reachable[f] = v
+ if len(reachable) > n {
+ // First time seeing f. Add it to the worklist.
+ r.worklist = append(r.worklist, f)
+ }
+}
+
+// addEdge adds the specified call graph edge, and marks it reachable.
+// addrTaken indicates whether to mark the callee as "address-taken".
+func (r *rta) addEdge(site ssa.CallInstruction, callee *ssa.Function, addrTaken bool) {
+ r.addReachable(callee, addrTaken)
+
+ if g := r.result.CallGraph; g != nil {
+ if site.Parent() == nil {
+ panic(site)
+ }
+ from := g.CreateNode(site.Parent())
+ to := g.CreateNode(callee)
+ callgraph.AddEdge(from, site, to)
+ }
+}
+
+// ---------- addrTakenFuncs × dynCallSites ----------
+
+// visitAddrTakenFunc is called each time we encounter an address-taken function f.
+func (r *rta) visitAddrTakenFunc(f *ssa.Function) {
+ // Create two-level map (Signature -> Function -> bool).
+ S := f.Signature
+ funcs, _ := r.addrTakenFuncsBySig.At(S).(map[*ssa.Function]bool)
+ if funcs == nil {
+ funcs = make(map[*ssa.Function]bool)
+ r.addrTakenFuncsBySig.Set(S, funcs)
+ }
+ if !funcs[f] {
+ // First time seeing f.
+ funcs[f] = true
+
+ // If we've seen any dyncalls of this type, mark it reachable,
+ // and add call graph edges.
+ sites, _ := r.dynCallSites.At(S).([]ssa.CallInstruction)
+ for _, site := range sites {
+ r.addEdge(site, f, true)
+ }
+ }
+}
+
+// visitDynCall is called each time we encounter a dynamic "call"-mode call.
+func (r *rta) visitDynCall(site ssa.CallInstruction) {
+ S := site.Common().Signature()
+
+ // Record the call site.
+ sites, _ := r.dynCallSites.At(S).([]ssa.CallInstruction)
+ r.dynCallSites.Set(S, append(sites, site))
+
+ // For each function of signature S that we know is address-taken,
+ // mark it reachable. We'll add the callgraph edges later.
+ funcs, _ := r.addrTakenFuncsBySig.At(S).(map[*ssa.Function]bool)
+ for g := range funcs {
+ r.addEdge(site, g, true)
+ }
+}
+
+// ---------- concrete types × invoke sites ----------
+
+// addInvokeEdge is called for each new pair (site, C) in the matrix.
+func (r *rta) addInvokeEdge(site ssa.CallInstruction, C types.Type) {
+ // Ascertain the concrete method of C to be called.
+ imethod := site.Common().Method
+ cmethod := r.prog.Method(r.prog.MethodSets.MethodSet(C).Lookup(imethod.Pkg(), imethod.Name()))
+ r.addEdge(site, cmethod, true)
+}
+
+// visitInvoke is called each time the algorithm encounters an "invoke"-mode call.
+func (r *rta) visitInvoke(site ssa.CallInstruction) {
+ I := site.Common().Value.Type().Underlying().(*types.Interface)
+
+ // Record the invoke site.
+ sites, _ := r.invokeSites.At(I).([]ssa.CallInstruction)
+ r.invokeSites.Set(I, append(sites, site))
+
+ // Add callgraph edge for each existing
+ // address-taken concrete type implementing I.
+ for _, C := range r.implementations(I) {
+ r.addInvokeEdge(site, C)
+ }
+}
+
+// ---------- main algorithm ----------
+
+// visitFunc processes function f.
+func (r *rta) visitFunc(f *ssa.Function) {
+ var space [32]*ssa.Value // preallocate space for common case
+
+ for _, b := range f.Blocks {
+ for _, instr := range b.Instrs {
+ rands := instr.Operands(space[:0])
+
+ switch instr := instr.(type) {
+ case ssa.CallInstruction:
+ call := instr.Common()
+ if call.IsInvoke() {
+ r.visitInvoke(instr)
+ } else if g := call.StaticCallee(); g != nil {
+ r.addEdge(instr, g, false)
+ } else if _, ok := call.Value.(*ssa.Builtin); !ok {
+ r.visitDynCall(instr)
+ }
+
+ // Ignore the call-position operand when
+ // looking for address-taken Functions.
+ // Hack: assume this is rands[0].
+ rands = rands[1:]
+
+ case *ssa.MakeInterface:
+ r.addRuntimeType(instr.X.Type(), false)
+ }
+
+ // Process all address-taken functions.
+ for _, op := range rands {
+ if g, ok := (*op).(*ssa.Function); ok {
+ r.visitAddrTakenFunc(g)
+ }
+ }
+ }
+ }
+}
+
+// Analyze performs Rapid Type Analysis, starting at the specified root
+// functions. It returns nil if no roots were specified.
+//
+// If buildCallGraph is true, Result.CallGraph will contain a call
+// graph; otherwise, only the other fields (reachable functions) are
+// populated.
+//
+func Analyze(roots []*ssa.Function, buildCallGraph bool) *Result {
+ if len(roots) == 0 {
+ return nil
+ }
+
+ r := &rta{
+ result: &Result{Reachable: make(map[*ssa.Function]struct{ AddrTaken bool })},
+ prog: roots[0].Prog,
+ }
+
+ if buildCallGraph {
+ // TODO(adonovan): change callgraph API to eliminate the
+ // notion of a distinguished root node. Some callgraphs
+ // have many roots, or none.
+ r.result.CallGraph = callgraph.New(roots[0])
+ }
+
+ hasher := typeutil.MakeHasher()
+ r.result.RuntimeTypes.SetHasher(hasher)
+ r.addrTakenFuncsBySig.SetHasher(hasher)
+ r.dynCallSites.SetHasher(hasher)
+ r.invokeSites.SetHasher(hasher)
+ r.concreteTypes.SetHasher(hasher)
+ r.interfaceTypes.SetHasher(hasher)
+
+ // Visit functions, processing their instructions, and adding
+ // new functions to the worklist, until a fixed point is
+ // reached.
+ var shadow []*ssa.Function // for efficiency, we double-buffer the worklist
+ r.worklist = append(r.worklist, roots...)
+ for len(r.worklist) > 0 {
+ shadow, r.worklist = r.worklist, shadow[:0]
+ for _, f := range shadow {
+ r.visitFunc(f)
+ }
+ }
+ return r.result
+}
+
+// interfaces(C) returns all currently known interfaces implemented by C.
+func (r *rta) interfaces(C types.Type) []*types.Interface {
+ // Ascertain set of interfaces C implements
+ // and update 'implements' relation.
+ var ifaces []*types.Interface
+ r.interfaceTypes.Iterate(func(I types.Type, concs interface{}) {
+ if I := I.(*types.Interface); types.Implements(C, I) {
+ concs, _ := concs.([]types.Type)
+ r.interfaceTypes.Set(I, append(concs, C))
+ ifaces = append(ifaces, I)
+ }
+ })
+ r.concreteTypes.Set(C, ifaces)
+ return ifaces
+}
+
+// implementations(I) returns all currently known concrete types that implement I.
+func (r *rta) implementations(I *types.Interface) []types.Type {
+ var concs []types.Type
+ if v := r.interfaceTypes.At(I); v != nil {
+ concs = v.([]types.Type)
+ } else {
+ // First time seeing this interface.
+ // Update the 'implements' relation.
+ r.concreteTypes.Iterate(func(C types.Type, ifaces interface{}) {
+ if types.Implements(C, I) {
+ ifaces, _ := ifaces.([]*types.Interface)
+ r.concreteTypes.Set(C, append(ifaces, I))
+ concs = append(concs, C)
+ }
+ })
+ r.interfaceTypes.Set(I, concs)
+ }
+ return concs
+}
+
+// addRuntimeType is called for each concrete type that can be the
+// dynamic type of some interface or reflect.Value.
+// Adapted from needMethods in go/ssa/builder.go
+//
+func (r *rta) addRuntimeType(T types.Type, skip bool) {
+ if prev, ok := r.result.RuntimeTypes.At(T).(bool); ok {
+ if skip && !prev {
+ r.result.RuntimeTypes.Set(T, skip)
+ }
+ return
+ }
+ r.result.RuntimeTypes.Set(T, skip)
+
+ mset := r.prog.MethodSets.MethodSet(T)
+
+ if _, ok := T.Underlying().(*types.Interface); !ok {
+ // T is a new concrete type.
+ for i, n := 0, mset.Len(); i < n; i++ {
+ sel := mset.At(i)
+ m := sel.Obj()
+
+ if m.Exported() {
+ // Exported methods are always potentially callable via reflection.
+ r.addReachable(r.prog.Method(sel), true)
+ }
+ }
+
+ // Add callgraph edge for each existing dynamic
+ // "invoke"-mode call via that interface.
+ for _, I := range r.interfaces(T) {
+ sites, _ := r.invokeSites.At(I).([]ssa.CallInstruction)
+ for _, site := range sites {
+ r.addInvokeEdge(site, T)
+ }
+ }
+ }
+
+ // Precondition: T is not a method signature (*Signature with Recv()!=nil).
+ // Recursive case: skip => don't call makeMethods(T).
+ // Each package maintains its own set of types it has visited.
+
+ var n *types.Named
+ switch T := T.(type) {
+ case *types.Named:
+ n = T
+ case *types.Pointer:
+ n, _ = T.Elem().(*types.Named)
+ }
+ if n != nil {
+ owner := n.Obj().Pkg()
+ if owner == nil {
+ return // built-in error type
+ }
+ }
+
+ // Recursion over signatures of each exported method.
+ for i := 0; i < mset.Len(); i++ {
+ if mset.At(i).Obj().Exported() {
+ sig := mset.At(i).Type().(*types.Signature)
+ r.addRuntimeType(sig.Params(), true) // skip the Tuple itself
+ r.addRuntimeType(sig.Results(), true) // skip the Tuple itself
+ }
+ }
+
+ switch t := T.(type) {
+ case *types.Basic:
+ // nop
+
+ case *types.Interface:
+ // nop---handled by recursion over method set.
+
+ case *types.Pointer:
+ r.addRuntimeType(t.Elem(), false)
+
+ case *types.Slice:
+ r.addRuntimeType(t.Elem(), false)
+
+ case *types.Chan:
+ r.addRuntimeType(t.Elem(), false)
+
+ case *types.Map:
+ r.addRuntimeType(t.Key(), false)
+ r.addRuntimeType(t.Elem(), false)
+
+ case *types.Signature:
+ if t.Recv() != nil {
+ panic(fmt.Sprintf("Signature %s has Recv %s", t, t.Recv()))
+ }
+ r.addRuntimeType(t.Params(), true) // skip the Tuple itself
+ r.addRuntimeType(t.Results(), true) // skip the Tuple itself
+
+ case *types.Named:
+ // A pointer-to-named type can be derived from a named
+ // type via reflection. It may have methods too.
+ r.addRuntimeType(types.NewPointer(T), false)
+
+ // Consider 'type T struct{S}' where S has methods.
+ // Reflection provides no way to get from T to struct{S},
+ // only to S, so the method set of struct{S} is unwanted,
+ // so set 'skip' flag during recursion.
+ r.addRuntimeType(t.Underlying(), true)
+
+ case *types.Array:
+ r.addRuntimeType(t.Elem(), false)
+
+ case *types.Struct:
+ for i, n := 0, t.NumFields(); i < n; i++ {
+ r.addRuntimeType(t.Field(i).Type(), false)
+ }
+
+ case *types.Tuple:
+ for i, n := 0, t.Len(); i < n; i++ {
+ r.addRuntimeType(t.At(i).Type(), false)
+ }
+
+ default:
+ panic(T)
+ }
+}
diff --git a/go/callgraph/rta/rta_test.go b/go/callgraph/rta/rta_test.go
new file mode 100644
index 0000000..e5aa846
--- /dev/null
+++ b/go/callgraph/rta/rta_test.go
@@ -0,0 +1,139 @@
+// 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 rta_test
+
+import (
+ "bytes"
+ "fmt"
+ "go/ast"
+ "go/parser"
+ "go/token"
+ "io/ioutil"
+ "sort"
+ "strings"
+ "testing"
+
+ "golang.org/x/tools/go/callgraph"
+ "golang.org/x/tools/go/callgraph/rta"
+ "golang.org/x/tools/go/loader"
+ "golang.org/x/tools/go/ssa"
+ "golang.org/x/tools/go/ssa/ssautil"
+ "golang.org/x/tools/go/types"
+)
+
+var inputs = []string{
+ "testdata/func.go",
+ "testdata/rtype.go",
+ "testdata/iface.go",
+}
+
+func expectation(f *ast.File) (string, token.Pos) {
+ for _, c := range f.Comments {
+ text := strings.TrimSpace(c.Text())
+ if t := strings.TrimPrefix(text, "WANT:\n"); t != text {
+ return t, c.Pos()
+ }
+ }
+ return "", token.NoPos
+}
+
+// TestRTA runs RTA on each file in inputs, prints the results, and
+// compares it with the golden results embedded in the WANT comment at
+// the end of the file.
+//
+// The results string consists of two parts: the set of dynamic call
+// edges, "f --> g", one per line, and the set of reachable functions,
+// one per line. Each set is sorted.
+//
+func TestRTA(t *testing.T) {
+ for _, filename := range inputs {
+ content, err := ioutil.ReadFile(filename)
+ if err != nil {
+ t.Errorf("couldn't read file '%s': %s", filename, err)
+ continue
+ }
+
+ conf := loader.Config{
+ ParserMode: parser.ParseComments,
+ }
+ f, err := conf.ParseFile(filename, content)
+ if err != nil {
+ t.Error(err)
+ continue
+ }
+
+ want, pos := expectation(f)
+ if pos == token.NoPos {
+ t.Errorf("No WANT: comment in %s", filename)
+ continue
+ }
+
+ conf.CreateFromFiles("main", f)
+ iprog, err := conf.Load()
+ if err != nil {
+ t.Error(err)
+ continue
+ }
+
+ prog := ssautil.CreateProgram(iprog, 0)
+ mainPkg := prog.Package(iprog.Created[0].Pkg)
+ prog.BuildAll()
+
+ res := rta.Analyze([]*ssa.Function{
+ mainPkg.Func("main"),
+ mainPkg.Func("init"),
+ }, true)
+
+ if got := printResult(res, mainPkg.Object); got != want {
+ t.Errorf("%s: got:\n%s\nwant:\n%s",
+ prog.Fset.Position(pos), got, want)
+ }
+ }
+}
+
+func printResult(res *rta.Result, from *types.Package) string {
+ var buf bytes.Buffer
+
+ writeSorted := func(ss []string) {
+ sort.Strings(ss)
+ for _, s := range ss {
+ fmt.Fprintf(&buf, " %s\n", s)
+ }
+ }
+
+ buf.WriteString("Dynamic calls\n")
+ var edges []string
+ callgraph.GraphVisitEdges(res.CallGraph, func(e *callgraph.Edge) error {
+ if strings.Contains(e.Description(), "dynamic") {
+ edges = append(edges, fmt.Sprintf("%s --> %s",
+ e.Caller.Func.RelString(from),
+ e.Callee.Func.RelString(from)))
+ }
+ return nil
+ })
+ writeSorted(edges)
+
+ buf.WriteString("Reachable functions\n")
+ var reachable []string
+ for f := range res.Reachable {
+ reachable = append(reachable, f.RelString(from))
+ }
+ writeSorted(reachable)
+
+ buf.WriteString("Reflect types\n")
+ var rtypes []string
+ res.RuntimeTypes.Iterate(func(key types.Type, value interface{}) {
+ if value == false { // accessible to reflection
+ rtypes = append(rtypes, types.TypeString(key, types.RelativeTo(from)))
+ }
+ })
+ writeSorted(rtypes)
+
+ return strings.TrimSpace(buf.String())
+}
diff --git a/go/callgraph/rta/testdata/func.go b/go/callgraph/rta/testdata/func.go
new file mode 100644
index 0000000..968c73d
--- /dev/null
+++ b/go/callgraph/rta/testdata/func.go
@@ -0,0 +1,37 @@
+//+build ignore
+
+package main
+
+// Test of dynamic function calls.
+// No interfaces, so no runtime/reflect types.
+
+func A1() {
+ A2(0)
+}
+
+func A2(int) {} // not address-taken
+
+func B() {} // unreachable
+
+var (
+ C = func(int) {}
+ D = func(int) {}
+)
+
+func main() {
+ A1()
+
+ pfn := C
+ pfn(0) // calls C and D but not A2 (same sig but not address-taken)
+}
+
+// WANT:
+// Dynamic calls
+// main --> init$1
+// main --> init$2
+// Reachable functions
+// A1
+// A2
+// init$1
+// init$2
+// Reflect types
diff --git a/go/callgraph/rta/testdata/iface.go b/go/callgraph/rta/testdata/iface.go
new file mode 100644
index 0000000..c3ee570
--- /dev/null
+++ b/go/callgraph/rta/testdata/iface.go
@@ -0,0 +1,79 @@
+//+build ignore
+
+package main
+
+// Test of interface calls.
+
+func use(interface{})
+
+type A byte // instantiated but not a reflect type
+
+func (A) f() {} // called directly
+func (A) F() {} // unreachable
+
+type B int // a reflect type
+
+func (*B) f() {} // reachable via interface invoke
+func (*B) F() {} // reachable: exported method of reflect type
+
+type B2 int // a reflect type, and *B2 also
+
+func (B2) f() {} // reachable via interface invoke
+func (B2) g() {} // reachable: exported method of reflect type
+
+type C string // not instantiated
+
+func (C) f() {} // unreachable
+func (C) F() {} // unreachable
+
+type D uint // instantiated only in dead code
+
+func (D) f() {} // unreachable
+func (D) F() {} // unreachable
+
+func main() {
+ A(0).f()
+
+ use(new(B))
+ use(B2(0))
+
+ var i interface {
+ f()
+ }
+ i.f() // calls (*B).f, (*B2).f and (B2.f)
+
+ live()
+}
+
+func live() {
+ var j interface {
+ f()
+ g()
+ }
+ j.f() // calls (B2).f and (*B2).f but not (*B).f (no g method).
+}
+
+func dead() {
+ use(D(0))
+}
+
+// WANT:
+// Dynamic calls
+// live --> (*B2).f
+// live --> (B2).f
+// main --> (*B).f
+// main --> (*B2).f
+// main --> (B2).f
+// Reachable functions
+// (*B).F
+// (*B).f
+// (*B2).f
+// (A).f
+// (B2).f
+// live
+// use
+// Reflect types
+// *B
+// *B2
+// B
+// B2
diff --git a/go/callgraph/rta/testdata/rtype.go b/go/callgraph/rta/testdata/rtype.go
new file mode 100644
index 0000000..85414e5
--- /dev/null
+++ b/go/callgraph/rta/testdata/rtype.go
@@ -0,0 +1,35 @@
+//+build ignore
+
+package main
+
+// Test of runtime types (types for which descriptors are needed).
+
+func use(interface{})
+
+type A byte // neither A nor byte are runtime types
+
+type B struct{ x uint } // B and uint are runtime types, but not the struct
+
+func main() {
+ var x int // not a runtime type
+ print(x)
+
+ var y string // runtime type due to interface conversion
+ use(y)
+
+ use(struct{ uint64 }{}) // struct is a runtime type
+
+ use(new(B)) // *B is a runtime type
+}
+
+// WANT:
+// Dynamic calls
+// Reachable functions
+// use
+// Reflect types
+// *B
+// B
+// string
+// struct{uint64}
+// uint
+// uint64
diff --git a/go/callgraph/static/static.go b/go/callgraph/static/static.go
new file mode 100644
index 0000000..709bb7b
--- /dev/null
+++ b/go/callgraph/static/static.go
@@ -0,0 +1,35 @@
+// Package static computes the call graph of a Go program containing
+// only static call edges.
+package static // import "golang.org/x/tools/go/callgraph/static"
+
+import (
+ "golang.org/x/tools/go/callgraph"
+ "golang.org/x/tools/go/ssa"
+ "golang.org/x/tools/go/ssa/ssautil"
+)
+
+// CallGraph computes the call graph of the specified program
+// considering only static calls.
+//
+func CallGraph(prog *ssa.Program) *callgraph.Graph {
+ cg := callgraph.New(nil) // TODO(adonovan) eliminate concept of rooted callgraph
+
+ // TODO(adonovan): opt: use only a single pass over the ssa.Program.
+ // TODO(adonovan): opt: this is slower than RTA (perhaps because
+ // the lower precision means so many edges are allocated)!
+ for f := range ssautil.AllFunctions(prog) {
+ fnode := cg.CreateNode(f)
+ for _, b := range f.Blocks {
+ for _, instr := range b.Instrs {
+ if site, ok := instr.(ssa.CallInstruction); ok {
+ if g := site.Common().StaticCallee(); g != nil {
+ gnode := cg.CreateNode(g)
+ callgraph.AddEdge(fnode, site, gnode)
+ }
+ }
+ }
+ }
+ }
+
+ return cg
+}
diff --git a/go/callgraph/static/static_test.go b/go/callgraph/static/static_test.go
new file mode 100644
index 0000000..62297f7
--- /dev/null
+++ b/go/callgraph/static/static_test.go
@@ -0,0 +1,88 @@
+// 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 static_test
+
+import (
+ "fmt"
+ "go/parser"
+ "reflect"
+ "sort"
+ "testing"
+
+ "golang.org/x/tools/go/callgraph"
+ "golang.org/x/tools/go/callgraph/static"
+ "golang.org/x/tools/go/loader"
+ "golang.org/x/tools/go/ssa/ssautil"
+)
+
+const input = `package P
+
+type C int
+func (C) f()
+
+type I interface{f()}
+
+func f() {
+ p := func() {}
+ g()
+ p() // SSA constant propagation => static
+
+ if unknown {
+ p = h
+ }
+ p() // dynamic
+
+ C(0).f()
+}
+
+func g() {
+ var i I = C(0)
+ i.f()
+}
+
+func h()
+
+var unknown bool
+`
+
+func TestStatic(t *testing.T) {
+ conf := loader.Config{ParserMode: parser.ParseComments}
+ f, err := conf.ParseFile("P.go", input)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ conf.CreateFromFiles("P", f)
+ iprog, err := conf.Load()
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ P := iprog.Created[0].Pkg
+
+ prog := ssautil.CreateProgram(iprog, 0)
+ prog.BuildAll()
+
+ cg := static.CallGraph(prog)
+
+ var edges []string
+ callgraph.GraphVisitEdges(cg, func(e *callgraph.Edge) error {
+ edges = append(edges, fmt.Sprintf("%s -> %s",
+ e.Caller.Func.RelString(P),
+ e.Callee.Func.RelString(P)))
+ return nil
+ })
+ sort.Strings(edges)
+
+ want := []string{
+ "(*C).f -> (C).f",
+ "f -> (C).f",
+ "f -> f$1",
+ "f -> g",
+ }
+ if !reflect.DeepEqual(edges, want) {
+ t.Errorf("Got edges %v, want %v", edges, want)
+ }
+}
diff --git a/go/callgraph/util.go b/go/callgraph/util.go
new file mode 100644
index 0000000..a8f8903
--- /dev/null
+++ b/go/callgraph/util.go
@@ -0,0 +1,181 @@
+// 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 callgraph
+
+import "golang.org/x/tools/go/ssa"
+
+// This file provides various utilities over call graphs, such as
+// visitation and path search.
+
+// CalleesOf returns a new set containing all direct callees of the
+// caller node.
+//
+func CalleesOf(caller *Node) map[*Node]bool {
+ callees := make(map[*Node]bool)
+ for _, e := range caller.Out {
+ callees[e.Callee] = true
+ }
+ return callees
+}
+
+// GraphVisitEdges visits all the edges in graph g in depth-first order.
+// The edge function is called for each edge in postorder. If it
+// returns non-nil, visitation stops and GraphVisitEdges returns that
+// value.
+//
+func GraphVisitEdges(g *Graph, edge func(*Edge) error) error {
+ seen := make(map[*Node]bool)
+ var visit func(n *Node) error
+ visit = func(n *Node) error {
+ if !seen[n] {
+ seen[n] = true
+ for _, e := range n.Out {
+ if err := visit(e.Callee); err != nil {
+ return err
+ }
+ if err := edge(e); err != nil {
+ return err
+ }
+ }
+ }
+ return nil
+ }
+ for _, n := range g.Nodes {
+ if err := visit(n); err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+// PathSearch finds an arbitrary path starting at node start and
+// ending at some node for which isEnd() returns true. On success,
+// PathSearch returns the path as an ordered list of edges; on
+// failure, it returns nil.
+//
+func PathSearch(start *Node, isEnd func(*Node) bool) []*Edge {
+ stack := make([]*Edge, 0, 32)
+ seen := make(map[*Node]bool)
+ var search func(n *Node) []*Edge
+ search = func(n *Node) []*Edge {
+ if !seen[n] {
+ seen[n] = true
+ if isEnd(n) {
+ return stack
+ }
+ for _, e := range n.Out {
+ stack = append(stack, e) // push
+ if found := search(e.Callee); found != nil {
+ return found
+ }
+ stack = stack[:len(stack)-1] // pop
+ }
+ }
+ return nil
+ }
+ return search(start)
+}
+
+// DeleteSyntheticNodes removes from call graph g all nodes for
+// synthetic functions (except g.Root and package initializers),
+// preserving the topology. In effect, calls to synthetic wrappers
+// are "inlined".
+//
+func (g *Graph) DeleteSyntheticNodes() {
+ // Measurements on the standard library and go.tools show that
+ // resulting graph has ~15% fewer nodes and 4-8% fewer edges
+ // than the input.
+ //
+ // Inlining a wrapper of in-degree m, out-degree n adds m*n
+ // and removes m+n edges. Since most wrappers are monomorphic
+ // (n=1) this results in a slight reduction. Polymorphic
+ // wrappers (n>1), e.g. from embedding an interface value
+ // inside a struct to satisfy some interface, cause an
+ // increase in the graph, but they seem to be uncommon.
+
+ // Hash all existing edges to avoid creating duplicates.
+ edges := make(map[Edge]bool)
+ for _, cgn := range g.Nodes {
+ for _, e := range cgn.Out {
+ edges[*e] = true
+ }
+ }
+ for fn, cgn := range g.Nodes {
+ if cgn == g.Root || fn.Synthetic == "" || isInit(cgn.Func) {
+ continue // keep
+ }
+ for _, eIn := range cgn.In {
+ for _, eOut := range cgn.Out {
+ newEdge := Edge{eIn.Caller, eIn.Site, eOut.Callee}
+ if edges[newEdge] {
+ continue // don't add duplicate
+ }
+ AddEdge(eIn.Caller, eIn.Site, eOut.Callee)
+ edges[newEdge] = true
+ }
+ }
+ g.DeleteNode(cgn)
+ }
+}
+
+func isInit(fn *ssa.Function) bool {
+ return fn.Pkg != nil && fn.Pkg.Func("init") == fn
+}
+
+// DeleteNode removes node n and its edges from the graph g.
+// (NB: not efficient for batch deletion.)
+func (g *Graph) DeleteNode(n *Node) {
+ n.deleteIns()
+ n.deleteOuts()
+ delete(g.Nodes, n.Func)
+}
+
+// deleteIns deletes all incoming edges to n.
+func (n *Node) deleteIns() {
+ for _, e := range n.In {
+ removeOutEdge(e)
+ }
+ n.In = nil
+}
+
+// deleteOuts deletes all outgoing edges from n.
+func (n *Node) deleteOuts() {
+ for _, e := range n.Out {
+ removeInEdge(e)
+ }
+ n.Out = nil
+}
+
+// removeOutEdge removes edge.Caller's outgoing edge 'edge'.
+func removeOutEdge(edge *Edge) {
+ caller := edge.Caller
+ n := len(caller.Out)
+ for i, e := range caller.Out {
+ if e == edge {
+ // Replace it with the final element and shrink the slice.
+ caller.Out[i] = caller.Out[n-1]
+ caller.Out[n-1] = nil // aid GC
+ caller.Out = caller.Out[:n-1]
+ return
+ }
+ }
+ panic("edge not found: " + edge.String())
+}
+
+// removeInEdge removes edge.Callee's incoming edge 'edge'.
+func removeInEdge(edge *Edge) {
+ caller := edge.Callee
+ n := len(caller.In)
+ for i, e := range caller.In {
+ if e == edge {
+ // Replace it with the final element and shrink the slice.
+ caller.In[i] = caller.In[n-1]
+ caller.In[n-1] = nil // aid GC
+ caller.In = caller.In[:n-1]
+ return
+ }
+ }
+ panic("edge not found: " + edge.String())
+}
diff --git a/go/exact/exact.go b/go/exact/exact.go
new file mode 100644
index 0000000..51c4906
--- /dev/null
+++ b/go/exact/exact.go
@@ -0,0 +1,920 @@
+// 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 exact implements Values representing untyped
+// Go constants and the corresponding operations. Values
+// and operations have unlimited precision.
+//
+// A special Unknown value may be used when a value
+// is unknown due to an error. Operations on unknown
+// values produce unknown values unless specified
+// otherwise.
+//
+package exact // import "golang.org/x/tools/go/exact"
+
+import (
+ "fmt"
+ "go/token"
+ "math/big"
+ "strconv"
+)
+
+// Kind specifies the kind of value represented by a Value.
+type Kind int
+
+// Implementation note: Kinds must be enumerated in
+// order of increasing "complexity" (used by match).
+
+const (
+ // unknown values
+ Unknown Kind = iota
+
+ // non-numeric values
+ Bool
+ String
+
+ // numeric values
+ Int
+ Float
+ Complex
+)
+
+// A Value represents a mathematically exact value of a given Kind.
+type Value interface {
+ // Kind returns the value kind; it is always the smallest
+ // kind in which the value can be represented exactly.
+ Kind() Kind
+
+ // String returns a human-readable form of the value.
+ String() string
+
+ // Prevent external implementations.
+ implementsValue()
+}
+
+// ----------------------------------------------------------------------------
+// Implementations
+
+type (
+ unknownVal struct{}
+ boolVal bool
+ stringVal string
+ int64Val int64
+ intVal struct{ val *big.Int }
+ floatVal struct{ val *big.Rat }
+ complexVal struct{ re, im *big.Rat }
+)
+
+func (unknownVal) Kind() Kind { return Unknown }
+func (boolVal) Kind() Kind { return Bool }
+func (stringVal) Kind() Kind { return String }
+func (int64Val) Kind() Kind { return Int }
+func (intVal) Kind() Kind { return Int }
+func (floatVal) Kind() Kind { return Float }
+func (complexVal) Kind() Kind { return Complex }
+
+func (unknownVal) String() string { return "unknown" }
+func (x boolVal) String() string { return fmt.Sprintf("%v", bool(x)) }
+func (x stringVal) String() string { return strconv.Quote(string(x)) }
+func (x int64Val) String() string { return strconv.FormatInt(int64(x), 10) }
+func (x intVal) String() string { return x.val.String() }
+func (x floatVal) String() string { return x.val.String() }
+func (x complexVal) String() string { return fmt.Sprintf("(%s + %si)", x.re, x.im) }
+
+func (unknownVal) implementsValue() {}
+func (boolVal) implementsValue() {}
+func (stringVal) implementsValue() {}
+func (int64Val) implementsValue() {}
+func (intVal) implementsValue() {}
+func (floatVal) implementsValue() {}
+func (complexVal) implementsValue() {}
+
+// int64 bounds
+var (
+ minInt64 = big.NewInt(-1 << 63)
+ maxInt64 = big.NewInt(1<<63 - 1)
+)
+
+func normInt(x *big.Int) Value {
+ if minInt64.Cmp(x) <= 0 && x.Cmp(maxInt64) <= 0 {
+ return int64Val(x.Int64())
+ }
+ return intVal{x}
+}
+
+func normFloat(x *big.Rat) Value {
+ if x.IsInt() {
+ return normInt(x.Num())
+ }
+ return floatVal{x}
+}
+
+func normComplex(re, im *big.Rat) Value {
+ if im.Sign() == 0 {
+ return normFloat(re)
+ }
+ return complexVal{re, im}
+}
+
+// ----------------------------------------------------------------------------
+// Factories
+
+// MakeUnknown returns the Unknown value.
+func MakeUnknown() Value { return unknownVal{} }
+
+// MakeBool returns the Bool value for x.
+func MakeBool(b bool) Value { return boolVal(b) }
+
+// MakeString returns the String value for x.
+func MakeString(s string) Value { return stringVal(s) }
+
+// MakeInt64 returns the Int value for x.
+func MakeInt64(x int64) Value { return int64Val(x) }
+
+// MakeUint64 returns the Int value for x.
+func MakeUint64(x uint64) Value { return normInt(new(big.Int).SetUint64(x)) }
+
+// MakeFloat64 returns the numeric value for x.
+// If x is not finite, the result is unknown.
+func MakeFloat64(x float64) Value {
+ if f := new(big.Rat).SetFloat64(x); f != nil {
+ return normFloat(f)
+ }
+ return unknownVal{}
+}
+
+// MakeFromLiteral returns the corresponding integer, floating-point,
+// imaginary, character, or string value for a Go literal string. The
+// result is nil if the literal string is invalid.
+func MakeFromLiteral(lit string, tok token.Token) Value {
+ switch tok {
+ case token.INT:
+ if x, err := strconv.ParseInt(lit, 0, 64); err == nil {
+ return int64Val(x)
+ }
+ if x, ok := new(big.Int).SetString(lit, 0); ok {
+ return intVal{x}
+ }
+
+ case token.FLOAT:
+ if x, ok := new(big.Rat).SetString(lit); ok {
+ return normFloat(x)
+ }
+
+ case token.IMAG:
+ if n := len(lit); n > 0 && lit[n-1] == 'i' {
+ if im, ok := new(big.Rat).SetString(lit[0 : n-1]); ok {
+ return normComplex(big.NewRat(0, 1), im)
+ }
+ }
+
+ case token.CHAR:
+ if n := len(lit); n >= 2 {
+ if code, _, _, err := strconv.UnquoteChar(lit[1:n-1], '\''); err == nil {
+ return int64Val(code)
+ }
+ }
+
+ case token.STRING:
+ if s, err := strconv.Unquote(lit); err == nil {
+ return stringVal(s)
+ }
+ }
+
+ return nil
+}
+
+// ----------------------------------------------------------------------------
+// Accessors
+//
+// For unknown arguments the result is the zero value for the respective
+// accessor type, except for Sign, where the result is 1.
+
+// BoolVal returns the Go boolean value of x, which must be a Bool or an Unknown.
+// If x is Unknown, the result is false.
+func BoolVal(x Value) bool {
+ switch x := x.(type) {
+ case boolVal:
+ return bool(x)
+ case unknownVal:
+ return false
+ }
+ panic(fmt.Sprintf("%v not a Bool", x))
+}
+
+// StringVal returns the Go string value of x, which must be a String or an Unknown.
+// If x is Unknown, the result is "".
+func StringVal(x Value) string {
+ switch x := x.(type) {
+ case stringVal:
+ return string(x)
+ case unknownVal:
+ return ""
+ }
+ panic(fmt.Sprintf("%v not a String", x))
+}
+
+// Int64Val returns the Go int64 value of x and whether the result is exact;
+// x must be an Int or an Unknown. If the result is not exact, its value is undefined.
+// If x is Unknown, the result is (0, false).
+func Int64Val(x Value) (int64, bool) {
+ switch x := x.(type) {
+ case int64Val:
+ return int64(x), true
+ case intVal:
+ return x.val.Int64(), x.val.BitLen() <= 63
+ case unknownVal:
+ return 0, false
+ }
+ panic(fmt.Sprintf("%v not an Int", x))
+}
+
+// Uint64Val returns the Go uint64 value of x and whether the result is exact;
+// x must be an Int or an Unknown. If the result is not exact, its value is undefined.
+// If x is Unknown, the result is (0, false).
+func Uint64Val(x Value) (uint64, bool) {
+ switch x := x.(type) {
+ case int64Val:
+ return uint64(x), x >= 0
+ case intVal:
+ return x.val.Uint64(), x.val.Sign() >= 0 && x.val.BitLen() <= 64
+ case unknownVal:
+ return 0, false
+ }
+ panic(fmt.Sprintf("%v not an Int", x))
+}
+
+// Float32Val is like Float64Val but for float32 instead of float64.
+func Float32Val(x Value) (float32, bool) {
+ switch x := x.(type) {
+ case int64Val:
+ f := float32(x)
+ return f, int64Val(f) == x
+ case intVal:
+ return ratToFloat32(new(big.Rat).SetFrac(x.val, int1))
+ case floatVal:
+ return ratToFloat32(x.val)
+ case unknownVal:
+ return 0, false
+ }
+ panic(fmt.Sprintf("%v not a Float", x))
+}
+
+// Float64Val returns the nearest Go float64 value of x and whether the result is exact;
+// x must be numeric but not Complex, or Unknown. For values too small (too close to 0)
+// to represent as float64, Float64Val silently underflows to 0. The result sign always
+// matches the sign of x, even for 0.
+// If x is Unknown, the result is (0, false).
+func Float64Val(x Value) (float64, bool) {
+ switch x := x.(type) {
+ case int64Val:
+ f := float64(int64(x))
+ return f, int64Val(f) == x
+ case intVal:
+ return new(big.Rat).SetFrac(x.val, int1).Float64()
+ case floatVal:
+ return x.val.Float64()
+ case unknownVal:
+ return 0, false
+ }
+ panic(fmt.Sprintf("%v not a Float", x))
+}
+
+// BitLen returns the number of bits required to represent
+// the absolute value x in binary representation; x must be an Int or an Unknown.
+// If x is Unknown, the result is 0.
+func BitLen(x Value) int {
+ switch x := x.(type) {
+ case int64Val:
+ return new(big.Int).SetInt64(int64(x)).BitLen()
+ case intVal:
+ return x.val.BitLen()
+ case unknownVal:
+ return 0
+ }
+ panic(fmt.Sprintf("%v not an Int", x))
+}
+
+// Sign returns -1, 0, or 1 depending on whether x < 0, x == 0, or x > 0;
+// x must be numeric or Unknown. For complex values x, the sign is 0 if x == 0,
+// otherwise it is != 0. If x is Unknown, the result is 1.
+func Sign(x Value) int {
+ switch x := x.(type) {
+ case int64Val:
+ switch {
+ case x < 0:
+ return -1
+ case x > 0:
+ return 1
+ }
+ return 0
+ case intVal:
+ return x.val.Sign()
+ case floatVal:
+ return x.val.Sign()
+ case complexVal:
+ return x.re.Sign() | x.im.Sign()
+ case unknownVal:
+ return 1 // avoid spurious division by zero errors
+ }
+ panic(fmt.Sprintf("%v not numeric", x))
+}
+
+// ----------------------------------------------------------------------------
+// Support for serializing/deserializing integers
+
+const (
+ // Compute the size of a Word in bytes.
+ _m = ^big.Word(0)
+ _log = _m>>8&1 + _m>>16&1 + _m>>32&1
+ wordSize = 1 << _log
+)
+
+// Bytes returns the bytes for the absolute value of x in little-
+// endian binary representation; x must be an Int.
+func Bytes(x Value) []byte {
+ var val *big.Int
+ switch x := x.(type) {
+ case int64Val:
+ val = new(big.Int).SetInt64(int64(x))
+ case intVal:
+ val = x.val
+ default:
+ panic(fmt.Sprintf("%v not an Int", x))
+ }
+
+ words := val.Bits()
+ bytes := make([]byte, len(words)*wordSize)
+
+ i := 0
+ for _, w := range words {
+ for j := 0; j < wordSize; j++ {
+ bytes[i] = byte(w)
+ w >>= 8
+ i++
+ }
+ }
+ // remove leading 0's
+ for i > 0 && bytes[i-1] == 0 {
+ i--
+ }
+
+ return bytes[:i]
+}
+
+// MakeFromBytes returns the Int value given the bytes of its little-endian
+// binary representation. An empty byte slice argument represents 0.
+func MakeFromBytes(bytes []byte) Value {
+ words := make([]big.Word, (len(bytes)+(wordSize-1))/wordSize)
+
+ i := 0
+ var w big.Word
+ var s uint
+ for _, b := range bytes {
+ w |= big.Word(b) << s
+ if s += 8; s == wordSize*8 {
+ words[i] = w
+ i++
+ w = 0
+ s = 0
+ }
+ }
+ // store last word
+ if i < len(words) {
+ words[i] = w
+ i++
+ }
+ // remove leading 0's
+ for i > 0 && words[i-1] == 0 {
+ i--
+ }
+
+ return normInt(new(big.Int).SetBits(words[:i]))
+}
+
+// ----------------------------------------------------------------------------
+// Support for disassembling fractions
+
+// Num returns the numerator of x; x must be Int, Float, or Unknown.
+// If x is Unknown, the result is Unknown, otherwise it is an Int
+// with the same sign as x.
+func Num(x Value) Value {
+ switch x := x.(type) {
+ case unknownVal, int64Val, intVal:
+ return x
+ case floatVal:
+ return normInt(x.val.Num())
+ }
+ panic(fmt.Sprintf("%v not Int or Float", x))
+}
+
+// Denom returns the denominator of x; x must be Int, Float, or Unknown.
+// If x is Unknown, the result is Unknown, otherwise it is an Int >= 1.
+func Denom(x Value) Value {
+ switch x := x.(type) {
+ case unknownVal:
+ return x
+ case int64Val, intVal:
+ return int64Val(1)
+ case floatVal:
+ return normInt(x.val.Denom())
+ }
+ panic(fmt.Sprintf("%v not Int or Float", x))
+}
+
+// ----------------------------------------------------------------------------
+// Support for assembling/disassembling complex numbers
+
+// MakeImag returns the numeric value x*i (possibly 0);
+// x must be Int, Float, or Unknown.
+// If x is Unknown, the result is Unknown.
+func MakeImag(x Value) Value {
+ var im *big.Rat
+ switch x := x.(type) {
+ case unknownVal:
+ return x
+ case int64Val:
+ im = big.NewRat(int64(x), 1)
+ case intVal:
+ im = new(big.Rat).SetFrac(x.val, int1)
+ case floatVal:
+ im = x.val
+ default:
+ panic(fmt.Sprintf("%v not Int or Float", x))
+ }
+ return normComplex(rat0, im)
+}
+
+// Real returns the real part of x, which must be a numeric or unknown value.
+// If x is Unknown, the result is Unknown.
+func Real(x Value) Value {
+ switch x := x.(type) {
+ case unknownVal, int64Val, intVal, floatVal:
+ return x
+ case complexVal:
+ return normFloat(x.re)
+ }
+ panic(fmt.Sprintf("%v not numeric", x))
+}
+
+// Imag returns the imaginary part of x, which must be a numeric or unknown value.
+// If x is Unknown, the result is Unknown.
+func Imag(x Value) Value {
+ switch x := x.(type) {
+ case unknownVal:
+ return x
+ case int64Val, intVal, floatVal:
+ return int64Val(0)
+ case complexVal:
+ return normFloat(x.im)
+ }
+ panic(fmt.Sprintf("%v not numeric", x))
+}
+
+// ----------------------------------------------------------------------------
+// Operations
+
+// is32bit reports whether x can be represented using 32 bits.
+func is32bit(x int64) bool {
+ const s = 32
+ return -1<<(s-1) <= x && x <= 1<<(s-1)-1
+}
+
+// is63bit reports whether x can be represented using 63 bits.
+func is63bit(x int64) bool {
+ const s = 63
+ return -1<<(s-1) <= x && x <= 1<<(s-1)-1
+}
+
+// UnaryOp returns the result of the unary expression op y.
+// The operation must be defined for the operand.
+// If size >= 0 it specifies the ^ (xor) result size in bytes.
+// If y is Unknown, the result is Unknown.
+//
+func UnaryOp(op token.Token, y Value, size int) Value {
+ switch op {
+ case token.ADD:
+ switch y.(type) {
+ case unknownVal, int64Val, intVal, floatVal, complexVal:
+ return y
+ }
+
+ case token.SUB:
+ switch y := y.(type) {
+ case unknownVal:
+ return y
+ case int64Val:
+ if z := -y; z != y {
+ return z // no overflow
+ }
+ return normInt(new(big.Int).Neg(big.NewInt(int64(y))))
+ case intVal:
+ return normInt(new(big.Int).Neg(y.val))
+ case floatVal:
+ return normFloat(new(big.Rat).Neg(y.val))
+ case complexVal:
+ return normComplex(new(big.Rat).Neg(y.re), new(big.Rat).Neg(y.im))
+ }
+
+ case token.XOR:
+ var z big.Int
+ switch y := y.(type) {
+ case unknownVal:
+ return y
+ case int64Val:
+ z.Not(big.NewInt(int64(y)))
+ case intVal:
+ z.Not(y.val)
+ default:
+ goto Error
+ }
+ // For unsigned types, the result will be negative and
+ // thus "too large": We must limit the result size to
+ // the type's size.
+ if size >= 0 {
+ s := uint(size) * 8
+ z.AndNot(&z, new(big.Int).Lsh(big.NewInt(-1), s)) // z &^= (-1)<<s
+ }
+ return normInt(&z)
+
+ case token.NOT:
+ switch y := y.(type) {
+ case unknownVal:
+ return y
+ case boolVal:
+ return !y
+ }
+ }
+
+Error:
+ panic(fmt.Sprintf("invalid unary operation %s%v", op, y))
+}
+
+var (
+ int1 = big.NewInt(1)
+ rat0 = big.NewRat(0, 1)
+)
+
+func ord(x Value) int {
+ switch x.(type) {
+ default:
+ return 0
+ case boolVal, stringVal:
+ return 1
+ case int64Val:
+ return 2
+ case intVal:
+ return 3
+ case floatVal:
+ return 4
+ case complexVal:
+ return 5
+ }
+}
+
+// match returns the matching representation (same type) with the
+// smallest complexity for two values x and y. If one of them is
+// numeric, both of them must be numeric. If one of them is Unknown,
+// both results are Unknown.
+//
+func match(x, y Value) (_, _ Value) {
+ if ord(x) > ord(y) {
+ y, x = match(y, x)
+ return x, y
+ }
+ // ord(x) <= ord(y)
+
+ switch x := x.(type) {
+ case unknownVal:
+ return x, x
+
+ case boolVal, stringVal, complexVal:
+ return x, y
+
+ case int64Val:
+ switch y := y.(type) {
+ case int64Val:
+ return x, y
+ case intVal:
+ return intVal{big.NewInt(int64(x))}, y
+ case floatVal:
+ return floatVal{big.NewRat(int64(x), 1)}, y
+ case complexVal:
+ return complexVal{big.NewRat(int64(x), 1), rat0}, y
+ }
+
+ case intVal:
+ switch y := y.(type) {
+ case intVal:
+ return x, y
+ case floatVal:
+ return floatVal{new(big.Rat).SetFrac(x.val, int1)}, y
+ case complexVal:
+ return complexVal{new(big.Rat).SetFrac(x.val, int1), rat0}, y
+ }
+
+ case floatVal:
+ switch y := y.(type) {
+ case floatVal:
+ return x, y
+ case complexVal:
+ return complexVal{x.val, rat0}, y
+ }
+ }
+
+ panic("unreachable")
+}
+
+// BinaryOp returns the result of the binary expression x op y.
+// The operation must be defined for the operands. If one of the
+// operands is Unknown, the result is Unknown.
+// To force integer division of Int operands, use op == token.QUO_ASSIGN
+// instead of token.QUO; the result is guaranteed to be Int in this case.
+// Division by zero leads to a run-time panic.
+//
+func BinaryOp(x Value, op token.Token, y Value) Value {
+ x, y = match(x, y)
+
+ switch x := x.(type) {
+ case unknownVal:
+ return x
+
+ case boolVal:
+ y := y.(boolVal)
+ switch op {
+ case token.LAND:
+ return x && y
+ case token.LOR:
+ return x || y
+ }
+
+ case int64Val:
+ a := int64(x)
+ b := int64(y.(int64Val))
+ var c int64
+ switch op {
+ case token.ADD:
+ if !is63bit(a) || !is63bit(b) {
+ return normInt(new(big.Int).Add(big.NewInt(a), big.NewInt(b)))
+ }
+ c = a + b
+ case token.SUB:
+ if !is63bit(a) || !is63bit(b) {
+ return normInt(new(big.Int).Sub(big.NewInt(a), big.NewInt(b)))
+ }
+ c = a - b
+ case token.MUL:
+ if !is32bit(a) || !is32bit(b) {
+ return normInt(new(big.Int).Mul(big.NewInt(a), big.NewInt(b)))
+ }
+ c = a * b
+ case token.QUO:
+ return normFloat(new(big.Rat).SetFrac(big.NewInt(a), big.NewInt(b)))
+ case token.QUO_ASSIGN: // force integer division
+ c = a / b
+ case token.REM:
+ c = a % b
+ case token.AND:
+ c = a & b
+ case token.OR:
+ c = a | b
+ case token.XOR:
+ c = a ^ b
+ case token.AND_NOT:
+ c = a &^ b
+ default:
+ goto Error
+ }
+ return int64Val(c)
+
+ case intVal:
+ a := x.val
+ b := y.(intVal).val
+ var c big.Int
+ switch op {
+ case token.ADD:
+ c.Add(a, b)
+ case token.SUB:
+ c.Sub(a, b)
+ case token.MUL:
+ c.Mul(a, b)
+ case token.QUO:
+ return normFloat(new(big.Rat).SetFrac(a, b))
+ case token.QUO_ASSIGN: // force integer division
+ c.Quo(a, b)
+ case token.REM:
+ c.Rem(a, b)
+ case token.AND:
+ c.And(a, b)
+ case token.OR:
+ c.Or(a, b)
+ case token.XOR:
+ c.Xor(a, b)
+ case token.AND_NOT:
+ c.AndNot(a, b)
+ default:
+ goto Error
+ }
+ return normInt(&c)
+
+ case floatVal:
+ a := x.val
+ b := y.(floatVal).val
+ var c big.Rat
+ switch op {
+ case token.ADD:
+ c.Add(a, b)
+ case token.SUB:
+ c.Sub(a, b)
+ case token.MUL:
+ c.Mul(a, b)
+ case token.QUO:
+ c.Quo(a, b)
+ default:
+ goto Error
+ }
+ return normFloat(&c)
+
+ case complexVal:
+ y := y.(complexVal)
+ a, b := x.re, x.im
+ c, d := y.re, y.im
+ var re, im big.Rat
+ switch op {
+ case token.ADD:
+ // (a+c) + i(b+d)
+ re.Add(a, c)
+ im.Add(b, d)
+ case token.SUB:
+ // (a-c) + i(b-d)
+ re.Sub(a, c)
+ im.Sub(b, d)
+ case token.MUL:
+ // (ac-bd) + i(bc+ad)
+ var ac, bd, bc, ad big.Rat
+ ac.Mul(a, c)
+ bd.Mul(b, d)
+ bc.Mul(b, c)
+ ad.Mul(a, d)
+ re.Sub(&ac, &bd)
+ im.Add(&bc, &ad)
+ case token.QUO:
+ // (ac+bd)/s + i(bc-ad)/s, with s = cc + dd
+ var ac, bd, bc, ad, s, cc, dd big.Rat
+ ac.Mul(a, c)
+ bd.Mul(b, d)
+ bc.Mul(b, c)
+ ad.Mul(a, d)
+ cc.Mul(c, c)
+ dd.Mul(d, d)
+ s.Add(&cc, &dd)
+ re.Add(&ac, &bd)
+ re.Quo(&re, &s)
+ im.Sub(&bc, &ad)
+ im.Quo(&im, &s)
+ default:
+ goto Error
+ }
+ return normComplex(&re, &im)
+
+ case stringVal:
+ if op == token.ADD {
+ return x + y.(stringVal)
+ }
+ }
+
+Error:
+ panic(fmt.Sprintf("invalid binary operation %v %s %v", x, op, y))
+}
+
+// Shift returns the result of the shift expression x op s
+// with op == token.SHL or token.SHR (<< or >>). x must be
+// an Int or an Unknown. If x is Unknown, the result is x.
+//
+func Shift(x Value, op token.Token, s uint) Value {
+ switch x := x.(type) {
+ case unknownVal:
+ return x
+
+ case int64Val:
+ if s == 0 {
+ return x
+ }
+ switch op {
+ case token.SHL:
+ z := big.NewInt(int64(x))
+ return normInt(z.Lsh(z, s))
+ case token.SHR:
+ return x >> s
+ }
+
+ case intVal:
+ if s == 0 {
+ return x
+ }
+ var z big.Int
+ switch op {
+ case token.SHL:
+ return normInt(z.Lsh(x.val, s))
+ case token.SHR:
+ return normInt(z.Rsh(x.val, s))
+ }
+ }
+
+ panic(fmt.Sprintf("invalid shift %v %s %d", x, op, s))
+}
+
+func cmpZero(x int, op token.Token) bool {
+ switch op {
+ case token.EQL:
+ return x == 0
+ case token.NEQ:
+ return x != 0
+ case token.LSS:
+ return x < 0
+ case token.LEQ:
+ return x <= 0
+ case token.GTR:
+ return x > 0
+ case token.GEQ:
+ return x >= 0
+ }
+ panic("unreachable")
+}
+
+// Compare returns the result of the comparison x op y.
+// The comparison must be defined for the operands.
+// If one of the operands is Unknown, the result is
+// false.
+//
+func Compare(x Value, op token.Token, y Value) bool {
+ x, y = match(x, y)
+
+ switch x := x.(type) {
+ case unknownVal:
+ return false
+
+ case boolVal:
+ y := y.(boolVal)
+ switch op {
+ case token.EQL:
+ return x == y
+ case token.NEQ:
+ return x != y
+ }
+
+ case int64Val:
+ y := y.(int64Val)
+ switch op {
+ case token.EQL:
+ return x == y
+ case token.NEQ:
+ return x != y
+ case token.LSS:
+ return x < y
+ case token.LEQ:
+ return x <= y
+ case token.GTR:
+ return x > y
+ case token.GEQ:
+ return x >= y
+ }
+
+ case intVal:
+ return cmpZero(x.val.Cmp(y.(intVal).val), op)
+
+ case floatVal:
+ return cmpZero(x.val.Cmp(y.(floatVal).val), op)
+
+ case complexVal:
+ y := y.(complexVal)
+ re := x.re.Cmp(y.re)
+ im := x.im.Cmp(y.im)
+ switch op {
+ case token.EQL:
+ return re == 0 && im == 0
+ case token.NEQ:
+ return re != 0 || im != 0
+ }
+
+ case stringVal:
+ y := y.(stringVal)
+ switch op {
+ case token.EQL:
+ return x == y
+ case token.NEQ:
+ return x != y
+ case token.LSS:
+ return x < y
+ case token.LEQ:
+ return x <= y
+ case token.GTR:
+ return x > y
+ case token.GEQ:
+ return x >= y
+ }
+ }
+
+ panic(fmt.Sprintf("invalid comparison %v %s %v", x, op, y))
+}
diff --git a/go/exact/exact_test.go b/go/exact/exact_test.go
new file mode 100644
index 0000000..aa38a89
--- /dev/null
+++ b/go/exact/exact_test.go
@@ -0,0 +1,375 @@
+// 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 exact
+
+import (
+ "go/token"
+ "strings"
+ "testing"
+)
+
+// TODO(gri) expand this test framework
+
+var opTests = []string{
+ // unary operations
+ `+ 0 = 0`,
+ `+ ? = ?`,
+ `- 1 = -1`,
+ `- ? = ?`,
+ `^ 0 = -1`,
+ `^ ? = ?`,
+
+ `! true = false`,
+ `! false = true`,
+ `! ? = ?`,
+
+ // etc.
+
+ // binary operations
+ `"" + "" = ""`,
+ `"foo" + "" = "foo"`,
+ `"" + "bar" = "bar"`,
+ `"foo" + "bar" = "foobar"`,
+
+ `0 + 0 = 0`,
+ `0 + 0.1 = 0.1`,
+ `0 + 0.1i = 0.1i`,
+ `0.1 + 0.9 = 1`,
+ `1e100 + 1e100 = 2e100`,
+ `? + 0 = ?`,
+ `0 + ? = ?`,
+
+ `0 - 0 = 0`,
+ `0 - 0.1 = -0.1`,
+ `0 - 0.1i = -0.1i`,
+ `1e100 - 1e100 = 0`,
+ `? - 0 = ?`,
+ `0 - ? = ?`,
+
+ `0 * 0 = 0`,
+ `1 * 0.1 = 0.1`,
+ `1 * 0.1i = 0.1i`,
+ `1i * 1i = -1`,
+ `? * 0 = ?`,
+ `0 * ? = ?`,
+
+ `0 / 0 = "division_by_zero"`,
+ `10 / 2 = 5`,
+ `5 / 3 = 5/3`,
+ `5i / 3i = 5/3`,
+ `? / 0 = ?`,
+ `0 / ? = ?`,
+
+ `0 % 0 = "runtime_error:_integer_divide_by_zero"`, // TODO(gri) should be the same as for /
+ `10 % 3 = 1`,
+ `? % 0 = ?`,
+ `0 % ? = ?`,
+
+ `0 & 0 = 0`,
+ `12345 & 0 = 0`,
+ `0xff & 0xf = 0xf`,
+ `? & 0 = ?`,
+ `0 & ? = ?`,
+
+ `0 | 0 = 0`,
+ `12345 | 0 = 12345`,
+ `0xb | 0xa0 = 0xab`,
+ `? | 0 = ?`,
+ `0 | ? = ?`,
+
+ `0 ^ 0 = 0`,
+ `1 ^ -1 = -2`,
+ `? ^ 0 = ?`,
+ `0 ^ ? = ?`,
+
+ `0 &^ 0 = 0`,
+ `0xf &^ 1 = 0xe`,
+ `1 &^ 0xf = 0`,
+ // etc.
+
+ // shifts
+ `0 << 0 = 0`,
+ `1 << 10 = 1024`,
+ `0 >> 0 = 0`,
+ `1024 >> 10 == 1`,
+ `? << 0 == ?`,
+ `? >> 10 == ?`,
+ // etc.
+
+ // comparisons
+ `false == false = true`,
+ `false == true = false`,
+ `true == false = false`,
+ `true == true = true`,
+
+ `false != false = false`,
+ `false != true = true`,
+ `true != false = true`,
+ `true != true = false`,
+
+ `"foo" == "bar" = false`,
+ `"foo" != "bar" = true`,
+ `"foo" < "bar" = false`,
+ `"foo" <= "bar" = false`,
+ `"foo" > "bar" = true`,
+ `"foo" >= "bar" = true`,
+
+ `0 == 0 = true`,
+ `0 != 0 = false`,
+ `0 < 10 = true`,
+ `10 <= 10 = true`,
+ `0 > 10 = false`,
+ `10 >= 10 = true`,
+
+ `1/123456789 == 1/123456789 == true`,
+ `1/123456789 != 1/123456789 == false`,
+ `1/123456789 < 1/123456788 == true`,
+ `1/123456788 <= 1/123456789 == false`,
+ `0.11 > 0.11 = false`,
+ `0.11 >= 0.11 = true`,
+
+ `? == 0 = false`,
+ `? != 0 = false`,
+ `? < 10 = false`,
+ `? <= 10 = false`,
+ `? > 10 = false`,
+ `? >= 10 = false`,
+
+ `0 == ? = false`,
+ `0 != ? = false`,
+ `0 < ? = false`,
+ `10 <= ? = false`,
+ `0 > ? = false`,
+ `10 >= ? = false`,
+
+ // etc.
+}
+
+func TestOps(t *testing.T) {
+ for _, test := range opTests {
+ a := strings.Split(test, " ")
+ i := 0 // operator index
+
+ var x, x0 Value
+ switch len(a) {
+ case 4:
+ // unary operation
+ case 5:
+ // binary operation
+ x, x0 = val(a[0]), val(a[0])
+ i = 1
+ default:
+ t.Errorf("invalid test case: %s", test)
+ continue
+ }
+
+ op, ok := optab[a[i]]
+ if !ok {
+ panic("missing optab entry for " + a[i])
+ }
+
+ y, y0 := val(a[i+1]), val(a[i+1])
+
+ got := doOp(x, op, y)
+ want := val(a[i+3])
+ if !eql(got, want) {
+ t.Errorf("%s: got %s; want %s", test, got, want)
+ }
+ if x0 != nil && !eql(x, x0) {
+ t.Errorf("%s: x changed to %s", test, x)
+ }
+ if !eql(y, y0) {
+ t.Errorf("%s: y changed to %s", test, y)
+ }
+ }
+}
+
+func eql(x, y Value) bool {
+ _, ux := x.(unknownVal)
+ _, uy := y.(unknownVal)
+ if ux || uy {
+ return ux == uy
+ }
+ return Compare(x, token.EQL, y)
+}
+
+// ----------------------------------------------------------------------------
+// Support functions
+
+func val(lit string) Value {
+ if len(lit) == 0 {
+ return MakeUnknown()
+ }
+
+ switch lit {
+ case "?":
+ return MakeUnknown()
+ case "true":
+ return MakeBool(true)
+ case "false":
+ return MakeBool(false)
+ }
+
+ tok := token.INT
+ switch first, last := lit[0], lit[len(lit)-1]; {
+ case first == '"' || first == '`':
+ tok = token.STRING
+ lit = strings.Replace(lit, "_", " ", -1)
+ case first == '\'':
+ tok = token.CHAR
+ case last == 'i':
+ tok = token.IMAG
+ default:
+ if !strings.HasPrefix(lit, "0x") && strings.ContainsAny(lit, "./Ee") {
+ tok = token.FLOAT
+ }
+ }
+
+ return MakeFromLiteral(lit, tok)
+}
+
+var optab = map[string]token.Token{
+ "!": token.NOT,
+
+ "+": token.ADD,
+ "-": token.SUB,
+ "*": token.MUL,
+ "/": token.QUO,
+ "%": token.REM,
+
+ "<<": token.SHL,
+ ">>": token.SHR,
+
+ "&": token.AND,
+ "|": token.OR,
+ "^": token.XOR,
+ "&^": token.AND_NOT,
+
+ "==": token.EQL,
+ "!=": token.NEQ,
+ "<": token.LSS,
+ "<=": token.LEQ,
+ ">": token.GTR,
+ ">=": token.GEQ,
+}
+
+func panicHandler(v *Value) {
+ switch p := recover().(type) {
+ case nil:
+ // nothing to do
+ case string:
+ *v = MakeString(p)
+ case error:
+ *v = MakeString(p.Error())
+ default:
+ panic(p)
+ }
+}
+
+func doOp(x Value, op token.Token, y Value) (z Value) {
+ defer panicHandler(&z)
+
+ if x == nil {
+ return UnaryOp(op, y, -1)
+ }
+
+ switch op {
+ case token.EQL, token.NEQ, token.LSS, token.LEQ, token.GTR, token.GEQ:
+ return MakeBool(Compare(x, op, y))
+ case token.SHL, token.SHR:
+ s, _ := Int64Val(y)
+ return Shift(x, op, uint(s))
+ default:
+ return BinaryOp(x, op, y)
+ }
+}
+
+// ----------------------------------------------------------------------------
+// Other tests
+
+var fracTests = []string{
+ "0 0 1",
+ "1 1 1",
+ "-1 -1 1",
+ "1.2 6 5",
+ "-0.991 -991 1000",
+ "1e100 1e100 1",
+}
+
+func TestFractions(t *testing.T) {
+ for _, test := range fracTests {
+ a := strings.Split(test, " ")
+ if len(a) != 3 {
+ t.Errorf("invalid test case: %s", test)
+ continue
+ }
+
+ x := val(a[0])
+ n := val(a[1])
+ d := val(a[2])
+
+ if got := Num(x); !eql(got, n) {
+ t.Errorf("%s: got num = %s; want %s", test, got, n)
+ }
+
+ if got := Denom(x); !eql(got, d) {
+ t.Errorf("%s: got denom = %s; want %s", test, got, d)
+ }
+ }
+}
+
+var bytesTests = []string{
+ "0",
+ "1",
+ "123456789",
+ "123456789012345678901234567890123456789012345678901234567890",
+}
+
+func TestBytes(t *testing.T) {
+ for _, test := range bytesTests {
+ x := val(test)
+ bytes := Bytes(x)
+
+ // special case 0
+ if Sign(x) == 0 && len(bytes) != 0 {
+ t.Errorf("%s: got %v; want empty byte slice", test, bytes)
+ }
+
+ if n := len(bytes); n > 0 && bytes[n-1] == 0 {
+ t.Errorf("%s: got %v; want no leading 0 byte", test, bytes)
+ }
+
+ if got := MakeFromBytes(bytes); !eql(got, x) {
+ t.Errorf("%s: got %s; want %s (bytes = %v)", test, got, x, bytes)
+ }
+ }
+}
+
+func TestUnknown(t *testing.T) {
+ u := MakeUnknown()
+ var values = []Value{
+ u,
+ MakeBool(false), // token.ADD ok below, operation is never considered
+ MakeString(""),
+ MakeInt64(1),
+ MakeFromLiteral("-1234567890123456789012345678901234567890", token.INT),
+ MakeFloat64(1.2),
+ MakeImag(MakeFloat64(1.2)),
+ }
+ for _, val := range values {
+ x, y := val, u
+ for i := range [2]int{} {
+ if i == 1 {
+ x, y = y, x
+ }
+ if got := BinaryOp(x, token.ADD, y); got.Kind() != Unknown {
+ t.Errorf("%s + %s: got %s; want %s", x, y, got, u)
+ }
+ if got := Compare(x, token.EQL, y); got {
+ t.Errorf("%s == %s: got true; want false", x, y)
+ }
+ }
+ }
+}
diff --git a/go/exact/go13.go b/go/exact/go13.go
new file mode 100644
index 0000000..1016c14
--- /dev/null
+++ b/go/exact/go13.go
@@ -0,0 +1,24 @@
+// 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.
+
+// +build !go1.4
+
+package exact
+
+import (
+ "math"
+ "math/big"
+)
+
+func ratToFloat32(x *big.Rat) (float32, bool) {
+ // Before 1.4, there's no Rat.Float32.
+ // Emulate it, albeit at the cost of
+ // imprecision in corner cases.
+ x64, exact := x.Float64()
+ x32 := float32(x64)
+ if math.IsInf(float64(x32), 0) {
+ exact = false
+ }
+ return x32, exact
+}
diff --git a/go/exact/go14.go b/go/exact/go14.go
new file mode 100644
index 0000000..b86e5d2
--- /dev/null
+++ b/go/exact/go14.go
@@ -0,0 +1,13 @@
+// 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.
+
+// +build go1.4
+
+package exact
+
+import "math/big"
+
+func ratToFloat32(x *big.Rat) (float32, bool) {
+ return x.Float32()
+}
diff --git a/go/gccgoimporter/gccgoinstallation.go b/go/gccgoimporter/gccgoinstallation.go
new file mode 100644
index 0000000..1c56cf5
--- /dev/null
+++ b/go/gccgoimporter/gccgoinstallation.go
@@ -0,0 +1,95 @@
+// 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 gccgoimporter
+
+import (
+ "bufio"
+ "os"
+ "os/exec"
+ "path/filepath"
+ "strings"
+
+ "golang.org/x/tools/go/types"
+)
+
+// Information about a specific installation of gccgo.
+type GccgoInstallation struct {
+ // Version of gcc (e.g. 4.8.0).
+ GccVersion string
+
+ // Target triple (e.g. x86_64-unknown-linux-gnu).
+ TargetTriple string
+
+ // Built-in library paths used by this installation.
+ LibPaths []string
+}
+
+// Ask the driver at the given path for information for this GccgoInstallation.
+func (inst *GccgoInstallation) InitFromDriver(gccgoPath string) (err error) {
+ cmd := exec.Command(gccgoPath, "-###", "-S", "-x", "go", "-")
+ stderr, err := cmd.StderrPipe()
+ if err != nil {
+ return
+ }
+
+ err = cmd.Start()
+ if err != nil {
+ return
+ }
+
+ scanner := bufio.NewScanner(stderr)
+ for scanner.Scan() {
+ line := scanner.Text()
+ switch {
+ case strings.HasPrefix(line, "Target: "):
+ inst.TargetTriple = line[8:]
+
+ case line[0] == ' ':
+ args := strings.Fields(line)
+ for _, arg := range args[1:] {
+ if strings.HasPrefix(arg, "-L") {
+ inst.LibPaths = append(inst.LibPaths, arg[2:])
+ }
+ }
+ }
+ }
+
+ stdout, err := exec.Command(gccgoPath, "-dumpversion").Output()
+ if err != nil {
+ return
+ }
+ inst.GccVersion = strings.TrimSpace(string(stdout))
+
+ return
+}
+
+// Return the list of export search paths for this GccgoInstallation.
+func (inst *GccgoInstallation) SearchPaths() (paths []string) {
+ for _, lpath := range inst.LibPaths {
+ spath := filepath.Join(lpath, "go", inst.GccVersion)
+ fi, err := os.Stat(spath)
+ if err != nil || !fi.IsDir() {
+ continue
+ }
+ paths = append(paths, spath)
+
+ spath = filepath.Join(spath, inst.TargetTriple)
+ fi, err = os.Stat(spath)
+ if err != nil || !fi.IsDir() {
+ continue
+ }
+ paths = append(paths, spath)
+ }
+
+ paths = append(paths, inst.LibPaths...)
+
+ return
+}
+
+// Return an importer that searches incpaths followed by the gcc installation's
+// built-in search paths and the current directory.
+func (inst *GccgoInstallation) GetImporter(incpaths []string, initmap map[*types.Package]InitData) types.Importer {
+ return GetImporter(append(append(incpaths, inst.SearchPaths()...), "."), initmap)
+}
diff --git a/go/gccgoimporter/gccgoinstallation_test.go b/go/gccgoimporter/gccgoinstallation_test.go
new file mode 100644
index 0000000..9ab928d
--- /dev/null
+++ b/go/gccgoimporter/gccgoinstallation_test.go
@@ -0,0 +1,194 @@
+// 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 gccgoimporter
+
+import (
+ "runtime"
+ "testing"
+
+ "golang.org/x/tools/go/types"
+)
+
+var importablePackages = [...]string{
+ "archive/tar",
+ "archive/zip",
+ "bufio",
+ "bytes",
+ "compress/bzip2",
+ "compress/flate",
+ "compress/gzip",
+ "compress/lzw",
+ "compress/zlib",
+ "container/heap",
+ "container/list",
+ "container/ring",
+ "crypto/aes",
+ "crypto/cipher",
+ "crypto/des",
+ "crypto/dsa",
+ "crypto/ecdsa",
+ "crypto/elliptic",
+ "crypto",
+ "crypto/hmac",
+ "crypto/md5",
+ "crypto/rand",
+ "crypto/rc4",
+ "crypto/rsa",
+ "crypto/sha1",
+ "crypto/sha256",
+ "crypto/sha512",
+ "crypto/subtle",
+ "crypto/tls",
+ "crypto/x509",
+ "crypto/x509/pkix",
+ "database/sql/driver",
+ "database/sql",
+ "debug/dwarf",
+ "debug/elf",
+ "debug/gosym",
+ "debug/macho",
+ "debug/pe",
+ "encoding/ascii85",
+ "encoding/asn1",
+ "encoding/base32",
+ "encoding/base64",
+ "encoding/binary",
+ "encoding/csv",
+ "encoding/gob",
+ "encoding",
+ "encoding/hex",
+ "encoding/json",
+ "encoding/pem",
+ "encoding/xml",
+ "errors",
+ "exp/proxy",
+ "exp/terminal",
+ "expvar",
+ "flag",
+ "fmt",
+ "go/ast",
+ "go/build",
+ "go/doc",
+ "go/format",
+ "go/parser",
+ "go/printer",
+ "go/scanner",
+ "go/token",
+ "hash/adler32",
+ "hash/crc32",
+ "hash/crc64",
+ "hash/fnv",
+ "hash",
+ "html",
+ "html/template",
+ "image/color",
+ "image/color/palette",
+ "image/draw",
+ "image/gif",
+ "image",
+ "image/jpeg",
+ "image/png",
+ "index/suffixarray",
+ "io",
+ "io/ioutil",
+ "log",
+ "log/syslog",
+ "math/big",
+ "math/cmplx",
+ "math",
+ "math/rand",
+ "mime",
+ "mime/multipart",
+ "net",
+ "net/http/cgi",
+ "net/http/cookiejar",
+ "net/http/fcgi",
+ "net/http",
+ "net/http/httptest",
+ "net/http/httputil",
+ "net/http/pprof",
+ "net/mail",
+ "net/rpc",
+ "net/rpc/jsonrpc",
+ "net/smtp",
+ "net/textproto",
+ "net/url",
+ "old/regexp",
+ "old/template",
+ "os/exec",
+ "os",
+ "os/signal",
+ "os/user",
+ "path/filepath",
+ "path",
+ "reflect",
+ "regexp",
+ "regexp/syntax",
+ "runtime/debug",
+ "runtime",
+ "runtime/pprof",
+ "sort",
+ "strconv",
+ "strings",
+ "sync/atomic",
+ "sync",
+ "syscall",
+ "testing",
+ "testing/iotest",
+ "testing/quick",
+ "text/scanner",
+ "text/tabwriter",
+ "text/template",
+ "text/template/parse",
+ "time",
+ "unicode",
+ "unicode/utf16",
+ "unicode/utf8",
+}
+
+func TestInstallationImporter(t *testing.T) {
+ // This test relies on gccgo being around, which it most likely will be if we
+ // were compiled with gccgo.
+ if runtime.Compiler != "gccgo" {
+ t.Skip("This test needs gccgo")
+ return
+ }
+
+ var inst GccgoInstallation
+ err := inst.InitFromDriver("gccgo")
+ if err != nil {
+ t.Fatal(err)
+ }
+ imp := inst.GetImporter(nil, nil)
+
+ // Ensure we don't regress the number of packages we can parse. First import
+ // all packages into the same map and then each individually.
+ pkgMap := make(map[string]*types.Package)
+ for _, pkg := range importablePackages {
+ _, err = imp(pkgMap, pkg)
+ if err != nil {
+ t.Error(err)
+ }
+ }
+
+ for _, pkg := range importablePackages {
+ _, err = imp(make(map[string]*types.Package), pkg)
+ if err != nil {
+ t.Error(err)
+ }
+ }
+
+ // Test for certain specific entities in the imported data.
+ for _, test := range [...]importerTest{
+ {pkgpath: "io", name: "Reader", want: "type Reader interface{Read(p []uint8) (n int, err error)}"},
+ {pkgpath: "io", name: "ReadWriter", want: "type ReadWriter interface{Reader; Writer}"},
+ {pkgpath: "math", name: "Pi", want: "const Pi untyped float"},
+ {pkgpath: "math", name: "Sin", want: "func Sin(x float64) float64"},
+ {pkgpath: "sort", name: "Ints", want: "func Ints(a []int)"},
+ {pkgpath: "unsafe", name: "Pointer", want: "type Pointer unsafe.Pointer"},
+ } {
+ runImporterTest(t, imp, nil, &test)
+ }
+}
diff --git a/go/gccgoimporter/importer.go b/go/gccgoimporter/importer.go
new file mode 100644
index 0000000..ac484af
--- /dev/null
+++ b/go/gccgoimporter/importer.go
@@ -0,0 +1,205 @@
+// 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 gccgoimporter implements Import for gccgo-generated object files.
+package gccgoimporter // import "golang.org/x/tools/go/gccgoimporter"
+
+import (
+ "bytes"
+ "debug/elf"
+ "fmt"
+ "io"
+ "io/ioutil"
+ "os"
+ "os/exec"
+ "path/filepath"
+ "strings"
+
+ "golang.org/x/tools/go/importer"
+ "golang.org/x/tools/go/types"
+)
+
+// A PackageInit describes an imported package that needs initialization.
+type PackageInit struct {
+ Name string // short package name
+ InitFunc string // name of init function
+ Priority int // priority of init function, see InitData.Priority
+}
+
+// The gccgo-specific init data for a package.
+type InitData struct {
+ // Initialization priority of this package relative to other packages.
+ // This is based on the maximum depth of the package's dependency graph;
+ // it is guaranteed to be greater than that of its dependencies.
+ Priority int
+
+ // The list of packages which this package depends on to be initialized,
+ // including itself if needed. This is the subset of the transitive closure of
+ // the package's dependencies that need initialization.
+ Inits []PackageInit
+}
+
+// Locate the file from which to read export data.
+// This is intended to replicate the logic in gofrontend.
+func findExportFile(searchpaths []string, pkgpath string) (string, error) {
+ for _, spath := range searchpaths {
+ pkgfullpath := filepath.Join(spath, pkgpath)
+ pkgdir, name := filepath.Split(pkgfullpath)
+
+ for _, filepath := range [...]string{
+ pkgfullpath,
+ pkgfullpath + ".gox",
+ pkgdir + "lib" + name + ".so",
+ pkgdir + "lib" + name + ".a",
+ pkgfullpath + ".o",
+ } {
+ fi, err := os.Stat(filepath)
+ if err == nil && !fi.IsDir() {
+ return filepath, nil
+ }
+ }
+ }
+
+ return "", fmt.Errorf("%s: could not find export data (tried %s)", pkgpath, strings.Join(searchpaths, ":"))
+}
+
+const (
+ gccgov1Magic = "v1;\n"
+ goimporterMagic = "\n$$ "
+ archiveMagic = "!<ar"
+)
+
+// Opens the export data file at the given path. If this is an ELF file,
+// searches for and opens the .go_export section. If this is an archive,
+// reads the export data from the first member, which is assumed to be an ELF file.
+// This is intended to replicate the logic in gofrontend.
+func openExportFile(fpath string) (reader io.ReadSeeker, closer io.Closer, err error) {
+ f, err := os.Open(fpath)
+ if err != nil {
+ return
+ }
+ closer = f
+ defer func() {
+ if err != nil && closer != nil {
+ f.Close()
+ }
+ }()
+
+ var magic [4]byte
+ _, err = f.ReadAt(magic[:], 0)
+ if err != nil {
+ return
+ }
+ // reset to offset 0 - needed on Plan 9 (see issue #11265)
+ // TODO: remove once issue #11265 has been resolved.
+ _, err = f.Seek(0, 0)
+ if err != nil {
+ return
+ }
+
+ var elfreader io.ReaderAt
+ switch string(magic[:]) {
+ case gccgov1Magic, goimporterMagic:
+ // Raw export data.
+ reader = f
+ return
+
+ case archiveMagic:
+ // TODO(pcc): Read the archive directly instead of using "ar".
+ f.Close()
+ closer = nil
+
+ cmd := exec.Command("ar", "p", fpath)
+ var out []byte
+ out, err = cmd.Output()
+ if err != nil {
+ return
+ }
+
+ elfreader = bytes.NewReader(out)
+
+ default:
+ elfreader = f
+ }
+
+ ef, err := elf.NewFile(elfreader)
+ if err != nil {
+ return
+ }
+
+ sec := ef.Section(".go_export")
+ if sec == nil {
+ err = fmt.Errorf("%s: .go_export section not found", fpath)
+ return
+ }
+
+ reader = sec.Open()
+ return
+}
+
+func GetImporter(searchpaths []string, initmap map[*types.Package]InitData) types.Importer {
+ return func(imports map[string]*types.Package, pkgpath string) (pkg *types.Package, err error) {
+ if pkgpath == "unsafe" {
+ return types.Unsafe, nil
+ }
+
+ fpath, err := findExportFile(searchpaths, pkgpath)
+ if err != nil {
+ return
+ }
+
+ reader, closer, err := openExportFile(fpath)
+ if err != nil {
+ return
+ }
+ if closer != nil {
+ defer closer.Close()
+ }
+
+ var magic [4]byte
+ _, err = reader.Read(magic[:])
+ if err != nil {
+ return
+ }
+ _, err = reader.Seek(0, 0)
+ if err != nil {
+ return
+ }
+
+ switch string(magic[:]) {
+ case gccgov1Magic:
+ var p parser
+ p.init(fpath, reader, imports)
+ pkg = p.parsePackage()
+ if initmap != nil {
+ initmap[pkg] = p.initdata
+ }
+
+ case goimporterMagic:
+ var data []byte
+ data, err = ioutil.ReadAll(reader)
+ if err != nil {
+ return
+ }
+ var n int
+ n, pkg, err = importer.ImportData(imports, data)
+ if err != nil {
+ return
+ }
+
+ if initmap != nil {
+ suffixreader := bytes.NewReader(data[n:])
+ var p parser
+ p.init(fpath, suffixreader, nil)
+ p.parseInitData()
+ initmap[pkg] = p.initdata
+ }
+
+ default:
+ err = fmt.Errorf("unrecognized magic string: %q", string(magic[:]))
+ }
+
+ return
+ }
+}
diff --git a/go/gccgoimporter/importer_test.go b/go/gccgoimporter/importer_test.go
new file mode 100644
index 0000000..78b4349
--- /dev/null
+++ b/go/gccgoimporter/importer_test.go
@@ -0,0 +1,170 @@
+// 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 gccgoimporter
+
+import (
+ "io/ioutil"
+ "os"
+ "os/exec"
+ "path/filepath"
+ "runtime"
+ "testing"
+
+ "golang.org/x/tools/go/types"
+)
+
+type importerTest struct {
+ pkgpath, name, want, wantval string
+ wantinits []string
+}
+
+func runImporterTest(t *testing.T, imp types.Importer, initmap map[*types.Package]InitData, test *importerTest) {
+ pkg, err := imp(make(map[string]*types.Package), test.pkgpath)
+ if err != nil {
+ t.Error(err)
+ return
+ }
+
+ if test.name != "" {
+ obj := pkg.Scope().Lookup(test.name)
+ if obj == nil {
+ t.Errorf("%s: object not found", test.name)
+ return
+ }
+
+ got := types.ObjectString(obj, types.RelativeTo(pkg))
+ if got != test.want {
+ t.Errorf("%s: got %q; want %q", test.name, got, test.want)
+ }
+
+ if test.wantval != "" {
+ gotval := obj.(*types.Const).Val().String()
+ if gotval != test.wantval {
+ t.Errorf("%s: got val %q; want val %q", test.name, gotval, test.wantval)
+ }
+ }
+ }
+
+ if len(test.wantinits) > 0 {
+ initdata := initmap[pkg]
+ found := false
+ // Check that the package's own init function has the package's priority
+ for _, pkginit := range initdata.Inits {
+ if pkginit.InitFunc == test.wantinits[0] {
+ if initdata.Priority != pkginit.Priority {
+ t.Errorf("%s: got self priority %d; want %d", test.pkgpath, pkginit.Priority, initdata.Priority)
+ }
+ found = true
+ break
+ }
+ }
+
+ if !found {
+ t.Errorf("%s: could not find expected function %q", test.pkgpath, test.wantinits[0])
+ }
+
+ // Each init function in the list other than the first one is a
+ // dependency of the function immediately before it. Check that
+ // the init functions appear in descending priority order.
+ priority := initdata.Priority
+ for _, wantdepinit := range test.wantinits[1:] {
+ found = false
+ for _, pkginit := range initdata.Inits {
+ if pkginit.InitFunc == wantdepinit {
+ if priority <= pkginit.Priority {
+ t.Errorf("%s: got dep priority %d; want less than %d", test.pkgpath, pkginit.Priority, priority)
+ }
+ found = true
+ priority = pkginit.Priority
+ break
+ }
+ }
+
+ if !found {
+ t.Errorf("%s: could not find expected function %q", test.pkgpath, wantdepinit)
+ }
+ }
+ }
+}
+
+var importerTests = [...]importerTest{
+ {pkgpath: "pointer", name: "Int8Ptr", want: "type Int8Ptr *int8"},
+ {pkgpath: "complexnums", name: "NN", want: "const NN untyped complex", wantval: "(-1/1 + -1/1i)"},
+ {pkgpath: "complexnums", name: "NP", want: "const NP untyped complex", wantval: "(-1/1 + 1/1i)"},
+ {pkgpath: "complexnums", name: "PN", want: "const PN untyped complex", wantval: "(1/1 + -1/1i)"},
+ {pkgpath: "complexnums", name: "PP", want: "const PP untyped complex", wantval: "(1/1 + 1/1i)"},
+ // TODO: enable this entry once bug has been tracked down
+ //{pkgpath: "imports", wantinits: []string{"imports..import", "fmt..import", "math..import"}},
+}
+
+func TestGoxImporter(t *testing.T) {
+ if runtime.GOOS == "android" {
+ t.Skipf("no testdata directory on %s", runtime.GOOS)
+ }
+ initmap := make(map[*types.Package]InitData)
+ imp := GetImporter([]string{"testdata"}, initmap)
+
+ for _, test := range importerTests {
+ runImporterTest(t, imp, initmap, &test)
+ }
+}
+
+func TestObjImporter(t *testing.T) {
+ // This test relies on gccgo being around, which it most likely will be if we
+ // were compiled with gccgo.
+ if runtime.Compiler != "gccgo" {
+ t.Skip("This test needs gccgo")
+ return
+ }
+
+ tmpdir, err := ioutil.TempDir("", "")
+ if err != nil {
+ t.Fatal(err)
+ }
+ initmap := make(map[*types.Package]InitData)
+ imp := GetImporter([]string{tmpdir}, initmap)
+
+ artmpdir, err := ioutil.TempDir("", "")
+ if err != nil {
+ t.Fatal(err)
+ }
+ arinitmap := make(map[*types.Package]InitData)
+ arimp := GetImporter([]string{artmpdir}, arinitmap)
+
+ for _, test := range importerTests {
+ gofile := filepath.Join("testdata", test.pkgpath+".go")
+ ofile := filepath.Join(tmpdir, test.pkgpath+".o")
+ afile := filepath.Join(artmpdir, "lib"+test.pkgpath+".a")
+
+ cmd := exec.Command("gccgo", "-fgo-pkgpath="+test.pkgpath, "-c", "-o", ofile, gofile)
+ out, err := cmd.CombinedOutput()
+ if err != nil {
+ t.Logf("%s", out)
+ t.Fatalf("gccgo %s failed: %s", gofile, err)
+ }
+
+ runImporterTest(t, imp, initmap, &test)
+
+ cmd = exec.Command("ar", "cr", afile, ofile)
+ out, err = cmd.CombinedOutput()
+ if err != nil {
+ t.Logf("%s", out)
+ t.Fatalf("ar cr %s %s failed: %s", afile, ofile, err)
+ }
+
+ runImporterTest(t, arimp, arinitmap, &test)
+
+ if err = os.Remove(ofile); err != nil {
+ t.Fatal(err)
+ }
+ if err = os.Remove(afile); err != nil {
+ t.Fatal(err)
+ }
+ }
+
+ if err = os.Remove(tmpdir); err != nil {
+ t.Fatal(err)
+ }
+}
diff --git a/go/gccgoimporter/parser.go b/go/gccgoimporter/parser.go
new file mode 100644
index 0000000..d20a967
--- /dev/null
+++ b/go/gccgoimporter/parser.go
@@ -0,0 +1,856 @@
+// 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 gccgoimporter
+
+import (
+ "bytes"
+ "errors"
+ "fmt"
+ "go/token"
+ "io"
+ "strconv"
+ "strings"
+ "text/scanner"
+
+ "golang.org/x/tools/go/exact"
+ "golang.org/x/tools/go/types"
+)
+
+type parser struct {
+ scanner scanner.Scanner
+ tok rune // current token
+ lit string // literal string; only valid for Ident, Int, String tokens
+ pkgpath string // package path of imported package
+ pkgname string // name of imported package
+ pkg *types.Package // reference to imported package
+ imports map[string]*types.Package // package path -> package object
+ typeMap map[int]types.Type // type number -> type
+ initdata InitData // package init priority data
+}
+
+func (p *parser) init(filename string, src io.Reader, imports map[string]*types.Package) {
+ p.scanner.Init(src)
+ p.scanner.Error = func(_ *scanner.Scanner, msg string) { p.error(msg) }
+ p.scanner.Mode = scanner.ScanIdents | scanner.ScanInts | scanner.ScanFloats | scanner.ScanStrings | scanner.ScanComments | scanner.SkipComments
+ p.scanner.Whitespace = 1<<'\t' | 1<<'\n' | 1<<' '
+ p.scanner.Filename = filename // for good error messages
+ p.next()
+ p.imports = imports
+ p.typeMap = make(map[int]types.Type)
+}
+
+type importError struct {
+ pos scanner.Position
+ err error
+}
+
+func (e importError) Error() string {
+ return fmt.Sprintf("import error %s (byte offset = %d): %s", e.pos, e.pos.Offset, e.err)
+}
+
+func (p *parser) error(err interface{}) {
+ if s, ok := err.(string); ok {
+ err = errors.New(s)
+ }
+ // panic with a runtime.Error if err is not an error
+ panic(importError{p.scanner.Pos(), err.(error)})
+}
+
+func (p *parser) errorf(format string, args ...interface{}) {
+ p.error(fmt.Errorf(format, args...))
+}
+
+func (p *parser) expect(tok rune) string {
+ lit := p.lit
+ if p.tok != tok {
+ p.errorf("expected %s, got %s (%s)", scanner.TokenString(tok), scanner.TokenString(p.tok), lit)
+ }
+ p.next()
+ return lit
+}
+
+func (p *parser) expectKeyword(keyword string) {
+ lit := p.expect(scanner.Ident)
+ if lit != keyword {
+ p.errorf("expected keyword %s, got %q", keyword, lit)
+ }
+}
+
+func (p *parser) parseString() string {
+ str, err := strconv.Unquote(p.expect(scanner.String))
+ if err != nil {
+ p.error(err)
+ }
+ return str
+}
+
+// unquotedString = { unquotedStringChar } .
+// unquotedStringChar = <neither a whitespace nor a ';' char> .
+func (p *parser) parseUnquotedString() string {
+ if p.tok == scanner.EOF {
+ p.error("unexpected EOF")
+ }
+ var buf bytes.Buffer
+ buf.WriteString(p.scanner.TokenText())
+ // This loop needs to examine each character before deciding whether to consume it. If we see a semicolon,
+ // we need to let it be consumed by p.next().
+ for ch := p.scanner.Peek(); ch != ';' && ch != scanner.EOF && p.scanner.Whitespace&(1<<uint(ch)) == 0; ch = p.scanner.Peek() {
+ buf.WriteRune(ch)
+ p.scanner.Next()
+ }
+ p.next()
+ return buf.String()
+}
+
+func (p *parser) next() {
+ p.tok = p.scanner.Scan()
+ switch p.tok {
+ case scanner.Ident, scanner.Int, scanner.Float, scanner.String, '·':
+ p.lit = p.scanner.TokenText()
+ default:
+ p.lit = ""
+ }
+}
+
+func (p *parser) parseQualifiedName() (path, name string) {
+ return p.parseQualifiedNameStr(p.parseString())
+}
+
+func (p *parser) parseUnquotedQualifiedName() (path, name string) {
+ return p.parseQualifiedNameStr(p.parseUnquotedString())
+}
+
+// qualifiedName = [ ["."] unquotedString "." ] unquotedString .
+//
+// The above production uses greedy matching.
+func (p *parser) parseQualifiedNameStr(unquotedName string) (pkgpath, name string) {
+ parts := strings.Split(unquotedName, ".")
+ if parts[0] == "" {
+ parts = parts[1:]
+ }
+
+ switch len(parts) {
+ case 0:
+ p.errorf("malformed qualified name: %q", unquotedName)
+ case 1:
+ // unqualified name
+ pkgpath = p.pkgpath
+ name = parts[0]
+ default:
+ // qualified name, which may contain periods
+ pkgpath = strings.Join(parts[0:len(parts)-1], ".")
+ name = parts[len(parts)-1]
+ }
+
+ return
+}
+
+// getPkg returns the package for a given path. If the package is
+// not found but we have a package name, create the package and
+// add it to the p.imports map.
+//
+func (p *parser) getPkg(pkgpath, name string) *types.Package {
+ // package unsafe is not in the imports map - handle explicitly
+ if pkgpath == "unsafe" {
+ return types.Unsafe
+ }
+ pkg := p.imports[pkgpath]
+ if pkg == nil && name != "" {
+ pkg = types.NewPackage(pkgpath, name)
+ p.imports[pkgpath] = pkg
+ }
+ return pkg
+}
+
+// parseExportedName is like parseQualifiedName, but
+// the package path is resolved to an imported *types.Package.
+//
+// ExportedName = string [string] .
+func (p *parser) parseExportedName() (pkg *types.Package, name string) {
+ path, name := p.parseQualifiedName()
+ var pkgname string
+ if p.tok == scanner.String {
+ pkgname = p.parseString()
+ }
+ pkg = p.getPkg(path, pkgname)
+ if pkg == nil {
+ p.errorf("package %s (path = %q) not found", name, path)
+ }
+ return
+}
+
+// Name = QualifiedName | "?" .
+func (p *parser) parseName() string {
+ if p.tok == '?' {
+ // Anonymous.
+ p.next()
+ return ""
+ }
+ // The package path is redundant for us. Don't try to parse it.
+ _, name := p.parseUnquotedQualifiedName()
+ return name
+}
+
+func deref(typ types.Type) types.Type {
+ if p, _ := typ.(*types.Pointer); p != nil {
+ typ = p.Elem()
+ }
+ return typ
+}
+
+// Field = Name Type [string] .
+func (p *parser) parseField(pkg *types.Package) (field *types.Var, tag string) {
+ name := p.parseName()
+ typ := p.parseType(pkg)
+ anon := false
+ if name == "" {
+ anon = true
+ switch typ := deref(typ).(type) {
+ case *types.Basic:
+ name = typ.Name()
+ case *types.Named:
+ name = typ.Obj().Name()
+ default:
+ p.error("anonymous field expected")
+ }
+ }
+ field = types.NewField(token.NoPos, pkg, name, typ, anon)
+ if p.tok == scanner.String {
+ tag = p.parseString()
+ }
+ return
+}
+
+// Param = Name ["..."] Type .
+func (p *parser) parseParam(pkg *types.Package) (param *types.Var, isVariadic bool) {
+ name := p.parseName()
+ if p.tok == '.' {
+ p.next()
+ p.expect('.')
+ p.expect('.')
+ isVariadic = true
+ }
+ typ := p.parseType(pkg)
+ if isVariadic {
+ typ = types.NewSlice(typ)
+ }
+ param = types.NewParam(token.NoPos, pkg, name, typ)
+ return
+}
+
+// Var = Name Type .
+func (p *parser) parseVar(pkg *types.Package) *types.Var {
+ name := p.parseName()
+ return types.NewVar(token.NoPos, pkg, name, p.parseType(pkg))
+}
+
+// ConstValue = string | "false" | "true" | ["-"] (int ["'"] | FloatOrComplex) .
+// FloatOrComplex = float ["i" | ("+"|"-") float "i"] .
+func (p *parser) parseConstValue() (val exact.Value, typ types.Type) {
+ switch p.tok {
+ case scanner.String:
+ str := p.parseString()
+ val = exact.MakeString(str)
+ typ = types.Typ[types.UntypedString]
+ return
+
+ case scanner.Ident:
+ b := false
+ switch p.lit {
+ case "false":
+ case "true":
+ b = true
+
+ default:
+ p.errorf("expected const value, got %s (%q)", scanner.TokenString(p.tok), p.lit)
+ }
+
+ p.next()
+ val = exact.MakeBool(b)
+ typ = types.Typ[types.UntypedBool]
+ return
+ }
+
+ sign := ""
+ if p.tok == '-' {
+ p.next()
+ sign = "-"
+ }
+
+ switch p.tok {
+ case scanner.Int:
+ val = exact.MakeFromLiteral(sign+p.lit, token.INT)
+ if val == nil {
+ p.error("could not parse integer literal")
+ }
+
+ p.next()
+ if p.tok == '\'' {
+ p.next()
+ typ = types.Typ[types.UntypedRune]
+ } else {
+ typ = types.Typ[types.UntypedInt]
+ }
+
+ case scanner.Float:
+ re := sign + p.lit
+ p.next()
+
+ var im string
+ switch p.tok {
+ case '+':
+ p.next()
+ im = p.expect(scanner.Float)
+
+ case '-':
+ p.next()
+ im = "-" + p.expect(scanner.Float)
+
+ case scanner.Ident:
+ // re is in fact the imaginary component. Expect "i" below.
+ im = re
+ re = "0"
+
+ default:
+ val = exact.MakeFromLiteral(re, token.FLOAT)
+ if val == nil {
+ p.error("could not parse float literal")
+ }
+ typ = types.Typ[types.UntypedFloat]
+ return
+ }
+
+ p.expectKeyword("i")
+ reval := exact.MakeFromLiteral(re, token.FLOAT)
+ if reval == nil {
+ p.error("could not parse real component of complex literal")
+ }
+ imval := exact.MakeFromLiteral(im+"i", token.IMAG)
+ if imval == nil {
+ p.error("could not parse imag component of complex literal")
+ }
+ val = exact.BinaryOp(reval, token.ADD, imval)
+ typ = types.Typ[types.UntypedComplex]
+
+ default:
+ p.errorf("expected const value, got %s (%q)", scanner.TokenString(p.tok), p.lit)
+ }
+
+ return
+}
+
+// Const = Name [Type] "=" ConstValue .
+func (p *parser) parseConst(pkg *types.Package) *types.Const {
+ name := p.parseName()
+ var typ types.Type
+ if p.tok == '<' {
+ typ = p.parseType(pkg)
+ }
+ p.expect('=')
+ val, vtyp := p.parseConstValue()
+ if typ == nil {
+ typ = vtyp
+ }
+ return types.NewConst(token.NoPos, pkg, name, typ, val)
+}
+
+// TypeName = ExportedName .
+func (p *parser) parseTypeName() *types.TypeName {
+ pkg, name := p.parseExportedName()
+ scope := pkg.Scope()
+ if obj := scope.Lookup(name); obj != nil {
+ return obj.(*types.TypeName)
+ }
+ obj := types.NewTypeName(token.NoPos, pkg, name, nil)
+ // a named type may be referred to before the underlying type
+ // is known - set it up
+ types.NewNamed(obj, nil, nil)
+ scope.Insert(obj)
+ return obj
+}
+
+// NamedType = TypeName Type { Method } .
+// Method = "func" "(" Param ")" Name ParamList ResultList ";" .
+func (p *parser) parseNamedType(n int) types.Type {
+ obj := p.parseTypeName()
+
+ pkg := obj.Pkg()
+ typ := obj.Type()
+ p.typeMap[n] = typ
+
+ nt, ok := typ.(*types.Named)
+ if !ok {
+ // This can happen for unsafe.Pointer, which is a TypeName holding a Basic type.
+ pt := p.parseType(pkg)
+ if pt != typ {
+ p.error("unexpected underlying type for non-named TypeName")
+ }
+ return typ
+ }
+
+ underlying := p.parseType(pkg)
+ if nt.Underlying() == nil {
+ nt.SetUnderlying(underlying.Underlying())
+ }
+
+ for p.tok == scanner.Ident {
+ // collect associated methods
+ p.expectKeyword("func")
+ p.expect('(')
+ receiver, _ := p.parseParam(pkg)
+ p.expect(')')
+ name := p.parseName()
+ params, isVariadic := p.parseParamList(pkg)
+ results := p.parseResultList(pkg)
+ p.expect(';')
+
+ sig := types.NewSignature(receiver, params, results, isVariadic)
+ nt.AddMethod(types.NewFunc(token.NoPos, pkg, name, sig))
+ }
+
+ return nt
+}
+
+func (p *parser) parseInt() int64 {
+ lit := p.expect(scanner.Int)
+ n, err := strconv.ParseInt(lit, 10, 0)
+ if err != nil {
+ p.error(err)
+ }
+ return n
+}
+
+// ArrayOrSliceType = "[" [ int ] "]" Type .
+func (p *parser) parseArrayOrSliceType(pkg *types.Package) types.Type {
+ p.expect('[')
+ if p.tok == ']' {
+ p.next()
+ return types.NewSlice(p.parseType(pkg))
+ }
+
+ n := p.parseInt()
+ p.expect(']')
+ return types.NewArray(p.parseType(pkg), n)
+}
+
+// MapType = "map" "[" Type "]" Type .
+func (p *parser) parseMapType(pkg *types.Package) types.Type {
+ p.expectKeyword("map")
+ p.expect('[')
+ key := p.parseType(pkg)
+ p.expect(']')
+ elem := p.parseType(pkg)
+ return types.NewMap(key, elem)
+}
+
+// ChanType = "chan" ["<-" | "-<"] Type .
+func (p *parser) parseChanType(pkg *types.Package) types.Type {
+ p.expectKeyword("chan")
+ dir := types.SendRecv
+ switch p.tok {
+ case '-':
+ p.next()
+ p.expect('<')
+ dir = types.SendOnly
+
+ case '<':
+ // don't consume '<' if it belongs to Type
+ if p.scanner.Peek() == '-' {
+ p.next()
+ p.expect('-')
+ dir = types.RecvOnly
+ }
+ }
+
+ return types.NewChan(dir, p.parseType(pkg))
+}
+
+// StructType = "struct" "{" { Field } "}" .
+func (p *parser) parseStructType(pkg *types.Package) types.Type {
+ p.expectKeyword("struct")
+
+ var fields []*types.Var
+ var tags []string
+
+ p.expect('{')
+ for p.tok != '}' && p.tok != scanner.EOF {
+ field, tag := p.parseField(pkg)
+ p.expect(';')
+ fields = append(fields, field)
+ tags = append(tags, tag)
+ }
+ p.expect('}')
+
+ return types.NewStruct(fields, tags)
+}
+
+// ParamList = "(" [ { Parameter "," } Parameter ] ")" .
+func (p *parser) parseParamList(pkg *types.Package) (*types.Tuple, bool) {
+ var list []*types.Var
+ isVariadic := false
+
+ p.expect('(')
+ for p.tok != ')' && p.tok != scanner.EOF {
+ if len(list) > 0 {
+ p.expect(',')
+ }
+ par, variadic := p.parseParam(pkg)
+ list = append(list, par)
+ if variadic {
+ if isVariadic {
+ p.error("... not on final argument")
+ }
+ isVariadic = true
+ }
+ }
+ p.expect(')')
+
+ return types.NewTuple(list...), isVariadic
+}
+
+// ResultList = Type | ParamList .
+func (p *parser) parseResultList(pkg *types.Package) *types.Tuple {
+ switch p.tok {
+ case '<':
+ return types.NewTuple(types.NewParam(token.NoPos, pkg, "", p.parseType(pkg)))
+
+ case '(':
+ params, _ := p.parseParamList(pkg)
+ return params
+
+ default:
+ return nil
+ }
+}
+
+// FunctionType = ParamList ResultList .
+func (p *parser) parseFunctionType(pkg *types.Package) *types.Signature {
+ params, isVariadic := p.parseParamList(pkg)
+ results := p.parseResultList(pkg)
+ return types.NewSignature(nil, params, results, isVariadic)
+}
+
+// Func = Name FunctionType .
+func (p *parser) parseFunc(pkg *types.Package) *types.Func {
+ name := p.parseName()
+ if strings.ContainsRune(name, '$') {
+ // This is a Type$equal or Type$hash function, which we don't want to parse,
+ // except for the types.
+ p.discardDirectiveWhileParsingTypes(pkg)
+ return nil
+ }
+ return types.NewFunc(token.NoPos, pkg, name, p.parseFunctionType(pkg))
+}
+
+// InterfaceType = "interface" "{" { ("?" Type | Func) ";" } "}" .
+func (p *parser) parseInterfaceType(pkg *types.Package) types.Type {
+ p.expectKeyword("interface")
+
+ var methods []*types.Func
+ var typs []*types.Named
+
+ p.expect('{')
+ for p.tok != '}' && p.tok != scanner.EOF {
+ if p.tok == '?' {
+ p.next()
+ typs = append(typs, p.parseType(pkg).(*types.Named))
+ } else {
+ method := p.parseFunc(pkg)
+ methods = append(methods, method)
+ }
+ p.expect(';')
+ }
+ p.expect('}')
+
+ return types.NewInterface(methods, typs)
+}
+
+// PointerType = "*" ("any" | Type) .
+func (p *parser) parsePointerType(pkg *types.Package) types.Type {
+ p.expect('*')
+ if p.tok == scanner.Ident {
+ p.expectKeyword("any")
+ return types.Typ[types.UnsafePointer]
+ }
+ return types.NewPointer(p.parseType(pkg))
+}
+
+// TypeDefinition = NamedType | MapType | ChanType | StructType | InterfaceType | PointerType | ArrayOrSliceType | FunctionType .
+func (p *parser) parseTypeDefinition(pkg *types.Package, n int) types.Type {
+ var t types.Type
+ switch p.tok {
+ case scanner.String:
+ t = p.parseNamedType(n)
+
+ case scanner.Ident:
+ switch p.lit {
+ case "map":
+ t = p.parseMapType(pkg)
+
+ case "chan":
+ t = p.parseChanType(pkg)
+
+ case "struct":
+ t = p.parseStructType(pkg)
+
+ case "interface":
+ t = p.parseInterfaceType(pkg)
+ }
+
+ case '*':
+ t = p.parsePointerType(pkg)
+
+ case '[':
+ t = p.parseArrayOrSliceType(pkg)
+
+ case '(':
+ t = p.parseFunctionType(pkg)
+ }
+
+ p.typeMap[n] = t
+ return t
+}
+
+const (
+ // From gofrontend/go/export.h
+ // Note that these values are negative in the gofrontend and have been made positive
+ // in the gccgoimporter.
+ gccgoBuiltinINT8 = 1
+ gccgoBuiltinINT16 = 2
+ gccgoBuiltinINT32 = 3
+ gccgoBuiltinINT64 = 4
+ gccgoBuiltinUINT8 = 5
+ gccgoBuiltinUINT16 = 6
+ gccgoBuiltinUINT32 = 7
+ gccgoBuiltinUINT64 = 8
+ gccgoBuiltinFLOAT32 = 9
+ gccgoBuiltinFLOAT64 = 10
+ gccgoBuiltinINT = 11
+ gccgoBuiltinUINT = 12
+ gccgoBuiltinUINTPTR = 13
+ gccgoBuiltinBOOL = 15
+ gccgoBuiltinSTRING = 16
+ gccgoBuiltinCOMPLEX64 = 17
+ gccgoBuiltinCOMPLEX128 = 18
+ gccgoBuiltinERROR = 19
+ gccgoBuiltinBYTE = 20
+ gccgoBuiltinRUNE = 21
+)
+
+func lookupBuiltinType(typ int) types.Type {
+ return [...]types.Type{
+ gccgoBuiltinINT8: types.Typ[types.Int8],
+ gccgoBuiltinINT16: types.Typ[types.Int16],
+ gccgoBuiltinINT32: types.Typ[types.Int32],
+ gccgoBuiltinINT64: types.Typ[types.Int64],
+ gccgoBuiltinUINT8: types.Typ[types.Uint8],
+ gccgoBuiltinUINT16: types.Typ[types.Uint16],
+ gccgoBuiltinUINT32: types.Typ[types.Uint32],
+ gccgoBuiltinUINT64: types.Typ[types.Uint64],
+ gccgoBuiltinFLOAT32: types.Typ[types.Float32],
+ gccgoBuiltinFLOAT64: types.Typ[types.Float64],
+ gccgoBuiltinINT: types.Typ[types.Int],
+ gccgoBuiltinUINT: types.Typ[types.Uint],
+ gccgoBuiltinUINTPTR: types.Typ[types.Uintptr],
+ gccgoBuiltinBOOL: types.Typ[types.Bool],
+ gccgoBuiltinSTRING: types.Typ[types.String],
+ gccgoBuiltinCOMPLEX64: types.Typ[types.Complex64],
+ gccgoBuiltinCOMPLEX128: types.Typ[types.Complex128],
+ gccgoBuiltinERROR: types.Universe.Lookup("error").Type(),
+ gccgoBuiltinBYTE: types.Universe.Lookup("byte").Type(),
+ gccgoBuiltinRUNE: types.Universe.Lookup("rune").Type(),
+ }[typ]
+}
+
+// Type = "<" "type" ( "-" int | int [ TypeDefinition ] ) ">" .
+func (p *parser) parseType(pkg *types.Package) (t types.Type) {
+ p.expect('<')
+ p.expectKeyword("type")
+
+ switch p.tok {
+ case scanner.Int:
+ n := p.parseInt()
+
+ if p.tok == '>' {
+ t = p.typeMap[int(n)]
+ } else {
+ t = p.parseTypeDefinition(pkg, int(n))
+ }
+
+ case '-':
+ p.next()
+ n := p.parseInt()
+ t = lookupBuiltinType(int(n))
+
+ default:
+ p.errorf("expected type number, got %s (%q)", scanner.TokenString(p.tok), p.lit)
+ return nil
+ }
+
+ p.expect('>')
+ return
+}
+
+// PackageInit = unquotedString unquotedString int .
+func (p *parser) parsePackageInit() PackageInit {
+ name := p.parseUnquotedString()
+ initfunc := p.parseUnquotedString()
+ priority := int(p.parseInt())
+ return PackageInit{Name: name, InitFunc: initfunc, Priority: priority}
+}
+
+// Throw away tokens until we see a ';'. If we see a '<', attempt to parse as a type.
+func (p *parser) discardDirectiveWhileParsingTypes(pkg *types.Package) {
+ for {
+ switch p.tok {
+ case ';':
+ return
+ case '<':
+ p.parseType(p.pkg)
+ case scanner.EOF:
+ p.error("unexpected EOF")
+ default:
+ p.next()
+ }
+ }
+}
+
+// Create the package if we have parsed both the package path and package name.
+func (p *parser) maybeCreatePackage() {
+ if p.pkgname != "" && p.pkgpath != "" {
+ p.pkg = p.getPkg(p.pkgpath, p.pkgname)
+ }
+}
+
+// InitDataDirective = "v1" ";" |
+// "priority" int ";" |
+// "init" { PackageInit } ";" |
+// "checksum" unquotedString ";" .
+func (p *parser) parseInitDataDirective() {
+ if p.tok != scanner.Ident {
+ // unexpected token kind; panic
+ p.expect(scanner.Ident)
+ }
+
+ switch p.lit {
+ case "v1":
+ p.next()
+ p.expect(';')
+
+ case "priority":
+ p.next()
+ p.initdata.Priority = int(p.parseInt())
+ p.expect(';')
+
+ case "init":
+ p.next()
+ for p.tok != ';' && p.tok != scanner.EOF {
+ p.initdata.Inits = append(p.initdata.Inits, p.parsePackageInit())
+ }
+ p.expect(';')
+
+ case "checksum":
+ // Don't let the scanner try to parse the checksum as a number.
+ defer func(mode uint) {
+ p.scanner.Mode = mode
+ }(p.scanner.Mode)
+ p.scanner.Mode &^= scanner.ScanInts | scanner.ScanFloats
+ p.next()
+ p.parseUnquotedString()
+ p.expect(';')
+
+ default:
+ p.errorf("unexpected identifier: %q", p.lit)
+ }
+}
+
+// Directive = InitDataDirective |
+// "package" unquotedString ";" |
+// "pkgpath" unquotedString ";" |
+// "import" unquotedString unquotedString string ";" |
+// "func" Func ";" |
+// "type" Type ";" |
+// "var" Var ";" |
+// "const" Const ";" .
+func (p *parser) parseDirective() {
+ if p.tok != scanner.Ident {
+ // unexpected token kind; panic
+ p.expect(scanner.Ident)
+ }
+
+ switch p.lit {
+ case "v1", "priority", "init", "checksum":
+ p.parseInitDataDirective()
+
+ case "package":
+ p.next()
+ p.pkgname = p.parseUnquotedString()
+ p.maybeCreatePackage()
+ p.expect(';')
+
+ case "pkgpath":
+ p.next()
+ p.pkgpath = p.parseUnquotedString()
+ p.maybeCreatePackage()
+ p.expect(';')
+
+ case "import":
+ p.next()
+ pkgname := p.parseUnquotedString()
+ pkgpath := p.parseUnquotedString()
+ p.getPkg(pkgpath, pkgname)
+ p.parseString()
+ p.expect(';')
+
+ case "func":
+ p.next()
+ fun := p.parseFunc(p.pkg)
+ if fun != nil {
+ p.pkg.Scope().Insert(fun)
+ }
+ p.expect(';')
+
+ case "type":
+ p.next()
+ p.parseType(p.pkg)
+ p.expect(';')
+
+ case "var":
+ p.next()
+ v := p.parseVar(p.pkg)
+ p.pkg.Scope().Insert(v)
+ p.expect(';')
+
+ case "const":
+ p.next()
+ c := p.parseConst(p.pkg)
+ p.pkg.Scope().Insert(c)
+ p.expect(';')
+
+ default:
+ p.errorf("unexpected identifier: %q", p.lit)
+ }
+}
+
+// Package = { Directive } .
+func (p *parser) parsePackage() *types.Package {
+ for p.tok != scanner.EOF {
+ p.parseDirective()
+ }
+ for _, typ := range p.typeMap {
+ if it, ok := typ.(*types.Interface); ok {
+ it.Complete()
+ }
+ }
+ p.pkg.MarkComplete()
+ return p.pkg
+}
+
+// InitData = { InitDataDirective } .
+func (p *parser) parseInitData() {
+ for p.tok != scanner.EOF {
+ p.parseInitDataDirective()
+ }
+}
diff --git a/go/gccgoimporter/parser_test.go b/go/gccgoimporter/parser_test.go
new file mode 100644
index 0000000..1f0f12a
--- /dev/null
+++ b/go/gccgoimporter/parser_test.go
@@ -0,0 +1,73 @@
+// 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 gccgoimporter
+
+import (
+ "bytes"
+ "strings"
+ "testing"
+ "text/scanner"
+
+ "golang.org/x/tools/go/types"
+)
+
+var typeParserTests = []struct {
+ id, typ, want, underlying, methods string
+}{
+ {id: "foo", typ: "<type -1>", want: "int8"},
+ {id: "foo", typ: "<type 1 *<type -19>>", want: "*error"},
+ {id: "foo", typ: "<type 1 *any>", want: "unsafe.Pointer"},
+ {id: "foo", typ: "<type 1 \"Bar\" <type 2 *<type 1>>>", want: "foo.Bar", underlying: "*foo.Bar"},
+ {id: "foo", typ: "<type 1 \"bar.Foo\" \"bar\" <type -1> func (? <type 1>) M (); >", want: "bar.Foo", underlying: "int8", methods: "func (bar.Foo).M()"},
+ {id: "foo", typ: "<type 1 \".bar.foo\" \"bar\" <type -1>>", want: "bar.foo", underlying: "int8"},
+ {id: "foo", typ: "<type 1 []<type -1>>", want: "[]int8"},
+ {id: "foo", typ: "<type 1 [42]<type -1>>", want: "[42]int8"},
+ {id: "foo", typ: "<type 1 map [<type -1>] <type -2>>", want: "map[int8]int16"},
+ {id: "foo", typ: "<type 1 chan <type -1>>", want: "chan int8"},
+ {id: "foo", typ: "<type 1 chan <- <type -1>>", want: "<-chan int8"},
+ {id: "foo", typ: "<type 1 chan -< <type -1>>", want: "chan<- int8"},
+ {id: "foo", typ: "<type 1 struct { I8 <type -1>; I16 <type -2> \"i16\"; }>", want: "struct{I8 int8; I16 int16 \"i16\"}"},
+ {id: "foo", typ: "<type 1 interface { Foo (a <type -1>, b <type -2>) <type -1>; Bar (? <type -2>, ? ...<type -1>) (? <type -2>, ? <type -1>); Baz (); }>", want: "interface{Bar(int16, ...int8) (int16, int8); Baz(); Foo(a int8, b int16) int8}"},
+ {id: "foo", typ: "<type 1 (? <type -1>) <type -2>>", want: "func(int8) int16"},
+}
+
+func TestTypeParser(t *testing.T) {
+ for _, test := range typeParserTests {
+ var p parser
+ p.init("test.gox", strings.NewReader(test.typ), make(map[string]*types.Package))
+ p.pkgname = test.id
+ p.pkgpath = test.id
+ p.maybeCreatePackage()
+ typ := p.parseType(p.pkg)
+
+ if p.tok != scanner.EOF {
+ t.Errorf("expected full parse, stopped at %q", p.lit)
+ }
+
+ got := typ.String()
+ if got != test.want {
+ t.Errorf("got type %q, expected %q", got, test.want)
+ }
+
+ if test.underlying != "" {
+ underlying := typ.Underlying().String()
+ if underlying != test.underlying {
+ t.Errorf("got underlying type %q, expected %q", underlying, test.underlying)
+ }
+ }
+
+ if test.methods != "" {
+ nt := typ.(*types.Named)
+ var buf bytes.Buffer
+ for i := 0; i != nt.NumMethods(); i++ {
+ buf.WriteString(nt.Method(i).String())
+ }
+ methods := buf.String()
+ if methods != test.methods {
+ t.Errorf("got methods %q, expected %q", methods, test.methods)
+ }
+ }
+ }
+}
diff --git a/go/gccgoimporter/testdata/complexnums.go b/go/gccgoimporter/testdata/complexnums.go
new file mode 100644
index 0000000..a51b6b0
--- /dev/null
+++ b/go/gccgoimporter/testdata/complexnums.go
@@ -0,0 +1,6 @@
+package complexnums
+
+const NN = -1 - 1i
+const NP = -1 + 1i
+const PN = 1 - 1i
+const PP = 1 + 1i
diff --git a/go/gccgoimporter/testdata/complexnums.gox b/go/gccgoimporter/testdata/complexnums.gox
new file mode 100644
index 0000000..b66524f
--- /dev/null
+++ b/go/gccgoimporter/testdata/complexnums.gox
@@ -0,0 +1,8 @@
+v1;
+package complexnums;
+pkgpath complexnums;
+priority 1;
+const NN = -0.1E1-0.1E1i ;
+const NP = -0.1E1+0.1E1i ;
+const PN = 0.1E1-0.1E1i ;
+const PP = 0.1E1+0.1E1i ;
diff --git a/go/gccgoimporter/testdata/imports.go b/go/gccgoimporter/testdata/imports.go
new file mode 100644
index 0000000..7907316
--- /dev/null
+++ b/go/gccgoimporter/testdata/imports.go
@@ -0,0 +1,5 @@
+package imports
+
+import "fmt"
+
+var Hello = fmt.Sprintf("Hello, world")
diff --git a/go/gccgoimporter/testdata/imports.gox b/go/gccgoimporter/testdata/imports.gox
new file mode 100644
index 0000000..958a4f5
--- /dev/null
+++ b/go/gccgoimporter/testdata/imports.gox
@@ -0,0 +1,7 @@
+v1;
+package imports;
+pkgpath imports;
+priority 7;
+import fmt fmt "fmt";
+init imports imports..import 7 math math..import 1 runtime runtime..import 1 strconv strconv..import 2 io io..import 3 reflect reflect..import 3 syscall syscall..import 3 time time..import 4 os os..import 5 fmt fmt..import 6;
+var Hello <type -16>;
diff --git a/go/gccgoimporter/testdata/pointer.go b/go/gccgoimporter/testdata/pointer.go
new file mode 100644
index 0000000..4ebc671
--- /dev/null
+++ b/go/gccgoimporter/testdata/pointer.go
@@ -0,0 +1,3 @@
+package pointer
+
+type Int8Ptr *int8
diff --git a/go/gccgoimporter/testdata/pointer.gox b/go/gccgoimporter/testdata/pointer.gox
new file mode 100644
index 0000000..d96ebbd
--- /dev/null
+++ b/go/gccgoimporter/testdata/pointer.gox
@@ -0,0 +1,4 @@
+v1;
+package pointer;
+pkgpath pointer;
+type <type 1 "Int8Ptr" <type 2 *<type -1>>>;
diff --git a/go/gcimporter/exportdata.go b/go/gcimporter/exportdata.go
new file mode 100644
index 0000000..657742b
--- /dev/null
+++ b/go/gcimporter/exportdata.go
@@ -0,0 +1,108 @@
+// 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 file implements FindExportData.
+
+package gcimporter
+
+import (
+ "bufio"
+ "errors"
+ "fmt"
+ "io"
+ "strconv"
+ "strings"
+)
+
+func readGopackHeader(r *bufio.Reader) (name string, size int, err error) {
+ // See $GOROOT/include/ar.h.
+ hdr := make([]byte, 16+12+6+6+8+10+2)
+ _, err = io.ReadFull(r, hdr)
+ if err != nil {
+ return
+ }
+ // leave for debugging
+ if false {
+ fmt.Printf("header: %s", hdr)
+ }
+ s := strings.TrimSpace(string(hdr[16+12+6+6+8:][:10]))
+ size, err = strconv.Atoi(s)
+ if err != nil || hdr[len(hdr)-2] != '`' || hdr[len(hdr)-1] != '\n' {
+ err = errors.New("invalid archive header")
+ return
+ }
+ name = strings.TrimSpace(string(hdr[:16]))
+ return
+}
+
+// FindExportData positions the reader r at the beginning of the
+// export data section of an underlying GC-created object/archive
+// file by reading from it. The reader must be positioned at the
+// start of the file before calling this function.
+//
+func FindExportData(r *bufio.Reader) (err error) {
+ // Read first line to make sure this is an object file.
+ line, err := r.ReadSlice('\n')
+ if err != nil {
+ return
+ }
+ if string(line) == "!<arch>\n" {
+ // Archive file. Scan to __.PKGDEF.
+ var name string
+ var size int
+ if name, size, err = readGopackHeader(r); err != nil {
+ return
+ }
+
+ // Optional leading __.GOSYMDEF or __.SYMDEF.
+ // Read and discard.
+ if name == "__.SYMDEF" || name == "__.GOSYMDEF" {
+ const block = 4096
+ tmp := make([]byte, block)
+ for size > 0 {
+ n := size
+ if n > block {
+ n = block
+ }
+ if _, err = io.ReadFull(r, tmp[:n]); err != nil {
+ return
+ }
+ size -= n
+ }
+
+ if name, size, err = readGopackHeader(r); err != nil {
+ return
+ }
+ }
+
+ // First real entry should be __.PKGDEF.
+ if name != "__.PKGDEF" {
+ err = errors.New("go archive is missing __.PKGDEF")
+ return
+ }
+
+ // Read first line of __.PKGDEF data, so that line
+ // is once again the first line of the input.
+ if line, err = r.ReadSlice('\n'); err != nil {
+ return
+ }
+ }
+
+ // Now at __.PKGDEF in archive or still at beginning of file.
+ // Either way, line should begin with "go object ".
+ if !strings.HasPrefix(string(line), "go object ") {
+ err = errors.New("not a go object file")
+ return
+ }
+
+ // Skip over object header to export data.
+ // Begins after first line with $$.
+ for line[0] != '$' {
+ if line, err = r.ReadSlice('\n'); err != nil {
+ return
+ }
+ }
+
+ return
+}
diff --git a/go/gcimporter/gcimporter.go b/go/gcimporter/gcimporter.go
new file mode 100644
index 0000000..031e870
--- /dev/null
+++ b/go/gcimporter/gcimporter.go
@@ -0,0 +1,995 @@
+// 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 gcimporter implements Import for gc-generated object files.
+// Importing this package installs Import as go/types.DefaultImport.
+package gcimporter // import "golang.org/x/tools/go/gcimporter"
+
+import (
+ "bufio"
+ "errors"
+ "fmt"
+ "go/build"
+ "go/token"
+ "io"
+ "os"
+ "path/filepath"
+ "sort"
+ "strconv"
+ "strings"
+ "text/scanner"
+
+ "golang.org/x/tools/go/exact"
+ "golang.org/x/tools/go/types"
+)
+
+// debugging/development support
+const debug = false
+
+func init() {
+ types.DefaultImport = Import
+}
+
+var pkgExts = [...]string{".a", ".5", ".6", ".7", ".8", ".9"}
+
+// FindPkg returns the filename and unique package id for an import
+// path based on package information provided by build.Import (using
+// the build.Default build.Context).
+// If no file was found, an empty filename is returned.
+//
+func FindPkg(path, srcDir string) (filename, id string) {
+ if len(path) == 0 {
+ return
+ }
+
+ id = path
+ var noext string
+ switch {
+ default:
+ // "x" -> "$GOPATH/pkg/$GOOS_$GOARCH/x.ext", "x"
+ // Don't require the source files to be present.
+ bp, _ := build.Import(path, srcDir, build.FindOnly|build.AllowBinary)
+ if bp.PkgObj == "" {
+ return
+ }
+ noext = strings.TrimSuffix(bp.PkgObj, ".a")
+
+ case build.IsLocalImport(path):
+ // "./x" -> "/this/directory/x.ext", "/this/directory/x"
+ noext = filepath.Join(srcDir, path)
+ id = noext
+
+ case filepath.IsAbs(path):
+ // for completeness only - go/build.Import
+ // does not support absolute imports
+ // "/x" -> "/x.ext", "/x"
+ noext = path
+ }
+
+ // try extensions
+ for _, ext := range pkgExts {
+ filename = noext + ext
+ if f, err := os.Stat(filename); err == nil && !f.IsDir() {
+ return
+ }
+ }
+
+ filename = "" // not found
+ return
+}
+
+// ImportData imports a package by reading the gc-generated export data,
+// adds the corresponding package object to the packages map indexed by id,
+// and returns the object.
+//
+// The packages map must contains all packages already imported. The data
+// reader position must be the beginning of the export data section. The
+// filename is only used in error messages.
+//
+// If packages[id] contains the completely imported package, that package
+// can be used directly, and there is no need to call this function (but
+// there is also no harm but for extra time used).
+//
+func ImportData(packages map[string]*types.Package, filename, id string, data io.Reader) (pkg *types.Package, err error) {
+ // support for parser error handling
+ defer func() {
+ switch r := recover().(type) {
+ case nil:
+ // nothing to do
+ case importError:
+ err = r
+ default:
+ panic(r) // internal error
+ }
+ }()
+
+ var p parser
+ p.init(filename, id, data, packages)
+ pkg = p.parseExport()
+
+ return
+}
+
+// Import imports a gc-generated package given its import path, adds the
+// corresponding package object to the packages map, and returns the object.
+// Local import paths are interpreted relative to the current working directory.
+// The packages map must contains all packages already imported.
+//
+func Import(packages map[string]*types.Package, path string) (pkg *types.Package, err error) {
+ if path == "unsafe" {
+ return types.Unsafe, nil
+ }
+
+ srcDir := "."
+ if build.IsLocalImport(path) {
+ srcDir, err = os.Getwd()
+ if err != nil {
+ return
+ }
+ }
+
+ filename, id := FindPkg(path, srcDir)
+ if filename == "" {
+ err = fmt.Errorf("can't find import: %s", id)
+ return
+ }
+
+ // no need to re-import if the package was imported completely before
+ if pkg = packages[id]; pkg != nil && pkg.Complete() {
+ return
+ }
+
+ // open file
+ f, err := os.Open(filename)
+ if err != nil {
+ return
+ }
+ defer func() {
+ f.Close()
+ if err != nil {
+ // add file name to error
+ err = fmt.Errorf("reading export data: %s: %v", filename, err)
+ }
+ }()
+
+ buf := bufio.NewReader(f)
+ if err = FindExportData(buf); err != nil {
+ return
+ }
+
+ pkg, err = ImportData(packages, filename, id, buf)
+
+ return
+}
+
+// ----------------------------------------------------------------------------
+// Parser
+
+// TODO(gri) Imported objects don't have position information.
+// Ideally use the debug table line info; alternatively
+// create some fake position (or the position of the
+// import). That way error messages referring to imported
+// objects can print meaningful information.
+
+// parser parses the exports inside a gc compiler-produced
+// object/archive file and populates its scope with the results.
+type parser struct {
+ scanner scanner.Scanner
+ tok rune // current token
+ lit string // literal string; only valid for Ident, Int, String tokens
+ id string // package id of imported package
+ sharedPkgs map[string]*types.Package // package id -> package object (across importer)
+ localPkgs map[string]*types.Package // package id -> package object (just this package)
+}
+
+func (p *parser) init(filename, id string, src io.Reader, packages map[string]*types.Package) {
+ p.scanner.Init(src)
+ p.scanner.Error = func(_ *scanner.Scanner, msg string) { p.error(msg) }
+ p.scanner.Mode = scanner.ScanIdents | scanner.ScanInts | scanner.ScanChars | scanner.ScanStrings | scanner.ScanComments | scanner.SkipComments
+ p.scanner.Whitespace = 1<<'\t' | 1<<' '
+ p.scanner.Filename = filename // for good error messages
+ p.next()
+ p.id = id
+ p.sharedPkgs = packages
+ if debug {
+ // check consistency of packages map
+ for _, pkg := range packages {
+ if pkg.Name() == "" {
+ fmt.Printf("no package name for %s\n", pkg.Path())
+ }
+ }
+ }
+}
+
+func (p *parser) next() {
+ p.tok = p.scanner.Scan()
+ switch p.tok {
+ case scanner.Ident, scanner.Int, scanner.Char, scanner.String, '·':
+ p.lit = p.scanner.TokenText()
+ default:
+ p.lit = ""
+ }
+ if debug {
+ fmt.Printf("%s: %q -> %q\n", scanner.TokenString(p.tok), p.scanner.TokenText(), p.lit)
+ }
+}
+
+func declTypeName(pkg *types.Package, name string) *types.TypeName {
+ scope := pkg.Scope()
+ if obj := scope.Lookup(name); obj != nil {
+ return obj.(*types.TypeName)
+ }
+ obj := types.NewTypeName(token.NoPos, pkg, name, nil)
+ // a named type may be referred to before the underlying type
+ // is known - set it up
+ types.NewNamed(obj, nil, nil)
+ scope.Insert(obj)
+ return obj
+}
+
+// ----------------------------------------------------------------------------
+// Error handling
+
+// Internal errors are boxed as importErrors.
+type importError struct {
+ pos scanner.Position
+ err error
+}
+
+func (e importError) Error() string {
+ return fmt.Sprintf("import error %s (byte offset = %d): %s", e.pos, e.pos.Offset, e.err)
+}
+
+func (p *parser) error(err interface{}) {
+ if s, ok := err.(string); ok {
+ err = errors.New(s)
+ }
+ // panic with a runtime.Error if err is not an error
+ panic(importError{p.scanner.Pos(), err.(error)})
+}
+
+func (p *parser) errorf(format string, args ...interface{}) {
+ p.error(fmt.Sprintf(format, args...))
+}
+
+func (p *parser) expect(tok rune) string {
+ lit := p.lit
+ if p.tok != tok {
+ p.errorf("expected %s, got %s (%s)", scanner.TokenString(tok), scanner.TokenString(p.tok), lit)
+ }
+ p.next()
+ return lit
+}
+
+func (p *parser) expectSpecial(tok string) {
+ sep := 'x' // not white space
+ i := 0
+ for i < len(tok) && p.tok == rune(tok[i]) && sep > ' ' {
+ sep = p.scanner.Peek() // if sep <= ' ', there is white space before the next token
+ p.next()
+ i++
+ }
+ if i < len(tok) {
+ p.errorf("expected %q, got %q", tok, tok[0:i])
+ }
+}
+
+func (p *parser) expectKeyword(keyword string) {
+ lit := p.expect(scanner.Ident)
+ if lit != keyword {
+ p.errorf("expected keyword %s, got %q", keyword, lit)
+ }
+}
+
+// ----------------------------------------------------------------------------
+// Qualified and unqualified names
+
+// PackageId = string_lit .
+//
+func (p *parser) parsePackageId() string {
+ id, err := strconv.Unquote(p.expect(scanner.String))
+ if err != nil {
+ p.error(err)
+ }
+ // id == "" stands for the imported package id
+ // (only known at time of package installation)
+ if id == "" {
+ id = p.id
+ }
+ return id
+}
+
+// PackageName = ident .
+//
+func (p *parser) parsePackageName() string {
+ return p.expect(scanner.Ident)
+}
+
+// dotIdentifier = ( ident | '·' ) { ident | int | '·' } .
+func (p *parser) parseDotIdent() string {
+ ident := ""
+ if p.tok != scanner.Int {
+ sep := 'x' // not white space
+ for (p.tok == scanner.Ident || p.tok == scanner.Int || p.tok == '·') && sep > ' ' {
+ ident += p.lit
+ sep = p.scanner.Peek() // if sep <= ' ', there is white space before the next token
+ p.next()
+ }
+ }
+ if ident == "" {
+ p.expect(scanner.Ident) // use expect() for error handling
+ }
+ return ident
+}
+
+// QualifiedName = "@" PackageId "." ( "?" | dotIdentifier ) .
+//
+func (p *parser) parseQualifiedName() (id, name string) {
+ p.expect('@')
+ id = p.parsePackageId()
+ p.expect('.')
+ // Per rev f280b8a485fd (10/2/2013), qualified names may be used for anonymous fields.
+ if p.tok == '?' {
+ p.next()
+ } else {
+ name = p.parseDotIdent()
+ }
+ return
+}
+
+// getPkg returns the package for a given id. If the package is
+// not found but we have a package name, create the package and
+// add it to the p.localPkgs and p.sharedPkgs maps.
+//
+// id identifies a package, usually by a canonical package path like
+// "encoding/json" but possibly by a non-canonical import path like
+// "./json".
+//
+func (p *parser) getPkg(id, name string) *types.Package {
+ // package unsafe is not in the packages maps - handle explicitly
+ if id == "unsafe" {
+ return types.Unsafe
+ }
+
+ pkg := p.localPkgs[id]
+ if pkg == nil && name != "" {
+ // first import of id from this package
+ pkg = p.sharedPkgs[id]
+ if pkg == nil {
+ // first import of id by this importer
+ pkg = types.NewPackage(id, name)
+ p.sharedPkgs[id] = pkg
+ }
+
+ if p.localPkgs == nil {
+ p.localPkgs = make(map[string]*types.Package)
+ }
+ p.localPkgs[id] = pkg
+ }
+ return pkg
+}
+
+// parseExportedName is like parseQualifiedName, but
+// the package id is resolved to an imported *types.Package.
+//
+func (p *parser) parseExportedName() (pkg *types.Package, name string) {
+ id, name := p.parseQualifiedName()
+ pkg = p.getPkg(id, "")
+ if pkg == nil {
+ p.errorf("%s package not found", id)
+ }
+ return
+}
+
+// ----------------------------------------------------------------------------
+// Types
+
+// BasicType = identifier .
+//
+func (p *parser) parseBasicType() types.Type {
+ id := p.expect(scanner.Ident)
+ obj := types.Universe.Lookup(id)
+ if obj, ok := obj.(*types.TypeName); ok {
+ return obj.Type()
+ }
+ p.errorf("not a basic type: %s", id)
+ return nil
+}
+
+// ArrayType = "[" int_lit "]" Type .
+//
+func (p *parser) parseArrayType() types.Type {
+ // "[" already consumed and lookahead known not to be "]"
+ lit := p.expect(scanner.Int)
+ p.expect(']')
+ elem := p.parseType()
+ n, err := strconv.ParseInt(lit, 10, 64)
+ if err != nil {
+ p.error(err)
+ }
+ return types.NewArray(elem, n)
+}
+
+// MapType = "map" "[" Type "]" Type .
+//
+func (p *parser) parseMapType() types.Type {
+ p.expectKeyword("map")
+ p.expect('[')
+ key := p.parseType()
+ p.expect(']')
+ elem := p.parseType()
+ return types.NewMap(key, elem)
+}
+
+// Name = identifier | "?" | QualifiedName .
+//
+// If materializePkg is set, the returned package is guaranteed to be set.
+// For fully qualified names, the returned package may be a fake package
+// (without name, scope, and not in the p.imports map), created for the
+// sole purpose of providing a package path. Fake packages are created
+// when the package id is not found in the p.imports map; in that case
+// we cannot create a real package because we don't have a package name.
+// For non-qualified names, the returned package is the imported package.
+//
+func (p *parser) parseName(materializePkg bool) (pkg *types.Package, name string) {
+ switch p.tok {
+ case scanner.Ident:
+ pkg = p.sharedPkgs[p.id]
+ name = p.lit
+ p.next()
+ case '?':
+ // anonymous
+ pkg = p.sharedPkgs[p.id]
+ p.next()
+ case '@':
+ // exported name prefixed with package path
+ var id string
+ id, name = p.parseQualifiedName()
+ if materializePkg {
+ // we don't have a package name - if the package
+ // doesn't exist yet, create a fake package instead
+ pkg = p.getPkg(id, "")
+ if pkg == nil {
+ pkg = types.NewPackage(id, "")
+ }
+ }
+ default:
+ p.error("name expected")
+ }
+ return
+}
+
+func deref(typ types.Type) types.Type {
+ if p, _ := typ.(*types.Pointer); p != nil {
+ return p.Elem()
+ }
+ return typ
+}
+
+// Field = Name Type [ string_lit ] .
+//
+func (p *parser) parseField() (*types.Var, string) {
+ pkg, name := p.parseName(true)
+ typ := p.parseType()
+ anonymous := false
+ if name == "" {
+ // anonymous field - typ must be T or *T and T must be a type name
+ switch typ := deref(typ).(type) {
+ case *types.Basic: // basic types are named types
+ pkg = nil
+ name = typ.Name()
+ case *types.Named:
+ name = typ.Obj().Name()
+ default:
+ p.errorf("anonymous field expected")
+ }
+ anonymous = true
+ }
+ tag := ""
+ if p.tok == scanner.String {
+ s := p.expect(scanner.String)
+ var err error
+ tag, err = strconv.Unquote(s)
+ if err != nil {
+ p.errorf("invalid struct tag %s: %s", s, err)
+ }
+ }
+ return types.NewField(token.NoPos, pkg, name, typ, anonymous), tag
+}
+
+// StructType = "struct" "{" [ FieldList ] "}" .
+// FieldList = Field { ";" Field } .
+//
+func (p *parser) parseStructType() types.Type {
+ var fields []*types.Var
+ var tags []string
+
+ p.expectKeyword("struct")
+ p.expect('{')
+ for i := 0; p.tok != '}' && p.tok != scanner.EOF; i++ {
+ if i > 0 {
+ p.expect(';')
+ }
+ fld, tag := p.parseField()
+ if tag != "" && tags == nil {
+ tags = make([]string, i)
+ }
+ if tags != nil {
+ tags = append(tags, tag)
+ }
+ fields = append(fields, fld)
+ }
+ p.expect('}')
+
+ return types.NewStruct(fields, tags)
+}
+
+// Parameter = ( identifier | "?" ) [ "..." ] Type [ string_lit ] .
+//
+func (p *parser) parseParameter() (par *types.Var, isVariadic bool) {
+ _, name := p.parseName(false)
+ // remove gc-specific parameter numbering
+ if i := strings.Index(name, "·"); i >= 0 {
+ name = name[:i]
+ }
+ if p.tok == '.' {
+ p.expectSpecial("...")
+ isVariadic = true
+ }
+ typ := p.parseType()
+ if isVariadic {
+ typ = types.NewSlice(typ)
+ }
+ // ignore argument tag (e.g. "noescape")
+ if p.tok == scanner.String {
+ p.next()
+ }
+ // TODO(gri) should we provide a package?
+ par = types.NewVar(token.NoPos, nil, name, typ)
+ return
+}
+
+// Parameters = "(" [ ParameterList ] ")" .
+// ParameterList = { Parameter "," } Parameter .
+//
+func (p *parser) parseParameters() (list []*types.Var, isVariadic bool) {
+ p.expect('(')
+ for p.tok != ')' && p.tok != scanner.EOF {
+ if len(list) > 0 {
+ p.expect(',')
+ }
+ par, variadic := p.parseParameter()
+ list = append(list, par)
+ if variadic {
+ if isVariadic {
+ p.error("... not on final argument")
+ }
+ isVariadic = true
+ }
+ }
+ p.expect(')')
+
+ return
+}
+
+// Signature = Parameters [ Result ] .
+// Result = Type | Parameters .
+//
+func (p *parser) parseSignature(recv *types.Var) *types.Signature {
+ params, isVariadic := p.parseParameters()
+
+ // optional result type
+ var results []*types.Var
+ if p.tok == '(' {
+ var variadic bool
+ results, variadic = p.parseParameters()
+ if variadic {
+ p.error("... not permitted on result type")
+ }
+ }
+
+ return types.NewSignature(recv, types.NewTuple(params...), types.NewTuple(results...), isVariadic)
+}
+
+// InterfaceType = "interface" "{" [ MethodList ] "}" .
+// MethodList = Method { ";" Method } .
+// Method = Name Signature .
+//
+// The methods of embedded interfaces are always "inlined"
+// by the compiler and thus embedded interfaces are never
+// visible in the export data.
+//
+func (p *parser) parseInterfaceType() types.Type {
+ var methods []*types.Func
+
+ p.expectKeyword("interface")
+ p.expect('{')
+ for i := 0; p.tok != '}' && p.tok != scanner.EOF; i++ {
+ if i > 0 {
+ p.expect(';')
+ }
+ pkg, name := p.parseName(true)
+ sig := p.parseSignature(nil)
+ methods = append(methods, types.NewFunc(token.NoPos, pkg, name, sig))
+ }
+ p.expect('}')
+
+ // Complete requires the type's embedded interfaces to be fully defined,
+ // but we do not define any
+ return types.NewInterface(methods, nil).Complete()
+}
+
+// ChanType = ( "chan" [ "<-" ] | "<-" "chan" ) Type .
+//
+func (p *parser) parseChanType() types.Type {
+ dir := types.SendRecv
+ if p.tok == scanner.Ident {
+ p.expectKeyword("chan")
+ if p.tok == '<' {
+ p.expectSpecial("<-")
+ dir = types.SendOnly
+ }
+ } else {
+ p.expectSpecial("<-")
+ p.expectKeyword("chan")
+ dir = types.RecvOnly
+ }
+ elem := p.parseType()
+ return types.NewChan(dir, elem)
+}
+
+// Type =
+// BasicType | TypeName | ArrayType | SliceType | StructType |
+// PointerType | FuncType | InterfaceType | MapType | ChanType |
+// "(" Type ")" .
+//
+// BasicType = ident .
+// TypeName = ExportedName .
+// SliceType = "[" "]" Type .
+// PointerType = "*" Type .
+// FuncType = "func" Signature .
+//
+func (p *parser) parseType() types.Type {
+ switch p.tok {
+ case scanner.Ident:
+ switch p.lit {
+ default:
+ return p.parseBasicType()
+ case "struct":
+ return p.parseStructType()
+ case "func":
+ // FuncType
+ p.next()
+ return p.parseSignature(nil)
+ case "interface":
+ return p.parseInterfaceType()
+ case "map":
+ return p.parseMapType()
+ case "chan":
+ return p.parseChanType()
+ }
+ case '@':
+ // TypeName
+ pkg, name := p.parseExportedName()
+ return declTypeName(pkg, name).Type()
+ case '[':
+ p.next() // look ahead
+ if p.tok == ']' {
+ // SliceType
+ p.next()
+ return types.NewSlice(p.parseType())
+ }
+ return p.parseArrayType()
+ case '*':
+ // PointerType
+ p.next()
+ return types.NewPointer(p.parseType())
+ case '<':
+ return p.parseChanType()
+ case '(':
+ // "(" Type ")"
+ p.next()
+ typ := p.parseType()
+ p.expect(')')
+ return typ
+ }
+ p.errorf("expected type, got %s (%q)", scanner.TokenString(p.tok), p.lit)
+ return nil
+}
+
+// ----------------------------------------------------------------------------
+// Declarations
+
+// ImportDecl = "import" PackageName PackageId .
+//
+func (p *parser) parseImportDecl() {
+ p.expectKeyword("import")
+ name := p.parsePackageName()
+ p.getPkg(p.parsePackageId(), name)
+}
+
+// int_lit = [ "+" | "-" ] { "0" ... "9" } .
+//
+func (p *parser) parseInt() string {
+ s := ""
+ switch p.tok {
+ case '-':
+ s = "-"
+ p.next()
+ case '+':
+ p.next()
+ }
+ return s + p.expect(scanner.Int)
+}
+
+// number = int_lit [ "p" int_lit ] .
+//
+func (p *parser) parseNumber() (typ *types.Basic, val exact.Value) {
+ // mantissa
+ mant := exact.MakeFromLiteral(p.parseInt(), token.INT)
+ if mant == nil {
+ panic("invalid mantissa")
+ }
+
+ if p.lit == "p" {
+ // exponent (base 2)
+ p.next()
+ exp, err := strconv.ParseInt(p.parseInt(), 10, 0)
+ if err != nil {
+ p.error(err)
+ }
+ if exp < 0 {
+ denom := exact.MakeInt64(1)
+ denom = exact.Shift(denom, token.SHL, uint(-exp))
+ typ = types.Typ[types.UntypedFloat]
+ val = exact.BinaryOp(mant, token.QUO, denom)
+ return
+ }
+ if exp > 0 {
+ mant = exact.Shift(mant, token.SHL, uint(exp))
+ }
+ typ = types.Typ[types.UntypedFloat]
+ val = mant
+ return
+ }
+
+ typ = types.Typ[types.UntypedInt]
+ val = mant
+ return
+}
+
+// ConstDecl = "const" ExportedName [ Type ] "=" Literal .
+// Literal = bool_lit | int_lit | float_lit | complex_lit | rune_lit | string_lit .
+// bool_lit = "true" | "false" .
+// complex_lit = "(" float_lit "+" float_lit "i" ")" .
+// rune_lit = "(" int_lit "+" int_lit ")" .
+// string_lit = `"` { unicode_char } `"` .
+//
+func (p *parser) parseConstDecl() {
+ p.expectKeyword("const")
+ pkg, name := p.parseExportedName()
+
+ var typ0 types.Type
+ if p.tok != '=' {
+ typ0 = p.parseType()
+ }
+
+ p.expect('=')
+ var typ types.Type
+ var val exact.Value
+ switch p.tok {
+ case scanner.Ident:
+ // bool_lit
+ if p.lit != "true" && p.lit != "false" {
+ p.error("expected true or false")
+ }
+ typ = types.Typ[types.UntypedBool]
+ val = exact.MakeBool(p.lit == "true")
+ p.next()
+
+ case '-', scanner.Int:
+ // int_lit
+ typ, val = p.parseNumber()
+
+ case '(':
+ // complex_lit or rune_lit
+ p.next()
+ if p.tok == scanner.Char {
+ p.next()
+ p.expect('+')
+ typ = types.Typ[types.UntypedRune]
+ _, val = p.parseNumber()
+ p.expect(')')
+ break
+ }
+ _, re := p.parseNumber()
+ p.expect('+')
+ _, im := p.parseNumber()
+ p.expectKeyword("i")
+ p.expect(')')
+ typ = types.Typ[types.UntypedComplex]
+ val = exact.BinaryOp(re, token.ADD, exact.MakeImag(im))
+
+ case scanner.Char:
+ // rune_lit
+ typ = types.Typ[types.UntypedRune]
+ val = exact.MakeFromLiteral(p.lit, token.CHAR)
+ p.next()
+
+ case scanner.String:
+ // string_lit
+ typ = types.Typ[types.UntypedString]
+ val = exact.MakeFromLiteral(p.lit, token.STRING)
+ p.next()
+
+ default:
+ p.errorf("expected literal got %s", scanner.TokenString(p.tok))
+ }
+
+ if typ0 == nil {
+ typ0 = typ
+ }
+
+ pkg.Scope().Insert(types.NewConst(token.NoPos, pkg, name, typ0, val))
+}
+
+// TypeDecl = "type" ExportedName Type .
+//
+func (p *parser) parseTypeDecl() {
+ p.expectKeyword("type")
+ pkg, name := p.parseExportedName()
+ obj := declTypeName(pkg, name)
+
+ // The type object may have been imported before and thus already
+ // have a type associated with it. We still need to parse the type
+ // structure, but throw it away if the object already has a type.
+ // This ensures that all imports refer to the same type object for
+ // a given type declaration.
+ typ := p.parseType()
+
+ if name := obj.Type().(*types.Named); name.Underlying() == nil {
+ name.SetUnderlying(typ)
+ }
+}
+
+// VarDecl = "var" ExportedName Type .
+//
+func (p *parser) parseVarDecl() {
+ p.expectKeyword("var")
+ pkg, name := p.parseExportedName()
+ typ := p.parseType()
+ pkg.Scope().Insert(types.NewVar(token.NoPos, pkg, name, typ))
+}
+
+// Func = Signature [ Body ] .
+// Body = "{" ... "}" .
+//
+func (p *parser) parseFunc(recv *types.Var) *types.Signature {
+ sig := p.parseSignature(recv)
+ if p.tok == '{' {
+ p.next()
+ for i := 1; i > 0; p.next() {
+ switch p.tok {
+ case '{':
+ i++
+ case '}':
+ i--
+ }
+ }
+ }
+ return sig
+}
+
+// MethodDecl = "func" Receiver Name Func .
+// Receiver = "(" ( identifier | "?" ) [ "*" ] ExportedName ")" .
+//
+func (p *parser) parseMethodDecl() {
+ // "func" already consumed
+ p.expect('(')
+ recv, _ := p.parseParameter() // receiver
+ p.expect(')')
+
+ // determine receiver base type object
+ base := deref(recv.Type()).(*types.Named)
+
+ // parse method name, signature, and possibly inlined body
+ _, name := p.parseName(true)
+ sig := p.parseFunc(recv)
+
+ // methods always belong to the same package as the base type object
+ pkg := base.Obj().Pkg()
+
+ // add method to type unless type was imported before
+ // and method exists already
+ // TODO(gri) This leads to a quadratic algorithm - ok for now because method counts are small.
+ base.AddMethod(types.NewFunc(token.NoPos, pkg, name, sig))
+}
+
+// FuncDecl = "func" ExportedName Func .
+//
+func (p *parser) parseFuncDecl() {
+ // "func" already consumed
+ pkg, name := p.parseExportedName()
+ typ := p.parseFunc(nil)
+ pkg.Scope().Insert(types.NewFunc(token.NoPos, pkg, name, typ))
+}
+
+// Decl = [ ImportDecl | ConstDecl | TypeDecl | VarDecl | FuncDecl | MethodDecl ] "\n" .
+//
+func (p *parser) parseDecl() {
+ if p.tok == scanner.Ident {
+ switch p.lit {
+ case "import":
+ p.parseImportDecl()
+ case "const":
+ p.parseConstDecl()
+ case "type":
+ p.parseTypeDecl()
+ case "var":
+ p.parseVarDecl()
+ case "func":
+ p.next() // look ahead
+ if p.tok == '(' {
+ p.parseMethodDecl()
+ } else {
+ p.parseFuncDecl()
+ }
+ }
+ }
+ p.expect('\n')
+}
+
+// ----------------------------------------------------------------------------
+// Export
+
+// Export = "PackageClause { Decl } "$$" .
+// PackageClause = "package" PackageName [ "safe" ] "\n" .
+//
+func (p *parser) parseExport() *types.Package {
+ p.expectKeyword("package")
+ name := p.parsePackageName()
+ if p.tok == scanner.Ident && p.lit == "safe" {
+ // package was compiled with -u option - ignore
+ p.next()
+ }
+ p.expect('\n')
+
+ pkg := p.getPkg(p.id, name)
+
+ for p.tok != '$' && p.tok != scanner.EOF {
+ p.parseDecl()
+ }
+
+ if ch := p.scanner.Peek(); p.tok != '$' || ch != '$' {
+ // don't call next()/expect() since reading past the
+ // export data may cause scanner errors (e.g. NUL chars)
+ p.errorf("expected '$$', got %s %c", scanner.TokenString(p.tok), ch)
+ }
+
+ if n := p.scanner.ErrorCount; n != 0 {
+ p.errorf("expected no scanner errors, got %d", n)
+ }
+
+ // Record all referenced packages as imports.
+ var imports []*types.Package
+ for id, pkg2 := range p.localPkgs {
+ if id == p.id {
+ continue // avoid self-edge
+ }
+ imports = append(imports, pkg2)
+ }
+ sort.Sort(byPath(imports))
+ pkg.SetImports(imports)
+
+ // package was imported completely and without errors
+ pkg.MarkComplete()
+
+ return pkg
+}
+
+type byPath []*types.Package
+
+func (a byPath) Len() int { return len(a) }
+func (a byPath) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
+func (a byPath) Less(i, j int) bool { return a[i].Path() < a[j].Path() }
diff --git a/go/gcimporter/gcimporter_test.go b/go/gcimporter/gcimporter_test.go
new file mode 100644
index 0000000..73a4747
--- /dev/null
+++ b/go/gcimporter/gcimporter_test.go
@@ -0,0 +1,242 @@
+// 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 gcimporter
+
+import (
+ "fmt"
+ "go/build"
+ "io/ioutil"
+ "os"
+ "os/exec"
+ "path/filepath"
+ "runtime"
+ "strings"
+ "testing"
+ "time"
+
+ "golang.org/x/tools/go/types"
+)
+
+// skipSpecialPlatforms causes the test to be skipped for platforms where
+// builders (build.golang.org) don't have access to compiled packages for
+// import.
+func skipSpecialPlatforms(t *testing.T) {
+ switch platform := runtime.GOOS + "-" + runtime.GOARCH; platform {
+ case "nacl-amd64p32",
+ "nacl-386",
+ "nacl-arm",
+ "darwin-arm",
+ "darwin-arm64":
+ t.Skipf("no compiled packages available for import on %s", platform)
+ }
+}
+
+var gcPath string // Go compiler path
+
+func init() {
+ if char, err := build.ArchChar(runtime.GOARCH); err == nil {
+ gcPath = filepath.Join(build.ToolDir, char+"g")
+ return
+ }
+ gcPath = "unknown-GOARCH-compiler"
+}
+
+func compile(t *testing.T, dirname, filename string) string {
+ cmd := exec.Command(gcPath, filename)
+ cmd.Dir = dirname
+ out, err := cmd.CombinedOutput()
+ if err != nil {
+ t.Logf("%s", out)
+ t.Fatalf("%s %s failed: %s", gcPath, filename, err)
+ }
+ archCh, _ := build.ArchChar(runtime.GOARCH)
+ // filename should end with ".go"
+ return filepath.Join(dirname, filename[:len(filename)-2]+archCh)
+}
+
+// Use the same global imports map for all tests. The effect is
+// as if all tested packages were imported into a single package.
+var imports = make(map[string]*types.Package)
+
+func testPath(t *testing.T, path string) *types.Package {
+ t0 := time.Now()
+ pkg, err := Import(imports, path)
+ if err != nil {
+ t.Errorf("testPath(%s): %s", path, err)
+ return nil
+ }
+ t.Logf("testPath(%s): %v", path, time.Since(t0))
+ return pkg
+}
+
+const maxTime = 30 * time.Second
+
+func testDir(t *testing.T, dir string, endTime time.Time) (nimports int) {
+ dirname := filepath.Join(runtime.GOROOT(), "pkg", runtime.GOOS+"_"+runtime.GOARCH, dir)
+ list, err := ioutil.ReadDir(dirname)
+ if err != nil {
+ t.Fatalf("testDir(%s): %s", dirname, err)
+ }
+ for _, f := range list {
+ if time.Now().After(endTime) {
+ t.Log("testing time used up")
+ return
+ }
+ switch {
+ case !f.IsDir():
+ // try extensions
+ for _, ext := range pkgExts {
+ if strings.HasSuffix(f.Name(), ext) {
+ name := f.Name()[0 : len(f.Name())-len(ext)] // remove extension
+ if testPath(t, filepath.Join(dir, name)) != nil {
+ nimports++
+ }
+ }
+ }
+ case f.IsDir():
+ nimports += testDir(t, filepath.Join(dir, f.Name()), endTime)
+ }
+ }
+ return
+}
+
+func TestImport(t *testing.T) {
+ // This package only handles gc export data.
+ if runtime.Compiler != "gc" {
+ t.Skipf("gc-built packages not available (compiler = %s)", runtime.Compiler)
+ return
+ }
+
+ // On cross-compile builds, the path will not exist.
+ // Need to use GOHOSTOS, which is not available.
+ if _, err := os.Stat(gcPath); err != nil {
+ t.Skipf("skipping test: %v", err)
+ }
+
+ if outFn := compile(t, "testdata", "exports.go"); outFn != "" {
+ defer os.Remove(outFn)
+ }
+
+ nimports := 0
+ if pkg := testPath(t, "./testdata/exports"); pkg != nil {
+ nimports++
+ // The package's Imports should include all the types
+ // referenced by the exportdata, which may be more than
+ // the import statements in the package's source, but
+ // fewer than the transitive closure of dependencies.
+ want := `[package ast ("go/ast") package token ("go/token") package runtime ("runtime")]`
+ got := fmt.Sprint(pkg.Imports())
+ if got != want {
+ t.Errorf(`Package("exports").Imports() = %s, want %s`, got, want)
+ }
+ }
+ nimports += testDir(t, "", time.Now().Add(maxTime)) // installed packages
+ t.Logf("tested %d imports", nimports)
+}
+
+var importedObjectTests = []struct {
+ name string
+ want string
+}{
+ {"unsafe.Pointer", "type Pointer unsafe.Pointer"},
+ {"math.Pi", "const Pi untyped float"},
+ {"io.Reader", "type Reader interface{Read(p []byte) (n int, err error)}"},
+ {"io.ReadWriter", "type ReadWriter interface{Read(p []byte) (n int, err error); Write(p []byte) (n int, err error)}"},
+ {"math.Sin", "func Sin(x float64) float64"},
+ // TODO(gri) add more tests
+}
+
+func TestImportedTypes(t *testing.T) {
+ skipSpecialPlatforms(t)
+
+ // This package only handles gc export data.
+ if runtime.Compiler != "gc" {
+ t.Skipf("gc-built packages not available (compiler = %s)", runtime.Compiler)
+ return
+ }
+
+ for _, test := range importedObjectTests {
+ s := strings.Split(test.name, ".")
+ if len(s) != 2 {
+ t.Fatal("inconsistent test data")
+ }
+ importPath := s[0]
+ objName := s[1]
+
+ pkg, err := Import(imports, importPath)
+ if err != nil {
+ t.Error(err)
+ continue
+ }
+
+ obj := pkg.Scope().Lookup(objName)
+ if obj == nil {
+ t.Errorf("%s: object not found", test.name)
+ continue
+ }
+
+ got := types.ObjectString(obj, types.RelativeTo(pkg))
+ if got != test.want {
+ t.Errorf("%s: got %q; want %q", test.name, got, test.want)
+ }
+ }
+}
+
+func TestIssue5815(t *testing.T) {
+ skipSpecialPlatforms(t)
+
+ // This package only handles gc export data.
+ if runtime.Compiler != "gc" {
+ t.Skipf("gc-built packages not available (compiler = %s)", runtime.Compiler)
+ return
+ }
+
+ pkg, err := Import(make(map[string]*types.Package), "strings")
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ scope := pkg.Scope()
+ for _, name := range scope.Names() {
+ obj := scope.Lookup(name)
+ if obj.Pkg() == nil {
+ t.Errorf("no pkg for %s", obj)
+ }
+ if tname, _ := obj.(*types.TypeName); tname != nil {
+ named := tname.Type().(*types.Named)
+ for i := 0; i < named.NumMethods(); i++ {
+ m := named.Method(i)
+ if m.Pkg() == nil {
+ t.Errorf("no pkg for %s", m)
+ }
+ }
+ }
+ }
+}
+
+// Smoke test to ensure that imported methods get the correct package.
+func TestCorrectMethodPackage(t *testing.T) {
+ skipSpecialPlatforms(t)
+
+ // This package only handles gc export data.
+ if runtime.Compiler != "gc" {
+ t.Skipf("gc-built packages not available (compiler = %s)", runtime.Compiler)
+ return
+ }
+
+ imports := make(map[string]*types.Package)
+ _, err := Import(imports, "net/http")
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ mutex := imports["sync"].Scope().Lookup("Mutex").(*types.TypeName).Type()
+ mset := types.NewMethodSet(types.NewPointer(mutex)) // methods of *sync.Mutex
+ sel := mset.Lookup(nil, "Lock")
+ lock := sel.Obj().(*types.Func)
+ if got, want := lock.Pkg().Path(), "sync"; got != want {
+ t.Errorf("got package path %q; want %q", got, want)
+ }
+}
diff --git a/go/gcimporter/testdata/exports.go b/go/gcimporter/testdata/exports.go
new file mode 100644
index 0000000..8ee28b0
--- /dev/null
+++ b/go/gcimporter/testdata/exports.go
@@ -0,0 +1,89 @@
+// 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 file is used to generate an object file which
+// serves as test file for gcimporter_test.go.
+
+package exports
+
+import (
+ "go/ast"
+)
+
+// Issue 3682: Correctly read dotted identifiers from export data.
+const init1 = 0
+
+func init() {}
+
+const (
+ C0 int = 0
+ C1 = 3.14159265
+ C2 = 2.718281828i
+ C3 = -123.456e-789
+ C4 = +123.456E+789
+ C5 = 1234i
+ C6 = "foo\n"
+ C7 = `bar\n`
+)
+
+type (
+ T1 int
+ T2 [10]int
+ T3 []int
+ T4 *int
+ T5 chan int
+ T6a chan<- int
+ T6b chan (<-chan int)
+ T6c chan<- (chan int)
+ T7 <-chan *ast.File
+ T8 struct{}
+ T9 struct {
+ a int
+ b, c float32
+ d []string `go:"tag"`
+ }
+ T10 struct {
+ T8
+ T9
+ _ *T10
+ }
+ T11 map[int]string
+ T12 interface{}
+ T13 interface {
+ m1()
+ m2(int) float32
+ }
+ T14 interface {
+ T12
+ T13
+ m3(x ...struct{}) []T9
+ }
+ T15 func()
+ T16 func(int)
+ T17 func(x int)
+ T18 func() float32
+ T19 func() (x float32)
+ T20 func(...interface{})
+ T21 struct{ next *T21 }
+ T22 struct{ link *T23 }
+ T23 struct{ link *T22 }
+ T24 *T24
+ T25 *T26
+ T26 *T27
+ T27 *T25
+ T28 func(T28) T28
+)
+
+var (
+ V0 int
+ V1 = -991.0
+)
+
+func F1() {}
+func F2(x int) {}
+func F3() int { return 0 }
+func F4() float32 { return 0 }
+func F5(a, b, c int, u, v, w struct{ x, y T1 }, more ...interface{}) (p, q, r chan<- T10)
+
+func (p *T1) M1()
diff --git a/go/importer/export.go b/go/importer/export.go
new file mode 100644
index 0000000..5930eaf
--- /dev/null
+++ b/go/importer/export.go
@@ -0,0 +1,462 @@
+// 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 importer
+
+import (
+ "bytes"
+ "encoding/binary"
+ "fmt"
+ "go/ast"
+ "strings"
+
+ "golang.org/x/tools/go/exact"
+ "golang.org/x/tools/go/types"
+)
+
+// debugging support
+const (
+ debug = false // emit debugging data
+ trace = false // print emitted data
+)
+
+// format returns a byte indicating the low-level encoding/decoding format
+// (debug vs product).
+func format() byte {
+ if debug {
+ return 'd'
+ }
+ return 'p'
+}
+
+// ExportData serializes the interface (exported package objects)
+// of package pkg and returns the corresponding data. The export
+// format is described elsewhere (TODO).
+func ExportData(pkg *types.Package) []byte {
+ p := exporter{
+ data: append([]byte(magic), format()),
+ pkgIndex: make(map[*types.Package]int),
+ typIndex: make(map[types.Type]int),
+ }
+
+ // populate typIndex with predeclared types
+ for _, t := range predeclared {
+ p.typIndex[t] = len(p.typIndex)
+ }
+
+ if trace {
+ p.tracef("export %s\n", pkg.Name())
+ defer p.tracef("\n")
+ }
+
+ p.string(version)
+
+ p.pkg(pkg)
+
+ // collect exported objects from package scope
+ var list []types.Object
+ scope := pkg.Scope()
+ for _, name := range scope.Names() {
+ if exported(name) {
+ list = append(list, scope.Lookup(name))
+ }
+ }
+
+ // write objects
+ p.int(len(list))
+ for _, obj := range list {
+ p.obj(obj)
+ }
+
+ return p.data
+}
+
+type exporter struct {
+ data []byte
+ pkgIndex map[*types.Package]int
+ typIndex map[types.Type]int
+
+ // tracing support
+ indent string
+}
+
+func (p *exporter) pkg(pkg *types.Package) {
+ if trace {
+ p.tracef("package { ")
+ defer p.tracef("} ")
+ }
+
+ if pkg == nil {
+ panic("unexpected nil pkg")
+ }
+
+ // if the package was seen before, write its index (>= 0)
+ if i, ok := p.pkgIndex[pkg]; ok {
+ p.int(i)
+ return
+ }
+ p.pkgIndex[pkg] = len(p.pkgIndex)
+
+ // otherwise, write the package tag (< 0) and package data
+ p.int(packageTag)
+ p.string(pkg.Name())
+ p.string(pkg.Path())
+}
+
+func (p *exporter) obj(obj types.Object) {
+ if trace {
+ p.tracef("object %s {\n", obj.Name())
+ defer p.tracef("}\n")
+ }
+
+ switch obj := obj.(type) {
+ case *types.Const:
+ p.int(constTag)
+ p.string(obj.Name())
+ p.typ(obj.Type())
+ p.value(obj.Val())
+ case *types.TypeName:
+ p.int(typeTag)
+ // name is written by corresponding named type
+ p.typ(obj.Type().(*types.Named))
+ case *types.Var:
+ p.int(varTag)
+ p.string(obj.Name())
+ p.typ(obj.Type())
+ case *types.Func:
+ p.int(funcTag)
+ p.string(obj.Name())
+ p.typ(obj.Type())
+ default:
+ panic(fmt.Sprintf("unexpected object type %T", obj))
+ }
+}
+
+func (p *exporter) value(x exact.Value) {
+ if trace {
+ p.tracef("value { ")
+ defer p.tracef("} ")
+ }
+
+ switch kind := x.Kind(); kind {
+ case exact.Bool:
+ tag := falseTag
+ if exact.BoolVal(x) {
+ tag = trueTag
+ }
+ p.int(tag)
+ case exact.Int:
+ if i, ok := exact.Int64Val(x); ok {
+ p.int(int64Tag)
+ p.int64(i)
+ return
+ }
+ p.int(floatTag)
+ p.float(x)
+ case exact.Float:
+ p.int(fractionTag)
+ p.fraction(x)
+ case exact.Complex:
+ p.int(complexTag)
+ p.fraction(exact.Real(x))
+ p.fraction(exact.Imag(x))
+ case exact.String:
+ p.int(stringTag)
+ p.string(exact.StringVal(x))
+ default:
+ panic(fmt.Sprintf("unexpected value kind %d", kind))
+ }
+}
+
+func (p *exporter) float(x exact.Value) {
+ sign := exact.Sign(x)
+ p.int(sign)
+ if sign == 0 {
+ return
+ }
+
+ p.ufloat(x)
+}
+
+func (p *exporter) fraction(x exact.Value) {
+ sign := exact.Sign(x)
+ p.int(sign)
+ if sign == 0 {
+ return
+ }
+
+ p.ufloat(exact.Num(x))
+ p.ufloat(exact.Denom(x))
+}
+
+// ufloat writes abs(x) in form of a binary exponent
+// followed by its mantissa bytes; x must be != 0.
+func (p *exporter) ufloat(x exact.Value) {
+ mant := exact.Bytes(x)
+ exp8 := -1
+ for i, b := range mant {
+ if b != 0 {
+ exp8 = i
+ break
+ }
+ }
+ if exp8 < 0 {
+ panic(fmt.Sprintf("%s has no mantissa", x))
+ }
+ p.int(exp8 * 8)
+ p.bytes(mant[exp8:])
+}
+
+func (p *exporter) typ(typ types.Type) {
+ if trace {
+ p.tracef("type {\n")
+ defer p.tracef("}\n")
+ }
+
+ // if the type was seen before, write its index (>= 0)
+ if i, ok := p.typIndex[typ]; ok {
+ p.int(i)
+ return
+ }
+ p.typIndex[typ] = len(p.typIndex)
+
+ // otherwise, write the type tag (< 0) and type data
+ switch t := typ.(type) {
+ case *types.Array:
+ p.int(arrayTag)
+ p.int64(t.Len())
+ p.typ(t.Elem())
+
+ case *types.Slice:
+ p.int(sliceTag)
+ p.typ(t.Elem())
+
+ case *types.Struct:
+ p.int(structTag)
+ n := t.NumFields()
+ p.int(n)
+ for i := 0; i < n; i++ {
+ p.field(t.Field(i))
+ p.string(t.Tag(i))
+ }
+
+ case *types.Pointer:
+ p.int(pointerTag)
+ p.typ(t.Elem())
+
+ case *types.Signature:
+ p.int(signatureTag)
+ p.signature(t)
+
+ case *types.Interface:
+ p.int(interfaceTag)
+
+ // write embedded interfaces
+ m := t.NumEmbeddeds()
+ p.int(m)
+ for i := 0; i < m; i++ {
+ p.typ(t.Embedded(i))
+ }
+
+ // write methods
+ n := t.NumExplicitMethods()
+ p.int(n)
+ for i := 0; i < n; i++ {
+ m := t.ExplicitMethod(i)
+ p.qualifiedName(m.Pkg(), m.Name())
+ p.typ(m.Type())
+ }
+
+ case *types.Map:
+ p.int(mapTag)
+ p.typ(t.Key())
+ p.typ(t.Elem())
+
+ case *types.Chan:
+ p.int(chanTag)
+ p.int(int(t.Dir()))
+ p.typ(t.Elem())
+
+ case *types.Named:
+ p.int(namedTag)
+
+ // write type object
+ obj := t.Obj()
+ p.string(obj.Name())
+ p.pkg(obj.Pkg())
+
+ // write underlying type
+ p.typ(t.Underlying())
+
+ // write associated methods
+ n := t.NumMethods()
+ p.int(n)
+ for i := 0; i < n; i++ {
+ m := t.Method(i)
+ p.string(m.Name())
+ p.typ(m.Type())
+ }
+
+ default:
+ panic("unreachable")
+ }
+}
+
+func (p *exporter) field(f *types.Var) {
+ // anonymous fields have "" name
+ name := ""
+ if !f.Anonymous() {
+ name = f.Name()
+ }
+
+ // qualifiedName will always emit the field package for
+ // anonymous fields because "" is not an exported name.
+ p.qualifiedName(f.Pkg(), name)
+ p.typ(f.Type())
+}
+
+func (p *exporter) qualifiedName(pkg *types.Package, name string) {
+ p.string(name)
+ // exported names don't need package
+ if !exported(name) {
+ if pkg == nil {
+ panic(fmt.Sprintf("nil package for unexported qualified name %s", name))
+ }
+ p.pkg(pkg)
+ }
+}
+
+func (p *exporter) signature(sig *types.Signature) {
+ // We need the receiver information (T vs *T)
+ // for methods associated with named types.
+ // We do not record interface receiver types in the
+ // export data because 1) the importer can derive them
+ // from the interface type and 2) they create cycles
+ // in the type graph.
+ if recv := sig.Recv(); recv != nil {
+ if _, ok := recv.Type().Underlying().(*types.Interface); !ok {
+ // 1-element tuple
+ p.int(1)
+ p.param(recv)
+ } else {
+ // 0-element tuple
+ p.int(0)
+ }
+ } else {
+ // 0-element tuple
+ p.int(0)
+ }
+ p.tuple(sig.Params())
+ p.tuple(sig.Results())
+ if sig.Variadic() {
+ p.int(1)
+ } else {
+ p.int(0)
+ }
+}
+
+func (p *exporter) param(v *types.Var) {
+ p.string(v.Name())
+ p.typ(v.Type())
+}
+
+func (p *exporter) tuple(t *types.Tuple) {
+ n := t.Len()
+ p.int(n)
+ for i := 0; i < n; i++ {
+ p.param(t.At(i))
+ }
+}
+
+// ----------------------------------------------------------------------------
+// encoders
+
+func (p *exporter) string(s string) {
+ p.bytes([]byte(s)) // (could be inlined if extra allocation matters)
+}
+
+func (p *exporter) int(x int) {
+ p.int64(int64(x))
+}
+
+func (p *exporter) int64(x int64) {
+ if debug {
+ p.marker('i')
+ }
+
+ if trace {
+ p.tracef("%d ", x)
+ }
+
+ p.rawInt64(x)
+}
+
+func (p *exporter) bytes(b []byte) {
+ if debug {
+ p.marker('b')
+ }
+
+ if trace {
+ p.tracef("%q ", b)
+ }
+
+ p.rawInt64(int64(len(b)))
+ if len(b) > 0 {
+ p.data = append(p.data, b...)
+ }
+}
+
+// marker emits a marker byte and position information which makes
+// it easy for a reader to detect if it is "out of sync". Used for
+// debug format only.
+func (p *exporter) marker(m byte) {
+ if debug {
+ p.data = append(p.data, m)
+ p.rawInt64(int64(len(p.data)))
+ }
+}
+
+// rawInt64 should only be used by low-level encoders
+func (p *exporter) rawInt64(x int64) {
+ var tmp [binary.MaxVarintLen64]byte
+ n := binary.PutVarint(tmp[:], x)
+ p.data = append(p.data, tmp[:n]...)
+}
+
+// utility functions
+
+func (p *exporter) tracef(format string, args ...interface{}) {
+ // rewrite format string to take care of indentation
+ const indent = ". "
+ if strings.IndexAny(format, "{}\n") >= 0 {
+ var buf bytes.Buffer
+ for i := 0; i < len(format); i++ {
+ // no need to deal with runes
+ ch := format[i]
+ switch ch {
+ case '{':
+ p.indent += indent
+ case '}':
+ p.indent = p.indent[:len(p.indent)-len(indent)]
+ if i+1 < len(format) && format[i+1] == '\n' {
+ buf.WriteByte('\n')
+ buf.WriteString(p.indent)
+ buf.WriteString("} ")
+ i++
+ continue
+ }
+ }
+ buf.WriteByte(ch)
+ if ch == '\n' {
+ buf.WriteString(p.indent)
+ }
+ }
+ format = buf.String()
+ }
+ fmt.Printf(format, args...)
+}
+
+func exported(name string) bool {
+ return ast.IsExported(name)
+}
diff --git a/go/importer/import.go b/go/importer/import.go
new file mode 100644
index 0000000..3fa37a5
--- /dev/null
+++ b/go/importer/import.go
@@ -0,0 +1,456 @@
+// 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 implementation is loosely based on the algorithm described
+// in: "On the linearization of graphs and writing symbol files",
+// by R. Griesemer, Technical Report 156, ETH Zürich, 1991.
+
+// package importer implements an exporter and importer for Go export data.
+package importer // import "golang.org/x/tools/go/importer"
+
+import (
+ "encoding/binary"
+ "fmt"
+ "go/token"
+
+ "golang.org/x/tools/go/exact"
+ "golang.org/x/tools/go/types"
+)
+
+// ImportData imports a package from the serialized package data
+// and returns the number of bytes consumed and a reference to the package.
+// If data is obviously malformed, an error is returned but in
+// general it is not recommended to call ImportData on untrusted
+// data.
+func ImportData(imports map[string]*types.Package, data []byte) (int, *types.Package, error) {
+ datalen := len(data)
+
+ // check magic string
+ var s string
+ if len(data) >= len(magic) {
+ s = string(data[:len(magic)])
+ data = data[len(magic):]
+ }
+ if s != magic {
+ return 0, nil, fmt.Errorf("incorrect magic string: got %q; want %q", s, magic)
+ }
+
+ // check low-level encoding format
+ var m byte = 'm' // missing format
+ if len(data) > 0 {
+ m = data[0]
+ data = data[1:]
+ }
+ if m != format() {
+ return 0, nil, fmt.Errorf("incorrect low-level encoding format: got %c; want %c", m, format())
+ }
+
+ p := importer{
+ data: data,
+ datalen: datalen,
+ imports: imports,
+ }
+
+ // populate typList with predeclared types
+ for _, t := range predeclared {
+ p.typList = append(p.typList, t)
+ }
+
+ if v := p.string(); v != version {
+ return 0, nil, fmt.Errorf("unknown version: got %s; want %s", v, version)
+ }
+
+ pkg := p.pkg()
+ if debug && p.pkgList[0] != pkg {
+ panic("imported packaged not found in pkgList[0]")
+ }
+
+ // read objects
+ n := p.int()
+ for i := 0; i < n; i++ {
+ p.obj(pkg)
+ }
+
+ // complete interfaces
+ for _, typ := range p.typList {
+ if it, ok := typ.(*types.Interface); ok {
+ it.Complete()
+ }
+ }
+
+ // package was imported completely and without errors
+ pkg.MarkComplete()
+
+ return p.consumed(), pkg, nil
+}
+
+type importer struct {
+ data []byte
+ datalen int
+ imports map[string]*types.Package
+ pkgList []*types.Package
+ typList []types.Type
+}
+
+func (p *importer) pkg() *types.Package {
+ // if the package was seen before, i is its index (>= 0)
+ i := p.int()
+ if i >= 0 {
+ return p.pkgList[i]
+ }
+
+ // otherwise, i is the package tag (< 0)
+ if i != packageTag {
+ panic(fmt.Sprintf("unexpected package tag %d", i))
+ }
+
+ // read package data
+ name := p.string()
+ path := p.string()
+
+ // if the package was imported before, use that one; otherwise create a new one
+ pkg := p.imports[path]
+ if pkg == nil {
+ pkg = types.NewPackage(path, name)
+ p.imports[path] = pkg
+ }
+ p.pkgList = append(p.pkgList, pkg)
+
+ return pkg
+}
+
+func (p *importer) obj(pkg *types.Package) {
+ var obj types.Object
+ switch tag := p.int(); tag {
+ case constTag:
+ obj = types.NewConst(token.NoPos, pkg, p.string(), p.typ(), p.value())
+ case typeTag:
+ // type object is added to scope via respective named type
+ _ = p.typ().(*types.Named)
+ return
+ case varTag:
+ obj = types.NewVar(token.NoPos, pkg, p.string(), p.typ())
+ case funcTag:
+ obj = types.NewFunc(token.NoPos, pkg, p.string(), p.typ().(*types.Signature))
+ default:
+ panic(fmt.Sprintf("unexpected object tag %d", tag))
+ }
+
+ if alt := pkg.Scope().Insert(obj); alt != nil {
+ panic(fmt.Sprintf("%s already declared", alt.Name()))
+ }
+}
+
+func (p *importer) value() exact.Value {
+ switch kind := exact.Kind(p.int()); kind {
+ case falseTag:
+ return exact.MakeBool(false)
+ case trueTag:
+ return exact.MakeBool(true)
+ case int64Tag:
+ return exact.MakeInt64(p.int64())
+ case floatTag:
+ return p.float()
+ case fractionTag:
+ return p.fraction()
+ case complexTag:
+ re := p.fraction()
+ im := p.fraction()
+ return exact.BinaryOp(re, token.ADD, exact.MakeImag(im))
+ case stringTag:
+ return exact.MakeString(p.string())
+ default:
+ panic(fmt.Sprintf("unexpected value kind %d", kind))
+ }
+}
+
+func (p *importer) float() exact.Value {
+ sign := p.int()
+ if sign == 0 {
+ return exact.MakeInt64(0)
+ }
+
+ x := p.ufloat()
+ if sign < 0 {
+ x = exact.UnaryOp(token.SUB, x, 0)
+ }
+ return x
+}
+
+func (p *importer) fraction() exact.Value {
+ sign := p.int()
+ if sign == 0 {
+ return exact.MakeInt64(0)
+ }
+
+ x := exact.BinaryOp(p.ufloat(), token.QUO, p.ufloat())
+ if sign < 0 {
+ x = exact.UnaryOp(token.SUB, x, 0)
+ }
+ return x
+}
+
+func (p *importer) ufloat() exact.Value {
+ exp := p.int()
+ x := exact.MakeFromBytes(p.bytes())
+ switch {
+ case exp < 0:
+ d := exact.Shift(exact.MakeInt64(1), token.SHL, uint(-exp))
+ x = exact.BinaryOp(x, token.QUO, d)
+ case exp > 0:
+ x = exact.Shift(x, token.SHL, uint(exp))
+ }
+ return x
+}
+
+func (p *importer) record(t types.Type) {
+ p.typList = append(p.typList, t)
+}
+
+func (p *importer) typ() types.Type {
+ // if the type was seen before, i is its index (>= 0)
+ i := p.int()
+ if i >= 0 {
+ return p.typList[i]
+ }
+
+ // otherwise, i is the type tag (< 0)
+ switch i {
+ case arrayTag:
+ t := new(types.Array)
+ p.record(t)
+
+ n := p.int64()
+ *t = *types.NewArray(p.typ(), n)
+ return t
+
+ case sliceTag:
+ t := new(types.Slice)
+ p.record(t)
+
+ *t = *types.NewSlice(p.typ())
+ return t
+
+ case structTag:
+ t := new(types.Struct)
+ p.record(t)
+
+ n := p.int()
+ fields := make([]*types.Var, n)
+ tags := make([]string, n)
+ for i := range fields {
+ fields[i] = p.field()
+ tags[i] = p.string()
+ }
+ *t = *types.NewStruct(fields, tags)
+ return t
+
+ case pointerTag:
+ t := new(types.Pointer)
+ p.record(t)
+
+ *t = *types.NewPointer(p.typ())
+ return t
+
+ case signatureTag:
+ t := new(types.Signature)
+ p.record(t)
+
+ *t = *p.signature()
+ return t
+
+ case interfaceTag:
+ // Create a dummy entry in the type list. This is safe because we
+ // cannot expect the interface type to appear in a cycle, as any
+ // such cycle must contain a named type which would have been
+ // first defined earlier.
+ n := len(p.typList)
+ p.record(nil)
+
+ // read embedded interfaces
+ embeddeds := make([]*types.Named, p.int())
+ for i := range embeddeds {
+ embeddeds[i] = p.typ().(*types.Named)
+ }
+
+ // read methods
+ methods := make([]*types.Func, p.int())
+ for i := range methods {
+ pkg, name := p.qualifiedName()
+ methods[i] = types.NewFunc(token.NoPos, pkg, name, p.typ().(*types.Signature))
+ }
+
+ t := types.NewInterface(methods, embeddeds)
+ p.typList[n] = t
+ return t
+
+ case mapTag:
+ t := new(types.Map)
+ p.record(t)
+
+ *t = *types.NewMap(p.typ(), p.typ())
+ return t
+
+ case chanTag:
+ t := new(types.Chan)
+ p.record(t)
+
+ *t = *types.NewChan(types.ChanDir(p.int()), p.typ())
+ return t
+
+ case namedTag:
+ // read type object
+ name := p.string()
+ pkg := p.pkg()
+ scope := pkg.Scope()
+ obj := scope.Lookup(name)
+
+ // if the object doesn't exist yet, create and insert it
+ if obj == nil {
+ obj = types.NewTypeName(token.NoPos, pkg, name, nil)
+ scope.Insert(obj)
+ }
+
+ // associate new named type with obj if it doesn't exist yet
+ t0 := types.NewNamed(obj.(*types.TypeName), nil, nil)
+
+ // but record the existing type, if any
+ t := obj.Type().(*types.Named)
+ p.record(t)
+
+ // read underlying type
+ t0.SetUnderlying(p.typ())
+
+ // read associated methods
+ for i, n := 0, p.int(); i < n; i++ {
+ t0.AddMethod(types.NewFunc(token.NoPos, pkg, p.string(), p.typ().(*types.Signature)))
+ }
+
+ return t
+
+ default:
+ panic(fmt.Sprintf("unexpected type tag %d", i))
+ }
+}
+
+func deref(typ types.Type) types.Type {
+ if p, _ := typ.(*types.Pointer); p != nil {
+ return p.Elem()
+ }
+ return typ
+}
+
+func (p *importer) field() *types.Var {
+ pkg, name := p.qualifiedName()
+ typ := p.typ()
+
+ anonymous := false
+ if name == "" {
+ // anonymous field - typ must be T or *T and T must be a type name
+ switch typ := deref(typ).(type) {
+ case *types.Basic: // basic types are named types
+ pkg = nil
+ name = typ.Name()
+ case *types.Named:
+ obj := typ.Obj()
+ name = obj.Name()
+ // correct the field package for anonymous fields
+ if exported(name) {
+ pkg = p.pkgList[0]
+ }
+ default:
+ panic("anonymous field expected")
+ }
+ anonymous = true
+ }
+
+ return types.NewField(token.NoPos, pkg, name, typ, anonymous)
+}
+
+func (p *importer) qualifiedName() (*types.Package, string) {
+ name := p.string()
+ pkg := p.pkgList[0] // exported names assume current package
+ if !exported(name) {
+ pkg = p.pkg()
+ }
+ return pkg, name
+}
+
+func (p *importer) signature() *types.Signature {
+ var recv *types.Var
+ if p.int() != 0 {
+ recv = p.param()
+ }
+ return types.NewSignature(recv, p.tuple(), p.tuple(), p.int() != 0)
+}
+
+func (p *importer) param() *types.Var {
+ return types.NewVar(token.NoPos, nil, p.string(), p.typ())
+}
+
+func (p *importer) tuple() *types.Tuple {
+ vars := make([]*types.Var, p.int())
+ for i := range vars {
+ vars[i] = p.param()
+ }
+ return types.NewTuple(vars...)
+}
+
+// ----------------------------------------------------------------------------
+// decoders
+
+func (p *importer) string() string {
+ return string(p.bytes())
+}
+
+func (p *importer) int() int {
+ return int(p.int64())
+}
+
+func (p *importer) int64() int64 {
+ if debug {
+ p.marker('i')
+ }
+
+ return p.rawInt64()
+}
+
+// Note: bytes() returns the respective byte slice w/o copy.
+func (p *importer) bytes() []byte {
+ if debug {
+ p.marker('b')
+ }
+
+ var b []byte
+ if n := int(p.rawInt64()); n > 0 {
+ b = p.data[:n]
+ p.data = p.data[n:]
+ }
+ return b
+}
+
+func (p *importer) marker(want byte) {
+ if debug {
+ if got := p.data[0]; got != want {
+ panic(fmt.Sprintf("incorrect marker: got %c; want %c (pos = %d)", got, want, p.consumed()))
+ }
+ p.data = p.data[1:]
+
+ pos := p.consumed()
+ if n := int(p.rawInt64()); n != pos {
+ panic(fmt.Sprintf("incorrect position: got %d; want %d", n, pos))
+ }
+ }
+}
+
+// rawInt64 should only be used by low-level decoders
+func (p *importer) rawInt64() int64 {
+ i, n := binary.Varint(p.data)
+ p.data = p.data[n:]
+ return i
+}
+
+func (p *importer) consumed() int {
+ return p.datalen - len(p.data)
+}
diff --git a/go/importer/import_test.go b/go/importer/import_test.go
new file mode 100644
index 0000000..3a2560c
--- /dev/null
+++ b/go/importer/import_test.go
@@ -0,0 +1,382 @@
+// 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 importer
+
+import (
+ "bufio"
+ "bytes"
+ "fmt"
+ "go/ast"
+ "go/build"
+ "go/parser"
+ "go/token"
+ "os"
+ "path/filepath"
+ "runtime"
+ "sort"
+ "strconv"
+ "testing"
+ "time"
+
+ "golang.org/x/tools/go/gcimporter"
+ "golang.org/x/tools/go/types"
+)
+
+var fset = token.NewFileSet()
+
+var tests = []string{
+ `package p`,
+
+ // consts
+ `package p; const X = true`,
+ `package p; const X, y, Z = true, false, 0 != 0`,
+ `package p; const ( A float32 = 1<<iota; B; C; D)`,
+ `package p; const X = "foo"`,
+ `package p; const X string = "foo"`,
+ `package p; const X = 0`,
+ `package p; const X = -42`,
+ `package p; const X = 3.14159265`,
+ `package p; const X = -1e-10`,
+ `package p; const X = 1.2 + 2.3i`,
+ `package p; const X = -1i`,
+ `package p; import "math"; const Pi = math.Pi`,
+ `package p; import m "math"; const Pi = m.Pi`,
+
+ // types
+ `package p; type T int`,
+ `package p; type T [10]int`,
+ `package p; type T []int`,
+ `package p; type T struct{}`,
+ `package p; type T struct{x int}`,
+ `package p; type T *int`,
+ `package p; type T func()`,
+ `package p; type T *T`,
+ `package p; type T interface{}`,
+ `package p; type T interface{ foo() }`,
+ `package p; type T interface{ m() T }`,
+ // TODO(gri) disabled for now - import/export works but
+ // types.Type.String() used in the test cannot handle cases
+ // like this yet
+ // `package p; type T interface{ m() interface{T} }`,
+ `package p; type T map[string]bool`,
+ `package p; type T chan int`,
+ `package p; type T <-chan complex64`,
+ `package p; type T chan<- map[int]string`,
+ // test case for issue 8177
+ `package p; type T1 interface { F(T2) }; type T2 interface { T1 }`,
+
+ // vars
+ `package p; var X int`,
+ `package p; var X, Y, Z struct{f int "tag"}`,
+
+ // funcs
+ `package p; func F()`,
+ `package p; func F(x int, y struct{}) bool`,
+ `package p; type T int; func (*T) F(x int, y struct{}) T`,
+
+ // selected special cases
+ `package p; type T int`,
+ `package p; type T uint8`,
+ `package p; type T byte`,
+ `package p; type T error`,
+ `package p; import "net/http"; type T http.Client`,
+ `package p; import "net/http"; type ( T1 http.Client; T2 struct { http.Client } )`,
+ `package p; import "unsafe"; type ( T1 unsafe.Pointer; T2 unsafe.Pointer )`,
+ `package p; import "unsafe"; type T struct { p unsafe.Pointer }`,
+}
+
+func TestImportSrc(t *testing.T) {
+ for _, src := range tests {
+ pkg, err := pkgForSource(src)
+ if err != nil {
+ t.Errorf("typecheck failed: %s", err)
+ continue
+ }
+ testExportImport(t, pkg, "")
+ }
+}
+
+func TestImportStdLib(t *testing.T) {
+ start := time.Now()
+
+ libs, err := stdLibs()
+ if err != nil {
+ t.Fatalf("could not compute list of std libraries: %s", err)
+ }
+ if len(libs) < 100 {
+ t.Fatalf("only %d std libraries found - something's not right", len(libs))
+ }
+
+ // make sure printed go/types types and gc-imported types
+ // can be compared reasonably well
+ types.GcCompatibilityMode = true
+
+ var totSize, totGcSize int
+ for _, lib := range libs {
+ // limit run time for short tests
+ if testing.Short() && time.Since(start) >= 750*time.Millisecond {
+ return
+ }
+
+ pkg, err := pkgForPath(lib)
+ switch err := err.(type) {
+ case nil:
+ // ok
+ case *build.NoGoError:
+ // no Go files - ignore
+ continue
+ default:
+ t.Errorf("typecheck failed: %s", err)
+ continue
+ }
+
+ size, gcsize := testExportImport(t, pkg, lib)
+ if gcsize == 0 {
+ // if gc import didn't happen, assume same size
+ // (and avoid division by zero below)
+ gcsize = size
+ }
+
+ if testing.Verbose() {
+ fmt.Printf("%s\t%d\t%d\t%d%%\n", lib, size, gcsize, int(float64(size)*100/float64(gcsize)))
+ }
+ totSize += size
+ totGcSize += gcsize
+ }
+
+ if testing.Verbose() {
+ fmt.Printf("\n%d\t%d\t%d%%\n", totSize, totGcSize, int(float64(totSize)*100/float64(totGcSize)))
+ }
+
+ types.GcCompatibilityMode = false
+}
+
+func testExportImport(t *testing.T, pkg0 *types.Package, path string) (size, gcsize int) {
+ data := ExportData(pkg0)
+ size = len(data)
+
+ imports := make(map[string]*types.Package)
+ n, pkg1, err := ImportData(imports, data)
+ if err != nil {
+ t.Errorf("package %s: import failed: %s", pkg0.Name(), err)
+ return
+ }
+ if n != size {
+ t.Errorf("package %s: not all input data consumed", pkg0.Name())
+ return
+ }
+
+ s0 := pkgString(pkg0)
+ s1 := pkgString(pkg1)
+ if s1 != s0 {
+ t.Errorf("package %s: \nimport got:\n%s\nwant:\n%s\n", pkg0.Name(), s1, s0)
+ }
+
+ // If we have a standard library, compare also against the gcimported package.
+ if path == "" {
+ return // not std library
+ }
+
+ gcdata, err := gcExportData(path)
+ if err != nil {
+ if pkg0.Name() == "main" {
+ return // no export data present for main package
+ }
+ t.Errorf("package %s: couldn't get export data: %s", pkg0.Name(), err)
+ }
+ gcsize = len(gcdata)
+
+ imports = make(map[string]*types.Package)
+ pkg2, err := gcImportData(imports, gcdata, path)
+ if err != nil {
+ t.Errorf("package %s: gcimport failed: %s", pkg0.Name(), err)
+ return
+ }
+
+ s2 := pkgString(pkg2)
+ if s2 != s0 {
+ t.Errorf("package %s: \ngcimport got:\n%s\nwant:\n%s\n", pkg0.Name(), s2, s0)
+ }
+
+ return
+}
+
+func pkgForSource(src string) (*types.Package, error) {
+ f, err := parser.ParseFile(fset, "", src, 0)
+ if err != nil {
+ return nil, err
+ }
+ return typecheck("import-test", f)
+}
+
+func pkgForPath(path string) (*types.Package, error) {
+ // collect filenames
+ ctxt := build.Default
+ pkginfo, err := ctxt.Import(path, "", 0)
+ if err != nil {
+ return nil, err
+ }
+ filenames := append(pkginfo.GoFiles, pkginfo.CgoFiles...)
+
+ // parse files
+ files := make([]*ast.File, len(filenames))
+ for i, filename := range filenames {
+ var err error
+ files[i], err = parser.ParseFile(fset, filepath.Join(pkginfo.Dir, filename), nil, 0)
+ if err != nil {
+ return nil, err
+ }
+ }
+
+ return typecheck(path, files...)
+}
+
+var defaultConf = types.Config{
+ // we only care about exports and thus can ignore function bodies
+ IgnoreFuncBodies: true,
+ // work around C imports if possible
+ FakeImportC: true,
+ // strconv exports IntSize as a constant. The type-checker must
+ // use the same word size otherwise the result of the type-checker
+ // and gc imports is different. We don't care about alignment
+ // since none of the tests have exported constants depending
+ // on alignment (see also issue 8366).
+ Sizes: &types.StdSizes{WordSize: strconv.IntSize / 8, MaxAlign: 8},
+}
+
+func typecheck(path string, files ...*ast.File) (*types.Package, error) {
+ return defaultConf.Check(path, fset, files, nil)
+}
+
+// pkgString returns a string representation of a package's exported interface.
+func pkgString(pkg *types.Package) string {
+ var buf bytes.Buffer
+
+ fmt.Fprintf(&buf, "package %s\n", pkg.Name())
+
+ scope := pkg.Scope()
+ for _, name := range scope.Names() {
+ if exported(name) {
+ obj := scope.Lookup(name)
+ buf.WriteString(obj.String())
+
+ switch obj := obj.(type) {
+ case *types.Const:
+ // For now only print constant values if they are not float
+ // or complex. This permits comparing go/types results with
+ // gc-generated gcimported package interfaces.
+ info := obj.Type().Underlying().(*types.Basic).Info()
+ if info&types.IsFloat == 0 && info&types.IsComplex == 0 {
+ fmt.Fprintf(&buf, " = %s", obj.Val())
+ }
+
+ case *types.TypeName:
+ // Print associated methods.
+ // Basic types (e.g., unsafe.Pointer) have *types.Basic
+ // type rather than *types.Named; so we need to check.
+ if typ, _ := obj.Type().(*types.Named); typ != nil {
+ if n := typ.NumMethods(); n > 0 {
+ // Sort methods by name so that we get the
+ // same order independent of whether the
+ // methods got imported or coming directly
+ // for the source.
+ // TODO(gri) This should probably be done
+ // in go/types.
+ list := make([]*types.Func, n)
+ for i := 0; i < n; i++ {
+ list[i] = typ.Method(i)
+ }
+ sort.Sort(byName(list))
+
+ buf.WriteString("\nmethods (\n")
+ for _, m := range list {
+ fmt.Fprintf(&buf, "\t%s\n", m)
+ }
+ buf.WriteString(")")
+ }
+ }
+ }
+ buf.WriteByte('\n')
+ }
+ }
+
+ return buf.String()
+}
+
+var stdLibRoot = filepath.Join(runtime.GOROOT(), "src") + string(filepath.Separator)
+
+// The following std libraries are excluded from the stdLibs list.
+var excluded = map[string]bool{
+ "builtin": true, // contains type declarations with cycles
+ "unsafe": true, // contains fake declarations
+}
+
+// stdLibs returns the list of standard library package paths.
+func stdLibs() (list []string, err error) {
+ err = filepath.Walk(stdLibRoot, func(path string, info os.FileInfo, err error) error {
+ if err == nil && info.IsDir() {
+ // testdata directories don't contain importable libraries
+ if info.Name() == "testdata" {
+ return filepath.SkipDir
+ }
+ pkgPath := path[len(stdLibRoot):] // remove stdLibRoot
+ if len(pkgPath) > 0 && !excluded[pkgPath] {
+ list = append(list, pkgPath)
+ }
+ }
+ return nil
+ })
+ return
+}
+
+type byName []*types.Func
+
+func (a byName) Len() int { return len(a) }
+func (a byName) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
+func (a byName) Less(i, j int) bool { return a[i].Name() < a[j].Name() }
+
+// gcExportData returns the gc-generated export data for the given path.
+// It is based on a trimmed-down version of gcimporter.Import which does
+// not do the actual import, does not handle package unsafe, and assumes
+// that path is a correct standard library package path (no canonicalization,
+// or handling of local import paths).
+func gcExportData(path string) ([]byte, error) {
+ filename, id := gcimporter.FindPkg(path, "")
+ if filename == "" {
+ return nil, fmt.Errorf("can't find import: %s", path)
+ }
+ if id != path {
+ panic("path should be canonicalized")
+ }
+
+ f, err := os.Open(filename)
+ if err != nil {
+ return nil, err
+ }
+ defer f.Close()
+
+ buf := bufio.NewReader(f)
+ if err = gcimporter.FindExportData(buf); err != nil {
+ return nil, err
+ }
+
+ var data []byte
+ for {
+ line, err := buf.ReadBytes('\n')
+ if err != nil {
+ return nil, err
+ }
+ data = append(data, line...)
+ // export data ends in "$$\n"
+ if len(line) == 3 && line[0] == '$' && line[1] == '$' {
+ return data, nil
+ }
+ }
+}
+
+func gcImportData(imports map[string]*types.Package, data []byte, path string) (*types.Package, error) {
+ filename := fmt.Sprintf("<filename for %s>", path) // so we have a decent error message if necessary
+ return gcimporter.ImportData(imports, filename, path, bufio.NewReader(bytes.NewBuffer(data)))
+}
diff --git a/go/importer/predefined.go b/go/importer/predefined.go
new file mode 100644
index 0000000..b23dfcb
--- /dev/null
+++ b/go/importer/predefined.go
@@ -0,0 +1,84 @@
+// 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 importer
+
+import "golang.org/x/tools/go/types"
+
+const (
+ magic = "\n$$ exports $$\n"
+ version = "v0"
+)
+
+// Tags. Must be < 0.
+const (
+ // Packages
+ packageTag = -(iota + 1)
+
+ // Objects
+ constTag
+ typeTag
+ varTag
+ funcTag
+
+ // Types
+ arrayTag
+ sliceTag
+ structTag
+ pointerTag
+ signatureTag
+ interfaceTag
+ mapTag
+ chanTag
+ namedTag
+
+ // Values
+ falseTag
+ trueTag
+ int64Tag
+ floatTag
+ fractionTag
+ complexTag
+ stringTag
+)
+
+var predeclared = []types.Type{
+ // basic types
+ types.Typ[types.Bool],
+ types.Typ[types.Int],
+ types.Typ[types.Int8],
+ types.Typ[types.Int16],
+ types.Typ[types.Int32],
+ types.Typ[types.Int64],
+ types.Typ[types.Uint],
+ types.Typ[types.Uint8],
+ types.Typ[types.Uint16],
+ types.Typ[types.Uint32],
+ types.Typ[types.Uint64],
+ types.Typ[types.Uintptr],
+ types.Typ[types.Float32],
+ types.Typ[types.Float64],
+ types.Typ[types.Complex64],
+ types.Typ[types.Complex128],
+ types.Typ[types.String],
+
+ // untyped types
+ types.Typ[types.UntypedBool],
+ types.Typ[types.UntypedInt],
+ types.Typ[types.UntypedRune],
+ types.Typ[types.UntypedFloat],
+ types.Typ[types.UntypedComplex],
+ types.Typ[types.UntypedString],
+ types.Typ[types.UntypedNil],
+
+ // package unsafe
+ types.Typ[types.UnsafePointer],
+
+ // aliases
+ types.Universe.Lookup("byte").Type(),
+ types.Universe.Lookup("rune").Type(),
+
+ // error
+ types.Universe.Lookup("error").Type(),
+}
diff --git a/go/loader/cgo.go b/go/loader/cgo.go
new file mode 100644
index 0000000..fb39e53
--- /dev/null
+++ b/go/loader/cgo.go
@@ -0,0 +1,199 @@
+package loader
+
+// This file handles cgo preprocessing of files containing `import "C"`.
+//
+// DESIGN
+//
+// The approach taken is to run the cgo processor on the package's
+// CgoFiles and parse the output, faking the filenames of the
+// resulting ASTs so that the synthetic file containing the C types is
+// called "C" (e.g. "~/go/src/net/C") and the preprocessed files
+// have their original names (e.g. "~/go/src/net/cgo_unix.go"),
+// not the names of the actual temporary files.
+//
+// The advantage of this approach is its fidelity to 'go build'. The
+// downside is that the token.Position.Offset for each AST node is
+// incorrect, being an offset within the temporary file. Line numbers
+// should still be correct because of the //line comments.
+//
+// The logic of this file is mostly plundered from the 'go build'
+// tool, which also invokes the cgo preprocessor.
+//
+//
+// REJECTED ALTERNATIVE
+//
+// An alternative approach that we explored is to extend go/types'
+// Importer mechanism to provide the identity of the importing package
+// so that each time `import "C"` appears it resolves to a different
+// synthetic package containing just the objects needed in that case.
+// The loader would invoke cgo but parse only the cgo_types.go file
+// defining the package-level objects, discarding the other files
+// resulting from preprocessing.
+//
+// The benefit of this approach would have been that source-level
+// syntax information would correspond exactly to the original cgo
+// file, with no preprocessing involved, making source tools like
+// godoc, oracle, and eg happy. However, the approach was rejected
+// due to the additional complexity it would impose on go/types. (It
+// made for a beautiful demo, though.)
+//
+// cgo files, despite their *.go extension, are not legal Go source
+// files per the specification since they may refer to unexported
+// members of package "C" such as C.int. Also, a function such as
+// C.getpwent has in effect two types, one matching its C type and one
+// which additionally returns (errno C.int). The cgo preprocessor
+// uses name mangling to distinguish these two functions in the
+// processed code, but go/types would need to duplicate this logic in
+// its handling of function calls, analogous to the treatment of map
+// lookups in which y=m[k] and y,ok=m[k] are both legal.
+
+import (
+ "fmt"
+ "go/ast"
+ "go/build"
+ "go/parser"
+ "go/token"
+ "io/ioutil"
+ "log"
+ "os"
+ "os/exec"
+ "path/filepath"
+ "regexp"
+ "strings"
+)
+
+// processCgoFiles invokes the cgo preprocessor on bp.CgoFiles, parses
+// the output and returns the resulting ASTs.
+//
+func processCgoFiles(bp *build.Package, fset *token.FileSet, DisplayPath func(path string) string, mode parser.Mode) ([]*ast.File, error) {
+ tmpdir, err := ioutil.TempDir("", strings.Replace(bp.ImportPath, "/", "_", -1)+"_C")
+ if err != nil {
+ return nil, err
+ }
+ defer os.RemoveAll(tmpdir)
+
+ pkgdir := bp.Dir
+ if DisplayPath != nil {
+ pkgdir = DisplayPath(pkgdir)
+ }
+
+ cgoFiles, cgoDisplayFiles, err := runCgo(bp, pkgdir, tmpdir)
+ if err != nil {
+ return nil, err
+ }
+ var files []*ast.File
+ for i := range cgoFiles {
+ rd, err := os.Open(cgoFiles[i])
+ if err != nil {
+ return nil, err
+ }
+ display := filepath.Join(bp.Dir, cgoDisplayFiles[i])
+ f, err := parser.ParseFile(fset, display, rd, mode)
+ rd.Close()
+ if err != nil {
+ return nil, err
+ }
+ files = append(files, f)
+ }
+ return files, nil
+}
+
+var cgoRe = regexp.MustCompile(`[/\\:]`)
+
+// runCgo invokes the cgo preprocessor on bp.CgoFiles and returns two
+// lists of files: the resulting processed files (in temporary
+// directory tmpdir) and the corresponding names of the unprocessed files.
+//
+// runCgo is adapted from (*builder).cgo in
+// $GOROOT/src/cmd/go/build.go, but these features are unsupported:
+// pkg-config, Objective C, CGOPKGPATH, CGO_FLAGS.
+//
+func runCgo(bp *build.Package, pkgdir, tmpdir string) (files, displayFiles []string, err error) {
+ cgoCPPFLAGS, _, _, _ := cflags(bp, true)
+ _, cgoexeCFLAGS, _, _ := cflags(bp, false)
+
+ if len(bp.CgoPkgConfig) > 0 {
+ return nil, nil, fmt.Errorf("cgo pkg-config not supported")
+ }
+
+ // Allows including _cgo_export.h from .[ch] files in the package.
+ cgoCPPFLAGS = append(cgoCPPFLAGS, "-I", tmpdir)
+
+ // _cgo_gotypes.go (displayed "C") contains the type definitions.
+ files = append(files, filepath.Join(tmpdir, "_cgo_gotypes.go"))
+ displayFiles = append(displayFiles, "C")
+ for _, fn := range bp.CgoFiles {
+ // "foo.cgo1.go" (displayed "foo.go") is the processed Go source.
+ f := cgoRe.ReplaceAllString(fn[:len(fn)-len("go")], "_")
+ files = append(files, filepath.Join(tmpdir, f+"cgo1.go"))
+ displayFiles = append(displayFiles, fn)
+ }
+
+ var cgoflags []string
+ if bp.Goroot && bp.ImportPath == "runtime/cgo" {
+ cgoflags = append(cgoflags, "-import_runtime_cgo=false")
+ }
+ if bp.Goroot && bp.ImportPath == "runtime/race" || bp.ImportPath == "runtime/cgo" {
+ cgoflags = append(cgoflags, "-import_syscall=false")
+ }
+
+ args := stringList(
+ "go", "tool", "cgo", "-objdir", tmpdir, cgoflags, "--",
+ cgoCPPFLAGS, cgoexeCFLAGS, bp.CgoFiles,
+ )
+ if false {
+ log.Printf("Running cgo for package %q: %s (dir=%s)", bp.ImportPath, args, pkgdir)
+ }
+ cmd := exec.Command(args[0], args[1:]...)
+ cmd.Dir = pkgdir
+ cmd.Stdout = os.Stderr
+ cmd.Stderr = os.Stderr
+ if err := cmd.Run(); err != nil {
+ return nil, nil, fmt.Errorf("cgo failed: %s: %s", args, err)
+ }
+
+ return files, displayFiles, nil
+}
+
+// -- unmodified from 'go build' ---------------------------------------
+
+// Return the flags to use when invoking the C or C++ compilers, or cgo.
+func cflags(p *build.Package, def bool) (cppflags, cflags, cxxflags, ldflags []string) {
+ var defaults string
+ if def {
+ defaults = "-g -O2"
+ }
+
+ cppflags = stringList(envList("CGO_CPPFLAGS", ""), p.CgoCPPFLAGS)
+ cflags = stringList(envList("CGO_CFLAGS", defaults), p.CgoCFLAGS)
+ cxxflags = stringList(envList("CGO_CXXFLAGS", defaults), p.CgoCXXFLAGS)
+ ldflags = stringList(envList("CGO_LDFLAGS", defaults), p.CgoLDFLAGS)
+ return
+}
+
+// envList returns the value of the given environment variable broken
+// into fields, using the default value when the variable is empty.
+func envList(key, def string) []string {
+ v := os.Getenv(key)
+ if v == "" {
+ v = def
+ }
+ return strings.Fields(v)
+}
+
+// stringList's arguments should be a sequence of string or []string values.
+// stringList flattens them into a single []string.
+func stringList(args ...interface{}) []string {
+ var x []string
+ for _, arg := range args {
+ switch arg := arg.(type) {
+ case []string:
+ x = append(x, arg...)
+ case string:
+ x = append(x, arg)
+ default:
+ panic("stringList: invalid argument")
+ }
+ }
+ return x
+}
diff --git a/go/loader/doc.go b/go/loader/doc.go
new file mode 100644
index 0000000..1ff4b15
--- /dev/null
+++ b/go/loader/doc.go
@@ -0,0 +1,189 @@
+// 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 loader loads a complete Go program from source code, parsing
+// and type-checking the initial packages plus their transitive closure
+// of dependencies. The ASTs and the derived facts are retained for
+// later use.
+//
+// THIS INTERFACE IS EXPERIMENTAL AND IS LIKELY TO CHANGE.
+//
+// The package defines two primary types: Config, which specifies a
+// set of initial packages to load and various other options; and
+// Program, which is the result of successfully loading the packages
+// specified by a configuration.
+//
+// The configuration can be set directly, but *Config provides various
+// convenience methods to simplify the common cases, each of which can
+// be called any number of times. Finally, these are followed by a
+// call to Load() to actually load and type-check the program.
+//
+// var conf loader.Config
+//
+// // Use the command-line arguments to specify
+// // a set of initial packages to load from source.
+// // See FromArgsUsage for help.
+// rest, err := conf.FromArgs(os.Args[1:], wantTests)
+//
+// // Parse the specified files and create an ad hoc package with path "foo".
+// // All files must have the same 'package' declaration.
+// conf.CreateFromFilenames("foo", "foo.go", "bar.go")
+//
+// // Create an ad hoc package with path "foo" from
+// // the specified already-parsed files.
+// // All ASTs must have the same 'package' declaration.
+// conf.CreateFromFiles("foo", parsedFiles)
+//
+// // Add "runtime" to the set of packages to be loaded.
+// conf.Import("runtime")
+//
+// // Adds "fmt" and "fmt_test" to the set of packages
+// // to be loaded. "fmt" will include *_test.go files.
+// conf.ImportWithTests("fmt")
+//
+// // Finally, load all the packages specified by the configuration.
+// prog, err := conf.Load()
+//
+// See examples_test.go for examples of API usage.
+//
+//
+// CONCEPTS AND TERMINOLOGY
+//
+// An AD HOC package is one specified as a set of source files on the
+// command line. In the simplest case, it may consist of a single file
+// such as $GOROOT/src/net/http/triv.go.
+//
+// EXTERNAL TEST packages are those comprised of a set of *_test.go
+// files all with the same 'package foo_test' declaration, all in the
+// same directory. (go/build.Package calls these files XTestFiles.)
+//
+// An IMPORTABLE package is one that can be referred to by some import
+// spec. The Path() of each importable package is unique within a
+// Program.
+//
+// ad hoc packages and external test packages are NON-IMPORTABLE. The
+// Path() of an ad hoc package is inferred from the package
+// declarations of its files and is therefore not a unique package key.
+// For example, Config.CreatePkgs may specify two initial ad hoc
+// packages both called "main".
+//
+// An AUGMENTED package is an importable package P plus all the
+// *_test.go files with same 'package foo' declaration as P.
+// (go/build.Package calls these files TestFiles.)
+//
+// The INITIAL packages are those specified in the configuration. A
+// DEPENDENCY is a package loaded to satisfy an import in an initial
+// package or another dependency.
+//
+package loader
+
+// IMPLEMENTATION NOTES
+//
+// 'go test', in-package test files, and import cycles
+// ---------------------------------------------------
+//
+// An external test package may depend upon members of the augmented
+// package that are not in the unaugmented package, such as functions
+// that expose internals. (See bufio/export_test.go for an example.)
+// So, the loader must ensure that for each external test package
+// it loads, it also augments the corresponding non-test package.
+//
+// The import graph over n unaugmented packages must be acyclic; the
+// import graph over n-1 unaugmented packages plus one augmented
+// package must also be acyclic. ('go test' relies on this.) But the
+// import graph over n augmented packages may contain cycles.
+//
+// First, all the (unaugmented) non-test packages and their
+// dependencies are imported in the usual way; the loader reports an
+// error if it detects an import cycle.
+//
+// Then, each package P for which testing is desired is augmented by
+// the list P' of its in-package test files, by calling
+// (*types.Checker).Files. This arrangement ensures that P' may
+// reference definitions within P, but P may not reference definitions
+// within P'. Furthermore, P' may import any other package, including
+// ones that depend upon P, without an import cycle error.
+//
+// Consider two packages A and B, both of which have lists of
+// in-package test files we'll call A' and B', and which have the
+// following import graph edges:
+// B imports A
+// B' imports A
+// A' imports B
+// This last edge would be expected to create an error were it not
+// for the special type-checking discipline above.
+// Cycles of size greater than two are possible. For example:
+// compress/bzip2/bzip2_test.go (package bzip2) imports "io/ioutil"
+// io/ioutil/tempfile_test.go (package ioutil) imports "regexp"
+// regexp/exec_test.go (package regexp) imports "compress/bzip2"
+//
+//
+// Concurrency
+// -----------
+//
+// Let us define the import dependency graph as follows. Each node is a
+// list of files passed to (Checker).Files at once. Many of these lists
+// are the production code of an importable Go package, so those nodes
+// are labelled by the package's import path. The remaining nodes are
+// ad hoc packages and lists of in-package *_test.go files that augment
+// an importable package; those nodes have no label.
+//
+// The edges of the graph represent import statements appearing within a
+// file. An edge connects a node (a list of files) to the node it
+// imports, which is importable and thus always labelled.
+//
+// Loading is controlled by this dependency graph.
+//
+// To reduce I/O latency, we start loading a package's dependencies
+// asynchronously as soon as we've parsed its files and enumerated its
+// imports (scanImports). This performs a preorder traversal of the
+// import dependency graph.
+//
+// To exploit hardware parallelism, we type-check unrelated packages in
+// parallel, where "unrelated" means not ordered by the partial order of
+// the import dependency graph.
+//
+// We use a concurrency-safe blocking cache (importer.imported) to
+// record the results of type-checking, whether success or failure. An
+// entry is created in this cache by startLoad the first time the
+// package is imported. The first goroutine to request an entry becomes
+// responsible for completing the task and broadcasting completion to
+// subsequent requestors, which block until then.
+//
+// Type checking occurs in (parallel) postorder: we cannot type-check a
+// set of files until we have loaded and type-checked all of their
+// immediate dependencies (and thus all of their transitive
+// dependencies). If the input were guaranteed free of import cycles,
+// this would be trivial: we could simply wait for completion of the
+// dependencies and then invoke the typechecker.
+//
+// But as we saw in the 'go test' section above, some cycles in the
+// import graph over packages are actually legal, so long as the
+// cycle-forming edge originates in the in-package test files that
+// augment the package. This explains why the nodes of the import
+// dependency graph are not packages, but lists of files: the unlabelled
+// nodes avoid the cycles. Consider packages A and B where B imports A
+// and A's in-package tests AT import B. The naively constructed import
+// graph over packages would contain a cycle (A+AT) --> B --> (A+AT) but
+// the graph over lists of files is AT --> B --> A, where AT is an
+// unlabelled node.
+//
+// Awaiting completion of the dependencies in a cyclic graph would
+// deadlock, so we must materialize the import dependency graph (as
+// importer.graph) and check whether each import edge forms a cycle. If
+// x imports y, and the graph already contains a path from y to x, then
+// there is an import cycle, in which case the processing of x must not
+// wait for the completion of processing of y.
+//
+// When the type-checker makes a callback (doImport) to the loader for a
+// given import edge, there are two possible cases. In the normal case,
+// the dependency has already been completely type-checked; doImport
+// does a cache lookup and returns it. In the cyclic case, the entry in
+// the cache is still necessarily incomplete, indicating a cycle. We
+// perform the cycle check again to obtain the error message, and return
+// the error.
+//
+// The result of using concurrency is about a 2.5x speedup for stdlib_test.
+
+// TODO(adonovan): overhaul the package documentation.
diff --git a/go/loader/example14_test.go b/go/loader/example14_test.go
new file mode 100644
index 0000000..76d5ea6
--- /dev/null
+++ b/go/loader/example14_test.go
@@ -0,0 +1,173 @@
+// 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.
+
+// +build !go1.5
+// +build !windows
+
+package loader_test
+
+import (
+ "fmt"
+ "go/token"
+ "log"
+ "path/filepath"
+ "runtime"
+ "sort"
+
+ "golang.org/x/tools/go/loader"
+)
+
+func printProgram(prog *loader.Program) {
+ // Created packages are the initial packages specified by a call
+ // to CreateFromFilenames or CreateFromFiles.
+ var names []string
+ for _, info := range prog.Created {
+ names = append(names, info.Pkg.Path())
+ }
+ fmt.Printf("created: %s\n", names)
+
+ // Imported packages are the initial packages specified by a
+ // call to Import or ImportWithTests.
+ names = nil
+ for _, info := range prog.Imported {
+ names = append(names, info.Pkg.Path())
+ }
+ sort.Strings(names)
+ fmt.Printf("imported: %s\n", names)
+
+ // InitialPackages contains the union of created and imported.
+ names = nil
+ for _, info := range prog.InitialPackages() {
+ names = append(names, info.Pkg.Path())
+ }
+ sort.Strings(names)
+ fmt.Printf("initial: %s\n", names)
+
+ // AllPackages contains all initial packages and their dependencies.
+ names = nil
+ for pkg := range prog.AllPackages {
+ names = append(names, pkg.Path())
+ }
+ sort.Strings(names)
+ fmt.Printf("all: %s\n", names)
+}
+
+func printFilenames(fset *token.FileSet, info *loader.PackageInfo) {
+ var names []string
+ for _, f := range info.Files {
+ names = append(names, filepath.Base(fset.File(f.Pos()).Name()))
+ }
+ fmt.Printf("%s.Files: %s\n", info.Pkg.Path(), names)
+}
+
+// This example loads a set of packages and all of their dependencies
+// from a typical command-line. FromArgs parses a command line and
+// makes calls to the other methods of Config shown in the examples that
+// follow.
+func ExampleConfig_FromArgs() {
+ args := []string{"mytool", "unicode/utf8", "errors", "runtime", "--", "foo", "bar"}
+ const wantTests = false
+
+ var conf loader.Config
+ rest, err := conf.FromArgs(args[1:], wantTests)
+ prog, err := conf.Load()
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ fmt.Printf("rest: %s\n", rest)
+ printProgram(prog)
+ // Output:
+ // rest: [foo bar]
+ // created: []
+ // imported: [errors runtime unicode/utf8]
+ // initial: [errors runtime unicode/utf8]
+ // all: [errors runtime unicode/utf8]
+}
+
+// This example creates and type-checks a single package (without tests)
+// from a list of filenames, and loads all of its dependencies.
+func ExampleConfig_CreateFromFilenames() {
+ var conf loader.Config
+ filename := filepath.Join(runtime.GOROOT(), "src/container/heap/heap.go")
+ conf.CreateFromFilenames("container/heap", filename)
+ prog, err := conf.Load()
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ printProgram(prog)
+ // Output:
+ // created: [container/heap]
+ // imported: []
+ // initial: [container/heap]
+ // all: [container/heap sort]
+}
+
+// In the examples below, for stability, the chosen packages are
+// relatively small, platform-independent, and low-level (and thus
+// infrequently changing).
+// The strconv package has internal and external tests.
+
+const hello = `package main
+
+import "fmt"
+
+func main() {
+ fmt.Println("Hello, world.")
+}
+`
+
+// This example creates and type-checks a package from a list of
+// already-parsed files, and loads all its dependencies.
+func ExampleConfig_CreateFromFiles() {
+ var conf loader.Config
+ f, err := conf.ParseFile("hello.go", hello)
+ if err != nil {
+ log.Fatal(err)
+ }
+ conf.CreateFromFiles("hello", f)
+ prog, err := conf.Load()
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ printProgram(prog)
+ printFilenames(prog.Fset, prog.Package("strconv"))
+ // Output:
+ // created: [hello]
+ // imported: []
+ // initial: [hello]
+ // all: [errors fmt hello io math os reflect runtime strconv sync sync/atomic syscall time unicode/utf8]
+ // strconv.Files: [atob.go atof.go atoi.go decimal.go extfloat.go ftoa.go isprint.go itoa.go quote.go]
+}
+
+// This example imports three packages, including the tests for one of
+// them, and loads all their dependencies.
+func ExampleConfig_Import() {
+ // ImportWithTest("strconv") causes strconv to include
+ // internal_test.go, and creates an external test package,
+ // strconv_test.
+ // (Compare with the example of CreateFromFiles.)
+
+ var conf loader.Config
+ conf.Import("unicode/utf8")
+ conf.Import("errors")
+ conf.ImportWithTests("strconv")
+ prog, err := conf.Load()
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ printProgram(prog)
+ printFilenames(prog.Fset, prog.Package("strconv"))
+ printFilenames(prog.Fset, prog.Package("strconv_test"))
+ // Output:
+ // created: [strconv_test]
+ // imported: [errors strconv unicode/utf8]
+ // initial: [errors strconv strconv_test unicode/utf8]
+ // all: [bufio bytes errors flag fmt io math math/rand os reflect runtime runtime/pprof sort strconv strconv_test strings sync sync/atomic syscall testing text/tabwriter time unicode unicode/utf8]
+ // strconv.Files: [atob.go atof.go atoi.go decimal.go extfloat.go ftoa.go isprint.go itoa.go quote.go internal_test.go]
+ // strconv_test.Files: [atob_test.go atof_test.go atoi_test.go decimal_test.go fp_test.go ftoa_test.go itoa_test.go quote_example_test.go quote_test.go strconv_test.go]
+}
diff --git a/go/loader/example_test.go b/go/loader/example_test.go
new file mode 100644
index 0000000..ce5afdb
--- /dev/null
+++ b/go/loader/example_test.go
@@ -0,0 +1,173 @@
+// 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.
+
+// +build go1.5
+// +build !windows
+
+package loader_test
+
+import (
+ "fmt"
+ "go/token"
+ "log"
+ "path/filepath"
+ "runtime"
+ "sort"
+
+ "golang.org/x/tools/go/loader"
+)
+
+func printProgram(prog *loader.Program) {
+ // Created packages are the initial packages specified by a call
+ // to CreateFromFilenames or CreateFromFiles.
+ var names []string
+ for _, info := range prog.Created {
+ names = append(names, info.Pkg.Path())
+ }
+ fmt.Printf("created: %s\n", names)
+
+ // Imported packages are the initial packages specified by a
+ // call to Import or ImportWithTests.
+ names = nil
+ for _, info := range prog.Imported {
+ names = append(names, info.Pkg.Path())
+ }
+ sort.Strings(names)
+ fmt.Printf("imported: %s\n", names)
+
+ // InitialPackages contains the union of created and imported.
+ names = nil
+ for _, info := range prog.InitialPackages() {
+ names = append(names, info.Pkg.Path())
+ }
+ sort.Strings(names)
+ fmt.Printf("initial: %s\n", names)
+
+ // AllPackages contains all initial packages and their dependencies.
+ names = nil
+ for pkg := range prog.AllPackages {
+ names = append(names, pkg.Path())
+ }
+ sort.Strings(names)
+ fmt.Printf("all: %s\n", names)
+}
+
+func printFilenames(fset *token.FileSet, info *loader.PackageInfo) {
+ var names []string
+ for _, f := range info.Files {
+ names = append(names, filepath.Base(fset.File(f.Pos()).Name()))
+ }
+ fmt.Printf("%s.Files: %s\n", info.Pkg.Path(), names)
+}
+
+// This example loads a set of packages and all of their dependencies
+// from a typical command-line. FromArgs parses a command line and
+// makes calls to the other methods of Config shown in the examples that
+// follow.
+func ExampleConfig_FromArgs() {
+ args := []string{"mytool", "unicode/utf8", "errors", "runtime", "--", "foo", "bar"}
+ const wantTests = false
+
+ var conf loader.Config
+ rest, err := conf.FromArgs(args[1:], wantTests)
+ prog, err := conf.Load()
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ fmt.Printf("rest: %s\n", rest)
+ printProgram(prog)
+ // Output:
+ // rest: [foo bar]
+ // created: []
+ // imported: [errors runtime unicode/utf8]
+ // initial: [errors runtime unicode/utf8]
+ // all: [errors runtime unicode/utf8]
+}
+
+// This example creates and type-checks a single package (without tests)
+// from a list of filenames, and loads all of its dependencies.
+func ExampleConfig_CreateFromFilenames() {
+ var conf loader.Config
+ filename := filepath.Join(runtime.GOROOT(), "src/container/heap/heap.go")
+ conf.CreateFromFilenames("container/heap", filename)
+ prog, err := conf.Load()
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ printProgram(prog)
+ // Output:
+ // created: [container/heap]
+ // imported: []
+ // initial: [container/heap]
+ // all: [container/heap sort]
+}
+
+// In the examples below, for stability, the chosen packages are
+// relatively small, platform-independent, and low-level (and thus
+// infrequently changing).
+// The strconv package has internal and external tests.
+
+const hello = `package main
+
+import "fmt"
+
+func main() {
+ fmt.Println("Hello, world.")
+}
+`
+
+// This example creates and type-checks a package from a list of
+// already-parsed files, and loads all its dependencies.
+func ExampleConfig_CreateFromFiles() {
+ var conf loader.Config
+ f, err := conf.ParseFile("hello.go", hello)
+ if err != nil {
+ log.Fatal(err)
+ }
+ conf.CreateFromFiles("hello", f)
+ prog, err := conf.Load()
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ printProgram(prog)
+ printFilenames(prog.Fset, prog.Package("strconv"))
+ // Output:
+ // created: [hello]
+ // imported: []
+ // initial: [hello]
+ // all: [errors fmt hello io math os reflect runtime strconv sync sync/atomic syscall time unicode/utf8]
+ // strconv.Files: [atob.go atof.go atoi.go decimal.go doc.go extfloat.go ftoa.go isprint.go itoa.go quote.go]
+}
+
+// This example imports three packages, including the tests for one of
+// them, and loads all their dependencies.
+func ExampleConfig_Import() {
+ // ImportWithTest("strconv") causes strconv to include
+ // internal_test.go, and creates an external test package,
+ // strconv_test.
+ // (Compare with the example of CreateFromFiles.)
+
+ var conf loader.Config
+ conf.Import("unicode/utf8")
+ conf.Import("errors")
+ conf.ImportWithTests("strconv")
+ prog, err := conf.Load()
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ printProgram(prog)
+ printFilenames(prog.Fset, prog.Package("strconv"))
+ printFilenames(prog.Fset, prog.Package("strconv_test"))
+ // Output:
+ // created: [strconv_test]
+ // imported: [errors strconv unicode/utf8]
+ // initial: [errors strconv strconv_test unicode/utf8]
+ // all: [bufio bytes errors flag fmt io log math math/rand os reflect runtime runtime/pprof runtime/trace sort strconv strconv_test strings sync sync/atomic syscall testing text/tabwriter time unicode unicode/utf8]
+ // strconv.Files: [atob.go atof.go atoi.go decimal.go doc.go extfloat.go ftoa.go isprint.go itoa.go quote.go internal_test.go]
+ // strconv_test.Files: [atob_test.go atof_test.go atoi_test.go decimal_test.go example_test.go fp_test.go ftoa_test.go itoa_test.go quote_test.go strconv_test.go]
+}
diff --git a/go/loader/loader.go b/go/loader/loader.go
new file mode 100644
index 0000000..1d3ead0
--- /dev/null
+++ b/go/loader/loader.go
@@ -0,0 +1,968 @@
+// 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 loader
+
+// See doc.go for package documentation and implementation notes.
+
+import (
+ "errors"
+ "fmt"
+ "go/ast"
+ "go/build"
+ "go/parser"
+ "go/token"
+ "os"
+ "sort"
+ "strings"
+ "sync"
+ "time"
+
+ "golang.org/x/tools/go/ast/astutil"
+ "golang.org/x/tools/go/types"
+)
+
+const trace = false // show timing info for type-checking
+
+// Config specifies the configuration for loading a whole program from
+// Go source code.
+// The zero value for Config is a ready-to-use default configuration.
+type Config struct {
+ // Fset is the file set for the parser to use when loading the
+ // program. If nil, it may be lazily initialized by any
+ // method of Config.
+ Fset *token.FileSet
+
+ // ParserMode specifies the mode to be used by the parser when
+ // loading source packages.
+ ParserMode parser.Mode
+
+ // TypeChecker contains options relating to the type checker.
+ //
+ // The supplied IgnoreFuncBodies is not used; the effective
+ // value comes from the TypeCheckFuncBodies func below.
+ // The supplied Import function is not used either.
+ TypeChecker types.Config
+
+ // TypeCheckFuncBodies is a predicate over package import
+ // paths. A package for which the predicate is false will
+ // have its package-level declarations type checked, but not
+ // its function bodies; this can be used to quickly load
+ // dependencies from source. If nil, all func bodies are type
+ // checked.
+ TypeCheckFuncBodies func(string) bool
+
+ // If Build is non-nil, it is used to locate source packages.
+ // Otherwise &build.Default is used.
+ //
+ // By default, cgo is invoked to preprocess Go files that
+ // import the fake package "C". This behaviour can be
+ // disabled by setting CGO_ENABLED=0 in the environment prior
+ // to startup, or by setting Build.CgoEnabled=false.
+ Build *build.Context
+
+ // The current directory, used for resolving relative package
+ // references such as "./go/loader". If empty, os.Getwd will be
+ // used instead.
+ Cwd string
+
+ // If DisplayPath is non-nil, it is used to transform each
+ // file name obtained from Build.Import(). This can be used
+ // to prevent a virtualized build.Config's file names from
+ // leaking into the user interface.
+ DisplayPath func(path string) string
+
+ // If AllowErrors is true, Load will return a Program even
+ // if some of the its packages contained I/O, parser or type
+ // errors; such errors are accessible via PackageInfo.Errors. If
+ // false, Load will fail if any package had an error.
+ AllowErrors bool
+
+ // CreatePkgs specifies a list of non-importable initial
+ // packages to create. The resulting packages will appear in
+ // the corresponding elements of the Program.Created slice.
+ CreatePkgs []PkgSpec
+
+ // ImportPkgs specifies a set of initial packages to load from
+ // source. The map keys are package import paths, used to
+ // locate the package relative to $GOROOT.
+ //
+ // The map value indicates whether to load tests. If true, Load
+ // will add and type-check two lists of files to the package:
+ // non-test files followed by in-package *_test.go files. In
+ // addition, it will append the external test package (if any)
+ // to Program.Created.
+ ImportPkgs map[string]bool
+
+ // FindPackage is called during Load to create the build.Package
+ // for a given import path. If nil, a default implementation
+ // based on ctxt.Import is used. A client may use this hook to
+ // adapt to a proprietary build system that does not follow the
+ // "go build" layout conventions, for example.
+ //
+ // It must be safe to call concurrently from multiple goroutines.
+ FindPackage func(ctxt *build.Context, importPath string) (*build.Package, error)
+}
+
+// A PkgSpec specifies a non-importable package to be created by Load.
+// Files are processed first, but typically only one of Files and
+// Filenames is provided. The path needn't be globally unique.
+//
+type PkgSpec struct {
+ Path string // import path ("" => use package declaration)
+ Files []*ast.File // ASTs of already-parsed files
+ Filenames []string // names of files to be parsed
+}
+
+// A Program is a Go program loaded from source as specified by a Config.
+type Program struct {
+ Fset *token.FileSet // the file set for this program
+
+ // Created[i] contains the initial package whose ASTs or
+ // filenames were supplied by Config.CreatePkgs[i], followed by
+ // the external test package, if any, of each package in
+ // Config.ImportPkgs ordered by ImportPath.
+ Created []*PackageInfo
+
+ // Imported contains the initially imported packages,
+ // as specified by Config.ImportPkgs.
+ Imported map[string]*PackageInfo
+
+ // AllPackages contains the PackageInfo of every package
+ // encountered by Load: all initial packages and all
+ // dependencies, including incomplete ones.
+ AllPackages map[*types.Package]*PackageInfo
+
+ // importMap is the canonical mapping of import paths to
+ // packages. It contains all Imported initial packages, but not
+ // Created ones, and all imported dependencies.
+ importMap map[string]*types.Package
+}
+
+// PackageInfo holds the ASTs and facts derived by the type-checker
+// for a single package.
+//
+// Not mutated once exposed via the API.
+//
+type PackageInfo struct {
+ Pkg *types.Package
+ Importable bool // true if 'import "Pkg.Path()"' would resolve to this
+ TransitivelyErrorFree bool // true if Pkg and all its dependencies are free of errors
+ Files []*ast.File // syntax trees for the package's files
+ Errors []error // non-nil if the package had errors
+ types.Info // type-checker deductions.
+
+ checker *types.Checker // transient type-checker state
+ errorFunc func(error)
+}
+
+func (info *PackageInfo) String() string { return info.Pkg.Path() }
+
+func (info *PackageInfo) appendError(err error) {
+ if info.errorFunc != nil {
+ info.errorFunc(err)
+ } else {
+ fmt.Fprintln(os.Stderr, err)
+ }
+ info.Errors = append(info.Errors, err)
+}
+
+func (conf *Config) fset() *token.FileSet {
+ if conf.Fset == nil {
+ conf.Fset = token.NewFileSet()
+ }
+ return conf.Fset
+}
+
+// ParseFile is a convenience function (intended for testing) that invokes
+// the parser using the Config's FileSet, which is initialized if nil.
+//
+// src specifies the parser input as a string, []byte, or io.Reader, and
+// filename is its apparent name. If src is nil, the contents of
+// filename are read from the file system.
+//
+func (conf *Config) ParseFile(filename string, src interface{}) (*ast.File, error) {
+ // TODO(adonovan): use conf.build() etc like parseFiles does.
+ return parser.ParseFile(conf.fset(), filename, src, conf.ParserMode)
+}
+
+// FromArgsUsage is a partial usage message that applications calling
+// FromArgs may wish to include in their -help output.
+const FromArgsUsage = `
+<args> is a list of arguments denoting a set of initial packages.
+It may take one of two forms:
+
+1. A list of *.go source files.
+
+ All of the specified files are loaded, parsed and type-checked
+ as a single package. All the files must belong to the same directory.
+
+2. A list of import paths, each denoting a package.
+
+ The package's directory is found relative to the $GOROOT and
+ $GOPATH using similar logic to 'go build', and the *.go files in
+ that directory are loaded, parsed and type-checked as a single
+ package.
+
+ In addition, all *_test.go files in the directory are then loaded
+ and parsed. Those files whose package declaration equals that of
+ the non-*_test.go files are included in the primary package. Test
+ files whose package declaration ends with "_test" are type-checked
+ as another package, the 'external' test package, so that a single
+ import path may denote two packages. (Whether this behaviour is
+ enabled is tool-specific, and may depend on additional flags.)
+
+A '--' argument terminates the list of packages.
+`
+
+// FromArgs interprets args as a set of initial packages to load from
+// source and updates the configuration. It returns the list of
+// unconsumed arguments.
+//
+// It is intended for use in command-line interfaces that require a
+// set of initial packages to be specified; see FromArgsUsage message
+// for details.
+//
+// Only superficial errors are reported at this stage; errors dependent
+// on I/O are detected during Load.
+//
+func (conf *Config) FromArgs(args []string, xtest bool) ([]string, error) {
+ var rest []string
+ for i, arg := range args {
+ if arg == "--" {
+ rest = args[i+1:]
+ args = args[:i]
+ break // consume "--" and return the remaining args
+ }
+ }
+
+ if len(args) > 0 && strings.HasSuffix(args[0], ".go") {
+ // Assume args is a list of a *.go files
+ // denoting a single ad hoc package.
+ for _, arg := range args {
+ if !strings.HasSuffix(arg, ".go") {
+ return nil, fmt.Errorf("named files must be .go files: %s", arg)
+ }
+ }
+ conf.CreateFromFilenames("", args...)
+ } else {
+ // Assume args are directories each denoting a
+ // package and (perhaps) an external test, iff xtest.
+ for _, arg := range args {
+ if xtest {
+ conf.ImportWithTests(arg)
+ } else {
+ conf.Import(arg)
+ }
+ }
+ }
+
+ return rest, nil
+}
+
+// CreateFromFilenames is a convenience function that adds
+// a conf.CreatePkgs entry to create a package of the specified *.go
+// files.
+//
+func (conf *Config) CreateFromFilenames(path string, filenames ...string) {
+ conf.CreatePkgs = append(conf.CreatePkgs, PkgSpec{Path: path, Filenames: filenames})
+}
+
+// CreateFromFiles is a convenience function that adds a conf.CreatePkgs
+// entry to create package of the specified path and parsed files.
+//
+func (conf *Config) CreateFromFiles(path string, files ...*ast.File) {
+ conf.CreatePkgs = append(conf.CreatePkgs, PkgSpec{Path: path, Files: files})
+}
+
+// ImportWithTests is a convenience function that adds path to
+// ImportPkgs, the set of initial source packages located relative to
+// $GOPATH. The package will be augmented by any *_test.go files in
+// its directory that contain a "package x" (not "package x_test")
+// declaration.
+//
+// In addition, if any *_test.go files contain a "package x_test"
+// declaration, an additional package comprising just those files will
+// be added to CreatePkgs.
+//
+func (conf *Config) ImportWithTests(path string) { conf.addImport(path, true) }
+
+// Import is a convenience function that adds path to ImportPkgs, the
+// set of initial packages that will be imported from source.
+//
+func (conf *Config) Import(path string) { conf.addImport(path, false) }
+
+func (conf *Config) addImport(path string, tests bool) {
+ if path == "C" || path == "unsafe" {
+ return // ignore; not a real package
+ }
+ if conf.ImportPkgs == nil {
+ conf.ImportPkgs = make(map[string]bool)
+ }
+ conf.ImportPkgs[path] = conf.ImportPkgs[path] || tests
+}
+
+// PathEnclosingInterval returns the PackageInfo and ast.Node that
+// contain source interval [start, end), and all the node's ancestors
+// up to the AST root. It searches all ast.Files of all packages in prog.
+// exact is defined as for astutil.PathEnclosingInterval.
+//
+// The zero value is returned if not found.
+//
+func (prog *Program) PathEnclosingInterval(start, end token.Pos) (pkg *PackageInfo, path []ast.Node, exact bool) {
+ for _, info := range prog.AllPackages {
+ for _, f := range info.Files {
+ if f.Pos() == token.NoPos {
+ // This can happen if the parser saw
+ // too many errors and bailed out.
+ // (Use parser.AllErrors to prevent that.)
+ continue
+ }
+ if !tokenFileContainsPos(prog.Fset.File(f.Pos()), start) {
+ continue
+ }
+ if path, exact := astutil.PathEnclosingInterval(f, start, end); path != nil {
+ return info, path, exact
+ }
+ }
+ }
+ return nil, nil, false
+}
+
+// InitialPackages returns a new slice containing the set of initial
+// packages (Created + Imported) in unspecified order.
+//
+func (prog *Program) InitialPackages() []*PackageInfo {
+ infos := make([]*PackageInfo, 0, len(prog.Created)+len(prog.Imported))
+ infos = append(infos, prog.Created...)
+ for _, info := range prog.Imported {
+ infos = append(infos, info)
+ }
+ return infos
+}
+
+// Package returns the ASTs and results of type checking for the
+// specified package.
+func (prog *Program) Package(path string) *PackageInfo {
+ if info, ok := prog.AllPackages[prog.importMap[path]]; ok {
+ return info
+ }
+ for _, info := range prog.Created {
+ if path == info.Pkg.Path() {
+ return info
+ }
+ }
+ return nil
+}
+
+// ---------- Implementation ----------
+
+// importer holds the working state of the algorithm.
+type importer struct {
+ conf *Config // the client configuration
+ start time.Time // for logging
+
+ progMu sync.Mutex // guards prog
+ prog *Program // the resulting program
+
+ importedMu sync.Mutex // guards imported
+ imported map[string]*importInfo // all imported packages (incl. failures) by import path
+
+ // import dependency graph: graph[x][y] => x imports y
+ //
+ // Since non-importable packages cannot be cyclic, we ignore
+ // their imports, thus we only need the subgraph over importable
+ // packages. Nodes are identified by their import paths.
+ graphMu sync.Mutex
+ graph map[string]map[string]bool
+}
+
+// importInfo tracks the success or failure of a single import.
+//
+// Upon completion, exactly one of info and err is non-nil:
+// info on successful creation of a package, err otherwise.
+// A successful package may still contain type errors.
+//
+type importInfo struct {
+ path string // import path
+ mu sync.Mutex // guards the following fields prior to completion
+ info *PackageInfo // results of typechecking (including errors)
+ err error // reason for failure to create a package
+ complete sync.Cond // complete condition is that one of info, err is non-nil.
+}
+
+// awaitCompletion blocks until ii is complete,
+// i.e. the info and err fields are safe to inspect without a lock.
+// It is concurrency-safe and idempotent.
+func (ii *importInfo) awaitCompletion() {
+ ii.mu.Lock()
+ for ii.info == nil && ii.err == nil {
+ ii.complete.Wait()
+ }
+ ii.mu.Unlock()
+}
+
+// Complete marks ii as complete.
+// Its info and err fields will not be subsequently updated.
+func (ii *importInfo) Complete(info *PackageInfo, err error) {
+ if info == nil && err == nil {
+ panic("Complete(nil, nil)")
+ }
+ ii.mu.Lock()
+ ii.info = info
+ ii.err = err
+ ii.complete.Broadcast()
+ ii.mu.Unlock()
+}
+
+// Load creates the initial packages specified by conf.{Create,Import}Pkgs,
+// loading their dependencies packages as needed.
+//
+// On success, Load returns a Program containing a PackageInfo for
+// each package. On failure, it returns an error.
+//
+// If AllowErrors is true, Load will return a Program even if some
+// packages contained I/O, parser or type errors, or if dependencies
+// were missing. (Such errors are accessible via PackageInfo.Errors. If
+// false, Load will fail if any package had an error.
+//
+// It is an error if no packages were loaded.
+//
+func (conf *Config) Load() (*Program, error) {
+ // Create a simple default error handler for parse/type errors.
+ if conf.TypeChecker.Error == nil {
+ conf.TypeChecker.Error = func(e error) { fmt.Fprintln(os.Stderr, e) }
+ }
+
+ // Set default working directory for relative package references.
+ if conf.Cwd == "" {
+ var err error
+ conf.Cwd, err = os.Getwd()
+ if err != nil {
+ return nil, err
+ }
+ }
+
+ // Install default FindPackage hook using go/build logic.
+ if conf.FindPackage == nil {
+ conf.FindPackage = func(ctxt *build.Context, path string) (*build.Package, error) {
+ // TODO(adonovan): cache calls to build.Import
+ // so we don't do it three times per test package.
+ ioLimit <- true
+ bp, err := ctxt.Import(path, conf.Cwd, 0)
+ <-ioLimit
+ if _, ok := err.(*build.NoGoError); ok {
+ return bp, nil // empty directory is not an error
+ }
+ return bp, err
+ }
+ }
+
+ prog := &Program{
+ Fset: conf.fset(),
+ Imported: make(map[string]*PackageInfo),
+ importMap: make(map[string]*types.Package),
+ AllPackages: make(map[*types.Package]*PackageInfo),
+ }
+
+ imp := importer{
+ conf: conf,
+ prog: prog,
+ imported: make(map[string]*importInfo),
+ start: time.Now(),
+ graph: make(map[string]map[string]bool),
+ }
+
+ // -- loading proper (concurrent phase) --------------------------------
+
+ var errpkgs []string // packages that contained errors
+
+ // Load the initially imported packages and their dependencies,
+ // in parallel.
+ for _, ii := range imp.loadAll("", conf.ImportPkgs) {
+ if ii.err != nil {
+ conf.TypeChecker.Error(ii.err) // failed to create package
+ errpkgs = append(errpkgs, ii.path)
+ continue
+ }
+ prog.Imported[ii.info.Pkg.Path()] = ii.info
+ }
+
+ // Augment the designated initial packages by their tests.
+ // Dependencies are loaded in parallel.
+ var xtestPkgs []*build.Package
+ for path, augment := range conf.ImportPkgs {
+ if !augment {
+ continue
+ }
+
+ bp, err := conf.FindPackage(conf.build(), path)
+ if err != nil {
+ // Package not found, or can't even parse package declaration.
+ // Already reported by previous loop; ignore it.
+ continue
+ }
+
+ // Needs external test package?
+ if len(bp.XTestGoFiles) > 0 {
+ xtestPkgs = append(xtestPkgs, bp)
+ }
+
+ imp.importedMu.Lock() // (unnecessary, we're sequential here)
+ ii, ok := imp.imported[path]
+ // Paranoid checks added due to issue #11012.
+ if !ok {
+ // Unreachable.
+ // The previous loop called loadAll and thus
+ // startLoad for each path in ImportPkgs, which
+ // populates imp.imported[path] with a non-zero value.
+ panic(fmt.Sprintf("imported[%q] not found", path))
+ }
+ if ii == nil {
+ // Unreachable.
+ // The ii values in this loop are the same as in
+ // the previous loop, which enforced the invariant
+ // that at least one of ii.err and ii.info is non-nil.
+ panic(fmt.Sprintf("imported[%q] == nil", path))
+ }
+ if ii.err != nil {
+ // The sole possible cause is failure of the
+ // FindPackage call in (*importer).load,
+ // but we rechecked that condition above.
+ // Perhaps the state of the file system changed
+ // in between? Seems unlikely.
+ panic(fmt.Sprintf("imported[%q].err = %v", path, ii.err))
+ }
+ if ii.info == nil {
+ // Unreachable.
+ // Complete has this postcondition:
+ // ii.err != nil || ii.info != nil
+ // and we know that ii.err == nil here.
+ panic(fmt.Sprintf("imported[%q].info = nil", path))
+ }
+ info := ii.info
+ imp.importedMu.Unlock()
+
+ // Parse the in-package test files.
+ files, errs := imp.conf.parsePackageFiles(bp, 't')
+ for _, err := range errs {
+ info.appendError(err)
+ }
+
+ // The test files augmenting package P cannot be imported,
+ // but may import packages that import P,
+ // so we must disable the cycle check.
+ imp.addFiles(info, files, false)
+ }
+
+ createPkg := func(path string, files []*ast.File, errs []error) {
+ info := imp.newPackageInfo(path)
+ for _, err := range errs {
+ info.appendError(err)
+ }
+
+ // Ad hoc packages are non-importable,
+ // so no cycle check is needed.
+ // addFiles loads dependencies in parallel.
+ imp.addFiles(info, files, false)
+ prog.Created = append(prog.Created, info)
+ }
+
+ // Create packages specified by conf.CreatePkgs.
+ for _, cp := range conf.CreatePkgs {
+ files, errs := parseFiles(conf.fset(), conf.build(), nil, ".", cp.Filenames, conf.ParserMode)
+ files = append(files, cp.Files...)
+
+ path := cp.Path
+ if path == "" {
+ if len(files) > 0 {
+ path = files[0].Name.Name
+ } else {
+ path = "(unnamed)"
+ }
+ }
+ createPkg(path, files, errs)
+ }
+
+ // Create external test packages.
+ sort.Sort(byImportPath(xtestPkgs))
+ for _, bp := range xtestPkgs {
+ files, errs := imp.conf.parsePackageFiles(bp, 'x')
+ createPkg(bp.ImportPath+"_test", files, errs)
+ }
+
+ // -- finishing up (sequential) ----------------------------------------
+
+ if len(prog.Imported)+len(prog.Created) == 0 {
+ return nil, errors.New("no initial packages were loaded")
+ }
+
+ // Create infos for indirectly imported packages.
+ // e.g. incomplete packages without syntax, loaded from export data.
+ for _, obj := range prog.importMap {
+ info := prog.AllPackages[obj]
+ if info == nil {
+ prog.AllPackages[obj] = &PackageInfo{Pkg: obj, Importable: true}
+ } else {
+ // finished
+ info.checker = nil
+ info.errorFunc = nil
+ }
+ }
+
+ if !conf.AllowErrors {
+ // Report errors in indirectly imported packages.
+ for _, info := range prog.AllPackages {
+ if len(info.Errors) > 0 {
+ errpkgs = append(errpkgs, info.Pkg.Path())
+ }
+ }
+ if errpkgs != nil {
+ var more string
+ if len(errpkgs) > 3 {
+ more = fmt.Sprintf(" and %d more", len(errpkgs)-3)
+ errpkgs = errpkgs[:3]
+ }
+ return nil, fmt.Errorf("couldn't load packages due to errors: %s%s",
+ strings.Join(errpkgs, ", "), more)
+ }
+ }
+
+ markErrorFreePackages(prog.AllPackages)
+
+ return prog, nil
+}
+
+type byImportPath []*build.Package
+
+func (b byImportPath) Len() int { return len(b) }
+func (b byImportPath) Less(i, j int) bool { return b[i].ImportPath < b[j].ImportPath }
+func (b byImportPath) Swap(i, j int) { b[i], b[j] = b[j], b[i] }
+
+// markErrorFreePackages sets the TransitivelyErrorFree flag on all
+// applicable packages.
+func markErrorFreePackages(allPackages map[*types.Package]*PackageInfo) {
+ // Build the transpose of the import graph.
+ importedBy := make(map[*types.Package]map[*types.Package]bool)
+ for P := range allPackages {
+ for _, Q := range P.Imports() {
+ clients, ok := importedBy[Q]
+ if !ok {
+ clients = make(map[*types.Package]bool)
+ importedBy[Q] = clients
+ }
+ clients[P] = true
+ }
+ }
+
+ // Find all packages reachable from some error package.
+ reachable := make(map[*types.Package]bool)
+ var visit func(*types.Package)
+ visit = func(p *types.Package) {
+ if !reachable[p] {
+ reachable[p] = true
+ for q := range importedBy[p] {
+ visit(q)
+ }
+ }
+ }
+ for _, info := range allPackages {
+ if len(info.Errors) > 0 {
+ visit(info.Pkg)
+ }
+ }
+
+ // Mark the others as "transitively error-free".
+ for _, info := range allPackages {
+ if !reachable[info.Pkg] {
+ info.TransitivelyErrorFree = true
+ }
+ }
+}
+
+// build returns the effective build context.
+func (conf *Config) build() *build.Context {
+ if conf.Build != nil {
+ return conf.Build
+ }
+ return &build.Default
+}
+
+// parsePackageFiles enumerates the files belonging to package path,
+// then loads, parses and returns them, plus a list of I/O or parse
+// errors that were encountered.
+//
+// 'which' indicates which files to include:
+// 'g': include non-test *.go source files (GoFiles + processed CgoFiles)
+// 't': include in-package *_test.go source files (TestGoFiles)
+// 'x': include external *_test.go source files. (XTestGoFiles)
+//
+func (conf *Config) parsePackageFiles(bp *build.Package, which rune) ([]*ast.File, []error) {
+ var filenames []string
+ switch which {
+ case 'g':
+ filenames = bp.GoFiles
+ case 't':
+ filenames = bp.TestGoFiles
+ case 'x':
+ filenames = bp.XTestGoFiles
+ default:
+ panic(which)
+ }
+
+ files, errs := parseFiles(conf.fset(), conf.build(), conf.DisplayPath, bp.Dir, filenames, conf.ParserMode)
+
+ // Preprocess CgoFiles and parse the outputs (sequentially).
+ if which == 'g' && bp.CgoFiles != nil {
+ cgofiles, err := processCgoFiles(bp, conf.fset(), conf.DisplayPath, conf.ParserMode)
+ if err != nil {
+ errs = append(errs, err)
+ } else {
+ files = append(files, cgofiles...)
+ }
+ }
+
+ return files, errs
+}
+
+// doImport imports the package denoted by path.
+// It implements the types.Importer signature.
+//
+// imports is the type-checker's package canonicalization map.
+//
+// It returns an error if a package could not be created
+// (e.g. go/build or parse error), but type errors are reported via
+// the types.Config.Error callback (the first of which is also saved
+// in the package's PackageInfo).
+//
+// Idempotent.
+//
+func (imp *importer) doImport(from *PackageInfo, to string) (*types.Package, error) {
+ // Package unsafe is handled specially, and has no PackageInfo.
+ // TODO(adonovan): move this check into go/types?
+ if to == "unsafe" {
+ return types.Unsafe, nil
+ }
+ if to == "C" {
+ // This should be unreachable, but ad hoc packages are
+ // not currently subject to cgo preprocessing.
+ // See https://github.com/golang/go/issues/11627.
+ return nil, fmt.Errorf(`the loader doesn't cgo-process ad hoc packages like %q; see Go issue 11627`,
+ from.Pkg.Path())
+ }
+
+ imp.importedMu.Lock()
+ ii := imp.imported[to]
+ imp.importedMu.Unlock()
+ if ii == nil {
+ panic("internal error: unexpected import: " + to)
+ }
+ if ii.err != nil {
+ return nil, ii.err
+ }
+ if ii.info != nil {
+ return ii.info.Pkg, nil
+ }
+
+ // Import of incomplete package: this indicates a cycle.
+ fromPath := from.Pkg.Path()
+ if cycle := imp.findPath(to, fromPath); cycle != nil {
+ cycle = append([]string{fromPath}, cycle...)
+ return nil, fmt.Errorf("import cycle: %s", strings.Join(cycle, " -> "))
+ }
+
+ panic("internal error: import of incomplete (yet acyclic) package: " + fromPath)
+}
+
+// loadAll loads, parses, and type-checks the specified packages in
+// parallel and returns their completed importInfos in unspecified order.
+//
+// fromPath is the import path of the importing package, if it is
+// importable, "" otherwise. It is used for cycle detection.
+//
+func (imp *importer) loadAll(fromPath string, paths map[string]bool) []*importInfo {
+ result := make([]*importInfo, 0, len(paths))
+ for path := range paths {
+ result = append(result, imp.startLoad(path))
+ }
+
+ if fromPath != "" {
+ // We're loading a set of imports.
+ //
+ // We must record graph edges from the importing package
+ // to its dependencies, and check for cycles.
+ imp.graphMu.Lock()
+ deps, ok := imp.graph[fromPath]
+ if !ok {
+ deps = make(map[string]bool)
+ imp.graph[fromPath] = deps
+ }
+ for path := range paths {
+ deps[path] = true
+ }
+ imp.graphMu.Unlock()
+ }
+
+ for _, ii := range result {
+ if fromPath != "" {
+ if cycle := imp.findPath(ii.path, fromPath); cycle != nil {
+ // Cycle-forming import: we must not await its
+ // completion since it would deadlock.
+ //
+ // We don't record the error in ii since
+ // the error is really associated with the
+ // cycle-forming edge, not the package itself.
+ // (Also it would complicate the
+ // invariants of importPath completion.)
+ if trace {
+ fmt.Fprintln(os.Stderr, "import cycle: %q", cycle)
+ }
+ continue
+ }
+ }
+ ii.awaitCompletion()
+ }
+ return result
+}
+
+// findPath returns an arbitrary path from 'from' to 'to' in the import
+// graph, or nil if there was none.
+func (imp *importer) findPath(from, to string) []string {
+ imp.graphMu.Lock()
+ defer imp.graphMu.Unlock()
+
+ seen := make(map[string]bool)
+ var search func(stack []string, importPath string) []string
+ search = func(stack []string, importPath string) []string {
+ if !seen[importPath] {
+ seen[importPath] = true
+ stack = append(stack, importPath)
+ if importPath == to {
+ return stack
+ }
+ for x := range imp.graph[importPath] {
+ if p := search(stack, x); p != nil {
+ return p
+ }
+ }
+ }
+ return nil
+ }
+ return search(make([]string, 0, 20), from)
+}
+
+// startLoad initiates the loading, parsing and type-checking of the
+// specified package and its dependencies, if it has not already begun.
+//
+// It returns an importInfo, not necessarily in a completed state. The
+// caller must call awaitCompletion() before accessing its info and err
+// fields.
+//
+// startLoad is concurrency-safe and idempotent.
+//
+func (imp *importer) startLoad(path string) *importInfo {
+ imp.importedMu.Lock()
+ ii, ok := imp.imported[path]
+ if !ok {
+ ii = &importInfo{path: path}
+ ii.complete.L = &ii.mu
+ imp.imported[path] = ii
+ go func() {
+ ii.Complete(imp.load(path))
+ }()
+ }
+ imp.importedMu.Unlock()
+
+ return ii
+}
+
+// load implements package loading by parsing Go source files
+// located by go/build.
+//
+func (imp *importer) load(path string) (*PackageInfo, error) {
+ bp, err := imp.conf.FindPackage(imp.conf.build(), path)
+ if err != nil {
+ return nil, err // package not found
+ }
+ info := imp.newPackageInfo(bp.ImportPath)
+ info.Importable = true
+ files, errs := imp.conf.parsePackageFiles(bp, 'g')
+ for _, err := range errs {
+ info.appendError(err)
+ }
+
+ imp.addFiles(info, files, true)
+
+ imp.progMu.Lock()
+ imp.prog.importMap[path] = info.Pkg
+ imp.progMu.Unlock()
+
+ return info, nil
+}
+
+// addFiles adds and type-checks the specified files to info, loading
+// their dependencies if needed. The order of files determines the
+// package initialization order. It may be called multiple times on the
+// same package. Errors are appended to the info.Errors field.
+//
+// cycleCheck determines whether the imports within files create
+// dependency edges that should be checked for potential cycles.
+//
+func (imp *importer) addFiles(info *PackageInfo, files []*ast.File, cycleCheck bool) {
+ info.Files = append(info.Files, files...)
+
+ // Ensure the dependencies are loaded, in parallel.
+ var fromPath string
+ if cycleCheck {
+ fromPath = info.Pkg.Path()
+ }
+ imp.loadAll(fromPath, scanImports(files))
+
+ if trace {
+ fmt.Fprintf(os.Stderr, "%s: start %q (%d)\n",
+ time.Since(imp.start), info.Pkg.Path(), len(files))
+ }
+
+ // Ignore the returned (first) error since we
+ // already collect them all in the PackageInfo.
+ info.checker.Files(files)
+
+ if trace {
+ fmt.Fprintf(os.Stderr, "%s: stop %q\n",
+ time.Since(imp.start), info.Pkg.Path())
+ }
+}
+
+func (imp *importer) newPackageInfo(path string) *PackageInfo {
+ pkg := types.NewPackage(path, "")
+ info := &PackageInfo{
+ Pkg: pkg,
+ Info: types.Info{
+ Types: make(map[ast.Expr]types.TypeAndValue),
+ Defs: make(map[*ast.Ident]types.Object),
+ Uses: make(map[*ast.Ident]types.Object),
+ Implicits: make(map[ast.Node]types.Object),
+ Scopes: make(map[ast.Node]*types.Scope),
+ Selections: make(map[*ast.SelectorExpr]*types.Selection),
+ },
+ errorFunc: imp.conf.TypeChecker.Error,
+ }
+
+ // Copy the types.Config so we can vary it across PackageInfos.
+ tc := imp.conf.TypeChecker
+ tc.IgnoreFuncBodies = false
+ if f := imp.conf.TypeCheckFuncBodies; f != nil {
+ tc.IgnoreFuncBodies = !f(path)
+ }
+ tc.Import = func(_ map[string]*types.Package, to string) (*types.Package, error) {
+ return imp.doImport(info, to)
+ }
+ tc.Error = info.appendError // appendError wraps the user's Error function
+
+ info.checker = types.NewChecker(&tc, imp.conf.fset(), pkg, &info.Info)
+ imp.progMu.Lock()
+ imp.prog.AllPackages[pkg] = info
+ imp.progMu.Unlock()
+ return info
+}
diff --git a/go/loader/loader_test.go b/go/loader/loader_test.go
new file mode 100644
index 0000000..602590e
--- /dev/null
+++ b/go/loader/loader_test.go
@@ -0,0 +1,674 @@
+// 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 loader_test
+
+import (
+ "fmt"
+ "go/build"
+ "path/filepath"
+ "reflect"
+ "sort"
+ "strings"
+ "sync"
+ "testing"
+
+ "golang.org/x/tools/go/buildutil"
+ "golang.org/x/tools/go/loader"
+)
+
+// TestFromArgs checks that conf.FromArgs populates conf correctly.
+// It does no I/O.
+func TestFromArgs(t *testing.T) {
+ type result struct {
+ Err string
+ Rest []string
+ ImportPkgs map[string]bool
+ CreatePkgs []loader.PkgSpec
+ }
+ for _, test := range []struct {
+ args []string
+ tests bool
+ want result
+ }{
+ // Mix of existing and non-existent packages.
+ {
+ args: []string{"nosuchpkg", "errors"},
+ want: result{
+ ImportPkgs: map[string]bool{"errors": false, "nosuchpkg": false},
+ },
+ },
+ // Same, with -test flag.
+ {
+ args: []string{"nosuchpkg", "errors"},
+ tests: true,
+ want: result{
+ ImportPkgs: map[string]bool{"errors": true, "nosuchpkg": true},
+ },
+ },
+ // Surplus arguments.
+ {
+ args: []string{"fmt", "errors", "--", "surplus"},
+ want: result{
+ Rest: []string{"surplus"},
+ ImportPkgs: map[string]bool{"errors": false, "fmt": false},
+ },
+ },
+ // Ad hoc package specified as *.go files.
+ {
+ args: []string{"foo.go", "bar.go"},
+ want: result{CreatePkgs: []loader.PkgSpec{{
+ Filenames: []string{"foo.go", "bar.go"},
+ }}},
+ },
+ // Mixture of *.go and import paths.
+ {
+ args: []string{"foo.go", "fmt"},
+ want: result{
+ Err: "named files must be .go files: fmt",
+ },
+ },
+ } {
+ var conf loader.Config
+ rest, err := conf.FromArgs(test.args, test.tests)
+ got := result{
+ Rest: rest,
+ ImportPkgs: conf.ImportPkgs,
+ CreatePkgs: conf.CreatePkgs,
+ }
+ if err != nil {
+ got.Err = err.Error()
+ }
+ if !reflect.DeepEqual(got, test.want) {
+ t.Errorf("FromArgs(%q) = %+v, want %+v", test.args, got, test.want)
+ }
+ }
+}
+
+func TestLoad_NoInitialPackages(t *testing.T) {
+ var conf loader.Config
+
+ const wantErr = "no initial packages were loaded"
+
+ prog, err := conf.Load()
+ if err == nil {
+ t.Errorf("Load succeeded unexpectedly, want %q", wantErr)
+ } else if err.Error() != wantErr {
+ t.Errorf("Load failed with wrong error %q, want %q", err, wantErr)
+ }
+ if prog != nil {
+ t.Errorf("Load unexpectedly returned a Program")
+ }
+}
+
+func TestLoad_MissingInitialPackage(t *testing.T) {
+ var conf loader.Config
+ conf.Import("nosuchpkg")
+ conf.Import("errors")
+
+ const wantErr = "couldn't load packages due to errors: nosuchpkg"
+
+ prog, err := conf.Load()
+ if err == nil {
+ t.Errorf("Load succeeded unexpectedly, want %q", wantErr)
+ } else if err.Error() != wantErr {
+ t.Errorf("Load failed with wrong error %q, want %q", err, wantErr)
+ }
+ if prog != nil {
+ t.Errorf("Load unexpectedly returned a Program")
+ }
+}
+
+func TestLoad_MissingInitialPackage_AllowErrors(t *testing.T) {
+ var conf loader.Config
+ conf.AllowErrors = true
+ conf.Import("nosuchpkg")
+ conf.ImportWithTests("errors")
+
+ prog, err := conf.Load()
+ if err != nil {
+ t.Errorf("Load failed unexpectedly: %v", err)
+ }
+ if prog == nil {
+ t.Fatalf("Load returned a nil Program")
+ }
+ if got, want := created(prog), "errors_test"; got != want {
+ t.Errorf("Created = %s, want %s", got, want)
+ }
+ if got, want := imported(prog), "errors"; got != want {
+ t.Errorf("Imported = %s, want %s", got, want)
+ }
+}
+
+func TestCreateUnnamedPackage(t *testing.T) {
+ var conf loader.Config
+ conf.CreateFromFilenames("")
+ prog, err := conf.Load()
+ if err != nil {
+ t.Fatalf("Load failed: %v", err)
+ }
+ if got, want := fmt.Sprint(prog.InitialPackages()), "[(unnamed)]"; got != want {
+ t.Errorf("InitialPackages = %s, want %s", got, want)
+ }
+}
+
+func TestLoad_MissingFileInCreatedPackage(t *testing.T) {
+ var conf loader.Config
+ conf.CreateFromFilenames("", "missing.go")
+
+ const wantErr = "couldn't load packages due to errors: (unnamed)"
+
+ prog, err := conf.Load()
+ if prog != nil {
+ t.Errorf("Load unexpectedly returned a Program")
+ }
+ if err == nil {
+ t.Fatalf("Load succeeded unexpectedly, want %q", wantErr)
+ }
+ if err.Error() != wantErr {
+ t.Fatalf("Load failed with wrong error %q, want %q", err, wantErr)
+ }
+}
+
+func TestLoad_MissingFileInCreatedPackage_AllowErrors(t *testing.T) {
+ conf := loader.Config{AllowErrors: true}
+ conf.CreateFromFilenames("", "missing.go")
+
+ prog, err := conf.Load()
+ if err != nil {
+ t.Errorf("Load failed: %v", err)
+ }
+ if got, want := fmt.Sprint(prog.InitialPackages()), "[(unnamed)]"; got != want {
+ t.Fatalf("InitialPackages = %s, want %s", got, want)
+ }
+}
+
+func TestLoad_ParseError(t *testing.T) {
+ var conf loader.Config
+ conf.CreateFromFilenames("badpkg", "testdata/badpkgdecl.go")
+
+ const wantErr = "couldn't load packages due to errors: badpkg"
+
+ prog, err := conf.Load()
+ if prog != nil {
+ t.Errorf("Load unexpectedly returned a Program")
+ }
+ if err == nil {
+ t.Fatalf("Load succeeded unexpectedly, want %q", wantErr)
+ }
+ if err.Error() != wantErr {
+ t.Fatalf("Load failed with wrong error %q, want %q", err, wantErr)
+ }
+}
+
+func TestLoad_ParseError_AllowErrors(t *testing.T) {
+ var conf loader.Config
+ conf.AllowErrors = true
+ conf.CreateFromFilenames("badpkg", "testdata/badpkgdecl.go")
+
+ prog, err := conf.Load()
+ if err != nil {
+ t.Errorf("Load failed unexpectedly: %v", err)
+ }
+ if prog == nil {
+ t.Fatalf("Load returned a nil Program")
+ }
+ if got, want := created(prog), "badpkg"; got != want {
+ t.Errorf("Created = %s, want %s", got, want)
+ }
+
+ badpkg := prog.Created[0]
+ if len(badpkg.Files) != 1 {
+ t.Errorf("badpkg has %d files, want 1", len(badpkg.Files))
+ }
+ wantErr := filepath.Join("testdata", "badpkgdecl.go") + ":1:34: expected 'package', found 'EOF'"
+ if !hasError(badpkg.Errors, wantErr) {
+ t.Errorf("badpkg.Errors = %v, want %s", badpkg.Errors, wantErr)
+ }
+}
+
+func TestLoad_FromSource_Success(t *testing.T) {
+ var conf loader.Config
+ conf.CreateFromFilenames("P", "testdata/a.go", "testdata/b.go")
+
+ prog, err := conf.Load()
+ if err != nil {
+ t.Errorf("Load failed unexpectedly: %v", err)
+ }
+ if prog == nil {
+ t.Fatalf("Load returned a nil Program")
+ }
+ if got, want := created(prog), "P"; got != want {
+ t.Errorf("Created = %s, want %s", got, want)
+ }
+}
+
+func TestLoad_FromImports_Success(t *testing.T) {
+ var conf loader.Config
+ conf.ImportWithTests("fmt")
+ conf.ImportWithTests("errors")
+
+ prog, err := conf.Load()
+ if err != nil {
+ t.Errorf("Load failed unexpectedly: %v", err)
+ }
+ if prog == nil {
+ t.Fatalf("Load returned a nil Program")
+ }
+ if got, want := created(prog), "errors_test fmt_test"; got != want {
+ t.Errorf("Created = %q, want %s", got, want)
+ }
+ if got, want := imported(prog), "errors fmt"; got != want {
+ t.Errorf("Imported = %s, want %s", got, want)
+ }
+ // Check set of transitive packages.
+ // There are >30 and the set may grow over time, so only check a few.
+ want := map[string]bool{
+ "strings": true,
+ "time": true,
+ "runtime": true,
+ "testing": true,
+ "unicode": true,
+ }
+ for _, path := range all(prog) {
+ delete(want, path)
+ }
+ if len(want) > 0 {
+ t.Errorf("AllPackages is missing these keys: %q", keys(want))
+ }
+}
+
+func TestLoad_MissingIndirectImport(t *testing.T) {
+ pkgs := map[string]string{
+ "a": `package a; import _ "b"`,
+ "b": `package b; import _ "c"`,
+ }
+ conf := loader.Config{Build: fakeContext(pkgs)}
+ conf.Import("a")
+
+ const wantErr = "couldn't load packages due to errors: b"
+
+ prog, err := conf.Load()
+ if err == nil {
+ t.Errorf("Load succeeded unexpectedly, want %q", wantErr)
+ } else if err.Error() != wantErr {
+ t.Errorf("Load failed with wrong error %q, want %q", err, wantErr)
+ }
+ if prog != nil {
+ t.Errorf("Load unexpectedly returned a Program")
+ }
+}
+
+func TestLoad_BadDependency_AllowErrors(t *testing.T) {
+ for _, test := range []struct {
+ descr string
+ pkgs map[string]string
+ wantPkgs string
+ }{
+
+ {
+ descr: "missing dependency",
+ pkgs: map[string]string{
+ "a": `package a; import _ "b"`,
+ "b": `package b; import _ "c"`,
+ },
+ wantPkgs: "a b",
+ },
+ {
+ descr: "bad package decl in dependency",
+ pkgs: map[string]string{
+ "a": `package a; import _ "b"`,
+ "b": `package b; import _ "c"`,
+ "c": `package`,
+ },
+ wantPkgs: "a b",
+ },
+ {
+ descr: "parse error in dependency",
+ pkgs: map[string]string{
+ "a": `package a; import _ "b"`,
+ "b": `package b; import _ "c"`,
+ "c": `package c; var x = `,
+ },
+ wantPkgs: "a b c",
+ },
+ } {
+ conf := loader.Config{
+ AllowErrors: true,
+ Build: fakeContext(test.pkgs),
+ }
+ conf.Import("a")
+
+ prog, err := conf.Load()
+ if err != nil {
+ t.Errorf("%s: Load failed unexpectedly: %v", test.descr, err)
+ }
+ if prog == nil {
+ t.Fatalf("%s: Load returned a nil Program", test.descr)
+ }
+
+ if got, want := imported(prog), "a"; got != want {
+ t.Errorf("%s: Imported = %s, want %s", test.descr, got, want)
+ }
+ if got := all(prog); strings.Join(got, " ") != test.wantPkgs {
+ t.Errorf("%s: AllPackages = %s, want %s", test.descr, got, test.wantPkgs)
+ }
+ }
+}
+
+func TestCwd(t *testing.T) {
+ ctxt := fakeContext(map[string]string{"one/two/three": `package three`})
+ for _, test := range []struct {
+ cwd, arg, want string
+ }{
+ {cwd: "/go/src/one", arg: "./two/three", want: "one/two/three"},
+ {cwd: "/go/src/one", arg: "../one/two/three", want: "one/two/three"},
+ {cwd: "/go/src/one", arg: "one/two/three", want: "one/two/three"},
+ {cwd: "/go/src/one/two/three", arg: ".", want: "one/two/three"},
+ {cwd: "/go/src/one", arg: "two/three", want: ""},
+ } {
+ conf := loader.Config{
+ Cwd: test.cwd,
+ Build: ctxt,
+ }
+ conf.Import(test.arg)
+
+ var got string
+ prog, err := conf.Load()
+ if prog != nil {
+ got = imported(prog)
+ }
+ if got != test.want {
+ t.Errorf("Load(%s) from %s: Imported = %s, want %s",
+ test.arg, test.cwd, got, test.want)
+ if err != nil {
+ t.Errorf("Load failed: %v", err)
+ }
+ }
+ }
+}
+
+// TODO(adonovan): more Load tests:
+//
+// failures:
+// - to parse package decl of *_test.go files
+// - to parse package decl of external *_test.go files
+// - to parse whole of *_test.go files
+// - to parse whole of external *_test.go files
+// - to open a *.go file during import scanning
+// - to import from binary
+
+// features:
+// - InitialPackages
+// - PackageCreated hook
+// - TypeCheckFuncBodies hook
+
+func TestTransitivelyErrorFreeFlag(t *testing.T) {
+ // Create an minimal custom build.Context
+ // that fakes the following packages:
+ //
+ // a --> b --> c! c has an error
+ // \ d and e are transitively error-free.
+ // e --> d
+ //
+ // Each package [a-e] consists of one file, x.go.
+ pkgs := map[string]string{
+ "a": `package a; import (_ "b"; _ "e")`,
+ "b": `package b; import _ "c"`,
+ "c": `package c; func f() { _ = int(false) }`, // type error within function body
+ "d": `package d;`,
+ "e": `package e; import _ "d"`,
+ }
+ conf := loader.Config{
+ AllowErrors: true,
+ Build: fakeContext(pkgs),
+ }
+ conf.Import("a")
+
+ prog, err := conf.Load()
+ if err != nil {
+ t.Errorf("Load failed: %s", err)
+ }
+ if prog == nil {
+ t.Fatalf("Load returned nil *Program")
+ }
+
+ for pkg, info := range prog.AllPackages {
+ var wantErr, wantTEF bool
+ switch pkg.Path() {
+ case "a", "b":
+ case "c":
+ wantErr = true
+ case "d", "e":
+ wantTEF = true
+ default:
+ t.Errorf("unexpected package: %q", pkg.Path())
+ continue
+ }
+
+ if (info.Errors != nil) != wantErr {
+ if wantErr {
+ t.Errorf("Package %q.Error = nil, want error", pkg.Path())
+ } else {
+ t.Errorf("Package %q has unexpected Errors: %v",
+ pkg.Path(), info.Errors)
+ }
+ }
+
+ if info.TransitivelyErrorFree != wantTEF {
+ t.Errorf("Package %q.TransitivelyErrorFree=%t, want %t",
+ pkg.Path(), info.TransitivelyErrorFree, wantTEF)
+ }
+ }
+}
+
+// Test that syntax (scan/parse), type, and loader errors are recorded
+// (in PackageInfo.Errors) and reported (via Config.TypeChecker.Error).
+func TestErrorReporting(t *testing.T) {
+ pkgs := map[string]string{
+ "a": `package a; import (_ "b"; _ "c"); var x int = false`,
+ "b": `package b; 'syntax error!`,
+ }
+ conf := loader.Config{
+ AllowErrors: true,
+ Build: fakeContext(pkgs),
+ }
+ var mu sync.Mutex
+ var allErrors []error
+ conf.TypeChecker.Error = func(err error) {
+ mu.Lock()
+ allErrors = append(allErrors, err)
+ mu.Unlock()
+ }
+ conf.Import("a")
+
+ prog, err := conf.Load()
+ if err != nil {
+ t.Errorf("Load failed: %s", err)
+ }
+ if prog == nil {
+ t.Fatalf("Load returned nil *Program")
+ }
+
+ // TODO(adonovan): test keys of ImportMap.
+
+ // Check errors recorded in each PackageInfo.
+ for pkg, info := range prog.AllPackages {
+ switch pkg.Path() {
+ case "a":
+ if !hasError(info.Errors, "cannot convert false") {
+ t.Errorf("a.Errors = %v, want bool conversion (type) error", info.Errors)
+ }
+ if !hasError(info.Errors, "could not import c") {
+ t.Errorf("a.Errors = %v, want import (loader) error", info.Errors)
+ }
+ case "b":
+ if !hasError(info.Errors, "rune literal not terminated") {
+ t.Errorf("b.Errors = %v, want unterminated literal (syntax) error", info.Errors)
+ }
+ }
+ }
+
+ // Check errors reported via error handler.
+ if !hasError(allErrors, "cannot convert false") ||
+ !hasError(allErrors, "rune literal not terminated") ||
+ !hasError(allErrors, "could not import c") {
+ t.Errorf("allErrors = %v, want syntax, type and loader errors", allErrors)
+ }
+}
+
+func TestCycles(t *testing.T) {
+ for _, test := range []struct {
+ descr string
+ ctxt *build.Context
+ wantErr string
+ }{
+ {
+ "self-cycle",
+ fakeContext(map[string]string{
+ "main": `package main; import _ "selfcycle"`,
+ "selfcycle": `package selfcycle; import _ "selfcycle"`,
+ }),
+ `import cycle: selfcycle -> selfcycle`,
+ },
+ {
+ "three-package cycle",
+ fakeContext(map[string]string{
+ "main": `package main; import _ "a"`,
+ "a": `package a; import _ "b"`,
+ "b": `package b; import _ "c"`,
+ "c": `package c; import _ "a"`,
+ }),
+ `import cycle: c -> a -> b -> c`,
+ },
+ {
+ "self-cycle in dependency of test file",
+ buildutil.FakeContext(map[string]map[string]string{
+ "main": {
+ "main.go": `package main`,
+ "main_test.go": `package main; import _ "a"`,
+ },
+ "a": {
+ "a.go": `package a; import _ "a"`,
+ },
+ }),
+ `import cycle: a -> a`,
+ },
+ // TODO(adonovan): fix: these fail
+ // {
+ // "two-package cycle in dependency of test file",
+ // buildutil.FakeContext(map[string]map[string]string{
+ // "main": {
+ // "main.go": `package main`,
+ // "main_test.go": `package main; import _ "a"`,
+ // },
+ // "a": {
+ // "a.go": `package a; import _ "main"`,
+ // },
+ // }),
+ // `import cycle: main -> a -> main`,
+ // },
+ // {
+ // "self-cycle in augmented package",
+ // buildutil.FakeContext(map[string]map[string]string{
+ // "main": {
+ // "main.go": `package main`,
+ // "main_test.go": `package main; import _ "main"`,
+ // },
+ // }),
+ // `import cycle: main -> main`,
+ // },
+ } {
+ conf := loader.Config{
+ AllowErrors: true,
+ Build: test.ctxt,
+ }
+ var mu sync.Mutex
+ var allErrors []error
+ conf.TypeChecker.Error = func(err error) {
+ mu.Lock()
+ allErrors = append(allErrors, err)
+ mu.Unlock()
+ }
+ conf.ImportWithTests("main")
+
+ prog, err := conf.Load()
+ if err != nil {
+ t.Errorf("%s: Load failed: %s", test.descr, err)
+ }
+ if prog == nil {
+ t.Fatalf("%s: Load returned nil *Program", test.descr)
+ }
+
+ if !hasError(allErrors, test.wantErr) {
+ t.Errorf("%s: Load() errors = %q, want %q",
+ test.descr, allErrors, test.wantErr)
+ }
+ }
+
+ // TODO(adonovan):
+ // - Test that in a legal test cycle, none of the symbols
+ // defined by augmentation are visible via import.
+}
+
+// ---- utilities ----
+
+// Simplifying wrapper around buildutil.FakeContext for single-file packages.
+func fakeContext(pkgs map[string]string) *build.Context {
+ pkgs2 := make(map[string]map[string]string)
+ for path, content := range pkgs {
+ pkgs2[path] = map[string]string{"x.go": content}
+ }
+ return buildutil.FakeContext(pkgs2)
+}
+
+func hasError(errors []error, substr string) bool {
+ for _, err := range errors {
+ if strings.Contains(err.Error(), substr) {
+ return true
+ }
+ }
+ return false
+}
+
+func keys(m map[string]bool) (keys []string) {
+ for key := range m {
+ keys = append(keys, key)
+ }
+ sort.Strings(keys)
+ return
+}
+
+// Returns all loaded packages.
+func all(prog *loader.Program) []string {
+ var pkgs []string
+ for _, info := range prog.AllPackages {
+ pkgs = append(pkgs, info.Pkg.Path())
+ }
+ sort.Strings(pkgs)
+ return pkgs
+}
+
+// Returns initially imported packages, as a string.
+func imported(prog *loader.Program) string {
+ var pkgs []string
+ for _, info := range prog.Imported {
+ pkgs = append(pkgs, info.Pkg.Path())
+ }
+ sort.Strings(pkgs)
+ return strings.Join(pkgs, " ")
+}
+
+// Returns initially created packages, as a string.
+func created(prog *loader.Program) string {
+ var pkgs []string
+ for _, info := range prog.Created {
+ pkgs = append(pkgs, info.Pkg.Path())
+ }
+ return strings.Join(pkgs, " ")
+}
diff --git a/go/loader/stdlib_test.go b/go/loader/stdlib_test.go
new file mode 100644
index 0000000..b62ecfb
--- /dev/null
+++ b/go/loader/stdlib_test.go
@@ -0,0 +1,197 @@
+// 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 loader_test
+
+// This file enumerates all packages beneath $GOROOT, loads them, plus
+// their external tests if any, runs the type checker on them, and
+// prints some summary information.
+//
+// Run test with GOMAXPROCS=8.
+
+import (
+ "bytes"
+ "fmt"
+ "go/ast"
+ "go/build"
+ "go/token"
+ "io/ioutil"
+ "path/filepath"
+ "runtime"
+ "strings"
+ "testing"
+ "time"
+
+ "golang.org/x/tools/go/buildutil"
+ "golang.org/x/tools/go/loader"
+ "golang.org/x/tools/go/types"
+)
+
+func TestStdlib(t *testing.T) {
+ if runtime.GOOS == "android" {
+ t.Skipf("incomplete std lib on %s", runtime.GOOS)
+ }
+
+ runtime.GC()
+ t0 := time.Now()
+ var memstats runtime.MemStats
+ runtime.ReadMemStats(&memstats)
+ alloc := memstats.Alloc
+
+ // Load, parse and type-check the program.
+ ctxt := build.Default // copy
+ ctxt.GOPATH = "" // disable GOPATH
+ conf := loader.Config{Build: &ctxt}
+ for _, path := range buildutil.AllPackages(conf.Build) {
+ conf.ImportWithTests(path)
+ }
+
+ prog, err := conf.Load()
+ if err != nil {
+ t.Fatalf("Load failed: %v", err)
+ }
+
+ t1 := time.Now()
+ runtime.GC()
+ runtime.ReadMemStats(&memstats)
+
+ numPkgs := len(prog.AllPackages)
+ if want := 205; numPkgs < want {
+ t.Errorf("Loaded only %d packages, want at least %d", numPkgs, want)
+ }
+
+ // Dump package members.
+ if false {
+ for pkg := range prog.AllPackages {
+ fmt.Printf("Package %s:\n", pkg.Path())
+ scope := pkg.Scope()
+ qualifier := types.RelativeTo(pkg)
+ for _, name := range scope.Names() {
+ if ast.IsExported(name) {
+ fmt.Printf("\t%s\n", types.ObjectString(scope.Lookup(name), qualifier))
+ }
+ }
+ fmt.Println()
+ }
+ }
+
+ // Check that Test functions for io/ioutil, regexp and
+ // compress/bzip2 are all simultaneously present.
+ // (The apparent cycle formed when augmenting all three of
+ // these packages by their tests was the original motivation
+ // for reporting b/7114.)
+ //
+ // compress/bzip2.TestBitReader in bzip2_test.go imports io/ioutil
+ // io/ioutil.TestTempFile in tempfile_test.go imports regexp
+ // regexp.TestRE2Search in exec_test.go imports compress/bzip2
+ for _, test := range []struct{ pkg, fn string }{
+ {"io/ioutil", "TestTempFile"},
+ {"regexp", "TestRE2Search"},
+ {"compress/bzip2", "TestBitReader"},
+ } {
+ info := prog.Imported[test.pkg]
+ if info == nil {
+ t.Errorf("failed to load package %q", test.pkg)
+ continue
+ }
+ obj, _ := info.Pkg.Scope().Lookup(test.fn).(*types.Func)
+ if obj == nil {
+ t.Errorf("package %q has no func %q", test.pkg, test.fn)
+ continue
+ }
+ }
+
+ // Dump some statistics.
+
+ // determine line count
+ var lineCount int
+ prog.Fset.Iterate(func(f *token.File) bool {
+ lineCount += f.LineCount()
+ return true
+ })
+
+ t.Log("GOMAXPROCS: ", runtime.GOMAXPROCS(0))
+ t.Log("#Source lines: ", lineCount)
+ t.Log("Load/parse/typecheck: ", t1.Sub(t0))
+ t.Log("#MB: ", int64(memstats.Alloc-alloc)/1000000)
+}
+
+func TestCgoOption(t *testing.T) {
+ switch runtime.GOOS {
+ // On these systems, the net and os/user packages don't use cgo
+ // or the std library is incomplete (Android).
+ case "android", "plan9", "solaris", "windows":
+ t.Skipf("no cgo or incomplete std lib on %s", runtime.GOOS)
+ }
+ // In nocgo builds (e.g. linux-amd64-nocgo),
+ // there is no "runtime/cgo" package,
+ // so cgo-generated Go files will have a failing import.
+ if !build.Default.CgoEnabled {
+ return
+ }
+ // Test that we can load cgo-using packages with
+ // CGO_ENABLED=[01], which causes go/build to select pure
+ // Go/native implementations, respectively, based on build
+ // tags.
+ //
+ // Each entry specifies a package-level object and the generic
+ // file expected to define it when cgo is disabled.
+ // When cgo is enabled, the exact file is not specified (since
+ // it varies by platform), but must differ from the generic one.
+ //
+ // The test also loads the actual file to verify that the
+ // object is indeed defined at that location.
+ for _, test := range []struct {
+ pkg, name, genericFile string
+ }{
+ {"net", "cgoLookupHost", "cgo_stub.go"},
+ {"os/user", "lookupId", "lookup_stubs.go"},
+ } {
+ ctxt := build.Default
+ for _, ctxt.CgoEnabled = range []bool{false, true} {
+ conf := loader.Config{Build: &ctxt}
+ conf.Import(test.pkg)
+ prog, err := conf.Load()
+ if err != nil {
+ t.Errorf("Load failed: %v", err)
+ continue
+ }
+ info := prog.Imported[test.pkg]
+ if info == nil {
+ t.Errorf("package %s not found", test.pkg)
+ continue
+ }
+ obj := info.Pkg.Scope().Lookup(test.name)
+ if obj == nil {
+ t.Errorf("no object %s.%s", test.pkg, test.name)
+ continue
+ }
+ posn := prog.Fset.Position(obj.Pos())
+ t.Logf("%s: %s (CgoEnabled=%t)", posn, obj, ctxt.CgoEnabled)
+
+ gotFile := filepath.Base(posn.Filename)
+ filesMatch := gotFile == test.genericFile
+
+ if ctxt.CgoEnabled && filesMatch {
+ t.Errorf("CGO_ENABLED=1: %s found in %s, want native file",
+ obj, gotFile)
+ } else if !ctxt.CgoEnabled && !filesMatch {
+ t.Errorf("CGO_ENABLED=0: %s found in %s, want %s",
+ obj, gotFile, test.genericFile)
+ }
+
+ // Load the file and check the object is declared at the right place.
+ b, err := ioutil.ReadFile(posn.Filename)
+ if err != nil {
+ t.Errorf("can't read %s: %s", posn.Filename, err)
+ continue
+ }
+ line := string(bytes.Split(b, []byte("\n"))[posn.Line-1])
+ ident := line[posn.Column-1:]
+ if !strings.HasPrefix(ident, test.name) {
+ t.Errorf("%s: %s not declared here (looking at %q)", posn, obj, ident)
+ }
+ }
+ }
+}
diff --git a/go/loader/testdata/a.go b/go/loader/testdata/a.go
new file mode 100644
index 0000000..bae3955
--- /dev/null
+++ b/go/loader/testdata/a.go
@@ -0,0 +1 @@
+package P
diff --git a/go/loader/testdata/b.go b/go/loader/testdata/b.go
new file mode 100644
index 0000000..bae3955
--- /dev/null
+++ b/go/loader/testdata/b.go
@@ -0,0 +1 @@
+package P
diff --git a/go/loader/testdata/badpkgdecl.go b/go/loader/testdata/badpkgdecl.go
new file mode 100644
index 0000000..1e39359
--- /dev/null
+++ b/go/loader/testdata/badpkgdecl.go
@@ -0,0 +1 @@
+// this file has no package decl
diff --git a/go/loader/util.go b/go/loader/util.go
new file mode 100644
index 0000000..3b64856
--- /dev/null
+++ b/go/loader/util.go
@@ -0,0 +1,124 @@
+// 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 loader
+
+import (
+ "go/ast"
+ "go/build"
+ "go/parser"
+ "go/token"
+ "io"
+ "os"
+ "strconv"
+ "sync"
+
+ "golang.org/x/tools/go/buildutil"
+)
+
+// We use a counting semaphore to limit
+// the number of parallel I/O calls per process.
+var ioLimit = make(chan bool, 10)
+
+// parseFiles parses the Go source files within directory dir and
+// returns the ASTs of the ones that could be at least partially parsed,
+// along with a list of I/O and parse errors encountered.
+//
+// I/O is done via ctxt, which may specify a virtual file system.
+// displayPath is used to transform the filenames attached to the ASTs.
+//
+func parseFiles(fset *token.FileSet, ctxt *build.Context, displayPath func(string) string, dir string, files []string, mode parser.Mode) ([]*ast.File, []error) {
+ if displayPath == nil {
+ displayPath = func(path string) string { return path }
+ }
+ var wg sync.WaitGroup
+ n := len(files)
+ parsed := make([]*ast.File, n)
+ errors := make([]error, n)
+ for i, file := range files {
+ if !buildutil.IsAbsPath(ctxt, file) {
+ file = buildutil.JoinPath(ctxt, dir, file)
+ }
+ wg.Add(1)
+ go func(i int, file string) {
+ ioLimit <- true // wait
+ defer func() {
+ wg.Done()
+ <-ioLimit // signal
+ }()
+ var rd io.ReadCloser
+ var err error
+ if ctxt.OpenFile != nil {
+ rd, err = ctxt.OpenFile(file)
+ } else {
+ rd, err = os.Open(file)
+ }
+ if err != nil {
+ errors[i] = err // open failed
+ return
+ }
+
+ // ParseFile may return both an AST and an error.
+ parsed[i], errors[i] = parser.ParseFile(fset, displayPath(file), rd, mode)
+ rd.Close()
+ }(i, file)
+ }
+ wg.Wait()
+
+ // Eliminate nils, preserving order.
+ var o int
+ for _, f := range parsed {
+ if f != nil {
+ parsed[o] = f
+ o++
+ }
+ }
+ parsed = parsed[:o]
+
+ o = 0
+ for _, err := range errors {
+ if err != nil {
+ errors[o] = err
+ o++
+ }
+ }
+ errors = errors[:o]
+
+ return parsed, errors
+}
+
+// scanImports returns the set of all package import paths from all
+// import specs in the specified files.
+func scanImports(files []*ast.File) map[string]bool {
+ imports := make(map[string]bool)
+ for _, f := range files {
+ for _, decl := range f.Decls {
+ if decl, ok := decl.(*ast.GenDecl); ok && decl.Tok == token.IMPORT {
+ for _, spec := range decl.Specs {
+ spec := spec.(*ast.ImportSpec)
+
+ // NB: do not assume the program is well-formed!
+ path, err := strconv.Unquote(spec.Path.Value)
+ if err != nil {
+ continue // quietly ignore the error
+ }
+ if path == "C" || path == "unsafe" {
+ continue // skip pseudo packages
+ }
+ imports[path] = true
+ }
+ }
+ }
+ }
+ return imports
+}
+
+// ---------- Internal helpers ----------
+
+// TODO(adonovan): make this a method: func (*token.File) Contains(token.Pos)
+func tokenFileContainsPos(f *token.File, pos token.Pos) bool {
+ p := int(pos)
+ base := f.Base()
+ return base <= p && p < base+f.Size()
+}
diff --git a/go/pointer/TODO b/go/pointer/TODO
new file mode 100644
index 0000000..f95e706
--- /dev/null
+++ b/go/pointer/TODO
@@ -0,0 +1,33 @@
+-*- text -*-
+
+Pointer analysis to-do list
+===========================
+
+CONSTRAINT GENERATION:
+- support reflection:
+ - a couple of operators are missing
+ - reflect.Values may contain lvalues (CanAddr)
+- implement native intrinsics. These vary by platform.
+- add to pts(a.panic) a label representing all runtime panics, e.g.
+ runtime.{TypeAssertionError,errorString,errorCString}.
+
+OPTIMISATIONS
+- pre-solver:
+ pointer equivalence: extend HVN to HRU
+ location equivalence
+- solver: HCD, LCD.
+- experiment with map+slice worklist in lieu of bitset.
+ It may have faster insert.
+
+MISC:
+- Test on all platforms.
+ Currently we assume these go/build tags: linux, amd64, !cgo.
+
+MAINTAINABILITY
+- Think about ways to make debugging this code easier. PTA logs
+ routinely exceed a million lines and require training to read.
+
+BUGS:
+- There's a crash bug in stdlib_test + reflection, rVCallConstraint.
+
+
diff --git a/go/pointer/analysis.go b/go/pointer/analysis.go
new file mode 100644
index 0000000..d02e536
--- /dev/null
+++ b/go/pointer/analysis.go
@@ -0,0 +1,447 @@
+// 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 pointer
+
+// This file defines the main datatypes and Analyze function of the pointer analysis.
+
+import (
+ "fmt"
+ "go/token"
+ "io"
+ "os"
+ "reflect"
+ "runtime"
+ "runtime/debug"
+ "sort"
+
+ "golang.org/x/tools/go/callgraph"
+ "golang.org/x/tools/go/ssa"
+ "golang.org/x/tools/go/types"
+ "golang.org/x/tools/go/types/typeutil"
+)
+
+const (
+ // optimization options; enable all when committing
+ optRenumber = true // enable renumbering optimization (makes logs hard to read)
+ optHVN = true // enable pointer equivalence via Hash-Value Numbering
+
+ // debugging options; disable all when committing
+ debugHVN = false // enable assertions in HVN
+ debugHVNVerbose = false // enable extra HVN logging
+ debugHVNCrossCheck = false // run solver with/without HVN and compare (caveats below)
+ debugTimers = false // show running time of each phase
+)
+
+// object.flags bitmask values.
+const (
+ otTagged = 1 << iota // type-tagged object
+ otIndirect // type-tagged object with indirect payload
+ otFunction // function object
+)
+
+// An object represents a contiguous block of memory to which some
+// (generalized) pointer may point.
+//
+// (Note: most variables called 'obj' are not *objects but nodeids
+// such that a.nodes[obj].obj != nil.)
+//
+type object struct {
+ // flags is a bitset of the node type (ot*) flags defined above.
+ flags uint32
+
+ // Number of following nodes belonging to the same "object"
+ // allocation. Zero for all other nodes.
+ size uint32
+
+ // data describes this object; it has one of these types:
+ //
+ // ssa.Value for an object allocated by an SSA operation.
+ // types.Type for an rtype instance object or *rtype-tagged object.
+ // string for an instrinsic object, e.g. the array behind os.Args.
+ // nil for an object allocated by an instrinsic.
+ // (cgn provides the identity of the intrinsic.)
+ data interface{}
+
+ // The call-graph node (=context) in which this object was allocated.
+ // May be nil for global objects: Global, Const, some Functions.
+ cgn *cgnode
+}
+
+// nodeid denotes a node.
+// It is an index within analysis.nodes.
+// We use small integers, not *node pointers, for many reasons:
+// - they are smaller on 64-bit systems.
+// - sets of them can be represented compactly in bitvectors or BDDs.
+// - order matters; a field offset can be computed by simple addition.
+type nodeid uint32
+
+// A node is an equivalence class of memory locations.
+// Nodes may be pointers, pointed-to locations, neither, or both.
+//
+// Nodes that are pointed-to locations ("labels") have an enclosing
+// object (see analysis.enclosingObject).
+//
+type node struct {
+ // If non-nil, this node is the start of an object
+ // (addressable memory location).
+ // The following obj.size nodes implicitly belong to the object;
+ // they locate their object by scanning back.
+ obj *object
+
+ // The type of the field denoted by this node. Non-aggregate,
+ // unless this is an tagged.T node (i.e. the thing
+ // pointed to by an interface) in which case typ is that type.
+ typ types.Type
+
+ // subelement indicates which directly embedded subelement of
+ // an object of aggregate type (struct, tuple, array) this is.
+ subelement *fieldInfo // e.g. ".a.b[*].c"
+
+ // Solver state for the canonical node of this pointer-
+ // equivalence class. Each node is created with its own state
+ // but they become shared after HVN.
+ solve *solverState
+}
+
+// An analysis instance holds the state of a single pointer analysis problem.
+type analysis struct {
+ config *Config // the client's control/observer interface
+ prog *ssa.Program // the program being analyzed
+ log io.Writer // log stream; nil to disable
+ panicNode nodeid // sink for panic, source for recover
+ nodes []*node // indexed by nodeid
+ flattenMemo map[types.Type][]*fieldInfo // memoization of flatten()
+ trackTypes map[types.Type]bool // memoization of shouldTrack()
+ constraints []constraint // set of constraints
+ cgnodes []*cgnode // all cgnodes
+ genq []*cgnode // queue of functions to generate constraints for
+ intrinsics map[*ssa.Function]intrinsic // non-nil values are summaries for intrinsic fns
+ globalval map[ssa.Value]nodeid // node for each global ssa.Value
+ globalobj map[ssa.Value]nodeid // maps v to sole member of pts(v), if singleton
+ localval map[ssa.Value]nodeid // node for each local ssa.Value
+ localobj map[ssa.Value]nodeid // maps v to sole member of pts(v), if singleton
+ atFuncs map[*ssa.Function]bool // address-taken functions (for presolver)
+ mapValues []nodeid // values of makemap objects (indirect in HVN)
+ work nodeset // solver's worklist
+ result *Result // results of the analysis
+ track track // pointerlike types whose aliasing we track
+ deltaSpace []int // working space for iterating over PTS deltas
+
+ // Reflection & intrinsics:
+ hasher typeutil.Hasher // cache of type hashes
+ reflectValueObj types.Object // type symbol for reflect.Value (if present)
+ reflectValueCall *ssa.Function // (reflect.Value).Call
+ reflectRtypeObj types.Object // *types.TypeName for reflect.rtype (if present)
+ reflectRtypePtr *types.Pointer // *reflect.rtype
+ reflectType *types.Named // reflect.Type
+ rtypes typeutil.Map // nodeid of canonical *rtype-tagged object for type T
+ reflectZeros typeutil.Map // nodeid of canonical T-tagged object for zero value
+ runtimeSetFinalizer *ssa.Function // runtime.SetFinalizer
+}
+
+// enclosingObj returns the first node of the addressable memory
+// object that encloses node id. Panic ensues if that node does not
+// belong to any object.
+func (a *analysis) enclosingObj(id nodeid) nodeid {
+ // Find previous node with obj != nil.
+ for i := id; i >= 0; i-- {
+ n := a.nodes[i]
+ if obj := n.obj; obj != nil {
+ if i+nodeid(obj.size) <= id {
+ break // out of bounds
+ }
+ return i
+ }
+ }
+ panic("node has no enclosing object")
+}
+
+// labelFor returns the Label for node id.
+// Panic ensues if that node is not addressable.
+func (a *analysis) labelFor(id nodeid) *Label {
+ return &Label{
+ obj: a.nodes[a.enclosingObj(id)].obj,
+ subelement: a.nodes[id].subelement,
+ }
+}
+
+func (a *analysis) warnf(pos token.Pos, format string, args ...interface{}) {
+ msg := fmt.Sprintf(format, args...)
+ if a.log != nil {
+ fmt.Fprintf(a.log, "%s: warning: %s\n", a.prog.Fset.Position(pos), msg)
+ }
+ a.result.Warnings = append(a.result.Warnings, Warning{pos, msg})
+}
+
+// computeTrackBits sets a.track to the necessary 'track' bits for the pointer queries.
+func (a *analysis) computeTrackBits() {
+ var queryTypes []types.Type
+ for v := range a.config.Queries {
+ queryTypes = append(queryTypes, v.Type())
+ }
+ for v := range a.config.IndirectQueries {
+ queryTypes = append(queryTypes, mustDeref(v.Type()))
+ }
+ for _, t := range queryTypes {
+ switch t.Underlying().(type) {
+ case *types.Chan:
+ a.track |= trackChan
+ case *types.Map:
+ a.track |= trackMap
+ case *types.Pointer:
+ a.track |= trackPtr
+ case *types.Slice:
+ a.track |= trackSlice
+ case *types.Interface:
+ a.track = trackAll
+ return
+ }
+ if rVObj := a.reflectValueObj; rVObj != nil && types.Identical(t, rVObj.Type()) {
+ a.track = trackAll
+ return
+ }
+ }
+}
+
+// Analyze runs the pointer analysis with the scope and options
+// specified by config, and returns the (synthetic) root of the callgraph.
+//
+// Pointer analysis of a transitively closed well-typed program should
+// always succeed. An error can occur only due to an internal bug.
+//
+func Analyze(config *Config) (result *Result, err error) {
+ if config.Mains == nil {
+ return nil, fmt.Errorf("no main/test packages to analyze (check $GOROOT/$GOPATH)")
+ }
+ defer func() {
+ if p := recover(); p != nil {
+ err = fmt.Errorf("internal error in pointer analysis: %v (please report this bug)", p)
+ fmt.Fprintln(os.Stderr, "Internal panic in pointer analysis:")
+ debug.PrintStack()
+ }
+ }()
+
+ a := &analysis{
+ config: config,
+ log: config.Log,
+ prog: config.prog(),
+ globalval: make(map[ssa.Value]nodeid),
+ globalobj: make(map[ssa.Value]nodeid),
+ flattenMemo: make(map[types.Type][]*fieldInfo),
+ trackTypes: make(map[types.Type]bool),
+ atFuncs: make(map[*ssa.Function]bool),
+ hasher: typeutil.MakeHasher(),
+ intrinsics: make(map[*ssa.Function]intrinsic),
+ result: &Result{
+ Queries: make(map[ssa.Value]Pointer),
+ IndirectQueries: make(map[ssa.Value]Pointer),
+ },
+ deltaSpace: make([]int, 0, 100),
+ }
+
+ if false {
+ a.log = os.Stderr // for debugging crashes; extremely verbose
+ }
+
+ if a.log != nil {
+ fmt.Fprintln(a.log, "==== Starting analysis")
+ }
+
+ // Pointer analysis requires a complete program for soundness.
+ // Check to prevent accidental misconfiguration.
+ for _, pkg := range a.prog.AllPackages() {
+ // (This only checks that the package scope is complete,
+ // not that func bodies exist, but it's a good signal.)
+ if !pkg.Object.Complete() {
+ return nil, fmt.Errorf(`pointer analysis requires a complete program yet package %q was incomplete`, pkg.Object.Path())
+ }
+ }
+
+ if reflect := a.prog.ImportedPackage("reflect"); reflect != nil {
+ rV := reflect.Object.Scope().Lookup("Value")
+ a.reflectValueObj = rV
+ a.reflectValueCall = a.prog.LookupMethod(rV.Type(), nil, "Call")
+ a.reflectType = reflect.Object.Scope().Lookup("Type").Type().(*types.Named)
+ a.reflectRtypeObj = reflect.Object.Scope().Lookup("rtype")
+ a.reflectRtypePtr = types.NewPointer(a.reflectRtypeObj.Type())
+
+ // Override flattening of reflect.Value, treating it like a basic type.
+ tReflectValue := a.reflectValueObj.Type()
+ a.flattenMemo[tReflectValue] = []*fieldInfo{{typ: tReflectValue}}
+
+ // Override shouldTrack of reflect.Value and *reflect.rtype.
+ // Always track pointers of these types.
+ a.trackTypes[tReflectValue] = true
+ a.trackTypes[a.reflectRtypePtr] = true
+
+ a.rtypes.SetHasher(a.hasher)
+ a.reflectZeros.SetHasher(a.hasher)
+ }
+ if runtime := a.prog.ImportedPackage("runtime"); runtime != nil {
+ a.runtimeSetFinalizer = runtime.Func("SetFinalizer")
+ }
+ a.computeTrackBits()
+
+ a.generate()
+ a.showCounts()
+
+ if optRenumber {
+ a.renumber()
+ }
+
+ N := len(a.nodes) // excludes solver-created nodes
+
+ if optHVN {
+ if debugHVNCrossCheck {
+ // Cross-check: run the solver once without
+ // optimization, once with, and compare the
+ // solutions.
+ savedConstraints := a.constraints
+
+ a.solve()
+ a.dumpSolution("A.pts", N)
+
+ // Restore.
+ a.constraints = savedConstraints
+ for _, n := range a.nodes {
+ n.solve = new(solverState)
+ }
+ a.nodes = a.nodes[:N]
+
+ // rtypes is effectively part of the solver state.
+ a.rtypes = typeutil.Map{}
+ a.rtypes.SetHasher(a.hasher)
+ }
+
+ a.hvn()
+ }
+
+ if debugHVNCrossCheck {
+ runtime.GC()
+ runtime.GC()
+ }
+
+ a.solve()
+
+ // Compare solutions.
+ if optHVN && debugHVNCrossCheck {
+ a.dumpSolution("B.pts", N)
+
+ if !diff("A.pts", "B.pts") {
+ return nil, fmt.Errorf("internal error: optimization changed solution")
+ }
+ }
+
+ // Create callgraph.Nodes in deterministic order.
+ if cg := a.result.CallGraph; cg != nil {
+ for _, caller := range a.cgnodes {
+ cg.CreateNode(caller.fn)
+ }
+ }
+
+ // Add dynamic edges to call graph.
+ var space [100]int
+ for _, caller := range a.cgnodes {
+ for _, site := range caller.sites {
+ for _, callee := range a.nodes[site.targets].solve.pts.AppendTo(space[:0]) {
+ a.callEdge(caller, site, nodeid(callee))
+ }
+ }
+ }
+
+ return a.result, nil
+}
+
+// callEdge is called for each edge in the callgraph.
+// calleeid is the callee's object node (has otFunction flag).
+//
+func (a *analysis) callEdge(caller *cgnode, site *callsite, calleeid nodeid) {
+ obj := a.nodes[calleeid].obj
+ if obj.flags&otFunction == 0 {
+ panic(fmt.Sprintf("callEdge %s -> n%d: not a function object", site, calleeid))
+ }
+ callee := obj.cgn
+
+ if cg := a.result.CallGraph; cg != nil {
+ // TODO(adonovan): opt: I would expect duplicate edges
+ // (to wrappers) to arise due to the elimination of
+ // context information, but I haven't observed any.
+ // Understand this better.
+ callgraph.AddEdge(cg.CreateNode(caller.fn), site.instr, cg.CreateNode(callee.fn))
+ }
+
+ if a.log != nil {
+ fmt.Fprintf(a.log, "\tcall edge %s -> %s\n", site, callee)
+ }
+
+ // Warn about calls to non-intrinsic external functions.
+ // TODO(adonovan): de-dup these messages.
+ if fn := callee.fn; fn.Blocks == nil && a.findIntrinsic(fn) == nil {
+ a.warnf(site.pos(), "unsound call to unknown intrinsic: %s", fn)
+ a.warnf(fn.Pos(), " (declared here)")
+ }
+}
+
+// dumpSolution writes the PTS solution to the specified file.
+//
+// It only dumps the nodes that existed before solving. The order in
+// which solver-created nodes are created depends on pre-solver
+// optimization, so we can't include them in the cross-check.
+//
+func (a *analysis) dumpSolution(filename string, N int) {
+ f, err := os.Create(filename)
+ if err != nil {
+ panic(err)
+ }
+ for id, n := range a.nodes[:N] {
+ if _, err := fmt.Fprintf(f, "pts(n%d) = {", id); err != nil {
+ panic(err)
+ }
+ var sep string
+ for _, l := range n.solve.pts.AppendTo(a.deltaSpace) {
+ if l >= N {
+ break
+ }
+ fmt.Fprintf(f, "%s%d", sep, l)
+ sep = " "
+ }
+ fmt.Fprintf(f, "} : %s\n", n.typ)
+ }
+ if err := f.Close(); err != nil {
+ panic(err)
+ }
+}
+
+// showCounts logs the size of the constraint system. A typical
+// optimized distribution is 65% copy, 13% load, 11% addr, 5%
+// offsetAddr, 4% store, 2% others.
+//
+func (a *analysis) showCounts() {
+ if a.log != nil {
+ counts := make(map[reflect.Type]int)
+ for _, c := range a.constraints {
+ counts[reflect.TypeOf(c)]++
+ }
+ fmt.Fprintf(a.log, "# constraints:\t%d\n", len(a.constraints))
+ var lines []string
+ for t, n := range counts {
+ line := fmt.Sprintf("%7d (%2d%%)\t%s", n, 100*n/len(a.constraints), t)
+ lines = append(lines, line)
+ }
+ sort.Sort(sort.Reverse(sort.StringSlice(lines)))
+ for _, line := range lines {
+ fmt.Fprintf(a.log, "\t%s\n", line)
+ }
+
+ fmt.Fprintf(a.log, "# nodes:\t%d\n", len(a.nodes))
+
+ // Show number of pointer equivalence classes.
+ m := make(map[*solverState]bool)
+ for _, n := range a.nodes {
+ m[n.solve] = true
+ }
+ fmt.Fprintf(a.log, "# ptsets:\t%d\n", len(m))
+ }
+}
diff --git a/go/pointer/api.go b/go/pointer/api.go
new file mode 100644
index 0000000..8f9ae0a
--- /dev/null
+++ b/go/pointer/api.go
@@ -0,0 +1,245 @@
+// 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 pointer
+
+import (
+ "bytes"
+ "fmt"
+ "go/token"
+ "io"
+
+ "golang.org/x/tools/container/intsets"
+ "golang.org/x/tools/go/callgraph"
+ "golang.org/x/tools/go/ssa"
+ "golang.org/x/tools/go/types/typeutil"
+)
+
+// A Config formulates a pointer analysis problem for Analyze().
+type Config struct {
+ // Mains contains the set of 'main' packages to analyze
+ // Clients must provide the analysis with at least one
+ // package defining a main() function.
+ //
+ // Non-main packages in the ssa.Program that are not
+ // dependencies of any main package may still affect the
+ // analysis result, because they contribute runtime types and
+ // thus methods.
+ // TODO(adonovan): investigate whether this is desirable.
+ Mains []*ssa.Package
+
+ // Reflection determines whether to handle reflection
+ // operators soundly, which is currently rather slow since it
+ // causes constraint to be generated during solving
+ // proportional to the number of constraint variables, which
+ // has not yet been reduced by presolver optimisation.
+ Reflection bool
+
+ // BuildCallGraph determines whether to construct a callgraph.
+ // If enabled, the graph will be available in Result.CallGraph.
+ BuildCallGraph bool
+
+ // The client populates Queries[v] or IndirectQueries[v]
+ // for each ssa.Value v of interest, to request that the
+ // points-to sets pts(v) or pts(*v) be computed. If the
+ // client needs both points-to sets, v may appear in both
+ // maps.
+ //
+ // (IndirectQueries is typically used for Values corresponding
+ // to source-level lvalues, e.g. an *ssa.Global.)
+ //
+ // The analysis populates the corresponding
+ // Result.{Indirect,}Queries map when it creates the pointer
+ // variable for v or *v. Upon completion the client can
+ // inspect that map for the results.
+ //
+ // TODO(adonovan): this API doesn't scale well for batch tools
+ // that want to dump the entire solution. Perhaps optionally
+ // populate a map[*ssa.DebugRef]Pointer in the Result, one
+ // entry per source expression.
+ //
+ Queries map[ssa.Value]struct{}
+ IndirectQueries map[ssa.Value]struct{}
+
+ // If Log is non-nil, log messages are written to it.
+ // Logging is extremely verbose.
+ Log io.Writer
+}
+
+type track uint32
+
+const (
+ trackChan track = 1 << iota // track 'chan' references
+ trackMap // track 'map' references
+ trackPtr // track regular pointers
+ trackSlice // track slice references
+
+ trackAll = ^track(0)
+)
+
+// AddQuery adds v to Config.Queries.
+// Precondition: CanPoint(v.Type()).
+// TODO(adonovan): consider returning a new Pointer for this query,
+// which will be initialized during analysis. That avoids the needs
+// for the corresponding ssa.Value-keyed maps in Config and Result.
+func (c *Config) AddQuery(v ssa.Value) {
+ if !CanPoint(v.Type()) {
+ panic(fmt.Sprintf("%s is not a pointer-like value: %s", v, v.Type()))
+ }
+ if c.Queries == nil {
+ c.Queries = make(map[ssa.Value]struct{})
+ }
+ c.Queries[v] = struct{}{}
+}
+
+// AddQuery adds v to Config.IndirectQueries.
+// Precondition: CanPoint(v.Type().Underlying().(*types.Pointer).Elem()).
+func (c *Config) AddIndirectQuery(v ssa.Value) {
+ if c.IndirectQueries == nil {
+ c.IndirectQueries = make(map[ssa.Value]struct{})
+ }
+ if !CanPoint(mustDeref(v.Type())) {
+ panic(fmt.Sprintf("%s is not the address of a pointer-like value: %s", v, v.Type()))
+ }
+ c.IndirectQueries[v] = struct{}{}
+}
+
+func (c *Config) prog() *ssa.Program {
+ for _, main := range c.Mains {
+ return main.Prog
+ }
+ panic("empty scope")
+}
+
+type Warning struct {
+ Pos token.Pos
+ Message string
+}
+
+// A Result contains the results of a pointer analysis.
+//
+// See Config for how to request the various Result components.
+//
+type Result struct {
+ CallGraph *callgraph.Graph // discovered call graph
+ Queries map[ssa.Value]Pointer // pts(v) for each v in Config.Queries.
+ IndirectQueries map[ssa.Value]Pointer // pts(*v) for each v in Config.IndirectQueries.
+ Warnings []Warning // warnings of unsoundness
+}
+
+// A Pointer is an equivalence class of pointer-like values.
+//
+// A Pointer doesn't have a unique type because pointers of distinct
+// types may alias the same object.
+//
+type Pointer struct {
+ a *analysis
+ n nodeid
+}
+
+// A PointsToSet is a set of labels (locations or allocations).
+type PointsToSet struct {
+ a *analysis // may be nil if pts is nil
+ pts *nodeset
+}
+
+func (s PointsToSet) String() string {
+ var buf bytes.Buffer
+ buf.WriteByte('[')
+ if s.pts != nil {
+ var space [50]int
+ for i, l := range s.pts.AppendTo(space[:0]) {
+ if i > 0 {
+ buf.WriteString(", ")
+ }
+ buf.WriteString(s.a.labelFor(nodeid(l)).String())
+ }
+ }
+ buf.WriteByte(']')
+ return buf.String()
+}
+
+// PointsTo returns the set of labels that this points-to set
+// contains.
+func (s PointsToSet) Labels() []*Label {
+ var labels []*Label
+ if s.pts != nil {
+ var space [50]int
+ for _, l := range s.pts.AppendTo(space[:0]) {
+ labels = append(labels, s.a.labelFor(nodeid(l)))
+ }
+ }
+ return labels
+}
+
+// If this PointsToSet came from a Pointer of interface kind
+// or a reflect.Value, DynamicTypes returns the set of dynamic
+// types that it may contain. (For an interface, they will
+// always be concrete types.)
+//
+// The result is a mapping whose keys are the dynamic types to which
+// it may point. For each pointer-like key type, the corresponding
+// map value is the PointsToSet for pointers of that type.
+//
+// The result is empty unless CanHaveDynamicTypes(T).
+//
+func (s PointsToSet) DynamicTypes() *typeutil.Map {
+ var tmap typeutil.Map
+ tmap.SetHasher(s.a.hasher)
+ if s.pts != nil {
+ var space [50]int
+ for _, x := range s.pts.AppendTo(space[:0]) {
+ ifaceObjId := nodeid(x)
+ if !s.a.isTaggedObject(ifaceObjId) {
+ continue // !CanHaveDynamicTypes(tDyn)
+ }
+ tDyn, v, indirect := s.a.taggedValue(ifaceObjId)
+ if indirect {
+ panic("indirect tagged object") // implement later
+ }
+ pts, ok := tmap.At(tDyn).(PointsToSet)
+ if !ok {
+ pts = PointsToSet{s.a, new(nodeset)}
+ tmap.Set(tDyn, pts)
+ }
+ pts.pts.addAll(&s.a.nodes[v].solve.pts)
+ }
+ }
+ return &tmap
+}
+
+// Intersects reports whether this points-to set and the
+// argument points-to set contain common members.
+func (x PointsToSet) Intersects(y PointsToSet) bool {
+ if x.pts == nil || y.pts == nil {
+ return false
+ }
+ // This takes Θ(|x|+|y|) time.
+ var z intsets.Sparse
+ z.Intersection(&x.pts.Sparse, &y.pts.Sparse)
+ return !z.IsEmpty()
+}
+
+func (p Pointer) String() string {
+ return fmt.Sprintf("n%d", p.n)
+}
+
+// PointsTo returns the points-to set of this pointer.
+func (p Pointer) PointsTo() PointsToSet {
+ if p.n == 0 {
+ return PointsToSet{}
+ }
+ return PointsToSet{p.a, &p.a.nodes[p.n].solve.pts}
+}
+
+// MayAlias reports whether the receiver pointer may alias
+// the argument pointer.
+func (p Pointer) MayAlias(q Pointer) bool {
+ return p.PointsTo().Intersects(q.PointsTo())
+}
+
+// DynamicTypes returns p.PointsTo().DynamicTypes().
+func (p Pointer) DynamicTypes() *typeutil.Map {
+ return p.PointsTo().DynamicTypes()
+}
diff --git a/go/pointer/callgraph.go b/go/pointer/callgraph.go
new file mode 100644
index 0000000..48e152e
--- /dev/null
+++ b/go/pointer/callgraph.go
@@ -0,0 +1,61 @@
+// 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 pointer
+
+// This file defines the internal (context-sensitive) call graph.
+
+import (
+ "fmt"
+ "go/token"
+
+ "golang.org/x/tools/go/ssa"
+)
+
+type cgnode struct {
+ fn *ssa.Function
+ obj nodeid // start of this contour's object block
+ sites []*callsite // ordered list of callsites within this function
+ callersite *callsite // where called from, if known; nil for shared contours
+}
+
+// contour returns a description of this node's contour.
+func (n *cgnode) contour() string {
+ if n.callersite == nil {
+ return "shared contour"
+ }
+ if n.callersite.instr != nil {
+ return fmt.Sprintf("as called from %s", n.callersite.instr.Parent())
+ }
+ return fmt.Sprintf("as called from intrinsic (targets=n%d)", n.callersite.targets)
+}
+
+func (n *cgnode) String() string {
+ return fmt.Sprintf("cg%d:%s", n.obj, n.fn)
+}
+
+// A callsite represents a single call site within a cgnode;
+// it is implicitly context-sensitive.
+// callsites never represent calls to built-ins;
+// they are handled as intrinsics.
+//
+type callsite struct {
+ targets nodeid // pts(·) contains objects for dynamically called functions
+ instr ssa.CallInstruction // the call instruction; nil for synthetic/intrinsic
+}
+
+func (c *callsite) String() string {
+ if c.instr != nil {
+ return c.instr.Common().Description()
+ }
+ return "synthetic function call"
+}
+
+// pos returns the source position of this callsite, or token.NoPos if implicit.
+func (c *callsite) pos() token.Pos {
+ if c.instr != nil {
+ return c.instr.Pos()
+ }
+ return token.NoPos
+}
diff --git a/go/pointer/constraint.go b/go/pointer/constraint.go
new file mode 100644
index 0000000..e6371cc
--- /dev/null
+++ b/go/pointer/constraint.go
@@ -0,0 +1,151 @@
+// 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 pointer
+
+import (
+ "golang.org/x/tools/go/types"
+)
+
+type constraint interface {
+ // For a complex constraint, returns the nodeid of the pointer
+ // to which it is attached. For addr and copy, returns dst.
+ ptr() nodeid
+
+ // renumber replaces each nodeid n in the constraint by mapping[n].
+ renumber(mapping []nodeid)
+
+ // presolve is a hook for constraint-specific behaviour during
+ // pre-solver optimization. Typical implementations mark as
+ // indirect the set of nodes to which the solver will add copy
+ // edges or PTS labels.
+ presolve(h *hvn)
+
+ // solve is called for complex constraints when the pts for
+ // the node to which they are attached has changed.
+ solve(a *analysis, delta *nodeset)
+
+ String() string
+}
+
+// dst = &src
+// pts(dst) ⊇ {src}
+// A base constraint used to initialize the solver's pt sets
+type addrConstraint struct {
+ dst nodeid // (ptr)
+ src nodeid
+}
+
+func (c *addrConstraint) ptr() nodeid { return c.dst }
+func (c *addrConstraint) renumber(mapping []nodeid) {
+ c.dst = mapping[c.dst]
+ c.src = mapping[c.src]
+}
+
+// dst = src
+// A simple constraint represented directly as a copyTo graph edge.
+type copyConstraint struct {
+ dst nodeid // (ptr)
+ src nodeid
+}
+
+func (c *copyConstraint) ptr() nodeid { return c.dst }
+func (c *copyConstraint) renumber(mapping []nodeid) {
+ c.dst = mapping[c.dst]
+ c.src = mapping[c.src]
+}
+
+// dst = src[offset]
+// A complex constraint attached to src (the pointer)
+type loadConstraint struct {
+ offset uint32
+ dst nodeid
+ src nodeid // (ptr)
+}
+
+func (c *loadConstraint) ptr() nodeid { return c.src }
+func (c *loadConstraint) renumber(mapping []nodeid) {
+ c.dst = mapping[c.dst]
+ c.src = mapping[c.src]
+}
+
+// dst[offset] = src
+// A complex constraint attached to dst (the pointer)
+type storeConstraint struct {
+ offset uint32
+ dst nodeid // (ptr)
+ src nodeid
+}
+
+func (c *storeConstraint) ptr() nodeid { return c.dst }
+func (c *storeConstraint) renumber(mapping []nodeid) {
+ c.dst = mapping[c.dst]
+ c.src = mapping[c.src]
+}
+
+// dst = &src.f or dst = &src[0]
+// A complex constraint attached to dst (the pointer)
+type offsetAddrConstraint struct {
+ offset uint32
+ dst nodeid
+ src nodeid // (ptr)
+}
+
+func (c *offsetAddrConstraint) ptr() nodeid { return c.src }
+func (c *offsetAddrConstraint) renumber(mapping []nodeid) {
+ c.dst = mapping[c.dst]
+ c.src = mapping[c.src]
+}
+
+// dst = src.(typ) where typ is an interface
+// A complex constraint attached to src (the interface).
+// No representation change: pts(dst) and pts(src) contains tagged objects.
+type typeFilterConstraint struct {
+ typ types.Type // an interface type
+ dst nodeid
+ src nodeid // (ptr)
+}
+
+func (c *typeFilterConstraint) ptr() nodeid { return c.src }
+func (c *typeFilterConstraint) renumber(mapping []nodeid) {
+ c.dst = mapping[c.dst]
+ c.src = mapping[c.src]
+}
+
+// dst = src.(typ) where typ is a concrete type
+// A complex constraint attached to src (the interface).
+//
+// If exact, only tagged objects identical to typ are untagged.
+// If !exact, tagged objects assignable to typ are untagged too.
+// The latter is needed for various reflect operators, e.g. Send.
+//
+// This entails a representation change:
+// pts(src) contains tagged objects,
+// pts(dst) contains their payloads.
+type untagConstraint struct {
+ typ types.Type // a concrete type
+ dst nodeid
+ src nodeid // (ptr)
+ exact bool
+}
+
+func (c *untagConstraint) ptr() nodeid { return c.src }
+func (c *untagConstraint) renumber(mapping []nodeid) {
+ c.dst = mapping[c.dst]
+ c.src = mapping[c.src]
+}
+
+// src.method(params...)
+// A complex constraint attached to iface.
+type invokeConstraint struct {
+ method *types.Func // the abstract method
+ iface nodeid // (ptr) the interface
+ params nodeid // the start of the identity/params/results block
+}
+
+func (c *invokeConstraint) ptr() nodeid { return c.iface }
+func (c *invokeConstraint) renumber(mapping []nodeid) {
+ c.iface = mapping[c.iface]
+ c.params = mapping[c.params]
+}
diff --git a/go/pointer/doc.go b/go/pointer/doc.go
new file mode 100644
index 0000000..22e569c
--- /dev/null
+++ b/go/pointer/doc.go
@@ -0,0 +1,610 @@
+// 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 pointer implements Andersen's analysis, an inclusion-based
+pointer analysis algorithm first described in (Andersen, 1994).
+
+A pointer analysis relates every pointer expression in a whole program
+to the set of memory locations to which it might point. This
+information can be used to construct a call graph of the program that
+precisely represents the destinations of dynamic function and method
+calls. It can also be used to determine, for example, which pairs of
+channel operations operate on the same channel.
+
+The package allows the client to request a set of expressions of
+interest for which the points-to information will be returned once the
+analysis is complete. In addition, the client may request that a
+callgraph is constructed. The example program in example_test.go
+demonstrates both of these features. Clients should not request more
+information than they need since it may increase the cost of the
+analysis significantly.
+
+
+CLASSIFICATION
+
+Our algorithm is INCLUSION-BASED: the points-to sets for x and y will
+be related by pts(y) ⊇ pts(x) if the program contains the statement
+y = x.
+
+It is FLOW-INSENSITIVE: it ignores all control flow constructs and the
+order of statements in a program. It is therefore a "MAY ALIAS"
+analysis: its facts are of the form "P may/may not point to L",
+not "P must point to L".
+
+It is FIELD-SENSITIVE: it builds separate points-to sets for distinct
+fields, such as x and y in struct { x, y *int }.
+
+It is mostly CONTEXT-INSENSITIVE: most functions are analyzed once,
+so values can flow in at one call to the function and return out at
+another. Only some smaller functions are analyzed with consideration
+of their calling context.
+
+It has a CONTEXT-SENSITIVE HEAP: objects are named by both allocation
+site and context, so the objects returned by two distinct calls to f:
+ func f() *T { return new(T) }
+are distinguished up to the limits of the calling context.
+
+It is a WHOLE PROGRAM analysis: it requires SSA-form IR for the
+complete Go program and summaries for native code.
+
+See the (Hind, PASTE'01) survey paper for an explanation of these terms.
+
+
+SOUNDNESS
+
+The analysis is fully sound when invoked on pure Go programs that do not
+use reflection or unsafe.Pointer conversions. In other words, if there
+is any possible execution of the program in which pointer P may point to
+object O, the analysis will report that fact.
+
+
+REFLECTION
+
+By default, the "reflect" library is ignored by the analysis, as if all
+its functions were no-ops, but if the client enables the Reflection flag,
+the analysis will make a reasonable attempt to model the effects of
+calls into this library. However, this comes at a significant
+performance cost, and not all features of that library are yet
+implemented. In addition, some simplifying approximations must be made
+to ensure that the analysis terminates; for example, reflection can be
+used to construct an infinite set of types and values of those types,
+but the analysis arbitrarily bounds the depth of such types.
+
+Most but not all reflection operations are supported.
+In particular, addressable reflect.Values are not yet implemented, so
+operations such as (reflect.Value).Set have no analytic effect.
+
+
+UNSAFE POINTER CONVERSIONS
+
+The pointer analysis makes no attempt to understand aliasing between the
+operand x and result y of an unsafe.Pointer conversion:
+ y = (*T)(unsafe.Pointer(x))
+It is as if the conversion allocated an entirely new object:
+ y = new(T)
+
+
+NATIVE CODE
+
+The analysis cannot model the aliasing effects of functions written in
+languages other than Go, such as runtime intrinsics in C or assembly, or
+code accessed via cgo. The result is as if such functions are no-ops.
+However, various important intrinsics are understood by the analysis,
+along with built-ins such as append.
+
+The analysis currently provides no way for users to specify the aliasing
+effects of native code.
+
+------------------------------------------------------------------------
+
+IMPLEMENTATION
+
+The remaining documentation is intended for package maintainers and
+pointer analysis specialists. Maintainers should have a solid
+understanding of the referenced papers (especially those by H&L and PKH)
+before making making significant changes.
+
+The implementation is similar to that described in (Pearce et al,
+PASTE'04). Unlike many algorithms which interleave constraint
+generation and solving, constructing the callgraph as they go, this
+implementation for the most part observes a phase ordering (generation
+before solving), with only simple (copy) constraints being generated
+during solving. (The exception is reflection, which creates various
+constraints during solving as new types flow to reflect.Value
+operations.) This improves the traction of presolver optimisations,
+but imposes certain restrictions, e.g. potential context sensitivity
+is limited since all variants must be created a priori.
+
+
+TERMINOLOGY
+
+A type is said to be "pointer-like" if it is a reference to an object.
+Pointer-like types include pointers and also interfaces, maps, channels,
+functions and slices.
+
+We occasionally use C's x->f notation to distinguish the case where x
+is a struct pointer from x.f where is a struct value.
+
+Pointer analysis literature (and our comments) often uses the notation
+dst=*src+offset to mean something different than what it means in Go.
+It means: for each node index p in pts(src), the node index p+offset is
+in pts(dst). Similarly *dst+offset=src is used for store constraints
+and dst=src+offset for offset-address constraints.
+
+
+NODES
+
+Nodes are the key datastructure of the analysis, and have a dual role:
+they represent both constraint variables (equivalence classes of
+pointers) and members of points-to sets (things that can be pointed
+at, i.e. "labels").
+
+Nodes are naturally numbered. The numbering enables compact
+representations of sets of nodes such as bitvectors (or BDDs); and the
+ordering enables a very cheap way to group related nodes together. For
+example, passing n parameters consists of generating n parallel
+constraints from caller+i to callee+i for 0<=i<n.
+
+The zero nodeid means "not a pointer". For simplicity, we generate flow
+constraints even for non-pointer types such as int. The pointer
+equivalence (PE) presolver optimization detects which variables cannot
+point to anything; this includes not only all variables of non-pointer
+types (such as int) but also variables of pointer-like types if they are
+always nil, or are parameters to a function that is never called.
+
+Each node represents a scalar part of a value or object.
+Aggregate types (structs, tuples, arrays) are recursively flattened
+out into a sequential list of scalar component types, and all the
+elements of an array are represented by a single node. (The
+flattening of a basic type is a list containing a single node.)
+
+Nodes are connected into a graph with various kinds of labelled edges:
+simple edges (or copy constraints) represent value flow. Complex
+edges (load, store, etc) trigger the creation of new simple edges
+during the solving phase.
+
+
+OBJECTS
+
+Conceptually, an "object" is a contiguous sequence of nodes denoting
+an addressable location: something that a pointer can point to. The
+first node of an object has a non-nil obj field containing information
+about the allocation: its size, context, and ssa.Value.
+
+Objects include:
+ - functions and globals;
+ - variable allocations in the stack frame or heap;
+ - maps, channels and slices created by calls to make();
+ - allocations to construct an interface;
+ - allocations caused by conversions, e.g. []byte(str).
+ - arrays allocated by calls to append();
+
+Many objects have no Go types. For example, the func, map and chan type
+kinds in Go are all varieties of pointers, but their respective objects
+are actual functions (executable code), maps (hash tables), and channels
+(synchronized queues). Given the way we model interfaces, they too are
+pointers to "tagged" objects with no Go type. And an *ssa.Global denotes
+the address of a global variable, but the object for a Global is the
+actual data. So, the types of an ssa.Value that creates an object is
+"off by one indirection": a pointer to the object.
+
+The individual nodes of an object are sometimes referred to as "labels".
+
+For uniformity, all objects have a non-zero number of fields, even those
+of the empty type struct{}. (All arrays are treated as if of length 1,
+so there are no empty arrays. The empty tuple is never address-taken,
+so is never an object.)
+
+
+TAGGED OBJECTS
+
+An tagged object has the following layout:
+
+ T -- obj.flags ⊇ {otTagged}
+ v
+ ...
+
+The T node's typ field is the dynamic type of the "payload": the value
+v which follows, flattened out. The T node's obj has the otTagged
+flag.
+
+Tagged objects are needed when generalizing across types: interfaces,
+reflect.Values, reflect.Types. Each of these three types is modelled
+as a pointer that exclusively points to tagged objects.
+
+Tagged objects may be indirect (obj.flags ⊇ {otIndirect}) meaning that
+the value v is not of type T but *T; this is used only for
+reflect.Values that represent lvalues. (These are not implemented yet.)
+
+
+ANALYSIS ABSTRACTION OF EACH TYPE
+
+Variables of the following "scalar" types may be represented by a
+single node: basic types, pointers, channels, maps, slices, 'func'
+pointers, interfaces.
+
+Pointers
+ Nothing to say here, oddly.
+
+Basic types (bool, string, numbers, unsafe.Pointer)
+ Currently all fields in the flattening of a type, including
+ non-pointer basic types such as int, are represented in objects and
+ values. Though non-pointer nodes within values are uninteresting,
+ non-pointer nodes in objects may be useful (if address-taken)
+ because they permit the analysis to deduce, in this example,
+
+ var s struct{ ...; x int; ... }
+ p := &s.x
+
+ that p points to s.x. If we ignored such object fields, we could only
+ say that p points somewhere within s.
+
+ All other basic types are ignored. Expressions of these types have
+ zero nodeid, and fields of these types within aggregate other types
+ are omitted.
+
+ unsafe.Pointers are not modelled as pointers, so a conversion of an
+ unsafe.Pointer to *T is (unsoundly) treated equivalent to new(T).
+
+Channels
+ An expression of type 'chan T' is a kind of pointer that points
+ exclusively to channel objects, i.e. objects created by MakeChan (or
+ reflection).
+
+ 'chan T' is treated like *T.
+ *ssa.MakeChan is treated as equivalent to new(T).
+ *ssa.Send and receive (*ssa.UnOp(ARROW)) and are equivalent to store
+ and load.
+
+Maps
+ An expression of type 'map[K]V' is a kind of pointer that points
+ exclusively to map objects, i.e. objects created by MakeMap (or
+ reflection).
+
+ map K[V] is treated like *M where M = struct{k K; v V}.
+ *ssa.MakeMap is equivalent to new(M).
+ *ssa.MapUpdate is equivalent to *y=x where *y and x have type M.
+ *ssa.Lookup is equivalent to y=x.v where x has type *M.
+
+Slices
+ A slice []T, which dynamically resembles a struct{array *T, len, cap int},
+ is treated as if it were just a *T pointer; the len and cap fields are
+ ignored.
+
+ *ssa.MakeSlice is treated like new([1]T): an allocation of a
+ singleton array.
+ *ssa.Index on a slice is equivalent to a load.
+ *ssa.IndexAddr on a slice returns the address of the sole element of the
+ slice, i.e. the same address.
+ *ssa.Slice is treated as a simple copy.
+
+Functions
+ An expression of type 'func...' is a kind of pointer that points
+ exclusively to function objects.
+
+ A function object has the following layout:
+
+ identity -- typ:*types.Signature; obj.flags ⊇ {otFunction}
+ params_0 -- (the receiver, if a method)
+ ...
+ params_n-1
+ results_0
+ ...
+ results_m-1
+
+ There may be multiple function objects for the same *ssa.Function
+ due to context-sensitive treatment of some functions.
+
+ The first node is the function's identity node.
+ Associated with every callsite is a special "targets" variable,
+ whose pts() contains the identity node of each function to which
+ the call may dispatch. Identity words are not otherwise used during
+ the analysis, but we construct the call graph from the pts()
+ solution for such nodes.
+
+ The following block of contiguous nodes represents the flattened-out
+ types of the parameters ("P-block") and results ("R-block") of the
+ function object.
+
+ The treatment of free variables of closures (*ssa.FreeVar) is like
+ that of global variables; it is not context-sensitive.
+ *ssa.MakeClosure instructions create copy edges to Captures.
+
+ A Go value of type 'func' (i.e. a pointer to one or more functions)
+ is a pointer whose pts() contains function objects. The valueNode()
+ for an *ssa.Function returns a singleton for that function.
+
+Interfaces
+ An expression of type 'interface{...}' is a kind of pointer that
+ points exclusively to tagged objects. All tagged objects pointed to
+ by an interface are direct (the otIndirect flag is clear) and
+ concrete (the tag type T is not itself an interface type). The
+ associated ssa.Value for an interface's tagged objects may be an
+ *ssa.MakeInterface instruction, or nil if the tagged object was
+ created by an instrinsic (e.g. reflection).
+
+ Constructing an interface value causes generation of constraints for
+ all of the concrete type's methods; we can't tell a priori which
+ ones may be called.
+
+ TypeAssert y = x.(T) is implemented by a dynamic constraint
+ triggered by each tagged object O added to pts(x): a typeFilter
+ constraint if T is an interface type, or an untag constraint if T is
+ a concrete type. A typeFilter tests whether O.typ implements T; if
+ so, O is added to pts(y). An untagFilter tests whether O.typ is
+ assignable to T,and if so, a copy edge O.v -> y is added.
+
+ ChangeInterface is a simple copy because the representation of
+ tagged objects is independent of the interface type (in contrast
+ to the "method tables" approach used by the gc runtime).
+
+ y := Invoke x.m(...) is implemented by allocating contiguous P/R
+ blocks for the callsite and adding a dynamic rule triggered by each
+ tagged object added to pts(x). The rule adds param/results copy
+ edges to/from each discovered concrete method.
+
+ (Q. Why do we model an interface as a pointer to a pair of type and
+ value, rather than as a pair of a pointer to type and a pointer to
+ value?
+ A. Control-flow joins would merge interfaces ({T1}, {V1}) and ({T2},
+ {V2}) to make ({T1,T2}, {V1,V2}), leading to the infeasible and
+ type-unsafe combination (T1,V2). Treating the value and its concrete
+ type as inseparable makes the analysis type-safe.)
+
+reflect.Value
+ A reflect.Value is modelled very similar to an interface{}, i.e. as
+ a pointer exclusively to tagged objects, but with two generalizations.
+
+ 1) a reflect.Value that represents an lvalue points to an indirect
+ (obj.flags ⊇ {otIndirect}) tagged object, which has a similar
+ layout to an tagged object except that the value is a pointer to
+ the dynamic type. Indirect tagged objects preserve the correct
+ aliasing so that mutations made by (reflect.Value).Set can be
+ observed.
+
+ Indirect objects only arise when an lvalue is derived from an
+ rvalue by indirection, e.g. the following code:
+
+ type S struct { X T }
+ var s S
+ var i interface{} = &s // i points to a *S-tagged object (from MakeInterface)
+ v1 := reflect.ValueOf(i) // v1 points to same *S-tagged object as i
+ v2 := v1.Elem() // v2 points to an indirect S-tagged object, pointing to s
+ v3 := v2.FieldByName("X") // v3 points to an indirect int-tagged object, pointing to s.X
+ v3.Set(y) // pts(s.X) ⊇ pts(y)
+
+ Whether indirect or not, the concrete type of the tagged object
+ corresponds to the user-visible dynamic type, and the existence
+ of a pointer is an implementation detail.
+
+ (NB: indirect tagged objects are not yet implemented)
+
+ 2) The dynamic type tag of a tagged object pointed to by a
+ reflect.Value may be an interface type; it need not be concrete.
+
+ This arises in code such as this:
+ tEface := reflect.TypeOf(new(interface{}).Elem() // interface{}
+ eface := reflect.Zero(tEface)
+ pts(eface) is a singleton containing an interface{}-tagged
+ object. That tagged object's payload is an interface{} value,
+ i.e. the pts of the payload contains only concrete-tagged
+ objects, although in this example it's the zero interface{} value,
+ so its pts is empty.
+
+reflect.Type
+ Just as in the real "reflect" library, we represent a reflect.Type
+ as an interface whose sole implementation is the concrete type,
+ *reflect.rtype. (This choice is forced on us by go/types: clients
+ cannot fabricate types with arbitrary method sets.)
+
+ rtype instances are canonical: there is at most one per dynamic
+ type. (rtypes are in fact large structs but since identity is all
+ that matters, we represent them by a single node.)
+
+ The payload of each *rtype-tagged object is an *rtype pointer that
+ points to exactly one such canonical rtype object. We exploit this
+ by setting the node.typ of the payload to the dynamic type, not
+ '*rtype'. This saves us an indirection in each resolution rule. As
+ an optimisation, *rtype-tagged objects are canonicalized too.
+
+
+Aggregate types:
+
+Aggregate types are treated as if all directly contained
+aggregates are recursively flattened out.
+
+Structs
+ *ssa.Field y = x.f creates a simple edge to y from x's node at f's offset.
+
+ *ssa.FieldAddr y = &x->f requires a dynamic closure rule to create
+ simple edges for each struct discovered in pts(x).
+
+ The nodes of a struct consist of a special 'identity' node (whose
+ type is that of the struct itself), followed by the nodes for all
+ the struct's fields, recursively flattened out. A pointer to the
+ struct is a pointer to its identity node. That node allows us to
+ distinguish a pointer to a struct from a pointer to its first field.
+
+ Field offsets are logical field offsets (plus one for the identity
+ node), so the sizes of the fields can be ignored by the analysis.
+
+ (The identity node is non-traditional but enables the distiction
+ described above, which is valuable for code comprehension tools.
+ Typical pointer analyses for C, whose purpose is compiler
+ optimization, must soundly model unsafe.Pointer (void*) conversions,
+ and this requires fidelity to the actual memory layout using physical
+ field offsets.)
+
+ *ssa.Field y = x.f creates a simple edge to y from x's node at f's offset.
+
+ *ssa.FieldAddr y = &x->f requires a dynamic closure rule to create
+ simple edges for each struct discovered in pts(x).
+
+Arrays
+ We model an array by an identity node (whose type is that of the
+ array itself) followed by a node representing all the elements of
+ the array; the analysis does not distinguish elements with different
+ indices. Effectively, an array is treated like struct{elem T}, a
+ load y=x[i] like y=x.elem, and a store x[i]=y like x.elem=y; the
+ index i is ignored.
+
+ A pointer to an array is pointer to its identity node. (A slice is
+ also a pointer to an array's identity node.) The identity node
+ allows us to distinguish a pointer to an array from a pointer to one
+ of its elements, but it is rather costly because it introduces more
+ offset constraints into the system. Furthermore, sound treatment of
+ unsafe.Pointer would require us to dispense with this node.
+
+ Arrays may be allocated by Alloc, by make([]T), by calls to append,
+ and via reflection.
+
+Tuples (T, ...)
+ Tuples are treated like structs with naturally numbered fields.
+ *ssa.Extract is analogous to *ssa.Field.
+
+ However, tuples have no identity field since by construction, they
+ cannot be address-taken.
+
+
+FUNCTION CALLS
+
+ There are three kinds of function call:
+ (1) static "call"-mode calls of functions.
+ (2) dynamic "call"-mode calls of functions.
+ (3) dynamic "invoke"-mode calls of interface methods.
+ Cases 1 and 2 apply equally to methods and standalone functions.
+
+ Static calls.
+ A static call consists three steps:
+ - finding the function object of the callee;
+ - creating copy edges from the actual parameter value nodes to the
+ P-block in the function object (this includes the receiver if
+ the callee is a method);
+ - creating copy edges from the R-block in the function object to
+ the value nodes for the result of the call.
+
+ A static function call is little more than two struct value copies
+ between the P/R blocks of caller and callee:
+
+ callee.P = caller.P
+ caller.R = callee.R
+
+ Context sensitivity
+
+ Static calls (alone) may be treated context sensitively,
+ i.e. each callsite may cause a distinct re-analysis of the
+ callee, improving precision. Our current context-sensitivity
+ policy treats all intrinsics and getter/setter methods in this
+ manner since such functions are small and seem like an obvious
+ source of spurious confluences, though this has not yet been
+ evaluated.
+
+ Dynamic function calls
+
+ Dynamic calls work in a similar manner except that the creation of
+ copy edges occurs dynamically, in a similar fashion to a pair of
+ struct copies in which the callee is indirect:
+
+ callee->P = caller.P
+ caller.R = callee->R
+
+ (Recall that the function object's P- and R-blocks are contiguous.)
+
+ Interface method invocation
+
+ For invoke-mode calls, we create a params/results block for the
+ callsite and attach a dynamic closure rule to the interface. For
+ each new tagged object that flows to the interface, we look up
+ the concrete method, find its function object, and connect its P/R
+ blocks to the callsite's P/R blocks, adding copy edges to the graph
+ during solving.
+
+ Recording call targets
+
+ The analysis notifies its clients of each callsite it encounters,
+ passing a CallSite interface. Among other things, the CallSite
+ contains a synthetic constraint variable ("targets") whose
+ points-to solution includes the set of all function objects to
+ which the call may dispatch.
+
+ It is via this mechanism that the callgraph is made available.
+ Clients may also elect to be notified of callgraph edges directly;
+ internally this just iterates all "targets" variables' pts(·)s.
+
+
+PRESOLVER
+
+We implement Hash-Value Numbering (HVN), a pre-solver constraint
+optimization described in Hardekopf & Lin, SAS'07. This is documented
+in more detail in hvn.go. We intend to add its cousins HR and HU in
+future.
+
+
+SOLVER
+
+The solver is currently a naive Andersen-style implementation; it does
+not perform online cycle detection, though we plan to add solver
+optimisations such as Hybrid- and Lazy- Cycle Detection from (Hardekopf
+& Lin, PLDI'07).
+
+It uses difference propagation (Pearce et al, SQC'04) to avoid
+redundant re-triggering of closure rules for values already seen.
+
+Points-to sets are represented using sparse bit vectors (similar to
+those used in LLVM and gcc), which are more space- and time-efficient
+than sets based on Go's built-in map type or dense bit vectors.
+
+Nodes are permuted prior to solving so that object nodes (which may
+appear in points-to sets) are lower numbered than non-object (var)
+nodes. This improves the density of the set over which the PTSs
+range, and thus the efficiency of the representation.
+
+Partly thanks to avoiding map iteration, the execution of the solver is
+100% deterministic, a great help during debugging.
+
+
+FURTHER READING
+
+Andersen, L. O. 1994. Program analysis and specialization for the C
+programming language. Ph.D. dissertation. DIKU, University of
+Copenhagen.
+
+David J. Pearce, Paul H. J. Kelly, and Chris Hankin. 2004. Efficient
+field-sensitive pointer analysis for C. In Proceedings of the 5th ACM
+SIGPLAN-SIGSOFT workshop on Program analysis for software tools and
+engineering (PASTE '04). ACM, New York, NY, USA, 37-42.
+http://doi.acm.org/10.1145/996821.996835
+
+David J. Pearce, Paul H. J. Kelly, and Chris Hankin. 2004. Online
+Cycle Detection and Difference Propagation: Applications to Pointer
+Analysis. Software Quality Control 12, 4 (December 2004), 311-337.
+http://dx.doi.org/10.1023/B:SQJO.0000039791.93071.a2
+
+David Grove and Craig Chambers. 2001. A framework for call graph
+construction algorithms. ACM Trans. Program. Lang. Syst. 23, 6
+(November 2001), 685-746.
+http://doi.acm.org/10.1145/506315.506316
+
+Ben Hardekopf and Calvin Lin. 2007. The ant and the grasshopper: fast
+and accurate pointer analysis for millions of lines of code. In
+Proceedings of the 2007 ACM SIGPLAN conference on Programming language
+design and implementation (PLDI '07). ACM, New York, NY, USA, 290-299.
+http://doi.acm.org/10.1145/1250734.1250767
+
+Ben Hardekopf and Calvin Lin. 2007. Exploiting pointer and location
+equivalence to optimize pointer analysis. In Proceedings of the 14th
+international conference on Static Analysis (SAS'07), Hanne Riis
+Nielson and Gilberto Filé (Eds.). Springer-Verlag, Berlin, Heidelberg,
+265-280.
+
+Atanas Rountev and Satish Chandra. 2000. Off-line variable substitution
+for scaling points-to analysis. In Proceedings of the ACM SIGPLAN 2000
+conference on Programming language design and implementation (PLDI '00).
+ACM, New York, NY, USA, 47-56. DOI=10.1145/349299.349310
+http://doi.acm.org/10.1145/349299.349310
+
+*/
+package pointer // import "golang.org/x/tools/go/pointer"
diff --git a/go/pointer/example_test.go b/go/pointer/example_test.go
new file mode 100644
index 0000000..ba70557
--- /dev/null
+++ b/go/pointer/example_test.go
@@ -0,0 +1,126 @@
+// 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 pointer_test
+
+import (
+ "fmt"
+ "sort"
+
+ "golang.org/x/tools/go/callgraph"
+ "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"
+)
+
+// This program demonstrates how to use the pointer analysis to
+// obtain a conservative call-graph of a Go program.
+// It also shows how to compute the points-to set of a variable,
+// in this case, (C).f's ch parameter.
+//
+func Example() {
+ const myprog = `
+package main
+
+import "fmt"
+
+type I interface {
+ f(map[string]int)
+}
+
+type C struct{}
+
+func (C) f(m map[string]int) {
+ fmt.Println("C.f()")
+}
+
+func main() {
+ var i I = C{}
+ x := map[string]int{"one":1}
+ i.f(x) // dynamic method call
+}
+`
+ var conf loader.Config
+
+ // Parse the input file, a string.
+ // (Command-line tools should use conf.FromArgs.)
+ file, err := conf.ParseFile("myprog.go", myprog)
+ if err != nil {
+ fmt.Print(err) // parse error
+ return
+ }
+
+ // Create single-file main package and import its dependencies.
+ conf.CreateFromFiles("main", file)
+
+ iprog, err := conf.Load()
+ if err != nil {
+ fmt.Print(err) // type error in some package
+ return
+ }
+
+ // Create SSA-form program representation.
+ prog := ssautil.CreateProgram(iprog, 0)
+ mainPkg := prog.Package(iprog.Created[0].Pkg)
+
+ // Build SSA code for bodies of all functions in the whole program.
+ prog.BuildAll()
+
+ // Configure the pointer analysis to build a call-graph.
+ config := &pointer.Config{
+ Mains: []*ssa.Package{mainPkg},
+ BuildCallGraph: true,
+ }
+
+ // Query points-to set of (C).f's parameter m, a map.
+ C := mainPkg.Type("C").Type()
+ Cfm := prog.LookupMethod(C, mainPkg.Object, "f").Params[1]
+ config.AddQuery(Cfm)
+
+ // Run the pointer analysis.
+ result, err := pointer.Analyze(config)
+ if err != nil {
+ panic(err) // internal error in pointer analysis
+ }
+
+ // Find edges originating from the main package.
+ // By converting to strings, we de-duplicate nodes
+ // representing the same function due to context sensitivity.
+ var edges []string
+ callgraph.GraphVisitEdges(result.CallGraph, func(edge *callgraph.Edge) error {
+ caller := edge.Caller.Func
+ if caller.Pkg == mainPkg {
+ edges = append(edges, fmt.Sprint(caller, " --> ", edge.Callee.Func))
+ }
+ return nil
+ })
+
+ // Print the edges in sorted order.
+ sort.Strings(edges)
+ for _, edge := range edges {
+ fmt.Println(edge)
+ }
+ fmt.Println()
+
+ // Print the labels of (C).f(m)'s points-to set.
+ fmt.Println("m may point to:")
+ var labels []string
+ for _, l := range result.Queries[Cfm].PointsTo().Labels() {
+ label := fmt.Sprintf(" %s: %s", prog.Fset.Position(l.Pos()), l)
+ labels = append(labels, label)
+ }
+ sort.Strings(labels)
+ for _, label := range labels {
+ fmt.Println(label)
+ }
+
+ // Output:
+ // (main.C).f --> fmt.Println
+ // main.init --> fmt.init
+ // main.main --> (main.C).f
+ //
+ // m may point to:
+ // myprog.go:18:21: makemap
+}
diff --git a/go/pointer/gen.go b/go/pointer/gen.go
new file mode 100644
index 0000000..6c256ac
--- /dev/null
+++ b/go/pointer/gen.go
@@ -0,0 +1,1292 @@
+// 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 pointer
+
+// This file defines the constraint generation phase.
+
+// TODO(adonovan): move the constraint definitions and the store() etc
+// functions which add them (and are also used by the solver) into a
+// new file, constraints.go.
+
+import (
+ "fmt"
+ "go/token"
+
+ "golang.org/x/tools/go/callgraph"
+ "golang.org/x/tools/go/ssa"
+ "golang.org/x/tools/go/types"
+)
+
+var (
+ tEface = types.NewInterface(nil, nil).Complete()
+ tInvalid = types.Typ[types.Invalid]
+ tUnsafePtr = types.Typ[types.UnsafePointer]
+)
+
+// ---------- Node creation ----------
+
+// nextNode returns the index of the next unused node.
+func (a *analysis) nextNode() nodeid {
+ return nodeid(len(a.nodes))
+}
+
+// addNodes creates nodes for all scalar elements in type typ, and
+// returns the id of the first one, or zero if the type was
+// analytically uninteresting.
+//
+// comment explains the origin of the nodes, as a debugging aid.
+//
+func (a *analysis) addNodes(typ types.Type, comment string) nodeid {
+ id := a.nextNode()
+ for _, fi := range a.flatten(typ) {
+ a.addOneNode(fi.typ, comment, fi)
+ }
+ if id == a.nextNode() {
+ return 0 // type contained no pointers
+ }
+ return id
+}
+
+// addOneNode creates a single node with type typ, and returns its id.
+//
+// typ should generally be scalar (except for tagged.T nodes
+// and struct/array identity nodes). Use addNodes for non-scalar types.
+//
+// comment explains the origin of the nodes, as a debugging aid.
+// subelement indicates the subelement, e.g. ".a.b[*].c".
+//
+func (a *analysis) addOneNode(typ types.Type, comment string, subelement *fieldInfo) nodeid {
+ id := a.nextNode()
+ a.nodes = append(a.nodes, &node{typ: typ, subelement: subelement, solve: new(solverState)})
+ if a.log != nil {
+ fmt.Fprintf(a.log, "\tcreate n%d %s for %s%s\n",
+ id, typ, comment, subelement.path())
+ }
+ return id
+}
+
+// setValueNode associates node id with the value v.
+// cgn identifies the context iff v is a local variable.
+//
+func (a *analysis) setValueNode(v ssa.Value, id nodeid, cgn *cgnode) {
+ if cgn != nil {
+ a.localval[v] = id
+ } else {
+ a.globalval[v] = id
+ }
+ if a.log != nil {
+ fmt.Fprintf(a.log, "\tval[%s] = n%d (%T)\n", v.Name(), id, v)
+ }
+
+ // Due to context-sensitivity, we may encounter the same Value
+ // in many contexts. We merge them to a canonical node, since
+ // that's what all clients want.
+
+ // Record the (v, id) relation if the client has queried pts(v).
+ if _, ok := a.config.Queries[v]; ok {
+ t := v.Type()
+ ptr, ok := a.result.Queries[v]
+ if !ok {
+ // First time? Create the canonical query node.
+ ptr = Pointer{a, a.addNodes(t, "query")}
+ a.result.Queries[v] = ptr
+ }
+ a.result.Queries[v] = ptr
+ a.copy(ptr.n, id, a.sizeof(t))
+ }
+
+ // Record the (*v, id) relation if the client has queried pts(*v).
+ if _, ok := a.config.IndirectQueries[v]; ok {
+ t := v.Type()
+ ptr, ok := a.result.IndirectQueries[v]
+ if !ok {
+ // First time? Create the canonical indirect query node.
+ ptr = Pointer{a, a.addNodes(v.Type(), "query.indirect")}
+ a.result.IndirectQueries[v] = ptr
+ }
+ a.genLoad(cgn, ptr.n, v, 0, a.sizeof(t))
+ }
+}
+
+// endObject marks the end of a sequence of calls to addNodes denoting
+// a single object allocation.
+//
+// obj is the start node of the object, from a prior call to nextNode.
+// Its size, flags and optional data will be updated.
+//
+func (a *analysis) endObject(obj nodeid, cgn *cgnode, data interface{}) *object {
+ // Ensure object is non-empty by padding;
+ // the pad will be the object node.
+ size := uint32(a.nextNode() - obj)
+ if size == 0 {
+ a.addOneNode(tInvalid, "padding", nil)
+ }
+ objNode := a.nodes[obj]
+ o := &object{
+ size: size, // excludes padding
+ cgn: cgn,
+ data: data,
+ }
+ objNode.obj = o
+
+ return o
+}
+
+// makeFunctionObject creates and returns a new function object
+// (contour) for fn, and returns the id of its first node. It also
+// enqueues fn for subsequent constraint generation.
+//
+// For a context-sensitive contour, callersite identifies the sole
+// callsite; for shared contours, caller is nil.
+//
+func (a *analysis) makeFunctionObject(fn *ssa.Function, callersite *callsite) nodeid {
+ if a.log != nil {
+ fmt.Fprintf(a.log, "\t---- makeFunctionObject %s\n", fn)
+ }
+
+ // obj is the function object (identity, params, results).
+ obj := a.nextNode()
+ cgn := a.makeCGNode(fn, obj, callersite)
+ sig := fn.Signature
+ a.addOneNode(sig, "func.cgnode", nil) // (scalar with Signature type)
+ if recv := sig.Recv(); recv != nil {
+ a.addNodes(recv.Type(), "func.recv")
+ }
+ a.addNodes(sig.Params(), "func.params")
+ a.addNodes(sig.Results(), "func.results")
+ a.endObject(obj, cgn, fn).flags |= otFunction
+
+ if a.log != nil {
+ fmt.Fprintf(a.log, "\t----\n")
+ }
+
+ // Queue it up for constraint processing.
+ a.genq = append(a.genq, cgn)
+
+ return obj
+}
+
+// makeTagged creates a tagged object of type typ.
+func (a *analysis) makeTagged(typ types.Type, cgn *cgnode, data interface{}) nodeid {
+ obj := a.addOneNode(typ, "tagged.T", nil) // NB: type may be non-scalar!
+ a.addNodes(typ, "tagged.v")
+ a.endObject(obj, cgn, data).flags |= otTagged
+ return obj
+}
+
+// makeRtype returns the canonical tagged object of type *rtype whose
+// payload points to the sole rtype object for T.
+//
+// TODO(adonovan): move to reflect.go; it's part of the solver really.
+//
+func (a *analysis) makeRtype(T types.Type) nodeid {
+ if v := a.rtypes.At(T); v != nil {
+ return v.(nodeid)
+ }
+
+ // Create the object for the reflect.rtype itself, which is
+ // ordinarily a large struct but here a single node will do.
+ obj := a.nextNode()
+ a.addOneNode(T, "reflect.rtype", nil)
+ a.endObject(obj, nil, T)
+
+ id := a.makeTagged(a.reflectRtypePtr, nil, T)
+ a.nodes[id+1].typ = T // trick (each *rtype tagged object is a singleton)
+ a.addressOf(a.reflectRtypePtr, id+1, obj)
+
+ a.rtypes.Set(T, id)
+ return id
+}
+
+// rtypeValue returns the type of the *reflect.rtype-tagged object obj.
+func (a *analysis) rtypeTaggedValue(obj nodeid) types.Type {
+ tDyn, t, _ := a.taggedValue(obj)
+ if tDyn != a.reflectRtypePtr {
+ panic(fmt.Sprintf("not a *reflect.rtype-tagged object: obj=n%d tag=%v payload=n%d", obj, tDyn, t))
+ }
+ return a.nodes[t].typ
+}
+
+// valueNode returns the id of the value node for v, creating it (and
+// the association) as needed. It may return zero for uninteresting
+// values containing no pointers.
+//
+func (a *analysis) valueNode(v ssa.Value) nodeid {
+ // Value nodes for locals are created en masse by genFunc.
+ if id, ok := a.localval[v]; ok {
+ return id
+ }
+
+ // Value nodes for globals are created on demand.
+ id, ok := a.globalval[v]
+ if !ok {
+ var comment string
+ if a.log != nil {
+ comment = v.String()
+ }
+ id = a.addNodes(v.Type(), comment)
+ if obj := a.objectNode(nil, v); obj != 0 {
+ a.addressOf(v.Type(), id, obj)
+ }
+ a.setValueNode(v, id, nil)
+ }
+ return id
+}
+
+// valueOffsetNode ascertains the node for tuple/struct value v,
+// then returns the node for its subfield #index.
+//
+func (a *analysis) valueOffsetNode(v ssa.Value, index int) nodeid {
+ id := a.valueNode(v)
+ if id == 0 {
+ panic(fmt.Sprintf("cannot offset within n0: %s = %s", v.Name(), v))
+ }
+ return id + nodeid(a.offsetOf(v.Type(), index))
+}
+
+// isTaggedObject reports whether object obj is a tagged object.
+func (a *analysis) isTaggedObject(obj nodeid) bool {
+ return a.nodes[obj].obj.flags&otTagged != 0
+}
+
+// taggedValue returns the dynamic type tag, the (first node of the)
+// payload, and the indirect flag of the tagged object starting at id.
+// Panic ensues if !isTaggedObject(id).
+//
+func (a *analysis) taggedValue(obj nodeid) (tDyn types.Type, v nodeid, indirect bool) {
+ n := a.nodes[obj]
+ flags := n.obj.flags
+ if flags&otTagged == 0 {
+ panic(fmt.Sprintf("not a tagged object: n%d", obj))
+ }
+ return n.typ, obj + 1, flags&otIndirect != 0
+}
+
+// funcParams returns the first node of the params (P) block of the
+// function whose object node (obj.flags&otFunction) is id.
+//
+func (a *analysis) funcParams(id nodeid) nodeid {
+ n := a.nodes[id]
+ if n.obj == nil || n.obj.flags&otFunction == 0 {
+ panic(fmt.Sprintf("funcParams(n%d): not a function object block", id))
+ }
+ return id + 1
+}
+
+// funcResults returns the first node of the results (R) block of the
+// function whose object node (obj.flags&otFunction) is id.
+//
+func (a *analysis) funcResults(id nodeid) nodeid {
+ n := a.nodes[id]
+ if n.obj == nil || n.obj.flags&otFunction == 0 {
+ panic(fmt.Sprintf("funcResults(n%d): not a function object block", id))
+ }
+ sig := n.typ.(*types.Signature)
+ id += 1 + nodeid(a.sizeof(sig.Params()))
+ if sig.Recv() != nil {
+ id += nodeid(a.sizeof(sig.Recv().Type()))
+ }
+ return id
+}
+
+// ---------- Constraint creation ----------
+
+// copy creates a constraint of the form dst = src.
+// sizeof is the width (in logical fields) of the copied type.
+//
+func (a *analysis) copy(dst, src nodeid, sizeof uint32) {
+ if src == dst || sizeof == 0 {
+ return // trivial
+ }
+ if src == 0 || dst == 0 {
+ panic(fmt.Sprintf("ill-typed copy dst=n%d src=n%d", dst, src))
+ }
+ for i := uint32(0); i < sizeof; i++ {
+ a.addConstraint(©Constraint{dst, src})
+ src++
+ dst++
+ }
+}
+
+// addressOf creates a constraint of the form id = &obj.
+// T is the type of the address.
+func (a *analysis) addressOf(T types.Type, id, obj nodeid) {
+ if id == 0 {
+ panic("addressOf: zero id")
+ }
+ if obj == 0 {
+ panic("addressOf: zero obj")
+ }
+ if a.shouldTrack(T) {
+ a.addConstraint(&addrConstraint{id, obj})
+ }
+}
+
+// load creates a load constraint of the form dst = src[offset].
+// offset is the pointer offset in logical fields.
+// sizeof is the width (in logical fields) of the loaded type.
+//
+func (a *analysis) load(dst, src nodeid, offset, sizeof uint32) {
+ if dst == 0 {
+ return // load of non-pointerlike value
+ }
+ if src == 0 && dst == 0 {
+ return // non-pointerlike operation
+ }
+ if src == 0 || dst == 0 {
+ panic(fmt.Sprintf("ill-typed load dst=n%d src=n%d", dst, src))
+ }
+ for i := uint32(0); i < sizeof; i++ {
+ a.addConstraint(&loadConstraint{offset, dst, src})
+ offset++
+ dst++
+ }
+}
+
+// store creates a store constraint of the form dst[offset] = src.
+// offset is the pointer offset in logical fields.
+// sizeof is the width (in logical fields) of the stored type.
+//
+func (a *analysis) store(dst, src nodeid, offset uint32, sizeof uint32) {
+ if src == 0 {
+ return // store of non-pointerlike value
+ }
+ if src == 0 && dst == 0 {
+ return // non-pointerlike operation
+ }
+ if src == 0 || dst == 0 {
+ panic(fmt.Sprintf("ill-typed store dst=n%d src=n%d", dst, src))
+ }
+ for i := uint32(0); i < sizeof; i++ {
+ a.addConstraint(&storeConstraint{offset, dst, src})
+ offset++
+ src++
+ }
+}
+
+// offsetAddr creates an offsetAddr constraint of the form dst = &src.#offset.
+// offset is the field offset in logical fields.
+// T is the type of the address.
+//
+func (a *analysis) offsetAddr(T types.Type, dst, src nodeid, offset uint32) {
+ if !a.shouldTrack(T) {
+ return
+ }
+ if offset == 0 {
+ // Simplify dst = &src->f0
+ // to dst = src
+ // (NB: this optimisation is defeated by the identity
+ // field prepended to struct and array objects.)
+ a.copy(dst, src, 1)
+ } else {
+ a.addConstraint(&offsetAddrConstraint{offset, dst, src})
+ }
+}
+
+// typeAssert creates a typeFilter or untag constraint of the form dst = src.(T):
+// typeFilter for an interface, untag for a concrete type.
+// The exact flag is specified as for untagConstraint.
+//
+func (a *analysis) typeAssert(T types.Type, dst, src nodeid, exact bool) {
+ if isInterface(T) {
+ a.addConstraint(&typeFilterConstraint{T, dst, src})
+ } else {
+ a.addConstraint(&untagConstraint{T, dst, src, exact})
+ }
+}
+
+// addConstraint adds c to the constraint set.
+func (a *analysis) addConstraint(c constraint) {
+ a.constraints = append(a.constraints, c)
+ if a.log != nil {
+ fmt.Fprintf(a.log, "\t%s\n", c)
+ }
+}
+
+// copyElems generates load/store constraints for *dst = *src,
+// where src and dst are slices or *arrays.
+//
+func (a *analysis) copyElems(cgn *cgnode, typ types.Type, dst, src ssa.Value) {
+ tmp := a.addNodes(typ, "copy")
+ sz := a.sizeof(typ)
+ a.genLoad(cgn, tmp, src, 1, sz)
+ a.genStore(cgn, dst, tmp, 1, sz)
+}
+
+// ---------- Constraint generation ----------
+
+// genConv generates constraints for the conversion operation conv.
+func (a *analysis) genConv(conv *ssa.Convert, cgn *cgnode) {
+ res := a.valueNode(conv)
+ if res == 0 {
+ return // result is non-pointerlike
+ }
+
+ tSrc := conv.X.Type()
+ tDst := conv.Type()
+
+ switch utSrc := tSrc.Underlying().(type) {
+ case *types.Slice:
+ // []byte/[]rune -> string?
+ return
+
+ case *types.Pointer:
+ // *T -> unsafe.Pointer?
+ if tDst.Underlying() == tUnsafePtr {
+ return // we don't model unsafe aliasing (unsound)
+ }
+
+ case *types.Basic:
+ switch tDst.Underlying().(type) {
+ case *types.Pointer:
+ // Treat unsafe.Pointer->*T conversions like
+ // new(T) and create an unaliased object.
+ if utSrc == tUnsafePtr {
+ obj := a.addNodes(mustDeref(tDst), "unsafe.Pointer conversion")
+ a.endObject(obj, cgn, conv)
+ a.addressOf(tDst, res, obj)
+ return
+ }
+
+ case *types.Slice:
+ // string -> []byte/[]rune (or named aliases)?
+ if utSrc.Info()&types.IsString != 0 {
+ obj := a.addNodes(sliceToArray(tDst), "convert")
+ a.endObject(obj, cgn, conv)
+ a.addressOf(tDst, res, obj)
+ return
+ }
+
+ case *types.Basic:
+ // All basic-to-basic type conversions are no-ops.
+ // This includes uintptr<->unsafe.Pointer conversions,
+ // which we (unsoundly) ignore.
+ return
+ }
+ }
+
+ panic(fmt.Sprintf("illegal *ssa.Convert %s -> %s: %s", tSrc, tDst, conv.Parent()))
+}
+
+// genAppend generates constraints for a call to append.
+func (a *analysis) genAppend(instr *ssa.Call, cgn *cgnode) {
+ // Consider z = append(x, y). y is optional.
+ // This may allocate a new [1]T array; call its object w.
+ // We get the following constraints:
+ // z = x
+ // z = &w
+ // *z = *y
+
+ x := instr.Call.Args[0]
+
+ z := instr
+ a.copy(a.valueNode(z), a.valueNode(x), 1) // z = x
+
+ if len(instr.Call.Args) == 1 {
+ return // no allocation for z = append(x) or _ = append(x).
+ }
+
+ // TODO(adonovan): test append([]byte, ...string) []byte.
+
+ y := instr.Call.Args[1]
+ tArray := sliceToArray(instr.Call.Args[0].Type())
+
+ var w nodeid
+ w = a.nextNode()
+ a.addNodes(tArray, "append")
+ a.endObject(w, cgn, instr)
+
+ a.copyElems(cgn, tArray.Elem(), z, y) // *z = *y
+ a.addressOf(instr.Type(), a.valueNode(z), w) // z = &w
+}
+
+// genBuiltinCall generates contraints for a call to a built-in.
+func (a *analysis) genBuiltinCall(instr ssa.CallInstruction, cgn *cgnode) {
+ call := instr.Common()
+ switch call.Value.(*ssa.Builtin).Name() {
+ case "append":
+ // Safe cast: append cannot appear in a go or defer statement.
+ a.genAppend(instr.(*ssa.Call), cgn)
+
+ case "copy":
+ tElem := call.Args[0].Type().Underlying().(*types.Slice).Elem()
+ a.copyElems(cgn, tElem, call.Args[0], call.Args[1])
+
+ case "panic":
+ a.copy(a.panicNode, a.valueNode(call.Args[0]), 1)
+
+ case "recover":
+ if v := instr.Value(); v != nil {
+ a.copy(a.valueNode(v), a.panicNode, 1)
+ }
+
+ case "print":
+ // In the tests, the probe might be the sole reference
+ // to its arg, so make sure we create nodes for it.
+ if len(call.Args) > 0 {
+ a.valueNode(call.Args[0])
+ }
+
+ case "ssa:wrapnilchk":
+ a.copy(a.valueNode(instr.Value()), a.valueNode(call.Args[0]), 1)
+
+ default:
+ // No-ops: close len cap real imag complex print println delete.
+ }
+}
+
+// shouldUseContext defines the context-sensitivity policy. It
+// returns true if we should analyse all static calls to fn anew.
+//
+// Obviously this interface rather limits how much freedom we have to
+// choose a policy. The current policy, rather arbitrarily, is true
+// for intrinsics and accessor methods (actually: short, single-block,
+// call-free functions). This is just a starting point.
+//
+func (a *analysis) shouldUseContext(fn *ssa.Function) bool {
+ if a.findIntrinsic(fn) != nil {
+ return true // treat intrinsics context-sensitively
+ }
+ if len(fn.Blocks) != 1 {
+ return false // too expensive
+ }
+ blk := fn.Blocks[0]
+ if len(blk.Instrs) > 10 {
+ return false // too expensive
+ }
+ if fn.Synthetic != "" && (fn.Pkg == nil || fn != fn.Pkg.Func("init")) {
+ return true // treat synthetic wrappers context-sensitively
+ }
+ for _, instr := range blk.Instrs {
+ switch instr := instr.(type) {
+ case ssa.CallInstruction:
+ // Disallow function calls (except to built-ins)
+ // because of the danger of unbounded recursion.
+ if _, ok := instr.Common().Value.(*ssa.Builtin); !ok {
+ return false
+ }
+ }
+ }
+ return true
+}
+
+// genStaticCall generates constraints for a statically dispatched function call.
+func (a *analysis) genStaticCall(caller *cgnode, site *callsite, call *ssa.CallCommon, result nodeid) {
+ fn := call.StaticCallee()
+
+ // Special cases for inlined intrinsics.
+ switch fn {
+ case a.runtimeSetFinalizer:
+ // Inline SetFinalizer so the call appears direct.
+ site.targets = a.addOneNode(tInvalid, "SetFinalizer.targets", nil)
+ a.addConstraint(&runtimeSetFinalizerConstraint{
+ targets: site.targets,
+ x: a.valueNode(call.Args[0]),
+ f: a.valueNode(call.Args[1]),
+ })
+ return
+
+ case a.reflectValueCall:
+ // Inline (reflect.Value).Call so the call appears direct.
+ dotdotdot := false
+ ret := reflectCallImpl(a, caller, site, a.valueNode(call.Args[0]), a.valueNode(call.Args[1]), dotdotdot)
+ if result != 0 {
+ a.addressOf(fn.Signature.Results().At(0).Type(), result, ret)
+ }
+ return
+ }
+
+ // Ascertain the context (contour/cgnode) for a particular call.
+ var obj nodeid
+ if a.shouldUseContext(fn) {
+ obj = a.makeFunctionObject(fn, site) // new contour
+ } else {
+ obj = a.objectNode(nil, fn) // shared contour
+ }
+ a.callEdge(caller, site, obj)
+
+ sig := call.Signature()
+
+ // Copy receiver, if any.
+ params := a.funcParams(obj)
+ args := call.Args
+ if sig.Recv() != nil {
+ sz := a.sizeof(sig.Recv().Type())
+ a.copy(params, a.valueNode(args[0]), sz)
+ params += nodeid(sz)
+ args = args[1:]
+ }
+
+ // Copy actual parameters into formal params block.
+ // Must loop, since the actuals aren't contiguous.
+ for i, arg := range args {
+ sz := a.sizeof(sig.Params().At(i).Type())
+ a.copy(params, a.valueNode(arg), sz)
+ params += nodeid(sz)
+ }
+
+ // Copy formal results block to actual result.
+ if result != 0 {
+ a.copy(result, a.funcResults(obj), a.sizeof(sig.Results()))
+ }
+}
+
+// genDynamicCall generates constraints for a dynamic function call.
+func (a *analysis) genDynamicCall(caller *cgnode, site *callsite, call *ssa.CallCommon, result nodeid) {
+ // pts(targets) will be the set of possible call targets.
+ site.targets = a.valueNode(call.Value)
+
+ // We add dynamic closure rules that store the arguments into
+ // the P-block and load the results from the R-block of each
+ // function discovered in pts(targets).
+
+ sig := call.Signature()
+ var offset uint32 = 1 // P/R block starts at offset 1
+ for i, arg := range call.Args {
+ sz := a.sizeof(sig.Params().At(i).Type())
+ a.genStore(caller, call.Value, a.valueNode(arg), offset, sz)
+ offset += sz
+ }
+ if result != 0 {
+ a.genLoad(caller, result, call.Value, offset, a.sizeof(sig.Results()))
+ }
+}
+
+// genInvoke generates constraints for a dynamic method invocation.
+func (a *analysis) genInvoke(caller *cgnode, site *callsite, call *ssa.CallCommon, result nodeid) {
+ if call.Value.Type() == a.reflectType {
+ a.genInvokeReflectType(caller, site, call, result)
+ return
+ }
+
+ sig := call.Signature()
+
+ // Allocate a contiguous targets/params/results block for this call.
+ block := a.nextNode()
+ // pts(targets) will be the set of possible call targets
+ site.targets = a.addOneNode(sig, "invoke.targets", nil)
+ p := a.addNodes(sig.Params(), "invoke.params")
+ r := a.addNodes(sig.Results(), "invoke.results")
+
+ // Copy the actual parameters into the call's params block.
+ for i, n := 0, sig.Params().Len(); i < n; i++ {
+ sz := a.sizeof(sig.Params().At(i).Type())
+ a.copy(p, a.valueNode(call.Args[i]), sz)
+ p += nodeid(sz)
+ }
+ // Copy the call's results block to the actual results.
+ if result != 0 {
+ a.copy(result, r, a.sizeof(sig.Results()))
+ }
+
+ // We add a dynamic invoke constraint that will connect the
+ // caller's and the callee's P/R blocks for each discovered
+ // call target.
+ a.addConstraint(&invokeConstraint{call.Method, a.valueNode(call.Value), block})
+}
+
+// genInvokeReflectType is a specialization of genInvoke where the
+// receiver type is a reflect.Type, under the assumption that there
+// can be at most one implementation of this interface, *reflect.rtype.
+//
+// (Though this may appear to be an instance of a pattern---method
+// calls on interfaces known to have exactly one implementation---in
+// practice it occurs rarely, so we special case for reflect.Type.)
+//
+// In effect we treat this:
+// var rt reflect.Type = ...
+// rt.F()
+// as this:
+// rt.(*reflect.rtype).F()
+//
+func (a *analysis) genInvokeReflectType(caller *cgnode, site *callsite, call *ssa.CallCommon, result nodeid) {
+ // Unpack receiver into rtype
+ rtype := a.addOneNode(a.reflectRtypePtr, "rtype.recv", nil)
+ recv := a.valueNode(call.Value)
+ a.typeAssert(a.reflectRtypePtr, rtype, recv, true)
+
+ // Look up the concrete method.
+ fn := a.prog.LookupMethod(a.reflectRtypePtr, call.Method.Pkg(), call.Method.Name())
+
+ obj := a.makeFunctionObject(fn, site) // new contour for this call
+ a.callEdge(caller, site, obj)
+
+ // From now on, it's essentially a static call, but little is
+ // gained by factoring together the code for both cases.
+
+ sig := fn.Signature // concrete method
+ targets := a.addOneNode(sig, "call.targets", nil)
+ a.addressOf(sig, targets, obj) // (a singleton)
+
+ // Copy receiver.
+ params := a.funcParams(obj)
+ a.copy(params, rtype, 1)
+ params++
+
+ // Copy actual parameters into formal P-block.
+ // Must loop, since the actuals aren't contiguous.
+ for i, arg := range call.Args {
+ sz := a.sizeof(sig.Params().At(i).Type())
+ a.copy(params, a.valueNode(arg), sz)
+ params += nodeid(sz)
+ }
+
+ // Copy formal R-block to actual R-block.
+ if result != 0 {
+ a.copy(result, a.funcResults(obj), a.sizeof(sig.Results()))
+ }
+}
+
+// genCall generates constraints for call instruction instr.
+func (a *analysis) genCall(caller *cgnode, instr ssa.CallInstruction) {
+ call := instr.Common()
+
+ // Intrinsic implementations of built-in functions.
+ if _, ok := call.Value.(*ssa.Builtin); ok {
+ a.genBuiltinCall(instr, caller)
+ return
+ }
+
+ var result nodeid
+ if v := instr.Value(); v != nil {
+ result = a.valueNode(v)
+ }
+
+ site := &callsite{instr: instr}
+ if call.StaticCallee() != nil {
+ a.genStaticCall(caller, site, call, result)
+ } else if call.IsInvoke() {
+ a.genInvoke(caller, site, call, result)
+ } else {
+ a.genDynamicCall(caller, site, call, result)
+ }
+
+ caller.sites = append(caller.sites, site)
+
+ if a.log != nil {
+ // TODO(adonovan): debug: improve log message.
+ fmt.Fprintf(a.log, "\t%s to targets %s from %s\n", site, site.targets, caller)
+ }
+}
+
+// objectNode returns the object to which v points, if known.
+// In other words, if the points-to set of v is a singleton, it
+// returns the sole label, zero otherwise.
+//
+// We exploit this information to make the generated constraints less
+// dynamic. For example, a complex load constraint can be replaced by
+// a simple copy constraint when the sole destination is known a priori.
+//
+// Some SSA instructions always have singletons points-to sets:
+// Alloc, Function, Global, MakeChan, MakeClosure, MakeInterface, MakeMap, MakeSlice.
+// Others may be singletons depending on their operands:
+// FreeVar, Const, Convert, FieldAddr, IndexAddr, Slice.
+//
+// Idempotent. Objects are created as needed, possibly via recursion
+// down the SSA value graph, e.g IndexAddr(FieldAddr(Alloc))).
+//
+func (a *analysis) objectNode(cgn *cgnode, v ssa.Value) nodeid {
+ switch v.(type) {
+ case *ssa.Global, *ssa.Function, *ssa.Const, *ssa.FreeVar:
+ // Global object.
+ obj, ok := a.globalobj[v]
+ if !ok {
+ switch v := v.(type) {
+ case *ssa.Global:
+ obj = a.nextNode()
+ a.addNodes(mustDeref(v.Type()), "global")
+ a.endObject(obj, nil, v)
+
+ case *ssa.Function:
+ obj = a.makeFunctionObject(v, nil)
+
+ case *ssa.Const:
+ // not addressable
+
+ case *ssa.FreeVar:
+ // not addressable
+ }
+
+ if a.log != nil {
+ fmt.Fprintf(a.log, "\tglobalobj[%s] = n%d\n", v, obj)
+ }
+ a.globalobj[v] = obj
+ }
+ return obj
+ }
+
+ // Local object.
+ obj, ok := a.localobj[v]
+ if !ok {
+ switch v := v.(type) {
+ case *ssa.Alloc:
+ obj = a.nextNode()
+ a.addNodes(mustDeref(v.Type()), "alloc")
+ a.endObject(obj, cgn, v)
+
+ case *ssa.MakeSlice:
+ obj = a.nextNode()
+ a.addNodes(sliceToArray(v.Type()), "makeslice")
+ a.endObject(obj, cgn, v)
+
+ case *ssa.MakeChan:
+ obj = a.nextNode()
+ a.addNodes(v.Type().Underlying().(*types.Chan).Elem(), "makechan")
+ a.endObject(obj, cgn, v)
+
+ case *ssa.MakeMap:
+ obj = a.nextNode()
+ tmap := v.Type().Underlying().(*types.Map)
+ a.addNodes(tmap.Key(), "makemap.key")
+ elem := a.addNodes(tmap.Elem(), "makemap.value")
+
+ // To update the value field, MapUpdate
+ // generates store-with-offset constraints which
+ // the presolver can't model, so we must mark
+ // those nodes indirect.
+ for id, end := elem, elem+nodeid(a.sizeof(tmap.Elem())); id < end; id++ {
+ a.mapValues = append(a.mapValues, id)
+ }
+ a.endObject(obj, cgn, v)
+
+ case *ssa.MakeInterface:
+ tConc := v.X.Type()
+ obj = a.makeTagged(tConc, cgn, v)
+
+ // Copy the value into it, if nontrivial.
+ if x := a.valueNode(v.X); x != 0 {
+ a.copy(obj+1, x, a.sizeof(tConc))
+ }
+
+ case *ssa.FieldAddr:
+ if xobj := a.objectNode(cgn, v.X); xobj != 0 {
+ obj = xobj + nodeid(a.offsetOf(mustDeref(v.X.Type()), v.Field))
+ }
+
+ case *ssa.IndexAddr:
+ if xobj := a.objectNode(cgn, v.X); xobj != 0 {
+ obj = xobj + 1
+ }
+
+ case *ssa.Slice:
+ obj = a.objectNode(cgn, v.X)
+
+ case *ssa.Convert:
+ // TODO(adonovan): opt: handle these cases too:
+ // - unsafe.Pointer->*T conversion acts like Alloc
+ // - string->[]byte/[]rune conversion acts like MakeSlice
+ }
+
+ if a.log != nil {
+ fmt.Fprintf(a.log, "\tlocalobj[%s] = n%d\n", v.Name(), obj)
+ }
+ a.localobj[v] = obj
+ }
+ return obj
+}
+
+// genLoad generates constraints for result = *(ptr + val).
+func (a *analysis) genLoad(cgn *cgnode, result nodeid, ptr ssa.Value, offset, sizeof uint32) {
+ if obj := a.objectNode(cgn, ptr); obj != 0 {
+ // Pre-apply loadConstraint.solve().
+ a.copy(result, obj+nodeid(offset), sizeof)
+ } else {
+ a.load(result, a.valueNode(ptr), offset, sizeof)
+ }
+}
+
+// genOffsetAddr generates constraints for a 'v=ptr.field' (FieldAddr)
+// or 'v=ptr[*]' (IndexAddr) instruction v.
+func (a *analysis) genOffsetAddr(cgn *cgnode, v ssa.Value, ptr nodeid, offset uint32) {
+ dst := a.valueNode(v)
+ if obj := a.objectNode(cgn, v); obj != 0 {
+ // Pre-apply offsetAddrConstraint.solve().
+ a.addressOf(v.Type(), dst, obj)
+ } else {
+ a.offsetAddr(v.Type(), dst, ptr, offset)
+ }
+}
+
+// genStore generates constraints for *(ptr + offset) = val.
+func (a *analysis) genStore(cgn *cgnode, ptr ssa.Value, val nodeid, offset, sizeof uint32) {
+ if obj := a.objectNode(cgn, ptr); obj != 0 {
+ // Pre-apply storeConstraint.solve().
+ a.copy(obj+nodeid(offset), val, sizeof)
+ } else {
+ a.store(a.valueNode(ptr), val, offset, sizeof)
+ }
+}
+
+// genInstr generates constraints for instruction instr in context cgn.
+func (a *analysis) genInstr(cgn *cgnode, instr ssa.Instruction) {
+ if a.log != nil {
+ var prefix string
+ if val, ok := instr.(ssa.Value); ok {
+ prefix = val.Name() + " = "
+ }
+ fmt.Fprintf(a.log, "; %s%s\n", prefix, instr)
+ }
+
+ switch instr := instr.(type) {
+ case *ssa.DebugRef:
+ // no-op.
+
+ case *ssa.UnOp:
+ switch instr.Op {
+ case token.ARROW: // <-x
+ // We can ignore instr.CommaOk because the node we're
+ // altering is always at zero offset relative to instr
+ tElem := instr.X.Type().Underlying().(*types.Chan).Elem()
+ a.genLoad(cgn, a.valueNode(instr), instr.X, 0, a.sizeof(tElem))
+
+ case token.MUL: // *x
+ a.genLoad(cgn, a.valueNode(instr), instr.X, 0, a.sizeof(instr.Type()))
+
+ default:
+ // NOT, SUB, XOR: no-op.
+ }
+
+ case *ssa.BinOp:
+ // All no-ops.
+
+ case ssa.CallInstruction: // *ssa.Call, *ssa.Go, *ssa.Defer
+ a.genCall(cgn, instr)
+
+ case *ssa.ChangeType:
+ a.copy(a.valueNode(instr), a.valueNode(instr.X), 1)
+
+ case *ssa.Convert:
+ a.genConv(instr, cgn)
+
+ case *ssa.Extract:
+ a.copy(a.valueNode(instr),
+ a.valueOffsetNode(instr.Tuple, instr.Index),
+ a.sizeof(instr.Type()))
+
+ case *ssa.FieldAddr:
+ a.genOffsetAddr(cgn, instr, a.valueNode(instr.X),
+ a.offsetOf(mustDeref(instr.X.Type()), instr.Field))
+
+ case *ssa.IndexAddr:
+ a.genOffsetAddr(cgn, instr, a.valueNode(instr.X), 1)
+
+ case *ssa.Field:
+ a.copy(a.valueNode(instr),
+ a.valueOffsetNode(instr.X, instr.Field),
+ a.sizeof(instr.Type()))
+
+ case *ssa.Index:
+ a.copy(a.valueNode(instr), 1+a.valueNode(instr.X), a.sizeof(instr.Type()))
+
+ case *ssa.Select:
+ recv := a.valueOffsetNode(instr, 2) // instr : (index, recvOk, recv0, ... recv_n-1)
+ for _, st := range instr.States {
+ elemSize := a.sizeof(st.Chan.Type().Underlying().(*types.Chan).Elem())
+ switch st.Dir {
+ case types.RecvOnly:
+ a.genLoad(cgn, recv, st.Chan, 0, elemSize)
+ recv += nodeid(elemSize)
+
+ case types.SendOnly:
+ a.genStore(cgn, st.Chan, a.valueNode(st.Send), 0, elemSize)
+ }
+ }
+
+ case *ssa.Return:
+ results := a.funcResults(cgn.obj)
+ for _, r := range instr.Results {
+ sz := a.sizeof(r.Type())
+ a.copy(results, a.valueNode(r), sz)
+ results += nodeid(sz)
+ }
+
+ case *ssa.Send:
+ a.genStore(cgn, instr.Chan, a.valueNode(instr.X), 0, a.sizeof(instr.X.Type()))
+
+ case *ssa.Store:
+ a.genStore(cgn, instr.Addr, a.valueNode(instr.Val), 0, a.sizeof(instr.Val.Type()))
+
+ case *ssa.Alloc, *ssa.MakeSlice, *ssa.MakeChan, *ssa.MakeMap, *ssa.MakeInterface:
+ v := instr.(ssa.Value)
+ a.addressOf(v.Type(), a.valueNode(v), a.objectNode(cgn, v))
+
+ case *ssa.ChangeInterface:
+ a.copy(a.valueNode(instr), a.valueNode(instr.X), 1)
+
+ case *ssa.TypeAssert:
+ a.typeAssert(instr.AssertedType, a.valueNode(instr), a.valueNode(instr.X), true)
+
+ case *ssa.Slice:
+ a.copy(a.valueNode(instr), a.valueNode(instr.X), 1)
+
+ case *ssa.If, *ssa.Jump:
+ // no-op.
+
+ case *ssa.Phi:
+ sz := a.sizeof(instr.Type())
+ for _, e := range instr.Edges {
+ a.copy(a.valueNode(instr), a.valueNode(e), sz)
+ }
+
+ case *ssa.MakeClosure:
+ fn := instr.Fn.(*ssa.Function)
+ a.copy(a.valueNode(instr), a.valueNode(fn), 1)
+ // Free variables are treated like global variables.
+ for i, b := range instr.Bindings {
+ a.copy(a.valueNode(fn.FreeVars[i]), a.valueNode(b), a.sizeof(b.Type()))
+ }
+
+ case *ssa.RunDefers:
+ // The analysis is flow insensitive, so we just "call"
+ // defers as we encounter them.
+
+ case *ssa.Range:
+ // Do nothing. Next{Iter: *ssa.Range} handles this case.
+
+ case *ssa.Next:
+ if !instr.IsString { // map
+ // Assumes that Next is always directly applied to a Range result.
+ theMap := instr.Iter.(*ssa.Range).X
+ tMap := theMap.Type().Underlying().(*types.Map)
+ ksize := a.sizeof(tMap.Key())
+ vsize := a.sizeof(tMap.Elem())
+
+ // Load from the map's (k,v) into the tuple's (ok, k, v).
+ a.genLoad(cgn, a.valueNode(instr)+1, theMap, 0, ksize+vsize)
+ }
+
+ case *ssa.Lookup:
+ if tMap, ok := instr.X.Type().Underlying().(*types.Map); ok {
+ // CommaOk can be ignored: field 0 is a no-op.
+ ksize := a.sizeof(tMap.Key())
+ vsize := a.sizeof(tMap.Elem())
+ a.genLoad(cgn, a.valueNode(instr), instr.X, ksize, vsize)
+ }
+
+ case *ssa.MapUpdate:
+ tmap := instr.Map.Type().Underlying().(*types.Map)
+ ksize := a.sizeof(tmap.Key())
+ vsize := a.sizeof(tmap.Elem())
+ a.genStore(cgn, instr.Map, a.valueNode(instr.Key), 0, ksize)
+ a.genStore(cgn, instr.Map, a.valueNode(instr.Value), ksize, vsize)
+
+ case *ssa.Panic:
+ a.copy(a.panicNode, a.valueNode(instr.X), 1)
+
+ default:
+ panic(fmt.Sprintf("unimplemented: %T", instr))
+ }
+}
+
+func (a *analysis) makeCGNode(fn *ssa.Function, obj nodeid, callersite *callsite) *cgnode {
+ cgn := &cgnode{fn: fn, obj: obj, callersite: callersite}
+ a.cgnodes = append(a.cgnodes, cgn)
+ return cgn
+}
+
+// genRootCalls generates the synthetic root of the callgraph and the
+// initial calls from it to the analysis scope, such as main, a test
+// or a library.
+//
+func (a *analysis) genRootCalls() *cgnode {
+ r := a.prog.NewFunction("<root>", new(types.Signature), "root of callgraph")
+ root := a.makeCGNode(r, 0, nil)
+
+ // TODO(adonovan): make an ssa utility to construct an actual
+ // root function so we don't need to special-case site-less
+ // call edges.
+
+ // For each main package, call main.init(), main.main().
+ for _, mainPkg := range a.config.Mains {
+ main := mainPkg.Func("main")
+ if main == nil {
+ panic(fmt.Sprintf("%s has no main function", mainPkg))
+ }
+
+ targets := a.addOneNode(main.Signature, "root.targets", nil)
+ site := &callsite{targets: targets}
+ root.sites = append(root.sites, site)
+ for _, fn := range [2]*ssa.Function{mainPkg.Func("init"), main} {
+ if a.log != nil {
+ fmt.Fprintf(a.log, "\troot call to %s:\n", fn)
+ }
+ a.copy(targets, a.valueNode(fn), 1)
+ }
+ }
+
+ return root
+}
+
+// genFunc generates constraints for function fn.
+func (a *analysis) genFunc(cgn *cgnode) {
+ fn := cgn.fn
+
+ impl := a.findIntrinsic(fn)
+
+ if a.log != nil {
+ fmt.Fprintf(a.log, "\n\n==== Generating constraints for %s, %s\n", cgn, cgn.contour())
+
+ // Hack: don't display body if intrinsic.
+ if impl != nil {
+ fn2 := *cgn.fn // copy
+ fn2.Locals = nil
+ fn2.Blocks = nil
+ fn2.WriteTo(a.log)
+ } else {
+ cgn.fn.WriteTo(a.log)
+ }
+ }
+
+ if impl != nil {
+ impl(a, cgn)
+ return
+ }
+
+ if fn.Blocks == nil {
+ // External function with no intrinsic treatment.
+ // We'll warn about calls to such functions at the end.
+ return
+ }
+
+ if a.log != nil {
+ fmt.Fprintln(a.log, "; Creating nodes for local values")
+ }
+
+ a.localval = make(map[ssa.Value]nodeid)
+ a.localobj = make(map[ssa.Value]nodeid)
+
+ // The value nodes for the params are in the func object block.
+ params := a.funcParams(cgn.obj)
+ for _, p := range fn.Params {
+ a.setValueNode(p, params, cgn)
+ params += nodeid(a.sizeof(p.Type()))
+ }
+
+ // Free variables have global cardinality:
+ // the outer function sets them with MakeClosure;
+ // the inner function accesses them with FreeVar.
+ //
+ // TODO(adonovan): treat free vars context-sensitively.
+
+ // Create value nodes for all value instructions
+ // since SSA may contain forward references.
+ var space [10]*ssa.Value
+ for _, b := range fn.Blocks {
+ for _, instr := range b.Instrs {
+ switch instr := instr.(type) {
+ case *ssa.Range:
+ // do nothing: it has a funky type,
+ // and *ssa.Next does all the work.
+
+ case ssa.Value:
+ var comment string
+ if a.log != nil {
+ comment = instr.Name()
+ }
+ id := a.addNodes(instr.Type(), comment)
+ a.setValueNode(instr, id, cgn)
+ }
+
+ // Record all address-taken functions (for presolver).
+ rands := instr.Operands(space[:0])
+ if call, ok := instr.(ssa.CallInstruction); ok && !call.Common().IsInvoke() {
+ // Skip CallCommon.Value in "call" mode.
+ // TODO(adonovan): fix: relies on unspecified ordering. Specify it.
+ rands = rands[1:]
+ }
+ for _, rand := range rands {
+ if atf, ok := (*rand).(*ssa.Function); ok {
+ a.atFuncs[atf] = true
+ }
+ }
+ }
+ }
+
+ // Generate constraints for instructions.
+ for _, b := range fn.Blocks {
+ for _, instr := range b.Instrs {
+ a.genInstr(cgn, instr)
+ }
+ }
+
+ a.localval = nil
+ a.localobj = nil
+}
+
+// genMethodsOf generates nodes and constraints for all methods of type T.
+func (a *analysis) genMethodsOf(T types.Type) {
+ itf := isInterface(T)
+
+ // TODO(adonovan): can we skip this entirely if itf is true?
+ // I think so, but the answer may depend on reflection.
+ mset := a.prog.MethodSets.MethodSet(T)
+ for i, n := 0, mset.Len(); i < n; i++ {
+ m := a.prog.Method(mset.At(i))
+ a.valueNode(m)
+
+ if !itf {
+ // Methods of concrete types are address-taken functions.
+ a.atFuncs[m] = true
+ }
+ }
+}
+
+// generate generates offline constraints for the entire program.
+func (a *analysis) generate() {
+ start("Constraint generation")
+ if a.log != nil {
+ fmt.Fprintln(a.log, "==== Generating constraints")
+ }
+
+ // Create a dummy node since we use the nodeid 0 for
+ // non-pointerlike variables.
+ a.addNodes(tInvalid, "(zero)")
+
+ // Create the global node for panic values.
+ a.panicNode = a.addNodes(tEface, "panic")
+
+ // Create nodes and constraints for all methods of reflect.rtype.
+ // (Shared contours are used by dynamic calls to reflect.Type
+ // methods---typically just String().)
+ if rtype := a.reflectRtypePtr; rtype != nil {
+ a.genMethodsOf(rtype)
+ }
+
+ root := a.genRootCalls()
+
+ if a.config.BuildCallGraph {
+ a.result.CallGraph = callgraph.New(root.fn)
+ }
+
+ // Create nodes and constraints for all methods of all types
+ // that are dynamically accessible via reflection or interfaces.
+ for _, T := range a.prog.RuntimeTypes() {
+ a.genMethodsOf(T)
+ }
+
+ // Generate constraints for entire program.
+ for len(a.genq) > 0 {
+ cgn := a.genq[0]
+ a.genq = a.genq[1:]
+ a.genFunc(cgn)
+ }
+
+ // The runtime magically allocates os.Args; so should we.
+ if os := a.prog.ImportedPackage("os"); os != nil {
+ // In effect: os.Args = new([1]string)[:]
+ T := types.NewSlice(types.Typ[types.String])
+ obj := a.addNodes(sliceToArray(T), "<command-line args>")
+ a.endObject(obj, nil, "<command-line args>")
+ a.addressOf(T, a.objectNode(nil, os.Var("Args")), obj)
+ }
+
+ // Discard generation state, to avoid confusion after node renumbering.
+ a.panicNode = 0
+ a.globalval = nil
+ a.localval = nil
+ a.localobj = nil
+
+ stop("Constraint generation")
+}
diff --git a/go/pointer/hvn.go b/go/pointer/hvn.go
new file mode 100644
index 0000000..a3ef1f3
--- /dev/null
+++ b/go/pointer/hvn.go
@@ -0,0 +1,969 @@
+package pointer
+
+// This file implements Hash-Value Numbering (HVN), a pre-solver
+// constraint optimization described in Hardekopf & Lin, SAS'07 (see
+// doc.go) that analyses the graph topology to determine which sets of
+// variables are "pointer equivalent" (PE), i.e. must have identical
+// points-to sets in the solution.
+//
+// A separate ("offline") graph is constructed. Its nodes are those of
+// the main-graph, plus an additional node *X for each pointer node X.
+// With this graph we can reason about the unknown points-to set of
+// dereferenced pointers. (We do not generalize this to represent
+// unknown fields x->f, perhaps because such fields would be numerous,
+// though it might be worth an experiment.)
+//
+// Nodes whose points-to relations are not entirely captured by the
+// graph are marked as "indirect": the *X nodes, the parameters of
+// address-taken functions (which includes all functions in method
+// sets), or nodes updated by the solver rules for reflection, etc.
+//
+// All addr (y=&x) nodes are initially assigned a pointer-equivalence
+// (PE) label equal to x's nodeid in the main graph. (These are the
+// only PE labels that are less than len(a.nodes).)
+//
+// All offsetAddr (y=&x.f) constraints are initially assigned a PE
+// label; such labels are memoized, keyed by (x, f), so that equivalent
+// nodes y as assigned the same label.
+//
+// Then we process each strongly connected component (SCC) of the graph
+// in topological order, assigning it a PE label based on the set P of
+// PE labels that flow to it from its immediate dependencies.
+//
+// If any node in P is "indirect", the entire SCC is assigned a fresh PE
+// label. Otherwise:
+//
+// |P|=0 if P is empty, all nodes in the SCC are non-pointers (e.g.
+// uninitialized variables, or formal params of dead functions)
+// and the SCC is assigned the PE label of zero.
+//
+// |P|=1 if P is a singleton, the SCC is assigned the same label as the
+// sole element of P.
+//
+// |P|>1 if P contains multiple labels, a unique label representing P is
+// invented and recorded in an hash table, so that other
+// equivalent SCCs may also be assigned this label, akin to
+// conventional hash-value numbering in a compiler.
+//
+// Finally, a renumbering is computed such that each node is replaced by
+// the lowest-numbered node with the same PE label. All constraints are
+// renumbered, and any resulting duplicates are eliminated.
+//
+// The only nodes that are not renumbered are the objects x in addr
+// (y=&x) constraints, since the ids of these nodes (and fields derived
+// from them via offsetAddr rules) are the elements of all points-to
+// sets, so they must remain as they are if we want the same solution.
+//
+// The solverStates (node.solve) for nodes in the same equivalence class
+// are linked together so that all nodes in the class have the same
+// solution. This avoids the need to renumber nodeids buried in
+// Queries, cgnodes, etc (like (*analysis).renumber() does) since only
+// the solution is needed.
+//
+// The result of HVN is that the number of distinct nodes and
+// constraints is reduced, but the solution is identical (almost---see
+// CROSS-CHECK below). In particular, both linear and cyclic chains of
+// copies are each replaced by a single node.
+//
+// Nodes and constraints created "online" (e.g. while solving reflection
+// constraints) are not subject to this optimization.
+//
+// PERFORMANCE
+//
+// In two benchmarks (oracle and godoc), HVN eliminates about two thirds
+// of nodes, the majority accounted for by non-pointers: nodes of
+// non-pointer type, pointers that remain nil, formal parameters of dead
+// functions, nodes of untracked types, etc. It also reduces the number
+// of constraints, also by about two thirds, and the solving time by
+// 30--42%, although we must pay about 15% for the running time of HVN
+// itself. The benefit is greater for larger applications.
+//
+// There are many possible optimizations to improve the performance:
+// * Use fewer than 1:1 onodes to main graph nodes: many of the onodes
+// we create are not needed.
+// * HU (HVN with Union---see paper): coalesce "union" peLabels when
+// their expanded-out sets are equal.
+// * HR (HVN with deReference---see paper): this will require that we
+// apply HVN until fixed point, which may need more bookkeeping of the
+// correspondance of main nodes to onodes.
+// * Location Equivalence (see paper): have points-to sets contain not
+// locations but location-equivalence class labels, each representing
+// a set of locations.
+// * HVN with field-sensitive ref: model each of the fields of a
+// pointer-to-struct.
+//
+// CROSS-CHECK
+//
+// To verify the soundness of the optimization, when the
+// debugHVNCrossCheck option is enabled, we run the solver twice, once
+// before and once after running HVN, dumping the solution to disk, and
+// then we compare the results. If they are not identical, the analysis
+// panics.
+//
+// The solution dumped to disk includes only the N*N submatrix of the
+// complete solution where N is the number of nodes after generation.
+// In other words, we ignore pointer variables and objects created by
+// the solver itself, since their numbering depends on the solver order,
+// which is affected by the optimization. In any case, that's the only
+// part the client cares about.
+//
+// The cross-check is too strict and may fail spuriously. Although the
+// H&L paper describing HVN states that the solutions obtained should be
+// identical, this is not the case in practice because HVN can collapse
+// cycles involving *p even when pts(p)={}. Consider this example
+// distilled from testdata/hello.go:
+//
+// var x T
+// func f(p **T) {
+// t0 = *p
+// ...
+// t1 = φ(t0, &x)
+// *p = t1
+// }
+//
+// If f is dead code, we get:
+// unoptimized: pts(p)={} pts(t0)={} pts(t1)={&x}
+// optimized: pts(p)={} pts(t0)=pts(t1)=pts(*p)={&x}
+//
+// It's hard to argue that this is a bug: the result is sound and the
+// loss of precision is inconsequential---f is dead code, after all.
+// But unfortunately it limits the usefulness of the cross-check since
+// failures must be carefully analyzed. Ben Hardekopf suggests (in
+// personal correspondence) some approaches to mitigating it:
+//
+// If there is a node with an HVN points-to set that is a superset
+// of the NORM points-to set, then either it's a bug or it's a
+// result of this issue. If it's a result of this issue, then in
+// the offline constraint graph there should be a REF node inside
+// some cycle that reaches this node, and in the NORM solution the
+// pointer being dereferenced by that REF node should be the empty
+// set. If that isn't true then this is a bug. If it is true, then
+// you can further check that in the NORM solution the "extra"
+// points-to info in the HVN solution does in fact come from that
+// purported cycle (if it doesn't, then this is still a bug). If
+// you're doing the further check then you'll need to do it for
+// each "extra" points-to element in the HVN points-to set.
+//
+// There are probably ways to optimize these checks by taking
+// advantage of graph properties. For example, extraneous points-to
+// info will flow through the graph and end up in many
+// nodes. Rather than checking every node with extra info, you
+// could probably work out the "origin point" of the extra info and
+// just check there. Note that the check in the first bullet is
+// looking for soundness bugs, while the check in the second bullet
+// is looking for precision bugs; depending on your needs, you may
+// care more about one than the other.
+//
+// which we should evaluate. The cross-check is nonetheless invaluable
+// for all but one of the programs in the pointer_test suite.
+
+import (
+ "fmt"
+ "io"
+ "reflect"
+
+ "golang.org/x/tools/container/intsets"
+ "golang.org/x/tools/go/types"
+)
+
+// A peLabel is a pointer-equivalence label: two nodes with the same
+// peLabel have identical points-to solutions.
+//
+// The numbers are allocated consecutively like so:
+// 0 not a pointer
+// 1..N-1 addrConstraints (equals the constraint's .src field, hence sparse)
+// ... offsetAddr constraints
+// ... SCCs (with indirect nodes or multiple inputs)
+//
+// Each PE label denotes a set of pointers containing a single addr, a
+// single offsetAddr, or some set of other PE labels.
+//
+type peLabel int
+
+type hvn struct {
+ a *analysis
+ N int // len(a.nodes) immediately after constraint generation
+ log io.Writer // (optional) log of HVN lemmas
+ onodes []*onode // nodes of the offline graph
+ label peLabel // the next available PE label
+ hvnLabel map[string]peLabel // hash-value numbering (PE label) for each set of onodeids
+ stack []onodeid // DFS stack
+ index int32 // next onode.index, from Tarjan's SCC algorithm
+
+ // For each distinct offsetAddrConstraint (src, offset) pair,
+ // offsetAddrLabels records a unique PE label >= N.
+ offsetAddrLabels map[offsetAddr]peLabel
+}
+
+// The index of an node in the offline graph.
+// (Currently the first N align with the main nodes,
+// but this may change with HRU.)
+type onodeid uint32
+
+// An onode is a node in the offline constraint graph.
+// (Where ambiguous, members of analysis.nodes are referred to as
+// "main graph" nodes.)
+//
+// Edges in the offline constraint graph (edges and implicit) point to
+// the source, i.e. against the flow of values: they are dependencies.
+// Implicit edges are used for SCC computation, but not for gathering
+// incoming labels.
+//
+type onode struct {
+ rep onodeid // index of representative of SCC in offline constraint graph
+
+ edges intsets.Sparse // constraint edges X-->Y (this onode is X)
+ implicit intsets.Sparse // implicit edges *X-->*Y (this onode is X)
+ peLabels intsets.Sparse // set of peLabels are pointer-equivalent to this one
+ indirect bool // node has points-to relations not represented in graph
+
+ // Tarjan's SCC algorithm
+ index, lowlink int32 // Tarjan numbering
+ scc int32 // -ve => on stack; 0 => unvisited; +ve => node is root of a found SCC
+}
+
+type offsetAddr struct {
+ ptr nodeid
+ offset uint32
+}
+
+// nextLabel issues the next unused pointer-equivalence label.
+func (h *hvn) nextLabel() peLabel {
+ h.label++
+ return h.label
+}
+
+// ref(X) returns the index of the onode for *X.
+func (h *hvn) ref(id onodeid) onodeid {
+ return id + onodeid(len(h.a.nodes))
+}
+
+// hvn computes pointer-equivalence labels (peLabels) using the Hash-based
+// Value Numbering (HVN) algorithm described in Hardekopf & Lin, SAS'07.
+//
+func (a *analysis) hvn() {
+ start("HVN")
+
+ if a.log != nil {
+ fmt.Fprintf(a.log, "\n\n==== Pointer equivalence optimization\n\n")
+ }
+
+ h := hvn{
+ a: a,
+ N: len(a.nodes),
+ log: a.log,
+ hvnLabel: make(map[string]peLabel),
+ offsetAddrLabels: make(map[offsetAddr]peLabel),
+ }
+
+ if h.log != nil {
+ fmt.Fprintf(h.log, "\nCreating offline graph nodes...\n")
+ }
+
+ // Create offline nodes. The first N nodes correspond to main
+ // graph nodes; the next N are their corresponding ref() nodes.
+ h.onodes = make([]*onode, 2*h.N)
+ for id := range a.nodes {
+ id := onodeid(id)
+ h.onodes[id] = &onode{}
+ h.onodes[h.ref(id)] = &onode{indirect: true}
+ }
+
+ // Each node initially represents just itself.
+ for id, o := range h.onodes {
+ o.rep = onodeid(id)
+ }
+
+ h.markIndirectNodes()
+
+ // Reserve the first N PE labels for addrConstraints.
+ h.label = peLabel(h.N)
+
+ // Add offline constraint edges.
+ if h.log != nil {
+ fmt.Fprintf(h.log, "\nAdding offline graph edges...\n")
+ }
+ for _, c := range a.constraints {
+ if debugHVNVerbose && h.log != nil {
+ fmt.Fprintf(h.log, "; %s\n", c)
+ }
+ c.presolve(&h)
+ }
+
+ // Find and collapse SCCs.
+ if h.log != nil {
+ fmt.Fprintf(h.log, "\nFinding SCCs...\n")
+ }
+ h.index = 1
+ for id, o := range h.onodes {
+ if id > 0 && o.index == 0 {
+ // Start depth-first search at each unvisited node.
+ h.visit(onodeid(id))
+ }
+ }
+
+ // Dump the solution
+ // (NB: somewhat redundant with logging from simplify().)
+ if debugHVNVerbose && h.log != nil {
+ fmt.Fprintf(h.log, "\nPointer equivalences:\n")
+ for id, o := range h.onodes {
+ if id == 0 {
+ continue
+ }
+ if id == int(h.N) {
+ fmt.Fprintf(h.log, "---\n")
+ }
+ fmt.Fprintf(h.log, "o%d\t", id)
+ if o.rep != onodeid(id) {
+ fmt.Fprintf(h.log, "rep=o%d", o.rep)
+ } else {
+ fmt.Fprintf(h.log, "p%d", o.peLabels.Min())
+ if o.indirect {
+ fmt.Fprint(h.log, " indirect")
+ }
+ }
+ fmt.Fprintln(h.log)
+ }
+ }
+
+ // Simplify the main constraint graph
+ h.simplify()
+
+ a.showCounts()
+
+ stop("HVN")
+}
+
+// ---- constraint-specific rules ----
+
+// dst := &src
+func (c *addrConstraint) presolve(h *hvn) {
+ // Each object (src) is an initial PE label.
+ label := peLabel(c.src) // label < N
+ if debugHVNVerbose && h.log != nil {
+ // duplicate log messages are possible
+ fmt.Fprintf(h.log, "\tcreate p%d: {&n%d}\n", label, c.src)
+ }
+ odst := onodeid(c.dst)
+ osrc := onodeid(c.src)
+
+ // Assign dst this label.
+ h.onodes[odst].peLabels.Insert(int(label))
+ if debugHVNVerbose && h.log != nil {
+ fmt.Fprintf(h.log, "\to%d has p%d\n", odst, label)
+ }
+
+ h.addImplicitEdge(h.ref(odst), osrc) // *dst ~~> src.
+}
+
+// dst = src
+func (c *copyConstraint) presolve(h *hvn) {
+ odst := onodeid(c.dst)
+ osrc := onodeid(c.src)
+ h.addEdge(odst, osrc) // dst --> src
+ h.addImplicitEdge(h.ref(odst), h.ref(osrc)) // *dst ~~> *src
+}
+
+// dst = *src + offset
+func (c *loadConstraint) presolve(h *hvn) {
+ odst := onodeid(c.dst)
+ osrc := onodeid(c.src)
+ if c.offset == 0 {
+ h.addEdge(odst, h.ref(osrc)) // dst --> *src
+ } else {
+ // We don't interpret load-with-offset, e.g. results
+ // of map value lookup, R-block of dynamic call, slice
+ // copy/append, reflection.
+ h.markIndirect(odst, "load with offset")
+ }
+}
+
+// *dst + offset = src
+func (c *storeConstraint) presolve(h *hvn) {
+ odst := onodeid(c.dst)
+ osrc := onodeid(c.src)
+ if c.offset == 0 {
+ h.onodes[h.ref(odst)].edges.Insert(int(osrc)) // *dst --> src
+ if debugHVNVerbose && h.log != nil {
+ fmt.Fprintf(h.log, "\to%d --> o%d\n", h.ref(odst), osrc)
+ }
+ } else {
+ // We don't interpret store-with-offset.
+ // See discussion of soundness at markIndirectNodes.
+ }
+}
+
+// dst = &src.offset
+func (c *offsetAddrConstraint) presolve(h *hvn) {
+ // Give each distinct (addr, offset) pair a fresh PE label.
+ // The cache performs CSE, effectively.
+ key := offsetAddr{c.src, c.offset}
+ label, ok := h.offsetAddrLabels[key]
+ if !ok {
+ label = h.nextLabel()
+ h.offsetAddrLabels[key] = label
+ if debugHVNVerbose && h.log != nil {
+ fmt.Fprintf(h.log, "\tcreate p%d: {&n%d.#%d}\n",
+ label, c.src, c.offset)
+ }
+ }
+
+ // Assign dst this label.
+ h.onodes[c.dst].peLabels.Insert(int(label))
+ if debugHVNVerbose && h.log != nil {
+ fmt.Fprintf(h.log, "\to%d has p%d\n", c.dst, label)
+ }
+}
+
+// dst = src.(typ) where typ is an interface
+func (c *typeFilterConstraint) presolve(h *hvn) {
+ h.markIndirect(onodeid(c.dst), "typeFilter result")
+}
+
+// dst = src.(typ) where typ is concrete
+func (c *untagConstraint) presolve(h *hvn) {
+ odst := onodeid(c.dst)
+ for end := odst + onodeid(h.a.sizeof(c.typ)); odst < end; odst++ {
+ h.markIndirect(odst, "untag result")
+ }
+}
+
+// dst = src.method(c.params...)
+func (c *invokeConstraint) presolve(h *hvn) {
+ // All methods are address-taken functions, so
+ // their formal P-blocks were already marked indirect.
+
+ // Mark the caller's targets node as indirect.
+ sig := c.method.Type().(*types.Signature)
+ id := c.params
+ h.markIndirect(onodeid(c.params), "invoke targets node")
+ id++
+
+ id += nodeid(h.a.sizeof(sig.Params()))
+
+ // Mark the caller's R-block as indirect.
+ end := id + nodeid(h.a.sizeof(sig.Results()))
+ for id < end {
+ h.markIndirect(onodeid(id), "invoke R-block")
+ id++
+ }
+}
+
+// markIndirectNodes marks as indirect nodes whose points-to relations
+// are not entirely captured by the offline graph, including:
+//
+// (a) All address-taken nodes (including the following nodes within
+// the same object). This is described in the paper.
+//
+// The most subtle cause of indirect nodes is the generation of
+// store-with-offset constraints since the offline graph doesn't
+// represent them. A global audit of constraint generation reveals the
+// following uses of store-with-offset:
+//
+// (b) genDynamicCall, for P-blocks of dynamically called functions,
+// to which dynamic copy edges will be added to them during
+// solving: from storeConstraint for standalone functions,
+// and from invokeConstraint for methods.
+// All such P-blocks must be marked indirect.
+// (c) MakeUpdate, to update the value part of a map object.
+// All MakeMap objects's value parts must be marked indirect.
+// (d) copyElems, to update the destination array.
+// All array elements must be marked indirect.
+//
+// Not all indirect marking happens here. ref() nodes are marked
+// indirect at construction, and each constraint's presolve() method may
+// mark additional nodes.
+//
+func (h *hvn) markIndirectNodes() {
+ // (a) all address-taken nodes, plus all nodes following them
+ // within the same object, since these may be indirectly
+ // stored or address-taken.
+ for _, c := range h.a.constraints {
+ if c, ok := c.(*addrConstraint); ok {
+ start := h.a.enclosingObj(c.src)
+ end := start + nodeid(h.a.nodes[start].obj.size)
+ for id := c.src; id < end; id++ {
+ h.markIndirect(onodeid(id), "A-T object")
+ }
+ }
+ }
+
+ // (b) P-blocks of all address-taken functions.
+ for id := 0; id < h.N; id++ {
+ obj := h.a.nodes[id].obj
+
+ // TODO(adonovan): opt: if obj.cgn.fn is a method and
+ // obj.cgn is not its shared contour, this is an
+ // "inlined" static method call. We needn't consider it
+ // address-taken since no invokeConstraint will affect it.
+
+ if obj != nil && obj.flags&otFunction != 0 && h.a.atFuncs[obj.cgn.fn] {
+ // address-taken function
+ if debugHVNVerbose && h.log != nil {
+ fmt.Fprintf(h.log, "n%d is address-taken: %s\n", id, obj.cgn.fn)
+ }
+ h.markIndirect(onodeid(id), "A-T func identity")
+ id++
+ sig := obj.cgn.fn.Signature
+ psize := h.a.sizeof(sig.Params())
+ if sig.Recv() != nil {
+ psize += h.a.sizeof(sig.Recv().Type())
+ }
+ for end := id + int(psize); id < end; id++ {
+ h.markIndirect(onodeid(id), "A-T func P-block")
+ }
+ id--
+ continue
+ }
+ }
+
+ // (c) all map objects' value fields.
+ for _, id := range h.a.mapValues {
+ h.markIndirect(onodeid(id), "makemap.value")
+ }
+
+ // (d) all array element objects.
+ // TODO(adonovan): opt: can we do better?
+ for id := 0; id < h.N; id++ {
+ // Identity node for an object of array type?
+ if tArray, ok := h.a.nodes[id].typ.(*types.Array); ok {
+ // Mark the array element nodes indirect.
+ // (Skip past the identity field.)
+ for _ = range h.a.flatten(tArray.Elem()) {
+ id++
+ h.markIndirect(onodeid(id), "array elem")
+ }
+ }
+ }
+}
+
+func (h *hvn) markIndirect(oid onodeid, comment string) {
+ h.onodes[oid].indirect = true
+ if debugHVNVerbose && h.log != nil {
+ fmt.Fprintf(h.log, "\to%d is indirect: %s\n", oid, comment)
+ }
+}
+
+// Adds an edge dst-->src.
+// Note the unusual convention: edges are dependency (contraflow) edges.
+func (h *hvn) addEdge(odst, osrc onodeid) {
+ h.onodes[odst].edges.Insert(int(osrc))
+ if debugHVNVerbose && h.log != nil {
+ fmt.Fprintf(h.log, "\to%d --> o%d\n", odst, osrc)
+ }
+}
+
+func (h *hvn) addImplicitEdge(odst, osrc onodeid) {
+ h.onodes[odst].implicit.Insert(int(osrc))
+ if debugHVNVerbose && h.log != nil {
+ fmt.Fprintf(h.log, "\to%d ~~> o%d\n", odst, osrc)
+ }
+}
+
+// visit implements the depth-first search of Tarjan's SCC algorithm.
+// Precondition: x is canonical.
+func (h *hvn) visit(x onodeid) {
+ h.checkCanonical(x)
+ xo := h.onodes[x]
+ xo.index = h.index
+ xo.lowlink = h.index
+ h.index++
+
+ h.stack = append(h.stack, x) // push
+ assert(xo.scc == 0, "node revisited")
+ xo.scc = -1
+
+ var deps []int
+ deps = xo.edges.AppendTo(deps)
+ deps = xo.implicit.AppendTo(deps)
+
+ for _, y := range deps {
+ // Loop invariant: x is canonical.
+
+ y := h.find(onodeid(y))
+
+ if x == y {
+ continue // nodes already coalesced
+ }
+
+ xo := h.onodes[x]
+ yo := h.onodes[y]
+
+ switch {
+ case yo.scc > 0:
+ // y is already a collapsed SCC
+
+ case yo.scc < 0:
+ // y is on the stack, and thus in the current SCC.
+ if yo.index < xo.lowlink {
+ xo.lowlink = yo.index
+ }
+
+ default:
+ // y is unvisited; visit it now.
+ h.visit(y)
+ // Note: x and y are now non-canonical.
+
+ x = h.find(onodeid(x))
+
+ if yo.lowlink < xo.lowlink {
+ xo.lowlink = yo.lowlink
+ }
+ }
+ }
+ h.checkCanonical(x)
+
+ // Is x the root of an SCC?
+ if xo.lowlink == xo.index {
+ // Coalesce all nodes in the SCC.
+ if debugHVNVerbose && h.log != nil {
+ fmt.Fprintf(h.log, "scc o%d\n", x)
+ }
+ for {
+ // Pop y from stack.
+ i := len(h.stack) - 1
+ y := h.stack[i]
+ h.stack = h.stack[:i]
+
+ h.checkCanonical(x)
+ xo := h.onodes[x]
+ h.checkCanonical(y)
+ yo := h.onodes[y]
+
+ if xo == yo {
+ // SCC is complete.
+ xo.scc = 1
+ h.labelSCC(x)
+ break
+ }
+ h.coalesce(x, y)
+ }
+ }
+}
+
+// Precondition: x is canonical.
+func (h *hvn) labelSCC(x onodeid) {
+ h.checkCanonical(x)
+ xo := h.onodes[x]
+ xpe := &xo.peLabels
+
+ // All indirect nodes get new labels.
+ if xo.indirect {
+ label := h.nextLabel()
+ if debugHVNVerbose && h.log != nil {
+ fmt.Fprintf(h.log, "\tcreate p%d: indirect SCC\n", label)
+ fmt.Fprintf(h.log, "\to%d has p%d\n", x, label)
+ }
+
+ // Remove pre-labeling, in case a direct pre-labeled node was
+ // merged with an indirect one.
+ xpe.Clear()
+ xpe.Insert(int(label))
+
+ return
+ }
+
+ // Invariant: all peLabels sets are non-empty.
+ // Those that are logically empty contain zero as their sole element.
+ // No other sets contains zero.
+
+ // Find all labels coming in to the coalesced SCC node.
+ for _, y := range xo.edges.AppendTo(nil) {
+ y := h.find(onodeid(y))
+ if y == x {
+ continue // already coalesced
+ }
+ ype := &h.onodes[y].peLabels
+ if debugHVNVerbose && h.log != nil {
+ fmt.Fprintf(h.log, "\tedge from o%d = %s\n", y, ype)
+ }
+
+ if ype.IsEmpty() {
+ if debugHVNVerbose && h.log != nil {
+ fmt.Fprintf(h.log, "\tnode has no PE label\n")
+ }
+ }
+ assert(!ype.IsEmpty(), "incoming node has no PE label")
+
+ if ype.Has(0) {
+ // {0} represents a non-pointer.
+ assert(ype.Len() == 1, "PE set contains {0, ...}")
+ } else {
+ xpe.UnionWith(ype)
+ }
+ }
+
+ switch xpe.Len() {
+ case 0:
+ // SCC has no incoming non-zero PE labels: it is a non-pointer.
+ xpe.Insert(0)
+
+ case 1:
+ // already a singleton
+
+ default:
+ // SCC has multiple incoming non-zero PE labels.
+ // Find the canonical label representing this set.
+ // We use String() as a fingerprint consistent with Equals().
+ key := xpe.String()
+ label, ok := h.hvnLabel[key]
+ if !ok {
+ label = h.nextLabel()
+ if debugHVNVerbose && h.log != nil {
+ fmt.Fprintf(h.log, "\tcreate p%d: union %s\n", label, xpe.String())
+ }
+ h.hvnLabel[key] = label
+ }
+ xpe.Clear()
+ xpe.Insert(int(label))
+ }
+
+ if debugHVNVerbose && h.log != nil {
+ fmt.Fprintf(h.log, "\to%d has p%d\n", x, xpe.Min())
+ }
+}
+
+// coalesce combines two nodes in the offline constraint graph.
+// Precondition: x and y are canonical.
+func (h *hvn) coalesce(x, y onodeid) {
+ xo := h.onodes[x]
+ yo := h.onodes[y]
+
+ // x becomes y's canonical representative.
+ yo.rep = x
+
+ if debugHVNVerbose && h.log != nil {
+ fmt.Fprintf(h.log, "\tcoalesce o%d into o%d\n", y, x)
+ }
+
+ // x accumulates y's edges.
+ xo.edges.UnionWith(&yo.edges)
+ yo.edges.Clear()
+
+ // x accumulates y's implicit edges.
+ xo.implicit.UnionWith(&yo.implicit)
+ yo.implicit.Clear()
+
+ // x accumulates y's pointer-equivalence labels.
+ xo.peLabels.UnionWith(&yo.peLabels)
+ yo.peLabels.Clear()
+
+ // x accumulates y's indirect flag.
+ if yo.indirect {
+ xo.indirect = true
+ }
+}
+
+// simplify computes a degenerate renumbering of nodeids from the PE
+// labels assigned by the hvn, and uses it to simplify the main
+// constraint graph, eliminating non-pointer nodes and duplicate
+// constraints.
+//
+func (h *hvn) simplify() {
+ // canon maps each peLabel to its canonical main node.
+ canon := make([]nodeid, h.label)
+ for i := range canon {
+ canon[i] = nodeid(h.N) // indicates "unset"
+ }
+
+ // mapping maps each main node index to the index of the canonical node.
+ mapping := make([]nodeid, len(h.a.nodes))
+
+ for id := range h.a.nodes {
+ id := nodeid(id)
+ if id == 0 {
+ canon[0] = 0
+ mapping[0] = 0
+ continue
+ }
+ oid := h.find(onodeid(id))
+ peLabels := &h.onodes[oid].peLabels
+ assert(peLabels.Len() == 1, "PE class is not a singleton")
+ label := peLabel(peLabels.Min())
+
+ canonId := canon[label]
+ if canonId == nodeid(h.N) {
+ // id becomes the representative of the PE label.
+ canonId = id
+ canon[label] = canonId
+
+ if h.a.log != nil {
+ fmt.Fprintf(h.a.log, "\tpts(n%d) is canonical : \t(%s)\n",
+ id, h.a.nodes[id].typ)
+ }
+
+ } else {
+ // Link the solver states for the two nodes.
+ assert(h.a.nodes[canonId].solve != nil, "missing solver state")
+ h.a.nodes[id].solve = h.a.nodes[canonId].solve
+
+ if h.a.log != nil {
+ // TODO(adonovan): debug: reorganize the log so it prints
+ // one line:
+ // pe y = x1, ..., xn
+ // for each canonical y. Requires allocation.
+ fmt.Fprintf(h.a.log, "\tpts(n%d) = pts(n%d) : %s\n",
+ id, canonId, h.a.nodes[id].typ)
+ }
+ }
+
+ mapping[id] = canonId
+ }
+
+ // Renumber the constraints, eliminate duplicates, and eliminate
+ // any containing non-pointers (n0).
+ addrs := make(map[addrConstraint]bool)
+ copys := make(map[copyConstraint]bool)
+ loads := make(map[loadConstraint]bool)
+ stores := make(map[storeConstraint]bool)
+ offsetAddrs := make(map[offsetAddrConstraint]bool)
+ untags := make(map[untagConstraint]bool)
+ typeFilters := make(map[typeFilterConstraint]bool)
+ invokes := make(map[invokeConstraint]bool)
+
+ nbefore := len(h.a.constraints)
+ cc := h.a.constraints[:0] // in-situ compaction
+ for _, c := range h.a.constraints {
+ // Renumber.
+ switch c := c.(type) {
+ case *addrConstraint:
+ // Don't renumber c.src since it is the label of
+ // an addressable object and will appear in PT sets.
+ c.dst = mapping[c.dst]
+ default:
+ c.renumber(mapping)
+ }
+
+ if c.ptr() == 0 {
+ continue // skip: constraint attached to non-pointer
+ }
+
+ var dup bool
+ switch c := c.(type) {
+ case *addrConstraint:
+ _, dup = addrs[*c]
+ addrs[*c] = true
+
+ case *copyConstraint:
+ if c.src == c.dst {
+ continue // skip degenerate copies
+ }
+ if c.src == 0 {
+ continue // skip copy from non-pointer
+ }
+ _, dup = copys[*c]
+ copys[*c] = true
+
+ case *loadConstraint:
+ if c.src == 0 {
+ continue // skip load from non-pointer
+ }
+ _, dup = loads[*c]
+ loads[*c] = true
+
+ case *storeConstraint:
+ if c.src == 0 {
+ continue // skip store from non-pointer
+ }
+ _, dup = stores[*c]
+ stores[*c] = true
+
+ case *offsetAddrConstraint:
+ if c.src == 0 {
+ continue // skip offset from non-pointer
+ }
+ _, dup = offsetAddrs[*c]
+ offsetAddrs[*c] = true
+
+ case *untagConstraint:
+ if c.src == 0 {
+ continue // skip untag of non-pointer
+ }
+ _, dup = untags[*c]
+ untags[*c] = true
+
+ case *typeFilterConstraint:
+ if c.src == 0 {
+ continue // skip filter of non-pointer
+ }
+ _, dup = typeFilters[*c]
+ typeFilters[*c] = true
+
+ case *invokeConstraint:
+ if c.params == 0 {
+ panic("non-pointer invoke.params")
+ }
+ if c.iface == 0 {
+ continue // skip invoke on non-pointer
+ }
+ _, dup = invokes[*c]
+ invokes[*c] = true
+
+ default:
+ // We don't bother de-duping advanced constraints
+ // (e.g. reflection) since they are uncommon.
+
+ // Eliminate constraints containing non-pointer nodeids.
+ //
+ // We use reflection to find the fields to avoid
+ // adding yet another method to constraint.
+ //
+ // TODO(adonovan): experiment with a constraint
+ // method that returns a slice of pointers to
+ // nodeids fields to enable uniform iteration;
+ // the renumber() method could be removed and
+ // implemented using the new one.
+ //
+ // TODO(adonovan): opt: this is unsound since
+ // some constraints still have an effect if one
+ // of the operands is zero: rVCall, rVMapIndex,
+ // rvSetMapIndex. Handle them specially.
+ rtNodeid := reflect.TypeOf(nodeid(0))
+ x := reflect.ValueOf(c).Elem()
+ for i, nf := 0, x.NumField(); i < nf; i++ {
+ f := x.Field(i)
+ if f.Type() == rtNodeid {
+ if f.Uint() == 0 {
+ dup = true // skip it
+ break
+ }
+ }
+ }
+ }
+ if dup {
+ continue // skip duplicates
+ }
+
+ cc = append(cc, c)
+ }
+ h.a.constraints = cc
+
+ if h.log != nil {
+ fmt.Fprintf(h.log, "#constraints: was %d, now %d\n", nbefore, len(h.a.constraints))
+ }
+}
+
+// find returns the canonical onodeid for x.
+// (The onodes form a disjoint set forest.)
+func (h *hvn) find(x onodeid) onodeid {
+ // TODO(adonovan): opt: this is a CPU hotspot. Try "union by rank".
+ xo := h.onodes[x]
+ rep := xo.rep
+ if rep != x {
+ rep = h.find(rep) // simple path compression
+ xo.rep = rep
+ }
+ return rep
+}
+
+func (h *hvn) checkCanonical(x onodeid) {
+ if debugHVN {
+ assert(x == h.find(x), "not canonical")
+ }
+}
+
+func assert(p bool, msg string) {
+ if debugHVN && !p {
+ panic("assertion failed: " + msg)
+ }
+}
diff --git a/go/pointer/intrinsics.go b/go/pointer/intrinsics.go
new file mode 100644
index 0000000..251c0e2
--- /dev/null
+++ b/go/pointer/intrinsics.go
@@ -0,0 +1,380 @@
+// 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 pointer
+
+// This package defines the treatment of intrinsics, i.e. library
+// functions requiring special analytical treatment.
+//
+// Most of these are C or assembly functions, but even some Go
+// functions require may special treatment if the analysis completely
+// replaces the implementation of an API such as reflection.
+
+// TODO(adonovan): support a means of writing analytic summaries in
+// the target code, so that users can summarise the effects of their
+// own C functions using a snippet of Go.
+
+import (
+ "fmt"
+
+ "golang.org/x/tools/go/ssa"
+ "golang.org/x/tools/go/types"
+)
+
+// Instances of 'intrinsic' generate analysis constraints for calls to
+// intrinsic functions.
+// Implementations may exploit information from the calling site
+// via cgn.callersite; for shared contours this is nil.
+type intrinsic func(a *analysis, cgn *cgnode)
+
+// Initialized in explicit init() to defeat (spurious) initialization
+// cycle error.
+var intrinsicsByName = make(map[string]intrinsic)
+
+func init() {
+ // Key strings are from Function.String().
+ // That little dot ۰ is an Arabic zero numeral (U+06F0),
+ // categories [Nd].
+ for name, fn := range map[string]intrinsic{
+ // Other packages.
+ "bytes.Equal": ext۰NoEffect,
+ "bytes.IndexByte": ext۰NoEffect,
+ "crypto/aes.decryptBlockAsm": ext۰NoEffect,
+ "crypto/aes.encryptBlockAsm": ext۰NoEffect,
+ "crypto/aes.expandKeyAsm": ext۰NoEffect,
+ "crypto/aes.hasAsm": ext۰NoEffect,
+ "crypto/md5.block": ext۰NoEffect,
+ "crypto/rc4.xorKeyStream": ext۰NoEffect,
+ "crypto/sha1.block": ext۰NoEffect,
+ "crypto/sha256.block": ext۰NoEffect,
+ "hash/crc32.castagnoliSSE42": ext۰NoEffect,
+ "hash/crc32.haveSSE42": ext۰NoEffect,
+ "math.Abs": ext۰NoEffect,
+ "math.Acos": ext۰NoEffect,
+ "math.Asin": ext۰NoEffect,
+ "math.Atan": ext۰NoEffect,
+ "math.Atan2": ext۰NoEffect,
+ "math.Ceil": ext۰NoEffect,
+ "math.Cos": ext۰NoEffect,
+ "math.Dim": ext۰NoEffect,
+ "math.Exp": ext۰NoEffect,
+ "math.Exp2": ext۰NoEffect,
+ "math.Expm1": ext۰NoEffect,
+ "math.Float32bits": ext۰NoEffect,
+ "math.Float32frombits": ext۰NoEffect,
+ "math.Float64bits": ext۰NoEffect,
+ "math.Float64frombits": ext۰NoEffect,
+ "math.Floor": ext۰NoEffect,
+ "math.Frexp": ext۰NoEffect,
+ "math.Hypot": ext۰NoEffect,
+ "math.Ldexp": ext۰NoEffect,
+ "math.Log": ext۰NoEffect,
+ "math.Log10": ext۰NoEffect,
+ "math.Log1p": ext۰NoEffect,
+ "math.Log2": ext۰NoEffect,
+ "math.Max": ext۰NoEffect,
+ "math.Min": ext۰NoEffect,
+ "math.Mod": ext۰NoEffect,
+ "math.Modf": ext۰NoEffect,
+ "math.Remainder": ext۰NoEffect,
+ "math.Sin": ext۰NoEffect,
+ "math.Sincos": ext۰NoEffect,
+ "math.Sqrt": ext۰NoEffect,
+ "math.Tan": ext۰NoEffect,
+ "math.Trunc": ext۰NoEffect,
+ "math/big.addMulVVW": ext۰NoEffect,
+ "math/big.addVV": ext۰NoEffect,
+ "math/big.addVW": ext۰NoEffect,
+ "math/big.bitLen": ext۰NoEffect,
+ "math/big.divWVW": ext۰NoEffect,
+ "math/big.divWW": ext۰NoEffect,
+ "math/big.mulAddVWW": ext۰NoEffect,
+ "math/big.mulWW": ext۰NoEffect,
+ "math/big.shlVU": ext۰NoEffect,
+ "math/big.shrVU": ext۰NoEffect,
+ "math/big.subVV": ext۰NoEffect,
+ "math/big.subVW": ext۰NoEffect,
+ "net.runtime_Semacquire": ext۰NoEffect,
+ "net.runtime_Semrelease": ext۰NoEffect,
+ "net.runtime_pollClose": ext۰NoEffect,
+ "net.runtime_pollOpen": ext۰NoEffect,
+ "net.runtime_pollReset": ext۰NoEffect,
+ "net.runtime_pollServerInit": ext۰NoEffect,
+ "net.runtime_pollSetDeadline": ext۰NoEffect,
+ "net.runtime_pollUnblock": ext۰NoEffect,
+ "net.runtime_pollWait": ext۰NoEffect,
+ "net.runtime_pollWaitCanceled": ext۰NoEffect,
+ "os.epipecheck": ext۰NoEffect,
+ "runtime.BlockProfile": ext۰NoEffect,
+ "runtime.Breakpoint": ext۰NoEffect,
+ "runtime.CPUProfile": ext۰NoEffect, // good enough
+ "runtime.Caller": ext۰NoEffect,
+ "runtime.Callers": ext۰NoEffect, // good enough
+ "runtime.FuncForPC": ext۰NoEffect,
+ "runtime.GC": ext۰NoEffect,
+ "runtime.GOMAXPROCS": ext۰NoEffect,
+ "runtime.Goexit": ext۰NoEffect,
+ "runtime.GoroutineProfile": ext۰NoEffect,
+ "runtime.Gosched": ext۰NoEffect,
+ "runtime.MemProfile": ext۰NoEffect,
+ "runtime.NumCPU": ext۰NoEffect,
+ "runtime.NumGoroutine": ext۰NoEffect,
+ "runtime.ReadMemStats": ext۰NoEffect,
+ "runtime.SetBlockProfileRate": ext۰NoEffect,
+ "runtime.SetCPUProfileRate": ext۰NoEffect,
+ "runtime.SetFinalizer": ext۰runtime۰SetFinalizer,
+ "runtime.Stack": ext۰NoEffect,
+ "runtime.ThreadCreateProfile": ext۰NoEffect,
+ "runtime.cstringToGo": ext۰NoEffect,
+ "runtime.funcentry_go": ext۰NoEffect,
+ "runtime.funcline_go": ext۰NoEffect,
+ "runtime.funcname_go": ext۰NoEffect,
+ "runtime.getgoroot": ext۰NoEffect,
+ "runtime/pprof.runtime_cyclesPerSecond": ext۰NoEffect,
+ "strings.IndexByte": ext۰NoEffect,
+ "sync.runtime_Semacquire": ext۰NoEffect,
+ "sync.runtime_Semrelease": ext۰NoEffect,
+ "sync.runtime_Syncsemacquire": ext۰NoEffect,
+ "sync.runtime_Syncsemcheck": ext۰NoEffect,
+ "sync.runtime_Syncsemrelease": ext۰NoEffect,
+ "sync.runtime_procPin": ext۰NoEffect,
+ "sync.runtime_procUnpin": ext۰NoEffect,
+ "sync.runtime_registerPool": ext۰NoEffect,
+ "sync/atomic.AddInt32": ext۰NoEffect,
+ "sync/atomic.AddInt64": ext۰NoEffect,
+ "sync/atomic.AddUint32": ext۰NoEffect,
+ "sync/atomic.AddUint64": ext۰NoEffect,
+ "sync/atomic.AddUintptr": ext۰NoEffect,
+ "sync/atomic.CompareAndSwapInt32": ext۰NoEffect,
+ "sync/atomic.CompareAndSwapUint32": ext۰NoEffect,
+ "sync/atomic.CompareAndSwapUint64": ext۰NoEffect,
+ "sync/atomic.CompareAndSwapUintptr": ext۰NoEffect,
+ "sync/atomic.LoadInt32": ext۰NoEffect,
+ "sync/atomic.LoadInt64": ext۰NoEffect,
+ "sync/atomic.LoadPointer": ext۰NoEffect, // ignore unsafe.Pointers
+ "sync/atomic.LoadUint32": ext۰NoEffect,
+ "sync/atomic.LoadUint64": ext۰NoEffect,
+ "sync/atomic.LoadUintptr": ext۰NoEffect,
+ "sync/atomic.StoreInt32": ext۰NoEffect,
+ "sync/atomic.StorePointer": ext۰NoEffect, // ignore unsafe.Pointers
+ "sync/atomic.StoreUint32": ext۰NoEffect,
+ "sync/atomic.StoreUintptr": ext۰NoEffect,
+ "syscall.Close": ext۰NoEffect,
+ "syscall.Exit": ext۰NoEffect,
+ "syscall.Getpid": ext۰NoEffect,
+ "syscall.Getwd": ext۰NoEffect,
+ "syscall.Kill": ext۰NoEffect,
+ "syscall.RawSyscall": ext۰NoEffect,
+ "syscall.RawSyscall6": ext۰NoEffect,
+ "syscall.Syscall": ext۰NoEffect,
+ "syscall.Syscall6": ext۰NoEffect,
+ "syscall.runtime_AfterFork": ext۰NoEffect,
+ "syscall.runtime_BeforeFork": ext۰NoEffect,
+ "syscall.setenv_c": ext۰NoEffect,
+ "time.Sleep": ext۰NoEffect,
+ "time.now": ext۰NoEffect,
+ "time.startTimer": ext۰time۰startTimer,
+ "time.stopTimer": ext۰NoEffect,
+ } {
+ intrinsicsByName[name] = fn
+ }
+}
+
+// findIntrinsic returns the constraint generation function for an
+// intrinsic function fn, or nil if the function should be handled normally.
+//
+func (a *analysis) findIntrinsic(fn *ssa.Function) intrinsic {
+ // Consult the *Function-keyed cache.
+ // A cached nil indicates a normal non-intrinsic function.
+ impl, ok := a.intrinsics[fn]
+ if !ok {
+ impl = intrinsicsByName[fn.String()] // may be nil
+
+ if a.isReflect(fn) {
+ if !a.config.Reflection {
+ impl = ext۰NoEffect // reflection disabled
+ } else if impl == nil {
+ // Ensure all "reflect" code is treated intrinsically.
+ impl = ext۰NotYetImplemented
+ }
+ }
+
+ a.intrinsics[fn] = impl
+ }
+ return impl
+}
+
+// isReflect reports whether fn belongs to the "reflect" package.
+func (a *analysis) isReflect(fn *ssa.Function) bool {
+ if a.reflectValueObj == nil {
+ return false // "reflect" package not loaded
+ }
+ reflectPackage := a.reflectValueObj.Pkg()
+ if fn.Pkg != nil && fn.Pkg.Object == reflectPackage {
+ return true
+ }
+ // Synthetic wrappers have a nil Pkg, so they slip through the
+ // previous check. Check the receiver package.
+ // TODO(adonovan): should synthetic wrappers have a non-nil Pkg?
+ if recv := fn.Signature.Recv(); recv != nil {
+ if named, ok := deref(recv.Type()).(*types.Named); ok {
+ if named.Obj().Pkg() == reflectPackage {
+ return true // e.g. wrapper of (reflect.Value).f
+ }
+ }
+ }
+ return false
+}
+
+// A trivial intrinsic suitable for any function that does not:
+// 1) induce aliases between its arguments or any global variables;
+// 2) call any functions; or
+// 3) create any labels.
+//
+// Many intrinsics (such as CompareAndSwapInt32) have a fourth kind of
+// effect: loading or storing through a pointer. Though these could
+// be significant, we deliberately ignore them because they are
+// generally not worth the effort.
+//
+// We sometimes violate condition #3 if the function creates only
+// non-function labels, as the control-flow graph is still sound.
+//
+func ext۰NoEffect(a *analysis, cgn *cgnode) {}
+
+func ext۰NotYetImplemented(a *analysis, cgn *cgnode) {
+ fn := cgn.fn
+ a.warnf(fn.Pos(), "unsound: intrinsic treatment of %s not yet implemented", fn)
+}
+
+// ---------- func runtime.SetFinalizer(x, f interface{}) ----------
+
+// runtime.SetFinalizer(x, f)
+type runtimeSetFinalizerConstraint struct {
+ targets nodeid // (indirect)
+ f nodeid // (ptr)
+ x nodeid
+}
+
+func (c *runtimeSetFinalizerConstraint) ptr() nodeid { return c.f }
+func (c *runtimeSetFinalizerConstraint) presolve(h *hvn) {
+ h.markIndirect(onodeid(c.targets), "SetFinalizer.targets")
+}
+func (c *runtimeSetFinalizerConstraint) renumber(mapping []nodeid) {
+ c.targets = mapping[c.targets]
+ c.f = mapping[c.f]
+ c.x = mapping[c.x]
+}
+
+func (c *runtimeSetFinalizerConstraint) String() string {
+ return fmt.Sprintf("runtime.SetFinalizer(n%d, n%d)", c.x, c.f)
+}
+
+func (c *runtimeSetFinalizerConstraint) solve(a *analysis, delta *nodeset) {
+ for _, fObj := range delta.AppendTo(a.deltaSpace) {
+ tDyn, f, indirect := a.taggedValue(nodeid(fObj))
+ if indirect {
+ // TODO(adonovan): we'll need to implement this
+ // when we start creating indirect tagged objects.
+ panic("indirect tagged object")
+ }
+
+ tSig, ok := tDyn.Underlying().(*types.Signature)
+ if !ok {
+ continue // not a function
+ }
+ if tSig.Recv() != nil {
+ panic(tSig)
+ }
+ if tSig.Params().Len() != 1 {
+ continue // not a unary function
+ }
+
+ // Extract x to tmp.
+ tx := tSig.Params().At(0).Type()
+ tmp := a.addNodes(tx, "SetFinalizer.tmp")
+ a.typeAssert(tx, tmp, c.x, false)
+
+ // Call f(tmp).
+ a.store(f, tmp, 1, a.sizeof(tx))
+
+ // Add dynamic call target.
+ if a.onlineCopy(c.targets, f) {
+ a.addWork(c.targets)
+ }
+ }
+}
+
+func ext۰runtime۰SetFinalizer(a *analysis, cgn *cgnode) {
+ // This is the shared contour, used for dynamic calls.
+ targets := a.addOneNode(tInvalid, "SetFinalizer.targets", nil)
+ cgn.sites = append(cgn.sites, &callsite{targets: targets})
+ params := a.funcParams(cgn.obj)
+ a.addConstraint(&runtimeSetFinalizerConstraint{
+ targets: targets,
+ x: params,
+ f: params + 1,
+ })
+}
+
+// ---------- func time.startTimer(t *runtimeTimer) ----------
+
+// time.StartTimer(t)
+type timeStartTimerConstraint struct {
+ targets nodeid // (indirect)
+ t nodeid // (ptr)
+}
+
+func (c *timeStartTimerConstraint) ptr() nodeid { return c.t }
+func (c *timeStartTimerConstraint) presolve(h *hvn) {
+ h.markIndirect(onodeid(c.targets), "StartTimer.targets")
+}
+func (c *timeStartTimerConstraint) renumber(mapping []nodeid) {
+ c.targets = mapping[c.targets]
+ c.t = mapping[c.t]
+}
+
+func (c *timeStartTimerConstraint) String() string {
+ return fmt.Sprintf("time.startTimer(n%d)", c.t)
+}
+
+func (c *timeStartTimerConstraint) solve(a *analysis, delta *nodeset) {
+ for _, tObj := range delta.AppendTo(a.deltaSpace) {
+ t := nodeid(tObj)
+
+ // We model startTimer as if it was defined thus:
+ // func startTimer(t *runtimeTimer) { t.f(t.arg) }
+
+ // We hard-code the field offsets of time.runtimeTimer:
+ // type runtimeTimer struct {
+ // 0 __identity__
+ // 1 i int32
+ // 2 when int64
+ // 3 period int64
+ // 4 f func(int64, interface{})
+ // 5 arg interface{}
+ // }
+ f := t + 4
+ arg := t + 5
+
+ // store t.arg to t.f.params[0]
+ // (offset 1 => skip identity)
+ a.store(f, arg, 1, 1)
+
+ // Add dynamic call target.
+ if a.onlineCopy(c.targets, f) {
+ a.addWork(c.targets)
+ }
+ }
+}
+
+func ext۰time۰startTimer(a *analysis, cgn *cgnode) {
+ // This is the shared contour, used for dynamic calls.
+ targets := a.addOneNode(tInvalid, "startTimer.targets", nil)
+ cgn.sites = append(cgn.sites, &callsite{targets: targets})
+ params := a.funcParams(cgn.obj)
+ a.addConstraint(&timeStartTimerConstraint{
+ targets: targets,
+ t: params,
+ })
+}
diff --git a/go/pointer/labels.go b/go/pointer/labels.go
new file mode 100644
index 0000000..cf6ef20
--- /dev/null
+++ b/go/pointer/labels.go
@@ -0,0 +1,152 @@
+// 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 pointer
+
+import (
+ "fmt"
+ "go/token"
+ "strings"
+
+ "golang.org/x/tools/go/ssa"
+ "golang.org/x/tools/go/types"
+)
+
+// A Label is an entity that may be pointed to by a pointer, map,
+// channel, 'func', slice or interface.
+//
+// Labels include:
+// - functions
+// - globals
+// - tagged objects, representing interfaces and reflect.Values
+// - arrays created by conversions (e.g. []byte("foo"), []byte(s))
+// - stack- and heap-allocated variables (including composite literals)
+// - channels, maps and arrays created by make()
+// - intrinsic or reflective operations that allocate (e.g. append, reflect.New)
+// - intrinsic objects, e.g. the initial array behind os.Args.
+// - and their subelements, e.g. "alloc.y[*].z"
+//
+// Labels are so varied that they defy good generalizations;
+// some have no value, no callgraph node, or no position.
+// Many objects have types that are inexpressible in Go:
+// maps, channels, functions, tagged objects.
+//
+// At most one of Value() or ReflectType() may return non-nil.
+//
+type Label struct {
+ obj *object // the addressable memory location containing this label
+ subelement *fieldInfo // subelement path within obj, e.g. ".a.b[*].c"
+}
+
+// Value returns the ssa.Value that allocated this label's object, if any.
+func (l Label) Value() ssa.Value {
+ val, _ := l.obj.data.(ssa.Value)
+ return val
+}
+
+// ReflectType returns the type represented by this label if it is an
+// reflect.rtype instance object or *reflect.rtype-tagged object.
+//
+func (l Label) ReflectType() types.Type {
+ rtype, _ := l.obj.data.(types.Type)
+ return rtype
+}
+
+// Path returns the path to the subelement of the object containing
+// this label. For example, ".x[*].y".
+//
+func (l Label) Path() string {
+ return l.subelement.path()
+}
+
+// Pos returns the position of this label, if known, zero otherwise.
+func (l Label) Pos() token.Pos {
+ switch data := l.obj.data.(type) {
+ case ssa.Value:
+ return data.Pos()
+ case types.Type:
+ if nt, ok := deref(data).(*types.Named); ok {
+ return nt.Obj().Pos()
+ }
+ }
+ if cgn := l.obj.cgn; cgn != nil {
+ return cgn.fn.Pos()
+ }
+ return token.NoPos
+}
+
+// String returns the printed form of this label.
+//
+// Examples: Object type:
+// x (a variable)
+// (sync.Mutex).Lock (a function)
+// convert (array created by conversion)
+// makemap (map allocated via make)
+// makechan (channel allocated via make)
+// makeinterface (tagged object allocated by makeinterface)
+// <alloc in reflect.Zero> (allocation in instrinsic)
+// sync.Mutex (a reflect.rtype instance)
+// <command-line arguments> (an intrinsic object)
+//
+// Labels within compound objects have subelement paths:
+// x.y[*].z (a struct variable, x)
+// append.y[*].z (array allocated by append)
+// makeslice.y[*].z (array allocated via make)
+//
+// TODO(adonovan): expose func LabelString(*types.Package, Label).
+//
+func (l Label) String() string {
+ var s string
+ switch v := l.obj.data.(type) {
+ case types.Type:
+ return v.String()
+
+ case string:
+ s = v // an intrinsic object (e.g. os.Args[*])
+
+ case nil:
+ if l.obj.cgn != nil {
+ // allocation by intrinsic or reflective operation
+ s = fmt.Sprintf("<alloc in %s>", l.obj.cgn.fn)
+ } else {
+ s = "<unknown>" // should be unreachable
+ }
+
+ case *ssa.Function:
+ s = v.String()
+
+ case *ssa.Global:
+ s = v.String()
+
+ case *ssa.Const:
+ s = v.Name()
+
+ case *ssa.Alloc:
+ s = v.Comment
+ if s == "" {
+ s = "alloc"
+ }
+
+ case *ssa.Call:
+ // Currently only calls to append can allocate objects.
+ if v.Call.Value.(*ssa.Builtin).Object().Name() != "append" {
+ panic("unhandled *ssa.Call label: " + v.Name())
+ }
+ s = "append"
+
+ case *ssa.MakeMap, *ssa.MakeChan, *ssa.MakeSlice, *ssa.Convert:
+ s = strings.ToLower(strings.TrimPrefix(fmt.Sprintf("%T", v), "*ssa."))
+
+ case *ssa.MakeInterface:
+ // MakeInterface is usually implicit in Go source (so
+ // Pos()==0), and tagged objects may be allocated
+ // synthetically (so no *MakeInterface data).
+ s = "makeinterface:" + v.X.Type().String()
+
+ default:
+ panic(fmt.Sprintf("unhandled object data type: %T", v))
+ }
+
+ return s + l.subelement.path()
+}
diff --git a/go/pointer/opt.go b/go/pointer/opt.go
new file mode 100644
index 0000000..2620cc0
--- /dev/null
+++ b/go/pointer/opt.go
@@ -0,0 +1,125 @@
+// 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 pointer
+
+// This file implements renumbering, a pre-solver optimization to
+// improve the efficiency of the solver's points-to set representation.
+//
+// TODO(adonovan): rename file "renumber.go"
+
+import "fmt"
+
+// renumber permutes a.nodes so that all nodes within an addressable
+// object appear before all non-addressable nodes, maintaining the
+// order of nodes within the same object (as required by offsetAddr).
+//
+// renumber must update every nodeid in the analysis (constraints,
+// Pointers, callgraph, etc) to reflect the new ordering.
+//
+// This is an optimisation to increase the locality and efficiency of
+// sparse representations of points-to sets. (Typically only about
+// 20% of nodes are within an object.)
+//
+// NB: nodes added during solving (e.g. for reflection, SetFinalizer)
+// will be appended to the end.
+//
+// Renumbering makes the PTA log inscrutable. To aid debugging, later
+// phases (e.g. HVN) must not rely on it having occurred.
+//
+func (a *analysis) renumber() {
+ if a.log != nil {
+ fmt.Fprintf(a.log, "\n\n==== Renumbering\n\n")
+ }
+
+ N := nodeid(len(a.nodes))
+ newNodes := make([]*node, N, N)
+ renumbering := make([]nodeid, N, N) // maps old to new
+
+ var i, j nodeid
+
+ // The zero node is special.
+ newNodes[j] = a.nodes[i]
+ renumbering[i] = j
+ i++
+ j++
+
+ // Pass 1: object nodes.
+ for i < N {
+ obj := a.nodes[i].obj
+ if obj == nil {
+ i++
+ continue
+ }
+
+ end := i + nodeid(obj.size)
+ for i < end {
+ newNodes[j] = a.nodes[i]
+ renumbering[i] = j
+ i++
+ j++
+ }
+ }
+ nobj := j
+
+ // Pass 2: non-object nodes.
+ for i = 1; i < N; {
+ obj := a.nodes[i].obj
+ if obj != nil {
+ i += nodeid(obj.size)
+ continue
+ }
+
+ newNodes[j] = a.nodes[i]
+ renumbering[i] = j
+ i++
+ j++
+ }
+
+ if j != N {
+ panic(fmt.Sprintf("internal error: j=%d, N=%d", j, N))
+ }
+
+ // Log the remapping table.
+ if a.log != nil {
+ fmt.Fprintf(a.log, "Renumbering nodes to improve density:\n")
+ fmt.Fprintf(a.log, "(%d object nodes of %d total)\n", nobj, N)
+ for old, new := range renumbering {
+ fmt.Fprintf(a.log, "\tn%d -> n%d\n", old, new)
+ }
+ }
+
+ // Now renumber all existing nodeids to use the new node permutation.
+ // It is critical that all reachable nodeids are accounted for!
+
+ // Renumber nodeids in queried Pointers.
+ for v, ptr := range a.result.Queries {
+ ptr.n = renumbering[ptr.n]
+ a.result.Queries[v] = ptr
+ }
+ for v, ptr := range a.result.IndirectQueries {
+ ptr.n = renumbering[ptr.n]
+ a.result.IndirectQueries[v] = ptr
+ }
+
+ // Renumber nodeids in global objects.
+ for v, id := range a.globalobj {
+ a.globalobj[v] = renumbering[id]
+ }
+
+ // Renumber nodeids in constraints.
+ for _, c := range a.constraints {
+ c.renumber(renumbering)
+ }
+
+ // Renumber nodeids in the call graph.
+ for _, cgn := range a.cgnodes {
+ cgn.obj = renumbering[cgn.obj]
+ for _, site := range cgn.sites {
+ site.targets = renumbering[site.targets]
+ }
+ }
+
+ a.nodes = newNodes
+}
diff --git a/go/pointer/pointer_test.go b/go/pointer/pointer_test.go
new file mode 100644
index 0000000..2744d4f
--- /dev/null
+++ b/go/pointer/pointer_test.go
@@ -0,0 +1,576 @@
+// 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 pointer_test
+
+// This test uses 'expectation' comments embedded within testdata/*.go
+// files to specify the expected pointer analysis behaviour.
+// See below for grammar.
+
+import (
+ "bytes"
+ "errors"
+ "fmt"
+ "go/token"
+ "io/ioutil"
+ "os"
+ "regexp"
+ "strconv"
+ "strings"
+ "testing"
+
+ "golang.org/x/tools/go/callgraph"
+ "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"
+ "golang.org/x/tools/go/types"
+ "golang.org/x/tools/go/types/typeutil"
+)
+
+var inputs = []string{
+ "testdata/a_test.go",
+ "testdata/another.go",
+ "testdata/arrayreflect.go",
+ "testdata/arrays.go",
+ "testdata/channels.go",
+ "testdata/chanreflect.go",
+ "testdata/context.go",
+ "testdata/conv.go",
+ "testdata/finalizer.go",
+ "testdata/flow.go",
+ "testdata/fmtexcerpt.go",
+ "testdata/func.go",
+ "testdata/funcreflect.go",
+ "testdata/hello.go", // NB: causes spurious failure of HVN cross-check
+ "testdata/interfaces.go",
+ "testdata/issue9002.go",
+ "testdata/mapreflect.go",
+ "testdata/maps.go",
+ "testdata/panic.go",
+ "testdata/recur.go",
+ "testdata/reflect.go",
+ "testdata/rtti.go",
+ "testdata/structreflect.go",
+ "testdata/structs.go",
+ "testdata/timer.go",
+}
+
+// Expectation grammar:
+//
+// @calls f -> g
+//
+// A 'calls' expectation asserts that edge (f, g) appears in the
+// callgraph. f and g are notated as per Function.String(), which
+// may contain spaces (e.g. promoted method in anon struct).
+//
+// @pointsto a | b | c
+//
+// A 'pointsto' expectation asserts that the points-to set of its
+// operand contains exactly the set of labels {a,b,c} notated as per
+// labelString.
+//
+// A 'pointsto' expectation must appear on the same line as a
+// print(x) statement; the expectation's operand is x.
+//
+// If one of the strings is "...", the expectation asserts that the
+// points-to set at least the other labels.
+//
+// We use '|' because label names may contain spaces, e.g. methods
+// of anonymous structs.
+//
+// From a theoretical perspective, concrete types in interfaces are
+// labels too, but they are represented differently and so have a
+// different expectation, @types, below.
+//
+// @types t | u | v
+//
+// A 'types' expectation asserts that the set of possible dynamic
+// types of its interface operand is exactly {t,u,v}, notated per
+// go/types.Type.String(). In other words, it asserts that the type
+// component of the interface may point to that set of concrete type
+// literals. It also works for reflect.Value, though the types
+// needn't be concrete in that case.
+//
+// A 'types' expectation must appear on the same line as a
+// print(x) statement; the expectation's operand is x.
+//
+// If one of the strings is "...", the expectation asserts that the
+// interface's type may point to at least the other types.
+//
+// We use '|' because type names may contain spaces.
+//
+// @warning "regexp"
+//
+// A 'warning' expectation asserts that the analysis issues a
+// warning that matches the regular expression within the string
+// literal.
+//
+// @line id
+//
+// A line directive associates the name "id" with the current
+// file:line. The string form of labels will use this id instead of
+// a file:line, making @pointsto expectations more robust against
+// perturbations in the source file.
+// (NB, anon functions still include line numbers.)
+//
+type expectation struct {
+ kind string // "pointsto" | "types" | "calls" | "warning"
+ filename string
+ linenum int // source line number, 1-based
+ args []string
+ types []types.Type // for types
+}
+
+func (e *expectation) String() string {
+ return fmt.Sprintf("@%s[%s]", e.kind, strings.Join(e.args, " | "))
+}
+
+func (e *expectation) errorf(format string, args ...interface{}) {
+ fmt.Printf("%s:%d: ", e.filename, e.linenum)
+ fmt.Printf(format, args...)
+ fmt.Println()
+}
+
+func (e *expectation) needsProbe() bool {
+ return e.kind == "pointsto" || e.kind == "types"
+}
+
+// Find probe (call to print(x)) of same source file/line as expectation.
+func findProbe(prog *ssa.Program, probes map[*ssa.CallCommon]bool, queries map[ssa.Value]pointer.Pointer, e *expectation) (site *ssa.CallCommon, pts pointer.PointsToSet) {
+ for call := range probes {
+ pos := prog.Fset.Position(call.Pos())
+ if pos.Line == e.linenum && pos.Filename == e.filename {
+ // TODO(adonovan): send this to test log (display only on failure).
+ // fmt.Printf("%s:%d: info: found probe for %s: %s\n",
+ // e.filename, e.linenum, e, p.arg0) // debugging
+ return call, queries[call.Args[0]].PointsTo()
+ }
+ }
+ return // e.g. analysis didn't reach this call
+}
+
+func doOneInput(input, filename string) bool {
+ var conf loader.Config
+
+ // Parsing.
+ f, err := conf.ParseFile(filename, input)
+ if err != nil {
+ fmt.Println(err)
+ return false
+ }
+
+ // Create single-file main package and import its dependencies.
+ conf.CreateFromFiles("main", f)
+ iprog, err := conf.Load()
+ if err != nil {
+ fmt.Println(err)
+ return false
+ }
+ mainPkgInfo := iprog.Created[0].Pkg
+
+ // SSA creation + building.
+ prog := ssautil.CreateProgram(iprog, ssa.SanityCheckFunctions)
+ prog.BuildAll()
+
+ mainpkg := prog.Package(mainPkgInfo)
+ ptrmain := mainpkg // main package for the pointer analysis
+ if mainpkg.Func("main") == nil {
+ // No main function; assume it's a test.
+ ptrmain = prog.CreateTestMainPackage(mainpkg)
+ }
+
+ // Find all calls to the built-in print(x). Analytically,
+ // print is a no-op, but it's a convenient hook for testing
+ // the PTS of an expression, so our tests use it.
+ probes := make(map[*ssa.CallCommon]bool)
+ for fn := range ssautil.AllFunctions(prog) {
+ if fn.Pkg == mainpkg {
+ for _, b := range fn.Blocks {
+ for _, instr := range b.Instrs {
+ if instr, ok := instr.(ssa.CallInstruction); ok {
+ call := instr.Common()
+ if b, ok := call.Value.(*ssa.Builtin); ok && b.Name() == "print" && len(call.Args) == 1 {
+ probes[instr.Common()] = true
+ }
+ }
+ }
+ }
+ }
+ }
+
+ ok := true
+
+ lineMapping := make(map[string]string) // maps "file:line" to @line tag
+
+ // Parse expectations in this input.
+ var exps []*expectation
+ re := regexp.MustCompile("// *@([a-z]*) *(.*)$")
+ lines := strings.Split(input, "\n")
+ for linenum, line := range lines {
+ linenum++ // make it 1-based
+ if matches := re.FindAllStringSubmatch(line, -1); matches != nil {
+ match := matches[0]
+ kind, rest := match[1], match[2]
+ e := &expectation{kind: kind, filename: filename, linenum: linenum}
+
+ if kind == "line" {
+ if rest == "" {
+ ok = false
+ e.errorf("@%s expectation requires identifier", kind)
+ } else {
+ lineMapping[fmt.Sprintf("%s:%d", filename, linenum)] = rest
+ }
+ continue
+ }
+
+ if e.needsProbe() && !strings.Contains(line, "print(") {
+ ok = false
+ e.errorf("@%s expectation must follow call to print(x)", kind)
+ continue
+ }
+
+ switch kind {
+ case "pointsto":
+ e.args = split(rest, "|")
+
+ case "types":
+ for _, typstr := range split(rest, "|") {
+ var t types.Type = types.Typ[types.Invalid] // means "..."
+ if typstr != "..." {
+ tv, err := types.Eval(prog.Fset, mainpkg.Object, f.Pos(), typstr)
+ if err != nil {
+ ok = false
+ // Don't print err since its location is bad.
+ e.errorf("'%s' is not a valid type: %s", typstr, err)
+ continue
+ }
+ t = tv.Type
+ }
+ e.types = append(e.types, t)
+ }
+
+ case "calls":
+ e.args = split(rest, "->")
+ // TODO(adonovan): eagerly reject the
+ // expectation if fn doesn't denote
+ // existing function, rather than fail
+ // the expectation after analysis.
+ if len(e.args) != 2 {
+ ok = false
+ e.errorf("@calls expectation wants 'caller -> callee' arguments")
+ continue
+ }
+
+ case "warning":
+ lit, err := strconv.Unquote(strings.TrimSpace(rest))
+ if err != nil {
+ ok = false
+ e.errorf("couldn't parse @warning operand: %s", err.Error())
+ continue
+ }
+ e.args = append(e.args, lit)
+
+ default:
+ ok = false
+ e.errorf("unknown expectation kind: %s", e)
+ continue
+ }
+ exps = append(exps, e)
+ }
+ }
+
+ var log bytes.Buffer
+ fmt.Fprintf(&log, "Input: %s\n", filename)
+
+ // Run the analysis.
+ config := &pointer.Config{
+ Reflection: true,
+ BuildCallGraph: true,
+ Mains: []*ssa.Package{ptrmain},
+ Log: &log,
+ }
+ for probe := range probes {
+ v := probe.Args[0]
+ if pointer.CanPoint(v.Type()) {
+ config.AddQuery(v)
+ }
+ }
+
+ // Print the log is there was an error or a panic.
+ complete := false
+ defer func() {
+ if !complete || !ok {
+ log.WriteTo(os.Stderr)
+ }
+ }()
+
+ result, err := pointer.Analyze(config)
+ if err != nil {
+ panic(err) // internal error in pointer analysis
+ }
+
+ // Check the expectations.
+ for _, e := range exps {
+ var call *ssa.CallCommon
+ var pts pointer.PointsToSet
+ var tProbe types.Type
+ if e.needsProbe() {
+ if call, pts = findProbe(prog, probes, result.Queries, e); call == nil {
+ ok = false
+ e.errorf("unreachable print() statement has expectation %s", e)
+ continue
+ }
+ tProbe = call.Args[0].Type()
+ if !pointer.CanPoint(tProbe) {
+ ok = false
+ e.errorf("expectation on non-pointerlike operand: %s", tProbe)
+ continue
+ }
+ }
+
+ switch e.kind {
+ case "pointsto":
+ if !checkPointsToExpectation(e, pts, lineMapping, prog) {
+ ok = false
+ }
+
+ case "types":
+ if !checkTypesExpectation(e, pts, tProbe) {
+ ok = false
+ }
+
+ case "calls":
+ if !checkCallsExpectation(prog, e, result.CallGraph) {
+ ok = false
+ }
+
+ case "warning":
+ if !checkWarningExpectation(prog, e, result.Warnings) {
+ ok = false
+ }
+ }
+ }
+
+ complete = true
+
+ // ok = false // debugging: uncomment to always see log
+
+ return ok
+}
+
+func labelString(l *pointer.Label, lineMapping map[string]string, prog *ssa.Program) string {
+ // Functions and Globals need no pos suffix,
+ // nor do allocations in intrinsic operations
+ // (for which we'll print the function name).
+ switch l.Value().(type) {
+ case nil, *ssa.Function, *ssa.Global:
+ return l.String()
+ }
+
+ str := l.String()
+ if pos := l.Pos(); pos != token.NoPos {
+ // Append the position, using a @line tag instead of a line number, if defined.
+ posn := prog.Fset.Position(pos)
+ s := fmt.Sprintf("%s:%d", posn.Filename, posn.Line)
+ if tag, ok := lineMapping[s]; ok {
+ return fmt.Sprintf("%s@%s:%d", str, tag, posn.Column)
+ }
+ str = fmt.Sprintf("%s@%s", str, posn)
+ }
+ return str
+}
+
+func checkPointsToExpectation(e *expectation, pts pointer.PointsToSet, lineMapping map[string]string, prog *ssa.Program) bool {
+ expected := make(map[string]int)
+ surplus := make(map[string]int)
+ exact := true
+ for _, g := range e.args {
+ if g == "..." {
+ exact = false
+ continue
+ }
+ expected[g]++
+ }
+ // Find the set of labels that the probe's
+ // argument (x in print(x)) may point to.
+ for _, label := range pts.Labels() {
+ name := labelString(label, lineMapping, prog)
+ if expected[name] > 0 {
+ expected[name]--
+ } else if exact {
+ surplus[name]++
+ }
+ }
+ // Report multiset difference:
+ ok := true
+ for _, count := range expected {
+ if count > 0 {
+ ok = false
+ e.errorf("value does not alias these expected labels: %s", join(expected))
+ break
+ }
+ }
+ for _, count := range surplus {
+ if count > 0 {
+ ok = false
+ e.errorf("value may additionally alias these labels: %s", join(surplus))
+ break
+ }
+ }
+ return ok
+}
+
+func checkTypesExpectation(e *expectation, pts pointer.PointsToSet, typ types.Type) bool {
+ var expected typeutil.Map
+ var surplus typeutil.Map
+ exact := true
+ for _, g := range e.types {
+ if g == types.Typ[types.Invalid] {
+ exact = false
+ continue
+ }
+ expected.Set(g, struct{}{})
+ }
+
+ if !pointer.CanHaveDynamicTypes(typ) {
+ e.errorf("@types expectation requires an interface- or reflect.Value-typed operand, got %s", typ)
+ return false
+ }
+
+ // Find the set of types that the probe's
+ // argument (x in print(x)) may contain.
+ for _, T := range pts.DynamicTypes().Keys() {
+ if expected.At(T) != nil {
+ expected.Delete(T)
+ } else if exact {
+ surplus.Set(T, struct{}{})
+ }
+ }
+ // Report set difference:
+ ok := true
+ if expected.Len() > 0 {
+ ok = false
+ e.errorf("interface cannot contain these types: %s", expected.KeysString())
+ }
+ if surplus.Len() > 0 {
+ ok = false
+ e.errorf("interface may additionally contain these types: %s", surplus.KeysString())
+ }
+ return ok
+}
+
+var errOK = errors.New("OK")
+
+func checkCallsExpectation(prog *ssa.Program, e *expectation, cg *callgraph.Graph) bool {
+ found := make(map[string]int)
+ err := callgraph.GraphVisitEdges(cg, func(edge *callgraph.Edge) error {
+ // Name-based matching is inefficient but it allows us to
+ // match functions whose names that would not appear in an
+ // index ("<root>") or which are not unique ("func@1.2").
+ if edge.Caller.Func.String() == e.args[0] {
+ calleeStr := edge.Callee.Func.String()
+ if calleeStr == e.args[1] {
+ return errOK // expectation satisified; stop the search
+ }
+ found[calleeStr]++
+ }
+ return nil
+ })
+ if err == errOK {
+ return true
+ }
+ if len(found) == 0 {
+ e.errorf("didn't find any calls from %s", e.args[0])
+ }
+ e.errorf("found no call from %s to %s, but only to %s",
+ e.args[0], e.args[1], join(found))
+ return false
+}
+
+func checkWarningExpectation(prog *ssa.Program, e *expectation, warnings []pointer.Warning) bool {
+ // TODO(adonovan): check the position part of the warning too?
+ re, err := regexp.Compile(e.args[0])
+ if err != nil {
+ e.errorf("invalid regular expression in @warning expectation: %s", err.Error())
+ return false
+ }
+
+ if len(warnings) == 0 {
+ e.errorf("@warning %s expectation, but no warnings", strconv.Quote(e.args[0]))
+ return false
+ }
+
+ for _, w := range warnings {
+ if re.MatchString(w.Message) {
+ return true
+ }
+ }
+
+ e.errorf("@warning %s expectation not satised; found these warnings though:", strconv.Quote(e.args[0]))
+ for _, w := range warnings {
+ fmt.Printf("%s: warning: %s\n", prog.Fset.Position(w.Pos), w.Message)
+ }
+ return false
+}
+
+func TestInput(t *testing.T) {
+ ok := true
+
+ wd, err := os.Getwd()
+ if err != nil {
+ t.Errorf("os.Getwd: %s", err)
+ return
+ }
+
+ // 'go test' does a chdir so that relative paths in
+ // diagnostics no longer make sense relative to the invoking
+ // shell's cwd. We print a special marker so that Emacs can
+ // make sense of them.
+ fmt.Fprintf(os.Stderr, "Entering directory `%s'\n", wd)
+
+ for _, filename := range inputs {
+ content, err := ioutil.ReadFile(filename)
+ if err != nil {
+ t.Errorf("couldn't read file '%s': %s", filename, err)
+ continue
+ }
+
+ if !doOneInput(string(content), filename) {
+ ok = false
+ }
+ }
+ if !ok {
+ t.Fail()
+ }
+}
+
+// join joins the elements of multiset with " | "s.
+func join(set map[string]int) string {
+ var buf bytes.Buffer
+ sep := ""
+ for name, count := range set {
+ for i := 0; i < count; i++ {
+ buf.WriteString(sep)
+ sep = " | "
+ buf.WriteString(name)
+ }
+ }
+ return buf.String()
+}
+
+// split returns the list of sep-delimited non-empty strings in s.
+func split(s, sep string) (r []string) {
+ for _, elem := range strings.Split(s, sep) {
+ elem = strings.TrimSpace(elem)
+ if elem != "" {
+ r = append(r, elem)
+ }
+ }
+ return
+}
diff --git a/go/pointer/print.go b/go/pointer/print.go
new file mode 100644
index 0000000..4f2f4c7
--- /dev/null
+++ b/go/pointer/print.go
@@ -0,0 +1,43 @@
+// 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 pointer
+
+import "fmt"
+
+func (c *addrConstraint) String() string {
+ return fmt.Sprintf("addr n%d <- {&n%d}", c.dst, c.src)
+}
+
+func (c *copyConstraint) String() string {
+ return fmt.Sprintf("copy n%d <- n%d", c.dst, c.src)
+}
+
+func (c *loadConstraint) String() string {
+ return fmt.Sprintf("load n%d <- n%d[%d]", c.dst, c.src, c.offset)
+}
+
+func (c *storeConstraint) String() string {
+ return fmt.Sprintf("store n%d[%d] <- n%d", c.dst, c.offset, c.src)
+}
+
+func (c *offsetAddrConstraint) String() string {
+ return fmt.Sprintf("offsetAddr n%d <- n%d.#%d", c.dst, c.src, c.offset)
+}
+
+func (c *typeFilterConstraint) String() string {
+ return fmt.Sprintf("typeFilter n%d <- n%d.(%s)", c.dst, c.src, c.typ)
+}
+
+func (c *untagConstraint) String() string {
+ return fmt.Sprintf("untag n%d <- n%d.(%s)", c.dst, c.src, c.typ)
+}
+
+func (c *invokeConstraint) String() string {
+ return fmt.Sprintf("invoke n%d.%s(n%d ...)", c.iface, c.method.Name(), c.params)
+}
+
+func (n nodeid) String() string {
+ return fmt.Sprintf("n%d", n)
+}
diff --git a/go/pointer/reflect.go b/go/pointer/reflect.go
new file mode 100644
index 0000000..466995c
--- /dev/null
+++ b/go/pointer/reflect.go
@@ -0,0 +1,1971 @@
+package pointer
+
+// This file implements the generation and resolution rules for
+// constraints arising from the use of reflection in the target
+// program. See doc.go for explanation of the representation.
+//
+// For consistency, the names of all parameters match those of the
+// actual functions in the "reflect" package.
+//
+// To avoid proliferation of equivalent labels, intrinsics should
+// memoize as much as possible, like TypeOf and Zero do for their
+// tagged objects.
+//
+// TODO(adonovan): this file is rather subtle. Explain how we derive
+// the implementation of each reflect operator from its spec,
+// including the subtleties of reflect.flag{Addr,RO,Indir}.
+// [Hint: our implementation is as if reflect.flagIndir was always
+// true, i.e. reflect.Values are pointers to tagged objects, there is
+// no inline allocation optimization; and indirect tagged objects (not
+// yet implemented) correspond to reflect.Values with
+// reflect.flagAddr.]
+// A picture would help too.
+//
+// TODO(adonovan): try factoring up the common parts of the majority of
+// these constraints that are single input, single output.
+
+import (
+ "fmt"
+ "reflect"
+
+ "golang.org/x/tools/go/exact"
+ "golang.org/x/tools/go/ssa"
+ "golang.org/x/tools/go/types"
+)
+
+func init() {
+ for name, fn := range map[string]intrinsic{
+ // reflect.Value methods.
+ "(reflect.Value).Addr": ext۰reflect۰Value۰Addr,
+ "(reflect.Value).Bool": ext۰NoEffect,
+ "(reflect.Value).Bytes": ext۰reflect۰Value۰Bytes,
+ "(reflect.Value).Call": ext۰reflect۰Value۰Call,
+ "(reflect.Value).CallSlice": ext۰reflect۰Value۰CallSlice,
+ "(reflect.Value).CanAddr": ext۰NoEffect,
+ "(reflect.Value).CanInterface": ext۰NoEffect,
+ "(reflect.Value).CanSet": ext۰NoEffect,
+ "(reflect.Value).Cap": ext۰NoEffect,
+ "(reflect.Value).Close": ext۰NoEffect,
+ "(reflect.Value).Complex": ext۰NoEffect,
+ "(reflect.Value).Convert": ext۰reflect۰Value۰Convert,
+ "(reflect.Value).Elem": ext۰reflect۰Value۰Elem,
+ "(reflect.Value).Field": ext۰reflect۰Value۰Field,
+ "(reflect.Value).FieldByIndex": ext۰reflect۰Value۰FieldByIndex,
+ "(reflect.Value).FieldByName": ext۰reflect۰Value۰FieldByName,
+ "(reflect.Value).FieldByNameFunc": ext۰reflect۰Value۰FieldByNameFunc,
+ "(reflect.Value).Float": ext۰NoEffect,
+ "(reflect.Value).Index": ext۰reflect۰Value۰Index,
+ "(reflect.Value).Int": ext۰NoEffect,
+ "(reflect.Value).Interface": ext۰reflect۰Value۰Interface,
+ "(reflect.Value).InterfaceData": ext۰NoEffect,
+ "(reflect.Value).IsNil": ext۰NoEffect,
+ "(reflect.Value).IsValid": ext۰NoEffect,
+ "(reflect.Value).Kind": ext۰NoEffect,
+ "(reflect.Value).Len": ext۰NoEffect,
+ "(reflect.Value).MapIndex": ext۰reflect۰Value۰MapIndex,
+ "(reflect.Value).MapKeys": ext۰reflect۰Value۰MapKeys,
+ "(reflect.Value).Method": ext۰reflect۰Value۰Method,
+ "(reflect.Value).MethodByName": ext۰reflect۰Value۰MethodByName,
+ "(reflect.Value).NumField": ext۰NoEffect,
+ "(reflect.Value).NumMethod": ext۰NoEffect,
+ "(reflect.Value).OverflowComplex": ext۰NoEffect,
+ "(reflect.Value).OverflowFloat": ext۰NoEffect,
+ "(reflect.Value).OverflowInt": ext۰NoEffect,
+ "(reflect.Value).OverflowUint": ext۰NoEffect,
+ "(reflect.Value).Pointer": ext۰NoEffect,
+ "(reflect.Value).Recv": ext۰reflect۰Value۰Recv,
+ "(reflect.Value).Send": ext۰reflect۰Value۰Send,
+ "(reflect.Value).Set": ext۰reflect۰Value۰Set,
+ "(reflect.Value).SetBool": ext۰NoEffect,
+ "(reflect.Value).SetBytes": ext۰reflect۰Value۰SetBytes,
+ "(reflect.Value).SetComplex": ext۰NoEffect,
+ "(reflect.Value).SetFloat": ext۰NoEffect,
+ "(reflect.Value).SetInt": ext۰NoEffect,
+ "(reflect.Value).SetLen": ext۰NoEffect,
+ "(reflect.Value).SetMapIndex": ext۰reflect۰Value۰SetMapIndex,
+ "(reflect.Value).SetPointer": ext۰reflect۰Value۰SetPointer,
+ "(reflect.Value).SetString": ext۰NoEffect,
+ "(reflect.Value).SetUint": ext۰NoEffect,
+ "(reflect.Value).Slice": ext۰reflect۰Value۰Slice,
+ "(reflect.Value).String": ext۰NoEffect,
+ "(reflect.Value).TryRecv": ext۰reflect۰Value۰Recv,
+ "(reflect.Value).TrySend": ext۰reflect۰Value۰Send,
+ "(reflect.Value).Type": ext۰NoEffect,
+ "(reflect.Value).Uint": ext۰NoEffect,
+ "(reflect.Value).UnsafeAddr": ext۰NoEffect,
+
+ // Standalone reflect.* functions.
+ "reflect.Append": ext۰reflect۰Append,
+ "reflect.AppendSlice": ext۰reflect۰AppendSlice,
+ "reflect.Copy": ext۰reflect۰Copy,
+ "reflect.ChanOf": ext۰reflect۰ChanOf,
+ "reflect.DeepEqual": ext۰NoEffect,
+ "reflect.Indirect": ext۰reflect۰Indirect,
+ "reflect.MakeChan": ext۰reflect۰MakeChan,
+ "reflect.MakeFunc": ext۰reflect۰MakeFunc,
+ "reflect.MakeMap": ext۰reflect۰MakeMap,
+ "reflect.MakeSlice": ext۰reflect۰MakeSlice,
+ "reflect.MapOf": ext۰reflect۰MapOf,
+ "reflect.New": ext۰reflect۰New,
+ "reflect.NewAt": ext۰reflect۰NewAt,
+ "reflect.PtrTo": ext۰reflect۰PtrTo,
+ "reflect.Select": ext۰reflect۰Select,
+ "reflect.SliceOf": ext۰reflect۰SliceOf,
+ "reflect.TypeOf": ext۰reflect۰TypeOf,
+ "reflect.ValueOf": ext۰reflect۰ValueOf,
+ "reflect.Zero": ext۰reflect۰Zero,
+ "reflect.init": ext۰NoEffect,
+
+ // *reflect.rtype methods
+ "(*reflect.rtype).Align": ext۰NoEffect,
+ "(*reflect.rtype).AssignableTo": ext۰NoEffect,
+ "(*reflect.rtype).Bits": ext۰NoEffect,
+ "(*reflect.rtype).ChanDir": ext۰NoEffect,
+ "(*reflect.rtype).ConvertibleTo": ext۰NoEffect,
+ "(*reflect.rtype).Elem": ext۰reflect۰rtype۰Elem,
+ "(*reflect.rtype).Field": ext۰reflect۰rtype۰Field,
+ "(*reflect.rtype).FieldAlign": ext۰NoEffect,
+ "(*reflect.rtype).FieldByIndex": ext۰reflect۰rtype۰FieldByIndex,
+ "(*reflect.rtype).FieldByName": ext۰reflect۰rtype۰FieldByName,
+ "(*reflect.rtype).FieldByNameFunc": ext۰reflect۰rtype۰FieldByNameFunc,
+ "(*reflect.rtype).Implements": ext۰NoEffect,
+ "(*reflect.rtype).In": ext۰reflect۰rtype۰In,
+ "(*reflect.rtype).IsVariadic": ext۰NoEffect,
+ "(*reflect.rtype).Key": ext۰reflect۰rtype۰Key,
+ "(*reflect.rtype).Kind": ext۰NoEffect,
+ "(*reflect.rtype).Len": ext۰NoEffect,
+ "(*reflect.rtype).Method": ext۰reflect۰rtype۰Method,
+ "(*reflect.rtype).MethodByName": ext۰reflect۰rtype۰MethodByName,
+ "(*reflect.rtype).Name": ext۰NoEffect,
+ "(*reflect.rtype).NumField": ext۰NoEffect,
+ "(*reflect.rtype).NumIn": ext۰NoEffect,
+ "(*reflect.rtype).NumMethod": ext۰NoEffect,
+ "(*reflect.rtype).NumOut": ext۰NoEffect,
+ "(*reflect.rtype).Out": ext۰reflect۰rtype۰Out,
+ "(*reflect.rtype).PkgPath": ext۰NoEffect,
+ "(*reflect.rtype).Size": ext۰NoEffect,
+ "(*reflect.rtype).String": ext۰NoEffect,
+ } {
+ intrinsicsByName[name] = fn
+ }
+}
+
+// -------------------- (reflect.Value) --------------------
+
+func ext۰reflect۰Value۰Addr(a *analysis, cgn *cgnode) {} // TODO(adonovan)
+
+// ---------- func (Value).Bytes() Value ----------
+
+// result = v.Bytes()
+type rVBytesConstraint struct {
+ v nodeid // (ptr)
+ result nodeid // (indirect)
+}
+
+func (c *rVBytesConstraint) ptr() nodeid { return c.v }
+func (c *rVBytesConstraint) presolve(h *hvn) {
+ h.markIndirect(onodeid(c.result), "rVBytes.result")
+}
+func (c *rVBytesConstraint) renumber(mapping []nodeid) {
+ c.v = mapping[c.v]
+ c.result = mapping[c.result]
+}
+
+func (c *rVBytesConstraint) String() string {
+ return fmt.Sprintf("n%d = reflect n%d.Bytes()", c.result, c.v)
+}
+
+func (c *rVBytesConstraint) solve(a *analysis, delta *nodeset) {
+ changed := false
+ for _, x := range delta.AppendTo(a.deltaSpace) {
+ vObj := nodeid(x)
+ tDyn, slice, indirect := a.taggedValue(vObj)
+ if indirect {
+ // TODO(adonovan): we'll need to implement this
+ // when we start creating indirect tagged objects.
+ panic("indirect tagged object")
+ }
+
+ tSlice, ok := tDyn.Underlying().(*types.Slice)
+ if ok && types.Identical(tSlice.Elem(), types.Typ[types.Uint8]) {
+ if a.onlineCopy(c.result, slice) {
+ changed = true
+ }
+ }
+ }
+ if changed {
+ a.addWork(c.result)
+ }
+}
+
+func ext۰reflect۰Value۰Bytes(a *analysis, cgn *cgnode) {
+ a.addConstraint(&rVBytesConstraint{
+ v: a.funcParams(cgn.obj),
+ result: a.funcResults(cgn.obj),
+ })
+}
+
+// ---------- func (Value).Call(in []Value) []Value ----------
+
+// result = v.Call(in)
+type rVCallConstraint struct {
+ cgn *cgnode
+ targets nodeid // (indirect)
+ v nodeid // (ptr)
+ arg nodeid // = in[*]
+ result nodeid // (indirect)
+ dotdotdot bool // interpret last arg as a "..." slice
+}
+
+func (c *rVCallConstraint) ptr() nodeid { return c.v }
+func (c *rVCallConstraint) presolve(h *hvn) {
+ h.markIndirect(onodeid(c.targets), "rVCall.targets")
+ h.markIndirect(onodeid(c.result), "rVCall.result")
+}
+func (c *rVCallConstraint) renumber(mapping []nodeid) {
+ c.targets = mapping[c.targets]
+ c.v = mapping[c.v]
+ c.arg = mapping[c.arg]
+ c.result = mapping[c.result]
+}
+
+func (c *rVCallConstraint) String() string {
+ return fmt.Sprintf("n%d = reflect n%d.Call(n%d)", c.result, c.v, c.arg)
+}
+
+func (c *rVCallConstraint) solve(a *analysis, delta *nodeset) {
+ if c.targets == 0 {
+ panic("no targets")
+ }
+
+ changed := false
+ for _, x := range delta.AppendTo(a.deltaSpace) {
+ vObj := nodeid(x)
+ tDyn, fn, indirect := a.taggedValue(vObj)
+ if indirect {
+ // TODO(adonovan): we'll need to implement this
+ // when we start creating indirect tagged objects.
+ panic("indirect tagged object")
+ }
+
+ tSig, ok := tDyn.Underlying().(*types.Signature)
+ if !ok {
+ continue // not a function
+ }
+ if tSig.Recv() != nil {
+ panic(tSig) // TODO(adonovan): rethink when we implement Method()
+ }
+
+ // Add dynamic call target.
+ if a.onlineCopy(c.targets, fn) {
+ a.addWork(c.targets)
+ // TODO(adonovan): is 'else continue' a sound optimisation here?
+ }
+
+ // Allocate a P/R block.
+ tParams := tSig.Params()
+ tResults := tSig.Results()
+ params := a.addNodes(tParams, "rVCall.params")
+ results := a.addNodes(tResults, "rVCall.results")
+
+ // Make a dynamic call to 'fn'.
+ a.store(fn, params, 1, a.sizeof(tParams))
+ a.load(results, fn, 1+a.sizeof(tParams), a.sizeof(tResults))
+
+ // Populate P by type-asserting each actual arg (all merged in c.arg).
+ for i, n := 0, tParams.Len(); i < n; i++ {
+ T := tParams.At(i).Type()
+ a.typeAssert(T, params, c.arg, false)
+ params += nodeid(a.sizeof(T))
+ }
+
+ // Use R by tagging and copying each actual result to c.result.
+ for i, n := 0, tResults.Len(); i < n; i++ {
+ T := tResults.At(i).Type()
+ // Convert from an arbitrary type to a reflect.Value
+ // (like MakeInterface followed by reflect.ValueOf).
+ if isInterface(T) {
+ // (don't tag)
+ if a.onlineCopy(c.result, results) {
+ changed = true
+ }
+ } else {
+ obj := a.makeTagged(T, c.cgn, nil)
+ a.onlineCopyN(obj+1, results, a.sizeof(T))
+ if a.addLabel(c.result, obj) { // (true)
+ changed = true
+ }
+ }
+ results += nodeid(a.sizeof(T))
+ }
+ }
+ if changed {
+ a.addWork(c.result)
+ }
+}
+
+// Common code for direct (inlined) and indirect calls to (reflect.Value).Call.
+func reflectCallImpl(a *analysis, cgn *cgnode, site *callsite, recv, arg nodeid, dotdotdot bool) nodeid {
+ // Allocate []reflect.Value array for the result.
+ ret := a.nextNode()
+ a.addNodes(types.NewArray(a.reflectValueObj.Type(), 1), "rVCall.ret")
+ a.endObject(ret, cgn, nil)
+
+ // pts(targets) will be the set of possible call targets.
+ site.targets = a.addOneNode(tInvalid, "rvCall.targets", nil)
+
+ // All arguments are merged since they arrive in a slice.
+ argelts := a.addOneNode(a.reflectValueObj.Type(), "rVCall.args", nil)
+ a.load(argelts, arg, 1, 1) // slice elements
+
+ a.addConstraint(&rVCallConstraint{
+ cgn: cgn,
+ targets: site.targets,
+ v: recv,
+ arg: argelts,
+ result: ret + 1, // results go into elements of ret
+ dotdotdot: dotdotdot,
+ })
+ return ret
+}
+
+func reflectCall(a *analysis, cgn *cgnode, dotdotdot bool) {
+ // This is the shared contour implementation of (reflect.Value).Call
+ // and CallSlice, as used by indirect calls (rare).
+ // Direct calls are inlined in gen.go, eliding the
+ // intermediate cgnode for Call.
+ site := new(callsite)
+ cgn.sites = append(cgn.sites, site)
+ recv := a.funcParams(cgn.obj)
+ arg := recv + 1
+ ret := reflectCallImpl(a, cgn, site, recv, arg, dotdotdot)
+ a.addressOf(cgn.fn.Signature.Results().At(0).Type(), a.funcResults(cgn.obj), ret)
+}
+
+func ext۰reflect۰Value۰Call(a *analysis, cgn *cgnode) {
+ reflectCall(a, cgn, false)
+}
+
+func ext۰reflect۰Value۰CallSlice(a *analysis, cgn *cgnode) {
+ // TODO(adonovan): implement. Also, inline direct calls in gen.go too.
+ if false {
+ reflectCall(a, cgn, true)
+ }
+}
+
+func ext۰reflect۰Value۰Convert(a *analysis, cgn *cgnode) {} // TODO(adonovan)
+
+// ---------- func (Value).Elem() Value ----------
+
+// result = v.Elem()
+type rVElemConstraint struct {
+ cgn *cgnode
+ v nodeid // (ptr)
+ result nodeid // (indirect)
+}
+
+func (c *rVElemConstraint) ptr() nodeid { return c.v }
+func (c *rVElemConstraint) presolve(h *hvn) {
+ h.markIndirect(onodeid(c.result), "rVElem.result")
+}
+func (c *rVElemConstraint) renumber(mapping []nodeid) {
+ c.v = mapping[c.v]
+ c.result = mapping[c.result]
+}
+
+func (c *rVElemConstraint) String() string {
+ return fmt.Sprintf("n%d = reflect n%d.Elem()", c.result, c.v)
+}
+
+func (c *rVElemConstraint) solve(a *analysis, delta *nodeset) {
+ changed := false
+ for _, x := range delta.AppendTo(a.deltaSpace) {
+ vObj := nodeid(x)
+ tDyn, payload, indirect := a.taggedValue(vObj)
+ if indirect {
+ // TODO(adonovan): we'll need to implement this
+ // when we start creating indirect tagged objects.
+ panic("indirect tagged object")
+ }
+
+ switch t := tDyn.Underlying().(type) {
+ case *types.Interface:
+ if a.onlineCopy(c.result, payload) {
+ changed = true
+ }
+
+ case *types.Pointer:
+ obj := a.makeTagged(t.Elem(), c.cgn, nil)
+ a.load(obj+1, payload, 0, a.sizeof(t.Elem()))
+ if a.addLabel(c.result, obj) {
+ changed = true
+ }
+ }
+ }
+ if changed {
+ a.addWork(c.result)
+ }
+}
+
+func ext۰reflect۰Value۰Elem(a *analysis, cgn *cgnode) {
+ a.addConstraint(&rVElemConstraint{
+ cgn: cgn,
+ v: a.funcParams(cgn.obj),
+ result: a.funcResults(cgn.obj),
+ })
+}
+
+func ext۰reflect۰Value۰Field(a *analysis, cgn *cgnode) {} // TODO(adonovan)
+func ext۰reflect۰Value۰FieldByIndex(a *analysis, cgn *cgnode) {} // TODO(adonovan)
+func ext۰reflect۰Value۰FieldByName(a *analysis, cgn *cgnode) {} // TODO(adonovan)
+func ext۰reflect۰Value۰FieldByNameFunc(a *analysis, cgn *cgnode) {} // TODO(adonovan)
+
+// ---------- func (Value).Index() Value ----------
+
+// result = v.Index()
+type rVIndexConstraint struct {
+ cgn *cgnode
+ v nodeid // (ptr)
+ result nodeid // (indirect)
+}
+
+func (c *rVIndexConstraint) ptr() nodeid { return c.v }
+func (c *rVIndexConstraint) presolve(h *hvn) {
+ h.markIndirect(onodeid(c.result), "rVIndex.result")
+}
+func (c *rVIndexConstraint) renumber(mapping []nodeid) {
+ c.v = mapping[c.v]
+ c.result = mapping[c.result]
+}
+
+func (c *rVIndexConstraint) String() string {
+ return fmt.Sprintf("n%d = reflect n%d.Index()", c.result, c.v)
+}
+
+func (c *rVIndexConstraint) solve(a *analysis, delta *nodeset) {
+ changed := false
+ for _, x := range delta.AppendTo(a.deltaSpace) {
+ vObj := nodeid(x)
+ tDyn, payload, indirect := a.taggedValue(vObj)
+ if indirect {
+ // TODO(adonovan): we'll need to implement this
+ // when we start creating indirect tagged objects.
+ panic("indirect tagged object")
+ }
+
+ var res nodeid
+ switch t := tDyn.Underlying().(type) {
+ case *types.Array:
+ res = a.makeTagged(t.Elem(), c.cgn, nil)
+ a.onlineCopyN(res+1, payload+1, a.sizeof(t.Elem()))
+
+ case *types.Slice:
+ res = a.makeTagged(t.Elem(), c.cgn, nil)
+ a.load(res+1, payload, 1, a.sizeof(t.Elem()))
+
+ case *types.Basic:
+ if t.Kind() == types.String {
+ res = a.makeTagged(types.Typ[types.Rune], c.cgn, nil)
+ }
+ }
+ if res != 0 && a.addLabel(c.result, res) {
+ changed = true
+ }
+ }
+ if changed {
+ a.addWork(c.result)
+ }
+}
+
+func ext۰reflect۰Value۰Index(a *analysis, cgn *cgnode) {
+ a.addConstraint(&rVIndexConstraint{
+ cgn: cgn,
+ v: a.funcParams(cgn.obj),
+ result: a.funcResults(cgn.obj),
+ })
+}
+
+// ---------- func (Value).Interface() Value ----------
+
+// result = v.Interface()
+type rVInterfaceConstraint struct {
+ v nodeid // (ptr)
+ result nodeid // (indirect)
+}
+
+func (c *rVInterfaceConstraint) ptr() nodeid { return c.v }
+func (c *rVInterfaceConstraint) presolve(h *hvn) {
+ h.markIndirect(onodeid(c.result), "rVInterface.result")
+}
+func (c *rVInterfaceConstraint) renumber(mapping []nodeid) {
+ c.v = mapping[c.v]
+ c.result = mapping[c.result]
+}
+
+func (c *rVInterfaceConstraint) String() string {
+ return fmt.Sprintf("n%d = reflect n%d.Interface()", c.result, c.v)
+}
+
+func (c *rVInterfaceConstraint) solve(a *analysis, delta *nodeset) {
+ changed := false
+ for _, x := range delta.AppendTo(a.deltaSpace) {
+ vObj := nodeid(x)
+ tDyn, payload, indirect := a.taggedValue(vObj)
+ if indirect {
+ // TODO(adonovan): we'll need to implement this
+ // when we start creating indirect tagged objects.
+ panic("indirect tagged object")
+ }
+
+ if isInterface(tDyn) {
+ if a.onlineCopy(c.result, payload) {
+ a.addWork(c.result)
+ }
+ } else {
+ if a.addLabel(c.result, vObj) {
+ changed = true
+ }
+ }
+ }
+ if changed {
+ a.addWork(c.result)
+ }
+}
+
+func ext۰reflect۰Value۰Interface(a *analysis, cgn *cgnode) {
+ a.addConstraint(&rVInterfaceConstraint{
+ v: a.funcParams(cgn.obj),
+ result: a.funcResults(cgn.obj),
+ })
+}
+
+// ---------- func (Value).MapIndex(Value) Value ----------
+
+// result = v.MapIndex(_)
+type rVMapIndexConstraint struct {
+ cgn *cgnode
+ v nodeid // (ptr)
+ result nodeid // (indirect)
+}
+
+func (c *rVMapIndexConstraint) ptr() nodeid { return c.v }
+func (c *rVMapIndexConstraint) presolve(h *hvn) {
+ h.markIndirect(onodeid(c.result), "rVMapIndex.result")
+}
+func (c *rVMapIndexConstraint) renumber(mapping []nodeid) {
+ c.v = mapping[c.v]
+ c.result = mapping[c.result]
+}
+
+func (c *rVMapIndexConstraint) String() string {
+ return fmt.Sprintf("n%d = reflect n%d.MapIndex(_)", c.result, c.v)
+}
+
+func (c *rVMapIndexConstraint) solve(a *analysis, delta *nodeset) {
+ changed := false
+ for _, x := range delta.AppendTo(a.deltaSpace) {
+ vObj := nodeid(x)
+ tDyn, m, indirect := a.taggedValue(vObj)
+ tMap, _ := tDyn.Underlying().(*types.Map)
+ if tMap == nil {
+ continue // not a map
+ }
+ if indirect {
+ // TODO(adonovan): we'll need to implement this
+ // when we start creating indirect tagged objects.
+ panic("indirect tagged object")
+ }
+
+ obj := a.makeTagged(tMap.Elem(), c.cgn, nil)
+ a.load(obj+1, m, a.sizeof(tMap.Key()), a.sizeof(tMap.Elem()))
+ if a.addLabel(c.result, obj) {
+ changed = true
+ }
+ }
+ if changed {
+ a.addWork(c.result)
+ }
+}
+
+func ext۰reflect۰Value۰MapIndex(a *analysis, cgn *cgnode) {
+ a.addConstraint(&rVMapIndexConstraint{
+ cgn: cgn,
+ v: a.funcParams(cgn.obj),
+ result: a.funcResults(cgn.obj),
+ })
+}
+
+// ---------- func (Value).MapKeys() []Value ----------
+
+// result = v.MapKeys()
+type rVMapKeysConstraint struct {
+ cgn *cgnode
+ v nodeid // (ptr)
+ result nodeid // (indirect)
+}
+
+func (c *rVMapKeysConstraint) ptr() nodeid { return c.v }
+func (c *rVMapKeysConstraint) presolve(h *hvn) {
+ h.markIndirect(onodeid(c.result), "rVMapKeys.result")
+}
+func (c *rVMapKeysConstraint) renumber(mapping []nodeid) {
+ c.v = mapping[c.v]
+ c.result = mapping[c.result]
+}
+
+func (c *rVMapKeysConstraint) String() string {
+ return fmt.Sprintf("n%d = reflect n%d.MapKeys()", c.result, c.v)
+}
+
+func (c *rVMapKeysConstraint) solve(a *analysis, delta *nodeset) {
+ changed := false
+ for _, x := range delta.AppendTo(a.deltaSpace) {
+ vObj := nodeid(x)
+ tDyn, m, indirect := a.taggedValue(vObj)
+ tMap, _ := tDyn.Underlying().(*types.Map)
+ if tMap == nil {
+ continue // not a map
+ }
+ if indirect {
+ // TODO(adonovan): we'll need to implement this
+ // when we start creating indirect tagged objects.
+ panic("indirect tagged object")
+ }
+
+ kObj := a.makeTagged(tMap.Key(), c.cgn, nil)
+ a.load(kObj+1, m, 0, a.sizeof(tMap.Key()))
+ if a.addLabel(c.result, kObj) {
+ changed = true
+ }
+ }
+ if changed {
+ a.addWork(c.result)
+ }
+}
+
+func ext۰reflect۰Value۰MapKeys(a *analysis, cgn *cgnode) {
+ // Allocate an array for the result.
+ obj := a.nextNode()
+ T := types.NewSlice(a.reflectValueObj.Type())
+ a.addNodes(sliceToArray(T), "reflect.MapKeys result")
+ a.endObject(obj, cgn, nil)
+ a.addressOf(T, a.funcResults(cgn.obj), obj)
+
+ a.addConstraint(&rVMapKeysConstraint{
+ cgn: cgn,
+ v: a.funcParams(cgn.obj),
+ result: obj + 1, // result is stored in array elems
+ })
+}
+
+func ext۰reflect۰Value۰Method(a *analysis, cgn *cgnode) {} // TODO(adonovan)
+func ext۰reflect۰Value۰MethodByName(a *analysis, cgn *cgnode) {} // TODO(adonovan)
+
+// ---------- func (Value).Recv(Value) Value ----------
+
+// result, _ = v.Recv()
+type rVRecvConstraint struct {
+ cgn *cgnode
+ v nodeid // (ptr)
+ result nodeid // (indirect)
+}
+
+func (c *rVRecvConstraint) ptr() nodeid { return c.v }
+func (c *rVRecvConstraint) presolve(h *hvn) {
+ h.markIndirect(onodeid(c.result), "rVRecv.result")
+}
+func (c *rVRecvConstraint) renumber(mapping []nodeid) {
+ c.v = mapping[c.v]
+ c.result = mapping[c.result]
+}
+
+func (c *rVRecvConstraint) String() string {
+ return fmt.Sprintf("n%d = reflect n%d.Recv()", c.result, c.v)
+}
+
+func (c *rVRecvConstraint) solve(a *analysis, delta *nodeset) {
+ changed := false
+ for _, x := range delta.AppendTo(a.deltaSpace) {
+ vObj := nodeid(x)
+ tDyn, ch, indirect := a.taggedValue(vObj)
+ tChan, _ := tDyn.Underlying().(*types.Chan)
+ if tChan == nil {
+ continue // not a channel
+ }
+ if indirect {
+ // TODO(adonovan): we'll need to implement this
+ // when we start creating indirect tagged objects.
+ panic("indirect tagged object")
+ }
+
+ tElem := tChan.Elem()
+ elemObj := a.makeTagged(tElem, c.cgn, nil)
+ a.load(elemObj+1, ch, 0, a.sizeof(tElem))
+ if a.addLabel(c.result, elemObj) {
+ changed = true
+ }
+ }
+ if changed {
+ a.addWork(c.result)
+ }
+}
+
+func ext۰reflect۰Value۰Recv(a *analysis, cgn *cgnode) {
+ a.addConstraint(&rVRecvConstraint{
+ cgn: cgn,
+ v: a.funcParams(cgn.obj),
+ result: a.funcResults(cgn.obj),
+ })
+}
+
+// ---------- func (Value).Send(Value) ----------
+
+// v.Send(x)
+type rVSendConstraint struct {
+ cgn *cgnode
+ v nodeid // (ptr)
+ x nodeid
+}
+
+func (c *rVSendConstraint) ptr() nodeid { return c.v }
+func (c *rVSendConstraint) presolve(*hvn) {}
+func (c *rVSendConstraint) renumber(mapping []nodeid) {
+ c.v = mapping[c.v]
+ c.x = mapping[c.x]
+}
+
+func (c *rVSendConstraint) String() string {
+ return fmt.Sprintf("reflect n%d.Send(n%d)", c.v, c.x)
+}
+
+func (c *rVSendConstraint) solve(a *analysis, delta *nodeset) {
+ for _, x := range delta.AppendTo(a.deltaSpace) {
+ vObj := nodeid(x)
+ tDyn, ch, indirect := a.taggedValue(vObj)
+ tChan, _ := tDyn.Underlying().(*types.Chan)
+ if tChan == nil {
+ continue // not a channel
+ }
+ if indirect {
+ // TODO(adonovan): we'll need to implement this
+ // when we start creating indirect tagged objects.
+ panic("indirect tagged object")
+ }
+
+ // Extract x's payload to xtmp, then store to channel.
+ tElem := tChan.Elem()
+ xtmp := a.addNodes(tElem, "Send.xtmp")
+ a.typeAssert(tElem, xtmp, c.x, false)
+ a.store(ch, xtmp, 0, a.sizeof(tElem))
+ }
+}
+
+func ext۰reflect۰Value۰Send(a *analysis, cgn *cgnode) {
+ params := a.funcParams(cgn.obj)
+ a.addConstraint(&rVSendConstraint{
+ cgn: cgn,
+ v: params,
+ x: params + 1,
+ })
+}
+
+func ext۰reflect۰Value۰Set(a *analysis, cgn *cgnode) {} // TODO(adonovan)
+
+// ---------- func (Value).SetBytes(x []byte) ----------
+
+// v.SetBytes(x)
+type rVSetBytesConstraint struct {
+ cgn *cgnode
+ v nodeid // (ptr)
+ x nodeid
+}
+
+func (c *rVSetBytesConstraint) ptr() nodeid { return c.v }
+func (c *rVSetBytesConstraint) presolve(*hvn) {}
+func (c *rVSetBytesConstraint) renumber(mapping []nodeid) {
+ c.v = mapping[c.v]
+ c.x = mapping[c.x]
+}
+
+func (c *rVSetBytesConstraint) String() string {
+ return fmt.Sprintf("reflect n%d.SetBytes(n%d)", c.v, c.x)
+}
+
+func (c *rVSetBytesConstraint) solve(a *analysis, delta *nodeset) {
+ for _, x := range delta.AppendTo(a.deltaSpace) {
+ vObj := nodeid(x)
+ tDyn, slice, indirect := a.taggedValue(vObj)
+ if indirect {
+ // TODO(adonovan): we'll need to implement this
+ // when we start creating indirect tagged objects.
+ panic("indirect tagged object")
+ }
+
+ tSlice, ok := tDyn.Underlying().(*types.Slice)
+ if ok && types.Identical(tSlice.Elem(), types.Typ[types.Uint8]) {
+ if a.onlineCopy(slice, c.x) {
+ a.addWork(slice)
+ }
+ }
+ }
+}
+
+func ext۰reflect۰Value۰SetBytes(a *analysis, cgn *cgnode) {
+ params := a.funcParams(cgn.obj)
+ a.addConstraint(&rVSetBytesConstraint{
+ cgn: cgn,
+ v: params,
+ x: params + 1,
+ })
+}
+
+// ---------- func (Value).SetMapIndex(k Value, v Value) ----------
+
+// v.SetMapIndex(key, val)
+type rVSetMapIndexConstraint struct {
+ cgn *cgnode
+ v nodeid // (ptr)
+ key nodeid
+ val nodeid
+}
+
+func (c *rVSetMapIndexConstraint) ptr() nodeid { return c.v }
+func (c *rVSetMapIndexConstraint) presolve(*hvn) {}
+func (c *rVSetMapIndexConstraint) renumber(mapping []nodeid) {
+ c.v = mapping[c.v]
+ c.key = mapping[c.key]
+ c.val = mapping[c.val]
+}
+
+func (c *rVSetMapIndexConstraint) String() string {
+ return fmt.Sprintf("reflect n%d.SetMapIndex(n%d, n%d)", c.v, c.key, c.val)
+}
+
+func (c *rVSetMapIndexConstraint) solve(a *analysis, delta *nodeset) {
+ for _, x := range delta.AppendTo(a.deltaSpace) {
+ vObj := nodeid(x)
+ tDyn, m, indirect := a.taggedValue(vObj)
+ tMap, _ := tDyn.Underlying().(*types.Map)
+ if tMap == nil {
+ continue // not a map
+ }
+ if indirect {
+ // TODO(adonovan): we'll need to implement this
+ // when we start creating indirect tagged objects.
+ panic("indirect tagged object")
+ }
+
+ keysize := a.sizeof(tMap.Key())
+
+ // Extract key's payload to keytmp, then store to map key.
+ keytmp := a.addNodes(tMap.Key(), "SetMapIndex.keytmp")
+ a.typeAssert(tMap.Key(), keytmp, c.key, false)
+ a.store(m, keytmp, 0, keysize)
+
+ // Extract val's payload to vtmp, then store to map value.
+ valtmp := a.addNodes(tMap.Elem(), "SetMapIndex.valtmp")
+ a.typeAssert(tMap.Elem(), valtmp, c.val, false)
+ a.store(m, valtmp, keysize, a.sizeof(tMap.Elem()))
+ }
+}
+
+func ext۰reflect۰Value۰SetMapIndex(a *analysis, cgn *cgnode) {
+ params := a.funcParams(cgn.obj)
+ a.addConstraint(&rVSetMapIndexConstraint{
+ cgn: cgn,
+ v: params,
+ key: params + 1,
+ val: params + 2,
+ })
+}
+
+func ext۰reflect۰Value۰SetPointer(a *analysis, cgn *cgnode) {} // TODO(adonovan)
+
+// ---------- func (Value).Slice(v Value, i, j int) Value ----------
+
+// result = v.Slice(_, _)
+type rVSliceConstraint struct {
+ cgn *cgnode
+ v nodeid // (ptr)
+ result nodeid // (indirect)
+}
+
+func (c *rVSliceConstraint) ptr() nodeid { return c.v }
+func (c *rVSliceConstraint) presolve(h *hvn) {
+ h.markIndirect(onodeid(c.result), "rVSlice.result")
+}
+func (c *rVSliceConstraint) renumber(mapping []nodeid) {
+ c.v = mapping[c.v]
+ c.result = mapping[c.result]
+}
+
+func (c *rVSliceConstraint) String() string {
+ return fmt.Sprintf("n%d = reflect n%d.Slice(_, _)", c.result, c.v)
+}
+
+func (c *rVSliceConstraint) solve(a *analysis, delta *nodeset) {
+ changed := false
+ for _, x := range delta.AppendTo(a.deltaSpace) {
+ vObj := nodeid(x)
+ tDyn, payload, indirect := a.taggedValue(vObj)
+ if indirect {
+ // TODO(adonovan): we'll need to implement this
+ // when we start creating indirect tagged objects.
+ panic("indirect tagged object")
+ }
+
+ var res nodeid
+ switch t := tDyn.Underlying().(type) {
+ case *types.Pointer:
+ if tArr, ok := t.Elem().Underlying().(*types.Array); ok {
+ // pointer to array
+ res = a.makeTagged(types.NewSlice(tArr.Elem()), c.cgn, nil)
+ if a.onlineCopy(res+1, payload) {
+ a.addWork(res + 1)
+ }
+ }
+
+ case *types.Array:
+ // TODO(adonovan): implement addressable
+ // arrays when we do indirect tagged objects.
+
+ case *types.Slice:
+ res = vObj
+
+ case *types.Basic:
+ if t == types.Typ[types.String] {
+ res = vObj
+ }
+ }
+
+ if res != 0 && a.addLabel(c.result, res) {
+ changed = true
+ }
+ }
+ if changed {
+ a.addWork(c.result)
+ }
+}
+
+func ext۰reflect۰Value۰Slice(a *analysis, cgn *cgnode) {
+ a.addConstraint(&rVSliceConstraint{
+ cgn: cgn,
+ v: a.funcParams(cgn.obj),
+ result: a.funcResults(cgn.obj),
+ })
+}
+
+// -------------------- Standalone reflect functions --------------------
+
+func ext۰reflect۰Append(a *analysis, cgn *cgnode) {} // TODO(adonovan)
+func ext۰reflect۰AppendSlice(a *analysis, cgn *cgnode) {} // TODO(adonovan)
+func ext۰reflect۰Copy(a *analysis, cgn *cgnode) {} // TODO(adonovan)
+
+// ---------- func ChanOf(ChanDir, Type) Type ----------
+
+// result = ChanOf(dir, t)
+type reflectChanOfConstraint struct {
+ cgn *cgnode
+ t nodeid // (ptr)
+ result nodeid // (indirect)
+ dirs []types.ChanDir
+}
+
+func (c *reflectChanOfConstraint) ptr() nodeid { return c.t }
+func (c *reflectChanOfConstraint) presolve(h *hvn) {
+ h.markIndirect(onodeid(c.result), "reflectChanOf.result")
+}
+func (c *reflectChanOfConstraint) renumber(mapping []nodeid) {
+ c.t = mapping[c.t]
+ c.result = mapping[c.result]
+}
+
+func (c *reflectChanOfConstraint) String() string {
+ return fmt.Sprintf("n%d = reflect.ChanOf(n%d)", c.result, c.t)
+}
+
+func (c *reflectChanOfConstraint) solve(a *analysis, delta *nodeset) {
+ changed := false
+ for _, x := range delta.AppendTo(a.deltaSpace) {
+ tObj := nodeid(x)
+ T := a.rtypeTaggedValue(tObj)
+
+ if typeTooHigh(T) {
+ continue
+ }
+
+ for _, dir := range c.dirs {
+ if a.addLabel(c.result, a.makeRtype(types.NewChan(dir, T))) {
+ changed = true
+ }
+ }
+ }
+ if changed {
+ a.addWork(c.result)
+ }
+}
+
+// dirMap maps reflect.ChanDir to the set of channel types generated by ChanOf.
+var dirMap = [...][]types.ChanDir{
+ 0: {types.SendOnly, types.RecvOnly, types.SendRecv}, // unknown
+ reflect.RecvDir: {types.RecvOnly},
+ reflect.SendDir: {types.SendOnly},
+ reflect.BothDir: {types.SendRecv},
+}
+
+func ext۰reflect۰ChanOf(a *analysis, cgn *cgnode) {
+ // If we have access to the callsite,
+ // and the channel argument is a constant (as is usual),
+ // only generate the requested direction.
+ var dir reflect.ChanDir // unknown
+ if site := cgn.callersite; site != nil {
+ if c, ok := site.instr.Common().Args[0].(*ssa.Const); ok {
+ v, _ := exact.Int64Val(c.Value)
+ if 0 <= v && v <= int64(reflect.BothDir) {
+ dir = reflect.ChanDir(v)
+ }
+ }
+ }
+
+ params := a.funcParams(cgn.obj)
+ a.addConstraint(&reflectChanOfConstraint{
+ cgn: cgn,
+ t: params + 1,
+ result: a.funcResults(cgn.obj),
+ dirs: dirMap[dir],
+ })
+}
+
+// ---------- func Indirect(v Value) Value ----------
+
+// result = Indirect(v)
+type reflectIndirectConstraint struct {
+ cgn *cgnode
+ v nodeid // (ptr)
+ result nodeid // (indirect)
+}
+
+func (c *reflectIndirectConstraint) ptr() nodeid { return c.v }
+func (c *reflectIndirectConstraint) presolve(h *hvn) {
+ h.markIndirect(onodeid(c.result), "reflectIndirect.result")
+}
+func (c *reflectIndirectConstraint) renumber(mapping []nodeid) {
+ c.v = mapping[c.v]
+ c.result = mapping[c.result]
+}
+
+func (c *reflectIndirectConstraint) String() string {
+ return fmt.Sprintf("n%d = reflect.Indirect(n%d)", c.result, c.v)
+}
+
+func (c *reflectIndirectConstraint) solve(a *analysis, delta *nodeset) {
+ changed := false
+ for _, x := range delta.AppendTo(a.deltaSpace) {
+ vObj := nodeid(x)
+ tDyn, _, _ := a.taggedValue(vObj)
+ var res nodeid
+ if tPtr, ok := tDyn.Underlying().(*types.Pointer); ok {
+ // load the payload of the pointer's tagged object
+ // into a new tagged object
+ res = a.makeTagged(tPtr.Elem(), c.cgn, nil)
+ a.load(res+1, vObj+1, 0, a.sizeof(tPtr.Elem()))
+ } else {
+ res = vObj
+ }
+
+ if a.addLabel(c.result, res) {
+ changed = true
+ }
+ }
+ if changed {
+ a.addWork(c.result)
+ }
+}
+
+func ext۰reflect۰Indirect(a *analysis, cgn *cgnode) {
+ a.addConstraint(&reflectIndirectConstraint{
+ cgn: cgn,
+ v: a.funcParams(cgn.obj),
+ result: a.funcResults(cgn.obj),
+ })
+}
+
+// ---------- func MakeChan(Type) Value ----------
+
+// result = MakeChan(typ)
+type reflectMakeChanConstraint struct {
+ cgn *cgnode
+ typ nodeid // (ptr)
+ result nodeid // (indirect)
+}
+
+func (c *reflectMakeChanConstraint) ptr() nodeid { return c.typ }
+func (c *reflectMakeChanConstraint) presolve(h *hvn) {
+ h.markIndirect(onodeid(c.result), "reflectMakeChan.result")
+}
+func (c *reflectMakeChanConstraint) renumber(mapping []nodeid) {
+ c.typ = mapping[c.typ]
+ c.result = mapping[c.result]
+}
+
+func (c *reflectMakeChanConstraint) String() string {
+ return fmt.Sprintf("n%d = reflect.MakeChan(n%d)", c.result, c.typ)
+}
+
+func (c *reflectMakeChanConstraint) solve(a *analysis, delta *nodeset) {
+ changed := false
+ for _, x := range delta.AppendTo(a.deltaSpace) {
+ typObj := nodeid(x)
+ T := a.rtypeTaggedValue(typObj)
+ tChan, ok := T.Underlying().(*types.Chan)
+ if !ok || tChan.Dir() != types.SendRecv {
+ continue // not a bidirectional channel type
+ }
+
+ obj := a.nextNode()
+ a.addNodes(tChan.Elem(), "reflect.MakeChan.value")
+ a.endObject(obj, c.cgn, nil)
+
+ // put its address in a new T-tagged object
+ id := a.makeTagged(T, c.cgn, nil)
+ a.addLabel(id+1, obj)
+
+ // flow the T-tagged object to the result
+ if a.addLabel(c.result, id) {
+ changed = true
+ }
+ }
+ if changed {
+ a.addWork(c.result)
+ }
+}
+
+func ext۰reflect۰MakeChan(a *analysis, cgn *cgnode) {
+ a.addConstraint(&reflectMakeChanConstraint{
+ cgn: cgn,
+ typ: a.funcParams(cgn.obj),
+ result: a.funcResults(cgn.obj),
+ })
+}
+
+func ext۰reflect۰MakeFunc(a *analysis, cgn *cgnode) {} // TODO(adonovan)
+
+// ---------- func MakeMap(Type) Value ----------
+
+// result = MakeMap(typ)
+type reflectMakeMapConstraint struct {
+ cgn *cgnode
+ typ nodeid // (ptr)
+ result nodeid // (indirect)
+}
+
+func (c *reflectMakeMapConstraint) ptr() nodeid { return c.typ }
+func (c *reflectMakeMapConstraint) presolve(h *hvn) {
+ h.markIndirect(onodeid(c.result), "reflectMakeMap.result")
+}
+func (c *reflectMakeMapConstraint) renumber(mapping []nodeid) {
+ c.typ = mapping[c.typ]
+ c.result = mapping[c.result]
+}
+
+func (c *reflectMakeMapConstraint) String() string {
+ return fmt.Sprintf("n%d = reflect.MakeMap(n%d)", c.result, c.typ)
+}
+
+func (c *reflectMakeMapConstraint) solve(a *analysis, delta *nodeset) {
+ changed := false
+ for _, x := range delta.AppendTo(a.deltaSpace) {
+ typObj := nodeid(x)
+ T := a.rtypeTaggedValue(typObj)
+ tMap, ok := T.Underlying().(*types.Map)
+ if !ok {
+ continue // not a map type
+ }
+
+ mapObj := a.nextNode()
+ a.addNodes(tMap.Key(), "reflect.MakeMap.key")
+ a.addNodes(tMap.Elem(), "reflect.MakeMap.value")
+ a.endObject(mapObj, c.cgn, nil)
+
+ // put its address in a new T-tagged object
+ id := a.makeTagged(T, c.cgn, nil)
+ a.addLabel(id+1, mapObj)
+
+ // flow the T-tagged object to the result
+ if a.addLabel(c.result, id) {
+ changed = true
+ }
+ }
+ if changed {
+ a.addWork(c.result)
+ }
+}
+
+func ext۰reflect۰MakeMap(a *analysis, cgn *cgnode) {
+ a.addConstraint(&reflectMakeMapConstraint{
+ cgn: cgn,
+ typ: a.funcParams(cgn.obj),
+ result: a.funcResults(cgn.obj),
+ })
+}
+
+// ---------- func MakeSlice(Type) Value ----------
+
+// result = MakeSlice(typ)
+type reflectMakeSliceConstraint struct {
+ cgn *cgnode
+ typ nodeid // (ptr)
+ result nodeid // (indirect)
+}
+
+func (c *reflectMakeSliceConstraint) ptr() nodeid { return c.typ }
+func (c *reflectMakeSliceConstraint) presolve(h *hvn) {
+ h.markIndirect(onodeid(c.result), "reflectMakeSlice.result")
+}
+func (c *reflectMakeSliceConstraint) renumber(mapping []nodeid) {
+ c.typ = mapping[c.typ]
+ c.result = mapping[c.result]
+}
+
+func (c *reflectMakeSliceConstraint) String() string {
+ return fmt.Sprintf("n%d = reflect.MakeSlice(n%d)", c.result, c.typ)
+}
+
+func (c *reflectMakeSliceConstraint) solve(a *analysis, delta *nodeset) {
+ changed := false
+ for _, x := range delta.AppendTo(a.deltaSpace) {
+ typObj := nodeid(x)
+ T := a.rtypeTaggedValue(typObj)
+ if _, ok := T.Underlying().(*types.Slice); !ok {
+ continue // not a slice type
+ }
+
+ obj := a.nextNode()
+ a.addNodes(sliceToArray(T), "reflect.MakeSlice")
+ a.endObject(obj, c.cgn, nil)
+
+ // put its address in a new T-tagged object
+ id := a.makeTagged(T, c.cgn, nil)
+ a.addLabel(id+1, obj)
+
+ // flow the T-tagged object to the result
+ if a.addLabel(c.result, id) {
+ changed = true
+ }
+ }
+ if changed {
+ a.addWork(c.result)
+ }
+}
+
+func ext۰reflect۰MakeSlice(a *analysis, cgn *cgnode) {
+ a.addConstraint(&reflectMakeSliceConstraint{
+ cgn: cgn,
+ typ: a.funcParams(cgn.obj),
+ result: a.funcResults(cgn.obj),
+ })
+}
+
+func ext۰reflect۰MapOf(a *analysis, cgn *cgnode) {} // TODO(adonovan)
+
+// ---------- func New(Type) Value ----------
+
+// result = New(typ)
+type reflectNewConstraint struct {
+ cgn *cgnode
+ typ nodeid // (ptr)
+ result nodeid // (indirect)
+}
+
+func (c *reflectNewConstraint) ptr() nodeid { return c.typ }
+func (c *reflectNewConstraint) presolve(h *hvn) {
+ h.markIndirect(onodeid(c.result), "reflectNew.result")
+}
+func (c *reflectNewConstraint) renumber(mapping []nodeid) {
+ c.typ = mapping[c.typ]
+ c.result = mapping[c.result]
+}
+
+func (c *reflectNewConstraint) String() string {
+ return fmt.Sprintf("n%d = reflect.New(n%d)", c.result, c.typ)
+}
+
+func (c *reflectNewConstraint) solve(a *analysis, delta *nodeset) {
+ changed := false
+ for _, x := range delta.AppendTo(a.deltaSpace) {
+ typObj := nodeid(x)
+ T := a.rtypeTaggedValue(typObj)
+
+ // allocate new T object
+ newObj := a.nextNode()
+ a.addNodes(T, "reflect.New")
+ a.endObject(newObj, c.cgn, nil)
+
+ // put its address in a new *T-tagged object
+ id := a.makeTagged(types.NewPointer(T), c.cgn, nil)
+ a.addLabel(id+1, newObj)
+
+ // flow the pointer to the result
+ if a.addLabel(c.result, id) {
+ changed = true
+ }
+ }
+ if changed {
+ a.addWork(c.result)
+ }
+}
+
+func ext۰reflect۰New(a *analysis, cgn *cgnode) {
+ a.addConstraint(&reflectNewConstraint{
+ cgn: cgn,
+ typ: a.funcParams(cgn.obj),
+ result: a.funcResults(cgn.obj),
+ })
+}
+
+func ext۰reflect۰NewAt(a *analysis, cgn *cgnode) {
+ ext۰reflect۰New(a, cgn)
+
+ // TODO(adonovan): also report dynamic calls to unsound intrinsics.
+ if site := cgn.callersite; site != nil {
+ a.warnf(site.pos(), "unsound: %s contains a reflect.NewAt() call", site.instr.Parent())
+ }
+}
+
+// ---------- func PtrTo(Type) Type ----------
+
+// result = PtrTo(t)
+type reflectPtrToConstraint struct {
+ cgn *cgnode
+ t nodeid // (ptr)
+ result nodeid // (indirect)
+}
+
+func (c *reflectPtrToConstraint) ptr() nodeid { return c.t }
+func (c *reflectPtrToConstraint) presolve(h *hvn) {
+ h.markIndirect(onodeid(c.result), "reflectPtrTo.result")
+}
+func (c *reflectPtrToConstraint) renumber(mapping []nodeid) {
+ c.t = mapping[c.t]
+ c.result = mapping[c.result]
+}
+
+func (c *reflectPtrToConstraint) String() string {
+ return fmt.Sprintf("n%d = reflect.PtrTo(n%d)", c.result, c.t)
+}
+
+func (c *reflectPtrToConstraint) solve(a *analysis, delta *nodeset) {
+ changed := false
+ for _, x := range delta.AppendTo(a.deltaSpace) {
+ tObj := nodeid(x)
+ T := a.rtypeTaggedValue(tObj)
+
+ if typeTooHigh(T) {
+ continue
+ }
+
+ if a.addLabel(c.result, a.makeRtype(types.NewPointer(T))) {
+ changed = true
+ }
+ }
+ if changed {
+ a.addWork(c.result)
+ }
+}
+
+func ext۰reflect۰PtrTo(a *analysis, cgn *cgnode) {
+ a.addConstraint(&reflectPtrToConstraint{
+ cgn: cgn,
+ t: a.funcParams(cgn.obj),
+ result: a.funcResults(cgn.obj),
+ })
+}
+
+func ext۰reflect۰Select(a *analysis, cgn *cgnode) {} // TODO(adonovan)
+
+// ---------- func SliceOf(Type) Type ----------
+
+// result = SliceOf(t)
+type reflectSliceOfConstraint struct {
+ cgn *cgnode
+ t nodeid // (ptr)
+ result nodeid // (indirect)
+}
+
+func (c *reflectSliceOfConstraint) ptr() nodeid { return c.t }
+func (c *reflectSliceOfConstraint) presolve(h *hvn) {
+ h.markIndirect(onodeid(c.result), "reflectSliceOf.result")
+}
+func (c *reflectSliceOfConstraint) renumber(mapping []nodeid) {
+ c.t = mapping[c.t]
+ c.result = mapping[c.result]
+}
+
+func (c *reflectSliceOfConstraint) String() string {
+ return fmt.Sprintf("n%d = reflect.SliceOf(n%d)", c.result, c.t)
+}
+
+func (c *reflectSliceOfConstraint) solve(a *analysis, delta *nodeset) {
+ changed := false
+ for _, x := range delta.AppendTo(a.deltaSpace) {
+ tObj := nodeid(x)
+ T := a.rtypeTaggedValue(tObj)
+
+ if typeTooHigh(T) {
+ continue
+ }
+
+ if a.addLabel(c.result, a.makeRtype(types.NewSlice(T))) {
+ changed = true
+ }
+ }
+ if changed {
+ a.addWork(c.result)
+ }
+}
+
+func ext۰reflect۰SliceOf(a *analysis, cgn *cgnode) {
+ a.addConstraint(&reflectSliceOfConstraint{
+ cgn: cgn,
+ t: a.funcParams(cgn.obj),
+ result: a.funcResults(cgn.obj),
+ })
+}
+
+// ---------- func TypeOf(v Value) Type ----------
+
+// result = TypeOf(i)
+type reflectTypeOfConstraint struct {
+ cgn *cgnode
+ i nodeid // (ptr)
+ result nodeid // (indirect)
+}
+
+func (c *reflectTypeOfConstraint) ptr() nodeid { return c.i }
+func (c *reflectTypeOfConstraint) presolve(h *hvn) {
+ h.markIndirect(onodeid(c.result), "reflectTypeOf.result")
+}
+func (c *reflectTypeOfConstraint) renumber(mapping []nodeid) {
+ c.i = mapping[c.i]
+ c.result = mapping[c.result]
+}
+
+func (c *reflectTypeOfConstraint) String() string {
+ return fmt.Sprintf("n%d = reflect.TypeOf(n%d)", c.result, c.i)
+}
+
+func (c *reflectTypeOfConstraint) solve(a *analysis, delta *nodeset) {
+ changed := false
+ for _, x := range delta.AppendTo(a.deltaSpace) {
+ iObj := nodeid(x)
+ tDyn, _, _ := a.taggedValue(iObj)
+ if a.addLabel(c.result, a.makeRtype(tDyn)) {
+ changed = true
+ }
+ }
+ if changed {
+ a.addWork(c.result)
+ }
+}
+
+func ext۰reflect۰TypeOf(a *analysis, cgn *cgnode) {
+ a.addConstraint(&reflectTypeOfConstraint{
+ cgn: cgn,
+ i: a.funcParams(cgn.obj),
+ result: a.funcResults(cgn.obj),
+ })
+}
+
+// ---------- func ValueOf(interface{}) Value ----------
+
+func ext۰reflect۰ValueOf(a *analysis, cgn *cgnode) {
+ // TODO(adonovan): when we start creating indirect tagged
+ // objects, we'll need to handle them specially here since
+ // they must never appear in the PTS of an interface{}.
+ a.copy(a.funcResults(cgn.obj), a.funcParams(cgn.obj), 1)
+}
+
+// ---------- func Zero(Type) Value ----------
+
+// result = Zero(typ)
+type reflectZeroConstraint struct {
+ cgn *cgnode
+ typ nodeid // (ptr)
+ result nodeid // (indirect)
+}
+
+func (c *reflectZeroConstraint) ptr() nodeid { return c.typ }
+func (c *reflectZeroConstraint) presolve(h *hvn) {
+ h.markIndirect(onodeid(c.result), "reflectZero.result")
+}
+func (c *reflectZeroConstraint) renumber(mapping []nodeid) {
+ c.typ = mapping[c.typ]
+ c.result = mapping[c.result]
+}
+
+func (c *reflectZeroConstraint) String() string {
+ return fmt.Sprintf("n%d = reflect.Zero(n%d)", c.result, c.typ)
+}
+
+func (c *reflectZeroConstraint) solve(a *analysis, delta *nodeset) {
+ changed := false
+ for _, x := range delta.AppendTo(a.deltaSpace) {
+ typObj := nodeid(x)
+ T := a.rtypeTaggedValue(typObj)
+
+ // TODO(adonovan): if T is an interface type, we need
+ // to create an indirect tagged object containing
+ // new(T). To avoid updates of such shared values,
+ // we'll need another flag on indirect tagged objects
+ // that marks whether they are addressable or
+ // readonly, just like the reflect package does.
+
+ // memoize using a.reflectZeros[T]
+ var id nodeid
+ if z := a.reflectZeros.At(T); false && z != nil {
+ id = z.(nodeid)
+ } else {
+ id = a.makeTagged(T, c.cgn, nil)
+ a.reflectZeros.Set(T, id)
+ }
+ if a.addLabel(c.result, id) {
+ changed = true
+ }
+ }
+ if changed {
+ a.addWork(c.result)
+ }
+}
+
+func ext۰reflect۰Zero(a *analysis, cgn *cgnode) {
+ a.addConstraint(&reflectZeroConstraint{
+ cgn: cgn,
+ typ: a.funcParams(cgn.obj),
+ result: a.funcResults(cgn.obj),
+ })
+}
+
+// -------------------- (*reflect.rtype) methods --------------------
+
+// ---------- func (*rtype) Elem() Type ----------
+
+// result = Elem(t)
+type rtypeElemConstraint struct {
+ cgn *cgnode
+ t nodeid // (ptr)
+ result nodeid // (indirect)
+}
+
+func (c *rtypeElemConstraint) ptr() nodeid { return c.t }
+func (c *rtypeElemConstraint) presolve(h *hvn) {
+ h.markIndirect(onodeid(c.result), "rtypeElem.result")
+}
+func (c *rtypeElemConstraint) renumber(mapping []nodeid) {
+ c.t = mapping[c.t]
+ c.result = mapping[c.result]
+}
+
+func (c *rtypeElemConstraint) String() string {
+ return fmt.Sprintf("n%d = (*reflect.rtype).Elem(n%d)", c.result, c.t)
+}
+
+func (c *rtypeElemConstraint) solve(a *analysis, delta *nodeset) {
+ // Implemented by *types.{Map,Chan,Array,Slice,Pointer}.
+ type hasElem interface {
+ Elem() types.Type
+ }
+ changed := false
+ for _, x := range delta.AppendTo(a.deltaSpace) {
+ tObj := nodeid(x)
+ T := a.nodes[tObj].obj.data.(types.Type)
+ if tHasElem, ok := T.Underlying().(hasElem); ok {
+ if a.addLabel(c.result, a.makeRtype(tHasElem.Elem())) {
+ changed = true
+ }
+ }
+ }
+ if changed {
+ a.addWork(c.result)
+ }
+}
+
+func ext۰reflect۰rtype۰Elem(a *analysis, cgn *cgnode) {
+ a.addConstraint(&rtypeElemConstraint{
+ cgn: cgn,
+ t: a.funcParams(cgn.obj),
+ result: a.funcResults(cgn.obj),
+ })
+}
+
+// ---------- func (*rtype) Field(int) StructField ----------
+// ---------- func (*rtype) FieldByName(string) (StructField, bool) ----------
+
+// result = FieldByName(t, name)
+// result = Field(t, _)
+type rtypeFieldByNameConstraint struct {
+ cgn *cgnode
+ name string // name of field; "" for unknown
+ t nodeid // (ptr)
+ result nodeid // (indirect)
+}
+
+func (c *rtypeFieldByNameConstraint) ptr() nodeid { return c.t }
+func (c *rtypeFieldByNameConstraint) presolve(h *hvn) {
+ h.markIndirect(onodeid(c.result+3), "rtypeFieldByName.result.Type")
+}
+func (c *rtypeFieldByNameConstraint) renumber(mapping []nodeid) {
+ c.t = mapping[c.t]
+ c.result = mapping[c.result]
+}
+
+func (c *rtypeFieldByNameConstraint) String() string {
+ return fmt.Sprintf("n%d = (*reflect.rtype).FieldByName(n%d, %q)", c.result, c.t, c.name)
+}
+
+func (c *rtypeFieldByNameConstraint) solve(a *analysis, delta *nodeset) {
+ // type StructField struct {
+ // 0 __identity__
+ // 1 Name string
+ // 2 PkgPath string
+ // 3 Type Type
+ // 4 Tag StructTag
+ // 5 Offset uintptr
+ // 6 Index []int
+ // 7 Anonymous bool
+ // }
+
+ for _, x := range delta.AppendTo(a.deltaSpace) {
+ tObj := nodeid(x)
+ T := a.nodes[tObj].obj.data.(types.Type)
+ tStruct, ok := T.Underlying().(*types.Struct)
+ if !ok {
+ continue // not a struct type
+ }
+
+ n := tStruct.NumFields()
+ for i := 0; i < n; i++ {
+ f := tStruct.Field(i)
+ if c.name == "" || c.name == f.Name() {
+
+ // a.offsetOf(Type) is 3.
+ if id := c.result + 3; a.addLabel(id, a.makeRtype(f.Type())) {
+ a.addWork(id)
+ }
+ // TODO(adonovan): StructField.Index should be non-nil.
+ }
+ }
+ }
+}
+
+func ext۰reflect۰rtype۰FieldByName(a *analysis, cgn *cgnode) {
+ // If we have access to the callsite,
+ // and the argument is a string constant,
+ // return only that field.
+ var name string
+ if site := cgn.callersite; site != nil {
+ if c, ok := site.instr.Common().Args[0].(*ssa.Const); ok {
+ name = exact.StringVal(c.Value)
+ }
+ }
+
+ a.addConstraint(&rtypeFieldByNameConstraint{
+ cgn: cgn,
+ name: name,
+ t: a.funcParams(cgn.obj),
+ result: a.funcResults(cgn.obj),
+ })
+}
+
+func ext۰reflect۰rtype۰Field(a *analysis, cgn *cgnode) {
+ // No-one ever calls Field with a constant argument,
+ // so we don't specialize that case.
+ a.addConstraint(&rtypeFieldByNameConstraint{
+ cgn: cgn,
+ t: a.funcParams(cgn.obj),
+ result: a.funcResults(cgn.obj),
+ })
+}
+
+func ext۰reflect۰rtype۰FieldByIndex(a *analysis, cgn *cgnode) {} // TODO(adonovan)
+func ext۰reflect۰rtype۰FieldByNameFunc(a *analysis, cgn *cgnode) {} // TODO(adonovan)
+
+// ---------- func (*rtype) In/Out(i int) Type ----------
+
+// result = In/Out(t, i)
+type rtypeInOutConstraint struct {
+ cgn *cgnode
+ t nodeid // (ptr)
+ result nodeid // (indirect)
+ out bool
+ i int // -ve if not a constant
+}
+
+func (c *rtypeInOutConstraint) ptr() nodeid { return c.t }
+func (c *rtypeInOutConstraint) presolve(h *hvn) {
+ h.markIndirect(onodeid(c.result), "rtypeInOut.result")
+}
+func (c *rtypeInOutConstraint) renumber(mapping []nodeid) {
+ c.t = mapping[c.t]
+ c.result = mapping[c.result]
+}
+
+func (c *rtypeInOutConstraint) String() string {
+ return fmt.Sprintf("n%d = (*reflect.rtype).InOut(n%d, %d)", c.result, c.t, c.i)
+}
+
+func (c *rtypeInOutConstraint) solve(a *analysis, delta *nodeset) {
+ changed := false
+ for _, x := range delta.AppendTo(a.deltaSpace) {
+ tObj := nodeid(x)
+ T := a.nodes[tObj].obj.data.(types.Type)
+ sig, ok := T.Underlying().(*types.Signature)
+ if !ok {
+ continue // not a func type
+ }
+
+ tuple := sig.Params()
+ if c.out {
+ tuple = sig.Results()
+ }
+ for i, n := 0, tuple.Len(); i < n; i++ {
+ if c.i < 0 || c.i == i {
+ if a.addLabel(c.result, a.makeRtype(tuple.At(i).Type())) {
+ changed = true
+ }
+ }
+ }
+ }
+ if changed {
+ a.addWork(c.result)
+ }
+}
+
+func ext۰reflect۰rtype۰InOut(a *analysis, cgn *cgnode, out bool) {
+ // If we have access to the callsite,
+ // and the argument is an int constant,
+ // return only that parameter.
+ index := -1
+ if site := cgn.callersite; site != nil {
+ if c, ok := site.instr.Common().Args[0].(*ssa.Const); ok {
+ v, _ := exact.Int64Val(c.Value)
+ index = int(v)
+ }
+ }
+ a.addConstraint(&rtypeInOutConstraint{
+ cgn: cgn,
+ t: a.funcParams(cgn.obj),
+ result: a.funcResults(cgn.obj),
+ out: out,
+ i: index,
+ })
+}
+
+func ext۰reflect۰rtype۰In(a *analysis, cgn *cgnode) {
+ ext۰reflect۰rtype۰InOut(a, cgn, false)
+}
+
+func ext۰reflect۰rtype۰Out(a *analysis, cgn *cgnode) {
+ ext۰reflect۰rtype۰InOut(a, cgn, true)
+}
+
+// ---------- func (*rtype) Key() Type ----------
+
+// result = Key(t)
+type rtypeKeyConstraint struct {
+ cgn *cgnode
+ t nodeid // (ptr)
+ result nodeid // (indirect)
+}
+
+func (c *rtypeKeyConstraint) ptr() nodeid { return c.t }
+func (c *rtypeKeyConstraint) presolve(h *hvn) {
+ h.markIndirect(onodeid(c.result), "rtypeKey.result")
+}
+func (c *rtypeKeyConstraint) renumber(mapping []nodeid) {
+ c.t = mapping[c.t]
+ c.result = mapping[c.result]
+}
+
+func (c *rtypeKeyConstraint) String() string {
+ return fmt.Sprintf("n%d = (*reflect.rtype).Key(n%d)", c.result, c.t)
+}
+
+func (c *rtypeKeyConstraint) solve(a *analysis, delta *nodeset) {
+ changed := false
+ for _, x := range delta.AppendTo(a.deltaSpace) {
+ tObj := nodeid(x)
+ T := a.nodes[tObj].obj.data.(types.Type)
+ if tMap, ok := T.Underlying().(*types.Map); ok {
+ if a.addLabel(c.result, a.makeRtype(tMap.Key())) {
+ changed = true
+ }
+ }
+ }
+ if changed {
+ a.addWork(c.result)
+ }
+}
+
+func ext۰reflect۰rtype۰Key(a *analysis, cgn *cgnode) {
+ a.addConstraint(&rtypeKeyConstraint{
+ cgn: cgn,
+ t: a.funcParams(cgn.obj),
+ result: a.funcResults(cgn.obj),
+ })
+}
+
+// ---------- func (*rtype) Method(int) (Method, bool) ----------
+// ---------- func (*rtype) MethodByName(string) (Method, bool) ----------
+
+// result = MethodByName(t, name)
+// result = Method(t, _)
+type rtypeMethodByNameConstraint struct {
+ cgn *cgnode
+ name string // name of method; "" for unknown
+ t nodeid // (ptr)
+ result nodeid // (indirect)
+}
+
+func (c *rtypeMethodByNameConstraint) ptr() nodeid { return c.t }
+func (c *rtypeMethodByNameConstraint) presolve(h *hvn) {
+ h.markIndirect(onodeid(c.result+3), "rtypeMethodByName.result.Type")
+ h.markIndirect(onodeid(c.result+4), "rtypeMethodByName.result.Func")
+}
+func (c *rtypeMethodByNameConstraint) renumber(mapping []nodeid) {
+ c.t = mapping[c.t]
+ c.result = mapping[c.result]
+}
+
+func (c *rtypeMethodByNameConstraint) String() string {
+ return fmt.Sprintf("n%d = (*reflect.rtype).MethodByName(n%d, %q)", c.result, c.t, c.name)
+}
+
+// changeRecv returns sig with Recv prepended to Params().
+func changeRecv(sig *types.Signature) *types.Signature {
+ params := sig.Params()
+ n := params.Len()
+ p2 := make([]*types.Var, n+1)
+ p2[0] = sig.Recv()
+ for i := 0; i < n; i++ {
+ p2[i+1] = params.At(i)
+ }
+ return types.NewSignature(nil, types.NewTuple(p2...), sig.Results(), sig.Variadic())
+}
+
+func (c *rtypeMethodByNameConstraint) solve(a *analysis, delta *nodeset) {
+ for _, x := range delta.AppendTo(a.deltaSpace) {
+ tObj := nodeid(x)
+ T := a.nodes[tObj].obj.data.(types.Type)
+
+ isIface := isInterface(T)
+
+ // We don't use Lookup(c.name) when c.name != "" to avoid
+ // ambiguity: >1 unexported methods could match.
+ mset := a.prog.MethodSets.MethodSet(T)
+ for i, n := 0, mset.Len(); i < n; i++ {
+ sel := mset.At(i)
+ if c.name == "" || c.name == sel.Obj().Name() {
+ // type Method struct {
+ // 0 __identity__
+ // 1 Name string
+ // 2 PkgPath string
+ // 3 Type Type
+ // 4 Func Value
+ // 5 Index int
+ // }
+
+ var sig *types.Signature
+ var fn *ssa.Function
+ if isIface {
+ sig = sel.Type().(*types.Signature)
+ } else {
+ fn = a.prog.Method(sel)
+ // move receiver to params[0]
+ sig = changeRecv(fn.Signature)
+ }
+
+ // a.offsetOf(Type) is 3.
+ if id := c.result + 3; a.addLabel(id, a.makeRtype(sig)) {
+ a.addWork(id)
+ }
+ if fn != nil {
+ // a.offsetOf(Func) is 4.
+ if id := c.result + 4; a.addLabel(id, a.objectNode(nil, fn)) {
+ a.addWork(id)
+ }
+ }
+ }
+ }
+ }
+}
+
+func ext۰reflect۰rtype۰MethodByName(a *analysis, cgn *cgnode) {
+ // If we have access to the callsite,
+ // and the argument is a string constant,
+ // return only that method.
+ var name string
+ if site := cgn.callersite; site != nil {
+ if c, ok := site.instr.Common().Args[0].(*ssa.Const); ok {
+ name = exact.StringVal(c.Value)
+ }
+ }
+
+ a.addConstraint(&rtypeMethodByNameConstraint{
+ cgn: cgn,
+ name: name,
+ t: a.funcParams(cgn.obj),
+ result: a.funcResults(cgn.obj),
+ })
+}
+
+func ext۰reflect۰rtype۰Method(a *analysis, cgn *cgnode) {
+ // No-one ever calls Method with a constant argument,
+ // so we don't specialize that case.
+ a.addConstraint(&rtypeMethodByNameConstraint{
+ cgn: cgn,
+ t: a.funcParams(cgn.obj),
+ result: a.funcResults(cgn.obj),
+ })
+}
+
+// typeHeight returns the "height" of the type, which is roughly
+// speaking the number of chan, map, pointer and slice type constructors
+// at the root of T; these are the four type kinds that can be created
+// via reflection. Chan and map constructors are counted as double the
+// height of slice and pointer constructors since they are less often
+// deeply nested.
+//
+// The solver rules for type constructors must somehow bound the set of
+// types they create to ensure termination of the algorithm in cases
+// where the output of a type constructor flows to its input, e.g.
+//
+// func f(t reflect.Type) {
+// f(reflect.PtrTo(t))
+// }
+//
+// It does this by limiting the type height to k, but this still leaves
+// a potentially exponential (4^k) number of of types that may be
+// enumerated in pathological cases.
+//
+func typeHeight(T types.Type) int {
+ switch T := T.(type) {
+ case *types.Chan:
+ return 2 + typeHeight(T.Elem())
+ case *types.Map:
+ k := typeHeight(T.Key())
+ v := typeHeight(T.Elem())
+ if v > k {
+ k = v // max(k, v)
+ }
+ return 2 + k
+ case *types.Slice:
+ return 1 + typeHeight(T.Elem())
+ case *types.Pointer:
+ return 1 + typeHeight(T.Elem())
+ }
+ return 0
+}
+
+func typeTooHigh(T types.Type) bool {
+ return typeHeight(T) > 3
+}
diff --git a/go/pointer/solve.go b/go/pointer/solve.go
new file mode 100644
index 0000000..ad1a65f
--- /dev/null
+++ b/go/pointer/solve.go
@@ -0,0 +1,371 @@
+// 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 pointer
+
+// This file defines a naive Andersen-style solver for the inclusion
+// constraint system.
+
+import (
+ "fmt"
+
+ "golang.org/x/tools/go/types"
+)
+
+type solverState struct {
+ complex []constraint // complex constraints attached to this node
+ copyTo nodeset // simple copy constraint edges
+ pts nodeset // points-to set of this node
+ prevPTS nodeset // pts(n) in previous iteration (for difference propagation)
+}
+
+func (a *analysis) solve() {
+ start("Solving")
+ if a.log != nil {
+ fmt.Fprintf(a.log, "\n\n==== Solving constraints\n\n")
+ }
+
+ // Solver main loop.
+ var delta nodeset
+ for {
+ // Add new constraints to the graph:
+ // static constraints from SSA on round 1,
+ // dynamic constraints from reflection thereafter.
+ a.processNewConstraints()
+
+ var x int
+ if !a.work.TakeMin(&x) {
+ break // empty
+ }
+ id := nodeid(x)
+ if a.log != nil {
+ fmt.Fprintf(a.log, "\tnode n%d\n", id)
+ }
+
+ n := a.nodes[id]
+
+ // Difference propagation.
+ delta.Difference(&n.solve.pts.Sparse, &n.solve.prevPTS.Sparse)
+ if delta.IsEmpty() {
+ continue
+ }
+ if a.log != nil {
+ fmt.Fprintf(a.log, "\t\tpts(n%d : %s) = %s + %s\n",
+ id, n.typ, &delta, &n.solve.prevPTS)
+ }
+ n.solve.prevPTS.Copy(&n.solve.pts.Sparse)
+
+ // Apply all resolution rules attached to n.
+ a.solveConstraints(n, &delta)
+
+ if a.log != nil {
+ fmt.Fprintf(a.log, "\t\tpts(n%d) = %s\n", id, &n.solve.pts)
+ }
+ }
+
+ if !a.nodes[0].solve.pts.IsEmpty() {
+ panic(fmt.Sprintf("pts(0) is nonempty: %s", &a.nodes[0].solve.pts))
+ }
+
+ // Release working state (but keep final PTS).
+ for _, n := range a.nodes {
+ n.solve.complex = nil
+ n.solve.copyTo.Clear()
+ n.solve.prevPTS.Clear()
+ }
+
+ if a.log != nil {
+ fmt.Fprintf(a.log, "Solver done\n")
+
+ // Dump solution.
+ for i, n := range a.nodes {
+ if !n.solve.pts.IsEmpty() {
+ fmt.Fprintf(a.log, "pts(n%d) = %s : %s\n", i, &n.solve.pts, n.typ)
+ }
+ }
+ }
+ stop("Solving")
+}
+
+// processNewConstraints takes the new constraints from a.constraints
+// and adds them to the graph, ensuring
+// that new constraints are applied to pre-existing labels and
+// that pre-existing constraints are applied to new labels.
+//
+func (a *analysis) processNewConstraints() {
+ // Take the slice of new constraints.
+ // (May grow during call to solveConstraints.)
+ constraints := a.constraints
+ a.constraints = nil
+
+ // Initialize points-to sets from addr-of (base) constraints.
+ for _, c := range constraints {
+ if c, ok := c.(*addrConstraint); ok {
+ dst := a.nodes[c.dst]
+ dst.solve.pts.add(c.src)
+
+ // Populate the worklist with nodes that point to
+ // something initially (due to addrConstraints) and
+ // have other constraints attached.
+ // (A no-op in round 1.)
+ if !dst.solve.copyTo.IsEmpty() || len(dst.solve.complex) > 0 {
+ a.addWork(c.dst)
+ }
+ }
+ }
+
+ // Attach simple (copy) and complex constraints to nodes.
+ var stale nodeset
+ for _, c := range constraints {
+ var id nodeid
+ switch c := c.(type) {
+ case *addrConstraint:
+ // base constraints handled in previous loop
+ continue
+ case *copyConstraint:
+ // simple (copy) constraint
+ id = c.src
+ a.nodes[id].solve.copyTo.add(c.dst)
+ default:
+ // complex constraint
+ id = c.ptr()
+ solve := a.nodes[id].solve
+ solve.complex = append(solve.complex, c)
+ }
+
+ if n := a.nodes[id]; !n.solve.pts.IsEmpty() {
+ if !n.solve.prevPTS.IsEmpty() {
+ stale.add(id)
+ }
+ a.addWork(id)
+ }
+ }
+ // Apply new constraints to pre-existing PTS labels.
+ var space [50]int
+ for _, id := range stale.AppendTo(space[:0]) {
+ n := a.nodes[nodeid(id)]
+ a.solveConstraints(n, &n.solve.prevPTS)
+ }
+}
+
+// solveConstraints applies each resolution rule attached to node n to
+// the set of labels delta. It may generate new constraints in
+// a.constraints.
+//
+func (a *analysis) solveConstraints(n *node, delta *nodeset) {
+ if delta.IsEmpty() {
+ return
+ }
+
+ // Process complex constraints dependent on n.
+ for _, c := range n.solve.complex {
+ if a.log != nil {
+ fmt.Fprintf(a.log, "\t\tconstraint %s\n", c)
+ }
+ c.solve(a, delta)
+ }
+
+ // Process copy constraints.
+ var copySeen nodeset
+ for _, x := range n.solve.copyTo.AppendTo(a.deltaSpace) {
+ mid := nodeid(x)
+ if copySeen.add(mid) {
+ if a.nodes[mid].solve.pts.addAll(delta) {
+ a.addWork(mid)
+ }
+ }
+ }
+}
+
+// addLabel adds label to the points-to set of ptr and reports whether the set grew.
+func (a *analysis) addLabel(ptr, label nodeid) bool {
+ b := a.nodes[ptr].solve.pts.add(label)
+ if b && a.log != nil {
+ fmt.Fprintf(a.log, "\t\tpts(n%d) += n%d\n", ptr, label)
+ }
+ return b
+}
+
+func (a *analysis) addWork(id nodeid) {
+ a.work.Insert(int(id))
+ if a.log != nil {
+ fmt.Fprintf(a.log, "\t\twork: n%d\n", id)
+ }
+}
+
+// onlineCopy adds a copy edge. It is called online, i.e. during
+// solving, so it adds edges and pts members directly rather than by
+// instantiating a 'constraint'.
+//
+// The size of the copy is implicitly 1.
+// It returns true if pts(dst) changed.
+//
+func (a *analysis) onlineCopy(dst, src nodeid) bool {
+ if dst != src {
+ if nsrc := a.nodes[src]; nsrc.solve.copyTo.add(dst) {
+ if a.log != nil {
+ fmt.Fprintf(a.log, "\t\t\tdynamic copy n%d <- n%d\n", dst, src)
+ }
+ // TODO(adonovan): most calls to onlineCopy
+ // are followed by addWork, possibly batched
+ // via a 'changed' flag; see if there's a
+ // noticeable penalty to calling addWork here.
+ return a.nodes[dst].solve.pts.addAll(&nsrc.solve.pts)
+ }
+ }
+ return false
+}
+
+// Returns sizeof.
+// Implicitly adds nodes to worklist.
+//
+// TODO(adonovan): now that we support a.copy() during solving, we
+// could eliminate onlineCopyN, but it's much slower. Investigate.
+//
+func (a *analysis) onlineCopyN(dst, src nodeid, sizeof uint32) uint32 {
+ for i := uint32(0); i < sizeof; i++ {
+ if a.onlineCopy(dst, src) {
+ a.addWork(dst)
+ }
+ src++
+ dst++
+ }
+ return sizeof
+}
+
+func (c *loadConstraint) solve(a *analysis, delta *nodeset) {
+ var changed bool
+ for _, x := range delta.AppendTo(a.deltaSpace) {
+ k := nodeid(x)
+ koff := k + nodeid(c.offset)
+ if a.onlineCopy(c.dst, koff) {
+ changed = true
+ }
+ }
+ if changed {
+ a.addWork(c.dst)
+ }
+}
+
+func (c *storeConstraint) solve(a *analysis, delta *nodeset) {
+ for _, x := range delta.AppendTo(a.deltaSpace) {
+ k := nodeid(x)
+ koff := k + nodeid(c.offset)
+ if a.onlineCopy(koff, c.src) {
+ a.addWork(koff)
+ }
+ }
+}
+
+func (c *offsetAddrConstraint) solve(a *analysis, delta *nodeset) {
+ dst := a.nodes[c.dst]
+ for _, x := range delta.AppendTo(a.deltaSpace) {
+ k := nodeid(x)
+ if dst.solve.pts.add(k + nodeid(c.offset)) {
+ a.addWork(c.dst)
+ }
+ }
+}
+
+func (c *typeFilterConstraint) solve(a *analysis, delta *nodeset) {
+ for _, x := range delta.AppendTo(a.deltaSpace) {
+ ifaceObj := nodeid(x)
+ tDyn, _, indirect := a.taggedValue(ifaceObj)
+ if indirect {
+ // TODO(adonovan): we'll need to implement this
+ // when we start creating indirect tagged objects.
+ panic("indirect tagged object")
+ }
+
+ if types.AssignableTo(tDyn, c.typ) {
+ if a.addLabel(c.dst, ifaceObj) {
+ a.addWork(c.dst)
+ }
+ }
+ }
+}
+
+func (c *untagConstraint) solve(a *analysis, delta *nodeset) {
+ predicate := types.AssignableTo
+ if c.exact {
+ predicate = types.Identical
+ }
+ for _, x := range delta.AppendTo(a.deltaSpace) {
+ ifaceObj := nodeid(x)
+ tDyn, v, indirect := a.taggedValue(ifaceObj)
+ if indirect {
+ // TODO(adonovan): we'll need to implement this
+ // when we start creating indirect tagged objects.
+ panic("indirect tagged object")
+ }
+
+ if predicate(tDyn, c.typ) {
+ // Copy payload sans tag to dst.
+ //
+ // TODO(adonovan): opt: if tDyn is
+ // nonpointerlike we can skip this entire
+ // constraint, perhaps. We only care about
+ // pointers among the fields.
+ a.onlineCopyN(c.dst, v, a.sizeof(tDyn))
+ }
+ }
+}
+
+func (c *invokeConstraint) solve(a *analysis, delta *nodeset) {
+ for _, x := range delta.AppendTo(a.deltaSpace) {
+ ifaceObj := nodeid(x)
+ tDyn, v, indirect := a.taggedValue(ifaceObj)
+ if indirect {
+ // TODO(adonovan): we may need to implement this if
+ // we ever apply invokeConstraints to reflect.Value PTSs,
+ // e.g. for (reflect.Value).Call.
+ panic("indirect tagged object")
+ }
+
+ // Look up the concrete method.
+ fn := a.prog.LookupMethod(tDyn, c.method.Pkg(), c.method.Name())
+ if fn == nil {
+ panic(fmt.Sprintf("n%d: no ssa.Function for %s", c.iface, c.method))
+ }
+ sig := fn.Signature
+
+ fnObj := a.globalobj[fn] // dynamic calls use shared contour
+ if fnObj == 0 {
+ // a.objectNode(fn) was not called during gen phase.
+ panic(fmt.Sprintf("a.globalobj[%s]==nil", fn))
+ }
+
+ // Make callsite's fn variable point to identity of
+ // concrete method. (There's no need to add it to
+ // worklist since it never has attached constraints.)
+ a.addLabel(c.params, fnObj)
+
+ // Extract value and connect to method's receiver.
+ // Copy payload to method's receiver param (arg0).
+ arg0 := a.funcParams(fnObj)
+ recvSize := a.sizeof(sig.Recv().Type())
+ a.onlineCopyN(arg0, v, recvSize)
+
+ src := c.params + 1 // skip past identity
+ dst := arg0 + nodeid(recvSize)
+
+ // Copy caller's argument block to method formal parameters.
+ paramsSize := a.sizeof(sig.Params())
+ a.onlineCopyN(dst, src, paramsSize)
+ src += nodeid(paramsSize)
+ dst += nodeid(paramsSize)
+
+ // Copy method results to caller's result block.
+ resultsSize := a.sizeof(sig.Results())
+ a.onlineCopyN(src, dst, resultsSize)
+ }
+}
+
+func (c *addrConstraint) solve(a *analysis, delta *nodeset) {
+ panic("addr is not a complex constraint")
+}
+
+func (c *copyConstraint) solve(a *analysis, delta *nodeset) {
+ panic("copy is not a complex constraint")
+}
diff --git a/go/pointer/stdlib_test.go b/go/pointer/stdlib_test.go
new file mode 100644
index 0000000..ef7c652
--- /dev/null
+++ b/go/pointer/stdlib_test.go
@@ -0,0 +1,109 @@
+// 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.
+
+// Incomplete source tree on Android.
+
+// +build !android
+
+package pointer
+
+// This file runs the pointer analysis on all packages and tests beneath
+// $GOROOT. It provides a "smoke test" that the analysis doesn't crash
+// on a large input, and a benchmark for performance measurement.
+//
+// Because it is relatively slow, the --stdlib flag must be enabled for
+// this test to run:
+// % go test -v golang.org/x/tools/go/pointer --stdlib
+
+import (
+ "flag"
+ "go/build"
+ "go/token"
+ "testing"
+ "time"
+
+ "golang.org/x/tools/go/buildutil"
+ "golang.org/x/tools/go/loader"
+ "golang.org/x/tools/go/ssa"
+ "golang.org/x/tools/go/ssa/ssautil"
+)
+
+var runStdlibTest = flag.Bool("stdlib", false, "Run the (slow) stdlib test")
+
+func TestStdlib(t *testing.T) {
+ if !*runStdlibTest {
+ t.Skip("skipping (slow) stdlib test (use --stdlib)")
+ }
+
+ // Load, parse and type-check the program.
+ ctxt := build.Default // copy
+ ctxt.GOPATH = "" // disable GOPATH
+ conf := loader.Config{Build: &ctxt}
+ if _, err := conf.FromArgs(buildutil.AllPackages(conf.Build), true); err != nil {
+ t.Errorf("FromArgs failed: %v", err)
+ return
+ }
+
+ iprog, err := conf.Load()
+ if err != nil {
+ t.Fatalf("Load failed: %v", err)
+ }
+
+ // Create SSA packages.
+ prog := ssautil.CreateProgram(iprog, 0)
+ prog.BuildAll()
+
+ numPkgs := len(prog.AllPackages())
+ if want := 240; numPkgs < want {
+ t.Errorf("Loaded only %d packages, want at least %d", numPkgs, want)
+ }
+
+ // Determine the set of packages/tests to analyze.
+ var testPkgs []*ssa.Package
+ for _, info := range iprog.InitialPackages() {
+ testPkgs = append(testPkgs, prog.Package(info.Pkg))
+ }
+ testmain := prog.CreateTestMainPackage(testPkgs...)
+ if testmain == nil {
+ t.Fatal("analysis scope has tests")
+ }
+
+ // Run the analysis.
+ config := &Config{
+ Reflection: false, // TODO(adonovan): fix remaining bug in rVCallConstraint, then enable.
+ BuildCallGraph: true,
+ Mains: []*ssa.Package{testmain},
+ }
+ // TODO(adonovan): add some query values (affects track bits).
+
+ t0 := time.Now()
+
+ result, err := Analyze(config)
+ if err != nil {
+ t.Fatal(err) // internal error in pointer analysis
+ }
+ _ = result // TODO(adonovan): measure something
+
+ t1 := time.Now()
+
+ // Dump some statistics.
+ allFuncs := ssautil.AllFunctions(prog)
+ var numInstrs int
+ for fn := range allFuncs {
+ for _, b := range fn.Blocks {
+ numInstrs += len(b.Instrs)
+ }
+ }
+
+ // determine line count
+ var lineCount int
+ prog.Fset.Iterate(func(f *token.File) bool {
+ lineCount += f.LineCount()
+ return true
+ })
+
+ t.Log("#Source lines: ", lineCount)
+ t.Log("#Instructions: ", numInstrs)
+ t.Log("Pointer analysis: ", t1.Sub(t0))
+}
diff --git a/go/pointer/testdata/a_test.go b/go/pointer/testdata/a_test.go
new file mode 100644
index 0000000..3baa9ac
--- /dev/null
+++ b/go/pointer/testdata/a_test.go
@@ -0,0 +1,42 @@
+// +build ignore
+
+package a
+
+// This test exercises the synthesis of testmain packages for tests.
+// The test framework doesn't directly let us perform negative
+// assertions (i.e. that TestingQuux isn't called, or that its
+// parameter's PTS is empty) so this test is rather roundabout.
+
+import "testing"
+
+func log(f func(*testing.T)) {
+ // The PTS of f is the set of called tests. TestingQuux is not present.
+ print(f) // @pointsto main.Test | main.TestFoo
+}
+
+func Test(t *testing.T) {
+ // Don't assert @pointsto(t) since its label contains a fragile line number.
+ log(Test)
+}
+
+func TestFoo(t *testing.T) {
+ // Don't assert @pointsto(t) since its label contains a fragile line number.
+ log(TestFoo)
+}
+
+func TestingQuux(t *testing.T) {
+ // We can't assert @pointsto(t) since this is dead code.
+ log(TestingQuux)
+}
+
+func BenchmarkFoo(b *testing.B) {
+}
+
+func ExampleBar() {
+}
+
+// Excludes TestingQuux.
+// @calls testing.tRunner -> main.Test
+// @calls testing.tRunner -> main.TestFoo
+// @calls testing.runExample -> main.ExampleBar
+// @calls (*testing.B).runN -> main.BenchmarkFoo
diff --git a/go/pointer/testdata/another.go b/go/pointer/testdata/another.go
new file mode 100644
index 0000000..12ed690
--- /dev/null
+++ b/go/pointer/testdata/another.go
@@ -0,0 +1,36 @@
+// +build ignore
+
+package main
+
+var unknown bool
+
+type S string
+
+func incr(x int) int { return x + 1 }
+
+func main() {
+ var i interface{}
+ i = 1
+ if unknown {
+ i = S("foo")
+ }
+ if unknown {
+ i = (func(int, int))(nil) // NB type compares equal to that below.
+ }
+ // Look, the test harness can handle equal-but-not-String-equal
+ // types because we parse types and using a typemap.
+ if unknown {
+ i = (func(x int, y int))(nil)
+ }
+ if unknown {
+ i = incr
+ }
+ print(i) // @types int | S | func(int, int) | func(int) int
+
+ // NB, an interface may never directly alias any global
+ // labels, even though it may contain pointers that do.
+ print(i) // @pointsto makeinterface:func(x int) int | makeinterface:func(x int, y int) | makeinterface:func(int, int) | makeinterface:int | makeinterface:main.S
+ print(i.(func(int) int)) // @pointsto main.incr
+
+ print() // regression test for crash
+}
diff --git a/go/pointer/testdata/arrayreflect.go b/go/pointer/testdata/arrayreflect.go
new file mode 100644
index 0000000..2b23674
--- /dev/null
+++ b/go/pointer/testdata/arrayreflect.go
@@ -0,0 +1,191 @@
+// +build ignore
+
+package main
+
+// Test of arrays & slices with reflection.
+
+import "reflect"
+
+var a, b int
+
+type S string
+
+func reflectValueSlice() {
+ // reflect.Value contains a slice.
+ slice := make([]*int, 10) // @line slice
+ slice[0] = &a
+ rvsl := reflect.ValueOf(slice).Slice(0, 0)
+ print(rvsl.Interface()) // @types []*int
+ print(rvsl.Interface().([]*int)) // @pointsto makeslice@slice:15
+ print(rvsl.Interface().([]*int)[42]) // @pointsto main.a
+
+ // reflect.Value contains an array (non-addressable).
+ array := [10]*int{&a} // @line array
+ rvarray := reflect.ValueOf(array).Slice(0, 0)
+ print(rvarray.Interface()) // @types
+ print(rvarray.Interface().([]*int)) // @pointsto
+ print(rvarray.Interface().([]*int)[42]) // @pointsto
+
+ // reflect.Value contains a pointer-to-array
+ rvparray := reflect.ValueOf(&array).Slice(0, 0)
+ print(rvparray.Interface()) // @types []*int
+ print(rvparray.Interface().([]*int)) // @pointsto array@array:2
+ print(rvparray.Interface().([]*int)[42]) // @pointsto main.a
+
+ // reflect.Value contains a string.
+ rvstring := reflect.ValueOf("hi").Slice(0, 0)
+ print(rvstring.Interface()) // @types string
+
+ // reflect.Value contains a (named) string type.
+ rvS := reflect.ValueOf(S("hi")).Slice(0, 0)
+ print(rvS.Interface()) // @types S
+
+ // reflect.Value contains a non-array pointer.
+ rvptr := reflect.ValueOf(new(int)).Slice(0, 0)
+ print(rvptr.Interface()) // @types
+
+ // reflect.Value contains a non-string basic type.
+ rvint := reflect.ValueOf(3).Slice(0, 0)
+ print(rvint.Interface()) // @types
+}
+
+func reflectValueBytes() {
+ sl1 := make([]byte, 0) // @line ar5sl1
+ sl2 := make([]byte, 0) // @line ar5sl2
+
+ rvsl1 := reflect.ValueOf(sl1)
+ print(rvsl1.Interface()) // @types []byte
+ print(rvsl1.Interface().([]byte)) // @pointsto makeslice@ar5sl1:13
+ print(rvsl1.Bytes()) // @pointsto makeslice@ar5sl1:13
+
+ rvsl2 := reflect.ValueOf(123)
+ rvsl2.SetBytes(sl2)
+ print(rvsl2.Interface()) // @types int
+ print(rvsl2.Interface().([]byte)) // @pointsto
+ print(rvsl2.Bytes()) // @pointsto
+
+ rvsl3 := reflect.ValueOf([]byte(nil))
+ rvsl3.SetBytes(sl2)
+ print(rvsl3.Interface()) // @types []byte
+ print(rvsl3.Interface().([]byte)) // @pointsto makeslice@ar5sl2:13
+ print(rvsl3.Bytes()) // @pointsto makeslice@ar5sl2:13
+}
+
+func reflectValueIndex() {
+ slice := []*int{&a} // @line ar6slice
+ rv1 := reflect.ValueOf(slice)
+ print(rv1.Index(42).Interface()) // @types *int
+ print(rv1.Index(42).Interface().(*int)) // @pointsto main.a
+
+ array := [10]*int{&a}
+ rv2 := reflect.ValueOf(array)
+ print(rv2.Index(42).Interface()) // @types *int
+ print(rv2.Index(42).Interface().(*int)) // @pointsto main.a
+
+ rv3 := reflect.ValueOf("string")
+ print(rv3.Index(42).Interface()) // @types rune
+
+ rv4 := reflect.ValueOf(&array)
+ print(rv4.Index(42).Interface()) // @types
+
+ rv5 := reflect.ValueOf(3)
+ print(rv5.Index(42).Interface()) // @types
+}
+
+func reflectValueElem() {
+ // Interface.
+ var iface interface{} = &a
+ rv1 := reflect.ValueOf(&iface).Elem()
+ print(rv1.Interface()) // @types *int
+ print(rv1.Interface().(*int)) // @pointsto main.a
+ print(rv1.Elem().Interface()) // @types *int
+ print(rv1.Elem().Interface().(*int)) // @pointsto main.a
+
+ print(reflect.ValueOf(new(interface{})).Elem().Elem()) // @types
+
+ // Pointer.
+ ptr := &a
+ rv2 := reflect.ValueOf(&ptr)
+ print(rv2.Elem().Interface()) // @types *int
+ print(rv2.Elem().Interface().(*int)) // @pointsto main.a
+
+ // No other type works with (rV).Elem, not even those that
+ // work with (rT).Elem: slice, array, map, chan.
+
+ rv3 := reflect.ValueOf([]*int{&a})
+ print(rv3.Elem().Interface()) // @types
+
+ rv4 := reflect.ValueOf([10]*int{&a})
+ print(rv4.Elem().Interface()) // @types
+
+ rv5 := reflect.ValueOf(map[*int]*int{&a: &b})
+ print(rv5.Elem().Interface()) // @types
+
+ ch := make(chan *int)
+ ch <- &a
+ rv6 := reflect.ValueOf(ch)
+ print(rv6.Elem().Interface()) // @types
+
+ rv7 := reflect.ValueOf(3)
+ print(rv7.Elem().Interface()) // @types
+}
+
+func reflectTypeElem() {
+ rt1 := reflect.TypeOf(make([]*int, 0))
+ print(reflect.Zero(rt1.Elem())) // @types *int
+
+ rt2 := reflect.TypeOf([10]*int{})
+ print(reflect.Zero(rt2.Elem())) // @types *int
+
+ rt3 := reflect.TypeOf(map[*int]*int{})
+ print(reflect.Zero(rt3.Elem())) // @types *int
+
+ rt4 := reflect.TypeOf(make(chan *int))
+ print(reflect.Zero(rt4.Elem())) // @types *int
+
+ ptr := &a
+ rt5 := reflect.TypeOf(&ptr)
+ print(reflect.Zero(rt5.Elem())) // @types *int
+
+ rt6 := reflect.TypeOf(3)
+ print(reflect.Zero(rt6.Elem())) // @types
+}
+
+func reflectPtrTo() {
+ tInt := reflect.TypeOf(3)
+ tPtrInt := reflect.PtrTo(tInt)
+ print(reflect.Zero(tPtrInt)) // @types *int
+ tPtrPtrInt := reflect.PtrTo(tPtrInt)
+ print(reflect.Zero(tPtrPtrInt)) // @types **int
+}
+
+func reflectSliceOf() {
+ tInt := reflect.TypeOf(3)
+ tSliceInt := reflect.SliceOf(tInt)
+ print(reflect.Zero(tSliceInt)) // @types []int
+}
+
+type T struct{ x int }
+
+func reflectMakeSlice() {
+ rt := []reflect.Type{
+ reflect.TypeOf(3),
+ reflect.TypeOf([]int{}),
+ reflect.TypeOf([]T{}),
+ }[0]
+ sl := reflect.MakeSlice(rt, 0, 0)
+ print(sl) // @types []int | []T
+ print(sl) // @pointsto <alloc in reflect.MakeSlice> | <alloc in reflect.MakeSlice>
+ print(&sl.Interface().([]T)[0].x) // @pointsto <alloc in reflect.MakeSlice>[*].x
+}
+
+func main() {
+ reflectValueSlice()
+ reflectValueBytes()
+ reflectValueIndex()
+ reflectValueElem()
+ reflectTypeElem()
+ reflectPtrTo()
+ reflectSliceOf()
+ reflectMakeSlice()
+}
diff --git a/go/pointer/testdata/arrays.go b/go/pointer/testdata/arrays.go
new file mode 100644
index 0000000..e57a15b
--- /dev/null
+++ b/go/pointer/testdata/arrays.go
@@ -0,0 +1,97 @@
+// +build ignore
+
+package main
+
+var unknown bool // defeat dead-code elimination
+
+var a, b int
+
+func array1() {
+ sliceA := make([]*int, 10) // @line a1make
+ sliceA[0] = &a
+
+ var sliceB []*int
+ sliceB = append(sliceB, &b) // @line a1append
+
+ print(sliceA) // @pointsto makeslice@a1make:16
+ print(sliceA[0]) // @pointsto main.a
+
+ print(sliceB) // @pointsto append@a1append:17
+ print(sliceB[100]) // @pointsto main.b
+}
+
+func array2() {
+ sliceA := make([]*int, 10) // @line a2make
+ sliceA[0] = &a
+
+ sliceB := sliceA[:]
+
+ print(sliceA) // @pointsto makeslice@a2make:16
+ print(sliceA[0]) // @pointsto main.a
+
+ print(sliceB) // @pointsto makeslice@a2make:16
+ print(sliceB[0]) // @pointsto main.a
+}
+
+func array3() {
+ a := []interface{}{"", 1}
+ b := []interface{}{true, func() {}}
+ print(a[0]) // @types string | int
+ print(b[0]) // @types bool | func()
+}
+
+// Test of append, copy, slice.
+func array4() {
+ var s2 struct { // @line a4L0
+ a [3]int
+ b struct{ c, d int }
+ }
+ var sl1 = make([]*int, 10) // @line a4make
+ var someint int // @line a4L1
+ sl1[1] = &someint
+ sl2 := append(sl1, &s2.a[1]) // @line a4append1
+ print(sl1) // @pointsto makeslice@a4make:16
+ print(sl2) // @pointsto append@a4append1:15 | makeslice@a4make:16
+ print(sl1[0]) // @pointsto someint@a4L1:6 | s2.a[*]@a4L0:6
+ print(sl2[0]) // @pointsto someint@a4L1:6 | s2.a[*]@a4L0:6
+
+ // In z=append(x,y) we should observe flow from y[*] to x[*].
+ var sl3 = make([]*int, 10) // @line a4L2
+ _ = append(sl3, &s2.a[1])
+ print(sl3) // @pointsto makeslice@a4L2:16
+ print(sl3[0]) // @pointsto s2.a[*]@a4L0:6
+
+ var sl4 = []*int{&a} // @line a4L3
+ sl4a := append(sl4) // @line a4L4
+ print(sl4a) // @pointsto slicelit@a4L3:18 | append@a4L4:16
+ print(&sl4a[0]) // @pointsto slicelit[*]@a4L3:18 | append[*]@a4L4:16
+ print(sl4a[0]) // @pointsto main.a
+
+ var sl5 = []*int{&b} // @line a4L5
+ copy(sl5, sl4)
+ print(sl5) // @pointsto slicelit@a4L5:18
+ print(&sl5[0]) // @pointsto slicelit[*]@a4L5:18
+ print(sl5[0]) // @pointsto main.b | main.a
+
+ var sl6 = sl5[:0]
+ print(sl6) // @pointsto slicelit@a4L5:18
+ print(&sl6[0]) // @pointsto slicelit[*]@a4L5:18
+ print(sl6[0]) // @pointsto main.b | main.a
+}
+
+func array5() {
+ var arr [2]*int
+ arr[0] = &a
+ arr[1] = &b
+
+ var n int
+ print(arr[n]) // @pointsto main.a | main.b
+}
+
+func main() {
+ array1()
+ array2()
+ array3()
+ array4()
+ array5()
+}
diff --git a/go/pointer/testdata/channels.go b/go/pointer/testdata/channels.go
new file mode 100644
index 0000000..76eb5f8
--- /dev/null
+++ b/go/pointer/testdata/channels.go
@@ -0,0 +1,118 @@
+// +build ignore
+
+package main
+
+func incr(x int) int { return x + 1 }
+
+func decr(x int) int { return x - 1 }
+
+var unknown bool // defeat dead-code elimination
+
+func chan1() {
+ chA := make(chan func(int) int, 0) // @line c1makeA
+ chB := make(chan func(int) int, 0) // @line c1makeB
+ chA <- incr
+ chB <- decr
+ chB <- func(int) int { return 1 }
+
+ print(chA) // @pointsto makechan@c1makeA:13
+ print(<-chA) // @pointsto main.incr
+
+ print(chB) // @pointsto makechan@c1makeB:13
+ print(<-chB) // @pointsto main.decr | main.chan1$1
+}
+
+func chan2() {
+ chA := make(chan func(int) int, 0) // @line c2makeA
+ chB := make(chan func(int) int, 0) // @line c2makeB
+ chA <- incr
+ chB <- decr
+ chB <- func(int) int { return 1 }
+
+ // Channels flow together.
+ // Labelsets remain distinct but elements are merged.
+ chAB := chA
+ if unknown {
+ chAB = chB
+ }
+
+ print(chA) // @pointsto makechan@c2makeA:13
+ print(<-chA) // @pointsto main.incr
+
+ print(chB) // @pointsto makechan@c2makeB:13
+ print(<-chB) // @pointsto main.decr | main.chan2$1
+
+ print(chAB) // @pointsto makechan@c2makeA:13 | makechan@c2makeB:13
+ print(<-chAB) // @pointsto main.incr | main.decr | main.chan2$1
+
+ (<-chA)(3)
+}
+
+// @calls main.chan2 -> main.incr
+
+func chan3() {
+ chA := make(chan func(int) int, 0) // @line c3makeA
+ chB := make(chan func(int) int, 0) // @line c3makeB
+ chA <- incr
+ chB <- decr
+ chB <- func(int) int { return 1 }
+ print(chA) // @pointsto makechan@c3makeA:13
+ print(<-chA) // @pointsto main.incr
+ print(chB) // @pointsto makechan@c3makeB:13
+ print(<-chB) // @pointsto main.decr | main.chan3$1
+
+ (<-chA)(3)
+}
+
+// @calls main.chan3 -> main.incr
+
+func chan4() {
+ chA := make(chan func(int) int, 0) // @line c4makeA
+ chB := make(chan func(int) int, 0) // @line c4makeB
+
+ select {
+ case chA <- incr:
+ case chB <- decr:
+ case a := <-chA:
+ print(a) // @pointsto main.incr
+ case b := <-chB:
+ print(b) // @pointsto main.decr
+ default:
+ print(chA) // @pointsto makechan@c4makeA:13
+ print(chB) // @pointsto makechan@c4makeB:13
+ }
+
+ for k := range chA {
+ print(k) // @pointsto main.incr
+ }
+ // Exercise constraint generation (regtest for a crash).
+ for _ = range chA {
+ }
+}
+
+// Multi-word channel value in select with multiple receive cases.
+// (Regtest for a crash.)
+func chan5() {
+ type T struct {
+ x *int
+ y interface{}
+ }
+ ch := make(chan T)
+ ch <- T{new(int), incr} // @line ch5new
+ select {
+ case a := <-ch:
+ print(a.x) // @pointsto new@ch5new:13
+ print(a.y) // @types func(x int) int
+ case b := <-ch:
+ print(b.x) // @pointsto new@ch5new:13
+ print(b.y) // @types func(x int) int
+ }
+}
+
+func main() {
+ chan1()
+ chan2()
+ chan3()
+ chan4()
+ chan5()
+}
diff --git a/go/pointer/testdata/chanreflect.go b/go/pointer/testdata/chanreflect.go
new file mode 100644
index 0000000..7d22efe
--- /dev/null
+++ b/go/pointer/testdata/chanreflect.go
@@ -0,0 +1,85 @@
+// +build ignore
+
+package main
+
+import "reflect"
+
+// Test of channels with reflection.
+
+var a, b int
+
+func chanreflect1() {
+ ch := make(chan *int, 0) // @line cr1make
+ crv := reflect.ValueOf(ch)
+ crv.Send(reflect.ValueOf(&a))
+ print(crv.Interface()) // @types chan *int
+ print(crv.Interface().(chan *int)) // @pointsto makechan@cr1make:12
+ print(<-ch) // @pointsto main.a
+}
+
+func chanreflect1i() {
+ // Exercises reflect.Value conversions to/from interfaces:
+ // a different code path than for concrete types.
+ ch := make(chan interface{}, 0)
+ reflect.ValueOf(ch).Send(reflect.ValueOf(&a))
+ v := <-ch
+ print(v) // @types *int
+ print(v.(*int)) // @pointsto main.a
+}
+
+func chanreflect2() {
+ ch := make(chan *int, 0)
+ ch <- &b
+ crv := reflect.ValueOf(ch)
+ r, _ := crv.Recv()
+ print(r.Interface()) // @types *int
+ print(r.Interface().(*int)) // @pointsto main.b
+}
+
+func chanOfRecv() {
+ // MakeChan(<-chan) is a no-op.
+ t := reflect.ChanOf(reflect.RecvDir, reflect.TypeOf(&a))
+ print(reflect.Zero(t).Interface()) // @types <-chan *int
+ print(reflect.MakeChan(t, 0).Interface().(<-chan *int)) // @pointsto
+ print(reflect.MakeChan(t, 0).Interface().(chan *int)) // @pointsto
+}
+
+func chanOfSend() {
+ // MakeChan(chan<-) is a no-op.
+ t := reflect.ChanOf(reflect.SendDir, reflect.TypeOf(&a))
+ print(reflect.Zero(t).Interface()) // @types chan<- *int
+ print(reflect.MakeChan(t, 0).Interface().(chan<- *int)) // @pointsto
+ print(reflect.MakeChan(t, 0).Interface().(chan *int)) // @pointsto
+}
+
+func chanOfBoth() {
+ t := reflect.ChanOf(reflect.BothDir, reflect.TypeOf(&a))
+ print(reflect.Zero(t).Interface()) // @types chan *int
+ ch := reflect.MakeChan(t, 0)
+ print(ch.Interface().(chan *int)) // @pointsto <alloc in reflect.MakeChan>
+ ch.Send(reflect.ValueOf(&b))
+ ch.Interface().(chan *int) <- &a
+ r, _ := ch.Recv()
+ print(r.Interface().(*int)) // @pointsto main.a | main.b
+ print(<-ch.Interface().(chan *int)) // @pointsto main.a | main.b
+}
+
+var unknownDir reflect.ChanDir // not a constant
+
+func chanOfUnknown() {
+ // Unknown channel direction: assume all three.
+ // MakeChan only works on the bi-di channel type.
+ t := reflect.ChanOf(unknownDir, reflect.TypeOf(&a))
+ print(reflect.Zero(t).Interface()) // @types <-chan *int | chan<- *int | chan *int
+ print(reflect.MakeChan(t, 0).Interface()) // @types chan *int
+}
+
+func main() {
+ chanreflect1()
+ chanreflect1i()
+ chanreflect2()
+ chanOfRecv()
+ chanOfSend()
+ chanOfBoth()
+ chanOfUnknown()
+}
diff --git a/go/pointer/testdata/chanreflect1.go b/go/pointer/testdata/chanreflect1.go
new file mode 100644
index 0000000..c5e2587
--- /dev/null
+++ b/go/pointer/testdata/chanreflect1.go
@@ -0,0 +1,35 @@
+// +build ignore
+
+package main
+
+import "reflect"
+
+//
+// This test is very sensitive to line-number perturbations!
+
+// Test of channels with reflection.
+
+var a, b int
+
+func chanreflect1() {
+ ch := make(chan *int, 0)
+ crv := reflect.ValueOf(ch)
+ crv.Send(reflect.ValueOf(&a))
+ print(crv.Interface()) // @types chan *int
+ print(crv.Interface().(chan *int)) // @pointsto makechan@testdata/chanreflect.go:15:12
+ print(<-ch) // @pointsto main.a
+}
+
+func chanreflect2() {
+ ch := make(chan *int, 0)
+ ch <- &b
+ crv := reflect.ValueOf(ch)
+ r, _ := crv.Recv()
+ print(r.Interface()) // @types *int
+ print(r.Interface().(*int)) // @pointsto main.b
+}
+
+func main() {
+ chanreflect1()
+ chanreflect2()
+}
diff --git a/go/pointer/testdata/context.go b/go/pointer/testdata/context.go
new file mode 100644
index 0000000..ed616e7
--- /dev/null
+++ b/go/pointer/testdata/context.go
@@ -0,0 +1,48 @@
+// +build ignore
+
+package main
+
+// Test of context-sensitive treatment of certain function calls,
+// e.g. static calls to simple accessor methods.
+
+var a, b int
+
+type T struct{ x *int }
+
+func (t *T) SetX(x *int) { t.x = x }
+func (t *T) GetX() *int { return t.x }
+
+func context1() {
+ var t1, t2 T
+ t1.SetX(&a)
+ t2.SetX(&b)
+ print(t1.GetX()) // @pointsto main.a
+ print(t2.GetX()) // @pointsto main.b
+}
+
+func context2() {
+ id := func(x *int) *int {
+ print(x) // @pointsto main.a | main.b
+ return x
+ }
+ print(id(&a)) // @pointsto main.a
+ print(id(&b)) // @pointsto main.b
+
+ // Same again, but anon func has free vars.
+ var c int // @line context2c
+ id2 := func(x *int) (*int, *int) {
+ print(x) // @pointsto main.a | main.b
+ return x, &c
+ }
+ p, q := id2(&a)
+ print(p) // @pointsto main.a
+ print(q) // @pointsto c@context2c:6
+ r, s := id2(&b)
+ print(r) // @pointsto main.b
+ print(s) // @pointsto c@context2c:6
+}
+
+func main() {
+ context1()
+ context2()
+}
diff --git a/go/pointer/testdata/conv.go b/go/pointer/testdata/conv.go
new file mode 100644
index 0000000..692f0ce
--- /dev/null
+++ b/go/pointer/testdata/conv.go
@@ -0,0 +1,63 @@
+// +build ignore
+
+package main
+
+import "unsafe"
+
+var a int
+
+func conv1() {
+ // Conversions of channel direction.
+ ch := make(chan int) // @line c1make
+ print((<-chan int)(ch)) // @pointsto makechan@c1make:12
+ print((chan<- int)(ch)) // @pointsto makechan@c1make:12
+}
+
+func conv2() {
+ // string -> []byte/[]rune conversion
+ s := "foo"
+ ba := []byte(s) // @line c2ba
+ ra := []rune(s) // @line c2ra
+ print(ba) // @pointsto convert@c2ba:14
+ print(ra) // @pointsto convert@c2ra:14
+}
+
+func conv3() {
+ // Conversion of same underlying types.
+ type PI *int
+ pi := PI(&a)
+ print(pi) // @pointsto main.a
+
+ pint := (*int)(pi)
+ print(pint) // @pointsto main.a
+
+ // Conversions between pointers to identical base types.
+ var y *PI = &pi
+ var x **int = (**int)(y)
+ print(*x) // @pointsto main.a
+ print(*y) // @pointsto main.a
+ y = (*PI)(x)
+ print(*y) // @pointsto main.a
+}
+
+func conv4() {
+ // Handling of unsafe.Pointer conversion is unsound:
+ // we lose the alias to main.a and get something like new(int) instead.
+ p := (*int)(unsafe.Pointer(&a)) // @line c2p
+ print(p) // @pointsto convert@c2p:13
+}
+
+// Regression test for b/8231.
+func conv5() {
+ type P unsafe.Pointer
+ var i *struct{}
+ _ = P(i)
+}
+
+func main() {
+ conv1()
+ conv2()
+ conv3()
+ conv4()
+ conv5()
+}
diff --git a/go/pointer/testdata/finalizer.go b/go/pointer/testdata/finalizer.go
new file mode 100644
index 0000000..97f25c9
--- /dev/null
+++ b/go/pointer/testdata/finalizer.go
@@ -0,0 +1,89 @@
+package main
+
+import "runtime"
+
+func final1a(x *int) int {
+ print(x) // @pointsto new@newint:10
+ return *x
+}
+
+func final1b(x *bool) {
+ print(x) // @pointsto
+}
+
+func runtimeSetFinalizer1() {
+ x := new(int) // @line newint
+ runtime.SetFinalizer(x, final1a) // ok: final1a's result is ignored
+ runtime.SetFinalizer(x, final1b) // param type mismatch: no effect
+}
+
+// @calls main.runtimeSetFinalizer1 -> main.final1a
+// @calls main.runtimeSetFinalizer1 -> main.final1b
+
+func final2a(x *bool) {
+ print(x) // @pointsto new@newbool1:10 | new@newbool2:10
+}
+
+func final2b(x *bool) {
+ print(x) // @pointsto new@newbool1:10 | new@newbool2:10
+}
+
+func runtimeSetFinalizer2() {
+ x := new(bool) // @line newbool1
+ f := final2a
+ if unknown {
+ x = new(bool) // @line newbool2
+ f = final2b
+ }
+ runtime.SetFinalizer(x, f)
+}
+
+// @calls main.runtimeSetFinalizer2 -> main.final2a
+// @calls main.runtimeSetFinalizer2 -> main.final2b
+
+type T int
+
+func (t *T) finalize() {
+ print(t) // @pointsto new@final3:10
+}
+
+func runtimeSetFinalizer3() {
+ x := new(T) // @line final3
+ runtime.SetFinalizer(x, (*T).finalize)
+}
+
+// @calls main.runtimeSetFinalizer3 -> (*main.T).finalize$thunk
+
+// I hope I never live to see this code in the wild.
+var setFinalizer = runtime.SetFinalizer
+
+func final4(x *int) {
+ print(x) // @pointsto new@finalIndirect:10
+}
+
+func runtimeSetFinalizerIndirect() {
+ // In an indirect call, the shared contour for SetFinalizer is
+ // used, i.e. the call is not inlined and appears in the call graph.
+ x := new(int) // @line finalIndirect
+ setFinalizer(x, final4)
+}
+
+// Exercise the elimination of SetFinalizer
+// constraints with non-pointer operands.
+func runtimeSetFinalizerNonpointer() {
+ runtime.SetFinalizer(nil, (*T).finalize) // x is a non-pointer
+ runtime.SetFinalizer((*T).finalize, nil) // f is a non-pointer
+}
+
+// @calls main.runtimeSetFinalizerIndirect -> runtime.SetFinalizer
+// @calls runtime.SetFinalizer -> main.final4
+
+func main() {
+ runtimeSetFinalizer1()
+ runtimeSetFinalizer2()
+ runtimeSetFinalizer3()
+ runtimeSetFinalizerIndirect()
+ runtimeSetFinalizerNonpointer()
+}
+
+var unknown bool // defeat dead-code elimination
diff --git a/go/pointer/testdata/flow.go b/go/pointer/testdata/flow.go
new file mode 100644
index 0000000..6fb599e
--- /dev/null
+++ b/go/pointer/testdata/flow.go
@@ -0,0 +1,63 @@
+// +build ignore
+
+package main
+
+// Demonstration of directionality of flow edges.
+
+func f1() {}
+func f2() {}
+
+var somepred bool
+
+// Tracking functions.
+func flow1() {
+ s := f1
+ p := f2
+ q := p
+ r := q
+ if somepred {
+ r = s
+ }
+ print(s) // @pointsto main.f1
+ print(p) // @pointsto main.f2
+ print(q) // @pointsto main.f2
+ print(r) // @pointsto main.f1 | main.f2
+}
+
+// Tracking concrete types in interfaces.
+func flow2() {
+ var s interface{} = 1
+ var p interface{} = "foo"
+ q := p
+ r := q
+ if somepred {
+ r = s
+ }
+ print(s) // @types int
+ print(p) // @types string
+ print(q) // @types string
+ print(r) // @types int | string
+}
+
+var g1, g2 int
+
+// Tracking addresses of globals.
+func flow3() {
+ s := &g1
+ p := &g2
+ q := p
+ r := q
+ if somepred {
+ r = s
+ }
+ print(s) // @pointsto main.g1
+ print(p) // @pointsto main.g2
+ print(q) // @pointsto main.g2
+ print(r) // @pointsto main.g2 | main.g1
+}
+
+func main() {
+ flow1()
+ flow2()
+ flow3()
+}
diff --git a/go/pointer/testdata/fmtexcerpt.go b/go/pointer/testdata/fmtexcerpt.go
new file mode 100644
index 0000000..ee2a0e7
--- /dev/null
+++ b/go/pointer/testdata/fmtexcerpt.go
@@ -0,0 +1,42 @@
+// +build ignore
+
+// This is a slice of the fmt package.
+
+package main
+
+type pp struct {
+ field interface{}
+}
+
+func newPrinter() *pp {
+ return new(pp)
+}
+
+func Fprintln(a ...interface{}) {
+ p := newPrinter()
+ p.doPrint(a, true, true)
+}
+
+func Println(a ...interface{}) {
+ Fprintln(a...)
+}
+
+func (p *pp) doPrint(a []interface{}, addspace, addnewline bool) {
+ print(a[0]) // @types S | string
+ stringer := a[0].(interface {
+ String() string
+ })
+
+ stringer.String()
+ print(stringer) // @types S
+}
+
+type S int
+
+func (S) String() string { return "" }
+
+func main() {
+ Println("Hello, World!", S(0))
+}
+
+// @calls (*main.pp).doPrint -> (main.S).String
diff --git a/go/pointer/testdata/func.go b/go/pointer/testdata/func.go
new file mode 100644
index 0000000..2155f8e
--- /dev/null
+++ b/go/pointer/testdata/func.go
@@ -0,0 +1,205 @@
+// +build ignore
+
+package main
+
+var a, b, c int
+
+var unknown bool // defeat dead-code elimination
+
+func func1() {
+ var h int // @line f1h
+ f := func(x *int) *int {
+ if unknown {
+ return &b
+ }
+ return x
+ }
+
+ // FV(g) = {f, h}
+ g := func(x *int) *int {
+ if unknown {
+ return &h
+ }
+ return f(x)
+ }
+
+ print(g(&a)) // @pointsto main.a | main.b | h@f1h:6
+ print(f(&a)) // @pointsto main.a | main.b
+ print(&a) // @pointsto main.a
+}
+
+// @calls main.func1 -> main.func1$2
+// @calls main.func1 -> main.func1$1
+// @calls main.func1$2 -> main.func1$1
+
+func func2() {
+ var x, y *int
+ defer func() {
+ x = &a
+ }()
+ go func() {
+ y = &b
+ }()
+ print(x) // @pointsto main.a
+ print(y) // @pointsto main.b
+}
+
+func func3() {
+ x, y := func() (x, y *int) {
+ x = &a
+ y = &b
+ if unknown {
+ return nil, &c
+ }
+ return
+ }()
+ print(x) // @pointsto main.a
+ print(y) // @pointsto main.b | main.c
+}
+
+func swap(x, y *int) (*int, *int) { // @line swap
+ print(&x) // @pointsto x@swap:11
+ print(x) // @pointsto makeslice[*]@func4make:11
+ print(&y) // @pointsto y@swap:14
+ print(y) // @pointsto j@f4j:5
+ return y, x
+}
+
+func func4() {
+ a := make([]int, 10) // @line func4make
+ i, j := 123, 456 // @line f4j
+ _ = i
+ p, q := swap(&a[3], &j)
+ print(p) // @pointsto j@f4j:5
+ print(q) // @pointsto makeslice[*]@func4make:11
+
+ f := &b
+ print(f) // @pointsto main.b
+}
+
+type T int
+
+func (t *T) f(x *int) *int {
+ print(t) // @pointsto main.a
+ print(x) // @pointsto main.c
+ return &b
+}
+
+func (t *T) g(x *int) *int {
+ print(t) // @pointsto main.a
+ print(x) // @pointsto main.b
+ return &c
+}
+
+func (t *T) h(x *int) *int {
+ print(t) // @pointsto main.a
+ print(x) // @pointsto main.b
+ return &c
+}
+
+var h func(*T, *int) *int
+
+func func5() {
+ // Static call of method.
+ t := (*T)(&a)
+ print(t.f(&c)) // @pointsto main.b
+
+ // Static call of method as function
+ print((*T).g(t, &b)) // @pointsto main.c
+
+ // Dynamic call (not invoke) of method.
+ h = (*T).h
+ print(h(t, &b)) // @pointsto main.c
+}
+
+// @calls main.func5 -> (*main.T).f
+// @calls main.func5 -> (*main.T).g$thunk
+// @calls main.func5 -> (*main.T).h$thunk
+
+func func6() {
+ A := &a
+ f := func() *int {
+ return A // (free variable)
+ }
+ print(f()) // @pointsto main.a
+}
+
+// @calls main.func6 -> main.func6$1
+
+type I interface {
+ f()
+}
+
+type D struct{}
+
+func (D) f() {}
+
+func func7() {
+ var i I = D{}
+ imethodClosure := i.f
+ imethodClosure()
+ // @calls main.func7 -> (main.I).f$bound
+ // @calls (main.I).f$bound -> (main.D).f
+
+ var d D
+ cmethodClosure := d.f
+ cmethodClosure()
+ // @calls main.func7 -> (main.D).f$bound
+ // @calls (main.D).f$bound ->(main.D).f
+
+ methodExpr := D.f
+ methodExpr(d)
+ // @calls main.func7 -> (main.D).f$thunk
+}
+
+func func8(x ...int) {
+ print(&x[0]) // @pointsto varargs[*]@varargs:15
+}
+
+type E struct {
+ x1, x2, x3, x4, x5 *int
+}
+
+func (e E) f() {}
+
+func func9() {
+ // Regression test for bug reported by Jon Valdes on golang-dev, Jun 19 2014.
+ // The receiver of a bound method closure may be of a multi-node type, E.
+ // valueNode was reserving only a single node for it, so the
+ // nodes used by the immediately following constraints
+ // (e.g. param 'i') would get clobbered.
+
+ var e E
+ e.x1 = &a
+ e.x2 = &a
+ e.x3 = &a
+ e.x4 = &a
+ e.x5 = &a
+
+ _ = e.f // form a closure---must reserve sizeof(E) nodes
+
+ func(i I) {
+ i.f() // must not crash the solver
+ }(new(D))
+
+ print(e.x1) // @pointsto main.a
+ print(e.x2) // @pointsto main.a
+ print(e.x3) // @pointsto main.a
+ print(e.x4) // @pointsto main.a
+ print(e.x5) // @pointsto main.a
+}
+
+func main() {
+ func1()
+ func2()
+ func3()
+ func4()
+ func5()
+ func6()
+ func7()
+ func8(1, 2, 3) // @line varargs
+ func9()
+}
+
+// @calls <root> -> main.main
+// @calls <root> -> main.init
diff --git a/go/pointer/testdata/funcreflect.go b/go/pointer/testdata/funcreflect.go
new file mode 100644
index 0000000..a0a9a5f
--- /dev/null
+++ b/go/pointer/testdata/funcreflect.go
@@ -0,0 +1,130 @@
+// +build ignore
+
+package main
+
+import "reflect"
+
+var zero, a, b int
+var false2 bool
+
+func f(p *int, q hasF) *int {
+ print(p) // @pointsto main.a
+ print(q) // @types *T
+ print(q.(*T)) // @pointsto new@newT1:22
+ return &b
+}
+
+func g(p *bool) (*int, *bool, hasF) {
+ return &b, p, new(T) // @line newT2
+}
+
+func reflectValueCall() {
+ rvf := reflect.ValueOf(f)
+ res := rvf.Call([]reflect.Value{
+ // argument order is not significant:
+ reflect.ValueOf(new(T)), // @line newT1
+ reflect.ValueOf(&a),
+ })
+ print(res[0].Interface()) // @types *int
+ print(res[0].Interface().(*int)) // @pointsto main.b
+}
+
+// @calls main.reflectValueCall -> main.f
+
+func reflectValueCallIndirect() {
+ rvf := reflect.ValueOf(g)
+ call := rvf.Call // kids, don't try this at home
+
+ // Indirect call uses shared contour.
+ //
+ // Also notice that argument position doesn't matter, and args
+ // of inappropriate type (e.g. 'a') are ignored.
+ res := call([]reflect.Value{
+ reflect.ValueOf(&a),
+ reflect.ValueOf(&false2),
+ })
+ res0 := res[0].Interface()
+ print(res0) // @types *int | *bool | *T
+ print(res0.(*int)) // @pointsto main.b
+ print(res0.(*bool)) // @pointsto main.false2
+ print(res0.(hasF)) // @types *T
+ print(res0.(*T)) // @pointsto new@newT2:19
+}
+
+// @calls main.reflectValueCallIndirect -> (reflect.Value).Call$bound
+// @calls (reflect.Value).Call$bound -> main.g
+
+func reflectTypeInOut() {
+ var f func(float64, bool) (string, int)
+ print(reflect.Zero(reflect.TypeOf(f).In(0)).Interface()) // @types float64
+ print(reflect.Zero(reflect.TypeOf(f).In(1)).Interface()) // @types bool
+ print(reflect.Zero(reflect.TypeOf(f).In(-1)).Interface()) // @types float64 | bool
+ print(reflect.Zero(reflect.TypeOf(f).In(zero)).Interface()) // @types float64 | bool
+
+ print(reflect.Zero(reflect.TypeOf(f).Out(0)).Interface()) // @types string
+ print(reflect.Zero(reflect.TypeOf(f).Out(1)).Interface()) // @types int
+ print(reflect.Zero(reflect.TypeOf(f).Out(2)).Interface()) // @types
+
+ print(reflect.Zero(reflect.TypeOf(3).Out(0)).Interface()) // @types
+}
+
+type hasF interface {
+ F()
+}
+
+type T struct{}
+
+func (T) F() {}
+func (T) g(int) {}
+
+type U struct{}
+
+func (U) F(int) {}
+func (U) g(string) {}
+
+type I interface {
+ f()
+}
+
+var nonconst string
+
+func reflectTypeMethodByName() {
+ TU := reflect.TypeOf([]interface{}{T{}, U{}}[0])
+ print(reflect.Zero(TU)) // @types T | U
+
+ F, _ := TU.MethodByName("F")
+ print(reflect.Zero(F.Type)) // @types func(T) | func(U, int)
+ print(F.Func) // @pointsto (main.T).F | (main.U).F
+
+ g, _ := TU.MethodByName("g")
+ print(reflect.Zero(g.Type)) // @types func(T, int) | func(U, string)
+ print(g.Func) // @pointsto (main.T).g | (main.U).g
+
+ // Non-literal method names are treated less precisely.
+ U := reflect.TypeOf(U{})
+ X, _ := U.MethodByName(nonconst)
+ print(reflect.Zero(X.Type)) // @types func(U, int) | func(U, string)
+ print(X.Func) // @pointsto (main.U).F | (main.U).g
+
+ // Interface methods.
+ rThasF := reflect.TypeOf(new(hasF)).Elem()
+ print(reflect.Zero(rThasF)) // @types hasF
+ F2, _ := rThasF.MethodByName("F")
+ print(reflect.Zero(F2.Type)) // @types func()
+ print(F2.Func) // @pointsto
+
+}
+
+func reflectTypeMethod() {
+ m := reflect.TypeOf(T{}).Method(0)
+ print(reflect.Zero(m.Type)) // @types func(T) | func(T, int)
+ print(m.Func) // @pointsto (main.T).F | (main.T).g
+}
+
+func main() {
+ reflectValueCall()
+ reflectValueCallIndirect()
+ reflectTypeInOut()
+ reflectTypeMethodByName()
+ reflectTypeMethod()
+}
diff --git a/go/pointer/testdata/hello.go b/go/pointer/testdata/hello.go
new file mode 100644
index 0000000..b81784b
--- /dev/null
+++ b/go/pointer/testdata/hello.go
@@ -0,0 +1,27 @@
+// +build ignore
+
+package main
+
+import (
+ "fmt"
+ "os"
+)
+
+type S int
+
+var theS S
+
+func (s *S) String() string {
+ print(s) // @pointsto main.theS
+ return ""
+}
+
+func main() {
+ // os.Args is considered intrinsically allocated,
+ // but may also be set explicitly (e.g. on Windows), hence '...'.
+ print(os.Args) // @pointsto <command-line args> | ...
+ fmt.Println("Hello, World!", &theS)
+}
+
+// @calls main.main -> fmt.Println
+// @calls (*fmt.pp).handleMethods -> (*main.S).String
diff --git a/go/pointer/testdata/interfaces.go b/go/pointer/testdata/interfaces.go
new file mode 100644
index 0000000..91c0fa9
--- /dev/null
+++ b/go/pointer/testdata/interfaces.go
@@ -0,0 +1,152 @@
+// +build ignore
+
+package main
+
+type I interface {
+ f()
+}
+
+type C int
+
+func (*C) f() {}
+
+type D struct{ ptr *int }
+
+func (D) f() {}
+
+type E struct{}
+
+func (*E) f() {}
+
+var a, b int
+
+var unknown bool // defeat dead-code elimination
+
+func interface1() {
+ var i interface{} = &a
+ var j interface{} = D{&b}
+ k := j
+ if unknown {
+ k = i
+ }
+
+ print(i) // @types *int
+ print(j) // @types D
+ print(k) // @types *int | D
+
+ print(i.(*int)) // @pointsto main.a
+ print(j.(*int)) // @pointsto
+ print(k.(*int)) // @pointsto main.a
+
+ print(i.(D).ptr) // @pointsto
+ print(j.(D).ptr) // @pointsto main.b
+ print(k.(D).ptr) // @pointsto main.b
+}
+
+func interface2() {
+ var i I = (*C)(&a)
+ var j I = D{&a}
+ k := j
+ if unknown {
+ k = i
+ }
+
+ print(i) // @types *C
+ print(j) // @types D
+ print(k) // @types *C | D
+ print(k) // @pointsto makeinterface:main.D | makeinterface:*main.C
+
+ k.f()
+ // @calls main.interface2 -> (*main.C).f
+ // @calls main.interface2 -> (main.D).f
+
+ print(i.(*C)) // @pointsto main.a
+ print(j.(D).ptr) // @pointsto main.a
+ print(k.(*C)) // @pointsto main.a
+
+ switch x := k.(type) {
+ case *C:
+ print(x) // @pointsto main.a
+ case D:
+ print(x.ptr) // @pointsto main.a
+ case *E:
+ print(x) // @pointsto
+ }
+}
+
+func interface3() {
+ // There should be no backflow of concrete types from the type-switch to x.
+ var x interface{} = 0
+ print(x) // @types int
+ switch x.(type) {
+ case int:
+ case string:
+ }
+}
+
+func interface4() {
+ var i interface{} = D{&a}
+ if unknown {
+ i = 123
+ }
+
+ print(i) // @types int | D
+
+ j := i.(I) // interface narrowing type-assertion
+ print(j) // @types D
+ print(j.(D).ptr) // @pointsto main.a
+
+ var l interface{} = j // interface widening assignment.
+ print(l) // @types D
+ print(l.(D).ptr) // @pointsto main.a
+
+ m := j.(interface{}) // interface widening type-assertion.
+ print(m) // @types D
+ print(m.(D).ptr) // @pointsto main.a
+}
+
+// Interface method calls and value flow:
+
+type J interface {
+ f(*int) *int
+}
+
+type P struct {
+ x int
+}
+
+func (p *P) f(pi *int) *int {
+ print(p) // @pointsto p@i5p:6
+ print(pi) // @pointsto i@i5i:6
+ return &p.x
+}
+
+func interface5() {
+ var p P // @line i5p
+ var j J = &p
+ var i int // @line i5i
+ print(j.f(&i)) // @pointsto p.x@i5p:6
+ print(&i) // @pointsto i@i5i:6
+
+ print(j) // @pointsto makeinterface:*main.P
+}
+
+// @calls main.interface5 -> (*main.P).f
+
+func interface6() {
+ f := I.f
+ print(f) // @pointsto (main.I).f$thunk
+ f(new(struct{ D }))
+}
+
+// @calls main.interface6 -> (main.I).f$thunk
+// @calls (main.I).f$thunk -> (*struct{main.D}).f
+
+func main() {
+ interface1()
+ interface2()
+ interface3()
+ interface4()
+ interface5()
+ interface6()
+}
diff --git a/go/pointer/testdata/issue9002.go b/go/pointer/testdata/issue9002.go
new file mode 100644
index 0000000..b7c2c61
--- /dev/null
+++ b/go/pointer/testdata/issue9002.go
@@ -0,0 +1,17 @@
+package main
+
+func main() {
+ // Regression test for golang issue 9002.
+ //
+ // The two-result "value,ok" receive operation generated a
+ // too-wide constraint loading (value int, ok bool), not bool,
+ // from the channel.
+ //
+ // This bug manifested itself in an out-of-bounds array access
+ // when the makechan object was the highest-numbered node, as in
+ // this program.
+ //
+ // In more realistic programs it silently resulted in bogus
+ // constraints.
+ _, _ = <-make(chan int)
+}
diff --git a/go/pointer/testdata/mapreflect.go b/go/pointer/testdata/mapreflect.go
new file mode 100644
index 0000000..bc5e7e6
--- /dev/null
+++ b/go/pointer/testdata/mapreflect.go
@@ -0,0 +1,117 @@
+// +build ignore
+
+package main
+
+// Test of maps with reflection.
+
+import "reflect"
+
+var a int
+var b bool
+
+func reflectMapKeysIndex() {
+ m := make(map[*int]*bool) // @line mr1make
+ m[&a] = &b
+
+ mrv := reflect.ValueOf(m)
+ print(mrv.Interface()) // @types map[*int]*bool
+ print(mrv.Interface().(map[*int]*bool)) // @pointsto makemap@mr1make:11
+ print(mrv) // @pointsto makeinterface:map[*int]*bool
+ print(mrv) // @types map[*int]*bool
+
+ keys := mrv.MapKeys()
+ print(keys) // @pointsto <alloc in (reflect.Value).MapKeys>
+ for _, k := range keys {
+ print(k) // @pointsto <alloc in (reflect.Value).MapKeys>
+ print(k) // @types *int
+ print(k.Interface()) // @types *int
+ print(k.Interface().(*int)) // @pointsto main.a
+
+ v := mrv.MapIndex(k)
+ print(v.Interface()) // @types *bool
+ print(v.Interface().(*bool)) // @pointsto main.b
+ }
+}
+
+func reflectSetMapIndex() {
+ m := make(map[*int]*bool)
+ mrv := reflect.ValueOf(m)
+ mrv.SetMapIndex(reflect.ValueOf(&a), reflect.ValueOf(&b))
+
+ print(m[nil]) // @pointsto main.b
+
+ for _, k := range mrv.MapKeys() {
+ print(k.Interface()) // @types *int
+ print(k.Interface().(*int)) // @pointsto main.a
+ }
+
+ tmap := reflect.TypeOf(m)
+ // types.EvalNode won't let us refer to non-exported types:
+ // print(tmap) // #@types *reflect.rtype
+ print(tmap) // @pointsto map[*int]*bool
+
+ zmap := reflect.Zero(tmap)
+ print(zmap) // @pointsto <alloc in reflect.Zero>
+ print(zmap.Interface()) // @pointsto <alloc in reflect.Zero>
+
+ print(tmap.Key()) // @pointsto *int
+ print(tmap.Elem()) // @pointsto *bool
+ print(reflect.Zero(tmap.Key())) // @pointsto <alloc in reflect.Zero>
+ print(reflect.Zero(tmap.Key()).Interface()) // @pointsto <alloc in reflect.Zero>
+ print(reflect.Zero(tmap.Key()).Interface()) // @types *int
+ print(reflect.Zero(tmap.Elem())) // @pointsto <alloc in reflect.Zero>
+ print(reflect.Zero(tmap.Elem()).Interface()) // @pointsto <alloc in reflect.Zero>
+ print(reflect.Zero(tmap.Elem()).Interface()) // @types *bool
+}
+
+func reflectSetMapIndexInterface() {
+ // Exercises reflect.Value conversions to/from interfaces:
+ // a different code path than for concrete types.
+ m := make(map[interface{}]interface{})
+ reflect.ValueOf(m).SetMapIndex(reflect.ValueOf(&a), reflect.ValueOf(&b))
+ for k, v := range m {
+ print(k) // @types *int
+ print(k.(*int)) // @pointsto main.a
+ print(v) // @types *bool
+ print(v.(*bool)) // @pointsto main.b
+ }
+}
+
+func reflectSetMapIndexAssignable() {
+ // SetMapIndex performs implicit assignability conversions.
+ type I *int
+ type J *int
+
+ str := reflect.ValueOf("")
+
+ // *int is assignable to I.
+ m1 := make(map[string]I)
+ reflect.ValueOf(m1).SetMapIndex(str, reflect.ValueOf(new(int))) // @line int
+ print(m1[""]) // @pointsto new@int:58
+
+ // I is assignable to I.
+ m2 := make(map[string]I)
+ reflect.ValueOf(m2).SetMapIndex(str, reflect.ValueOf(I(new(int)))) // @line I
+ print(m2[""]) // @pointsto new@I:60
+
+ // J is not assignable to I.
+ m3 := make(map[string]I)
+ reflect.ValueOf(m3).SetMapIndex(str, reflect.ValueOf(J(new(int))))
+ print(m3[""]) // @pointsto
+}
+
+func reflectMakeMap() {
+ t := reflect.TypeOf(map[*int]*bool(nil))
+ v := reflect.MakeMap(t)
+ print(v) // @types map[*int]*bool
+ print(v) // @pointsto <alloc in reflect.MakeMap>
+}
+
+func main() {
+ reflectMapKeysIndex()
+ reflectSetMapIndex()
+ reflectSetMapIndexInterface()
+ reflectSetMapIndexAssignable()
+ reflectMakeMap()
+ // TODO(adonovan): reflect.MapOf(Type)
+}
diff --git a/go/pointer/testdata/maps.go b/go/pointer/testdata/maps.go
new file mode 100644
index 0000000..6f3751d
--- /dev/null
+++ b/go/pointer/testdata/maps.go
@@ -0,0 +1,51 @@
+// +build ignore
+
+package main
+
+// Test of maps.
+
+var a, b, c int
+
+func maps1() {
+ m1 := map[*int]*int{&a: &b} // @line m1m1
+ m2 := make(map[*int]*int) // @line m1m2
+ m2[&b] = &a
+
+ print(m1[nil]) // @pointsto main.b | main.c
+ print(m2[nil]) // @pointsto main.a
+
+ print(m1) // @pointsto makemap@m1m1:21
+ print(m2) // @pointsto makemap@m1m2:12
+
+ m1[&b] = &c
+
+ for k, v := range m1 {
+ print(k) // @pointsto main.a | main.b
+ print(v) // @pointsto main.b | main.c
+ }
+
+ for k, v := range m2 {
+ print(k) // @pointsto main.b
+ print(v) // @pointsto main.a
+ }
+
+ // Lookup doesn't create any aliases.
+ print(m2[&c]) // @pointsto main.a
+ if _, ok := m2[&a]; ok {
+ print(m2[&c]) // @pointsto main.a
+ }
+}
+
+func maps2() {
+ m1 := map[*int]*int{&a: &b}
+ m2 := map[*int]*int{&b: &c}
+ _ = []map[*int]*int{m1, m2} // (no spurious merging of m1, m2)
+
+ print(m1[nil]) // @pointsto main.b
+ print(m2[nil]) // @pointsto main.c
+}
+
+func main() {
+ maps1()
+ maps2()
+}
diff --git a/go/pointer/testdata/panic.go b/go/pointer/testdata/panic.go
new file mode 100644
index 0000000..ee8a766
--- /dev/null
+++ b/go/pointer/testdata/panic.go
@@ -0,0 +1,36 @@
+// +build ignore
+
+package main
+
+// Test of value flow from panic() to recover().
+// We model them as stores/loads of a global location.
+// We ignore concrete panic types originating from the runtime.
+
+var someval int
+
+type myPanic struct{}
+
+func f(int) {}
+
+func g() string { return "" }
+
+func deadcode() {
+ panic(123) // not reached
+}
+
+func main() {
+ switch someval {
+ case 0:
+ panic("oops")
+ case 1:
+ panic(myPanic{})
+ case 2:
+ panic(f)
+ case 3:
+ panic(g)
+ }
+ ex := recover()
+ print(ex) // @types myPanic | string | func(int) | func() string
+ print(ex.(func(int))) // @pointsto main.f
+ print(ex.(func() string)) // @pointsto main.g
+}
diff --git a/go/pointer/testdata/recur.go b/go/pointer/testdata/recur.go
new file mode 100644
index 0000000..4c7229d
--- /dev/null
+++ b/go/pointer/testdata/recur.go
@@ -0,0 +1,11 @@
+// +build ignore
+
+package main
+
+// Analysis abstraction of recursive calls is finite.
+
+func main() {
+ main()
+}
+
+// @calls main.main -> main.main
diff --git a/go/pointer/testdata/reflect.go b/go/pointer/testdata/reflect.go
new file mode 100644
index 0000000..6b8d0f2
--- /dev/null
+++ b/go/pointer/testdata/reflect.go
@@ -0,0 +1,115 @@
+// +build ignore
+
+package main
+
+import "reflect"
+import "unsafe"
+
+var a, b int
+var unknown bool
+
+func reflectIndirect() {
+ ptr := &a
+ // Pointer:
+ print(reflect.Indirect(reflect.ValueOf(&ptr)).Interface().(*int)) // @pointsto main.a
+ // Non-pointer:
+ print(reflect.Indirect(reflect.ValueOf([]*int{ptr})).Interface().([]*int)[0]) // @pointsto main.a
+}
+
+func reflectNewAt() {
+ var x [8]byte
+ print(reflect.NewAt(reflect.TypeOf(3), unsafe.Pointer(&x)).Interface()) // @types *int
+}
+
+// @warning "unsound: main.reflectNewAt contains a reflect.NewAt.. call"
+
+func reflectTypeOf() {
+ t := reflect.TypeOf(3)
+ if unknown {
+ t = reflect.TypeOf("foo")
+ }
+ // TODO(adonovan): make types.Eval let us refer to unexported types.
+ print(t) // #@types *reflect.rtype
+ print(reflect.Zero(t).Interface()) // @types int | string
+ newint := reflect.New(t).Interface() // @line rtonew
+ print(newint) // @types *int | *string
+ print(newint.(*int)) // @pointsto <alloc in reflect.New>
+ print(newint.(*string)) // @pointsto <alloc in reflect.New>
+}
+
+func reflectTypeElem() {
+ print(reflect.Zero(reflect.TypeOf(&a).Elem()).Interface()) // @types int
+ print(reflect.Zero(reflect.TypeOf([]string{}).Elem()).Interface()) // @types string
+ print(reflect.Zero(reflect.TypeOf(make(chan bool)).Elem()).Interface()) // @types bool
+ print(reflect.Zero(reflect.TypeOf(make(map[string]float64)).Elem()).Interface()) // @types float64
+ print(reflect.Zero(reflect.TypeOf([3]complex64{}).Elem()).Interface()) // @types complex64
+ print(reflect.Zero(reflect.TypeOf(3).Elem()).Interface()) // @types
+ print(reflect.Zero(reflect.TypeOf(new(interface{})).Elem())) // @types interface{}
+ print(reflect.Zero(reflect.TypeOf(new(interface{})).Elem()).Interface()) // @types
+}
+
+// reflect.Values within reflect.Values.
+func metareflection() {
+ // "box" a *int twice, unbox it twice.
+ v0 := reflect.ValueOf(&a)
+ print(v0) // @types *int
+ v1 := reflect.ValueOf(v0) // box
+ print(v1) // @types reflect.Value
+ v2 := reflect.ValueOf(v1) // box
+ print(v2) // @types reflect.Value
+ v1a := v2.Interface().(reflect.Value) // unbox
+ print(v1a) // @types reflect.Value
+ v0a := v1a.Interface().(reflect.Value) // unbox
+ print(v0a) // @types *int
+ print(v0a.Interface().(*int)) // @pointsto main.a
+
+ // "box" an interface{} lvalue twice, unbox it twice.
+ var iface interface{} = 3
+ x0 := reflect.ValueOf(&iface).Elem()
+ print(x0) // @types interface{}
+ x1 := reflect.ValueOf(x0) // box
+ print(x1) // @types reflect.Value
+ x2 := reflect.ValueOf(x1) // box
+ print(x2) // @types reflect.Value
+ x1a := x2.Interface().(reflect.Value) // unbox
+ print(x1a) // @types reflect.Value
+ x0a := x1a.Interface().(reflect.Value) // unbox
+ print(x0a) // @types interface{}
+ print(x0a.Interface()) // @types int
+}
+
+type T struct{}
+
+// When the output of a type constructor flows to its input, we must
+// bound the set of types created to ensure termination of the algorithm.
+func typeCycle() {
+ t := reflect.TypeOf(0)
+ u := reflect.TypeOf("")
+ v := reflect.TypeOf(T{})
+ for unknown {
+ t = reflect.PtrTo(t)
+ t = reflect.SliceOf(t)
+
+ u = reflect.SliceOf(u)
+
+ if unknown {
+ v = reflect.ChanOf(reflect.BothDir, v)
+ } else {
+ v = reflect.PtrTo(v)
+ }
+ }
+
+ // Type height is bounded to about 4 map/slice/chan/pointer constructors.
+ print(reflect.Zero(t).Interface()) // @types int | []*int | []*[]*int
+ print(reflect.Zero(u).Interface()) // @types string | []string | [][]string | [][][]string | [][][][]string
+ print(reflect.Zero(v).Interface()) // @types T | *T | **T | ***T | ****T | chan T | *chan T | **chan T | chan *T | *chan *T | chan **T | chan ***T | chan chan T | chan *chan T | chan chan *T
+}
+
+func main() {
+ reflectIndirect()
+ reflectNewAt()
+ reflectTypeOf()
+ reflectTypeElem()
+ metareflection()
+ typeCycle()
+}
diff --git a/go/pointer/testdata/rtti.go b/go/pointer/testdata/rtti.go
new file mode 100644
index 0000000..826936d
--- /dev/null
+++ b/go/pointer/testdata/rtti.go
@@ -0,0 +1,29 @@
+package main
+
+// Regression test for oracle crash
+// https://code.google.com/p/go/issues/detail?id=6605
+//
+// Using reflection, methods may be called on types that are not the
+// operand of any ssa.MakeInterface instruction. In this example,
+// (Y).F is called by deriving the type Y from *Y. Prior to the fix,
+// no RTTI (or method set) for type Y was included in the program, so
+// the F() call would crash.
+
+import "reflect"
+
+var a int
+
+type X struct{}
+
+func (X) F() *int {
+ return &a
+}
+
+type I interface {
+ F() *int
+}
+
+func main() {
+ type Y struct{ X }
+ print(reflect.Indirect(reflect.ValueOf(new(Y))).Interface().(I).F()) // @pointsto main.a
+}
diff --git a/go/pointer/testdata/structreflect.go b/go/pointer/testdata/structreflect.go
new file mode 100644
index 0000000..9fb49f5
--- /dev/null
+++ b/go/pointer/testdata/structreflect.go
@@ -0,0 +1,45 @@
+// +build ignore
+
+package main
+
+import "reflect"
+
+type A struct {
+ f *int
+ g interface{}
+ h bool
+}
+
+var dyn string
+
+func reflectTypeFieldByName() {
+ f, _ := reflect.TypeOf(A{}).FieldByName("f")
+ print(f.Type) // @pointsto *int
+
+ g, _ := reflect.TypeOf(A{}).FieldByName("g")
+ print(g.Type) // @pointsto interface{}
+ print(reflect.Zero(g.Type)) // @pointsto <alloc in reflect.Zero>
+ print(reflect.Zero(g.Type)) // @types interface{}
+
+ print(reflect.Zero(g.Type).Interface()) // @pointsto
+ print(reflect.Zero(g.Type).Interface()) // @types
+
+ h, _ := reflect.TypeOf(A{}).FieldByName("h")
+ print(h.Type) // @pointsto bool
+
+ missing, _ := reflect.TypeOf(A{}).FieldByName("missing")
+ print(missing.Type) // @pointsto
+
+ dyn, _ := reflect.TypeOf(A{}).FieldByName(dyn)
+ print(dyn.Type) // @pointsto *int | bool | interface{}
+}
+
+func reflectTypeField() {
+ fld := reflect.TypeOf(A{}).Field(0)
+ print(fld.Type) // @pointsto *int | bool | interface{}
+}
+
+func main() {
+ reflectTypeFieldByName()
+ reflectTypeField()
+}
diff --git a/go/pointer/testdata/structs.go b/go/pointer/testdata/structs.go
new file mode 100644
index 0000000..9036d60
--- /dev/null
+++ b/go/pointer/testdata/structs.go
@@ -0,0 +1,100 @@
+// +build ignore
+
+package main
+
+var unknown bool // defeat dead-code elimination
+
+var p, q int
+
+type A struct {
+ f *int
+ g interface{}
+}
+
+func (a A) m1() {
+ print(a.f) // @pointsto main.p
+}
+
+func (a *A) m2() {
+ print(a) // @pointsto complit.A@struct1s:9
+ print(a.f) // @pointsto main.p
+}
+
+type B struct {
+ h *int
+ A
+}
+
+func structs1() {
+ b := &B{ // @line struct1s
+ h: &q,
+ }
+ b.f = &p
+ b.g = b
+
+ print(b.h) // @pointsto main.q
+ print(b.f) // @pointsto main.p
+ print(b.g) // @types *B
+
+ ptr := &b.f
+ print(*ptr) // @pointsto main.p
+
+ b.m1()
+ b.m2()
+}
+
+// @calls main.structs1 -> (main.A).m1
+// @calls main.structs1 -> (*main.A).m2
+// @calls (*main.B).m1 -> (main.A).m1
+// @calls (*main.B).m2 -> (*main.A).m2
+
+type T struct {
+ x int
+ y int
+}
+
+type S struct {
+ a [3]T
+ b *[3]T
+ c [3]*T
+}
+
+func structs2() {
+ var s S // @line s2s
+ print(&s) // @pointsto s@s2s:6
+ print(&s.a) // @pointsto s.a@s2s:6
+ print(&s.a[0]) // @pointsto s.a[*]@s2s:6
+ print(&s.a[0].x) // @pointsto s.a[*].x@s2s:6
+ print(&s.a[0].y) // @pointsto s.a[*].y@s2s:6
+ print(&s.b) // @pointsto s.b@s2s:6
+ print(&s.b[0]) // @pointsto
+ print(&s.b[0].x) // @pointsto
+ print(&s.b[0].y) // @pointsto
+ print(&s.c) // @pointsto s.c@s2s:6
+ print(&s.c[0]) // @pointsto s.c[*]@s2s:6
+ print(&s.c[0].x) // @pointsto
+ print(&s.c[0].y) // @pointsto
+
+ var s2 S // @line s2s2
+ s2.b = new([3]T) // @line s2s2b
+ print(s2.b) // @pointsto new@s2s2b:12
+ print(&s2.b) // @pointsto s2.b@s2s2:6
+ print(&s2.b[0]) // @pointsto new[*]@s2s2b:12
+ print(&s2.b[0].x) // @pointsto new[*].x@s2s2b:12
+ print(&s2.b[0].y) // @pointsto new[*].y@s2s2b:12
+ print(&s2.c[0].x) // @pointsto
+ print(&s2.c[0].y) // @pointsto
+
+ var s3 S // @line s2s3
+ s3.c[2] = new(T) // @line s2s3c
+ print(&s3.c) // @pointsto s3.c@s2s3:6
+ print(s3.c[1]) // @pointsto new@s2s3c:15
+ print(&s3.c[1]) // @pointsto s3.c[*]@s2s3:6
+ print(&s3.c[1].x) // @pointsto new.x@s2s3c:15
+ print(&s3.c[1].y) // @pointsto new.y@s2s3c:15
+}
+
+func main() {
+ structs1()
+ structs2()
+}
diff --git a/go/pointer/testdata/timer.go b/go/pointer/testdata/timer.go
new file mode 100644
index 0000000..465d081
--- /dev/null
+++ b/go/pointer/testdata/timer.go
@@ -0,0 +1,24 @@
+// +build ignore
+
+package main
+
+import "time"
+
+func after() {}
+
+func main() {
+ // @calls time.startTimer -> time.sendTime
+ ticker := time.NewTicker(1)
+ <-ticker.C
+
+ // @calls time.startTimer -> time.sendTime
+ timer := time.NewTimer(time.Second)
+ <-timer.C
+
+ // @calls time.startTimer -> time.goFunc
+ // @calls time.goFunc -> main.after
+ timer = time.AfterFunc(time.Second, after)
+ <-timer.C
+}
+
+// @calls time.sendTime -> time.Now
diff --git a/go/pointer/util.go b/go/pointer/util.go
new file mode 100644
index 0000000..d4ccbb5
--- /dev/null
+++ b/go/pointer/util.go
@@ -0,0 +1,314 @@
+// 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 pointer
+
+import (
+ "bytes"
+ "fmt"
+ "log"
+ "os"
+ "os/exec"
+ "runtime"
+ "time"
+
+ "golang.org/x/tools/container/intsets"
+ "golang.org/x/tools/go/types"
+)
+
+// CanPoint reports whether the type T is pointerlike,
+// for the purposes of this analysis.
+func CanPoint(T types.Type) bool {
+ switch T := T.(type) {
+ case *types.Named:
+ if obj := T.Obj(); obj.Name() == "Value" && obj.Pkg().Path() == "reflect" {
+ return true // treat reflect.Value like interface{}
+ }
+ return CanPoint(T.Underlying())
+
+ case *types.Pointer, *types.Interface, *types.Map, *types.Chan, *types.Signature, *types.Slice:
+ return true
+ }
+
+ return false // array struct tuple builtin basic
+}
+
+// CanHaveDynamicTypes reports whether the type T can "hold" dynamic types,
+// i.e. is an interface (incl. reflect.Type) or a reflect.Value.
+//
+func CanHaveDynamicTypes(T types.Type) bool {
+ switch T := T.(type) {
+ case *types.Named:
+ if obj := T.Obj(); obj.Name() == "Value" && obj.Pkg().Path() == "reflect" {
+ return true // reflect.Value
+ }
+ return CanHaveDynamicTypes(T.Underlying())
+ case *types.Interface:
+ return true
+ }
+ return false
+}
+
+func isInterface(T types.Type) bool { return types.IsInterface(T) }
+
+// mustDeref returns the element type of its argument, which must be a
+// pointer; panic ensues otherwise.
+func mustDeref(typ types.Type) types.Type {
+ return typ.Underlying().(*types.Pointer).Elem()
+}
+
+// deref returns a pointer's element type; otherwise it returns typ.
+func deref(typ types.Type) types.Type {
+ if p, ok := typ.Underlying().(*types.Pointer); ok {
+ return p.Elem()
+ }
+ return typ
+}
+
+// A fieldInfo describes one subelement (node) of the flattening-out
+// of a type T: the subelement's type and its path from the root of T.
+//
+// For example, for this type:
+// type line struct{ points []struct{x, y int} }
+// flatten() of the inner struct yields the following []fieldInfo:
+// struct{ x, y int } ""
+// int ".x"
+// int ".y"
+// and flatten(line) yields:
+// struct{ points []struct{x, y int} } ""
+// struct{ x, y int } ".points[*]"
+// int ".points[*].x
+// int ".points[*].y"
+//
+type fieldInfo struct {
+ typ types.Type
+
+ // op and tail describe the path to the element (e.g. ".a#2.b[*].c").
+ op interface{} // *Array: true; *Tuple: int; *Struct: *types.Var; *Named: nil
+ tail *fieldInfo
+}
+
+// path returns a user-friendly string describing the subelement path.
+//
+func (fi *fieldInfo) path() string {
+ var buf bytes.Buffer
+ for p := fi; p != nil; p = p.tail {
+ switch op := p.op.(type) {
+ case bool:
+ fmt.Fprintf(&buf, "[*]")
+ case int:
+ fmt.Fprintf(&buf, "#%d", op)
+ case *types.Var:
+ fmt.Fprintf(&buf, ".%s", op.Name())
+ }
+ }
+ return buf.String()
+}
+
+// flatten returns a list of directly contained fields in the preorder
+// traversal of the type tree of t. The resulting elements are all
+// scalars (basic types or pointerlike types), except for struct/array
+// "identity" nodes, whose type is that of the aggregate.
+//
+// reflect.Value is considered pointerlike, similar to interface{}.
+//
+// Callers must not mutate the result.
+//
+func (a *analysis) flatten(t types.Type) []*fieldInfo {
+ fl, ok := a.flattenMemo[t]
+ if !ok {
+ switch t := t.(type) {
+ case *types.Named:
+ u := t.Underlying()
+ if isInterface(u) {
+ // Debuggability hack: don't remove
+ // the named type from interfaces as
+ // they're very verbose.
+ fl = append(fl, &fieldInfo{typ: t})
+ } else {
+ fl = a.flatten(u)
+ }
+
+ case *types.Basic,
+ *types.Signature,
+ *types.Chan,
+ *types.Map,
+ *types.Interface,
+ *types.Slice,
+ *types.Pointer:
+ fl = append(fl, &fieldInfo{typ: t})
+
+ case *types.Array:
+ fl = append(fl, &fieldInfo{typ: t}) // identity node
+ for _, fi := range a.flatten(t.Elem()) {
+ fl = append(fl, &fieldInfo{typ: fi.typ, op: true, tail: fi})
+ }
+
+ case *types.Struct:
+ fl = append(fl, &fieldInfo{typ: t}) // identity node
+ for i, n := 0, t.NumFields(); i < n; i++ {
+ f := t.Field(i)
+ for _, fi := range a.flatten(f.Type()) {
+ fl = append(fl, &fieldInfo{typ: fi.typ, op: f, tail: fi})
+ }
+ }
+
+ case *types.Tuple:
+ // No identity node: tuples are never address-taken.
+ n := t.Len()
+ if n == 1 {
+ // Don't add a fieldInfo link for singletons,
+ // e.g. in params/results.
+ fl = append(fl, a.flatten(t.At(0).Type())...)
+ } else {
+ for i := 0; i < n; i++ {
+ f := t.At(i)
+ for _, fi := range a.flatten(f.Type()) {
+ fl = append(fl, &fieldInfo{typ: fi.typ, op: i, tail: fi})
+ }
+ }
+ }
+
+ default:
+ panic(t)
+ }
+
+ a.flattenMemo[t] = fl
+ }
+
+ return fl
+}
+
+// sizeof returns the number of pointerlike abstractions (nodes) in the type t.
+func (a *analysis) sizeof(t types.Type) uint32 {
+ return uint32(len(a.flatten(t)))
+}
+
+// shouldTrack reports whether object type T contains (recursively)
+// any fields whose addresses should be tracked.
+func (a *analysis) shouldTrack(T types.Type) bool {
+ if a.track == trackAll {
+ return true // fast path
+ }
+ track, ok := a.trackTypes[T]
+ if !ok {
+ a.trackTypes[T] = true // break cycles conservatively
+ // NB: reflect.Value, reflect.Type are pre-populated to true.
+ for _, fi := range a.flatten(T) {
+ switch ft := fi.typ.Underlying().(type) {
+ case *types.Interface, *types.Signature:
+ track = true // needed for callgraph
+ case *types.Basic:
+ // no-op
+ case *types.Chan:
+ track = a.track&trackChan != 0 || a.shouldTrack(ft.Elem())
+ case *types.Map:
+ track = a.track&trackMap != 0 || a.shouldTrack(ft.Key()) || a.shouldTrack(ft.Elem())
+ case *types.Slice:
+ track = a.track&trackSlice != 0 || a.shouldTrack(ft.Elem())
+ case *types.Pointer:
+ track = a.track&trackPtr != 0 || a.shouldTrack(ft.Elem())
+ case *types.Array, *types.Struct:
+ // No need to look at field types since they will follow (flattened).
+ default:
+ // Includes *types.Tuple, which are never address-taken.
+ panic(ft)
+ }
+ if track {
+ break
+ }
+ }
+ a.trackTypes[T] = track
+ if !track && a.log != nil {
+ fmt.Fprintf(a.log, "\ttype not tracked: %s\n", T)
+ }
+ }
+ return track
+}
+
+// offsetOf returns the (abstract) offset of field index within struct
+// or tuple typ.
+func (a *analysis) offsetOf(typ types.Type, index int) uint32 {
+ var offset uint32
+ switch t := typ.Underlying().(type) {
+ case *types.Tuple:
+ for i := 0; i < index; i++ {
+ offset += a.sizeof(t.At(i).Type())
+ }
+ case *types.Struct:
+ offset++ // the node for the struct itself
+ for i := 0; i < index; i++ {
+ offset += a.sizeof(t.Field(i).Type())
+ }
+ default:
+ panic(fmt.Sprintf("offsetOf(%s : %T)", typ, typ))
+ }
+ return offset
+}
+
+// sliceToArray returns the type representing the arrays to which
+// slice type slice points.
+func sliceToArray(slice types.Type) *types.Array {
+ return types.NewArray(slice.Underlying().(*types.Slice).Elem(), 1)
+}
+
+// Node set -------------------------------------------------------------------
+
+type nodeset struct {
+ intsets.Sparse
+}
+
+func (ns *nodeset) String() string {
+ var buf bytes.Buffer
+ buf.WriteRune('{')
+ var space [50]int
+ for i, n := range ns.AppendTo(space[:0]) {
+ if i > 0 {
+ buf.WriteString(", ")
+ }
+ buf.WriteRune('n')
+ fmt.Fprintf(&buf, "%d", n)
+ }
+ buf.WriteRune('}')
+ return buf.String()
+}
+
+func (ns *nodeset) add(n nodeid) bool {
+ return ns.Sparse.Insert(int(n))
+}
+
+func (x *nodeset) addAll(y *nodeset) bool {
+ return x.UnionWith(&y.Sparse)
+}
+
+// Profiling & debugging -------------------------------------------------------
+
+var timers = make(map[string]time.Time)
+
+func start(name string) {
+ if debugTimers {
+ timers[name] = time.Now()
+ log.Printf("%s...\n", name)
+ }
+}
+
+func stop(name string) {
+ if debugTimers {
+ log.Printf("%s took %s\n", name, time.Since(timers[name]))
+ }
+}
+
+// diff runs the command "diff a b" and reports its success.
+func diff(a, b string) bool {
+ var cmd *exec.Cmd
+ switch runtime.GOOS {
+ case "plan9":
+ cmd = exec.Command("/bin/diff", "-c", a, b)
+ default:
+ cmd = exec.Command("/usr/bin/diff", "-u", a, b)
+ }
+ cmd.Stdout = os.Stderr
+ cmd.Stderr = os.Stderr
+ return cmd.Run() == nil
+}
diff --git a/go/ssa/blockopt.go b/go/ssa/blockopt.go
new file mode 100644
index 0000000..e79260a
--- /dev/null
+++ b/go/ssa/blockopt.go
@@ -0,0 +1,187 @@
+// 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 ssa
+
+// Simple block optimizations to simplify the control flow graph.
+
+// TODO(adonovan): opt: instead of creating several "unreachable" blocks
+// per function in the Builder, reuse a single one (e.g. at Blocks[1])
+// to reduce garbage.
+
+import (
+ "fmt"
+ "os"
+)
+
+// If true, perform sanity checking and show progress at each
+// successive iteration of optimizeBlocks. Very verbose.
+const debugBlockOpt = false
+
+// markReachable sets Index=-1 for all blocks reachable from b.
+func markReachable(b *BasicBlock) {
+ b.Index = -1
+ for _, succ := range b.Succs {
+ if succ.Index == 0 {
+ markReachable(succ)
+ }
+ }
+}
+
+// deleteUnreachableBlocks marks all reachable blocks of f and
+// eliminates (nils) all others, including possibly cyclic subgraphs.
+//
+func deleteUnreachableBlocks(f *Function) {
+ const white, black = 0, -1
+ // We borrow b.Index temporarily as the mark bit.
+ for _, b := range f.Blocks {
+ b.Index = white
+ }
+ markReachable(f.Blocks[0])
+ if f.Recover != nil {
+ markReachable(f.Recover)
+ }
+ for i, b := range f.Blocks {
+ if b.Index == white {
+ for _, c := range b.Succs {
+ if c.Index == black {
+ c.removePred(b) // delete white->black edge
+ }
+ }
+ if debugBlockOpt {
+ fmt.Fprintln(os.Stderr, "unreachable", b)
+ }
+ f.Blocks[i] = nil // delete b
+ }
+ }
+ f.removeNilBlocks()
+}
+
+// jumpThreading attempts to apply simple jump-threading to block b,
+// in which a->b->c become a->c if b is just a Jump.
+// The result is true if the optimization was applied.
+//
+func jumpThreading(f *Function, b *BasicBlock) bool {
+ if b.Index == 0 {
+ return false // don't apply to entry block
+ }
+ if b.Instrs == nil {
+ return false
+ }
+ if _, ok := b.Instrs[0].(*Jump); !ok {
+ return false // not just a jump
+ }
+ c := b.Succs[0]
+ if c == b {
+ return false // don't apply to degenerate jump-to-self.
+ }
+ if c.hasPhi() {
+ return false // not sound without more effort
+ }
+ for j, a := range b.Preds {
+ a.replaceSucc(b, c)
+
+ // If a now has two edges to c, replace its degenerate If by Jump.
+ if len(a.Succs) == 2 && a.Succs[0] == c && a.Succs[1] == c {
+ jump := new(Jump)
+ jump.setBlock(a)
+ a.Instrs[len(a.Instrs)-1] = jump
+ a.Succs = a.Succs[:1]
+ c.removePred(b)
+ } else {
+ if j == 0 {
+ c.replacePred(b, a)
+ } else {
+ c.Preds = append(c.Preds, a)
+ }
+ }
+
+ if debugBlockOpt {
+ fmt.Fprintln(os.Stderr, "jumpThreading", a, b, c)
+ }
+ }
+ f.Blocks[b.Index] = nil // delete b
+ return true
+}
+
+// fuseBlocks attempts to apply the block fusion optimization to block
+// a, in which a->b becomes ab if len(a.Succs)==len(b.Preds)==1.
+// The result is true if the optimization was applied.
+//
+func fuseBlocks(f *Function, a *BasicBlock) bool {
+ if len(a.Succs) != 1 {
+ return false
+ }
+ b := a.Succs[0]
+ if len(b.Preds) != 1 {
+ return false
+ }
+
+ // Degenerate &&/|| ops may result in a straight-line CFG
+ // containing φ-nodes. (Ideally we'd replace such them with
+ // their sole operand but that requires Referrers, built later.)
+ if b.hasPhi() {
+ return false // not sound without further effort
+ }
+
+ // Eliminate jump at end of A, then copy all of B across.
+ a.Instrs = append(a.Instrs[:len(a.Instrs)-1], b.Instrs...)
+ for _, instr := range b.Instrs {
+ instr.setBlock(a)
+ }
+
+ // A inherits B's successors
+ a.Succs = append(a.succs2[:0], b.Succs...)
+
+ // Fix up Preds links of all successors of B.
+ for _, c := range b.Succs {
+ c.replacePred(b, a)
+ }
+
+ if debugBlockOpt {
+ fmt.Fprintln(os.Stderr, "fuseBlocks", a, b)
+ }
+
+ f.Blocks[b.Index] = nil // delete b
+ return true
+}
+
+// optimizeBlocks() performs some simple block optimizations on a
+// completed function: dead block elimination, block fusion, jump
+// threading.
+//
+func optimizeBlocks(f *Function) {
+ deleteUnreachableBlocks(f)
+
+ // Loop until no further progress.
+ changed := true
+ for changed {
+ changed = false
+
+ if debugBlockOpt {
+ f.WriteTo(os.Stderr)
+ mustSanityCheck(f, nil)
+ }
+
+ for _, b := range f.Blocks {
+ // f.Blocks will temporarily contain nils to indicate
+ // deleted blocks; we remove them at the end.
+ if b == nil {
+ continue
+ }
+
+ // Fuse blocks. b->c becomes bc.
+ if fuseBlocks(f, b) {
+ changed = true
+ }
+
+ // a->b->c becomes a->c if b contains only a Jump.
+ if jumpThreading(f, b) {
+ changed = true
+ continue // (b was disconnected)
+ }
+ }
+ }
+ f.removeNilBlocks()
+}
diff --git a/go/ssa/builder.go b/go/ssa/builder.go
new file mode 100644
index 0000000..5b8ce0e
--- /dev/null
+++ b/go/ssa/builder.go
@@ -0,0 +1,2370 @@
+// 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 ssa
+
+// This file implements the BUILD phase of SSA construction.
+//
+// SSA construction has two phases, CREATE and BUILD. In the CREATE phase
+// (create.go), all packages are constructed and type-checked and
+// definitions of all package members are created, method-sets are
+// computed, and wrapper methods are synthesized.
+// ssa.Packages are created in arbitrary order.
+//
+// In the BUILD phase (builder.go), the builder traverses the AST of
+// each Go source function and generates SSA instructions for the
+// function body. Initializer expressions for package-level variables
+// are emitted to the package's init() function in the order specified
+// by go/types.Info.InitOrder, then code for each function in the
+// package is generated in lexical order.
+// The BUILD phases for distinct packages are independent and are
+// executed in parallel.
+//
+// TODO(adonovan): indeed, building functions is now embarrassingly parallel.
+// Audit for concurrency then benchmark using more goroutines.
+//
+// The builder's and Program's indices (maps) are populated and
+// mutated during the CREATE phase, but during the BUILD phase they
+// remain constant. The sole exception is Prog.methodSets and its
+// related maps, which are protected by a dedicated mutex.
+
+import (
+ "fmt"
+ "go/ast"
+ "go/token"
+ "os"
+ "sync"
+ "sync/atomic"
+
+ "golang.org/x/tools/go/exact"
+ "golang.org/x/tools/go/types"
+)
+
+type opaqueType struct {
+ types.Type
+ name string
+}
+
+func (t *opaqueType) String() string { return t.name }
+
+var (
+ varOk = newVar("ok", tBool)
+ varIndex = newVar("index", tInt)
+
+ // Type constants.
+ tBool = types.Typ[types.Bool]
+ tByte = types.Typ[types.Byte]
+ tInt = types.Typ[types.Int]
+ tInvalid = types.Typ[types.Invalid]
+ tString = types.Typ[types.String]
+ tUntypedNil = types.Typ[types.UntypedNil]
+ tRangeIter = &opaqueType{nil, "iter"} // the type of all "range" iterators
+ tEface = new(types.Interface)
+
+ // SSA Value constants.
+ vZero = intConst(0)
+ vOne = intConst(1)
+ vTrue = NewConst(exact.MakeBool(true), tBool)
+)
+
+// builder holds state associated with the package currently being built.
+// Its methods contain all the logic for AST-to-SSA conversion.
+type builder struct{}
+
+// cond emits to fn code to evaluate boolean condition e and jump
+// to t or f depending on its value, performing various simplifications.
+//
+// Postcondition: fn.currentBlock is nil.
+//
+func (b *builder) cond(fn *Function, e ast.Expr, t, f *BasicBlock) {
+ switch e := e.(type) {
+ case *ast.ParenExpr:
+ b.cond(fn, e.X, t, f)
+ return
+
+ case *ast.BinaryExpr:
+ switch e.Op {
+ case token.LAND:
+ ltrue := fn.newBasicBlock("cond.true")
+ b.cond(fn, e.X, ltrue, f)
+ fn.currentBlock = ltrue
+ b.cond(fn, e.Y, t, f)
+ return
+
+ case token.LOR:
+ lfalse := fn.newBasicBlock("cond.false")
+ b.cond(fn, e.X, t, lfalse)
+ fn.currentBlock = lfalse
+ b.cond(fn, e.Y, t, f)
+ return
+ }
+
+ case *ast.UnaryExpr:
+ if e.Op == token.NOT {
+ b.cond(fn, e.X, f, t)
+ return
+ }
+ }
+
+ // A traditional compiler would simplify "if false" (etc) here
+ // but we do not, for better fidelity to the source code.
+ //
+ // The value of a constant condition may be platform-specific,
+ // and may cause blocks that are reachable in some configuration
+ // to be hidden from subsequent analyses such as bug-finding tools.
+ emitIf(fn, b.expr(fn, e), t, f)
+}
+
+// logicalBinop emits code to fn to evaluate e, a &&- or
+// ||-expression whose reified boolean value is wanted.
+// The value is returned.
+//
+func (b *builder) logicalBinop(fn *Function, e *ast.BinaryExpr) Value {
+ rhs := fn.newBasicBlock("binop.rhs")
+ done := fn.newBasicBlock("binop.done")
+
+ // T(e) = T(e.X) = T(e.Y) after untyped constants have been
+ // eliminated.
+ // TODO(adonovan): not true; MyBool==MyBool yields UntypedBool.
+ t := fn.Pkg.typeOf(e)
+
+ var short Value // value of the short-circuit path
+ switch e.Op {
+ case token.LAND:
+ b.cond(fn, e.X, rhs, done)
+ short = NewConst(exact.MakeBool(false), t)
+
+ case token.LOR:
+ b.cond(fn, e.X, done, rhs)
+ short = NewConst(exact.MakeBool(true), t)
+ }
+
+ // Is rhs unreachable?
+ if rhs.Preds == nil {
+ // Simplify false&&y to false, true||y to true.
+ fn.currentBlock = done
+ return short
+ }
+
+ // Is done unreachable?
+ if done.Preds == nil {
+ // Simplify true&&y (or false||y) to y.
+ fn.currentBlock = rhs
+ return b.expr(fn, e.Y)
+ }
+
+ // All edges from e.X to done carry the short-circuit value.
+ var edges []Value
+ for _ = range done.Preds {
+ edges = append(edges, short)
+ }
+
+ // The edge from e.Y to done carries the value of e.Y.
+ fn.currentBlock = rhs
+ edges = append(edges, b.expr(fn, e.Y))
+ emitJump(fn, done)
+ fn.currentBlock = done
+
+ phi := &Phi{Edges: edges, Comment: e.Op.String()}
+ phi.pos = e.OpPos
+ phi.typ = t
+ return done.emit(phi)
+}
+
+// exprN lowers a multi-result expression e to SSA form, emitting code
+// to fn and returning a single Value whose type is a *types.Tuple.
+// The caller must access the components via Extract.
+//
+// Multi-result expressions include CallExprs in a multi-value
+// assignment or return statement, and "value,ok" uses of
+// TypeAssertExpr, IndexExpr (when X is a map), and UnaryExpr (when Op
+// is token.ARROW).
+//
+func (b *builder) exprN(fn *Function, e ast.Expr) Value {
+ typ := fn.Pkg.typeOf(e).(*types.Tuple)
+ switch e := e.(type) {
+ case *ast.ParenExpr:
+ return b.exprN(fn, e.X)
+
+ case *ast.CallExpr:
+ // Currently, no built-in function nor type conversion
+ // has multiple results, so we can avoid some of the
+ // cases for single-valued CallExpr.
+ var c Call
+ b.setCall(fn, e, &c.Call)
+ c.typ = typ
+ return fn.emit(&c)
+
+ case *ast.IndexExpr:
+ mapt := fn.Pkg.typeOf(e.X).Underlying().(*types.Map)
+ lookup := &Lookup{
+ X: b.expr(fn, e.X),
+ Index: emitConv(fn, b.expr(fn, e.Index), mapt.Key()),
+ CommaOk: true,
+ }
+ lookup.setType(typ)
+ lookup.setPos(e.Lbrack)
+ return fn.emit(lookup)
+
+ case *ast.TypeAssertExpr:
+ return emitTypeTest(fn, b.expr(fn, e.X), typ.At(0).Type(), e.Lparen)
+
+ case *ast.UnaryExpr: // must be receive <-
+ unop := &UnOp{
+ Op: token.ARROW,
+ X: b.expr(fn, e.X),
+ CommaOk: true,
+ }
+ unop.setType(typ)
+ unop.setPos(e.OpPos)
+ return fn.emit(unop)
+ }
+ panic(fmt.Sprintf("exprN(%T) in %s", e, fn))
+}
+
+// builtin emits to fn SSA instructions to implement a call to the
+// built-in function obj with the specified arguments
+// and return type. It returns the value defined by the result.
+//
+// The result is nil if no special handling was required; in this case
+// the caller should treat this like an ordinary library function
+// call.
+//
+func (b *builder) builtin(fn *Function, obj *types.Builtin, args []ast.Expr, typ types.Type, pos token.Pos) Value {
+ switch obj.Name() {
+ case "make":
+ switch typ.Underlying().(type) {
+ case *types.Slice:
+ n := b.expr(fn, args[1])
+ m := n
+ if len(args) == 3 {
+ m = b.expr(fn, args[2])
+ }
+ if m, ok := m.(*Const); ok {
+ // treat make([]T, n, m) as new([m]T)[:n]
+ cap, _ := exact.Int64Val(m.Value)
+ at := types.NewArray(typ.Underlying().(*types.Slice).Elem(), cap)
+ alloc := emitNew(fn, at, pos)
+ alloc.Comment = "makeslice"
+ v := &Slice{
+ X: alloc,
+ High: n,
+ }
+ v.setPos(pos)
+ v.setType(typ)
+ return fn.emit(v)
+ }
+ v := &MakeSlice{
+ Len: n,
+ Cap: m,
+ }
+ v.setPos(pos)
+ v.setType(typ)
+ return fn.emit(v)
+
+ case *types.Map:
+ var res Value
+ if len(args) == 2 {
+ res = b.expr(fn, args[1])
+ }
+ v := &MakeMap{Reserve: res}
+ v.setPos(pos)
+ v.setType(typ)
+ return fn.emit(v)
+
+ case *types.Chan:
+ var sz Value = vZero
+ if len(args) == 2 {
+ sz = b.expr(fn, args[1])
+ }
+ v := &MakeChan{Size: sz}
+ v.setPos(pos)
+ v.setType(typ)
+ return fn.emit(v)
+ }
+
+ case "new":
+ alloc := emitNew(fn, deref(typ), pos)
+ alloc.Comment = "new"
+ return alloc
+
+ case "len", "cap":
+ // Special case: len or cap of an array or *array is
+ // based on the type, not the value which may be nil.
+ // We must still evaluate the value, though. (If it
+ // was side-effect free, the whole call would have
+ // been constant-folded.)
+ t := deref(fn.Pkg.typeOf(args[0])).Underlying()
+ if at, ok := t.(*types.Array); ok {
+ b.expr(fn, args[0]) // for effects only
+ return intConst(at.Len())
+ }
+ // Otherwise treat as normal.
+
+ case "panic":
+ fn.emit(&Panic{
+ X: emitConv(fn, b.expr(fn, args[0]), tEface),
+ pos: pos,
+ })
+ fn.currentBlock = fn.newBasicBlock("unreachable")
+ return vTrue // any non-nil Value will do
+ }
+ return nil // treat all others as a regular function call
+}
+
+// addr lowers a single-result addressable expression e to SSA form,
+// emitting code to fn and returning the location (an lvalue) defined
+// by the expression.
+//
+// If escaping is true, addr marks the base variable of the
+// addressable expression e as being a potentially escaping pointer
+// value. For example, in this code:
+//
+// a := A{
+// b: [1]B{B{c: 1}}
+// }
+// return &a.b[0].c
+//
+// the application of & causes a.b[0].c to have its address taken,
+// which means that ultimately the local variable a must be
+// heap-allocated. This is a simple but very conservative escape
+// analysis.
+//
+// Operations forming potentially escaping pointers include:
+// - &x, including when implicit in method call or composite literals.
+// - a[:] iff a is an array (not *array)
+// - references to variables in lexically enclosing functions.
+//
+func (b *builder) addr(fn *Function, e ast.Expr, escaping bool) lvalue {
+ switch e := e.(type) {
+ case *ast.Ident:
+ if isBlankIdent(e) {
+ return blank{}
+ }
+ obj := fn.Pkg.objectOf(e)
+ v := fn.Prog.packageLevelValue(obj) // var (address)
+ if v == nil {
+ v = fn.lookup(obj, escaping)
+ }
+ return &address{addr: v, pos: e.Pos(), expr: e}
+
+ case *ast.CompositeLit:
+ t := deref(fn.Pkg.typeOf(e))
+ var v *Alloc
+ if escaping {
+ v = emitNew(fn, t, e.Lbrace)
+ } else {
+ v = fn.addLocal(t, e.Lbrace)
+ }
+ v.Comment = "complit"
+ var sb storebuf
+ b.compLit(fn, v, e, true, &sb)
+ sb.emit(fn)
+ return &address{addr: v, pos: e.Lbrace, expr: e}
+
+ case *ast.ParenExpr:
+ return b.addr(fn, e.X, escaping)
+
+ case *ast.SelectorExpr:
+ sel, ok := fn.Pkg.info.Selections[e]
+ if !ok {
+ // qualified identifier
+ return b.addr(fn, e.Sel, escaping)
+ }
+ if sel.Kind() != types.FieldVal {
+ panic(sel)
+ }
+ wantAddr := true
+ v := b.receiver(fn, e.X, wantAddr, escaping, sel)
+ last := len(sel.Index()) - 1
+ return &address{
+ addr: emitFieldSelection(fn, v, sel.Index()[last], true, e.Sel),
+ pos: e.Sel.Pos(),
+ expr: e.Sel,
+ }
+
+ case *ast.IndexExpr:
+ var x Value
+ var et types.Type
+ switch t := fn.Pkg.typeOf(e.X).Underlying().(type) {
+ case *types.Array:
+ x = b.addr(fn, e.X, escaping).address(fn)
+ et = types.NewPointer(t.Elem())
+ case *types.Pointer: // *array
+ x = b.expr(fn, e.X)
+ et = types.NewPointer(t.Elem().Underlying().(*types.Array).Elem())
+ case *types.Slice:
+ x = b.expr(fn, e.X)
+ et = types.NewPointer(t.Elem())
+ case *types.Map:
+ return &element{
+ m: b.expr(fn, e.X),
+ k: emitConv(fn, b.expr(fn, e.Index), t.Key()),
+ t: t.Elem(),
+ pos: e.Lbrack,
+ }
+ default:
+ panic("unexpected container type in IndexExpr: " + t.String())
+ }
+ v := &IndexAddr{
+ X: x,
+ Index: emitConv(fn, b.expr(fn, e.Index), tInt),
+ }
+ v.setPos(e.Lbrack)
+ v.setType(et)
+ return &address{addr: fn.emit(v), pos: e.Lbrack, expr: e}
+
+ case *ast.StarExpr:
+ return &address{addr: b.expr(fn, e.X), pos: e.Star, expr: e}
+ }
+
+ panic(fmt.Sprintf("unexpected address expression: %T", e))
+}
+
+type store struct {
+ lhs lvalue
+ rhs Value
+}
+
+type storebuf struct{ stores []store }
+
+func (sb *storebuf) store(lhs lvalue, rhs Value) {
+ sb.stores = append(sb.stores, store{lhs, rhs})
+}
+
+func (sb *storebuf) emit(fn *Function) {
+ for _, s := range sb.stores {
+ s.lhs.store(fn, s.rhs)
+ }
+}
+
+// assign emits to fn code to initialize the lvalue loc with the value
+// of expression e. If isZero is true, assign assumes that loc holds
+// the zero value for its type.
+//
+// This is equivalent to loc.store(fn, b.expr(fn, e)), but may generate
+// better code in some cases, e.g., for composite literals in an
+// addressable location.
+//
+// If sb is not nil, assign generates code to evaluate expression e, but
+// not to update loc. Instead, the necessary stores are appended to the
+// storebuf sb so that they can be executed later. This allows correct
+// in-place update of existing variables when the RHS is a composite
+// literal that may reference parts of the LHS.
+//
+func (b *builder) assign(fn *Function, loc lvalue, e ast.Expr, isZero bool, sb *storebuf) {
+ // Can we initialize it in place?
+ if e, ok := unparen(e).(*ast.CompositeLit); ok {
+ // A CompositeLit never evaluates to a pointer,
+ // so if the type of the location is a pointer,
+ // an &-operation is implied.
+ if _, ok := loc.(blank); !ok { // avoid calling blank.typ()
+ if isPointer(loc.typ()) {
+ ptr := b.addr(fn, e, true).address(fn)
+ // copy address
+ if sb != nil {
+ sb.store(loc, ptr)
+ } else {
+ loc.store(fn, ptr)
+ }
+ return
+ }
+ }
+
+ if _, ok := loc.(*address); ok {
+ if isInterface(loc.typ()) {
+ // e.g. var x interface{} = T{...}
+ // Can't in-place initialize an interface value.
+ // Fall back to copying.
+ } else {
+ // x = T{...} or x := T{...}
+ addr := loc.address(fn)
+ if sb != nil {
+ b.compLit(fn, addr, e, isZero, sb)
+ } else {
+ var sb storebuf
+ b.compLit(fn, addr, e, isZero, &sb)
+ sb.emit(fn)
+ }
+
+ // Subtle: emit debug ref for aggregate types only;
+ // slice and map are handled by store ops in compLit.
+ switch loc.typ().Underlying().(type) {
+ case *types.Struct, *types.Array:
+ emitDebugRef(fn, e, addr, true)
+ }
+
+ return
+ }
+ }
+ }
+
+ // simple case: just copy
+ rhs := b.expr(fn, e)
+ if sb != nil {
+ sb.store(loc, rhs)
+ } else {
+ loc.store(fn, rhs)
+ }
+}
+
+// expr lowers a single-result expression e to SSA form, emitting code
+// to fn and returning the Value defined by the expression.
+//
+func (b *builder) expr(fn *Function, e ast.Expr) Value {
+ e = unparen(e)
+
+ tv := fn.Pkg.info.Types[e]
+
+ // Is expression a constant?
+ if tv.Value != nil {
+ return NewConst(tv.Value, tv.Type)
+ }
+
+ var v Value
+ if tv.Addressable() {
+ // Prefer pointer arithmetic ({Index,Field}Addr) followed
+ // by Load over subelement extraction (e.g. Index, Field),
+ // to avoid large copies.
+ v = b.addr(fn, e, false).load(fn)
+ } else {
+ v = b.expr0(fn, e, tv)
+ }
+ if fn.debugInfo() {
+ emitDebugRef(fn, e, v, false)
+ }
+ return v
+}
+
+func (b *builder) expr0(fn *Function, e ast.Expr, tv types.TypeAndValue) Value {
+ switch e := e.(type) {
+ case *ast.BasicLit:
+ panic("non-constant BasicLit") // unreachable
+
+ case *ast.FuncLit:
+ fn2 := &Function{
+ name: fmt.Sprintf("%s$%d", fn.Name(), 1+len(fn.AnonFuncs)),
+ Signature: fn.Pkg.typeOf(e.Type).Underlying().(*types.Signature),
+ pos: e.Type.Func,
+ parent: fn,
+ Pkg: fn.Pkg,
+ Prog: fn.Prog,
+ syntax: e,
+ }
+ fn.AnonFuncs = append(fn.AnonFuncs, fn2)
+ b.buildFunction(fn2)
+ if fn2.FreeVars == nil {
+ return fn2
+ }
+ v := &MakeClosure{Fn: fn2}
+ v.setType(tv.Type)
+ for _, fv := range fn2.FreeVars {
+ v.Bindings = append(v.Bindings, fv.outer)
+ fv.outer = nil
+ }
+ return fn.emit(v)
+
+ case *ast.TypeAssertExpr: // single-result form only
+ return emitTypeAssert(fn, b.expr(fn, e.X), tv.Type, e.Lparen)
+
+ case *ast.CallExpr:
+ if fn.Pkg.info.Types[e.Fun].IsType() {
+ // Explicit type conversion, e.g. string(x) or big.Int(x)
+ x := b.expr(fn, e.Args[0])
+ y := emitConv(fn, x, tv.Type)
+ if y != x {
+ switch y := y.(type) {
+ case *Convert:
+ y.pos = e.Lparen
+ case *ChangeType:
+ y.pos = e.Lparen
+ case *MakeInterface:
+ y.pos = e.Lparen
+ }
+ }
+ return y
+ }
+ // Call to "intrinsic" built-ins, e.g. new, make, panic.
+ if id, ok := unparen(e.Fun).(*ast.Ident); ok {
+ if obj, ok := fn.Pkg.info.Uses[id].(*types.Builtin); ok {
+ if v := b.builtin(fn, obj, e.Args, tv.Type, e.Lparen); v != nil {
+ return v
+ }
+ }
+ }
+ // Regular function call.
+ var v Call
+ b.setCall(fn, e, &v.Call)
+ v.setType(tv.Type)
+ return fn.emit(&v)
+
+ case *ast.UnaryExpr:
+ switch e.Op {
+ case token.AND: // &X --- potentially escaping.
+ addr := b.addr(fn, e.X, true)
+ if _, ok := unparen(e.X).(*ast.StarExpr); ok {
+ // &*p must panic if p is nil (http://golang.org/s/go12nil).
+ // For simplicity, we'll just (suboptimally) rely
+ // on the side effects of a load.
+ // TODO(adonovan): emit dedicated nilcheck.
+ addr.load(fn)
+ }
+ return addr.address(fn)
+ case token.ADD:
+ return b.expr(fn, e.X)
+ case token.NOT, token.ARROW, token.SUB, token.XOR: // ! <- - ^
+ v := &UnOp{
+ Op: e.Op,
+ X: b.expr(fn, e.X),
+ }
+ v.setPos(e.OpPos)
+ v.setType(tv.Type)
+ return fn.emit(v)
+ default:
+ panic(e.Op)
+ }
+
+ case *ast.BinaryExpr:
+ switch e.Op {
+ case token.LAND, token.LOR:
+ return b.logicalBinop(fn, e)
+ case token.SHL, token.SHR:
+ fallthrough
+ case token.ADD, token.SUB, token.MUL, token.QUO, token.REM, token.AND, token.OR, token.XOR, token.AND_NOT:
+ return emitArith(fn, e.Op, b.expr(fn, e.X), b.expr(fn, e.Y), tv.Type, e.OpPos)
+
+ case token.EQL, token.NEQ, token.GTR, token.LSS, token.LEQ, token.GEQ:
+ cmp := emitCompare(fn, e.Op, b.expr(fn, e.X), b.expr(fn, e.Y), e.OpPos)
+ // The type of x==y may be UntypedBool.
+ return emitConv(fn, cmp, DefaultType(tv.Type))
+ default:
+ panic("illegal op in BinaryExpr: " + e.Op.String())
+ }
+
+ case *ast.SliceExpr:
+ var low, high, max Value
+ var x Value
+ switch fn.Pkg.typeOf(e.X).Underlying().(type) {
+ case *types.Array:
+ // Potentially escaping.
+ x = b.addr(fn, e.X, true).address(fn)
+ case *types.Basic, *types.Slice, *types.Pointer: // *array
+ x = b.expr(fn, e.X)
+ default:
+ panic("unreachable")
+ }
+ if e.High != nil {
+ high = b.expr(fn, e.High)
+ }
+ if e.Low != nil {
+ low = b.expr(fn, e.Low)
+ }
+ if e.Slice3 {
+ max = b.expr(fn, e.Max)
+ }
+ v := &Slice{
+ X: x,
+ Low: low,
+ High: high,
+ Max: max,
+ }
+ v.setPos(e.Lbrack)
+ v.setType(tv.Type)
+ return fn.emit(v)
+
+ case *ast.Ident:
+ obj := fn.Pkg.info.Uses[e]
+ // Universal built-in or nil?
+ switch obj := obj.(type) {
+ case *types.Builtin:
+ return &Builtin{name: obj.Name(), sig: tv.Type.(*types.Signature)}
+ case *types.Nil:
+ return nilConst(tv.Type)
+ }
+ // Package-level func or var?
+ if v := fn.Prog.packageLevelValue(obj); v != nil {
+ if _, ok := obj.(*types.Var); ok {
+ return emitLoad(fn, v) // var (address)
+ }
+ return v // (func)
+ }
+ // Local var.
+ return emitLoad(fn, fn.lookup(obj, false)) // var (address)
+
+ case *ast.SelectorExpr:
+ sel, ok := fn.Pkg.info.Selections[e]
+ if !ok {
+ // qualified identifier
+ return b.expr(fn, e.Sel)
+ }
+ switch sel.Kind() {
+ case types.MethodExpr:
+ // (*T).f or T.f, the method f from the method-set of type T.
+ // The result is a "thunk".
+ return emitConv(fn, makeThunk(fn.Prog, sel), tv.Type)
+
+ case types.MethodVal:
+ // e.f where e is an expression and f is a method.
+ // The result is a "bound".
+ obj := sel.Obj().(*types.Func)
+ rt := recvType(obj)
+ wantAddr := isPointer(rt)
+ escaping := true
+ v := b.receiver(fn, e.X, wantAddr, escaping, sel)
+ if isInterface(rt) {
+ // If v has interface type I,
+ // we must emit a check that v is non-nil.
+ // We use: typeassert v.(I).
+ emitTypeAssert(fn, v, rt, token.NoPos)
+ }
+ c := &MakeClosure{
+ Fn: makeBound(fn.Prog, obj),
+ Bindings: []Value{v},
+ }
+ c.setPos(e.Sel.Pos())
+ c.setType(tv.Type)
+ return fn.emit(c)
+
+ case types.FieldVal:
+ indices := sel.Index()
+ last := len(indices) - 1
+ v := b.expr(fn, e.X)
+ v = emitImplicitSelections(fn, v, indices[:last])
+ v = emitFieldSelection(fn, v, indices[last], false, e.Sel)
+ return v
+ }
+
+ panic("unexpected expression-relative selector")
+
+ case *ast.IndexExpr:
+ switch t := fn.Pkg.typeOf(e.X).Underlying().(type) {
+ case *types.Array:
+ // Non-addressable array (in a register).
+ v := &Index{
+ X: b.expr(fn, e.X),
+ Index: emitConv(fn, b.expr(fn, e.Index), tInt),
+ }
+ v.setPos(e.Lbrack)
+ v.setType(t.Elem())
+ return fn.emit(v)
+
+ case *types.Map:
+ // Maps are not addressable.
+ mapt := fn.Pkg.typeOf(e.X).Underlying().(*types.Map)
+ v := &Lookup{
+ X: b.expr(fn, e.X),
+ Index: emitConv(fn, b.expr(fn, e.Index), mapt.Key()),
+ }
+ v.setPos(e.Lbrack)
+ v.setType(mapt.Elem())
+ return fn.emit(v)
+
+ case *types.Basic: // => string
+ // Strings are not addressable.
+ v := &Lookup{
+ X: b.expr(fn, e.X),
+ Index: b.expr(fn, e.Index),
+ }
+ v.setPos(e.Lbrack)
+ v.setType(tByte)
+ return fn.emit(v)
+
+ case *types.Slice, *types.Pointer: // *array
+ // Addressable slice/array; use IndexAddr and Load.
+ return b.addr(fn, e, false).load(fn)
+
+ default:
+ panic("unexpected container type in IndexExpr: " + t.String())
+ }
+
+ case *ast.CompositeLit, *ast.StarExpr:
+ // Addressable types (lvalues)
+ return b.addr(fn, e, false).load(fn)
+ }
+
+ panic(fmt.Sprintf("unexpected expr: %T", e))
+}
+
+// stmtList emits to fn code for all statements in list.
+func (b *builder) stmtList(fn *Function, list []ast.Stmt) {
+ for _, s := range list {
+ b.stmt(fn, s)
+ }
+}
+
+// receiver emits to fn code for expression e in the "receiver"
+// position of selection e.f (where f may be a field or a method) and
+// returns the effective receiver after applying the implicit field
+// selections of sel.
+//
+// wantAddr requests that the result is an an address. If
+// !sel.Indirect(), this may require that e be built in addr() mode; it
+// must thus be addressable.
+//
+// escaping is defined as per builder.addr().
+//
+func (b *builder) receiver(fn *Function, e ast.Expr, wantAddr, escaping bool, sel *types.Selection) Value {
+ var v Value
+ if wantAddr && !sel.Indirect() && !isPointer(fn.Pkg.typeOf(e)) {
+ v = b.addr(fn, e, escaping).address(fn)
+ } else {
+ v = b.expr(fn, e)
+ }
+
+ last := len(sel.Index()) - 1
+ v = emitImplicitSelections(fn, v, sel.Index()[:last])
+ if !wantAddr && isPointer(v.Type()) {
+ v = emitLoad(fn, v)
+ }
+ return v
+}
+
+// setCallFunc populates the function parts of a CallCommon structure
+// (Func, Method, Recv, Args[0]) based on the kind of invocation
+// occurring in e.
+//
+func (b *builder) setCallFunc(fn *Function, e *ast.CallExpr, c *CallCommon) {
+ c.pos = e.Lparen
+
+ // Is this a method call?
+ if selector, ok := unparen(e.Fun).(*ast.SelectorExpr); ok {
+ sel, ok := fn.Pkg.info.Selections[selector]
+ if ok && sel.Kind() == types.MethodVal {
+ obj := sel.Obj().(*types.Func)
+ recv := recvType(obj)
+ wantAddr := isPointer(recv)
+ escaping := true
+ v := b.receiver(fn, selector.X, wantAddr, escaping, sel)
+ if isInterface(recv) {
+ // Invoke-mode call.
+ c.Value = v
+ c.Method = obj
+ } else {
+ // "Call"-mode call.
+ c.Value = fn.Prog.declaredFunc(obj)
+ c.Args = append(c.Args, v)
+ }
+ return
+ }
+
+ // sel.Kind()==MethodExpr indicates T.f() or (*T).f():
+ // a statically dispatched call to the method f in the
+ // method-set of T or *T. T may be an interface.
+ //
+ // e.Fun would evaluate to a concrete method, interface
+ // wrapper function, or promotion wrapper.
+ //
+ // For now, we evaluate it in the usual way.
+ //
+ // TODO(adonovan): opt: inline expr() here, to make the
+ // call static and to avoid generation of wrappers.
+ // It's somewhat tricky as it may consume the first
+ // actual parameter if the call is "invoke" mode.
+ //
+ // Examples:
+ // type T struct{}; func (T) f() {} // "call" mode
+ // type T interface { f() } // "invoke" mode
+ //
+ // type S struct{ T }
+ //
+ // var s S
+ // S.f(s)
+ // (*S).f(&s)
+ //
+ // Suggested approach:
+ // - consume the first actual parameter expression
+ // and build it with b.expr().
+ // - apply implicit field selections.
+ // - use MethodVal logic to populate fields of c.
+ }
+
+ // Evaluate the function operand in the usual way.
+ c.Value = b.expr(fn, e.Fun)
+}
+
+// emitCallArgs emits to f code for the actual parameters of call e to
+// a (possibly built-in) function of effective type sig.
+// The argument values are appended to args, which is then returned.
+//
+func (b *builder) emitCallArgs(fn *Function, sig *types.Signature, e *ast.CallExpr, args []Value) []Value {
+ // f(x, y, z...): pass slice z straight through.
+ if e.Ellipsis != 0 {
+ for i, arg := range e.Args {
+ v := emitConv(fn, b.expr(fn, arg), sig.Params().At(i).Type())
+ args = append(args, v)
+ }
+ return args
+ }
+
+ offset := len(args) // 1 if call has receiver, 0 otherwise
+
+ // Evaluate actual parameter expressions.
+ //
+ // If this is a chained call of the form f(g()) where g has
+ // multiple return values (MRV), they are flattened out into
+ // args; a suffix of them may end up in a varargs slice.
+ for _, arg := range e.Args {
+ v := b.expr(fn, arg)
+ if ttuple, ok := v.Type().(*types.Tuple); ok { // MRV chain
+ for i, n := 0, ttuple.Len(); i < n; i++ {
+ args = append(args, emitExtract(fn, v, i))
+ }
+ } else {
+ args = append(args, v)
+ }
+ }
+
+ // Actual->formal assignability conversions for normal parameters.
+ np := sig.Params().Len() // number of normal parameters
+ if sig.Variadic() {
+ np--
+ }
+ for i := 0; i < np; i++ {
+ args[offset+i] = emitConv(fn, args[offset+i], sig.Params().At(i).Type())
+ }
+
+ // Actual->formal assignability conversions for variadic parameter,
+ // and construction of slice.
+ if sig.Variadic() {
+ varargs := args[offset+np:]
+ st := sig.Params().At(np).Type().(*types.Slice)
+ vt := st.Elem()
+ if len(varargs) == 0 {
+ args = append(args, nilConst(st))
+ } else {
+ // Replace a suffix of args with a slice containing it.
+ at := types.NewArray(vt, int64(len(varargs)))
+ a := emitNew(fn, at, token.NoPos)
+ a.setPos(e.Rparen)
+ a.Comment = "varargs"
+ for i, arg := range varargs {
+ iaddr := &IndexAddr{
+ X: a,
+ Index: intConst(int64(i)),
+ }
+ iaddr.setType(types.NewPointer(vt))
+ fn.emit(iaddr)
+ emitStore(fn, iaddr, arg, arg.Pos())
+ }
+ s := &Slice{X: a}
+ s.setType(st)
+ args[offset+np] = fn.emit(s)
+ args = args[:offset+np+1]
+ }
+ }
+ return args
+}
+
+// setCall emits to fn code to evaluate all the parameters of a function
+// call e, and populates *c with those values.
+//
+func (b *builder) setCall(fn *Function, e *ast.CallExpr, c *CallCommon) {
+ // First deal with the f(...) part and optional receiver.
+ b.setCallFunc(fn, e, c)
+
+ // Then append the other actual parameters.
+ sig, _ := fn.Pkg.typeOf(e.Fun).Underlying().(*types.Signature)
+ if sig == nil {
+ panic(fmt.Sprintf("no signature for call of %s", e.Fun))
+ }
+ c.Args = b.emitCallArgs(fn, sig, e, c.Args)
+}
+
+// assignOp emits to fn code to perform loc += incr or loc -= incr.
+func (b *builder) assignOp(fn *Function, loc lvalue, incr Value, op token.Token) {
+ oldv := loc.load(fn)
+ loc.store(fn, emitArith(fn, op, oldv, emitConv(fn, incr, oldv.Type()), loc.typ(), token.NoPos))
+}
+
+// localValueSpec emits to fn code to define all of the vars in the
+// function-local ValueSpec, spec.
+//
+func (b *builder) localValueSpec(fn *Function, spec *ast.ValueSpec) {
+ switch {
+ case len(spec.Values) == len(spec.Names):
+ // e.g. var x, y = 0, 1
+ // 1:1 assignment
+ for i, id := range spec.Names {
+ if !isBlankIdent(id) {
+ fn.addLocalForIdent(id)
+ }
+ lval := b.addr(fn, id, false) // non-escaping
+ b.assign(fn, lval, spec.Values[i], true, nil)
+ }
+
+ case len(spec.Values) == 0:
+ // e.g. var x, y int
+ // Locals are implicitly zero-initialized.
+ for _, id := range spec.Names {
+ if !isBlankIdent(id) {
+ lhs := fn.addLocalForIdent(id)
+ if fn.debugInfo() {
+ emitDebugRef(fn, id, lhs, true)
+ }
+ }
+ }
+
+ default:
+ // e.g. var x, y = pos()
+ tuple := b.exprN(fn, spec.Values[0])
+ for i, id := range spec.Names {
+ if !isBlankIdent(id) {
+ fn.addLocalForIdent(id)
+ lhs := b.addr(fn, id, false) // non-escaping
+ lhs.store(fn, emitExtract(fn, tuple, i))
+ }
+ }
+ }
+}
+
+// assignStmt emits code to fn for a parallel assignment of rhss to lhss.
+// isDef is true if this is a short variable declaration (:=).
+//
+// Note the similarity with localValueSpec.
+//
+func (b *builder) assignStmt(fn *Function, lhss, rhss []ast.Expr, isDef bool) {
+ // Side effects of all LHSs and RHSs must occur in left-to-right order.
+ lvals := make([]lvalue, len(lhss))
+ isZero := make([]bool, len(lhss))
+ for i, lhs := range lhss {
+ var lval lvalue = blank{}
+ if !isBlankIdent(lhs) {
+ if isDef {
+ if obj := fn.Pkg.info.Defs[lhs.(*ast.Ident)]; obj != nil {
+ fn.addNamedLocal(obj)
+ isZero[i] = true
+ }
+ }
+ lval = b.addr(fn, lhs, false) // non-escaping
+ }
+ lvals[i] = lval
+ }
+ if len(lhss) == len(rhss) {
+ // Simple assignment: x = f() (!isDef)
+ // Parallel assignment: x, y = f(), g() (!isDef)
+ // or short var decl: x, y := f(), g() (isDef)
+ //
+ // In all cases, the RHSs may refer to the LHSs,
+ // so we need a storebuf.
+ var sb storebuf
+ for i := range rhss {
+ b.assign(fn, lvals[i], rhss[i], isZero[i], &sb)
+ }
+ sb.emit(fn)
+ } else {
+ // e.g. x, y = pos()
+ tuple := b.exprN(fn, rhss[0])
+ for i, lval := range lvals {
+ lval.store(fn, emitExtract(fn, tuple, i))
+ }
+ }
+}
+
+// arrayLen returns the length of the array whose composite literal elements are elts.
+func (b *builder) arrayLen(fn *Function, elts []ast.Expr) int64 {
+ var max int64 = -1
+ var i int64 = -1
+ for _, e := range elts {
+ if kv, ok := e.(*ast.KeyValueExpr); ok {
+ i = b.expr(fn, kv.Key).(*Const).Int64()
+ } else {
+ i++
+ }
+ if i > max {
+ max = i
+ }
+ }
+ return max + 1
+}
+
+// compLit emits to fn code to initialize a composite literal e at
+// address addr with type typ.
+//
+// Nested composite literals are recursively initialized in place
+// where possible. If isZero is true, compLit assumes that addr
+// holds the zero value for typ.
+//
+// Because the elements of a composite literal may refer to the
+// variables being updated, as in the second line below,
+// x := T{a: 1}
+// x = T{a: x.a}
+// all the reads must occur before all the writes. Thus all stores to
+// loc are emitted to the storebuf sb for later execution.
+//
+// A CompositeLit may have pointer type only in the recursive (nested)
+// case when the type name is implicit. e.g. in []*T{{}}, the inner
+// literal has type *T behaves like &T{}.
+// In that case, addr must hold a T, not a *T.
+//
+func (b *builder) compLit(fn *Function, addr Value, e *ast.CompositeLit, isZero bool, sb *storebuf) {
+ typ := deref(fn.Pkg.typeOf(e))
+ switch t := typ.Underlying().(type) {
+ case *types.Struct:
+ if !isZero && len(e.Elts) != t.NumFields() {
+ // memclear
+ sb.store(&address{addr, e.Lbrace, nil},
+ zeroValue(fn, deref(addr.Type())))
+ isZero = true
+ }
+ for i, e := range e.Elts {
+ fieldIndex := i
+ pos := e.Pos()
+ if kv, ok := e.(*ast.KeyValueExpr); ok {
+ fname := kv.Key.(*ast.Ident).Name
+ for i, n := 0, t.NumFields(); i < n; i++ {
+ sf := t.Field(i)
+ if sf.Name() == fname {
+ fieldIndex = i
+ pos = kv.Colon
+ e = kv.Value
+ break
+ }
+ }
+ }
+ sf := t.Field(fieldIndex)
+ faddr := &FieldAddr{
+ X: addr,
+ Field: fieldIndex,
+ }
+ faddr.setType(types.NewPointer(sf.Type()))
+ fn.emit(faddr)
+ b.assign(fn, &address{addr: faddr, pos: pos, expr: e}, e, isZero, sb)
+ }
+
+ case *types.Array, *types.Slice:
+ var at *types.Array
+ var array Value
+ switch t := t.(type) {
+ case *types.Slice:
+ at = types.NewArray(t.Elem(), b.arrayLen(fn, e.Elts))
+ alloc := emitNew(fn, at, e.Lbrace)
+ alloc.Comment = "slicelit"
+ array = alloc
+ case *types.Array:
+ at = t
+ array = addr
+
+ if !isZero && int64(len(e.Elts)) != at.Len() {
+ // memclear
+ sb.store(&address{array, e.Lbrace, nil},
+ zeroValue(fn, deref(array.Type())))
+ }
+ }
+
+ var idx *Const
+ for _, e := range e.Elts {
+ pos := e.Pos()
+ if kv, ok := e.(*ast.KeyValueExpr); ok {
+ idx = b.expr(fn, kv.Key).(*Const)
+ pos = kv.Colon
+ e = kv.Value
+ } else {
+ var idxval int64
+ if idx != nil {
+ idxval = idx.Int64() + 1
+ }
+ idx = intConst(idxval)
+ }
+ iaddr := &IndexAddr{
+ X: array,
+ Index: idx,
+ }
+ iaddr.setType(types.NewPointer(at.Elem()))
+ fn.emit(iaddr)
+ if t != at { // slice
+ // backing array is unaliased => storebuf not needed.
+ b.assign(fn, &address{addr: iaddr, pos: pos, expr: e}, e, true, nil)
+ } else {
+ b.assign(fn, &address{addr: iaddr, pos: pos, expr: e}, e, true, sb)
+ }
+ }
+
+ if t != at { // slice
+ s := &Slice{X: array}
+ s.setPos(e.Lbrace)
+ s.setType(typ)
+ sb.store(&address{addr: addr, pos: e.Lbrace, expr: e}, fn.emit(s))
+ }
+
+ case *types.Map:
+ m := &MakeMap{Reserve: intConst(int64(len(e.Elts)))}
+ m.setPos(e.Lbrace)
+ m.setType(typ)
+ fn.emit(m)
+ for _, e := range e.Elts {
+ e := e.(*ast.KeyValueExpr)
+ loc := element{
+ m: m,
+ k: emitConv(fn, b.expr(fn, e.Key), t.Key()),
+ t: t.Elem(),
+ pos: e.Colon,
+ }
+
+ // We call assign() only because it takes care
+ // of any &-operation required in the recursive
+ // case, e.g.,
+ // map[int]*struct{}{0: {}} implies &struct{}{}.
+ // In-place update is of course impossible,
+ // and no storebuf is needed.
+ b.assign(fn, &loc, e.Value, true, nil)
+ }
+ sb.store(&address{addr: addr, pos: e.Lbrace, expr: e}, m)
+
+ default:
+ panic("unexpected CompositeLit type: " + t.String())
+ }
+}
+
+// switchStmt emits to fn code for the switch statement s, optionally
+// labelled by label.
+//
+func (b *builder) switchStmt(fn *Function, s *ast.SwitchStmt, label *lblock) {
+ // We treat SwitchStmt like a sequential if-else chain.
+ // Multiway dispatch can be recovered later by ssautil.Switches()
+ // to those cases that are free of side effects.
+ if s.Init != nil {
+ b.stmt(fn, s.Init)
+ }
+ var tag Value = vTrue
+ if s.Tag != nil {
+ tag = b.expr(fn, s.Tag)
+ }
+ done := fn.newBasicBlock("switch.done")
+ if label != nil {
+ label._break = done
+ }
+ // We pull the default case (if present) down to the end.
+ // But each fallthrough label must point to the next
+ // body block in source order, so we preallocate a
+ // body block (fallthru) for the next case.
+ // Unfortunately this makes for a confusing block order.
+ var dfltBody *[]ast.Stmt
+ var dfltFallthrough *BasicBlock
+ var fallthru, dfltBlock *BasicBlock
+ ncases := len(s.Body.List)
+ for i, clause := range s.Body.List {
+ body := fallthru
+ if body == nil {
+ body = fn.newBasicBlock("switch.body") // first case only
+ }
+
+ // Preallocate body block for the next case.
+ fallthru = done
+ if i+1 < ncases {
+ fallthru = fn.newBasicBlock("switch.body")
+ }
+
+ cc := clause.(*ast.CaseClause)
+ if cc.List == nil {
+ // Default case.
+ dfltBody = &cc.Body
+ dfltFallthrough = fallthru
+ dfltBlock = body
+ continue
+ }
+
+ var nextCond *BasicBlock
+ for _, cond := range cc.List {
+ nextCond = fn.newBasicBlock("switch.next")
+ // TODO(adonovan): opt: when tag==vTrue, we'd
+ // get better code if we use b.cond(cond)
+ // instead of BinOp(EQL, tag, b.expr(cond))
+ // followed by If. Don't forget conversions
+ // though.
+ cond := emitCompare(fn, token.EQL, tag, b.expr(fn, cond), token.NoPos)
+ emitIf(fn, cond, body, nextCond)
+ fn.currentBlock = nextCond
+ }
+ fn.currentBlock = body
+ fn.targets = &targets{
+ tail: fn.targets,
+ _break: done,
+ _fallthrough: fallthru,
+ }
+ b.stmtList(fn, cc.Body)
+ fn.targets = fn.targets.tail
+ emitJump(fn, done)
+ fn.currentBlock = nextCond
+ }
+ if dfltBlock != nil {
+ emitJump(fn, dfltBlock)
+ fn.currentBlock = dfltBlock
+ fn.targets = &targets{
+ tail: fn.targets,
+ _break: done,
+ _fallthrough: dfltFallthrough,
+ }
+ b.stmtList(fn, *dfltBody)
+ fn.targets = fn.targets.tail
+ }
+ emitJump(fn, done)
+ fn.currentBlock = done
+}
+
+// typeSwitchStmt emits to fn code for the type switch statement s, optionally
+// labelled by label.
+//
+func (b *builder) typeSwitchStmt(fn *Function, s *ast.TypeSwitchStmt, label *lblock) {
+ // We treat TypeSwitchStmt like a sequential if-else chain.
+ // Multiway dispatch can be recovered later by ssautil.Switches().
+
+ // Typeswitch lowering:
+ //
+ // var x X
+ // switch y := x.(type) {
+ // case T1, T2: S1 // >1 (y := x)
+ // case nil: SN // nil (y := x)
+ // default: SD // 0 types (y := x)
+ // case T3: S3 // 1 type (y := x.(T3))
+ // }
+ //
+ // ...s.Init...
+ // x := eval x
+ // .caseT1:
+ // t1, ok1 := typeswitch,ok x <T1>
+ // if ok1 then goto S1 else goto .caseT2
+ // .caseT2:
+ // t2, ok2 := typeswitch,ok x <T2>
+ // if ok2 then goto S1 else goto .caseNil
+ // .S1:
+ // y := x
+ // ...S1...
+ // goto done
+ // .caseNil:
+ // if t2, ok2 := typeswitch,ok x <T2>
+ // if x == nil then goto SN else goto .caseT3
+ // .SN:
+ // y := x
+ // ...SN...
+ // goto done
+ // .caseT3:
+ // t3, ok3 := typeswitch,ok x <T3>
+ // if ok3 then goto S3 else goto default
+ // .S3:
+ // y := t3
+ // ...S3...
+ // goto done
+ // .default:
+ // y := x
+ // ...SD...
+ // goto done
+ // .done:
+
+ if s.Init != nil {
+ b.stmt(fn, s.Init)
+ }
+
+ var x Value
+ switch ass := s.Assign.(type) {
+ case *ast.ExprStmt: // x.(type)
+ x = b.expr(fn, unparen(ass.X).(*ast.TypeAssertExpr).X)
+ case *ast.AssignStmt: // y := x.(type)
+ x = b.expr(fn, unparen(ass.Rhs[0]).(*ast.TypeAssertExpr).X)
+ }
+
+ done := fn.newBasicBlock("typeswitch.done")
+ if label != nil {
+ label._break = done
+ }
+ var default_ *ast.CaseClause
+ for _, clause := range s.Body.List {
+ cc := clause.(*ast.CaseClause)
+ if cc.List == nil {
+ default_ = cc
+ continue
+ }
+ body := fn.newBasicBlock("typeswitch.body")
+ var next *BasicBlock
+ var casetype types.Type
+ var ti Value // ti, ok := typeassert,ok x <Ti>
+ for _, cond := range cc.List {
+ next = fn.newBasicBlock("typeswitch.next")
+ casetype = fn.Pkg.typeOf(cond)
+ var condv Value
+ if casetype == tUntypedNil {
+ condv = emitCompare(fn, token.EQL, x, nilConst(x.Type()), token.NoPos)
+ ti = x
+ } else {
+ yok := emitTypeTest(fn, x, casetype, cc.Case)
+ ti = emitExtract(fn, yok, 0)
+ condv = emitExtract(fn, yok, 1)
+ }
+ emitIf(fn, condv, body, next)
+ fn.currentBlock = next
+ }
+ if len(cc.List) != 1 {
+ ti = x
+ }
+ fn.currentBlock = body
+ b.typeCaseBody(fn, cc, ti, done)
+ fn.currentBlock = next
+ }
+ if default_ != nil {
+ b.typeCaseBody(fn, default_, x, done)
+ } else {
+ emitJump(fn, done)
+ }
+ fn.currentBlock = done
+}
+
+func (b *builder) typeCaseBody(fn *Function, cc *ast.CaseClause, x Value, done *BasicBlock) {
+ if obj := fn.Pkg.info.Implicits[cc]; obj != nil {
+ // In a switch y := x.(type), each case clause
+ // implicitly declares a distinct object y.
+ // In a single-type case, y has that type.
+ // In multi-type cases, 'case nil' and default,
+ // y has the same type as the interface operand.
+ emitStore(fn, fn.addNamedLocal(obj), x, obj.Pos())
+ }
+ fn.targets = &targets{
+ tail: fn.targets,
+ _break: done,
+ }
+ b.stmtList(fn, cc.Body)
+ fn.targets = fn.targets.tail
+ emitJump(fn, done)
+}
+
+// selectStmt emits to fn code for the select statement s, optionally
+// labelled by label.
+//
+func (b *builder) selectStmt(fn *Function, s *ast.SelectStmt, label *lblock) {
+ // A blocking select of a single case degenerates to a
+ // simple send or receive.
+ // TODO(adonovan): opt: is this optimization worth its weight?
+ if len(s.Body.List) == 1 {
+ clause := s.Body.List[0].(*ast.CommClause)
+ if clause.Comm != nil {
+ b.stmt(fn, clause.Comm)
+ done := fn.newBasicBlock("select.done")
+ if label != nil {
+ label._break = done
+ }
+ fn.targets = &targets{
+ tail: fn.targets,
+ _break: done,
+ }
+ b.stmtList(fn, clause.Body)
+ fn.targets = fn.targets.tail
+ emitJump(fn, done)
+ fn.currentBlock = done
+ return
+ }
+ }
+
+ // First evaluate all channels in all cases, and find
+ // the directions of each state.
+ var states []*SelectState
+ blocking := true
+ debugInfo := fn.debugInfo()
+ for _, clause := range s.Body.List {
+ var st *SelectState
+ switch comm := clause.(*ast.CommClause).Comm.(type) {
+ case nil: // default case
+ blocking = false
+ continue
+
+ case *ast.SendStmt: // ch<- i
+ ch := b.expr(fn, comm.Chan)
+ st = &SelectState{
+ Dir: types.SendOnly,
+ Chan: ch,
+ Send: emitConv(fn, b.expr(fn, comm.Value),
+ ch.Type().Underlying().(*types.Chan).Elem()),
+ Pos: comm.Arrow,
+ }
+ if debugInfo {
+ st.DebugNode = comm
+ }
+
+ case *ast.AssignStmt: // x := <-ch
+ recv := unparen(comm.Rhs[0]).(*ast.UnaryExpr)
+ st = &SelectState{
+ Dir: types.RecvOnly,
+ Chan: b.expr(fn, recv.X),
+ Pos: recv.OpPos,
+ }
+ if debugInfo {
+ st.DebugNode = recv
+ }
+
+ case *ast.ExprStmt: // <-ch
+ recv := unparen(comm.X).(*ast.UnaryExpr)
+ st = &SelectState{
+ Dir: types.RecvOnly,
+ Chan: b.expr(fn, recv.X),
+ Pos: recv.OpPos,
+ }
+ if debugInfo {
+ st.DebugNode = recv
+ }
+ }
+ states = append(states, st)
+ }
+
+ // We dispatch on the (fair) result of Select using a
+ // sequential if-else chain, in effect:
+ //
+ // idx, recvOk, r0...r_n-1 := select(...)
+ // if idx == 0 { // receive on channel 0 (first receive => r0)
+ // x, ok := r0, recvOk
+ // ...state0...
+ // } else if v == 1 { // send on channel 1
+ // ...state1...
+ // } else {
+ // ...default...
+ // }
+ sel := &Select{
+ States: states,
+ Blocking: blocking,
+ }
+ sel.setPos(s.Select)
+ var vars []*types.Var
+ vars = append(vars, varIndex, varOk)
+ for _, st := range states {
+ if st.Dir == types.RecvOnly {
+ tElem := st.Chan.Type().Underlying().(*types.Chan).Elem()
+ vars = append(vars, anonVar(tElem))
+ }
+ }
+ sel.setType(types.NewTuple(vars...))
+
+ fn.emit(sel)
+ idx := emitExtract(fn, sel, 0)
+
+ done := fn.newBasicBlock("select.done")
+ if label != nil {
+ label._break = done
+ }
+
+ var defaultBody *[]ast.Stmt
+ state := 0
+ r := 2 // index in 'sel' tuple of value; increments if st.Dir==RECV
+ for _, cc := range s.Body.List {
+ clause := cc.(*ast.CommClause)
+ if clause.Comm == nil {
+ defaultBody = &clause.Body
+ continue
+ }
+ body := fn.newBasicBlock("select.body")
+ next := fn.newBasicBlock("select.next")
+ emitIf(fn, emitCompare(fn, token.EQL, idx, intConst(int64(state)), token.NoPos), body, next)
+ fn.currentBlock = body
+ fn.targets = &targets{
+ tail: fn.targets,
+ _break: done,
+ }
+ switch comm := clause.Comm.(type) {
+ case *ast.ExprStmt: // <-ch
+ if debugInfo {
+ v := emitExtract(fn, sel, r)
+ emitDebugRef(fn, states[state].DebugNode.(ast.Expr), v, false)
+ }
+ r++
+
+ case *ast.AssignStmt: // x := <-states[state].Chan
+ if comm.Tok == token.DEFINE {
+ fn.addLocalForIdent(comm.Lhs[0].(*ast.Ident))
+ }
+ x := b.addr(fn, comm.Lhs[0], false) // non-escaping
+ v := emitExtract(fn, sel, r)
+ if debugInfo {
+ emitDebugRef(fn, states[state].DebugNode.(ast.Expr), v, false)
+ }
+ x.store(fn, v)
+
+ if len(comm.Lhs) == 2 { // x, ok := ...
+ if comm.Tok == token.DEFINE {
+ fn.addLocalForIdent(comm.Lhs[1].(*ast.Ident))
+ }
+ ok := b.addr(fn, comm.Lhs[1], false) // non-escaping
+ ok.store(fn, emitExtract(fn, sel, 1))
+ }
+ r++
+ }
+ b.stmtList(fn, clause.Body)
+ fn.targets = fn.targets.tail
+ emitJump(fn, done)
+ fn.currentBlock = next
+ state++
+ }
+ if defaultBody != nil {
+ fn.targets = &targets{
+ tail: fn.targets,
+ _break: done,
+ }
+ b.stmtList(fn, *defaultBody)
+ fn.targets = fn.targets.tail
+ } else {
+ // A blocking select must match some case.
+ // (This should really be a runtime.errorString, not a string.)
+ fn.emit(&Panic{
+ X: emitConv(fn, stringConst("blocking select matched no case"), tEface),
+ })
+ fn.currentBlock = fn.newBasicBlock("unreachable")
+ }
+ emitJump(fn, done)
+ fn.currentBlock = done
+}
+
+// forStmt emits to fn code for the for statement s, optionally
+// labelled by label.
+//
+func (b *builder) forStmt(fn *Function, s *ast.ForStmt, label *lblock) {
+ // ...init...
+ // jump loop
+ // loop:
+ // if cond goto body else done
+ // body:
+ // ...body...
+ // jump post
+ // post: (target of continue)
+ // ...post...
+ // jump loop
+ // done: (target of break)
+ if s.Init != nil {
+ b.stmt(fn, s.Init)
+ }
+ body := fn.newBasicBlock("for.body")
+ done := fn.newBasicBlock("for.done") // target of 'break'
+ loop := body // target of back-edge
+ if s.Cond != nil {
+ loop = fn.newBasicBlock("for.loop")
+ }
+ cont := loop // target of 'continue'
+ if s.Post != nil {
+ cont = fn.newBasicBlock("for.post")
+ }
+ if label != nil {
+ label._break = done
+ label._continue = cont
+ }
+ emitJump(fn, loop)
+ fn.currentBlock = loop
+ if loop != body {
+ b.cond(fn, s.Cond, body, done)
+ fn.currentBlock = body
+ }
+ fn.targets = &targets{
+ tail: fn.targets,
+ _break: done,
+ _continue: cont,
+ }
+ b.stmt(fn, s.Body)
+ fn.targets = fn.targets.tail
+ emitJump(fn, cont)
+
+ if s.Post != nil {
+ fn.currentBlock = cont
+ b.stmt(fn, s.Post)
+ emitJump(fn, loop) // back-edge
+ }
+ fn.currentBlock = done
+}
+
+// rangeIndexed emits to fn the header for an integer-indexed loop
+// over array, *array or slice value x.
+// The v result is defined only if tv is non-nil.
+// forPos is the position of the "for" token.
+//
+func (b *builder) rangeIndexed(fn *Function, x Value, tv types.Type, pos token.Pos) (k, v Value, loop, done *BasicBlock) {
+ //
+ // length = len(x)
+ // index = -1
+ // loop: (target of continue)
+ // index++
+ // if index < length goto body else done
+ // body:
+ // k = index
+ // v = x[index]
+ // ...body...
+ // jump loop
+ // done: (target of break)
+
+ // Determine number of iterations.
+ var length Value
+ if arr, ok := deref(x.Type()).Underlying().(*types.Array); ok {
+ // For array or *array, the number of iterations is
+ // known statically thanks to the type. We avoid a
+ // data dependence upon x, permitting later dead-code
+ // elimination if x is pure, static unrolling, etc.
+ // Ranging over a nil *array may have >0 iterations.
+ // We still generate code for x, in case it has effects.
+ length = intConst(arr.Len())
+ } else {
+ // length = len(x).
+ var c Call
+ c.Call.Value = makeLen(x.Type())
+ c.Call.Args = []Value{x}
+ c.setType(tInt)
+ length = fn.emit(&c)
+ }
+
+ index := fn.addLocal(tInt, token.NoPos)
+ emitStore(fn, index, intConst(-1), pos)
+
+ loop = fn.newBasicBlock("rangeindex.loop")
+ emitJump(fn, loop)
+ fn.currentBlock = loop
+
+ incr := &BinOp{
+ Op: token.ADD,
+ X: emitLoad(fn, index),
+ Y: vOne,
+ }
+ incr.setType(tInt)
+ emitStore(fn, index, fn.emit(incr), pos)
+
+ body := fn.newBasicBlock("rangeindex.body")
+ done = fn.newBasicBlock("rangeindex.done")
+ emitIf(fn, emitCompare(fn, token.LSS, incr, length, token.NoPos), body, done)
+ fn.currentBlock = body
+
+ k = emitLoad(fn, index)
+ if tv != nil {
+ switch t := x.Type().Underlying().(type) {
+ case *types.Array:
+ instr := &Index{
+ X: x,
+ Index: k,
+ }
+ instr.setType(t.Elem())
+ v = fn.emit(instr)
+
+ case *types.Pointer: // *array
+ instr := &IndexAddr{
+ X: x,
+ Index: k,
+ }
+ instr.setType(types.NewPointer(t.Elem().Underlying().(*types.Array).Elem()))
+ v = emitLoad(fn, fn.emit(instr))
+
+ case *types.Slice:
+ instr := &IndexAddr{
+ X: x,
+ Index: k,
+ }
+ instr.setType(types.NewPointer(t.Elem()))
+ v = emitLoad(fn, fn.emit(instr))
+
+ default:
+ panic("rangeIndexed x:" + t.String())
+ }
+ }
+ return
+}
+
+// rangeIter emits to fn the header for a loop using
+// Range/Next/Extract to iterate over map or string value x.
+// tk and tv are the types of the key/value results k and v, or nil
+// if the respective component is not wanted.
+//
+func (b *builder) rangeIter(fn *Function, x Value, tk, tv types.Type, pos token.Pos) (k, v Value, loop, done *BasicBlock) {
+ //
+ // it = range x
+ // loop: (target of continue)
+ // okv = next it (ok, key, value)
+ // ok = extract okv #0
+ // if ok goto body else done
+ // body:
+ // k = extract okv #1
+ // v = extract okv #2
+ // ...body...
+ // jump loop
+ // done: (target of break)
+ //
+
+ if tk == nil {
+ tk = tInvalid
+ }
+ if tv == nil {
+ tv = tInvalid
+ }
+
+ rng := &Range{X: x}
+ rng.setPos(pos)
+ rng.setType(tRangeIter)
+ it := fn.emit(rng)
+
+ loop = fn.newBasicBlock("rangeiter.loop")
+ emitJump(fn, loop)
+ fn.currentBlock = loop
+
+ _, isString := x.Type().Underlying().(*types.Basic)
+
+ okv := &Next{
+ Iter: it,
+ IsString: isString,
+ }
+ okv.setType(types.NewTuple(
+ varOk,
+ newVar("k", tk),
+ newVar("v", tv),
+ ))
+ fn.emit(okv)
+
+ body := fn.newBasicBlock("rangeiter.body")
+ done = fn.newBasicBlock("rangeiter.done")
+ emitIf(fn, emitExtract(fn, okv, 0), body, done)
+ fn.currentBlock = body
+
+ if tk != tInvalid {
+ k = emitExtract(fn, okv, 1)
+ }
+ if tv != tInvalid {
+ v = emitExtract(fn, okv, 2)
+ }
+ return
+}
+
+// rangeChan emits to fn the header for a loop that receives from
+// channel x until it fails.
+// tk is the channel's element type, or nil if the k result is
+// not wanted
+// pos is the position of the '=' or ':=' token.
+//
+func (b *builder) rangeChan(fn *Function, x Value, tk types.Type, pos token.Pos) (k Value, loop, done *BasicBlock) {
+ //
+ // loop: (target of continue)
+ // ko = <-x (key, ok)
+ // ok = extract ko #1
+ // if ok goto body else done
+ // body:
+ // k = extract ko #0
+ // ...
+ // goto loop
+ // done: (target of break)
+
+ loop = fn.newBasicBlock("rangechan.loop")
+ emitJump(fn, loop)
+ fn.currentBlock = loop
+ recv := &UnOp{
+ Op: token.ARROW,
+ X: x,
+ CommaOk: true,
+ }
+ recv.setPos(pos)
+ recv.setType(types.NewTuple(
+ newVar("k", x.Type().Underlying().(*types.Chan).Elem()),
+ varOk,
+ ))
+ ko := fn.emit(recv)
+ body := fn.newBasicBlock("rangechan.body")
+ done = fn.newBasicBlock("rangechan.done")
+ emitIf(fn, emitExtract(fn, ko, 1), body, done)
+ fn.currentBlock = body
+ if tk != nil {
+ k = emitExtract(fn, ko, 0)
+ }
+ return
+}
+
+// rangeStmt emits to fn code for the range statement s, optionally
+// labelled by label.
+//
+func (b *builder) rangeStmt(fn *Function, s *ast.RangeStmt, label *lblock) {
+ var tk, tv types.Type
+ if s.Key != nil && !isBlankIdent(s.Key) {
+ tk = fn.Pkg.typeOf(s.Key)
+ }
+ if s.Value != nil && !isBlankIdent(s.Value) {
+ tv = fn.Pkg.typeOf(s.Value)
+ }
+
+ // If iteration variables are defined (:=), this
+ // occurs once outside the loop.
+ //
+ // Unlike a short variable declaration, a RangeStmt
+ // using := never redeclares an existing variable; it
+ // always creates a new one.
+ if s.Tok == token.DEFINE {
+ if tk != nil {
+ fn.addLocalForIdent(s.Key.(*ast.Ident))
+ }
+ if tv != nil {
+ fn.addLocalForIdent(s.Value.(*ast.Ident))
+ }
+ }
+
+ x := b.expr(fn, s.X)
+
+ var k, v Value
+ var loop, done *BasicBlock
+ switch rt := x.Type().Underlying().(type) {
+ case *types.Slice, *types.Array, *types.Pointer: // *array
+ k, v, loop, done = b.rangeIndexed(fn, x, tv, s.For)
+
+ case *types.Chan:
+ k, loop, done = b.rangeChan(fn, x, tk, s.For)
+
+ case *types.Map, *types.Basic: // string
+ k, v, loop, done = b.rangeIter(fn, x, tk, tv, s.For)
+
+ default:
+ panic("Cannot range over: " + rt.String())
+ }
+
+ // Evaluate both LHS expressions before we update either.
+ var kl, vl lvalue
+ if tk != nil {
+ kl = b.addr(fn, s.Key, false) // non-escaping
+ }
+ if tv != nil {
+ vl = b.addr(fn, s.Value, false) // non-escaping
+ }
+ if tk != nil {
+ kl.store(fn, k)
+ }
+ if tv != nil {
+ vl.store(fn, v)
+ }
+
+ if label != nil {
+ label._break = done
+ label._continue = loop
+ }
+
+ fn.targets = &targets{
+ tail: fn.targets,
+ _break: done,
+ _continue: loop,
+ }
+ b.stmt(fn, s.Body)
+ fn.targets = fn.targets.tail
+ emitJump(fn, loop) // back-edge
+ fn.currentBlock = done
+}
+
+// stmt lowers statement s to SSA form, emitting code to fn.
+func (b *builder) stmt(fn *Function, _s ast.Stmt) {
+ // The label of the current statement. If non-nil, its _goto
+ // target is always set; its _break and _continue are set only
+ // within the body of switch/typeswitch/select/for/range.
+ // It is effectively an additional default-nil parameter of stmt().
+ var label *lblock
+start:
+ switch s := _s.(type) {
+ case *ast.EmptyStmt:
+ // ignore. (Usually removed by gofmt.)
+
+ case *ast.DeclStmt: // Con, Var or Typ
+ d := s.Decl.(*ast.GenDecl)
+ if d.Tok == token.VAR {
+ for _, spec := range d.Specs {
+ if vs, ok := spec.(*ast.ValueSpec); ok {
+ b.localValueSpec(fn, vs)
+ }
+ }
+ }
+
+ case *ast.LabeledStmt:
+ label = fn.labelledBlock(s.Label)
+ emitJump(fn, label._goto)
+ fn.currentBlock = label._goto
+ _s = s.Stmt
+ goto start // effectively: tailcall stmt(fn, s.Stmt, label)
+
+ case *ast.ExprStmt:
+ b.expr(fn, s.X)
+
+ case *ast.SendStmt:
+ fn.emit(&Send{
+ Chan: b.expr(fn, s.Chan),
+ X: emitConv(fn, b.expr(fn, s.Value),
+ fn.Pkg.typeOf(s.Chan).Underlying().(*types.Chan).Elem()),
+ pos: s.Arrow,
+ })
+
+ case *ast.IncDecStmt:
+ op := token.ADD
+ if s.Tok == token.DEC {
+ op = token.SUB
+ }
+ loc := b.addr(fn, s.X, false)
+ b.assignOp(fn, loc, NewConst(exact.MakeInt64(1), loc.typ()), op)
+
+ case *ast.AssignStmt:
+ switch s.Tok {
+ case token.ASSIGN, token.DEFINE:
+ b.assignStmt(fn, s.Lhs, s.Rhs, s.Tok == token.DEFINE)
+
+ default: // +=, etc.
+ op := s.Tok + token.ADD - token.ADD_ASSIGN
+ b.assignOp(fn, b.addr(fn, s.Lhs[0], false), b.expr(fn, s.Rhs[0]), op)
+ }
+
+ case *ast.GoStmt:
+ // The "intrinsics" new/make/len/cap are forbidden here.
+ // panic is treated like an ordinary function call.
+ v := Go{pos: s.Go}
+ b.setCall(fn, s.Call, &v.Call)
+ fn.emit(&v)
+
+ case *ast.DeferStmt:
+ // The "intrinsics" new/make/len/cap are forbidden here.
+ // panic is treated like an ordinary function call.
+ v := Defer{pos: s.Defer}
+ b.setCall(fn, s.Call, &v.Call)
+ fn.emit(&v)
+
+ // A deferred call can cause recovery from panic,
+ // and control resumes at the Recover block.
+ createRecoverBlock(fn)
+
+ case *ast.ReturnStmt:
+ var results []Value
+ if len(s.Results) == 1 && fn.Signature.Results().Len() > 1 {
+ // Return of one expression in a multi-valued function.
+ tuple := b.exprN(fn, s.Results[0])
+ ttuple := tuple.Type().(*types.Tuple)
+ for i, n := 0, ttuple.Len(); i < n; i++ {
+ results = append(results,
+ emitConv(fn, emitExtract(fn, tuple, i),
+ fn.Signature.Results().At(i).Type()))
+ }
+ } else {
+ // 1:1 return, or no-arg return in non-void function.
+ for i, r := range s.Results {
+ v := emitConv(fn, b.expr(fn, r), fn.Signature.Results().At(i).Type())
+ results = append(results, v)
+ }
+ }
+ if fn.namedResults != nil {
+ // Function has named result parameters (NRPs).
+ // Perform parallel assignment of return operands to NRPs.
+ for i, r := range results {
+ emitStore(fn, fn.namedResults[i], r, s.Return)
+ }
+ }
+ // Run function calls deferred in this
+ // function when explicitly returning from it.
+ fn.emit(new(RunDefers))
+ if fn.namedResults != nil {
+ // Reload NRPs to form the result tuple.
+ results = results[:0]
+ for _, r := range fn.namedResults {
+ results = append(results, emitLoad(fn, r))
+ }
+ }
+ fn.emit(&Return{Results: results, pos: s.Return})
+ fn.currentBlock = fn.newBasicBlock("unreachable")
+
+ case *ast.BranchStmt:
+ var block *BasicBlock
+ switch s.Tok {
+ case token.BREAK:
+ if s.Label != nil {
+ block = fn.labelledBlock(s.Label)._break
+ } else {
+ for t := fn.targets; t != nil && block == nil; t = t.tail {
+ block = t._break
+ }
+ }
+
+ case token.CONTINUE:
+ if s.Label != nil {
+ block = fn.labelledBlock(s.Label)._continue
+ } else {
+ for t := fn.targets; t != nil && block == nil; t = t.tail {
+ block = t._continue
+ }
+ }
+
+ case token.FALLTHROUGH:
+ for t := fn.targets; t != nil && block == nil; t = t.tail {
+ block = t._fallthrough
+ }
+
+ case token.GOTO:
+ block = fn.labelledBlock(s.Label)._goto
+ }
+ emitJump(fn, block)
+ fn.currentBlock = fn.newBasicBlock("unreachable")
+
+ case *ast.BlockStmt:
+ b.stmtList(fn, s.List)
+
+ case *ast.IfStmt:
+ if s.Init != nil {
+ b.stmt(fn, s.Init)
+ }
+ then := fn.newBasicBlock("if.then")
+ done := fn.newBasicBlock("if.done")
+ els := done
+ if s.Else != nil {
+ els = fn.newBasicBlock("if.else")
+ }
+ b.cond(fn, s.Cond, then, els)
+ fn.currentBlock = then
+ b.stmt(fn, s.Body)
+ emitJump(fn, done)
+
+ if s.Else != nil {
+ fn.currentBlock = els
+ b.stmt(fn, s.Else)
+ emitJump(fn, done)
+ }
+
+ fn.currentBlock = done
+
+ case *ast.SwitchStmt:
+ b.switchStmt(fn, s, label)
+
+ case *ast.TypeSwitchStmt:
+ b.typeSwitchStmt(fn, s, label)
+
+ case *ast.SelectStmt:
+ b.selectStmt(fn, s, label)
+
+ case *ast.ForStmt:
+ b.forStmt(fn, s, label)
+
+ case *ast.RangeStmt:
+ b.rangeStmt(fn, s, label)
+
+ default:
+ panic(fmt.Sprintf("unexpected statement kind: %T", s))
+ }
+}
+
+// buildFunction builds SSA code for the body of function fn. Idempotent.
+func (b *builder) buildFunction(fn *Function) {
+ if fn.Blocks != nil {
+ return // building already started
+ }
+
+ var recvField *ast.FieldList
+ var body *ast.BlockStmt
+ var functype *ast.FuncType
+ switch n := fn.syntax.(type) {
+ case nil:
+ return // not a Go source function. (Synthetic, or from object file.)
+ case *ast.FuncDecl:
+ functype = n.Type
+ recvField = n.Recv
+ body = n.Body
+ case *ast.FuncLit:
+ functype = n.Type
+ body = n.Body
+ default:
+ panic(n)
+ }
+
+ if body == nil {
+ // External function.
+ if fn.Params == nil {
+ // This condition ensures we add a non-empty
+ // params list once only, but we may attempt
+ // the degenerate empty case repeatedly.
+ // TODO(adonovan): opt: don't do that.
+
+ // We set Function.Params even though there is no body
+ // code to reference them. This simplifies clients.
+ if recv := fn.Signature.Recv(); recv != nil {
+ fn.addParamObj(recv)
+ }
+ params := fn.Signature.Params()
+ for i, n := 0, params.Len(); i < n; i++ {
+ fn.addParamObj(params.At(i))
+ }
+ }
+ return
+ }
+ if fn.Prog.mode&LogSource != 0 {
+ defer logStack("build function %s @ %s", fn, fn.Prog.Fset.Position(fn.pos))()
+ }
+ fn.startBody()
+ fn.createSyntacticParams(recvField, functype)
+ b.stmt(fn, body)
+ if cb := fn.currentBlock; cb != nil && (cb == fn.Blocks[0] || cb == fn.Recover || cb.Preds != nil) {
+ // Control fell off the end of the function's body block.
+ //
+ // Block optimizations eliminate the current block, if
+ // unreachable. It is a builder invariant that
+ // if this no-arg return is ill-typed for
+ // fn.Signature.Results, this block must be
+ // unreachable. The sanity checker checks this.
+ fn.emit(new(RunDefers))
+ fn.emit(new(Return))
+ }
+ fn.finishBody()
+}
+
+// buildFuncDecl builds SSA code for the function or method declared
+// by decl in package pkg.
+//
+func (b *builder) buildFuncDecl(pkg *Package, decl *ast.FuncDecl) {
+ id := decl.Name
+ if isBlankIdent(id) {
+ return // discard
+ }
+ fn := pkg.values[pkg.info.Defs[id]].(*Function)
+ if decl.Recv == nil && id.Name == "init" {
+ var v Call
+ v.Call.Value = fn
+ v.setType(types.NewTuple())
+ pkg.init.emit(&v)
+ }
+ b.buildFunction(fn)
+}
+
+// BuildAll calls Package.Build() for each package in prog.
+// Building occurs in parallel unless the BuildSerially mode flag was set.
+//
+// BuildAll is intended for whole-program analysis; a typical compiler
+// need only build a single package.
+//
+// BuildAll is idempotent and thread-safe.
+//
+// TODO(adonovan): rename to Build.
+//
+func (prog *Program) BuildAll() {
+ var wg sync.WaitGroup
+ for _, p := range prog.packages {
+ if prog.mode&BuildSerially != 0 {
+ p.Build()
+ } else {
+ wg.Add(1)
+ go func(p *Package) {
+ p.Build()
+ wg.Done()
+ }(p)
+ }
+ }
+ wg.Wait()
+}
+
+// Build builds SSA code for all functions and vars in package p.
+//
+// Precondition: CreatePackage must have been called for all of p's
+// direct imports (and hence its direct imports must have been
+// error-free).
+//
+// Build is idempotent and thread-safe.
+//
+func (p *Package) Build() {
+ if !atomic.CompareAndSwapInt32(&p.started, 0, 1) {
+ return // already started
+ }
+ if p.info == nil {
+ return // synthetic package, e.g. "testmain"
+ }
+ if p.files == nil {
+ p.info = nil
+ return // package loaded from export data
+ }
+
+ // Ensure we have runtime type info for all exported members.
+ // TODO(adonovan): ideally belongs in memberFromObject, but
+ // that would require package creation in topological order.
+ for name, mem := range p.Members {
+ if ast.IsExported(name) {
+ p.Prog.needMethodsOf(mem.Type())
+ }
+ }
+ if p.Prog.mode&LogSource != 0 {
+ defer logStack("build %s", p)()
+ }
+ init := p.init
+ init.startBody()
+
+ var done *BasicBlock
+
+ if p.Prog.mode&BareInits == 0 {
+ // Make init() skip if package is already initialized.
+ initguard := p.Var("init$guard")
+ doinit := init.newBasicBlock("init.start")
+ done = init.newBasicBlock("init.done")
+ emitIf(init, emitLoad(init, initguard), done, doinit)
+ init.currentBlock = doinit
+ emitStore(init, initguard, vTrue, token.NoPos)
+
+ // Call the init() function of each package we import.
+ for _, pkg := range p.Object.Imports() {
+ prereq := p.Prog.packages[pkg]
+ if prereq == nil {
+ panic(fmt.Sprintf("Package(%q).Build(): unsatisfied import: Program.CreatePackage(%q) was not called", p.Object.Path(), pkg.Path()))
+ }
+ var v Call
+ v.Call.Value = prereq.init
+ v.Call.pos = init.pos
+ v.setType(types.NewTuple())
+ init.emit(&v)
+ }
+ }
+
+ var b builder
+
+ // Initialize package-level vars in correct order.
+ for _, varinit := range p.info.InitOrder {
+ if init.Prog.mode&LogSource != 0 {
+ fmt.Fprintf(os.Stderr, "build global initializer %v @ %s\n",
+ varinit.Lhs, p.Prog.Fset.Position(varinit.Rhs.Pos()))
+ }
+ if len(varinit.Lhs) == 1 {
+ // 1:1 initialization: var x, y = a(), b()
+ var lval lvalue
+ if v := varinit.Lhs[0]; v.Name() != "_" {
+ lval = &address{addr: p.values[v].(*Global), pos: v.Pos()}
+ } else {
+ lval = blank{}
+ }
+ b.assign(init, lval, varinit.Rhs, true, nil)
+ } else {
+ // n:1 initialization: var x, y := f()
+ tuple := b.exprN(init, varinit.Rhs)
+ for i, v := range varinit.Lhs {
+ if v.Name() == "_" {
+ continue
+ }
+ emitStore(init, p.values[v].(*Global), emitExtract(init, tuple, i), v.Pos())
+ }
+ }
+ }
+
+ // Build all package-level functions, init functions
+ // and methods, including unreachable/blank ones.
+ // We build them in source order, but it's not significant.
+ for _, file := range p.files {
+ for _, decl := range file.Decls {
+ if decl, ok := decl.(*ast.FuncDecl); ok {
+ b.buildFuncDecl(p, decl)
+ }
+ }
+ }
+
+ // Finish up init().
+ if p.Prog.mode&BareInits == 0 {
+ emitJump(init, done)
+ init.currentBlock = done
+ }
+ init.emit(new(Return))
+ init.finishBody()
+
+ p.info = nil // We no longer need ASTs or go/types deductions.
+
+ if p.Prog.mode&SanityCheckFunctions != 0 {
+ sanityCheckPackage(p)
+ }
+}
+
+// Like ObjectOf, but panics instead of returning nil.
+// Only valid during p's create and build phases.
+func (p *Package) objectOf(id *ast.Ident) types.Object {
+ if o := p.info.ObjectOf(id); o != nil {
+ return o
+ }
+ panic(fmt.Sprintf("no types.Object for ast.Ident %s @ %s",
+ id.Name, p.Prog.Fset.Position(id.Pos())))
+}
+
+// Like TypeOf, but panics instead of returning nil.
+// Only valid during p's create and build phases.
+func (p *Package) typeOf(e ast.Expr) types.Type {
+ if T := p.info.TypeOf(e); T != nil {
+ return T
+ }
+ panic(fmt.Sprintf("no type for %T @ %s",
+ e, p.Prog.Fset.Position(e.Pos())))
+}
diff --git a/go/ssa/builder_test.go b/go/ssa/builder_test.go
new file mode 100644
index 0000000..e7ac838
--- /dev/null
+++ b/go/ssa/builder_test.go
@@ -0,0 +1,419 @@
+// 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 ssa_test
+
+import (
+ "bytes"
+ "go/ast"
+ "go/parser"
+ "go/token"
+ "reflect"
+ "sort"
+ "strings"
+ "testing"
+
+ "golang.org/x/tools/go/loader"
+ "golang.org/x/tools/go/ssa"
+ "golang.org/x/tools/go/ssa/ssautil"
+ "golang.org/x/tools/go/types"
+
+ _ "golang.org/x/tools/go/gcimporter"
+)
+
+func isEmpty(f *ssa.Function) bool { return f.Blocks == nil }
+
+// Tests that programs partially loaded from gc object files contain
+// functions with no code for the external portions, but are otherwise ok.
+func TestBuildPackage(t *testing.T) {
+ input := `
+package main
+
+import (
+ "bytes"
+ "io"
+ "testing"
+)
+
+func main() {
+ var t testing.T
+ t.Parallel() // static call to external declared method
+ t.Fail() // static call to promoted external declared method
+ testing.Short() // static call to external package-level function
+
+ var w io.Writer = new(bytes.Buffer)
+ w.Write(nil) // interface invoke of external declared method
+}
+`
+
+ // Parse the file.
+ fset := token.NewFileSet()
+ f, err := parser.ParseFile(fset, "input.go", input, 0)
+ if err != nil {
+ t.Error(err)
+ return
+ }
+
+ // Build an SSA program from the parsed file.
+ // Load its dependencies from gc binary export data.
+ mainPkg, _, err := ssautil.BuildPackage(new(types.Config), fset,
+ types.NewPackage("main", ""), []*ast.File{f}, ssa.SanityCheckFunctions)
+ if err != nil {
+ t.Error(err)
+ return
+ }
+
+ // The main package, its direct and indirect dependencies are loaded.
+ deps := []string{
+ // directly imported dependencies:
+ "bytes", "io", "testing",
+ // indirect dependencies (partial list):
+ "errors", "fmt", "os", "runtime",
+ }
+
+ prog := mainPkg.Prog
+ all := prog.AllPackages()
+ if len(all) <= len(deps) {
+ t.Errorf("unexpected set of loaded packages: %q", all)
+ }
+ for _, path := range deps {
+ pkg := prog.ImportedPackage(path)
+ if pkg == nil {
+ t.Errorf("package not loaded: %q", path)
+ continue
+ }
+
+ // External packages should have no function bodies (except for wrappers).
+ isExt := pkg != mainPkg
+
+ // init()
+ if isExt && !isEmpty(pkg.Func("init")) {
+ t.Errorf("external package %s has non-empty init", pkg)
+ } else if !isExt && isEmpty(pkg.Func("init")) {
+ t.Errorf("main package %s has empty init", pkg)
+ }
+
+ for _, mem := range pkg.Members {
+ switch mem := mem.(type) {
+ case *ssa.Function:
+ // Functions at package level.
+ if isExt && !isEmpty(mem) {
+ t.Errorf("external function %s is non-empty", mem)
+ } else if !isExt && isEmpty(mem) {
+ t.Errorf("function %s is empty", mem)
+ }
+
+ case *ssa.Type:
+ // Methods of named types T.
+ // (In this test, all exported methods belong to *T not T.)
+ if !isExt {
+ t.Fatalf("unexpected name type in main package: %s", mem)
+ }
+ mset := prog.MethodSets.MethodSet(types.NewPointer(mem.Type()))
+ for i, n := 0, mset.Len(); i < n; i++ {
+ m := prog.Method(mset.At(i))
+ // For external types, only synthetic wrappers have code.
+ expExt := !strings.Contains(m.Synthetic, "wrapper")
+ if expExt && !isEmpty(m) {
+ t.Errorf("external method %s is non-empty: %s",
+ m, m.Synthetic)
+ } else if !expExt && isEmpty(m) {
+ t.Errorf("method function %s is empty: %s",
+ m, m.Synthetic)
+ }
+ }
+ }
+ }
+ }
+
+ expectedCallee := []string{
+ "(*testing.T).Parallel",
+ "(*testing.common).Fail",
+ "testing.Short",
+ "N/A",
+ }
+ callNum := 0
+ for _, b := range mainPkg.Func("main").Blocks {
+ for _, instr := range b.Instrs {
+ switch instr := instr.(type) {
+ case ssa.CallInstruction:
+ call := instr.Common()
+ if want := expectedCallee[callNum]; want != "N/A" {
+ got := call.StaticCallee().String()
+ if want != got {
+ t.Errorf("call #%d from main.main: got callee %s, want %s",
+ callNum, got, want)
+ }
+ }
+ callNum++
+ }
+ }
+ }
+ if callNum != 4 {
+ t.Errorf("in main.main: got %d calls, want %d", callNum, 4)
+ }
+}
+
+// TestRuntimeTypes tests that (*Program).RuntimeTypes() includes all necessary types.
+func TestRuntimeTypes(t *testing.T) {
+ tests := []struct {
+ input string
+ want []string
+ }{
+ // An exported package-level type is needed.
+ {`package A; type T struct{}; func (T) f() {}`,
+ []string{"*p.T", "p.T"},
+ },
+ // An unexported package-level type is not needed.
+ {`package B; type t struct{}; func (t) f() {}`,
+ nil,
+ },
+ // Subcomponents of type of exported package-level var are needed.
+ {`package C; import "bytes"; var V struct {*bytes.Buffer}`,
+ []string{"*bytes.Buffer", "*struct{*bytes.Buffer}", "struct{*bytes.Buffer}"},
+ },
+ // Subcomponents of type of unexported package-level var are not needed.
+ {`package D; import "bytes"; var v struct {*bytes.Buffer}`,
+ nil,
+ },
+ // Subcomponents of type of exported package-level function are needed.
+ {`package E; import "bytes"; func F(struct {*bytes.Buffer}) {}`,
+ []string{"*bytes.Buffer", "struct{*bytes.Buffer}"},
+ },
+ // Subcomponents of type of unexported package-level function are not needed.
+ {`package F; import "bytes"; func f(struct {*bytes.Buffer}) {}`,
+ nil,
+ },
+ // Subcomponents of type of exported method of uninstantiated unexported type are not needed.
+ {`package G; import "bytes"; type x struct{}; func (x) G(struct {*bytes.Buffer}) {}; var v x`,
+ nil,
+ },
+ // ...unless used by MakeInterface.
+ {`package G2; import "bytes"; type x struct{}; func (x) G(struct {*bytes.Buffer}) {}; var v interface{} = x{}`,
+ []string{"*bytes.Buffer", "*p.x", "p.x", "struct{*bytes.Buffer}"},
+ },
+ // Subcomponents of type of unexported method are not needed.
+ {`package I; import "bytes"; type X struct{}; func (X) G(struct {*bytes.Buffer}) {}`,
+ []string{"*bytes.Buffer", "*p.X", "p.X", "struct{*bytes.Buffer}"},
+ },
+ // Local types aren't needed.
+ {`package J; import "bytes"; func f() { type T struct {*bytes.Buffer}; var t T; _ = t }`,
+ nil,
+ },
+ // ...unless used by MakeInterface.
+ {`package K; import "bytes"; func f() { type T struct {*bytes.Buffer}; _ = interface{}(T{}) }`,
+ []string{"*bytes.Buffer", "*p.T", "p.T"},
+ },
+ // Types used as operand of MakeInterface are needed.
+ {`package L; import "bytes"; func f() { _ = interface{}(struct{*bytes.Buffer}{}) }`,
+ []string{"*bytes.Buffer", "struct{*bytes.Buffer}"},
+ },
+ // MakeInterface is optimized away when storing to a blank.
+ {`package M; import "bytes"; var _ interface{} = struct{*bytes.Buffer}{}`,
+ nil,
+ },
+ }
+ for _, test := range tests {
+ // Parse the file.
+ fset := token.NewFileSet()
+ f, err := parser.ParseFile(fset, "input.go", test.input, 0)
+ if err != nil {
+ t.Errorf("test %q: %s", test.input[:15], err)
+ continue
+ }
+
+ // Create a single-file main package.
+ // Load dependencies from gc binary export data.
+ ssapkg, _, err := ssautil.BuildPackage(new(types.Config), fset,
+ types.NewPackage("p", ""), []*ast.File{f}, ssa.SanityCheckFunctions)
+ if err != nil {
+ t.Errorf("test %q: %s", test.input[:15], err)
+ continue
+ }
+
+ var typstrs []string
+ for _, T := range ssapkg.Prog.RuntimeTypes() {
+ typstrs = append(typstrs, T.String())
+ }
+ sort.Strings(typstrs)
+
+ if !reflect.DeepEqual(typstrs, test.want) {
+ t.Errorf("test 'package %s': got %q, want %q",
+ f.Name.Name, typstrs, test.want)
+ }
+ }
+}
+
+// TestInit tests that synthesized init functions are correctly formed.
+// Bare init functions omit calls to dependent init functions and the use of
+// an init guard. They are useful in cases where the client uses a different
+// calling convention for init functions, or cases where it is easier for a
+// client to analyze bare init functions. Both of these aspects are used by
+// the llgo compiler for simpler integration with gccgo's runtime library,
+// and to simplify the analysis whereby it deduces which stores to globals
+// can be lowered to global initializers.
+func TestInit(t *testing.T) {
+ tests := []struct {
+ mode ssa.BuilderMode
+ input, want string
+ }{
+ {0, `package A; import _ "errors"; var i int = 42`,
+ `# Name: A.init
+# Package: A
+# Synthetic: package initializer
+func init():
+0: entry P:0 S:2
+ t0 = *init$guard bool
+ if t0 goto 2 else 1
+1: init.start P:1 S:1
+ *init$guard = true:bool
+ t1 = errors.init() ()
+ *i = 42:int
+ jump 2
+2: init.done P:2 S:0
+ return
+
+`},
+ {ssa.BareInits, `package B; import _ "errors"; var i int = 42`,
+ `# Name: B.init
+# Package: B
+# Synthetic: package initializer
+func init():
+0: entry P:0 S:0
+ *i = 42:int
+ return
+
+`},
+ }
+ for _, test := range tests {
+ // Create a single-file main package.
+ var conf loader.Config
+ f, err := conf.ParseFile("<input>", test.input)
+ if err != nil {
+ t.Errorf("test %q: %s", test.input[:15], err)
+ continue
+ }
+ conf.CreateFromFiles(f.Name.Name, f)
+
+ lprog, err := conf.Load()
+ if err != nil {
+ t.Errorf("test 'package %s': Load: %s", f.Name.Name, err)
+ continue
+ }
+ prog := ssautil.CreateProgram(lprog, test.mode)
+ mainPkg := prog.Package(lprog.Created[0].Pkg)
+ prog.BuildAll()
+ initFunc := mainPkg.Func("init")
+ if initFunc == nil {
+ t.Errorf("test 'package %s': no init function", f.Name.Name)
+ continue
+ }
+
+ var initbuf bytes.Buffer
+ _, err = initFunc.WriteTo(&initbuf)
+ if err != nil {
+ t.Errorf("test 'package %s': WriteTo: %s", f.Name.Name, err)
+ continue
+ }
+
+ if initbuf.String() != test.want {
+ t.Errorf("test 'package %s': got %s, want %s", f.Name.Name, initbuf.String(), test.want)
+ }
+ }
+}
+
+// TestSyntheticFuncs checks that the expected synthetic functions are
+// created, reachable, and not duplicated.
+func TestSyntheticFuncs(t *testing.T) {
+ const input = `package P
+type T int
+func (T) f() int
+func (*T) g() int
+var (
+ // thunks
+ a = T.f
+ b = T.f
+ c = (struct{T}).f
+ d = (struct{T}).f
+ e = (*T).g
+ f = (*T).g
+ g = (struct{*T}).g
+ h = (struct{*T}).g
+
+ // bounds
+ i = T(0).f
+ j = T(0).f
+ k = new(T).g
+ l = new(T).g
+
+ // wrappers
+ m interface{} = struct{T}{}
+ n interface{} = struct{T}{}
+ o interface{} = struct{*T}{}
+ p interface{} = struct{*T}{}
+ q interface{} = new(struct{T})
+ r interface{} = new(struct{T})
+ s interface{} = new(struct{*T})
+ t interface{} = new(struct{*T})
+)
+`
+ // Parse
+ var conf loader.Config
+ f, err := conf.ParseFile("<input>", input)
+ if err != nil {
+ t.Fatalf("parse: %v", err)
+ }
+ conf.CreateFromFiles(f.Name.Name, f)
+
+ // Load
+ lprog, err := conf.Load()
+ if err != nil {
+ t.Fatalf("Load: %v", err)
+ }
+
+ // Create and build SSA
+ prog := ssautil.CreateProgram(lprog, 0)
+ prog.BuildAll()
+
+ // Enumerate reachable synthetic functions
+ want := map[string]string{
+ "(*P.T).g$bound": "bound method wrapper for func (*P.T).g() int",
+ "(P.T).f$bound": "bound method wrapper for func (P.T).f() int",
+
+ "(*P.T).g$thunk": "thunk for func (*P.T).g() int",
+ "(P.T).f$thunk": "thunk for func (P.T).f() int",
+ "(struct{*P.T}).g$thunk": "thunk for func (*P.T).g() int",
+ "(struct{P.T}).f$thunk": "thunk for func (P.T).f() int",
+
+ "(*P.T).f": "wrapper for func (P.T).f() int",
+ "(*struct{*P.T}).f": "wrapper for func (P.T).f() int",
+ "(*struct{*P.T}).g": "wrapper for func (*P.T).g() int",
+ "(*struct{P.T}).f": "wrapper for func (P.T).f() int",
+ "(*struct{P.T}).g": "wrapper for func (*P.T).g() int",
+ "(struct{*P.T}).f": "wrapper for func (P.T).f() int",
+ "(struct{*P.T}).g": "wrapper for func (*P.T).g() int",
+ "(struct{P.T}).f": "wrapper for func (P.T).f() int",
+
+ "P.init": "package initializer",
+ }
+ for fn := range ssautil.AllFunctions(prog) {
+ if fn.Synthetic == "" {
+ continue
+ }
+ name := fn.String()
+ wantDescr, ok := want[name]
+ if !ok {
+ t.Errorf("got unexpected/duplicate func: %q: %q", name, fn.Synthetic)
+ continue
+ }
+ delete(want, name)
+
+ if wantDescr != fn.Synthetic {
+ t.Errorf("(%s).Synthetic = %q, want %q", name, fn.Synthetic, wantDescr)
+ }
+ }
+ for fn, descr := range want {
+ t.Errorf("want func: %q: %q", fn, descr)
+ }
+}
diff --git a/go/ssa/const.go b/go/ssa/const.go
new file mode 100644
index 0000000..304096e
--- /dev/null
+++ b/go/ssa/const.go
@@ -0,0 +1,168 @@
+// 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 ssa
+
+// This file defines the Const SSA value type.
+
+import (
+ "fmt"
+ "go/token"
+ "strconv"
+
+ "golang.org/x/tools/go/exact"
+ "golang.org/x/tools/go/types"
+)
+
+// NewConst returns a new constant of the specified value and type.
+// val must be valid according to the specification of Const.Value.
+//
+func NewConst(val exact.Value, typ types.Type) *Const {
+ return &Const{typ, val}
+}
+
+// intConst returns an 'int' constant that evaluates to i.
+// (i is an int64 in case the host is narrower than the target.)
+func intConst(i int64) *Const {
+ return NewConst(exact.MakeInt64(i), tInt)
+}
+
+// nilConst returns a nil constant of the specified type, which may
+// be any reference type, including interfaces.
+//
+func nilConst(typ types.Type) *Const {
+ return NewConst(nil, typ)
+}
+
+// stringConst returns a 'string' constant that evaluates to s.
+func stringConst(s string) *Const {
+ return NewConst(exact.MakeString(s), tString)
+}
+
+// zeroConst returns a new "zero" constant of the specified type,
+// which must not be an array or struct type: the zero values of
+// aggregates are well-defined but cannot be represented by Const.
+//
+func zeroConst(t types.Type) *Const {
+ switch t := t.(type) {
+ case *types.Basic:
+ switch {
+ case t.Info()&types.IsBoolean != 0:
+ return NewConst(exact.MakeBool(false), t)
+ case t.Info()&types.IsNumeric != 0:
+ return NewConst(exact.MakeInt64(0), t)
+ case t.Info()&types.IsString != 0:
+ return NewConst(exact.MakeString(""), t)
+ case t.Kind() == types.UnsafePointer:
+ fallthrough
+ case t.Kind() == types.UntypedNil:
+ return nilConst(t)
+ default:
+ panic(fmt.Sprint("zeroConst for unexpected type:", t))
+ }
+ case *types.Pointer, *types.Slice, *types.Interface, *types.Chan, *types.Map, *types.Signature:
+ return nilConst(t)
+ case *types.Named:
+ return NewConst(zeroConst(t.Underlying()).Value, t)
+ case *types.Array, *types.Struct, *types.Tuple:
+ panic(fmt.Sprint("zeroConst applied to aggregate:", t))
+ }
+ panic(fmt.Sprint("zeroConst: unexpected ", t))
+}
+
+func (c *Const) RelString(from *types.Package) string {
+ var s string
+ if c.Value == nil {
+ s = "nil"
+ } else if c.Value.Kind() == exact.String {
+ s = exact.StringVal(c.Value)
+ const max = 20
+ // TODO(adonovan): don't cut a rune in half.
+ if len(s) > max {
+ s = s[:max-3] + "..." // abbreviate
+ }
+ s = strconv.Quote(s)
+ } else {
+ s = c.Value.String()
+ }
+ return s + ":" + relType(c.Type(), from)
+}
+
+func (c *Const) Name() string {
+ return c.RelString(nil)
+}
+
+func (c *Const) String() string {
+ return c.Name()
+}
+
+func (c *Const) Type() types.Type {
+ return c.typ
+}
+
+func (c *Const) Referrers() *[]Instruction {
+ return nil
+}
+
+func (c *Const) Parent() *Function { return nil }
+
+func (c *Const) Pos() token.Pos {
+ return token.NoPos
+}
+
+// IsNil returns true if this constant represents a typed or untyped nil value.
+func (c *Const) IsNil() bool {
+ return c.Value == nil
+}
+
+// Int64 returns the numeric value of this constant truncated to fit
+// a signed 64-bit integer.
+//
+func (c *Const) Int64() int64 {
+ switch x := c.Value; x.Kind() {
+ case exact.Int:
+ if i, ok := exact.Int64Val(x); ok {
+ return i
+ }
+ return 0
+ case exact.Float:
+ f, _ := exact.Float64Val(x)
+ return int64(f)
+ }
+ panic(fmt.Sprintf("unexpected constant value: %T", c.Value))
+}
+
+// Uint64 returns the numeric value of this constant truncated to fit
+// an unsigned 64-bit integer.
+//
+func (c *Const) Uint64() uint64 {
+ switch x := c.Value; x.Kind() {
+ case exact.Int:
+ if u, ok := exact.Uint64Val(x); ok {
+ return u
+ }
+ return 0
+ case exact.Float:
+ f, _ := exact.Float64Val(x)
+ return uint64(f)
+ }
+ panic(fmt.Sprintf("unexpected constant value: %T", c.Value))
+}
+
+// Float64 returns the numeric value of this constant truncated to fit
+// a float64.
+//
+func (c *Const) Float64() float64 {
+ f, _ := exact.Float64Val(c.Value)
+ return f
+}
+
+// Complex128 returns the complex value of this constant truncated to
+// fit a complex128.
+//
+func (c *Const) Complex128() complex128 {
+ re, _ := exact.Float64Val(exact.Real(c.Value))
+ im, _ := exact.Float64Val(exact.Imag(c.Value))
+ return complex(re, im)
+}
diff --git a/go/ssa/create.go b/go/ssa/create.go
new file mode 100644
index 0000000..88226ae
--- /dev/null
+++ b/go/ssa/create.go
@@ -0,0 +1,257 @@
+// 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 ssa
+
+// This file implements the CREATE phase of SSA construction.
+// See builder.go for explanation.
+
+import (
+ "fmt"
+ "go/ast"
+ "go/token"
+ "os"
+ "sync"
+
+ "golang.org/x/tools/go/types"
+ "golang.org/x/tools/go/types/typeutil"
+)
+
+// NewProgram returns a new SSA Program.
+//
+// mode controls diagnostics and checking during SSA construction.
+//
+func NewProgram(fset *token.FileSet, mode BuilderMode) *Program {
+ prog := &Program{
+ Fset: fset,
+ imported: make(map[string]*Package),
+ packages: make(map[*types.Package]*Package),
+ thunks: make(map[selectionKey]*Function),
+ bounds: make(map[*types.Func]*Function),
+ mode: mode,
+ }
+
+ h := typeutil.MakeHasher() // protected by methodsMu, in effect
+ prog.methodSets.SetHasher(h)
+ prog.canon.SetHasher(h)
+
+ return prog
+}
+
+// memberFromObject populates package pkg with a member for the
+// typechecker object obj.
+//
+// For objects from Go source code, syntax is the associated syntax
+// tree (for funcs and vars only); it will be used during the build
+// phase.
+//
+func memberFromObject(pkg *Package, obj types.Object, syntax ast.Node) {
+ name := obj.Name()
+ switch obj := obj.(type) {
+ case *types.TypeName:
+ pkg.Members[name] = &Type{
+ object: obj,
+ pkg: pkg,
+ }
+
+ case *types.Const:
+ c := &NamedConst{
+ object: obj,
+ Value: NewConst(obj.Val(), obj.Type()),
+ pkg: pkg,
+ }
+ pkg.values[obj] = c.Value
+ pkg.Members[name] = c
+
+ case *types.Var:
+ g := &Global{
+ Pkg: pkg,
+ name: name,
+ object: obj,
+ typ: types.NewPointer(obj.Type()), // address
+ pos: obj.Pos(),
+ }
+ pkg.values[obj] = g
+ pkg.Members[name] = g
+
+ case *types.Func:
+ sig := obj.Type().(*types.Signature)
+ if sig.Recv() == nil && name == "init" {
+ pkg.ninit++
+ name = fmt.Sprintf("init#%d", pkg.ninit)
+ }
+ fn := &Function{
+ name: name,
+ object: obj,
+ Signature: sig,
+ syntax: syntax,
+ pos: obj.Pos(),
+ Pkg: pkg,
+ Prog: pkg.Prog,
+ }
+ if syntax == nil {
+ fn.Synthetic = "loaded from gc object file"
+ }
+
+ pkg.values[obj] = fn
+ if sig.Recv() == nil {
+ pkg.Members[name] = fn // package-level function
+ }
+
+ default: // (incl. *types.Package)
+ panic("unexpected Object type: " + obj.String())
+ }
+}
+
+// membersFromDecl populates package pkg with members for each
+// typechecker object (var, func, const or type) associated with the
+// specified decl.
+//
+func membersFromDecl(pkg *Package, decl ast.Decl) {
+ switch decl := decl.(type) {
+ case *ast.GenDecl: // import, const, type or var
+ switch decl.Tok {
+ case token.CONST:
+ for _, spec := range decl.Specs {
+ for _, id := range spec.(*ast.ValueSpec).Names {
+ if !isBlankIdent(id) {
+ memberFromObject(pkg, pkg.info.Defs[id], nil)
+ }
+ }
+ }
+
+ case token.VAR:
+ for _, spec := range decl.Specs {
+ for _, id := range spec.(*ast.ValueSpec).Names {
+ if !isBlankIdent(id) {
+ memberFromObject(pkg, pkg.info.Defs[id], spec)
+ }
+ }
+ }
+
+ case token.TYPE:
+ for _, spec := range decl.Specs {
+ id := spec.(*ast.TypeSpec).Name
+ if !isBlankIdent(id) {
+ memberFromObject(pkg, pkg.info.Defs[id], nil)
+ }
+ }
+ }
+
+ case *ast.FuncDecl:
+ id := decl.Name
+ if !isBlankIdent(id) {
+ memberFromObject(pkg, pkg.info.Defs[id], decl)
+ }
+ }
+}
+
+// CreatePackage constructs and returns an SSA Package from the
+// specified type-checked, error-free file ASTs, and populates its
+// Members mapping.
+//
+// importable determines whether this package should be returned by a
+// subsequent call to ImportedPackage(pkg.Path()).
+//
+// The real work of building SSA form for each function is not done
+// until a subsequent call to Package.Build().
+//
+func (prog *Program) CreatePackage(pkg *types.Package, files []*ast.File, info *types.Info, importable bool) *Package {
+ p := &Package{
+ Prog: prog,
+ Members: make(map[string]Member),
+ values: make(map[types.Object]Value),
+ Object: pkg,
+ info: info, // transient (CREATE and BUILD phases)
+ files: files, // transient (CREATE and BUILD phases)
+ }
+
+ // Add init() function.
+ p.init = &Function{
+ name: "init",
+ Signature: new(types.Signature),
+ Synthetic: "package initializer",
+ Pkg: p,
+ Prog: prog,
+ }
+ p.Members[p.init.name] = p.init
+
+ // CREATE phase.
+ // Allocate all package members: vars, funcs, consts and types.
+ if len(files) > 0 {
+ // Go source package.
+ for _, file := range files {
+ for _, decl := range file.Decls {
+ membersFromDecl(p, decl)
+ }
+ }
+ } else {
+ // GC-compiled binary package.
+ // No code.
+ // No position information.
+ scope := p.Object.Scope()
+ for _, name := range scope.Names() {
+ obj := scope.Lookup(name)
+ memberFromObject(p, obj, nil)
+ if obj, ok := obj.(*types.TypeName); ok {
+ named := obj.Type().(*types.Named)
+ for i, n := 0, named.NumMethods(); i < n; i++ {
+ memberFromObject(p, named.Method(i), nil)
+ }
+ }
+ }
+ }
+
+ if prog.mode&BareInits == 0 {
+ // Add initializer guard variable.
+ initguard := &Global{
+ Pkg: p,
+ name: "init$guard",
+ typ: types.NewPointer(tBool),
+ }
+ p.Members[initguard.Name()] = initguard
+ }
+
+ if prog.mode&GlobalDebug != 0 {
+ p.SetDebugMode(true)
+ }
+
+ if prog.mode&PrintPackages != 0 {
+ printMu.Lock()
+ p.WriteTo(os.Stdout)
+ printMu.Unlock()
+ }
+
+ if importable {
+ prog.imported[p.Object.Path()] = p
+ }
+ prog.packages[p.Object] = p
+
+ return p
+}
+
+// printMu serializes printing of Packages/Functions to stdout.
+var printMu sync.Mutex
+
+// AllPackages returns a new slice containing all packages in the
+// program prog in unspecified order.
+//
+func (prog *Program) AllPackages() []*Package {
+ pkgs := make([]*Package, 0, len(prog.packages))
+ for _, pkg := range prog.packages {
+ pkgs = append(pkgs, pkg)
+ }
+ return pkgs
+}
+
+// ImportedPackage returns the importable SSA Package whose import
+// path is path, or nil if no such SSA package has been created.
+//
+// Not all packages are importable. For example, no import
+// declaration can resolve to the x_test package created by 'go test'
+// or the ad-hoc main package created 'go build foo.go'.
+//
+func (prog *Program) ImportedPackage(path string) *Package {
+ return prog.imported[path]
+}
diff --git a/go/ssa/doc.go b/go/ssa/doc.go
new file mode 100644
index 0000000..2aa04f4
--- /dev/null
+++ b/go/ssa/doc.go
@@ -0,0 +1,123 @@
+// 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 ssa defines a representation of the elements of Go programs
+// (packages, types, functions, variables and constants) using a
+// static single-assignment (SSA) form intermediate representation
+// (IR) for the bodies of functions.
+//
+// THIS INTERFACE IS EXPERIMENTAL AND IS LIKELY TO CHANGE.
+//
+// For an introduction to SSA form, see
+// http://en.wikipedia.org/wiki/Static_single_assignment_form.
+// This page provides a broader reading list:
+// http://www.dcs.gla.ac.uk/~jsinger/ssa.html.
+//
+// The level of abstraction of the SSA form is intentionally close to
+// the source language to facilitate construction of source analysis
+// tools. It is not intended for machine code generation.
+//
+// All looping, branching and switching constructs are replaced with
+// unstructured control flow. Higher-level control flow constructs
+// such as multi-way branch can be reconstructed as needed; see
+// ssautil.Switches() for an example.
+//
+// To construct an SSA-form program, call ssautil.CreateProgram on a
+// loader.Program, a set of type-checked packages created from
+// parsed Go source files. The resulting ssa.Program contains all the
+// packages and their members, but SSA code is not created for
+// function bodies until a subsequent call to (*Package).Build.
+//
+// The builder initially builds a naive SSA form in which all local
+// variables are addresses of stack locations with explicit loads and
+// stores. Registerisation of eligible locals and φ-node insertion
+// using dominance and dataflow are then performed as a second pass
+// called "lifting" to improve the accuracy and performance of
+// subsequent analyses; this pass can be skipped by setting the
+// NaiveForm builder flag.
+//
+// The primary interfaces of this package are:
+//
+// - Member: a named member of a Go package.
+// - Value: an expression that yields a value.
+// - Instruction: a statement that consumes values and performs computation.
+// - Node: a Value or Instruction (emphasizing its membership in the SSA value graph)
+//
+// A computation that yields a result implements both the Value and
+// Instruction interfaces. The following table shows for each
+// concrete type which of these interfaces it implements.
+//
+// Value? Instruction? Member?
+// *Alloc ✔ ✔
+// *BinOp ✔ ✔
+// *Builtin ✔
+// *Call ✔ ✔
+// *ChangeInterface ✔ ✔
+// *ChangeType ✔ ✔
+// *Const ✔
+// *Convert ✔ ✔
+// *DebugRef ✔
+// *Defer ✔
+// *Extract ✔ ✔
+// *Field ✔ ✔
+// *FieldAddr ✔ ✔
+// *FreeVar ✔
+// *Function ✔ ✔ (func)
+// *Global ✔ ✔ (var)
+// *Go ✔
+// *If ✔
+// *Index ✔ ✔
+// *IndexAddr ✔ ✔
+// *Jump ✔
+// *Lookup ✔ ✔
+// *MakeChan ✔ ✔
+// *MakeClosure ✔ ✔
+// *MakeInterface ✔ ✔
+// *MakeMap ✔ ✔
+// *MakeSlice ✔ ✔
+// *MapUpdate ✔
+// *NamedConst ✔ (const)
+// *Next ✔ ✔
+// *Panic ✔
+// *Parameter ✔
+// *Phi ✔ ✔
+// *Range ✔ ✔
+// *Return ✔
+// *RunDefers ✔
+// *Select ✔ ✔
+// *Send ✔
+// *Slice ✔ ✔
+// *Store ✔
+// *Type ✔ (type)
+// *TypeAssert ✔ ✔
+// *UnOp ✔ ✔
+//
+// Other key types in this package include: Program, Package, Function
+// and BasicBlock.
+//
+// The program representation constructed by this package is fully
+// resolved internally, i.e. it does not rely on the names of Values,
+// Packages, Functions, Types or BasicBlocks for the correct
+// interpretation of the program. Only the identities of objects and
+// the topology of the SSA and type graphs are semantically
+// significant. (There is one exception: Ids, used to identify field
+// and method names, contain strings.) Avoidance of name-based
+// operations simplifies the implementation of subsequent passes and
+// can make them very efficient. Many objects are nonetheless named
+// to aid in debugging, but it is not essential that the names be
+// either accurate or unambiguous. The public API exposes a number of
+// name-based maps for client convenience.
+//
+// The ssa/ssautil package provides various utilities that depend only
+// on the public API of this package.
+//
+// TODO(adonovan): Consider the exceptional control-flow implications
+// of defer and recover().
+//
+// TODO(adonovan): write a how-to document for all the various cases
+// of trying to determine corresponding elements across the four
+// domains of source locations, ast.Nodes, types.Objects,
+// ssa.Values/Instructions.
+//
+package ssa // import "golang.org/x/tools/go/ssa"
diff --git a/go/ssa/dom.go b/go/ssa/dom.go
new file mode 100644
index 0000000..12ef430
--- /dev/null
+++ b/go/ssa/dom.go
@@ -0,0 +1,341 @@
+// 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 ssa
+
+// This file defines algorithms related to dominance.
+
+// Dominator tree construction ----------------------------------------
+//
+// We use the algorithm described in Lengauer & Tarjan. 1979. A fast
+// algorithm for finding dominators in a flowgraph.
+// http://doi.acm.org/10.1145/357062.357071
+//
+// We also apply the optimizations to SLT described in Georgiadis et
+// al, Finding Dominators in Practice, JGAA 2006,
+// http://jgaa.info/accepted/2006/GeorgiadisTarjanWerneck2006.10.1.pdf
+// to avoid the need for buckets of size > 1.
+
+import (
+ "bytes"
+ "fmt"
+ "math/big"
+ "os"
+ "sort"
+)
+
+// Idom returns the block that immediately dominates b:
+// its parent in the dominator tree, if any.
+// Neither the entry node (b.Index==0) nor recover node
+// (b==b.Parent().Recover()) have a parent.
+//
+func (b *BasicBlock) Idom() *BasicBlock { return b.dom.idom }
+
+// Dominees returns the list of blocks that b immediately dominates:
+// its children in the dominator tree.
+//
+func (b *BasicBlock) Dominees() []*BasicBlock { return b.dom.children }
+
+// Dominates reports whether b dominates c.
+func (b *BasicBlock) Dominates(c *BasicBlock) bool {
+ return b.dom.pre <= c.dom.pre && c.dom.post <= b.dom.post
+}
+
+type byDomPreorder []*BasicBlock
+
+func (a byDomPreorder) Len() int { return len(a) }
+func (a byDomPreorder) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
+func (a byDomPreorder) Less(i, j int) bool { return a[i].dom.pre < a[j].dom.pre }
+
+// DomPreorder returns a new slice containing the blocks of f in
+// dominator tree preorder.
+//
+func (f *Function) DomPreorder() []*BasicBlock {
+ n := len(f.Blocks)
+ order := make(byDomPreorder, n, n)
+ copy(order, f.Blocks)
+ sort.Sort(order)
+ return order
+}
+
+// domInfo contains a BasicBlock's dominance information.
+type domInfo struct {
+ idom *BasicBlock // immediate dominator (parent in domtree)
+ children []*BasicBlock // nodes immediately dominated by this one
+ pre, post int32 // pre- and post-order numbering within domtree
+}
+
+// ltState holds the working state for Lengauer-Tarjan algorithm
+// (during which domInfo.pre is repurposed for CFG DFS preorder number).
+type ltState struct {
+ // Each slice is indexed by b.Index.
+ sdom []*BasicBlock // b's semidominator
+ parent []*BasicBlock // b's parent in DFS traversal of CFG
+ ancestor []*BasicBlock // b's ancestor with least sdom
+}
+
+// dfs implements the depth-first search part of the LT algorithm.
+func (lt *ltState) dfs(v *BasicBlock, i int32, preorder []*BasicBlock) int32 {
+ preorder[i] = v
+ v.dom.pre = i // For now: DFS preorder of spanning tree of CFG
+ i++
+ lt.sdom[v.Index] = v
+ lt.link(nil, v)
+ for _, w := range v.Succs {
+ if lt.sdom[w.Index] == nil {
+ lt.parent[w.Index] = v
+ i = lt.dfs(w, i, preorder)
+ }
+ }
+ return i
+}
+
+// eval implements the EVAL part of the LT algorithm.
+func (lt *ltState) eval(v *BasicBlock) *BasicBlock {
+ // TODO(adonovan): opt: do path compression per simple LT.
+ u := v
+ for ; lt.ancestor[v.Index] != nil; v = lt.ancestor[v.Index] {
+ if lt.sdom[v.Index].dom.pre < lt.sdom[u.Index].dom.pre {
+ u = v
+ }
+ }
+ return u
+}
+
+// link implements the LINK part of the LT algorithm.
+func (lt *ltState) link(v, w *BasicBlock) {
+ lt.ancestor[w.Index] = v
+}
+
+// buildDomTree computes the dominator tree of f using the LT algorithm.
+// Precondition: all blocks are reachable (e.g. optimizeBlocks has been run).
+//
+func buildDomTree(f *Function) {
+ // The step numbers refer to the original LT paper; the
+ // reordering is due to Georgiadis.
+
+ // Clear any previous domInfo.
+ for _, b := range f.Blocks {
+ b.dom = domInfo{}
+ }
+
+ n := len(f.Blocks)
+ // Allocate space for 5 contiguous [n]*BasicBlock arrays:
+ // sdom, parent, ancestor, preorder, buckets.
+ space := make([]*BasicBlock, 5*n, 5*n)
+ lt := ltState{
+ sdom: space[0:n],
+ parent: space[n : 2*n],
+ ancestor: space[2*n : 3*n],
+ }
+
+ // Step 1. Number vertices by depth-first preorder.
+ preorder := space[3*n : 4*n]
+ root := f.Blocks[0]
+ prenum := lt.dfs(root, 0, preorder)
+ recover := f.Recover
+ if recover != nil {
+ lt.dfs(recover, prenum, preorder)
+ }
+
+ buckets := space[4*n : 5*n]
+ copy(buckets, preorder)
+
+ // In reverse preorder...
+ for i := int32(n) - 1; i > 0; i-- {
+ w := preorder[i]
+
+ // Step 3. Implicitly define the immediate dominator of each node.
+ for v := buckets[i]; v != w; v = buckets[v.dom.pre] {
+ u := lt.eval(v)
+ if lt.sdom[u.Index].dom.pre < i {
+ v.dom.idom = u
+ } else {
+ v.dom.idom = w
+ }
+ }
+
+ // Step 2. Compute the semidominators of all nodes.
+ lt.sdom[w.Index] = lt.parent[w.Index]
+ for _, v := range w.Preds {
+ u := lt.eval(v)
+ if lt.sdom[u.Index].dom.pre < lt.sdom[w.Index].dom.pre {
+ lt.sdom[w.Index] = lt.sdom[u.Index]
+ }
+ }
+
+ lt.link(lt.parent[w.Index], w)
+
+ if lt.parent[w.Index] == lt.sdom[w.Index] {
+ w.dom.idom = lt.parent[w.Index]
+ } else {
+ buckets[i] = buckets[lt.sdom[w.Index].dom.pre]
+ buckets[lt.sdom[w.Index].dom.pre] = w
+ }
+ }
+
+ // The final 'Step 3' is now outside the loop.
+ for v := buckets[0]; v != root; v = buckets[v.dom.pre] {
+ v.dom.idom = root
+ }
+
+ // Step 4. Explicitly define the immediate dominator of each
+ // node, in preorder.
+ for _, w := range preorder[1:] {
+ if w == root || w == recover {
+ w.dom.idom = nil
+ } else {
+ if w.dom.idom != lt.sdom[w.Index] {
+ w.dom.idom = w.dom.idom.dom.idom
+ }
+ // Calculate Children relation as inverse of Idom.
+ w.dom.idom.dom.children = append(w.dom.idom.dom.children, w)
+ }
+ }
+
+ pre, post := numberDomTree(root, 0, 0)
+ if recover != nil {
+ numberDomTree(recover, pre, post)
+ }
+
+ // printDomTreeDot(os.Stderr, f) // debugging
+ // printDomTreeText(os.Stderr, root, 0) // debugging
+
+ if f.Prog.mode&SanityCheckFunctions != 0 {
+ sanityCheckDomTree(f)
+ }
+}
+
+// numberDomTree sets the pre- and post-order numbers of a depth-first
+// traversal of the dominator tree rooted at v. These are used to
+// answer dominance queries in constant time.
+//
+func numberDomTree(v *BasicBlock, pre, post int32) (int32, int32) {
+ v.dom.pre = pre
+ pre++
+ for _, child := range v.dom.children {
+ pre, post = numberDomTree(child, pre, post)
+ }
+ v.dom.post = post
+ post++
+ return pre, post
+}
+
+// Testing utilities ----------------------------------------
+
+// sanityCheckDomTree checks the correctness of the dominator tree
+// computed by the LT algorithm by comparing against the dominance
+// relation computed by a naive Kildall-style forward dataflow
+// analysis (Algorithm 10.16 from the "Dragon" book).
+//
+func sanityCheckDomTree(f *Function) {
+ n := len(f.Blocks)
+
+ // D[i] is the set of blocks that dominate f.Blocks[i],
+ // represented as a bit-set of block indices.
+ D := make([]big.Int, n)
+
+ one := big.NewInt(1)
+
+ // all is the set of all blocks; constant.
+ var all big.Int
+ all.Set(one).Lsh(&all, uint(n)).Sub(&all, one)
+
+ // Initialization.
+ for i, b := range f.Blocks {
+ if i == 0 || b == f.Recover {
+ // A root is dominated only by itself.
+ D[i].SetBit(&D[0], 0, 1)
+ } else {
+ // All other blocks are (initially) dominated
+ // by every block.
+ D[i].Set(&all)
+ }
+ }
+
+ // Iteration until fixed point.
+ for changed := true; changed; {
+ changed = false
+ for i, b := range f.Blocks {
+ if i == 0 || b == f.Recover {
+ continue
+ }
+ // Compute intersection across predecessors.
+ var x big.Int
+ x.Set(&all)
+ for _, pred := range b.Preds {
+ x.And(&x, &D[pred.Index])
+ }
+ x.SetBit(&x, i, 1) // a block always dominates itself.
+ if D[i].Cmp(&x) != 0 {
+ D[i].Set(&x)
+ changed = true
+ }
+ }
+ }
+
+ // Check the entire relation. O(n^2).
+ // The Recover block (if any) must be treated specially so we skip it.
+ ok := true
+ for i := 0; i < n; i++ {
+ for j := 0; j < n; j++ {
+ b, c := f.Blocks[i], f.Blocks[j]
+ if c == f.Recover {
+ continue
+ }
+ actual := b.Dominates(c)
+ expected := D[j].Bit(i) == 1
+ if actual != expected {
+ fmt.Fprintf(os.Stderr, "dominates(%s, %s)==%t, want %t\n", b, c, actual, expected)
+ ok = false
+ }
+ }
+ }
+
+ preorder := f.DomPreorder()
+ for _, b := range f.Blocks {
+ if got := preorder[b.dom.pre]; got != b {
+ fmt.Fprintf(os.Stderr, "preorder[%d]==%s, want %s\n", b.dom.pre, got, b)
+ ok = false
+ }
+ }
+
+ if !ok {
+ panic("sanityCheckDomTree failed for " + f.String())
+ }
+
+}
+
+// Printing functions ----------------------------------------
+
+// printDomTree prints the dominator tree as text, using indentation.
+func printDomTreeText(buf *bytes.Buffer, v *BasicBlock, indent int) {
+ fmt.Fprintf(buf, "%*s%s\n", 4*indent, "", v)
+ for _, child := range v.dom.children {
+ printDomTreeText(buf, child, indent+1)
+ }
+}
+
+// printDomTreeDot prints the dominator tree of f in AT&T GraphViz
+// (.dot) format.
+func printDomTreeDot(buf *bytes.Buffer, f *Function) {
+ fmt.Fprintln(buf, "//", f)
+ fmt.Fprintln(buf, "digraph domtree {")
+ for i, b := range f.Blocks {
+ v := b.dom
+ fmt.Fprintf(buf, "\tn%d [label=\"%s (%d, %d)\",shape=\"rectangle\"];\n", v.pre, b, v.pre, v.post)
+ // TODO(adonovan): improve appearance of edges
+ // belonging to both dominator tree and CFG.
+
+ // Dominator tree edge.
+ if i != 0 {
+ fmt.Fprintf(buf, "\tn%d -> n%d [style=\"solid\",weight=100];\n", v.idom.dom.pre, v.pre)
+ }
+ // CFG edges.
+ for _, pred := range b.Preds {
+ fmt.Fprintf(buf, "\tn%d -> n%d [style=\"dotted\",weight=0];\n", pred.dom.pre, v.pre)
+ }
+ }
+ fmt.Fprintln(buf, "}")
+}
diff --git a/go/ssa/emit.go b/go/ssa/emit.go
new file mode 100644
index 0000000..fa9646b
--- /dev/null
+++ b/go/ssa/emit.go
@@ -0,0 +1,469 @@
+// 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 ssa
+
+// Helpers for emitting SSA instructions.
+
+import (
+ "fmt"
+ "go/ast"
+ "go/token"
+
+ "golang.org/x/tools/go/types"
+)
+
+// emitNew emits to f a new (heap Alloc) instruction allocating an
+// object of type typ. pos is the optional source location.
+//
+func emitNew(f *Function, typ types.Type, pos token.Pos) *Alloc {
+ v := &Alloc{Heap: true}
+ v.setType(types.NewPointer(typ))
+ v.setPos(pos)
+ f.emit(v)
+ return v
+}
+
+// emitLoad emits to f an instruction to load the address addr into a
+// new temporary, and returns the value so defined.
+//
+func emitLoad(f *Function, addr Value) *UnOp {
+ v := &UnOp{Op: token.MUL, X: addr}
+ v.setType(deref(addr.Type()))
+ f.emit(v)
+ return v
+}
+
+// emitDebugRef emits to f a DebugRef pseudo-instruction associating
+// expression e with value v.
+//
+func emitDebugRef(f *Function, e ast.Expr, v Value, isAddr bool) {
+ if !f.debugInfo() {
+ return // debugging not enabled
+ }
+ if v == nil || e == nil {
+ panic("nil")
+ }
+ var obj types.Object
+ e = unparen(e)
+ if id, ok := e.(*ast.Ident); ok {
+ if isBlankIdent(id) {
+ return
+ }
+ obj = f.Pkg.objectOf(id)
+ switch obj.(type) {
+ case *types.Nil, *types.Const, *types.Builtin:
+ return
+ }
+ }
+ f.emit(&DebugRef{
+ X: v,
+ Expr: e,
+ IsAddr: isAddr,
+ object: obj,
+ })
+}
+
+// emitArith emits to f code to compute the binary operation op(x, y)
+// where op is an eager shift, logical or arithmetic operation.
+// (Use emitCompare() for comparisons and Builder.logicalBinop() for
+// non-eager operations.)
+//
+func emitArith(f *Function, op token.Token, x, y Value, t types.Type, pos token.Pos) Value {
+ switch op {
+ case token.SHL, token.SHR:
+ x = emitConv(f, x, t)
+ // y may be signed or an 'untyped' constant.
+ // TODO(adonovan): whence signed values?
+ if b, ok := y.Type().Underlying().(*types.Basic); ok && b.Info()&types.IsUnsigned == 0 {
+ y = emitConv(f, y, types.Typ[types.Uint64])
+ }
+
+ case token.ADD, token.SUB, token.MUL, token.QUO, token.REM, token.AND, token.OR, token.XOR, token.AND_NOT:
+ x = emitConv(f, x, t)
+ y = emitConv(f, y, t)
+
+ default:
+ panic("illegal op in emitArith: " + op.String())
+
+ }
+ v := &BinOp{
+ Op: op,
+ X: x,
+ Y: y,
+ }
+ v.setPos(pos)
+ v.setType(t)
+ return f.emit(v)
+}
+
+// emitCompare emits to f code compute the boolean result of
+// comparison comparison 'x op y'.
+//
+func emitCompare(f *Function, op token.Token, x, y Value, pos token.Pos) Value {
+ xt := x.Type().Underlying()
+ yt := y.Type().Underlying()
+
+ // Special case to optimise a tagless SwitchStmt so that
+ // these are equivalent
+ // switch { case e: ...}
+ // switch true { case e: ... }
+ // if e==true { ... }
+ // even in the case when e's type is an interface.
+ // TODO(adonovan): opt: generalise to x==true, false!=y, etc.
+ if x == vTrue && op == token.EQL {
+ if yt, ok := yt.(*types.Basic); ok && yt.Info()&types.IsBoolean != 0 {
+ return y
+ }
+ }
+
+ if types.Identical(xt, yt) {
+ // no conversion necessary
+ } else if _, ok := xt.(*types.Interface); ok {
+ y = emitConv(f, y, x.Type())
+ } else if _, ok := yt.(*types.Interface); ok {
+ x = emitConv(f, x, y.Type())
+ } else if _, ok := x.(*Const); ok {
+ x = emitConv(f, x, y.Type())
+ } else if _, ok := y.(*Const); ok {
+ y = emitConv(f, y, x.Type())
+ } else {
+ // other cases, e.g. channels. No-op.
+ }
+
+ v := &BinOp{
+ Op: op,
+ X: x,
+ Y: y,
+ }
+ v.setPos(pos)
+ v.setType(tBool)
+ return f.emit(v)
+}
+
+// isValuePreserving returns true if a conversion from ut_src to
+// ut_dst is value-preserving, i.e. just a change of type.
+// Precondition: neither argument is a named type.
+//
+func isValuePreserving(ut_src, ut_dst types.Type) bool {
+ // Identical underlying types?
+ if types.Identical(ut_dst, ut_src) {
+ return true
+ }
+
+ switch ut_dst.(type) {
+ case *types.Chan:
+ // Conversion between channel types?
+ _, ok := ut_src.(*types.Chan)
+ return ok
+
+ case *types.Pointer:
+ // Conversion between pointers with identical base types?
+ _, ok := ut_src.(*types.Pointer)
+ return ok
+ }
+ return false
+}
+
+// emitConv emits to f code to convert Value val to exactly type typ,
+// and returns the converted value. Implicit conversions are required
+// by language assignability rules in assignments, parameter passing,
+// etc. Conversions cannot fail dynamically.
+//
+func emitConv(f *Function, val Value, typ types.Type) Value {
+ t_src := val.Type()
+
+ // Identical types? Conversion is a no-op.
+ if types.Identical(t_src, typ) {
+ return val
+ }
+
+ ut_dst := typ.Underlying()
+ ut_src := t_src.Underlying()
+
+ // Just a change of type, but not value or representation?
+ if isValuePreserving(ut_src, ut_dst) {
+ c := &ChangeType{X: val}
+ c.setType(typ)
+ return f.emit(c)
+ }
+
+ // Conversion to, or construction of a value of, an interface type?
+ if _, ok := ut_dst.(*types.Interface); ok {
+ // Assignment from one interface type to another?
+ if _, ok := ut_src.(*types.Interface); ok {
+ c := &ChangeInterface{X: val}
+ c.setType(typ)
+ return f.emit(c)
+ }
+
+ // Untyped nil constant? Return interface-typed nil constant.
+ if ut_src == tUntypedNil {
+ return nilConst(typ)
+ }
+
+ // Convert (non-nil) "untyped" literals to their default type.
+ if t, ok := ut_src.(*types.Basic); ok && t.Info()&types.IsUntyped != 0 {
+ val = emitConv(f, val, DefaultType(ut_src))
+ }
+
+ f.Pkg.Prog.needMethodsOf(val.Type())
+ mi := &MakeInterface{X: val}
+ mi.setType(typ)
+ return f.emit(mi)
+ }
+
+ // Conversion of a compile-time constant value?
+ if c, ok := val.(*Const); ok {
+ if _, ok := ut_dst.(*types.Basic); ok || c.IsNil() {
+ // Conversion of a compile-time constant to
+ // another constant type results in a new
+ // constant of the destination type and
+ // (initially) the same abstract value.
+ // We don't truncate the value yet.
+ return NewConst(c.Value, typ)
+ }
+
+ // We're converting from constant to non-constant type,
+ // e.g. string -> []byte/[]rune.
+ }
+
+ // A representation-changing conversion?
+ // At least one of {ut_src,ut_dst} must be *Basic.
+ // (The other may be []byte or []rune.)
+ _, ok1 := ut_src.(*types.Basic)
+ _, ok2 := ut_dst.(*types.Basic)
+ if ok1 || ok2 {
+ c := &Convert{X: val}
+ c.setType(typ)
+ return f.emit(c)
+ }
+
+ panic(fmt.Sprintf("in %s: cannot convert %s (%s) to %s", f, val, val.Type(), typ))
+}
+
+// emitStore emits to f an instruction to store value val at location
+// addr, applying implicit conversions as required by assignability rules.
+//
+func emitStore(f *Function, addr, val Value, pos token.Pos) *Store {
+ s := &Store{
+ Addr: addr,
+ Val: emitConv(f, val, deref(addr.Type())),
+ pos: pos,
+ }
+ f.emit(s)
+ return s
+}
+
+// emitJump emits to f a jump to target, and updates the control-flow graph.
+// Postcondition: f.currentBlock is nil.
+//
+func emitJump(f *Function, target *BasicBlock) {
+ b := f.currentBlock
+ b.emit(new(Jump))
+ addEdge(b, target)
+ f.currentBlock = nil
+}
+
+// emitIf emits to f a conditional jump to tblock or fblock based on
+// cond, and updates the control-flow graph.
+// Postcondition: f.currentBlock is nil.
+//
+func emitIf(f *Function, cond Value, tblock, fblock *BasicBlock) {
+ b := f.currentBlock
+ b.emit(&If{Cond: cond})
+ addEdge(b, tblock)
+ addEdge(b, fblock)
+ f.currentBlock = nil
+}
+
+// emitExtract emits to f an instruction to extract the index'th
+// component of tuple. It returns the extracted value.
+//
+func emitExtract(f *Function, tuple Value, index int) Value {
+ e := &Extract{Tuple: tuple, Index: index}
+ e.setType(tuple.Type().(*types.Tuple).At(index).Type())
+ return f.emit(e)
+}
+
+// emitTypeAssert emits to f a type assertion value := x.(t) and
+// returns the value. x.Type() must be an interface.
+//
+func emitTypeAssert(f *Function, x Value, t types.Type, pos token.Pos) Value {
+ a := &TypeAssert{X: x, AssertedType: t}
+ a.setPos(pos)
+ a.setType(t)
+ return f.emit(a)
+}
+
+// emitTypeTest emits to f a type test value,ok := x.(t) and returns
+// a (value, ok) tuple. x.Type() must be an interface.
+//
+func emitTypeTest(f *Function, x Value, t types.Type, pos token.Pos) Value {
+ a := &TypeAssert{
+ X: x,
+ AssertedType: t,
+ CommaOk: true,
+ }
+ a.setPos(pos)
+ a.setType(types.NewTuple(
+ newVar("value", t),
+ varOk,
+ ))
+ return f.emit(a)
+}
+
+// emitTailCall emits to f a function call in tail position. The
+// caller is responsible for all fields of 'call' except its type.
+// Intended for wrapper methods.
+// Precondition: f does/will not use deferred procedure calls.
+// Postcondition: f.currentBlock is nil.
+//
+func emitTailCall(f *Function, call *Call) {
+ tresults := f.Signature.Results()
+ nr := tresults.Len()
+ if nr == 1 {
+ call.typ = tresults.At(0).Type()
+ } else {
+ call.typ = tresults
+ }
+ tuple := f.emit(call)
+ var ret Return
+ switch nr {
+ case 0:
+ // no-op
+ case 1:
+ ret.Results = []Value{tuple}
+ default:
+ for i := 0; i < nr; i++ {
+ v := emitExtract(f, tuple, i)
+ // TODO(adonovan): in principle, this is required:
+ // v = emitConv(f, o.Type, f.Signature.Results[i].Type)
+ // but in practice emitTailCall is only used when
+ // the types exactly match.
+ ret.Results = append(ret.Results, v)
+ }
+ }
+ f.emit(&ret)
+ f.currentBlock = nil
+}
+
+// emitImplicitSelections emits to f code to apply the sequence of
+// implicit field selections specified by indices to base value v, and
+// returns the selected value.
+//
+// If v is the address of a struct, the result will be the address of
+// a field; if it is the value of a struct, the result will be the
+// value of a field.
+//
+func emitImplicitSelections(f *Function, v Value, indices []int) Value {
+ for _, index := range indices {
+ fld := deref(v.Type()).Underlying().(*types.Struct).Field(index)
+
+ if isPointer(v.Type()) {
+ instr := &FieldAddr{
+ X: v,
+ Field: index,
+ }
+ instr.setType(types.NewPointer(fld.Type()))
+ v = f.emit(instr)
+ // Load the field's value iff indirectly embedded.
+ if isPointer(fld.Type()) {
+ v = emitLoad(f, v)
+ }
+ } else {
+ instr := &Field{
+ X: v,
+ Field: index,
+ }
+ instr.setType(fld.Type())
+ v = f.emit(instr)
+ }
+ }
+ return v
+}
+
+// emitFieldSelection emits to f code to select the index'th field of v.
+//
+// If wantAddr, the input must be a pointer-to-struct and the result
+// will be the field's address; otherwise the result will be the
+// field's value.
+// Ident id is used for position and debug info.
+//
+func emitFieldSelection(f *Function, v Value, index int, wantAddr bool, id *ast.Ident) Value {
+ fld := deref(v.Type()).Underlying().(*types.Struct).Field(index)
+ if isPointer(v.Type()) {
+ instr := &FieldAddr{
+ X: v,
+ Field: index,
+ }
+ instr.setPos(id.Pos())
+ instr.setType(types.NewPointer(fld.Type()))
+ v = f.emit(instr)
+ // Load the field's value iff we don't want its address.
+ if !wantAddr {
+ v = emitLoad(f, v)
+ }
+ } else {
+ instr := &Field{
+ X: v,
+ Field: index,
+ }
+ instr.setPos(id.Pos())
+ instr.setType(fld.Type())
+ v = f.emit(instr)
+ }
+ emitDebugRef(f, id, v, wantAddr)
+ return v
+}
+
+// zeroValue emits to f code to produce a zero value of type t,
+// and returns it.
+//
+func zeroValue(f *Function, t types.Type) Value {
+ switch t.Underlying().(type) {
+ case *types.Struct, *types.Array:
+ return emitLoad(f, f.addLocal(t, token.NoPos))
+ default:
+ return zeroConst(t)
+ }
+}
+
+// createRecoverBlock emits to f a block of code to return after a
+// recovered panic, and sets f.Recover to it.
+//
+// If f's result parameters are named, the code loads and returns
+// their current values, otherwise it returns the zero values of their
+// type.
+//
+// Idempotent.
+//
+func createRecoverBlock(f *Function) {
+ if f.Recover != nil {
+ return // already created
+ }
+ saved := f.currentBlock
+
+ f.Recover = f.newBasicBlock("recover")
+ f.currentBlock = f.Recover
+
+ var results []Value
+ if f.namedResults != nil {
+ // Reload NRPs to form value tuple.
+ for _, r := range f.namedResults {
+ results = append(results, emitLoad(f, r))
+ }
+ } else {
+ R := f.Signature.Results()
+ for i, n := 0, R.Len(); i < n; i++ {
+ T := R.At(i).Type()
+
+ // Return zero value of each result type.
+ results = append(results, zeroValue(f, T))
+ }
+ }
+ f.emit(&Return{Results: results})
+
+ f.currentBlock = saved
+}
diff --git a/go/ssa/example_test.go b/go/ssa/example_test.go
new file mode 100644
index 0000000..3e095b8
--- /dev/null
+++ b/go/ssa/example_test.go
@@ -0,0 +1,138 @@
+// 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 ssa_test
+
+import (
+ "fmt"
+ "os"
+
+ "go/ast"
+ "go/parser"
+ "go/token"
+
+ "golang.org/x/tools/go/loader"
+ "golang.org/x/tools/go/ssa"
+ "golang.org/x/tools/go/ssa/ssautil"
+ "golang.org/x/tools/go/types"
+)
+
+const hello = `
+package main
+
+import "fmt"
+
+const message = "Hello, World!"
+
+func main() {
+ fmt.Println(message)
+}
+`
+
+// This program demonstrates how to run the SSA builder on a single
+// package of one or more already-parsed files. Its dependencies are
+// loaded from compiler export data. This is what you'd typically use
+// for a compiler; it does not depend on golang.org/x/tools/go/loader.
+//
+// It shows the printed representation of packages, functions, and
+// instructions. Within the function listing, the name of each
+// BasicBlock such as ".0.entry" is printed left-aligned, followed by
+// the block's Instructions.
+//
+// For each instruction that defines an SSA virtual register
+// (i.e. implements Value), the type of that value is shown in the
+// right column.
+//
+// Build and run the ssadump.go program if you want a standalone tool
+// with similar functionality. It is located at
+// golang.org/x/tools/cmd/ssadump.
+//
+func ExampleBuildPackage() {
+ // Parse the source files.
+ fset := token.NewFileSet()
+ f, err := parser.ParseFile(fset, "hello.go", hello, parser.ParseComments)
+ if err != nil {
+ fmt.Print(err) // parse error
+ return
+ }
+ files := []*ast.File{f}
+
+ // Create the type-checker's package.
+ pkg := types.NewPackage("hello", "")
+
+ // Type-check the package, load dependencies.
+ // Create and build the SSA program.
+ hello, _, err := ssautil.BuildPackage(
+ new(types.Config), fset, pkg, files, ssa.SanityCheckFunctions)
+ if err != nil {
+ fmt.Print(err) // type error in some package
+ return
+ }
+
+ // Print out the package.
+ hello.WriteTo(os.Stdout)
+
+ // Print out the package-level functions.
+ hello.Func("init").WriteTo(os.Stdout)
+ hello.Func("main").WriteTo(os.Stdout)
+
+ // Output:
+ //
+ // package hello:
+ // func init func()
+ // var init$guard bool
+ // func main func()
+ // const message message = "Hello, World!":untyped string
+ //
+ // # Name: hello.init
+ // # Package: hello
+ // # Synthetic: package initializer
+ // func init():
+ // 0: entry P:0 S:2
+ // t0 = *init$guard bool
+ // if t0 goto 2 else 1
+ // 1: init.start P:1 S:1
+ // *init$guard = true:bool
+ // t1 = fmt.init() ()
+ // jump 2
+ // 2: init.done P:2 S:0
+ // return
+ //
+ // # Name: hello.main
+ // # Package: hello
+ // # Location: hello.go:8:6
+ // func main():
+ // 0: entry P:0 S:0
+ // t0 = new [1]interface{} (varargs) *[1]interface{}
+ // t1 = &t0[0:int] *interface{}
+ // t2 = make interface{} <- string ("Hello, World!":string) interface{}
+ // *t1 = t2
+ // t3 = slice t0[:] []interface{}
+ // t4 = fmt.Println(t3...) (n int, err error)
+ // return
+}
+
+// This program shows how to load a main package (cmd/nm) and all its
+// dependencies from source, using the loader, and then build SSA code
+// for the entire program. This is what you'd typically use for a
+// whole-program analysis.
+//
+func ExampleLoadProgram() {
+ // Load cmd/nm and its dependencies.
+ var conf loader.Config
+ conf.Import("cmd/nm")
+ lprog, err := conf.Load()
+ if err != nil {
+ fmt.Print(err) // type error in some package
+ return
+ }
+
+ // Create SSA-form program representation.
+ prog := ssautil.CreateProgram(lprog, ssa.SanityCheckFunctions)
+
+ // Build SSA code for the entire cmd/nm program.
+ prog.BuildAll()
+
+ // Output:
+}
diff --git a/go/ssa/func.go b/go/ssa/func.go
new file mode 100644
index 0000000..a9c0f75
--- /dev/null
+++ b/go/ssa/func.go
@@ -0,0 +1,690 @@
+// 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 ssa
+
+// This file implements the Function and BasicBlock types.
+
+import (
+ "bytes"
+ "fmt"
+ "go/ast"
+ "go/token"
+ "io"
+ "os"
+ "strings"
+
+ "golang.org/x/tools/go/types"
+)
+
+// addEdge adds a control-flow graph edge from from to to.
+func addEdge(from, to *BasicBlock) {
+ from.Succs = append(from.Succs, to)
+ to.Preds = append(to.Preds, from)
+}
+
+// Parent returns the function that contains block b.
+func (b *BasicBlock) Parent() *Function { return b.parent }
+
+// String returns a human-readable label of this block.
+// It is not guaranteed unique within the function.
+//
+func (b *BasicBlock) String() string {
+ return fmt.Sprintf("%d", b.Index)
+}
+
+// emit appends an instruction to the current basic block.
+// If the instruction defines a Value, it is returned.
+//
+func (b *BasicBlock) emit(i Instruction) Value {
+ i.setBlock(b)
+ b.Instrs = append(b.Instrs, i)
+ v, _ := i.(Value)
+ return v
+}
+
+// predIndex returns the i such that b.Preds[i] == c or panics if
+// there is none.
+func (b *BasicBlock) predIndex(c *BasicBlock) int {
+ for i, pred := range b.Preds {
+ if pred == c {
+ return i
+ }
+ }
+ panic(fmt.Sprintf("no edge %s -> %s", c, b))
+}
+
+// hasPhi returns true if b.Instrs contains φ-nodes.
+func (b *BasicBlock) hasPhi() bool {
+ _, ok := b.Instrs[0].(*Phi)
+ return ok
+}
+
+// phis returns the prefix of b.Instrs containing all the block's φ-nodes.
+func (b *BasicBlock) phis() []Instruction {
+ for i, instr := range b.Instrs {
+ if _, ok := instr.(*Phi); !ok {
+ return b.Instrs[:i]
+ }
+ }
+ return nil // unreachable in well-formed blocks
+}
+
+// replacePred replaces all occurrences of p in b's predecessor list with q.
+// Ordinarily there should be at most one.
+//
+func (b *BasicBlock) replacePred(p, q *BasicBlock) {
+ for i, pred := range b.Preds {
+ if pred == p {
+ b.Preds[i] = q
+ }
+ }
+}
+
+// replaceSucc replaces all occurrences of p in b's successor list with q.
+// Ordinarily there should be at most one.
+//
+func (b *BasicBlock) replaceSucc(p, q *BasicBlock) {
+ for i, succ := range b.Succs {
+ if succ == p {
+ b.Succs[i] = q
+ }
+ }
+}
+
+// removePred removes all occurrences of p in b's
+// predecessor list and φ-nodes.
+// Ordinarily there should be at most one.
+//
+func (b *BasicBlock) removePred(p *BasicBlock) {
+ phis := b.phis()
+
+ // We must preserve edge order for φ-nodes.
+ j := 0
+ for i, pred := range b.Preds {
+ if pred != p {
+ b.Preds[j] = b.Preds[i]
+ // Strike out φ-edge too.
+ for _, instr := range phis {
+ phi := instr.(*Phi)
+ phi.Edges[j] = phi.Edges[i]
+ }
+ j++
+ }
+ }
+ // Nil out b.Preds[j:] and φ-edges[j:] to aid GC.
+ for i := j; i < len(b.Preds); i++ {
+ b.Preds[i] = nil
+ for _, instr := range phis {
+ instr.(*Phi).Edges[i] = nil
+ }
+ }
+ b.Preds = b.Preds[:j]
+ for _, instr := range phis {
+ phi := instr.(*Phi)
+ phi.Edges = phi.Edges[:j]
+ }
+}
+
+// Destinations associated with unlabelled for/switch/select stmts.
+// We push/pop one of these as we enter/leave each construct and for
+// each BranchStmt we scan for the innermost target of the right type.
+//
+type targets struct {
+ tail *targets // rest of stack
+ _break *BasicBlock
+ _continue *BasicBlock
+ _fallthrough *BasicBlock
+}
+
+// Destinations associated with a labelled block.
+// We populate these as labels are encountered in forward gotos or
+// labelled statements.
+//
+type lblock struct {
+ _goto *BasicBlock
+ _break *BasicBlock
+ _continue *BasicBlock
+}
+
+// labelledBlock returns the branch target associated with the
+// specified label, creating it if needed.
+//
+func (f *Function) labelledBlock(label *ast.Ident) *lblock {
+ lb := f.lblocks[label.Obj]
+ if lb == nil {
+ lb = &lblock{_goto: f.newBasicBlock(label.Name)}
+ if f.lblocks == nil {
+ f.lblocks = make(map[*ast.Object]*lblock)
+ }
+ f.lblocks[label.Obj] = lb
+ }
+ return lb
+}
+
+// addParam adds a (non-escaping) parameter to f.Params of the
+// specified name, type and source position.
+//
+func (f *Function) addParam(name string, typ types.Type, pos token.Pos) *Parameter {
+ v := &Parameter{
+ name: name,
+ typ: typ,
+ pos: pos,
+ parent: f,
+ }
+ f.Params = append(f.Params, v)
+ return v
+}
+
+func (f *Function) addParamObj(obj types.Object) *Parameter {
+ name := obj.Name()
+ if name == "" {
+ name = fmt.Sprintf("arg%d", len(f.Params))
+ }
+ param := f.addParam(name, obj.Type(), obj.Pos())
+ param.object = obj
+ return param
+}
+
+// addSpilledParam declares a parameter that is pre-spilled to the
+// stack; the function body will load/store the spilled location.
+// Subsequent lifting will eliminate spills where possible.
+//
+func (f *Function) addSpilledParam(obj types.Object) {
+ param := f.addParamObj(obj)
+ spill := &Alloc{Comment: obj.Name()}
+ spill.setType(types.NewPointer(obj.Type()))
+ spill.setPos(obj.Pos())
+ f.objects[obj] = spill
+ f.Locals = append(f.Locals, spill)
+ f.emit(spill)
+ f.emit(&Store{Addr: spill, Val: param})
+}
+
+// startBody initializes the function prior to generating SSA code for its body.
+// Precondition: f.Type() already set.
+//
+func (f *Function) startBody() {
+ f.currentBlock = f.newBasicBlock("entry")
+ f.objects = make(map[types.Object]Value) // needed for some synthetics, e.g. init
+}
+
+// createSyntacticParams populates f.Params and generates code (spills
+// and named result locals) for all the parameters declared in the
+// syntax. In addition it populates the f.objects mapping.
+//
+// Preconditions:
+// f.startBody() was called.
+// Postcondition:
+// len(f.Params) == len(f.Signature.Params) + (f.Signature.Recv() ? 1 : 0)
+//
+func (f *Function) createSyntacticParams(recv *ast.FieldList, functype *ast.FuncType) {
+ // Receiver (at most one inner iteration).
+ if recv != nil {
+ for _, field := range recv.List {
+ for _, n := range field.Names {
+ f.addSpilledParam(f.Pkg.info.Defs[n])
+ }
+ // Anonymous receiver? No need to spill.
+ if field.Names == nil {
+ f.addParamObj(f.Signature.Recv())
+ }
+ }
+ }
+
+ // Parameters.
+ if functype.Params != nil {
+ n := len(f.Params) // 1 if has recv, 0 otherwise
+ for _, field := range functype.Params.List {
+ for _, n := range field.Names {
+ f.addSpilledParam(f.Pkg.info.Defs[n])
+ }
+ // Anonymous parameter? No need to spill.
+ if field.Names == nil {
+ f.addParamObj(f.Signature.Params().At(len(f.Params) - n))
+ }
+ }
+ }
+
+ // Named results.
+ if functype.Results != nil {
+ for _, field := range functype.Results.List {
+ // Implicit "var" decl of locals for named results.
+ for _, n := range field.Names {
+ f.namedResults = append(f.namedResults, f.addLocalForIdent(n))
+ }
+ }
+ }
+}
+
+// numberRegisters assigns numbers to all SSA registers
+// (value-defining Instructions) in f, to aid debugging.
+// (Non-Instruction Values are named at construction.)
+//
+func numberRegisters(f *Function) {
+ v := 0
+ for _, b := range f.Blocks {
+ for _, instr := range b.Instrs {
+ switch instr.(type) {
+ case Value:
+ instr.(interface {
+ setNum(int)
+ }).setNum(v)
+ v++
+ }
+ }
+ }
+}
+
+// buildReferrers populates the def/use information in all non-nil
+// Value.Referrers slice.
+// Precondition: all such slices are initially empty.
+func buildReferrers(f *Function) {
+ var rands []*Value
+ for _, b := range f.Blocks {
+ for _, instr := range b.Instrs {
+ rands = instr.Operands(rands[:0]) // recycle storage
+ for _, rand := range rands {
+ if r := *rand; r != nil {
+ if ref := r.Referrers(); ref != nil {
+ *ref = append(*ref, instr)
+ }
+ }
+ }
+ }
+ }
+}
+
+// finishBody() finalizes the function after SSA code generation of its body.
+func (f *Function) finishBody() {
+ f.objects = nil
+ f.currentBlock = nil
+ f.lblocks = nil
+
+ // Don't pin the AST in memory (except in debug mode).
+ if n := f.syntax; n != nil && !f.debugInfo() {
+ f.syntax = extentNode{n.Pos(), n.End()}
+ }
+
+ // Remove from f.Locals any Allocs that escape to the heap.
+ j := 0
+ for _, l := range f.Locals {
+ if !l.Heap {
+ f.Locals[j] = l
+ j++
+ }
+ }
+ // Nil out f.Locals[j:] to aid GC.
+ for i := j; i < len(f.Locals); i++ {
+ f.Locals[i] = nil
+ }
+ f.Locals = f.Locals[:j]
+
+ optimizeBlocks(f)
+
+ buildReferrers(f)
+
+ buildDomTree(f)
+
+ if f.Prog.mode&NaiveForm == 0 {
+ // For debugging pre-state of lifting pass:
+ // numberRegisters(f)
+ // f.WriteTo(os.Stderr)
+ lift(f)
+ }
+
+ f.namedResults = nil // (used by lifting)
+
+ numberRegisters(f)
+
+ if f.Prog.mode&PrintFunctions != 0 {
+ printMu.Lock()
+ f.WriteTo(os.Stdout)
+ printMu.Unlock()
+ }
+
+ if f.Prog.mode&SanityCheckFunctions != 0 {
+ mustSanityCheck(f, nil)
+ }
+}
+
+// removeNilBlocks eliminates nils from f.Blocks and updates each
+// BasicBlock.Index. Use this after any pass that may delete blocks.
+//
+func (f *Function) removeNilBlocks() {
+ j := 0
+ for _, b := range f.Blocks {
+ if b != nil {
+ b.Index = j
+ f.Blocks[j] = b
+ j++
+ }
+ }
+ // Nil out f.Blocks[j:] to aid GC.
+ for i := j; i < len(f.Blocks); i++ {
+ f.Blocks[i] = nil
+ }
+ f.Blocks = f.Blocks[:j]
+}
+
+// SetDebugMode sets the debug mode for package pkg. If true, all its
+// functions will include full debug info. This greatly increases the
+// size of the instruction stream, and causes Functions to depend upon
+// the ASTs, potentially keeping them live in memory for longer.
+//
+func (pkg *Package) SetDebugMode(debug bool) {
+ // TODO(adonovan): do we want ast.File granularity?
+ pkg.debug = debug
+}
+
+// debugInfo reports whether debug info is wanted for this function.
+func (f *Function) debugInfo() bool {
+ return f.Pkg != nil && f.Pkg.debug
+}
+
+// addNamedLocal creates a local variable, adds it to function f and
+// returns it. Its name and type are taken from obj. Subsequent
+// calls to f.lookup(obj) will return the same local.
+//
+func (f *Function) addNamedLocal(obj types.Object) *Alloc {
+ l := f.addLocal(obj.Type(), obj.Pos())
+ l.Comment = obj.Name()
+ f.objects[obj] = l
+ return l
+}
+
+func (f *Function) addLocalForIdent(id *ast.Ident) *Alloc {
+ return f.addNamedLocal(f.Pkg.info.Defs[id])
+}
+
+// addLocal creates an anonymous local variable of type typ, adds it
+// to function f and returns it. pos is the optional source location.
+//
+func (f *Function) addLocal(typ types.Type, pos token.Pos) *Alloc {
+ v := &Alloc{}
+ v.setType(types.NewPointer(typ))
+ v.setPos(pos)
+ f.Locals = append(f.Locals, v)
+ f.emit(v)
+ return v
+}
+
+// lookup returns the address of the named variable identified by obj
+// that is local to function f or one of its enclosing functions.
+// If escaping, the reference comes from a potentially escaping pointer
+// expression and the referent must be heap-allocated.
+//
+func (f *Function) lookup(obj types.Object, escaping bool) Value {
+ if v, ok := f.objects[obj]; ok {
+ if alloc, ok := v.(*Alloc); ok && escaping {
+ alloc.Heap = true
+ }
+ return v // function-local var (address)
+ }
+
+ // Definition must be in an enclosing function;
+ // plumb it through intervening closures.
+ if f.parent == nil {
+ panic("no ssa.Value for " + obj.String())
+ }
+ outer := f.parent.lookup(obj, true) // escaping
+ v := &FreeVar{
+ name: obj.Name(),
+ typ: outer.Type(),
+ pos: outer.Pos(),
+ outer: outer,
+ parent: f,
+ }
+ f.objects[obj] = v
+ f.FreeVars = append(f.FreeVars, v)
+ return v
+}
+
+// emit emits the specified instruction to function f.
+func (f *Function) emit(instr Instruction) Value {
+ return f.currentBlock.emit(instr)
+}
+
+// RelString returns the full name of this function, qualified by
+// package name, receiver type, etc.
+//
+// The specific formatting rules are not guaranteed and may change.
+//
+// Examples:
+// "math.IsNaN" // a package-level function
+// "(*bytes.Buffer).Bytes" // a declared method or a wrapper
+// "(*bytes.Buffer).Bytes$thunk" // thunk (func wrapping method; receiver is param 0)
+// "(*bytes.Buffer).Bytes$bound" // bound (func wrapping method; receiver supplied by closure)
+// "main.main$1" // an anonymous function in main
+// "main.init#1" // a declared init function
+// "main.init" // the synthesized package initializer
+//
+// When these functions are referred to from within the same package
+// (i.e. from == f.Pkg.Object), they are rendered without the package path.
+// For example: "IsNaN", "(*Buffer).Bytes", etc.
+//
+// All non-synthetic functions have distinct package-qualified names.
+// (But two methods may have the same name "(T).f" if one is a synthetic
+// wrapper promoting a non-exported method "f" from another package; in
+// that case, the strings are equal but the identifiers "f" are distinct.)
+//
+func (f *Function) RelString(from *types.Package) string {
+ // Anonymous?
+ if f.parent != nil {
+ // An anonymous function's Name() looks like "parentName$1",
+ // but its String() should include the type/package/etc.
+ parent := f.parent.RelString(from)
+ for i, anon := range f.parent.AnonFuncs {
+ if anon == f {
+ return fmt.Sprintf("%s$%d", parent, 1+i)
+ }
+ }
+
+ return f.name // should never happen
+ }
+
+ // Method (declared or wrapper)?
+ if recv := f.Signature.Recv(); recv != nil {
+ return f.relMethod(from, recv.Type())
+ }
+
+ // Thunk?
+ if f.method != nil {
+ return f.relMethod(from, f.method.Recv())
+ }
+
+ // Bound?
+ if len(f.FreeVars) == 1 && strings.HasSuffix(f.name, "$bound") {
+ return f.relMethod(from, f.FreeVars[0].Type())
+ }
+
+ // Package-level function?
+ // Prefix with package name for cross-package references only.
+ if p := f.pkgobj(); p != nil && p != from {
+ return fmt.Sprintf("%s.%s", p.Path(), f.name)
+ }
+
+ // Unknown.
+ return f.name
+}
+
+func (f *Function) relMethod(from *types.Package, recv types.Type) string {
+ return fmt.Sprintf("(%s).%s", relType(recv, from), f.name)
+}
+
+// writeSignature writes to buf the signature sig in declaration syntax.
+func writeSignature(buf *bytes.Buffer, from *types.Package, name string, sig *types.Signature, params []*Parameter) {
+ buf.WriteString("func ")
+ if recv := sig.Recv(); recv != nil {
+ buf.WriteString("(")
+ if n := params[0].Name(); n != "" {
+ buf.WriteString(n)
+ buf.WriteString(" ")
+ }
+ types.WriteType(buf, params[0].Type(), types.RelativeTo(from))
+ buf.WriteString(") ")
+ }
+ buf.WriteString(name)
+ types.WriteSignature(buf, sig, types.RelativeTo(from))
+}
+
+func (f *Function) pkgobj() *types.Package {
+ if f.Pkg != nil {
+ return f.Pkg.Object
+ }
+ return nil
+}
+
+var _ io.WriterTo = (*Function)(nil) // *Function implements io.Writer
+
+func (f *Function) WriteTo(w io.Writer) (int64, error) {
+ var buf bytes.Buffer
+ WriteFunction(&buf, f)
+ n, err := w.Write(buf.Bytes())
+ return int64(n), err
+}
+
+// WriteFunction writes to buf a human-readable "disassembly" of f.
+func WriteFunction(buf *bytes.Buffer, f *Function) {
+ fmt.Fprintf(buf, "# Name: %s\n", f.String())
+ if f.Pkg != nil {
+ fmt.Fprintf(buf, "# Package: %s\n", f.Pkg.Object.Path())
+ }
+ if syn := f.Synthetic; syn != "" {
+ fmt.Fprintln(buf, "# Synthetic:", syn)
+ }
+ if pos := f.Pos(); pos.IsValid() {
+ fmt.Fprintf(buf, "# Location: %s\n", f.Prog.Fset.Position(pos))
+ }
+
+ if f.parent != nil {
+ fmt.Fprintf(buf, "# Parent: %s\n", f.parent.Name())
+ }
+
+ if f.Recover != nil {
+ fmt.Fprintf(buf, "# Recover: %s\n", f.Recover)
+ }
+
+ from := f.pkgobj()
+
+ if f.FreeVars != nil {
+ buf.WriteString("# Free variables:\n")
+ for i, fv := range f.FreeVars {
+ fmt.Fprintf(buf, "# % 3d:\t%s %s\n", i, fv.Name(), relType(fv.Type(), from))
+ }
+ }
+
+ if len(f.Locals) > 0 {
+ buf.WriteString("# Locals:\n")
+ for i, l := range f.Locals {
+ fmt.Fprintf(buf, "# % 3d:\t%s %s\n", i, l.Name(), relType(deref(l.Type()), from))
+ }
+ }
+ writeSignature(buf, from, f.Name(), f.Signature, f.Params)
+ buf.WriteString(":\n")
+
+ if f.Blocks == nil {
+ buf.WriteString("\t(external)\n")
+ }
+
+ // NB. column calculations are confused by non-ASCII
+ // characters and assume 8-space tabs.
+ const punchcard = 80 // for old time's sake.
+ const tabwidth = 8
+ for _, b := range f.Blocks {
+ if b == nil {
+ // Corrupt CFG.
+ fmt.Fprintf(buf, ".nil:\n")
+ continue
+ }
+ n, _ := fmt.Fprintf(buf, "%d:", b.Index)
+ bmsg := fmt.Sprintf("%s P:%d S:%d", b.Comment, len(b.Preds), len(b.Succs))
+ fmt.Fprintf(buf, "%*s%s\n", punchcard-1-n-len(bmsg), "", bmsg)
+
+ if false { // CFG debugging
+ fmt.Fprintf(buf, "\t# CFG: %s --> %s --> %s\n", b.Preds, b, b.Succs)
+ }
+ for _, instr := range b.Instrs {
+ buf.WriteString("\t")
+ switch v := instr.(type) {
+ case Value:
+ l := punchcard - tabwidth
+ // Left-align the instruction.
+ if name := v.Name(); name != "" {
+ n, _ := fmt.Fprintf(buf, "%s = ", name)
+ l -= n
+ }
+ n, _ := buf.WriteString(instr.String())
+ l -= n
+ // Right-align the type if there's space.
+ if t := v.Type(); t != nil {
+ buf.WriteByte(' ')
+ ts := relType(t, from)
+ l -= len(ts) + len(" ") // (spaces before and after type)
+ if l > 0 {
+ fmt.Fprintf(buf, "%*s", l, "")
+ }
+ buf.WriteString(ts)
+ }
+ case nil:
+ // Be robust against bad transforms.
+ buf.WriteString("<deleted>")
+ default:
+ buf.WriteString(instr.String())
+ }
+ buf.WriteString("\n")
+ }
+ }
+ fmt.Fprintf(buf, "\n")
+}
+
+// newBasicBlock adds to f a new basic block and returns it. It does
+// not automatically become the current block for subsequent calls to emit.
+// comment is an optional string for more readable debugging output.
+//
+func (f *Function) newBasicBlock(comment string) *BasicBlock {
+ b := &BasicBlock{
+ Index: len(f.Blocks),
+ Comment: comment,
+ parent: f,
+ }
+ b.Succs = b.succs2[:0]
+ f.Blocks = append(f.Blocks, b)
+ return b
+}
+
+// NewFunction returns a new synthetic Function instance belonging to
+// prog, with its name and signature fields set as specified.
+//
+// The caller is responsible for initializing the remaining fields of
+// the function object, e.g. Pkg, Params, Blocks.
+//
+// It is practically impossible for clients to construct well-formed
+// SSA functions/packages/programs directly, so we assume this is the
+// job of the Builder alone. NewFunction exists to provide clients a
+// little flexibility. For example, analysis tools may wish to
+// construct fake Functions for the root of the callgraph, a fake
+// "reflect" package, etc.
+//
+// TODO(adonovan): think harder about the API here.
+//
+func (prog *Program) NewFunction(name string, sig *types.Signature, provenance string) *Function {
+ return &Function{Prog: prog, name: name, Signature: sig, Synthetic: provenance}
+}
+
+type extentNode [2]token.Pos
+
+func (n extentNode) Pos() token.Pos { return n[0] }
+func (n extentNode) End() token.Pos { return n[1] }
+
+// Syntax returns an ast.Node whose Pos/End methods provide the
+// lexical extent of the function if it was defined by Go source code
+// (f.Synthetic==""), or nil otherwise.
+//
+// If f was built with debug information (see Package.SetDebugRef),
+// the result is the *ast.FuncDecl or *ast.FuncLit that declared the
+// function. Otherwise, it is an opaque Node providing only position
+// information; this avoids pinning the AST in memory.
+//
+func (f *Function) Syntax() ast.Node { return f.syntax }
diff --git a/go/ssa/interp/external.go b/go/ssa/interp/external.go
new file mode 100644
index 0000000..eb0757f
--- /dev/null
+++ b/go/ssa/interp/external.go
@@ -0,0 +1,493 @@
+// 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 interp
+
+// Emulated functions that we cannot interpret because they are
+// external or because they use "unsafe" or "reflect" operations.
+
+import (
+ "math"
+ "os"
+ "runtime"
+ "syscall"
+ "time"
+ "unsafe"
+
+ "golang.org/x/tools/go/ssa"
+ "golang.org/x/tools/go/types"
+)
+
+type externalFn func(fr *frame, args []value) value
+
+// TODO(adonovan): fix: reflect.Value abstracts an lvalue or an
+// rvalue; Set() causes mutations that can be observed via aliases.
+// We have not captured that correctly here.
+
+// Key strings are from Function.String().
+var externals map[string]externalFn
+
+func init() {
+ // That little dot ۰ is an Arabic zero numeral (U+06F0), categories [Nd].
+ externals = map[string]externalFn{
+ "(*sync.Pool).Get": ext۰sync۰Pool۰Get,
+ "(*sync.Pool).Put": ext۰sync۰Pool۰Put,
+ "(reflect.Value).Bool": ext۰reflect۰Value۰Bool,
+ "(reflect.Value).CanAddr": ext۰reflect۰Value۰CanAddr,
+ "(reflect.Value).CanInterface": ext۰reflect۰Value۰CanInterface,
+ "(reflect.Value).Elem": ext۰reflect۰Value۰Elem,
+ "(reflect.Value).Field": ext۰reflect۰Value۰Field,
+ "(reflect.Value).Float": ext۰reflect۰Value۰Float,
+ "(reflect.Value).Index": ext۰reflect۰Value۰Index,
+ "(reflect.Value).Int": ext۰reflect۰Value۰Int,
+ "(reflect.Value).Interface": ext۰reflect۰Value۰Interface,
+ "(reflect.Value).IsNil": ext۰reflect۰Value۰IsNil,
+ "(reflect.Value).IsValid": ext۰reflect۰Value۰IsValid,
+ "(reflect.Value).Kind": ext۰reflect۰Value۰Kind,
+ "(reflect.Value).Len": ext۰reflect۰Value۰Len,
+ "(reflect.Value).MapIndex": ext۰reflect۰Value۰MapIndex,
+ "(reflect.Value).MapKeys": ext۰reflect۰Value۰MapKeys,
+ "(reflect.Value).NumField": ext۰reflect۰Value۰NumField,
+ "(reflect.Value).NumMethod": ext۰reflect۰Value۰NumMethod,
+ "(reflect.Value).Pointer": ext۰reflect۰Value۰Pointer,
+ "(reflect.Value).Set": ext۰reflect۰Value۰Set,
+ "(reflect.Value).String": ext۰reflect۰Value۰String,
+ "(reflect.Value).Type": ext۰reflect۰Value۰Type,
+ "(reflect.Value).Uint": ext۰reflect۰Value۰Uint,
+ "(reflect.error).Error": ext۰reflect۰error۰Error,
+ "(reflect.rtype).Bits": ext۰reflect۰rtype۰Bits,
+ "(reflect.rtype).Elem": ext۰reflect۰rtype۰Elem,
+ "(reflect.rtype).Field": ext۰reflect۰rtype۰Field,
+ "(reflect.rtype).In": ext۰reflect۰rtype۰In,
+ "(reflect.rtype).Kind": ext۰reflect۰rtype۰Kind,
+ "(reflect.rtype).NumField": ext۰reflect۰rtype۰NumField,
+ "(reflect.rtype).NumIn": ext۰reflect۰rtype۰NumIn,
+ "(reflect.rtype).NumMethod": ext۰reflect۰rtype۰NumMethod,
+ "(reflect.rtype).NumOut": ext۰reflect۰rtype۰NumOut,
+ "(reflect.rtype).Out": ext۰reflect۰rtype۰Out,
+ "(reflect.rtype).Size": ext۰reflect۰rtype۰Size,
+ "(reflect.rtype).String": ext۰reflect۰rtype۰String,
+ "bytes.Equal": ext۰bytes۰Equal,
+ "bytes.IndexByte": ext۰bytes۰IndexByte,
+ "hash/crc32.haveSSE42": ext۰crc32۰haveSSE42,
+ "math.Abs": ext۰math۰Abs,
+ "math.Exp": ext۰math۰Exp,
+ "math.Float32bits": ext۰math۰Float32bits,
+ "math.Float32frombits": ext۰math۰Float32frombits,
+ "math.Float64bits": ext۰math۰Float64bits,
+ "math.Float64frombits": ext۰math۰Float64frombits,
+ "math.Ldexp": ext۰math۰Ldexp,
+ "math.Log": ext۰math۰Log,
+ "math.Min": ext۰math۰Min,
+ "os.runtime_args": ext۰os۰runtime_args,
+ "os.runtime_beforeExit": ext۰os۰runtime_beforeExit,
+ "reflect.New": ext۰reflect۰New,
+ "reflect.SliceOf": ext۰reflect۰SliceOf,
+ "reflect.TypeOf": ext۰reflect۰TypeOf,
+ "reflect.ValueOf": ext۰reflect۰ValueOf,
+ "reflect.Zero": ext۰reflect۰Zero,
+ "reflect.init": ext۰reflect۰Init,
+ "reflect.valueInterface": ext۰reflect۰valueInterface,
+ "runtime.Breakpoint": ext۰runtime۰Breakpoint,
+ "runtime.Caller": ext۰runtime۰Caller,
+ "runtime.Callers": ext۰runtime۰Callers,
+ "runtime.FuncForPC": ext۰runtime۰FuncForPC,
+ "runtime.GC": ext۰runtime۰GC,
+ "runtime.GOMAXPROCS": ext۰runtime۰GOMAXPROCS,
+ "runtime.Goexit": ext۰runtime۰Goexit,
+ "runtime.Gosched": ext۰runtime۰Gosched,
+ "runtime.init": ext۰runtime۰init,
+ "runtime.NumCPU": ext۰runtime۰NumCPU,
+ "runtime.ReadMemStats": ext۰runtime۰ReadMemStats,
+ "runtime.SetFinalizer": ext۰runtime۰SetFinalizer,
+ "(*runtime.Func).Entry": ext۰runtime۰Func۰Entry,
+ "(*runtime.Func).FileLine": ext۰runtime۰Func۰FileLine,
+ "(*runtime.Func).Name": ext۰runtime۰Func۰Name,
+ "runtime.environ": ext۰runtime۰environ,
+ "runtime.getgoroot": ext۰runtime۰getgoroot,
+ "strings.IndexByte": ext۰strings۰IndexByte,
+ "sync.runtime_Semacquire": ext۰sync۰runtime_Semacquire,
+ "sync.runtime_Semrelease": ext۰sync۰runtime_Semrelease,
+ "sync.runtime_Syncsemcheck": ext۰sync۰runtime_Syncsemcheck,
+ "sync.runtime_registerPoolCleanup": ext۰sync۰runtime_registerPoolCleanup,
+ "sync/atomic.AddInt32": ext۰atomic۰AddInt32,
+ "sync/atomic.AddUint32": ext۰atomic۰AddUint32,
+ "sync/atomic.AddUint64": ext۰atomic۰AddUint64,
+ "sync/atomic.CompareAndSwapInt32": ext۰atomic۰CompareAndSwapInt32,
+ "sync/atomic.LoadInt32": ext۰atomic۰LoadInt32,
+ "sync/atomic.LoadUint32": ext۰atomic۰LoadUint32,
+ "sync/atomic.StoreInt32": ext۰atomic۰StoreInt32,
+ "sync/atomic.StoreUint32": ext۰atomic۰StoreUint32,
+ "syscall.Close": ext۰syscall۰Close,
+ "syscall.Exit": ext۰syscall۰Exit,
+ "syscall.Fstat": ext۰syscall۰Fstat,
+ "syscall.Getpid": ext۰syscall۰Getpid,
+ "syscall.Getwd": ext۰syscall۰Getwd,
+ "syscall.Kill": ext۰syscall۰Kill,
+ "syscall.Lstat": ext۰syscall۰Lstat,
+ "syscall.Open": ext۰syscall۰Open,
+ "syscall.ParseDirent": ext۰syscall۰ParseDirent,
+ "syscall.RawSyscall": ext۰syscall۰RawSyscall,
+ "syscall.Read": ext۰syscall۰Read,
+ "syscall.ReadDirent": ext۰syscall۰ReadDirent,
+ "syscall.Stat": ext۰syscall۰Stat,
+ "syscall.Write": ext۰syscall۰Write,
+ "syscall.runtime_envs": ext۰runtime۰environ,
+ "time.Sleep": ext۰time۰Sleep,
+ "time.now": ext۰time۰now,
+ }
+}
+
+// wrapError returns an interpreted 'error' interface value for err.
+func wrapError(err error) value {
+ if err == nil {
+ return iface{}
+ }
+ return iface{t: errorType, v: err.Error()}
+}
+
+func ext۰sync۰Pool۰Get(fr *frame, args []value) value {
+ Pool := fr.i.prog.ImportedPackage("sync").Type("Pool").Object()
+ _, newIndex, _ := types.LookupFieldOrMethod(Pool.Type(), false, Pool.Pkg(), "New")
+
+ if New := (*args[0].(*value)).(structure)[newIndex[0]]; New != nil {
+ return call(fr.i, fr, 0, New, nil)
+ }
+ return nil
+}
+
+func ext۰sync۰Pool۰Put(fr *frame, args []value) value {
+ return nil
+}
+
+func ext۰bytes۰Equal(fr *frame, args []value) value {
+ // func Equal(a, b []byte) bool
+ a := args[0].([]value)
+ b := args[1].([]value)
+ if len(a) != len(b) {
+ return false
+ }
+ for i := range a {
+ if a[i] != b[i] {
+ return false
+ }
+ }
+ return true
+}
+
+func ext۰bytes۰IndexByte(fr *frame, args []value) value {
+ // func IndexByte(s []byte, c byte) int
+ s := args[0].([]value)
+ c := args[1].(byte)
+ for i, b := range s {
+ if b.(byte) == c {
+ return i
+ }
+ }
+ return -1
+}
+
+func ext۰crc32۰haveSSE42(fr *frame, args []value) value {
+ return false
+}
+
+func ext۰math۰Float64frombits(fr *frame, args []value) value {
+ return math.Float64frombits(args[0].(uint64))
+}
+
+func ext۰math۰Float64bits(fr *frame, args []value) value {
+ return math.Float64bits(args[0].(float64))
+}
+
+func ext۰math۰Float32frombits(fr *frame, args []value) value {
+ return math.Float32frombits(args[0].(uint32))
+}
+
+func ext۰math۰Abs(fr *frame, args []value) value {
+ return math.Abs(args[0].(float64))
+}
+
+func ext۰math۰Exp(fr *frame, args []value) value {
+ return math.Exp(args[0].(float64))
+}
+
+func ext۰math۰Float32bits(fr *frame, args []value) value {
+ return math.Float32bits(args[0].(float32))
+}
+
+func ext۰math۰Min(fr *frame, args []value) value {
+ return math.Min(args[0].(float64), args[1].(float64))
+}
+
+func ext۰math۰Ldexp(fr *frame, args []value) value {
+ return math.Ldexp(args[0].(float64), args[1].(int))
+}
+
+func ext۰math۰Log(fr *frame, args []value) value {
+ return math.Log(args[0].(float64))
+}
+
+func ext۰os۰runtime_args(fr *frame, args []value) value {
+ return fr.i.osArgs
+}
+
+func ext۰os۰runtime_beforeExit(fr *frame, args []value) value {
+ return nil
+}
+
+func ext۰runtime۰Breakpoint(fr *frame, args []value) value {
+ runtime.Breakpoint()
+ return nil
+}
+
+func ext۰runtime۰Caller(fr *frame, args []value) value {
+ // func Caller(skip int) (pc uintptr, file string, line int, ok bool)
+ skip := 1 + args[0].(int)
+ for i := 0; i < skip; i++ {
+ if fr != nil {
+ fr = fr.caller
+ }
+ }
+ var pc uintptr
+ var file string
+ var line int
+ var ok bool
+ if fr != nil {
+ fn := fr.fn
+ // TODO(adonovan): use pc/posn of current instruction, not start of fn.
+ pc = uintptr(unsafe.Pointer(fn))
+ posn := fn.Prog.Fset.Position(fn.Pos())
+ file = posn.Filename
+ line = posn.Line
+ ok = true
+ }
+ return tuple{pc, file, line, ok}
+}
+
+func ext۰runtime۰Callers(fr *frame, args []value) value {
+ // Callers(skip int, pc []uintptr) int
+ skip := args[0].(int)
+ pc := args[1].([]value)
+ for i := 0; i < skip; i++ {
+ if fr != nil {
+ fr = fr.caller
+ }
+ }
+ i := 0
+ for fr != nil {
+ pc[i] = uintptr(unsafe.Pointer(fr.fn))
+ i++
+ fr = fr.caller
+ }
+ return i
+}
+
+func ext۰runtime۰FuncForPC(fr *frame, args []value) value {
+ // FuncForPC(pc uintptr) *Func
+ pc := args[0].(uintptr)
+ var fn *ssa.Function
+ if pc != 0 {
+ fn = (*ssa.Function)(unsafe.Pointer(pc)) // indeed unsafe!
+ }
+ var Func value
+ Func = structure{fn} // a runtime.Func
+ return &Func
+}
+
+func ext۰runtime۰environ(fr *frame, args []value) value {
+ // This function also implements syscall.runtime_envs.
+ return environ
+}
+
+func ext۰runtime۰getgoroot(fr *frame, args []value) value {
+ return os.Getenv("GOROOT")
+}
+
+func ext۰strings۰IndexByte(fr *frame, args []value) value {
+ // func IndexByte(s string, c byte) int
+ s := args[0].(string)
+ c := args[1].(byte)
+ for i := 0; i < len(s); i++ {
+ if s[i] == c {
+ return i
+ }
+ }
+ return -1
+}
+
+func ext۰sync۰runtime_Syncsemcheck(fr *frame, args []value) value {
+ // TODO(adonovan): fix: implement.
+ return nil
+}
+
+func ext۰sync۰runtime_registerPoolCleanup(fr *frame, args []value) value {
+ return nil
+}
+
+func ext۰sync۰runtime_Semacquire(fr *frame, args []value) value {
+ // TODO(adonovan): fix: implement.
+ return nil
+}
+
+func ext۰sync۰runtime_Semrelease(fr *frame, args []value) value {
+ // TODO(adonovan): fix: implement.
+ return nil
+}
+
+func ext۰runtime۰GOMAXPROCS(fr *frame, args []value) value {
+ // Ignore args[0]; don't let the interpreted program
+ // set the interpreter's GOMAXPROCS!
+ return runtime.GOMAXPROCS(0)
+}
+
+func ext۰runtime۰Goexit(fr *frame, args []value) value {
+ // TODO(adonovan): don't kill the interpreter's main goroutine.
+ runtime.Goexit()
+ return nil
+}
+
+func ext۰runtime۰GC(fr *frame, args []value) value {
+ runtime.GC()
+ return nil
+}
+
+func ext۰runtime۰Gosched(fr *frame, args []value) value {
+ runtime.Gosched()
+ return nil
+}
+
+func ext۰runtime۰init(fr *frame, args []value) value {
+ return nil
+}
+
+func ext۰runtime۰NumCPU(fr *frame, args []value) value {
+ return runtime.NumCPU()
+}
+
+func ext۰runtime۰ReadMemStats(fr *frame, args []value) value {
+ // TODO(adonovan): populate args[0].(Struct)
+ return nil
+}
+
+func ext۰atomic۰LoadUint32(fr *frame, args []value) value {
+ // TODO(adonovan): fix: not atomic!
+ return (*args[0].(*value)).(uint32)
+}
+
+func ext۰atomic۰StoreUint32(fr *frame, args []value) value {
+ // TODO(adonovan): fix: not atomic!
+ *args[0].(*value) = args[1].(uint32)
+ return nil
+}
+
+func ext۰atomic۰LoadInt32(fr *frame, args []value) value {
+ // TODO(adonovan): fix: not atomic!
+ return (*args[0].(*value)).(int32)
+}
+
+func ext۰atomic۰StoreInt32(fr *frame, args []value) value {
+ // TODO(adonovan): fix: not atomic!
+ *args[0].(*value) = args[1].(int32)
+ return nil
+}
+
+func ext۰atomic۰CompareAndSwapInt32(fr *frame, args []value) value {
+ // TODO(adonovan): fix: not atomic!
+ p := args[0].(*value)
+ if (*p).(int32) == args[1].(int32) {
+ *p = args[2].(int32)
+ return true
+ }
+ return false
+}
+
+func ext۰atomic۰AddInt32(fr *frame, args []value) value {
+ // TODO(adonovan): fix: not atomic!
+ p := args[0].(*value)
+ newv := (*p).(int32) + args[1].(int32)
+ *p = newv
+ return newv
+}
+
+func ext۰atomic۰AddUint32(fr *frame, args []value) value {
+ // TODO(adonovan): fix: not atomic!
+ p := args[0].(*value)
+ newv := (*p).(uint32) + args[1].(uint32)
+ *p = newv
+ return newv
+}
+
+func ext۰atomic۰AddUint64(fr *frame, args []value) value {
+ // TODO(adonovan): fix: not atomic!
+ p := args[0].(*value)
+ newv := (*p).(uint64) + args[1].(uint64)
+ *p = newv
+ return newv
+}
+
+func ext۰runtime۰SetFinalizer(fr *frame, args []value) value {
+ return nil // ignore
+}
+
+// Pretend: type runtime.Func struct { entry *ssa.Function }
+
+func ext۰runtime۰Func۰FileLine(fr *frame, args []value) value {
+ // func (*runtime.Func) FileLine(uintptr) (string, int)
+ f, _ := (*args[0].(*value)).(structure)[0].(*ssa.Function)
+ pc := args[1].(uintptr)
+ _ = pc
+ if f != nil {
+ // TODO(adonovan): use position of current instruction, not fn.
+ posn := f.Prog.Fset.Position(f.Pos())
+ return tuple{posn.Filename, posn.Line}
+ }
+ return tuple{"", 0}
+}
+
+func ext۰runtime۰Func۰Name(fr *frame, args []value) value {
+ // func (*runtime.Func) Name() string
+ f, _ := (*args[0].(*value)).(structure)[0].(*ssa.Function)
+ if f != nil {
+ return f.String()
+ }
+ return ""
+}
+
+func ext۰runtime۰Func۰Entry(fr *frame, args []value) value {
+ // func (*runtime.Func) Entry() uintptr
+ f, _ := (*args[0].(*value)).(structure)[0].(*ssa.Function)
+ return uintptr(unsafe.Pointer(f))
+}
+
+func ext۰time۰now(fr *frame, args []value) value {
+ nano := time.Now().UnixNano()
+ return tuple{int64(nano / 1e9), int32(nano % 1e9)}
+}
+
+func ext۰time۰Sleep(fr *frame, args []value) value {
+ time.Sleep(time.Duration(args[0].(int64)))
+ return nil
+}
+
+func ext۰syscall۰Exit(fr *frame, args []value) value {
+ panic(exitPanic(args[0].(int)))
+}
+
+func ext۰syscall۰Getwd(fr *frame, args []value) value {
+ s, err := syscall.Getwd()
+ return tuple{s, wrapError(err)}
+}
+
+func ext۰syscall۰Getpid(fr *frame, args []value) value {
+ return syscall.Getpid()
+}
+
+func valueToBytes(v value) []byte {
+ in := v.([]value)
+ b := make([]byte, len(in))
+ for i := range in {
+ b[i] = in[i].(byte)
+ }
+ return b
+}
diff --git a/go/ssa/interp/external_darwin.go b/go/ssa/interp/external_darwin.go
new file mode 100644
index 0000000..4974ad6
--- /dev/null
+++ b/go/ssa/interp/external_darwin.go
@@ -0,0 +1,18 @@
+// 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.
+
+// +build darwin
+
+package interp
+
+import "syscall"
+
+func init() {
+ externals["syscall.Sysctl"] = ext۰syscall۰Sysctl
+}
+
+func ext۰syscall۰Sysctl(fr *frame, args []value) value {
+ r, err := syscall.Sysctl(args[0].(string))
+ return tuple{r, wrapError(err)}
+}
diff --git a/go/ssa/interp/external_freebsd.go b/go/ssa/interp/external_freebsd.go
new file mode 100644
index 0000000..5203303
--- /dev/null
+++ b/go/ssa/interp/external_freebsd.go
@@ -0,0 +1,24 @@
+// 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.
+
+// +build freebsd
+
+package interp
+
+import "syscall"
+
+func init() {
+ externals["syscall.Sysctl"] = ext۰syscall۰Sysctl
+ externals["syscall.SysctlUint32"] = ext۰syscall۰SysctlUint32
+}
+
+func ext۰syscall۰Sysctl(fr *frame, args []value) value {
+ r, err := syscall.Sysctl(args[0].(string))
+ return tuple{r, wrapError(err)}
+}
+
+func ext۰syscall۰SysctlUint32(fr *frame, args []value) value {
+ r, err := syscall.SysctlUint32(args[0].(string))
+ return tuple{r, wrapError(err)}
+}
diff --git a/go/ssa/interp/external_plan9.go b/go/ssa/interp/external_plan9.go
new file mode 100644
index 0000000..05d02d5
--- /dev/null
+++ b/go/ssa/interp/external_plan9.go
@@ -0,0 +1,47 @@
+// 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 interp
+
+import "syscall"
+
+func ext۰syscall۰Close(fr *frame, args []value) value {
+ panic("syscall.Close not yet implemented")
+}
+func ext۰syscall۰Fstat(fr *frame, args []value) value {
+ panic("syscall.Fstat not yet implemented")
+}
+func ext۰syscall۰Kill(fr *frame, args []value) value {
+ panic("syscall.Kill not yet implemented")
+}
+func ext۰syscall۰Lstat(fr *frame, args []value) value {
+ panic("syscall.Lstat not yet implemented")
+}
+func ext۰syscall۰Open(fr *frame, args []value) value {
+ panic("syscall.Open not yet implemented")
+}
+func ext۰syscall۰ParseDirent(fr *frame, args []value) value {
+ panic("syscall.ParseDirent not yet implemented")
+}
+func ext۰syscall۰Read(fr *frame, args []value) value {
+ panic("syscall.Read not yet implemented")
+}
+func ext۰syscall۰ReadDirent(fr *frame, args []value) value {
+ panic("syscall.ReadDirent not yet implemented")
+}
+func ext۰syscall۰Stat(fr *frame, args []value) value {
+ panic("syscall.Stat not yet implemented")
+}
+func ext۰syscall۰Write(fr *frame, args []value) value {
+ // func Write(fd int, p []byte) (n int, err error)
+ n, err := write(args[0].(int), valueToBytes(args[1]))
+ return tuple{n, wrapError(err)}
+}
+func ext۰syscall۰RawSyscall(fr *frame, args []value) value {
+ return tuple{^uintptr(0), uintptr(0), uintptr(0)}
+}
+
+func syswrite(fd int, b []byte) (int, error) {
+ return syscall.Write(fd, b)
+}
diff --git a/go/ssa/interp/external_unix.go b/go/ssa/interp/external_unix.go
new file mode 100644
index 0000000..c482eab
--- /dev/null
+++ b/go/ssa/interp/external_unix.go
@@ -0,0 +1,132 @@
+// 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 !windows,!plan9
+
+package interp
+
+import "syscall"
+
+func fillStat(st *syscall.Stat_t, stat structure) {
+ stat[0] = st.Dev
+ stat[1] = st.Ino
+ stat[2] = st.Nlink
+ stat[3] = st.Mode
+ stat[4] = st.Uid
+ stat[5] = st.Gid
+
+ stat[7] = st.Rdev
+ stat[8] = st.Size
+ stat[9] = st.Blksize
+ stat[10] = st.Blocks
+ // TODO(adonovan): fix: copy Timespecs.
+ // stat[11] = st.Atim
+ // stat[12] = st.Mtim
+ // stat[13] = st.Ctim
+}
+
+func ext۰syscall۰Close(fr *frame, args []value) value {
+ // func Close(fd int) (err error)
+ return wrapError(syscall.Close(args[0].(int)))
+}
+
+func ext۰syscall۰Fstat(fr *frame, args []value) value {
+ // func Fstat(fd int, stat *Stat_t) (err error)
+ fd := args[0].(int)
+ stat := (*args[1].(*value)).(structure)
+
+ var st syscall.Stat_t
+ err := syscall.Fstat(fd, &st)
+ fillStat(&st, stat)
+ return wrapError(err)
+}
+
+func ext۰syscall۰ReadDirent(fr *frame, args []value) value {
+ // func ReadDirent(fd int, buf []byte) (n int, err error)
+ fd := args[0].(int)
+ p := args[1].([]value)
+ b := make([]byte, len(p))
+ n, err := syscall.ReadDirent(fd, b)
+ for i := 0; i < n; i++ {
+ p[i] = b[i]
+ }
+ return tuple{n, wrapError(err)}
+}
+
+func ext۰syscall۰Kill(fr *frame, args []value) value {
+ // func Kill(pid int, sig Signal) (err error)
+ return wrapError(syscall.Kill(args[0].(int), syscall.Signal(args[1].(int))))
+}
+
+func ext۰syscall۰Lstat(fr *frame, args []value) value {
+ // func Lstat(name string, stat *Stat_t) (err error)
+ name := args[0].(string)
+ stat := (*args[1].(*value)).(structure)
+
+ var st syscall.Stat_t
+ err := syscall.Lstat(name, &st)
+ fillStat(&st, stat)
+ return wrapError(err)
+}
+
+func ext۰syscall۰Open(fr *frame, args []value) value {
+ // func Open(path string, mode int, perm uint32) (fd int, err error) {
+ path := args[0].(string)
+ mode := args[1].(int)
+ perm := args[2].(uint32)
+ fd, err := syscall.Open(path, mode, perm)
+ return tuple{fd, wrapError(err)}
+}
+
+func ext۰syscall۰ParseDirent(fr *frame, args []value) value {
+ // func ParseDirent(buf []byte, max int, names []string) (consumed int, count int, newnames []string)
+ max := args[1].(int)
+ var names []string
+ for _, iname := range args[2].([]value) {
+ names = append(names, iname.(string))
+ }
+ consumed, count, newnames := syscall.ParseDirent(valueToBytes(args[0]), max, names)
+ var inewnames []value
+ for _, newname := range newnames {
+ inewnames = append(inewnames, newname)
+ }
+ return tuple{consumed, count, inewnames}
+}
+
+func ext۰syscall۰Read(fr *frame, args []value) value {
+ // func Read(fd int, p []byte) (n int, err error)
+ fd := args[0].(int)
+ p := args[1].([]value)
+ b := make([]byte, len(p))
+ n, err := syscall.Read(fd, b)
+ for i := 0; i < n; i++ {
+ p[i] = b[i]
+ }
+ return tuple{n, wrapError(err)}
+}
+
+func ext۰syscall۰Stat(fr *frame, args []value) value {
+ // func Stat(name string, stat *Stat_t) (err error)
+ name := args[0].(string)
+ stat := (*args[1].(*value)).(structure)
+
+ var st syscall.Stat_t
+ err := syscall.Stat(name, &st)
+ fillStat(&st, stat)
+ return wrapError(err)
+}
+
+func ext۰syscall۰Write(fr *frame, args []value) value {
+ // func Write(fd int, p []byte) (n int, err error)
+ n, err := write(args[0].(int), valueToBytes(args[1]))
+ return tuple{n, wrapError(err)}
+}
+
+func ext۰syscall۰RawSyscall(fr *frame, args []value) value {
+ return tuple{uintptr(0), uintptr(0), uintptr(syscall.ENOSYS)}
+}
+
+func syswrite(fd int, b []byte) (int, error) {
+ return syscall.Write(fd, b)
+}
diff --git a/go/ssa/interp/external_windows.go b/go/ssa/interp/external_windows.go
new file mode 100644
index 0000000..ef28a37
--- /dev/null
+++ b/go/ssa/interp/external_windows.go
@@ -0,0 +1,44 @@
+// 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 interp
+
+import "syscall"
+
+func ext۰syscall۰Close(fr *frame, args []value) value {
+ panic("syscall.Close not yet implemented")
+}
+func ext۰syscall۰Fstat(fr *frame, args []value) value {
+ panic("syscall.Fstat not yet implemented")
+}
+func ext۰syscall۰Kill(fr *frame, args []value) value {
+ panic("syscall.Kill not yet implemented")
+}
+func ext۰syscall۰Lstat(fr *frame, args []value) value {
+ panic("syscall.Lstat not yet implemented")
+}
+func ext۰syscall۰Open(fr *frame, args []value) value {
+ panic("syscall.Open not yet implemented")
+}
+func ext۰syscall۰ParseDirent(fr *frame, args []value) value {
+ panic("syscall.ParseDirent not yet implemented")
+}
+func ext۰syscall۰Read(fr *frame, args []value) value {
+ panic("syscall.Read not yet implemented")
+}
+func ext۰syscall۰ReadDirent(fr *frame, args []value) value {
+ panic("syscall.ReadDirent not yet implemented")
+}
+func ext۰syscall۰Stat(fr *frame, args []value) value {
+ panic("syscall.Stat not yet implemented")
+}
+func ext۰syscall۰Write(fr *frame, args []value) value {
+ panic("syscall.Write not yet implemented")
+}
+func ext۰syscall۰RawSyscall(fr *frame, args []value) value {
+ return tuple{uintptr(0), uintptr(0), uintptr(syscall.ENOSYS)}
+}
+func syswrite(fd int, b []byte) (int, error) {
+ panic("syswrite not yet implemented")
+}
diff --git a/go/ssa/interp/interp.go b/go/ssa/interp/interp.go
new file mode 100644
index 0000000..afe4939
--- /dev/null
+++ b/go/ssa/interp/interp.go
@@ -0,0 +1,750 @@
+// 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 ssa/interp defines an interpreter for the SSA
+// representation of Go programs.
+//
+// This interpreter is provided as an adjunct for testing the SSA
+// construction algorithm. Its purpose is to provide a minimal
+// metacircular implementation of the dynamic semantics of each SSA
+// instruction. It is not, and will never be, a production-quality Go
+// interpreter.
+//
+// The following is a partial list of Go features that are currently
+// unsupported or incomplete in the interpreter.
+//
+// * Unsafe operations, including all uses of unsafe.Pointer, are
+// impossible to support given the "boxed" value representation we
+// have chosen.
+//
+// * The reflect package is only partially implemented.
+//
+// * "sync/atomic" operations are not currently atomic due to the
+// "boxed" value representation: it is not possible to read, modify
+// and write an interface value atomically. As a consequence, Mutexes
+// are currently broken. TODO(adonovan): provide a metacircular
+// implementation of Mutex avoiding the broken atomic primitives.
+//
+// * recover is only partially implemented. Also, the interpreter
+// makes no attempt to distinguish target panics from interpreter
+// crashes.
+//
+// * map iteration is asymptotically inefficient.
+//
+// * the sizes of the int, uint and uintptr types in the target
+// program are assumed to be the same as those of the interpreter
+// itself.
+//
+// * all values occupy space, even those of types defined by the spec
+// to have zero size, e.g. struct{}. This can cause asymptotic
+// performance degradation.
+//
+// * os.Exit is implemented using panic, causing deferred functions to
+// run.
+package interp // import "golang.org/x/tools/go/ssa/interp"
+
+import (
+ "fmt"
+ "go/token"
+ "os"
+ "reflect"
+ "runtime"
+
+ "golang.org/x/tools/go/ssa"
+ "golang.org/x/tools/go/types"
+)
+
+type continuation int
+
+const (
+ kNext continuation = iota
+ kReturn
+ kJump
+)
+
+// Mode is a bitmask of options affecting the interpreter.
+type Mode uint
+
+const (
+ DisableRecover Mode = 1 << iota // Disable recover() in target programs; show interpreter crash instead.
+ EnableTracing // Print a trace of all instructions as they are interpreted.
+)
+
+type methodSet map[string]*ssa.Function
+
+// State shared between all interpreted goroutines.
+type interpreter struct {
+ osArgs []value // the value of os.Args
+ prog *ssa.Program // the SSA program
+ globals map[ssa.Value]*value // addresses of global variables (immutable)
+ mode Mode // interpreter options
+ reflectPackage *ssa.Package // the fake reflect package
+ errorMethods methodSet // the method set of reflect.error, which implements the error interface.
+ rtypeMethods methodSet // the method set of rtype, which implements the reflect.Type interface.
+ runtimeErrorString types.Type // the runtime.errorString type
+ sizes types.Sizes // the effective type-sizing function
+}
+
+type deferred struct {
+ fn value
+ args []value
+ instr *ssa.Defer
+ tail *deferred
+}
+
+type frame struct {
+ i *interpreter
+ caller *frame
+ fn *ssa.Function
+ block, prevBlock *ssa.BasicBlock
+ env map[ssa.Value]value // dynamic values of SSA variables
+ locals []value
+ defers *deferred
+ result value
+ panicking bool
+ panic interface{}
+}
+
+func (fr *frame) get(key ssa.Value) value {
+ switch key := key.(type) {
+ case nil:
+ // Hack; simplifies handling of optional attributes
+ // such as ssa.Slice.{Low,High}.
+ return nil
+ case *ssa.Function, *ssa.Builtin:
+ return key
+ case *ssa.Const:
+ return constValue(key)
+ case *ssa.Global:
+ if r, ok := fr.i.globals[key]; ok {
+ return r
+ }
+ }
+ if r, ok := fr.env[key]; ok {
+ return r
+ }
+ panic(fmt.Sprintf("get: no value for %T: %v", key, key.Name()))
+}
+
+// runDefer runs a deferred call d.
+// It always returns normally, but may set or clear fr.panic.
+//
+func (fr *frame) runDefer(d *deferred) {
+ if fr.i.mode&EnableTracing != 0 {
+ fmt.Fprintf(os.Stderr, "%s: invoking deferred function call\n",
+ fr.i.prog.Fset.Position(d.instr.Pos()))
+ }
+ var ok bool
+ defer func() {
+ if !ok {
+ // Deferred call created a new state of panic.
+ fr.panicking = true
+ fr.panic = recover()
+ }
+ }()
+ call(fr.i, fr, d.instr.Pos(), d.fn, d.args)
+ ok = true
+}
+
+// runDefers executes fr's deferred function calls in LIFO order.
+//
+// On entry, fr.panicking indicates a state of panic; if
+// true, fr.panic contains the panic value.
+//
+// On completion, if a deferred call started a panic, or if no
+// deferred call recovered from a previous state of panic, then
+// runDefers itself panics after the last deferred call has run.
+//
+// If there was no initial state of panic, or it was recovered from,
+// runDefers returns normally.
+//
+func (fr *frame) runDefers() {
+ for d := fr.defers; d != nil; d = d.tail {
+ fr.runDefer(d)
+ }
+ fr.defers = nil
+ if fr.panicking {
+ panic(fr.panic) // new panic, or still panicking
+ }
+}
+
+// lookupMethod returns the method set for type typ, which may be one
+// of the interpreter's fake types.
+func lookupMethod(i *interpreter, typ types.Type, meth *types.Func) *ssa.Function {
+ switch typ {
+ case rtypeType:
+ return i.rtypeMethods[meth.Id()]
+ case errorType:
+ return i.errorMethods[meth.Id()]
+ }
+ return i.prog.LookupMethod(typ, meth.Pkg(), meth.Name())
+}
+
+// visitInstr interprets a single ssa.Instruction within the activation
+// record frame. It returns a continuation value indicating where to
+// read the next instruction from.
+func visitInstr(fr *frame, instr ssa.Instruction) continuation {
+ switch instr := instr.(type) {
+ case *ssa.DebugRef:
+ // no-op
+
+ case *ssa.UnOp:
+ fr.env[instr] = unop(instr, fr.get(instr.X))
+
+ case *ssa.BinOp:
+ fr.env[instr] = binop(instr.Op, instr.X.Type(), fr.get(instr.X), fr.get(instr.Y))
+
+ case *ssa.Call:
+ fn, args := prepareCall(fr, &instr.Call)
+ fr.env[instr] = call(fr.i, fr, instr.Pos(), fn, args)
+
+ case *ssa.ChangeInterface:
+ fr.env[instr] = fr.get(instr.X)
+
+ case *ssa.ChangeType:
+ fr.env[instr] = fr.get(instr.X) // (can't fail)
+
+ case *ssa.Convert:
+ fr.env[instr] = conv(instr.Type(), instr.X.Type(), fr.get(instr.X))
+
+ case *ssa.MakeInterface:
+ fr.env[instr] = iface{t: instr.X.Type(), v: fr.get(instr.X)}
+
+ case *ssa.Extract:
+ fr.env[instr] = fr.get(instr.Tuple).(tuple)[instr.Index]
+
+ case *ssa.Slice:
+ fr.env[instr] = slice(fr.get(instr.X), fr.get(instr.Low), fr.get(instr.High), fr.get(instr.Max))
+
+ case *ssa.Return:
+ switch len(instr.Results) {
+ case 0:
+ case 1:
+ fr.result = fr.get(instr.Results[0])
+ default:
+ var res []value
+ for _, r := range instr.Results {
+ res = append(res, fr.get(r))
+ }
+ fr.result = tuple(res)
+ }
+ fr.block = nil
+ return kReturn
+
+ case *ssa.RunDefers:
+ fr.runDefers()
+
+ case *ssa.Panic:
+ panic(targetPanic{fr.get(instr.X)})
+
+ case *ssa.Send:
+ fr.get(instr.Chan).(chan value) <- fr.get(instr.X)
+
+ case *ssa.Store:
+ store(deref(instr.Addr.Type()), fr.get(instr.Addr).(*value), fr.get(instr.Val))
+
+ case *ssa.If:
+ succ := 1
+ if fr.get(instr.Cond).(bool) {
+ succ = 0
+ }
+ fr.prevBlock, fr.block = fr.block, fr.block.Succs[succ]
+ return kJump
+
+ case *ssa.Jump:
+ fr.prevBlock, fr.block = fr.block, fr.block.Succs[0]
+ return kJump
+
+ case *ssa.Defer:
+ fn, args := prepareCall(fr, &instr.Call)
+ fr.defers = &deferred{
+ fn: fn,
+ args: args,
+ instr: instr,
+ tail: fr.defers,
+ }
+
+ case *ssa.Go:
+ fn, args := prepareCall(fr, &instr.Call)
+ go call(fr.i, nil, instr.Pos(), fn, args)
+
+ case *ssa.MakeChan:
+ fr.env[instr] = make(chan value, asInt(fr.get(instr.Size)))
+
+ case *ssa.Alloc:
+ var addr *value
+ if instr.Heap {
+ // new
+ addr = new(value)
+ fr.env[instr] = addr
+ } else {
+ // local
+ addr = fr.env[instr].(*value)
+ }
+ *addr = zero(deref(instr.Type()))
+
+ case *ssa.MakeSlice:
+ slice := make([]value, asInt(fr.get(instr.Cap)))
+ tElt := instr.Type().Underlying().(*types.Slice).Elem()
+ for i := range slice {
+ slice[i] = zero(tElt)
+ }
+ fr.env[instr] = slice[:asInt(fr.get(instr.Len))]
+
+ case *ssa.MakeMap:
+ reserve := 0
+ if instr.Reserve != nil {
+ reserve = asInt(fr.get(instr.Reserve))
+ }
+ fr.env[instr] = makeMap(instr.Type().Underlying().(*types.Map).Key(), reserve)
+
+ case *ssa.Range:
+ fr.env[instr] = rangeIter(fr.get(instr.X), instr.X.Type())
+
+ case *ssa.Next:
+ fr.env[instr] = fr.get(instr.Iter).(iter).next()
+
+ case *ssa.FieldAddr:
+ x := fr.get(instr.X)
+ // FIXME wrong! &global.f must not change if we do *global = zero!
+ fr.env[instr] = &(*x.(*value)).(structure)[instr.Field]
+
+ case *ssa.Field:
+ fr.env[instr] = fr.get(instr.X).(structure)[instr.Field]
+
+ case *ssa.IndexAddr:
+ x := fr.get(instr.X)
+ idx := fr.get(instr.Index)
+ switch x := x.(type) {
+ case []value:
+ fr.env[instr] = &x[asInt(idx)]
+ case *value: // *array
+ fr.env[instr] = &(*x).(array)[asInt(idx)]
+ default:
+ panic(fmt.Sprintf("unexpected x type in IndexAddr: %T", x))
+ }
+
+ case *ssa.Index:
+ fr.env[instr] = fr.get(instr.X).(array)[asInt(fr.get(instr.Index))]
+
+ case *ssa.Lookup:
+ fr.env[instr] = lookup(instr, fr.get(instr.X), fr.get(instr.Index))
+
+ case *ssa.MapUpdate:
+ m := fr.get(instr.Map)
+ key := fr.get(instr.Key)
+ v := fr.get(instr.Value)
+ switch m := m.(type) {
+ case map[value]value:
+ m[key] = v
+ case *hashmap:
+ m.insert(key.(hashable), v)
+ default:
+ panic(fmt.Sprintf("illegal map type: %T", m))
+ }
+
+ case *ssa.TypeAssert:
+ fr.env[instr] = typeAssert(fr.i, instr, fr.get(instr.X).(iface))
+
+ case *ssa.MakeClosure:
+ var bindings []value
+ for _, binding := range instr.Bindings {
+ bindings = append(bindings, fr.get(binding))
+ }
+ fr.env[instr] = &closure{instr.Fn.(*ssa.Function), bindings}
+
+ case *ssa.Phi:
+ for i, pred := range instr.Block().Preds {
+ if fr.prevBlock == pred {
+ fr.env[instr] = fr.get(instr.Edges[i])
+ break
+ }
+ }
+
+ case *ssa.Select:
+ var cases []reflect.SelectCase
+ if !instr.Blocking {
+ cases = append(cases, reflect.SelectCase{
+ Dir: reflect.SelectDefault,
+ })
+ }
+ for _, state := range instr.States {
+ var dir reflect.SelectDir
+ if state.Dir == types.RecvOnly {
+ dir = reflect.SelectRecv
+ } else {
+ dir = reflect.SelectSend
+ }
+ var send reflect.Value
+ if state.Send != nil {
+ send = reflect.ValueOf(fr.get(state.Send))
+ }
+ cases = append(cases, reflect.SelectCase{
+ Dir: dir,
+ Chan: reflect.ValueOf(fr.get(state.Chan)),
+ Send: send,
+ })
+ }
+ chosen, recv, recvOk := reflect.Select(cases)
+ if !instr.Blocking {
+ chosen-- // default case should have index -1.
+ }
+ r := tuple{chosen, recvOk}
+ for i, st := range instr.States {
+ if st.Dir == types.RecvOnly {
+ var v value
+ if i == chosen && recvOk {
+ // No need to copy since send makes an unaliased copy.
+ v = recv.Interface().(value)
+ } else {
+ v = zero(st.Chan.Type().Underlying().(*types.Chan).Elem())
+ }
+ r = append(r, v)
+ }
+ }
+ fr.env[instr] = r
+
+ default:
+ panic(fmt.Sprintf("unexpected instruction: %T", instr))
+ }
+
+ // if val, ok := instr.(ssa.Value); ok {
+ // fmt.Println(toString(fr.env[val])) // debugging
+ // }
+
+ return kNext
+}
+
+// prepareCall determines the function value and argument values for a
+// function call in a Call, Go or Defer instruction, performing
+// interface method lookup if needed.
+//
+func prepareCall(fr *frame, call *ssa.CallCommon) (fn value, args []value) {
+ v := fr.get(call.Value)
+ if call.Method == nil {
+ // Function call.
+ fn = v
+ } else {
+ // Interface method invocation.
+ recv := v.(iface)
+ if recv.t == nil {
+ panic("method invoked on nil interface")
+ }
+ if f := lookupMethod(fr.i, recv.t, call.Method); f == nil {
+ // Unreachable in well-typed programs.
+ panic(fmt.Sprintf("method set for dynamic type %v does not contain %s", recv.t, call.Method))
+ } else {
+ fn = f
+ }
+ args = append(args, recv.v)
+ }
+ for _, arg := range call.Args {
+ args = append(args, fr.get(arg))
+ }
+ return
+}
+
+// call interprets a call to a function (function, builtin or closure)
+// fn with arguments args, returning its result.
+// callpos is the position of the callsite.
+//
+func call(i *interpreter, caller *frame, callpos token.Pos, fn value, args []value) value {
+ switch fn := fn.(type) {
+ case *ssa.Function:
+ if fn == nil {
+ panic("call of nil function") // nil of func type
+ }
+ return callSSA(i, caller, callpos, fn, args, nil)
+ case *closure:
+ return callSSA(i, caller, callpos, fn.Fn, args, fn.Env)
+ case *ssa.Builtin:
+ return callBuiltin(caller, callpos, fn, args)
+ }
+ panic(fmt.Sprintf("cannot call %T", fn))
+}
+
+func loc(fset *token.FileSet, pos token.Pos) string {
+ if pos == token.NoPos {
+ return ""
+ }
+ return " at " + fset.Position(pos).String()
+}
+
+// callSSA interprets a call to function fn with arguments args,
+// and lexical environment env, returning its result.
+// callpos is the position of the callsite.
+//
+func callSSA(i *interpreter, caller *frame, callpos token.Pos, fn *ssa.Function, args []value, env []value) value {
+ if i.mode&EnableTracing != 0 {
+ fset := fn.Prog.Fset
+ // TODO(adonovan): fix: loc() lies for external functions.
+ fmt.Fprintf(os.Stderr, "Entering %s%s.\n", fn, loc(fset, fn.Pos()))
+ suffix := ""
+ if caller != nil {
+ suffix = ", resuming " + caller.fn.String() + loc(fset, callpos)
+ }
+ defer fmt.Fprintf(os.Stderr, "Leaving %s%s.\n", fn, suffix)
+ }
+ fr := &frame{
+ i: i,
+ caller: caller, // for panic/recover
+ fn: fn,
+ }
+ if fn.Parent() == nil {
+ name := fn.String()
+ if ext := externals[name]; ext != nil {
+ if i.mode&EnableTracing != 0 {
+ fmt.Fprintln(os.Stderr, "\t(external)")
+ }
+ return ext(fr, args)
+ }
+ if fn.Blocks == nil {
+ panic("no code for function: " + name)
+ }
+ }
+ fr.env = make(map[ssa.Value]value)
+ fr.block = fn.Blocks[0]
+ fr.locals = make([]value, len(fn.Locals))
+ for i, l := range fn.Locals {
+ fr.locals[i] = zero(deref(l.Type()))
+ fr.env[l] = &fr.locals[i]
+ }
+ for i, p := range fn.Params {
+ fr.env[p] = args[i]
+ }
+ for i, fv := range fn.FreeVars {
+ fr.env[fv] = env[i]
+ }
+ for fr.block != nil {
+ runFrame(fr)
+ }
+ // Destroy the locals to avoid accidental use after return.
+ for i := range fn.Locals {
+ fr.locals[i] = bad{}
+ }
+ return fr.result
+}
+
+// runFrame executes SSA instructions starting at fr.block and
+// continuing until a return, a panic, or a recovered panic.
+//
+// After a panic, runFrame panics.
+//
+// After a normal return, fr.result contains the result of the call
+// and fr.block is nil.
+//
+// A recovered panic in a function without named return parameters
+// (NRPs) becomes a normal return of the zero value of the function's
+// result type.
+//
+// After a recovered panic in a function with NRPs, fr.result is
+// undefined and fr.block contains the block at which to resume
+// control.
+//
+func runFrame(fr *frame) {
+ defer func() {
+ if fr.block == nil {
+ return // normal return
+ }
+ if fr.i.mode&DisableRecover != 0 {
+ return // let interpreter crash
+ }
+ fr.panicking = true
+ fr.panic = recover()
+ if fr.i.mode&EnableTracing != 0 {
+ fmt.Fprintf(os.Stderr, "Panicking: %T %v.\n", fr.panic, fr.panic)
+ }
+ fr.runDefers()
+ fr.block = fr.fn.Recover
+ }()
+
+ for {
+ if fr.i.mode&EnableTracing != 0 {
+ fmt.Fprintf(os.Stderr, ".%s:\n", fr.block)
+ }
+ block:
+ for _, instr := range fr.block.Instrs {
+ if fr.i.mode&EnableTracing != 0 {
+ if v, ok := instr.(ssa.Value); ok {
+ fmt.Fprintln(os.Stderr, "\t", v.Name(), "=", instr)
+ } else {
+ fmt.Fprintln(os.Stderr, "\t", instr)
+ }
+ }
+ switch visitInstr(fr, instr) {
+ case kReturn:
+ return
+ case kNext:
+ // no-op
+ case kJump:
+ break block
+ }
+ }
+ }
+}
+
+// doRecover implements the recover() built-in.
+func doRecover(caller *frame) value {
+ // recover() must be exactly one level beneath the deferred
+ // function (two levels beneath the panicking function) to
+ // have any effect. Thus we ignore both "defer recover()" and
+ // "defer f() -> g() -> recover()".
+ if caller.i.mode&DisableRecover == 0 &&
+ caller != nil && !caller.panicking &&
+ caller.caller != nil && caller.caller.panicking {
+ caller.caller.panicking = false
+ p := caller.caller.panic
+ caller.caller.panic = nil
+ switch p := p.(type) {
+ case targetPanic:
+ // The target program explicitly called panic().
+ return p.v
+ case runtime.Error:
+ // The interpreter encountered a runtime error.
+ return iface{caller.i.runtimeErrorString, p.Error()}
+ case string:
+ // The interpreter explicitly called panic().
+ return iface{caller.i.runtimeErrorString, p}
+ default:
+ panic(fmt.Sprintf("unexpected panic type %T in target call to recover()", p))
+ }
+ }
+ return iface{}
+}
+
+// setGlobal sets the value of a system-initialized global variable.
+func setGlobal(i *interpreter, pkg *ssa.Package, name string, v value) {
+ if g, ok := i.globals[pkg.Var(name)]; ok {
+ *g = v
+ return
+ }
+ panic("no global variable: " + pkg.Object.Path() + "." + name)
+}
+
+var environ []value
+
+func init() {
+ for _, s := range os.Environ() {
+ environ = append(environ, s)
+ }
+ environ = append(environ, "GOSSAINTERP=1")
+ environ = append(environ, "GOARCH="+runtime.GOARCH)
+}
+
+// deleteBodies delete the bodies of all standalone functions except the
+// specified ones. A missing intrinsic leads to a clear runtime error.
+func deleteBodies(pkg *ssa.Package, except ...string) {
+ keep := make(map[string]bool)
+ for _, e := range except {
+ keep[e] = true
+ }
+ for _, mem := range pkg.Members {
+ if fn, ok := mem.(*ssa.Function); ok && !keep[fn.Name()] {
+ fn.Blocks = nil
+ }
+ }
+}
+
+// Interpret interprets the Go program whose main package is mainpkg.
+// mode specifies various interpreter options. filename and args are
+// the initial values of os.Args for the target program. sizes is the
+// effective type-sizing function for this program.
+//
+// Interpret returns the exit code of the program: 2 for panic (like
+// gc does), or the argument to os.Exit for normal termination.
+//
+// The SSA program must include the "runtime" package.
+//
+func Interpret(mainpkg *ssa.Package, mode Mode, sizes types.Sizes, filename string, args []string) (exitCode int) {
+ i := &interpreter{
+ prog: mainpkg.Prog,
+ globals: make(map[ssa.Value]*value),
+ mode: mode,
+ sizes: sizes,
+ }
+ runtimePkg := i.prog.ImportedPackage("runtime")
+ if runtimePkg == nil {
+ panic("ssa.Program doesn't include runtime package")
+ }
+ i.runtimeErrorString = runtimePkg.Type("errorString").Object().Type()
+
+ initReflect(i)
+
+ i.osArgs = append(i.osArgs, filename)
+ for _, arg := range args {
+ i.osArgs = append(i.osArgs, arg)
+ }
+
+ for _, pkg := range i.prog.AllPackages() {
+ // Initialize global storage.
+ for _, m := range pkg.Members {
+ switch v := m.(type) {
+ case *ssa.Global:
+ cell := zero(deref(v.Type()))
+ i.globals[v] = &cell
+ }
+ }
+
+ // Ad-hoc initialization for magic system variables.
+ switch pkg.Object.Path() {
+ case "syscall":
+ setGlobal(i, pkg, "envs", environ)
+
+ case "reflect":
+ deleteBodies(pkg, "DeepEqual", "deepValueEqual")
+
+ case "runtime":
+ sz := sizes.Sizeof(pkg.Object.Scope().Lookup("MemStats").Type())
+ setGlobal(i, pkg, "sizeof_C_MStats", uintptr(sz))
+ deleteBodies(pkg, "GOROOT", "gogetenv")
+ }
+ }
+
+ // Top-level error handler.
+ exitCode = 2
+ defer func() {
+ if exitCode != 2 || i.mode&DisableRecover != 0 {
+ return
+ }
+ switch p := recover().(type) {
+ case exitPanic:
+ exitCode = int(p)
+ return
+ case targetPanic:
+ fmt.Fprintln(os.Stderr, "panic:", toString(p.v))
+ case runtime.Error:
+ fmt.Fprintln(os.Stderr, "panic:", p.Error())
+ case string:
+ fmt.Fprintln(os.Stderr, "panic:", p)
+ default:
+ fmt.Fprintf(os.Stderr, "panic: unexpected type: %T: %v\n", p, p)
+ }
+
+ // TODO(adonovan): dump panicking interpreter goroutine?
+ // buf := make([]byte, 0x10000)
+ // runtime.Stack(buf, false)
+ // fmt.Fprintln(os.Stderr, string(buf))
+ // (Or dump panicking target goroutine?)
+ }()
+
+ // Run!
+ call(i, nil, token.NoPos, mainpkg.Func("init"), nil)
+ if mainFn := mainpkg.Func("main"); mainFn != nil {
+ call(i, nil, token.NoPos, mainFn, nil)
+ exitCode = 0
+ } else {
+ fmt.Fprintln(os.Stderr, "No main function.")
+ exitCode = 1
+ }
+ return
+}
+
+// deref returns a pointer's element type; otherwise it returns typ.
+// TODO(adonovan): Import from ssa?
+func deref(typ types.Type) types.Type {
+ if p, ok := typ.Underlying().(*types.Pointer); ok {
+ return p.Elem()
+ }
+ return typ
+}
diff --git a/go/ssa/interp/interp_test.go b/go/ssa/interp/interp_test.go
new file mode 100644
index 0000000..f36c23e
--- /dev/null
+++ b/go/ssa/interp/interp_test.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.
+
+// +build !android,!windows,!plan9
+
+package interp_test
+
+import (
+ "bytes"
+ "fmt"
+ "go/build"
+ "os"
+ "path/filepath"
+ "strings"
+ "testing"
+ "time"
+
+ "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"
+)
+
+// Each line contains a space-separated list of $GOROOT/test/
+// filenames comprising the main package of a program.
+// They are ordered quickest-first, roughly.
+//
+// TODO(adonovan): integrate into the $GOROOT/test driver scripts,
+// golden file checking, etc.
+var gorootTestTests = []string{
+ "235.go",
+ "alias1.go",
+ "chancap.go",
+ "func5.go",
+ "func6.go",
+ "func7.go",
+ "func8.go",
+ "helloworld.go",
+ "varinit.go",
+ "escape3.go",
+ "initcomma.go",
+ "cmp.go",
+ "compos.go",
+ "turing.go",
+ "indirect.go",
+ "complit.go",
+ "for.go",
+ "struct0.go",
+ "intcvt.go",
+ "printbig.go",
+ "deferprint.go",
+ "escape.go",
+ "range.go",
+ "const4.go",
+ "float_lit.go",
+ "bigalg.go",
+ "decl.go",
+ "if.go",
+ "named.go",
+ "bigmap.go",
+ "func.go",
+ "reorder2.go",
+ "closure.go",
+ "gc.go",
+ "simassign.go",
+ "iota.go",
+ "nilptr2.go",
+ "goprint.go", // doesn't actually assert anything (cmpout)
+ "utf.go",
+ "method.go",
+ "char_lit.go",
+ "env.go",
+ "int_lit.go",
+ "string_lit.go",
+ "defer.go",
+ "typeswitch.go",
+ "stringrange.go",
+ "reorder.go",
+ "method3.go",
+ "literal.go",
+ "nul1.go", // doesn't actually assert anything (errorcheckoutput)
+ "zerodivide.go",
+ "convert.go",
+ "convT2X.go",
+ "switch.go",
+ "initialize.go",
+ "ddd.go",
+ "blank.go", // partly disabled
+ "map.go",
+ "closedchan.go",
+ "divide.go",
+ "rename.go",
+ "const3.go",
+ "nil.go",
+ "recover.go", // reflection parts disabled
+ "recover1.go",
+ "recover2.go",
+ "recover3.go",
+ "typeswitch1.go",
+ "floatcmp.go",
+ "crlf.go", // doesn't actually assert anything (runoutput)
+ // Slow tests follow.
+ "bom.go", // ~1.7s
+ "gc1.go", // ~1.7s
+ "cmplxdivide.go cmplxdivide1.go", // ~2.4s
+
+ // Working, but not worth enabling:
+ // "append.go", // works, but slow (15s).
+ // "gc2.go", // works, but slow, and cheats on the memory check.
+ // "sigchld.go", // works, but only on POSIX.
+ // "peano.go", // works only up to n=9, and slow even then.
+ // "stack.go", // works, but too slow (~30s) by default.
+ // "solitaire.go", // works, but too slow (~30s).
+ // "const.go", // works but for but one bug: constant folder doesn't consider representations.
+ // "init1.go", // too slow (80s) and not that interesting. Cheats on ReadMemStats check too.
+ // "rotate.go rotate0.go", // emits source for a test
+ // "rotate.go rotate1.go", // emits source for a test
+ // "rotate.go rotate2.go", // emits source for a test
+ // "rotate.go rotate3.go", // emits source for a test
+ // "64bit.go", // emits source for a test
+ // "run.go", // test driver, not a test.
+
+ // Broken. TODO(adonovan): fix.
+ // copy.go // very slow; but with N=4 quickly crashes, slice index out of range.
+ // nilptr.go // interp: V > uintptr not implemented. Slow test, lots of mem
+ // args.go // works, but requires specific os.Args from the driver.
+ // index.go // a template, not a real test.
+ // mallocfin.go // SetFinalizer not implemented.
+
+ // TODO(adonovan): add tests from $GOROOT/test/* subtrees:
+ // bench chan bugs fixedbugs interface ken.
+}
+
+// These are files in go.tools/go/ssa/interp/testdata/.
+var testdataTests = []string{
+ "boundmeth.go",
+ "complit.go",
+ "coverage.go",
+ "defer.go",
+ "fieldprom.go",
+ "ifaceconv.go",
+ "ifaceprom.go",
+ "initorder.go",
+ "methprom.go",
+ "mrvchain.go",
+ "range.go",
+ "recover.go",
+ "reflect.go",
+ "static.go",
+ "callstack.go",
+}
+
+// These are files and packages in $GOROOT/src/.
+var gorootSrcTests = []string{
+ "encoding/ascii85",
+ "encoding/hex",
+ // "encoding/pem", // TODO(adonovan): implement (reflect.Value).SetString
+ // "testing", // TODO(adonovan): implement runtime.Goexit correctly
+ "unicode",
+
+ // Too slow:
+ // "container/ring",
+ // "hash/adler32",
+
+ // TODO(adonovan): packages with Examples require os.Pipe (unimplemented):
+ // "hash/crc32",
+ // "unicode/utf8",
+ // "log",
+ // "path",
+ // "flag",
+ // "encoding/csv"
+ // "text/scanner"
+}
+
+type successPredicate func(exitcode int, output string) error
+
+func run(t *testing.T, dir, input string, success successPredicate) bool {
+ fmt.Printf("Input: %s\n", input)
+
+ start := time.Now()
+
+ var inputs []string
+ for _, i := range strings.Split(input, " ") {
+ if strings.HasSuffix(i, ".go") {
+ i = dir + i
+ }
+ inputs = append(inputs, i)
+ }
+
+ var conf loader.Config
+ if _, err := conf.FromArgs(inputs, true); err != nil {
+ t.Errorf("FromArgs(%s) failed: %s", inputs, err)
+ return false
+ }
+
+ conf.Import("runtime")
+
+ // Print a helpful hint if we don't make it to the end.
+ var hint string
+ defer func() {
+ if hint != "" {
+ fmt.Println("FAIL")
+ fmt.Println(hint)
+ } else {
+ fmt.Println("PASS")
+ }
+
+ interp.CapturedOutput = nil
+ }()
+
+ hint = fmt.Sprintf("To dump SSA representation, run:\n%% go build golang.org/x/tools/cmd/ssadump && ./ssadump -build=CFP %s\n", input)
+
+ iprog, err := conf.Load()
+ if err != nil {
+ t.Errorf("conf.Load(%s) failed: %s", inputs, err)
+ return false
+ }
+
+ prog := ssautil.CreateProgram(iprog, ssa.SanityCheckFunctions)
+ prog.BuildAll()
+
+ var mainPkg *ssa.Package
+ var initialPkgs []*ssa.Package
+ for _, info := range iprog.InitialPackages() {
+ if info.Pkg.Path() == "runtime" {
+ continue // not an initial package
+ }
+ p := prog.Package(info.Pkg)
+ initialPkgs = append(initialPkgs, p)
+ if mainPkg == nil && p.Func("main") != nil {
+ mainPkg = p
+ }
+ }
+ if mainPkg == nil {
+ testmainPkg := prog.CreateTestMainPackage(initialPkgs...)
+ if testmainPkg == nil {
+ t.Errorf("CreateTestMainPackage(%s) returned nil", mainPkg)
+ return false
+ }
+ if testmainPkg.Func("main") == nil {
+ t.Errorf("synthetic testmain package has no main")
+ return false
+ }
+ mainPkg = testmainPkg
+ }
+
+ var out bytes.Buffer
+ interp.CapturedOutput = &out
+
+ hint = fmt.Sprintf("To trace execution, run:\n%% go build golang.org/x/tools/cmd/ssadump && ./ssadump -build=C -run --interp=T %s\n", input)
+ exitCode := interp.Interpret(mainPkg, 0, &types.StdSizes{8, 8}, inputs[0], []string{})
+
+ // The definition of success varies with each file.
+ if err := success(exitCode, out.String()); err != nil {
+ t.Errorf("interp.Interpret(%s) failed: %s", inputs, err)
+ return false
+ }
+
+ hint = "" // call off the hounds
+
+ if false {
+ fmt.Println(input, time.Since(start)) // test profiling
+ }
+
+ return true
+}
+
+const slash = string(os.PathSeparator)
+
+func printFailures(failures []string) {
+ if failures != nil {
+ fmt.Println("The following tests failed:")
+ for _, f := range failures {
+ fmt.Printf("\t%s\n", f)
+ }
+ }
+}
+
+func success(exitcode int, output string) error {
+ if exitcode != 0 {
+ return fmt.Errorf("exit code was %d", exitcode)
+ }
+ if strings.Contains(output, "BUG") {
+ return fmt.Errorf("exited zero but output contained 'BUG'")
+ }
+ return nil
+}
+
+// TestTestdataFiles runs the interpreter on testdata/*.go.
+func TestTestdataFiles(t *testing.T) {
+ var failures []string
+ start := time.Now()
+ for _, input := range testdataTests {
+ if testing.Short() && time.Since(start) > 30*time.Second {
+ printFailures(failures)
+ t.Skipf("timeout - aborting test")
+ }
+ if !run(t, "testdata"+slash, input, success) {
+ failures = append(failures, input)
+ }
+ }
+ printFailures(failures)
+}
+
+// TestGorootTest runs the interpreter on $GOROOT/test/*.go.
+func TestGorootTest(t *testing.T) {
+ if testing.Short() {
+ t.Skip() // too slow (~30s)
+ }
+
+ var failures []string
+
+ for _, input := range gorootTestTests {
+ if !run(t, filepath.Join(build.Default.GOROOT, "test")+slash, input, success) {
+ failures = append(failures, input)
+ }
+ }
+ for _, input := range gorootSrcTests {
+ if !run(t, filepath.Join(build.Default.GOROOT, "src")+slash, input, success) {
+ failures = append(failures, input)
+ }
+ }
+ printFailures(failures)
+}
+
+// TestTestmainPackage runs the interpreter on a synthetic "testmain" package.
+func TestTestmainPackage(t *testing.T) {
+ if testing.Short() {
+ t.Skip() // too slow on some platforms
+ }
+
+ success := func(exitcode int, output string) error {
+ if exitcode == 0 {
+ return fmt.Errorf("unexpected success")
+ }
+ if !strings.Contains(output, "FAIL: TestFoo") {
+ return fmt.Errorf("missing failure log for TestFoo")
+ }
+ if !strings.Contains(output, "FAIL: TestBar") {
+ return fmt.Errorf("missing failure log for TestBar")
+ }
+ // TODO(adonovan): test benchmarks too
+ return nil
+ }
+ run(t, "testdata"+slash, "a_test.go", success)
+}
+
+// CreateTestMainPackage should return nil if there were no tests.
+func TestNullTestmainPackage(t *testing.T) {
+ var conf loader.Config
+ conf.CreateFromFilenames("", "testdata/b_test.go")
+ iprog, err := conf.Load()
+ if err != nil {
+ t.Fatalf("CreatePackages failed: %s", err)
+ }
+ prog := ssautil.CreateProgram(iprog, ssa.SanityCheckFunctions)
+ mainPkg := prog.Package(iprog.Created[0].Pkg)
+ if mainPkg.Func("main") != nil {
+ t.Fatalf("unexpected main function")
+ }
+ if prog.CreateTestMainPackage(mainPkg) != nil {
+ t.Fatalf("CreateTestMainPackage returned non-nil")
+ }
+}
diff --git a/go/ssa/interp/map.go b/go/ssa/interp/map.go
new file mode 100644
index 0000000..5dbaf0a
--- /dev/null
+++ b/go/ssa/interp/map.go
@@ -0,0 +1,113 @@
+// 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 interp
+
+// Custom hashtable atop map.
+// For use when the key's equivalence relation is not consistent with ==.
+
+// The Go specification doesn't address the atomicity of map operations.
+// The FAQ states that an implementation is permitted to crash on
+// concurrent map access.
+
+import (
+ "golang.org/x/tools/go/types"
+)
+
+type hashable interface {
+ hash(t types.Type) int
+ eq(t types.Type, x interface{}) bool
+}
+
+type entry struct {
+ key hashable
+ value value
+ next *entry
+}
+
+// A hashtable atop the built-in map. Since each bucket contains
+// exactly one hash value, there's no need to perform hash-equality
+// tests when walking the linked list. Rehashing is done by the
+// underlying map.
+type hashmap struct {
+ keyType types.Type
+ table map[int]*entry
+ length int // number of entries in map
+}
+
+// makeMap returns an empty initialized map of key type kt,
+// preallocating space for reserve elements.
+func makeMap(kt types.Type, reserve int) value {
+ if usesBuiltinMap(kt) {
+ return make(map[value]value, reserve)
+ }
+ return &hashmap{keyType: kt, table: make(map[int]*entry, reserve)}
+}
+
+// delete removes the association for key k, if any.
+func (m *hashmap) delete(k hashable) {
+ if m != nil {
+ hash := k.hash(m.keyType)
+ head := m.table[hash]
+ if head != nil {
+ if k.eq(m.keyType, head.key) {
+ m.table[hash] = head.next
+ m.length--
+ return
+ }
+ prev := head
+ for e := head.next; e != nil; e = e.next {
+ if k.eq(m.keyType, e.key) {
+ prev.next = e.next
+ m.length--
+ return
+ }
+ prev = e
+ }
+ }
+ }
+}
+
+// lookup returns the value associated with key k, if present, or
+// value(nil) otherwise.
+func (m *hashmap) lookup(k hashable) value {
+ if m != nil {
+ hash := k.hash(m.keyType)
+ for e := m.table[hash]; e != nil; e = e.next {
+ if k.eq(m.keyType, e.key) {
+ return e.value
+ }
+ }
+ }
+ return nil
+}
+
+// insert updates the map to associate key k with value v. If there
+// was already an association for an eq() (though not necessarily ==)
+// k, the previous key remains in the map and its associated value is
+// updated.
+func (m *hashmap) insert(k hashable, v value) {
+ hash := k.hash(m.keyType)
+ head := m.table[hash]
+ for e := head; e != nil; e = e.next {
+ if k.eq(m.keyType, e.key) {
+ e.value = v
+ return
+ }
+ }
+ m.table[hash] = &entry{
+ key: k,
+ value: v,
+ next: head,
+ }
+ m.length++
+}
+
+// len returns the number of key/value associations in the map.
+func (m *hashmap) len() int {
+ if m != nil {
+ return m.length
+ }
+ return 0
+}
diff --git a/go/ssa/interp/ops.go b/go/ssa/interp/ops.go
new file mode 100644
index 0000000..de89904
--- /dev/null
+++ b/go/ssa/interp/ops.go
@@ -0,0 +1,1394 @@
+// 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 interp
+
+import (
+ "bytes"
+ "fmt"
+ "go/token"
+ "strings"
+ "sync"
+ "unsafe"
+
+ "golang.org/x/tools/go/exact"
+ "golang.org/x/tools/go/ssa"
+ "golang.org/x/tools/go/types"
+)
+
+// If the target program panics, the interpreter panics with this type.
+type targetPanic struct {
+ v value
+}
+
+func (p targetPanic) String() string {
+ return toString(p.v)
+}
+
+// If the target program calls exit, the interpreter panics with this type.
+type exitPanic int
+
+// constValue returns the value of the constant with the
+// dynamic type tag appropriate for c.Type().
+func constValue(c *ssa.Const) value {
+ if c.IsNil() {
+ return zero(c.Type()) // typed nil
+ }
+
+ if t, ok := c.Type().Underlying().(*types.Basic); ok {
+ // TODO(adonovan): eliminate untyped constants from SSA form.
+ switch t.Kind() {
+ case types.Bool, types.UntypedBool:
+ return exact.BoolVal(c.Value)
+ case types.Int, types.UntypedInt:
+ // Assume sizeof(int) is same on host and target.
+ return int(c.Int64())
+ case types.Int8:
+ return int8(c.Int64())
+ case types.Int16:
+ return int16(c.Int64())
+ case types.Int32, types.UntypedRune:
+ return int32(c.Int64())
+ case types.Int64:
+ return c.Int64()
+ case types.Uint:
+ // Assume sizeof(uint) is same on host and target.
+ return uint(c.Uint64())
+ case types.Uint8:
+ return uint8(c.Uint64())
+ case types.Uint16:
+ return uint16(c.Uint64())
+ case types.Uint32:
+ return uint32(c.Uint64())
+ case types.Uint64:
+ return c.Uint64()
+ case types.Uintptr:
+ // Assume sizeof(uintptr) is same on host and target.
+ return uintptr(c.Uint64())
+ case types.Float32:
+ return float32(c.Float64())
+ case types.Float64, types.UntypedFloat:
+ return c.Float64()
+ case types.Complex64:
+ return complex64(c.Complex128())
+ case types.Complex128, types.UntypedComplex:
+ return c.Complex128()
+ case types.String, types.UntypedString:
+ if c.Value.Kind() == exact.String {
+ return exact.StringVal(c.Value)
+ }
+ return string(rune(c.Int64()))
+ }
+ }
+
+ panic(fmt.Sprintf("constValue: %s", c))
+}
+
+// asInt converts x, which must be an integer, to an int suitable for
+// use as a slice or array index or operand to make().
+func asInt(x value) int {
+ switch x := x.(type) {
+ case int:
+ return x
+ case int8:
+ return int(x)
+ case int16:
+ return int(x)
+ case int32:
+ return int(x)
+ case int64:
+ return int(x)
+ case uint:
+ return int(x)
+ case uint8:
+ return int(x)
+ case uint16:
+ return int(x)
+ case uint32:
+ return int(x)
+ case uint64:
+ return int(x)
+ case uintptr:
+ return int(x)
+ }
+ panic(fmt.Sprintf("cannot convert %T to int", x))
+}
+
+// asUint64 converts x, which must be an unsigned integer, to a uint64
+// suitable for use as a bitwise shift count.
+func asUint64(x value) uint64 {
+ switch x := x.(type) {
+ case uint:
+ return uint64(x)
+ case uint8:
+ return uint64(x)
+ case uint16:
+ return uint64(x)
+ case uint32:
+ return uint64(x)
+ case uint64:
+ return x
+ case uintptr:
+ return uint64(x)
+ }
+ panic(fmt.Sprintf("cannot convert %T to uint64", x))
+}
+
+// zero returns a new "zero" value of the specified type.
+func zero(t types.Type) value {
+ switch t := t.(type) {
+ case *types.Basic:
+ if t.Kind() == types.UntypedNil {
+ panic("untyped nil has no zero value")
+ }
+ if t.Info()&types.IsUntyped != 0 {
+ // TODO(adonovan): make it an invariant that
+ // this is unreachable. Currently some
+ // constants have 'untyped' types when they
+ // should be defaulted by the typechecker.
+ t = ssa.DefaultType(t).(*types.Basic)
+ }
+ switch t.Kind() {
+ case types.Bool:
+ return false
+ case types.Int:
+ return int(0)
+ case types.Int8:
+ return int8(0)
+ case types.Int16:
+ return int16(0)
+ case types.Int32:
+ return int32(0)
+ case types.Int64:
+ return int64(0)
+ case types.Uint:
+ return uint(0)
+ case types.Uint8:
+ return uint8(0)
+ case types.Uint16:
+ return uint16(0)
+ case types.Uint32:
+ return uint32(0)
+ case types.Uint64:
+ return uint64(0)
+ case types.Uintptr:
+ return uintptr(0)
+ case types.Float32:
+ return float32(0)
+ case types.Float64:
+ return float64(0)
+ case types.Complex64:
+ return complex64(0)
+ case types.Complex128:
+ return complex128(0)
+ case types.String:
+ return ""
+ case types.UnsafePointer:
+ return unsafe.Pointer(nil)
+ default:
+ panic(fmt.Sprint("zero for unexpected type:", t))
+ }
+ case *types.Pointer:
+ return (*value)(nil)
+ case *types.Array:
+ a := make(array, t.Len())
+ for i := range a {
+ a[i] = zero(t.Elem())
+ }
+ return a
+ case *types.Named:
+ return zero(t.Underlying())
+ case *types.Interface:
+ return iface{} // nil type, methodset and value
+ case *types.Slice:
+ return []value(nil)
+ case *types.Struct:
+ s := make(structure, t.NumFields())
+ for i := range s {
+ s[i] = zero(t.Field(i).Type())
+ }
+ return s
+ case *types.Tuple:
+ if t.Len() == 1 {
+ return zero(t.At(0).Type())
+ }
+ s := make(tuple, t.Len())
+ for i := range s {
+ s[i] = zero(t.At(i).Type())
+ }
+ return s
+ case *types.Chan:
+ return chan value(nil)
+ case *types.Map:
+ if usesBuiltinMap(t.Key()) {
+ return map[value]value(nil)
+ }
+ return (*hashmap)(nil)
+ case *types.Signature:
+ return (*ssa.Function)(nil)
+ }
+ panic(fmt.Sprint("zero: unexpected ", t))
+}
+
+// slice returns x[lo:hi:max]. Any of lo, hi and max may be nil.
+func slice(x, lo, hi, max value) value {
+ var Len, Cap int
+ switch x := x.(type) {
+ case string:
+ Len = len(x)
+ case []value:
+ Len = len(x)
+ Cap = cap(x)
+ case *value: // *array
+ a := (*x).(array)
+ Len = len(a)
+ Cap = cap(a)
+ }
+
+ l := 0
+ if lo != nil {
+ l = asInt(lo)
+ }
+
+ h := Len
+ if hi != nil {
+ h = asInt(hi)
+ }
+
+ m := Cap
+ if max != nil {
+ m = asInt(max)
+ }
+
+ switch x := x.(type) {
+ case string:
+ return x[l:h]
+ case []value:
+ return x[l:h:m]
+ case *value: // *array
+ a := (*x).(array)
+ return []value(a)[l:h:m]
+ }
+ panic(fmt.Sprintf("slice: unexpected X type: %T", x))
+}
+
+// lookup returns x[idx] where x is a map or string.
+func lookup(instr *ssa.Lookup, x, idx value) value {
+ switch x := x.(type) { // map or string
+ case map[value]value, *hashmap:
+ var v value
+ var ok bool
+ switch x := x.(type) {
+ case map[value]value:
+ v, ok = x[idx]
+ case *hashmap:
+ v = x.lookup(idx.(hashable))
+ ok = v != nil
+ }
+ if !ok {
+ v = zero(instr.X.Type().Underlying().(*types.Map).Elem())
+ }
+ if instr.CommaOk {
+ v = tuple{v, ok}
+ }
+ return v
+ case string:
+ return x[asInt(idx)]
+ }
+ panic(fmt.Sprintf("unexpected x type in Lookup: %T", x))
+}
+
+// binop implements all arithmetic and logical binary operators for
+// numeric datatypes and strings. Both operands must have identical
+// dynamic type.
+//
+func binop(op token.Token, t types.Type, x, y value) value {
+ switch op {
+ case token.ADD:
+ switch x.(type) {
+ case int:
+ return x.(int) + y.(int)
+ case int8:
+ return x.(int8) + y.(int8)
+ case int16:
+ return x.(int16) + y.(int16)
+ case int32:
+ return x.(int32) + y.(int32)
+ case int64:
+ return x.(int64) + y.(int64)
+ case uint:
+ return x.(uint) + y.(uint)
+ case uint8:
+ return x.(uint8) + y.(uint8)
+ case uint16:
+ return x.(uint16) + y.(uint16)
+ case uint32:
+ return x.(uint32) + y.(uint32)
+ case uint64:
+ return x.(uint64) + y.(uint64)
+ case uintptr:
+ return x.(uintptr) + y.(uintptr)
+ case float32:
+ return x.(float32) + y.(float32)
+ case float64:
+ return x.(float64) + y.(float64)
+ case complex64:
+ return x.(complex64) + y.(complex64)
+ case complex128:
+ return x.(complex128) + y.(complex128)
+ case string:
+ return x.(string) + y.(string)
+ }
+
+ case token.SUB:
+ switch x.(type) {
+ case int:
+ return x.(int) - y.(int)
+ case int8:
+ return x.(int8) - y.(int8)
+ case int16:
+ return x.(int16) - y.(int16)
+ case int32:
+ return x.(int32) - y.(int32)
+ case int64:
+ return x.(int64) - y.(int64)
+ case uint:
+ return x.(uint) - y.(uint)
+ case uint8:
+ return x.(uint8) - y.(uint8)
+ case uint16:
+ return x.(uint16) - y.(uint16)
+ case uint32:
+ return x.(uint32) - y.(uint32)
+ case uint64:
+ return x.(uint64) - y.(uint64)
+ case uintptr:
+ return x.(uintptr) - y.(uintptr)
+ case float32:
+ return x.(float32) - y.(float32)
+ case float64:
+ return x.(float64) - y.(float64)
+ case complex64:
+ return x.(complex64) - y.(complex64)
+ case complex128:
+ return x.(complex128) - y.(complex128)
+ }
+
+ case token.MUL:
+ switch x.(type) {
+ case int:
+ return x.(int) * y.(int)
+ case int8:
+ return x.(int8) * y.(int8)
+ case int16:
+ return x.(int16) * y.(int16)
+ case int32:
+ return x.(int32) * y.(int32)
+ case int64:
+ return x.(int64) * y.(int64)
+ case uint:
+ return x.(uint) * y.(uint)
+ case uint8:
+ return x.(uint8) * y.(uint8)
+ case uint16:
+ return x.(uint16) * y.(uint16)
+ case uint32:
+ return x.(uint32) * y.(uint32)
+ case uint64:
+ return x.(uint64) * y.(uint64)
+ case uintptr:
+ return x.(uintptr) * y.(uintptr)
+ case float32:
+ return x.(float32) * y.(float32)
+ case float64:
+ return x.(float64) * y.(float64)
+ case complex64:
+ return x.(complex64) * y.(complex64)
+ case complex128:
+ return x.(complex128) * y.(complex128)
+ }
+
+ case token.QUO:
+ switch x.(type) {
+ case int:
+ return x.(int) / y.(int)
+ case int8:
+ return x.(int8) / y.(int8)
+ case int16:
+ return x.(int16) / y.(int16)
+ case int32:
+ return x.(int32) / y.(int32)
+ case int64:
+ return x.(int64) / y.(int64)
+ case uint:
+ return x.(uint) / y.(uint)
+ case uint8:
+ return x.(uint8) / y.(uint8)
+ case uint16:
+ return x.(uint16) / y.(uint16)
+ case uint32:
+ return x.(uint32) / y.(uint32)
+ case uint64:
+ return x.(uint64) / y.(uint64)
+ case uintptr:
+ return x.(uintptr) / y.(uintptr)
+ case float32:
+ return x.(float32) / y.(float32)
+ case float64:
+ return x.(float64) / y.(float64)
+ case complex64:
+ return x.(complex64) / y.(complex64)
+ case complex128:
+ return x.(complex128) / y.(complex128)
+ }
+
+ case token.REM:
+ switch x.(type) {
+ case int:
+ return x.(int) % y.(int)
+ case int8:
+ return x.(int8) % y.(int8)
+ case int16:
+ return x.(int16) % y.(int16)
+ case int32:
+ return x.(int32) % y.(int32)
+ case int64:
+ return x.(int64) % y.(int64)
+ case uint:
+ return x.(uint) % y.(uint)
+ case uint8:
+ return x.(uint8) % y.(uint8)
+ case uint16:
+ return x.(uint16) % y.(uint16)
+ case uint32:
+ return x.(uint32) % y.(uint32)
+ case uint64:
+ return x.(uint64) % y.(uint64)
+ case uintptr:
+ return x.(uintptr) % y.(uintptr)
+ }
+
+ case token.AND:
+ switch x.(type) {
+ case int:
+ return x.(int) & y.(int)
+ case int8:
+ return x.(int8) & y.(int8)
+ case int16:
+ return x.(int16) & y.(int16)
+ case int32:
+ return x.(int32) & y.(int32)
+ case int64:
+ return x.(int64) & y.(int64)
+ case uint:
+ return x.(uint) & y.(uint)
+ case uint8:
+ return x.(uint8) & y.(uint8)
+ case uint16:
+ return x.(uint16) & y.(uint16)
+ case uint32:
+ return x.(uint32) & y.(uint32)
+ case uint64:
+ return x.(uint64) & y.(uint64)
+ case uintptr:
+ return x.(uintptr) & y.(uintptr)
+ }
+
+ case token.OR:
+ switch x.(type) {
+ case int:
+ return x.(int) | y.(int)
+ case int8:
+ return x.(int8) | y.(int8)
+ case int16:
+ return x.(int16) | y.(int16)
+ case int32:
+ return x.(int32) | y.(int32)
+ case int64:
+ return x.(int64) | y.(int64)
+ case uint:
+ return x.(uint) | y.(uint)
+ case uint8:
+ return x.(uint8) | y.(uint8)
+ case uint16:
+ return x.(uint16) | y.(uint16)
+ case uint32:
+ return x.(uint32) | y.(uint32)
+ case uint64:
+ return x.(uint64) | y.(uint64)
+ case uintptr:
+ return x.(uintptr) | y.(uintptr)
+ }
+
+ case token.XOR:
+ switch x.(type) {
+ case int:
+ return x.(int) ^ y.(int)
+ case int8:
+ return x.(int8) ^ y.(int8)
+ case int16:
+ return x.(int16) ^ y.(int16)
+ case int32:
+ return x.(int32) ^ y.(int32)
+ case int64:
+ return x.(int64) ^ y.(int64)
+ case uint:
+ return x.(uint) ^ y.(uint)
+ case uint8:
+ return x.(uint8) ^ y.(uint8)
+ case uint16:
+ return x.(uint16) ^ y.(uint16)
+ case uint32:
+ return x.(uint32) ^ y.(uint32)
+ case uint64:
+ return x.(uint64) ^ y.(uint64)
+ case uintptr:
+ return x.(uintptr) ^ y.(uintptr)
+ }
+
+ case token.AND_NOT:
+ switch x.(type) {
+ case int:
+ return x.(int) &^ y.(int)
+ case int8:
+ return x.(int8) &^ y.(int8)
+ case int16:
+ return x.(int16) &^ y.(int16)
+ case int32:
+ return x.(int32) &^ y.(int32)
+ case int64:
+ return x.(int64) &^ y.(int64)
+ case uint:
+ return x.(uint) &^ y.(uint)
+ case uint8:
+ return x.(uint8) &^ y.(uint8)
+ case uint16:
+ return x.(uint16) &^ y.(uint16)
+ case uint32:
+ return x.(uint32) &^ y.(uint32)
+ case uint64:
+ return x.(uint64) &^ y.(uint64)
+ case uintptr:
+ return x.(uintptr) &^ y.(uintptr)
+ }
+
+ case token.SHL:
+ y := asUint64(y)
+ switch x.(type) {
+ case int:
+ return x.(int) << y
+ case int8:
+ return x.(int8) << y
+ case int16:
+ return x.(int16) << y
+ case int32:
+ return x.(int32) << y
+ case int64:
+ return x.(int64) << y
+ case uint:
+ return x.(uint) << y
+ case uint8:
+ return x.(uint8) << y
+ case uint16:
+ return x.(uint16) << y
+ case uint32:
+ return x.(uint32) << y
+ case uint64:
+ return x.(uint64) << y
+ case uintptr:
+ return x.(uintptr) << y
+ }
+
+ case token.SHR:
+ y := asUint64(y)
+ switch x.(type) {
+ case int:
+ return x.(int) >> y
+ case int8:
+ return x.(int8) >> y
+ case int16:
+ return x.(int16) >> y
+ case int32:
+ return x.(int32) >> y
+ case int64:
+ return x.(int64) >> y
+ case uint:
+ return x.(uint) >> y
+ case uint8:
+ return x.(uint8) >> y
+ case uint16:
+ return x.(uint16) >> y
+ case uint32:
+ return x.(uint32) >> y
+ case uint64:
+ return x.(uint64) >> y
+ case uintptr:
+ return x.(uintptr) >> y
+ }
+
+ case token.LSS:
+ switch x.(type) {
+ case int:
+ return x.(int) < y.(int)
+ case int8:
+ return x.(int8) < y.(int8)
+ case int16:
+ return x.(int16) < y.(int16)
+ case int32:
+ return x.(int32) < y.(int32)
+ case int64:
+ return x.(int64) < y.(int64)
+ case uint:
+ return x.(uint) < y.(uint)
+ case uint8:
+ return x.(uint8) < y.(uint8)
+ case uint16:
+ return x.(uint16) < y.(uint16)
+ case uint32:
+ return x.(uint32) < y.(uint32)
+ case uint64:
+ return x.(uint64) < y.(uint64)
+ case uintptr:
+ return x.(uintptr) < y.(uintptr)
+ case float32:
+ return x.(float32) < y.(float32)
+ case float64:
+ return x.(float64) < y.(float64)
+ case string:
+ return x.(string) < y.(string)
+ }
+
+ case token.LEQ:
+ switch x.(type) {
+ case int:
+ return x.(int) <= y.(int)
+ case int8:
+ return x.(int8) <= y.(int8)
+ case int16:
+ return x.(int16) <= y.(int16)
+ case int32:
+ return x.(int32) <= y.(int32)
+ case int64:
+ return x.(int64) <= y.(int64)
+ case uint:
+ return x.(uint) <= y.(uint)
+ case uint8:
+ return x.(uint8) <= y.(uint8)
+ case uint16:
+ return x.(uint16) <= y.(uint16)
+ case uint32:
+ return x.(uint32) <= y.(uint32)
+ case uint64:
+ return x.(uint64) <= y.(uint64)
+ case uintptr:
+ return x.(uintptr) <= y.(uintptr)
+ case float32:
+ return x.(float32) <= y.(float32)
+ case float64:
+ return x.(float64) <= y.(float64)
+ case string:
+ return x.(string) <= y.(string)
+ }
+
+ case token.EQL:
+ return eqnil(t, x, y)
+
+ case token.NEQ:
+ return !eqnil(t, x, y)
+
+ case token.GTR:
+ switch x.(type) {
+ case int:
+ return x.(int) > y.(int)
+ case int8:
+ return x.(int8) > y.(int8)
+ case int16:
+ return x.(int16) > y.(int16)
+ case int32:
+ return x.(int32) > y.(int32)
+ case int64:
+ return x.(int64) > y.(int64)
+ case uint:
+ return x.(uint) > y.(uint)
+ case uint8:
+ return x.(uint8) > y.(uint8)
+ case uint16:
+ return x.(uint16) > y.(uint16)
+ case uint32:
+ return x.(uint32) > y.(uint32)
+ case uint64:
+ return x.(uint64) > y.(uint64)
+ case uintptr:
+ return x.(uintptr) > y.(uintptr)
+ case float32:
+ return x.(float32) > y.(float32)
+ case float64:
+ return x.(float64) > y.(float64)
+ case string:
+ return x.(string) > y.(string)
+ }
+
+ case token.GEQ:
+ switch x.(type) {
+ case int:
+ return x.(int) >= y.(int)
+ case int8:
+ return x.(int8) >= y.(int8)
+ case int16:
+ return x.(int16) >= y.(int16)
+ case int32:
+ return x.(int32) >= y.(int32)
+ case int64:
+ return x.(int64) >= y.(int64)
+ case uint:
+ return x.(uint) >= y.(uint)
+ case uint8:
+ return x.(uint8) >= y.(uint8)
+ case uint16:
+ return x.(uint16) >= y.(uint16)
+ case uint32:
+ return x.(uint32) >= y.(uint32)
+ case uint64:
+ return x.(uint64) >= y.(uint64)
+ case uintptr:
+ return x.(uintptr) >= y.(uintptr)
+ case float32:
+ return x.(float32) >= y.(float32)
+ case float64:
+ return x.(float64) >= y.(float64)
+ case string:
+ return x.(string) >= y.(string)
+ }
+ }
+ panic(fmt.Sprintf("invalid binary op: %T %s %T", x, op, y))
+}
+
+// eqnil returns the comparison x == y using the equivalence relation
+// appropriate for type t.
+// If t is a reference type, at most one of x or y may be a nil value
+// of that type.
+//
+func eqnil(t types.Type, x, y value) bool {
+ switch t.Underlying().(type) {
+ case *types.Map, *types.Signature, *types.Slice:
+ // Since these types don't support comparison,
+ // one of the operands must be a literal nil.
+ switch x := x.(type) {
+ case *hashmap:
+ return (x != nil) == (y.(*hashmap) != nil)
+ case map[value]value:
+ return (x != nil) == (y.(map[value]value) != nil)
+ case *ssa.Function:
+ switch y := y.(type) {
+ case *ssa.Function:
+ return (x != nil) == (y != nil)
+ case *closure:
+ return true
+ }
+ case *closure:
+ return (x != nil) == (y.(*ssa.Function) != nil)
+ case []value:
+ return (x != nil) == (y.([]value) != nil)
+ }
+ panic(fmt.Sprintf("eqnil(%s): illegal dynamic type: %T", t, x))
+ }
+
+ return equals(t, x, y)
+}
+
+func unop(instr *ssa.UnOp, x value) value {
+ switch instr.Op {
+ case token.ARROW: // receive
+ v, ok := <-x.(chan value)
+ if !ok {
+ v = zero(instr.X.Type().Underlying().(*types.Chan).Elem())
+ }
+ if instr.CommaOk {
+ v = tuple{v, ok}
+ }
+ return v
+ case token.SUB:
+ switch x := x.(type) {
+ case int:
+ return -x
+ case int8:
+ return -x
+ case int16:
+ return -x
+ case int32:
+ return -x
+ case int64:
+ return -x
+ case uint:
+ return -x
+ case uint8:
+ return -x
+ case uint16:
+ return -x
+ case uint32:
+ return -x
+ case uint64:
+ return -x
+ case uintptr:
+ return -x
+ case float32:
+ return -x
+ case float64:
+ return -x
+ case complex64:
+ return -x
+ case complex128:
+ return -x
+ }
+ case token.MUL:
+ return load(deref(instr.X.Type()), x.(*value))
+ case token.NOT:
+ return !x.(bool)
+ case token.XOR:
+ switch x := x.(type) {
+ case int:
+ return ^x
+ case int8:
+ return ^x
+ case int16:
+ return ^x
+ case int32:
+ return ^x
+ case int64:
+ return ^x
+ case uint:
+ return ^x
+ case uint8:
+ return ^x
+ case uint16:
+ return ^x
+ case uint32:
+ return ^x
+ case uint64:
+ return ^x
+ case uintptr:
+ return ^x
+ }
+ }
+ panic(fmt.Sprintf("invalid unary op %s %T", instr.Op, x))
+}
+
+// typeAssert checks whether dynamic type of itf is instr.AssertedType.
+// It returns the extracted value on success, and panics on failure,
+// unless instr.CommaOk, in which case it always returns a "value,ok" tuple.
+//
+func typeAssert(i *interpreter, instr *ssa.TypeAssert, itf iface) value {
+ var v value
+ err := ""
+ if itf.t == nil {
+ err = fmt.Sprintf("interface conversion: interface is nil, not %s", instr.AssertedType)
+
+ } else if idst, ok := instr.AssertedType.Underlying().(*types.Interface); ok {
+ v = itf
+ err = checkInterface(i, idst, itf)
+
+ } else if types.Identical(itf.t, instr.AssertedType) {
+ v = itf.v // extract value
+
+ } else {
+ err = fmt.Sprintf("interface conversion: interface is %s, not %s", itf.t, instr.AssertedType)
+ }
+
+ if err != "" {
+ if !instr.CommaOk {
+ panic(err)
+ }
+ return tuple{zero(instr.AssertedType), false}
+ }
+ if instr.CommaOk {
+ return tuple{v, true}
+ }
+ return v
+}
+
+// If CapturedOutput is non-nil, all writes by the interpreted program
+// to file descriptors 1 and 2 will also be written to CapturedOutput.
+//
+// (The $GOROOT/test system requires that the test be considered a
+// failure if "BUG" appears in the combined stdout/stderr output, even
+// if it exits zero. This is a global variable shared by all
+// interpreters in the same process.)
+//
+var CapturedOutput *bytes.Buffer
+var capturedOutputMu sync.Mutex
+
+// write writes bytes b to the target program's file descriptor fd.
+// The print/println built-ins and the write() system call funnel
+// through here so they can be captured by the test driver.
+func write(fd int, b []byte) (int, error) {
+ // TODO(adonovan): fix: on Windows, std{out,err} are not 1, 2.
+ if CapturedOutput != nil && (fd == 1 || fd == 2) {
+ capturedOutputMu.Lock()
+ CapturedOutput.Write(b) // ignore errors
+ capturedOutputMu.Unlock()
+ }
+ return syswrite(fd, b)
+}
+
+// callBuiltin interprets a call to builtin fn with arguments args,
+// returning its result.
+func callBuiltin(caller *frame, callpos token.Pos, fn *ssa.Builtin, args []value) value {
+ switch fn.Name() {
+ case "append":
+ if len(args) == 1 {
+ return args[0]
+ }
+ if s, ok := args[1].(string); ok {
+ // append([]byte, ...string) []byte
+ arg0 := args[0].([]value)
+ for i := 0; i < len(s); i++ {
+ arg0 = append(arg0, s[i])
+ }
+ return arg0
+ }
+ // append([]T, ...[]T) []T
+ return append(args[0].([]value), args[1].([]value)...)
+
+ case "copy": // copy([]T, []T) int or copy([]byte, string) int
+ src := args[1]
+ if _, ok := src.(string); ok {
+ params := fn.Type().(*types.Signature).Params()
+ src = conv(params.At(0).Type(), params.At(1).Type(), src)
+ }
+ return copy(args[0].([]value), src.([]value))
+
+ case "close": // close(chan T)
+ close(args[0].(chan value))
+ return nil
+
+ case "delete": // delete(map[K]value, K)
+ switch m := args[0].(type) {
+ case map[value]value:
+ delete(m, args[1])
+ case *hashmap:
+ m.delete(args[1].(hashable))
+ default:
+ panic(fmt.Sprintf("illegal map type: %T", m))
+ }
+ return nil
+
+ case "print", "println": // print(any, ...)
+ ln := fn.Name() == "println"
+ var buf bytes.Buffer
+ for i, arg := range args {
+ if i > 0 && ln {
+ buf.WriteRune(' ')
+ }
+ buf.WriteString(toString(arg))
+ }
+ if ln {
+ buf.WriteRune('\n')
+ }
+ write(1, buf.Bytes())
+ return nil
+
+ case "len":
+ switch x := args[0].(type) {
+ case string:
+ return len(x)
+ case array:
+ return len(x)
+ case *value:
+ return len((*x).(array))
+ case []value:
+ return len(x)
+ case map[value]value:
+ return len(x)
+ case *hashmap:
+ return x.len()
+ case chan value:
+ return len(x)
+ default:
+ panic(fmt.Sprintf("len: illegal operand: %T", x))
+ }
+
+ case "cap":
+ switch x := args[0].(type) {
+ case array:
+ return cap(x)
+ case *value:
+ return cap((*x).(array))
+ case []value:
+ return cap(x)
+ case chan value:
+ return cap(x)
+ default:
+ panic(fmt.Sprintf("cap: illegal operand: %T", x))
+ }
+
+ case "real":
+ switch c := args[0].(type) {
+ case complex64:
+ return real(c)
+ case complex128:
+ return real(c)
+ default:
+ panic(fmt.Sprintf("real: illegal operand: %T", c))
+ }
+
+ case "imag":
+ switch c := args[0].(type) {
+ case complex64:
+ return imag(c)
+ case complex128:
+ return imag(c)
+ default:
+ panic(fmt.Sprintf("imag: illegal operand: %T", c))
+ }
+
+ case "complex":
+ switch f := args[0].(type) {
+ case float32:
+ return complex(f, args[1].(float32))
+ case float64:
+ return complex(f, args[1].(float64))
+ default:
+ panic(fmt.Sprintf("complex: illegal operand: %T", f))
+ }
+
+ case "panic":
+ // ssa.Panic handles most cases; this is only for "go
+ // panic" or "defer panic".
+ panic(targetPanic{args[0]})
+
+ case "recover":
+ return doRecover(caller)
+
+ case "ssa:wrapnilchk":
+ recv := args[0]
+ if recv.(*value) == nil {
+ recvType := args[1]
+ methodName := args[2]
+ panic(fmt.Sprintf("value method (%s).%s called using nil *%s pointer",
+ recvType, methodName, recvType))
+ }
+ return recv
+ }
+
+ panic("unknown built-in: " + fn.Name())
+}
+
+func rangeIter(x value, t types.Type) iter {
+ switch x := x.(type) {
+ case map[value]value:
+ // TODO(adonovan): fix: leaks goroutines and channels
+ // on each incomplete map iteration. We need to open
+ // up an iteration interface using the
+ // reflect.(Value).MapKeys machinery.
+ it := make(mapIter)
+ go func() {
+ for k, v := range x {
+ it <- [2]value{k, v}
+ }
+ close(it)
+ }()
+ return it
+ case *hashmap:
+ // TODO(adonovan): fix: leaks goroutines and channels
+ // on each incomplete map iteration. We need to open
+ // up an iteration interface using the
+ // reflect.(Value).MapKeys machinery.
+ it := make(mapIter)
+ go func() {
+ for _, e := range x.table {
+ for e != nil {
+ it <- [2]value{e.key, e.value}
+ e = e.next
+ }
+ }
+ close(it)
+ }()
+ return it
+ case string:
+ return &stringIter{Reader: strings.NewReader(x)}
+ }
+ panic(fmt.Sprintf("cannot range over %T", x))
+}
+
+// widen widens a basic typed value x to the widest type of its
+// category, one of:
+// bool, int64, uint64, float64, complex128, string.
+// This is inefficient but reduces the size of the cross-product of
+// cases we have to consider.
+//
+func widen(x value) value {
+ switch y := x.(type) {
+ case bool, int64, uint64, float64, complex128, string, unsafe.Pointer:
+ return x
+ case int:
+ return int64(y)
+ case int8:
+ return int64(y)
+ case int16:
+ return int64(y)
+ case int32:
+ return int64(y)
+ case uint:
+ return uint64(y)
+ case uint8:
+ return uint64(y)
+ case uint16:
+ return uint64(y)
+ case uint32:
+ return uint64(y)
+ case uintptr:
+ return uint64(y)
+ case float32:
+ return float64(y)
+ case complex64:
+ return complex128(y)
+ }
+ panic(fmt.Sprintf("cannot widen %T", x))
+}
+
+// conv converts the value x of type t_src to type t_dst and returns
+// the result.
+// Possible cases are described with the ssa.Convert operator.
+//
+func conv(t_dst, t_src types.Type, x value) value {
+ ut_src := t_src.Underlying()
+ ut_dst := t_dst.Underlying()
+
+ // Destination type is not an "untyped" type.
+ if b, ok := ut_dst.(*types.Basic); ok && b.Info()&types.IsUntyped != 0 {
+ panic("oops: conversion to 'untyped' type: " + b.String())
+ }
+
+ // Nor is it an interface type.
+ if _, ok := ut_dst.(*types.Interface); ok {
+ if _, ok := ut_src.(*types.Interface); ok {
+ panic("oops: Convert should be ChangeInterface")
+ } else {
+ panic("oops: Convert should be MakeInterface")
+ }
+ }
+
+ // Remaining conversions:
+ // + untyped string/number/bool constant to a specific
+ // representation.
+ // + conversions between non-complex numeric types.
+ // + conversions between complex numeric types.
+ // + integer/[]byte/[]rune -> string.
+ // + string -> []byte/[]rune.
+ //
+ // All are treated the same: first we extract the value to the
+ // widest representation (int64, uint64, float64, complex128,
+ // or string), then we convert it to the desired type.
+
+ switch ut_src := ut_src.(type) {
+ case *types.Pointer:
+ switch ut_dst := ut_dst.(type) {
+ case *types.Basic:
+ // *value to unsafe.Pointer?
+ if ut_dst.Kind() == types.UnsafePointer {
+ return unsafe.Pointer(x.(*value))
+ }
+ }
+
+ case *types.Slice:
+ // []byte or []rune -> string
+ // TODO(adonovan): fix: type B byte; conv([]B -> string).
+ switch ut_src.Elem().(*types.Basic).Kind() {
+ case types.Byte:
+ x := x.([]value)
+ b := make([]byte, 0, len(x))
+ for i := range x {
+ b = append(b, x[i].(byte))
+ }
+ return string(b)
+
+ case types.Rune:
+ x := x.([]value)
+ r := make([]rune, 0, len(x))
+ for i := range x {
+ r = append(r, x[i].(rune))
+ }
+ return string(r)
+ }
+
+ case *types.Basic:
+ x = widen(x)
+
+ // integer -> string?
+ // TODO(adonovan): fix: test integer -> named alias of string.
+ if ut_src.Info()&types.IsInteger != 0 {
+ if ut_dst, ok := ut_dst.(*types.Basic); ok && ut_dst.Kind() == types.String {
+ return string(asInt(x))
+ }
+ }
+
+ // string -> []rune, []byte or string?
+ if s, ok := x.(string); ok {
+ switch ut_dst := ut_dst.(type) {
+ case *types.Slice:
+ var res []value
+ // TODO(adonovan): fix: test named alias of rune, byte.
+ switch ut_dst.Elem().(*types.Basic).Kind() {
+ case types.Rune:
+ for _, r := range []rune(s) {
+ res = append(res, r)
+ }
+ return res
+ case types.Byte:
+ for _, b := range []byte(s) {
+ res = append(res, b)
+ }
+ return res
+ }
+ case *types.Basic:
+ if ut_dst.Kind() == types.String {
+ return x.(string)
+ }
+ }
+ break // fail: no other conversions for string
+ }
+
+ // unsafe.Pointer -> *value
+ if ut_src.Kind() == types.UnsafePointer {
+ // TODO(adonovan): this is wrong and cannot
+ // really be fixed with the current design.
+ //
+ // return (*value)(x.(unsafe.Pointer))
+ // creates a new pointer of a different
+ // type but the underlying interface value
+ // knows its "true" type and so cannot be
+ // meaningfully used through the new pointer.
+ //
+ // To make this work, the interpreter needs to
+ // simulate the memory layout of a real
+ // compiled implementation.
+ //
+ // To at least preserve type-safety, we'll
+ // just return the zero value of the
+ // destination type.
+ return zero(t_dst)
+ }
+
+ // Conversions between complex numeric types?
+ if ut_src.Info()&types.IsComplex != 0 {
+ switch ut_dst.(*types.Basic).Kind() {
+ case types.Complex64:
+ return complex64(x.(complex128))
+ case types.Complex128:
+ return x.(complex128)
+ }
+ break // fail: no other conversions for complex
+ }
+
+ // Conversions between non-complex numeric types?
+ if ut_src.Info()&types.IsNumeric != 0 {
+ kind := ut_dst.(*types.Basic).Kind()
+ switch x := x.(type) {
+ case int64: // signed integer -> numeric?
+ switch kind {
+ case types.Int:
+ return int(x)
+ case types.Int8:
+ return int8(x)
+ case types.Int16:
+ return int16(x)
+ case types.Int32:
+ return int32(x)
+ case types.Int64:
+ return int64(x)
+ case types.Uint:
+ return uint(x)
+ case types.Uint8:
+ return uint8(x)
+ case types.Uint16:
+ return uint16(x)
+ case types.Uint32:
+ return uint32(x)
+ case types.Uint64:
+ return uint64(x)
+ case types.Uintptr:
+ return uintptr(x)
+ case types.Float32:
+ return float32(x)
+ case types.Float64:
+ return float64(x)
+ }
+
+ case uint64: // unsigned integer -> numeric?
+ switch kind {
+ case types.Int:
+ return int(x)
+ case types.Int8:
+ return int8(x)
+ case types.Int16:
+ return int16(x)
+ case types.Int32:
+ return int32(x)
+ case types.Int64:
+ return int64(x)
+ case types.Uint:
+ return uint(x)
+ case types.Uint8:
+ return uint8(x)
+ case types.Uint16:
+ return uint16(x)
+ case types.Uint32:
+ return uint32(x)
+ case types.Uint64:
+ return uint64(x)
+ case types.Uintptr:
+ return uintptr(x)
+ case types.Float32:
+ return float32(x)
+ case types.Float64:
+ return float64(x)
+ }
+
+ case float64: // floating point -> numeric?
+ switch kind {
+ case types.Int:
+ return int(x)
+ case types.Int8:
+ return int8(x)
+ case types.Int16:
+ return int16(x)
+ case types.Int32:
+ return int32(x)
+ case types.Int64:
+ return int64(x)
+ case types.Uint:
+ return uint(x)
+ case types.Uint8:
+ return uint8(x)
+ case types.Uint16:
+ return uint16(x)
+ case types.Uint32:
+ return uint32(x)
+ case types.Uint64:
+ return uint64(x)
+ case types.Uintptr:
+ return uintptr(x)
+ case types.Float32:
+ return float32(x)
+ case types.Float64:
+ return float64(x)
+ }
+ }
+ }
+ }
+
+ panic(fmt.Sprintf("unsupported conversion: %s -> %s, dynamic type %T", t_src, t_dst, x))
+}
+
+// checkInterface checks that the method set of x implements the
+// interface itype.
+// On success it returns "", on failure, an error message.
+//
+func checkInterface(i *interpreter, itype *types.Interface, x iface) string {
+ if meth, _ := types.MissingMethod(x.t, itype, true); meth != nil {
+ return fmt.Sprintf("interface conversion: %v is not %v: missing method %s",
+ x.t, itype, meth.Name())
+ }
+ return "" // ok
+}
diff --git a/go/ssa/interp/reflect.go b/go/ssa/interp/reflect.go
new file mode 100644
index 0000000..468771b
--- /dev/null
+++ b/go/ssa/interp/reflect.go
@@ -0,0 +1,574 @@
+// 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 interp
+
+// Emulated "reflect" package.
+//
+// We completely replace the built-in "reflect" package.
+// The only thing clients can depend upon are that reflect.Type is an
+// interface and reflect.Value is an (opaque) struct.
+
+import (
+ "fmt"
+ "go/token"
+ "reflect"
+ "unsafe"
+
+ "golang.org/x/tools/go/ssa"
+ "golang.org/x/tools/go/types"
+)
+
+type opaqueType struct {
+ types.Type
+ name string
+}
+
+func (t *opaqueType) String() string { return t.name }
+
+// A bogus "reflect" type-checker package. Shared across interpreters.
+var reflectTypesPackage = types.NewPackage("reflect", "reflect")
+
+// rtype is the concrete type the interpreter uses to implement the
+// reflect.Type interface.
+//
+// type rtype <opaque>
+var rtypeType = makeNamedType("rtype", &opaqueType{nil, "rtype"})
+
+// error is an (interpreted) named type whose underlying type is string.
+// The interpreter uses it for all implementations of the built-in error
+// interface that it creates.
+// We put it in the "reflect" package for expedience.
+//
+// type error string
+var errorType = makeNamedType("error", &opaqueType{nil, "error"})
+
+func makeNamedType(name string, underlying types.Type) *types.Named {
+ obj := types.NewTypeName(token.NoPos, reflectTypesPackage, name, nil)
+ return types.NewNamed(obj, underlying, nil)
+}
+
+func makeReflectValue(t types.Type, v value) value {
+ return structure{rtype{t}, v}
+}
+
+// Given a reflect.Value, returns its rtype.
+func rV2T(v value) rtype {
+ return v.(structure)[0].(rtype)
+}
+
+// Given a reflect.Value, returns the underlying interpreter value.
+func rV2V(v value) value {
+ return v.(structure)[1]
+}
+
+// makeReflectType boxes up an rtype in a reflect.Type interface.
+func makeReflectType(rt rtype) value {
+ return iface{rtypeType, rt}
+}
+
+func ext۰reflect۰Init(fr *frame, args []value) value {
+ // Signature: func()
+ return nil
+}
+
+func ext۰reflect۰rtype۰Bits(fr *frame, args []value) value {
+ // Signature: func (t reflect.rtype) int
+ rt := args[0].(rtype).t
+ basic, ok := rt.Underlying().(*types.Basic)
+ if !ok {
+ panic(fmt.Sprintf("reflect.Type.Bits(%T): non-basic type", rt))
+ }
+ return int(fr.i.sizes.Sizeof(basic)) * 8
+}
+
+func ext۰reflect۰rtype۰Elem(fr *frame, args []value) value {
+ // Signature: func (t reflect.rtype) reflect.Type
+ return makeReflectType(rtype{args[0].(rtype).t.Underlying().(interface {
+ Elem() types.Type
+ }).Elem()})
+}
+
+func ext۰reflect۰rtype۰Field(fr *frame, args []value) value {
+ // Signature: func (t reflect.rtype, i int) reflect.StructField
+ st := args[0].(rtype).t.Underlying().(*types.Struct)
+ i := args[1].(int)
+ f := st.Field(i)
+ return structure{
+ f.Name(),
+ f.Pkg().Path(),
+ makeReflectType(rtype{f.Type()}),
+ st.Tag(i),
+ 0, // TODO(adonovan): offset
+ []value{}, // TODO(adonovan): indices
+ f.Anonymous(),
+ }
+}
+
+func ext۰reflect۰rtype۰In(fr *frame, args []value) value {
+ // Signature: func (t reflect.rtype, i int) int
+ i := args[1].(int)
+ return makeReflectType(rtype{args[0].(rtype).t.(*types.Signature).Params().At(i).Type()})
+}
+
+func ext۰reflect۰rtype۰Kind(fr *frame, args []value) value {
+ // Signature: func (t reflect.rtype) uint
+ return uint(reflectKind(args[0].(rtype).t))
+}
+
+func ext۰reflect۰rtype۰NumField(fr *frame, args []value) value {
+ // Signature: func (t reflect.rtype) int
+ return args[0].(rtype).t.Underlying().(*types.Struct).NumFields()
+}
+
+func ext۰reflect۰rtype۰NumIn(fr *frame, args []value) value {
+ // Signature: func (t reflect.rtype) int
+ return args[0].(rtype).t.(*types.Signature).Params().Len()
+}
+
+func ext۰reflect۰rtype۰NumMethod(fr *frame, args []value) value {
+ // Signature: func (t reflect.rtype) int
+ return fr.i.prog.MethodSets.MethodSet(args[0].(rtype).t).Len()
+}
+
+func ext۰reflect۰rtype۰NumOut(fr *frame, args []value) value {
+ // Signature: func (t reflect.rtype) int
+ return args[0].(rtype).t.(*types.Signature).Results().Len()
+}
+
+func ext۰reflect۰rtype۰Out(fr *frame, args []value) value {
+ // Signature: func (t reflect.rtype, i int) int
+ i := args[1].(int)
+ return makeReflectType(rtype{args[0].(rtype).t.(*types.Signature).Results().At(i).Type()})
+}
+
+func ext۰reflect۰rtype۰Size(fr *frame, args []value) value {
+ // Signature: func (t reflect.rtype) uintptr
+ return uintptr(fr.i.sizes.Sizeof(args[0].(rtype).t))
+}
+
+func ext۰reflect۰rtype۰String(fr *frame, args []value) value {
+ // Signature: func (t reflect.rtype) string
+ return args[0].(rtype).t.String()
+}
+
+func ext۰reflect۰New(fr *frame, args []value) value {
+ // Signature: func (t reflect.Type) reflect.Value
+ t := args[0].(iface).v.(rtype).t
+ alloc := zero(t)
+ return makeReflectValue(types.NewPointer(t), &alloc)
+}
+
+func ext۰reflect۰SliceOf(fr *frame, args []value) value {
+ // Signature: func (t reflect.rtype) Type
+ return makeReflectType(rtype{types.NewSlice(args[0].(iface).v.(rtype).t)})
+}
+
+func ext۰reflect۰TypeOf(fr *frame, args []value) value {
+ // Signature: func (t reflect.rtype) Type
+ return makeReflectType(rtype{args[0].(iface).t})
+}
+
+func ext۰reflect۰ValueOf(fr *frame, args []value) value {
+ // Signature: func (interface{}) reflect.Value
+ itf := args[0].(iface)
+ return makeReflectValue(itf.t, itf.v)
+}
+
+func ext۰reflect۰Zero(fr *frame, args []value) value {
+ // Signature: func (t reflect.Type) reflect.Value
+ t := args[0].(iface).v.(rtype).t
+ return makeReflectValue(t, zero(t))
+}
+
+func reflectKind(t types.Type) reflect.Kind {
+ switch t := t.(type) {
+ case *types.Named:
+ return reflectKind(t.Underlying())
+ case *types.Basic:
+ switch t.Kind() {
+ case types.Bool:
+ return reflect.Bool
+ case types.Int:
+ return reflect.Int
+ case types.Int8:
+ return reflect.Int8
+ case types.Int16:
+ return reflect.Int16
+ case types.Int32:
+ return reflect.Int32
+ case types.Int64:
+ return reflect.Int64
+ case types.Uint:
+ return reflect.Uint
+ case types.Uint8:
+ return reflect.Uint8
+ case types.Uint16:
+ return reflect.Uint16
+ case types.Uint32:
+ return reflect.Uint32
+ case types.Uint64:
+ return reflect.Uint64
+ case types.Uintptr:
+ return reflect.Uintptr
+ case types.Float32:
+ return reflect.Float32
+ case types.Float64:
+ return reflect.Float64
+ case types.Complex64:
+ return reflect.Complex64
+ case types.Complex128:
+ return reflect.Complex128
+ case types.String:
+ return reflect.String
+ case types.UnsafePointer:
+ return reflect.UnsafePointer
+ }
+ case *types.Array:
+ return reflect.Array
+ case *types.Chan:
+ return reflect.Chan
+ case *types.Signature:
+ return reflect.Func
+ case *types.Interface:
+ return reflect.Interface
+ case *types.Map:
+ return reflect.Map
+ case *types.Pointer:
+ return reflect.Ptr
+ case *types.Slice:
+ return reflect.Slice
+ case *types.Struct:
+ return reflect.Struct
+ }
+ panic(fmt.Sprint("unexpected type: ", t))
+}
+
+func ext۰reflect۰Value۰Kind(fr *frame, args []value) value {
+ // Signature: func (reflect.Value) uint
+ return uint(reflectKind(rV2T(args[0]).t))
+}
+
+func ext۰reflect۰Value۰String(fr *frame, args []value) value {
+ // Signature: func (reflect.Value) string
+ return toString(rV2V(args[0]))
+}
+
+func ext۰reflect۰Value۰Type(fr *frame, args []value) value {
+ // Signature: func (reflect.Value) reflect.Type
+ return makeReflectType(rV2T(args[0]))
+}
+
+func ext۰reflect۰Value۰Uint(fr *frame, args []value) value {
+ // Signature: func (reflect.Value) uint64
+ switch v := rV2V(args[0]).(type) {
+ case uint:
+ return uint64(v)
+ case uint8:
+ return uint64(v)
+ case uint16:
+ return uint64(v)
+ case uint32:
+ return uint64(v)
+ case uint64:
+ return uint64(v)
+ case uintptr:
+ return uint64(v)
+ }
+ panic("reflect.Value.Uint")
+}
+
+func ext۰reflect۰Value۰Len(fr *frame, args []value) value {
+ // Signature: func (reflect.Value) int
+ switch v := rV2V(args[0]).(type) {
+ case string:
+ return len(v)
+ case array:
+ return len(v)
+ case chan value:
+ return cap(v)
+ case []value:
+ return len(v)
+ case *hashmap:
+ return v.len()
+ case map[value]value:
+ return len(v)
+ default:
+ panic(fmt.Sprintf("reflect.(Value).Len(%v)", v))
+ }
+}
+
+func ext۰reflect۰Value۰MapIndex(fr *frame, args []value) value {
+ // Signature: func (reflect.Value) Value
+ tValue := rV2T(args[0]).t.Underlying().(*types.Map).Key()
+ k := rV2V(args[1])
+ switch m := rV2V(args[0]).(type) {
+ case map[value]value:
+ if v, ok := m[k]; ok {
+ return makeReflectValue(tValue, v)
+ }
+
+ case *hashmap:
+ if v := m.lookup(k.(hashable)); v != nil {
+ return makeReflectValue(tValue, v)
+ }
+
+ default:
+ panic(fmt.Sprintf("(reflect.Value).MapIndex(%T, %T)", m, k))
+ }
+ return makeReflectValue(nil, nil)
+}
+
+func ext۰reflect۰Value۰MapKeys(fr *frame, args []value) value {
+ // Signature: func (reflect.Value) []Value
+ var keys []value
+ tKey := rV2T(args[0]).t.Underlying().(*types.Map).Key()
+ switch v := rV2V(args[0]).(type) {
+ case map[value]value:
+ for k := range v {
+ keys = append(keys, makeReflectValue(tKey, k))
+ }
+
+ case *hashmap:
+ for _, e := range v.table {
+ for ; e != nil; e = e.next {
+ keys = append(keys, makeReflectValue(tKey, e.key))
+ }
+ }
+
+ default:
+ panic(fmt.Sprintf("(reflect.Value).MapKeys(%T)", v))
+ }
+ return keys
+}
+
+func ext۰reflect۰Value۰NumField(fr *frame, args []value) value {
+ // Signature: func (reflect.Value) int
+ return len(rV2V(args[0]).(structure))
+}
+
+func ext۰reflect۰Value۰NumMethod(fr *frame, args []value) value {
+ // Signature: func (reflect.Value) int
+ return fr.i.prog.MethodSets.MethodSet(rV2T(args[0]).t).Len()
+}
+
+func ext۰reflect۰Value۰Pointer(fr *frame, args []value) value {
+ // Signature: func (v reflect.Value) uintptr
+ switch v := rV2V(args[0]).(type) {
+ case *value:
+ return uintptr(unsafe.Pointer(v))
+ case chan value:
+ return reflect.ValueOf(v).Pointer()
+ case []value:
+ return reflect.ValueOf(v).Pointer()
+ case *hashmap:
+ return reflect.ValueOf(v.table).Pointer()
+ case map[value]value:
+ return reflect.ValueOf(v).Pointer()
+ case *ssa.Function:
+ return uintptr(unsafe.Pointer(v))
+ case *closure:
+ return uintptr(unsafe.Pointer(v))
+ default:
+ panic(fmt.Sprintf("reflect.(Value).Pointer(%T)", v))
+ }
+}
+
+func ext۰reflect۰Value۰Index(fr *frame, args []value) value {
+ // Signature: func (v reflect.Value, i int) Value
+ i := args[1].(int)
+ t := rV2T(args[0]).t.Underlying()
+ switch v := rV2V(args[0]).(type) {
+ case array:
+ return makeReflectValue(t.(*types.Array).Elem(), v[i])
+ case []value:
+ return makeReflectValue(t.(*types.Slice).Elem(), v[i])
+ default:
+ panic(fmt.Sprintf("reflect.(Value).Index(%T)", v))
+ }
+}
+
+func ext۰reflect۰Value۰Bool(fr *frame, args []value) value {
+ // Signature: func (reflect.Value) bool
+ return rV2V(args[0]).(bool)
+}
+
+func ext۰reflect۰Value۰CanAddr(fr *frame, args []value) value {
+ // Signature: func (v reflect.Value) bool
+ // Always false for our representation.
+ return false
+}
+
+func ext۰reflect۰Value۰CanInterface(fr *frame, args []value) value {
+ // Signature: func (v reflect.Value) bool
+ // Always true for our representation.
+ return true
+}
+
+func ext۰reflect۰Value۰Elem(fr *frame, args []value) value {
+ // Signature: func (v reflect.Value) reflect.Value
+ switch x := rV2V(args[0]).(type) {
+ case iface:
+ return makeReflectValue(x.t, x.v)
+ case *value:
+ return makeReflectValue(rV2T(args[0]).t.Underlying().(*types.Pointer).Elem(), *x)
+ default:
+ panic(fmt.Sprintf("reflect.(Value).Elem(%T)", x))
+ }
+}
+
+func ext۰reflect۰Value۰Field(fr *frame, args []value) value {
+ // Signature: func (v reflect.Value, i int) reflect.Value
+ v := args[0]
+ i := args[1].(int)
+ return makeReflectValue(rV2T(v).t.Underlying().(*types.Struct).Field(i).Type(), rV2V(v).(structure)[i])
+}
+
+func ext۰reflect۰Value۰Float(fr *frame, args []value) value {
+ // Signature: func (reflect.Value) float64
+ switch v := rV2V(args[0]).(type) {
+ case float32:
+ return float64(v)
+ case float64:
+ return float64(v)
+ }
+ panic("reflect.Value.Float")
+}
+
+func ext۰reflect۰Value۰Interface(fr *frame, args []value) value {
+ // Signature: func (v reflect.Value) interface{}
+ return ext۰reflect۰valueInterface(fr, args)
+}
+
+func ext۰reflect۰Value۰Int(fr *frame, args []value) value {
+ // Signature: func (reflect.Value) int64
+ switch x := rV2V(args[0]).(type) {
+ case int:
+ return int64(x)
+ case int8:
+ return int64(x)
+ case int16:
+ return int64(x)
+ case int32:
+ return int64(x)
+ case int64:
+ return x
+ default:
+ panic(fmt.Sprintf("reflect.(Value).Int(%T)", x))
+ }
+}
+
+func ext۰reflect۰Value۰IsNil(fr *frame, args []value) value {
+ // Signature: func (reflect.Value) bool
+ switch x := rV2V(args[0]).(type) {
+ case *value:
+ return x == nil
+ case chan value:
+ return x == nil
+ case map[value]value:
+ return x == nil
+ case *hashmap:
+ return x == nil
+ case iface:
+ return x.t == nil
+ case []value:
+ return x == nil
+ case *ssa.Function:
+ return x == nil
+ case *ssa.Builtin:
+ return x == nil
+ case *closure:
+ return x == nil
+ default:
+ panic(fmt.Sprintf("reflect.(Value).IsNil(%T)", x))
+ }
+}
+
+func ext۰reflect۰Value۰IsValid(fr *frame, args []value) value {
+ // Signature: func (reflect.Value) bool
+ return rV2V(args[0]) != nil
+}
+
+func ext۰reflect۰Value۰Set(fr *frame, args []value) value {
+ // TODO(adonovan): implement.
+ return nil
+}
+
+func ext۰reflect۰valueInterface(fr *frame, args []value) value {
+ // Signature: func (v reflect.Value, safe bool) interface{}
+ v := args[0].(structure)
+ return iface{rV2T(v).t, rV2V(v)}
+}
+
+func ext۰reflect۰error۰Error(fr *frame, args []value) value {
+ return args[0]
+}
+
+// newMethod creates a new method of the specified name, package and receiver type.
+func newMethod(pkg *ssa.Package, recvType types.Type, name string) *ssa.Function {
+ // TODO(adonovan): fix: hack: currently the only part of Signature
+ // that is needed is the "pointerness" of Recv.Type, and for
+ // now, we'll set it to always be false since we're only
+ // concerned with rtype. Encapsulate this better.
+ sig := types.NewSignature(types.NewVar(token.NoPos, nil, "recv", recvType), nil, nil, false)
+ fn := pkg.Prog.NewFunction(name, sig, "fake reflect method")
+ fn.Pkg = pkg
+ return fn
+}
+
+func initReflect(i *interpreter) {
+ i.reflectPackage = &ssa.Package{
+ Prog: i.prog,
+ Object: reflectTypesPackage,
+ Members: make(map[string]ssa.Member),
+ }
+
+ // Clobber the type-checker's notion of reflect.Value's
+ // underlying type so that it more closely matches the fake one
+ // (at least in the number of fields---we lie about the type of
+ // the rtype field).
+ //
+ // We must ensure that calls to (ssa.Value).Type() return the
+ // fake type so that correct "shape" is used when allocating
+ // variables, making zero values, loading, and storing.
+ //
+ // TODO(adonovan): obviously this is a hack. We need a cleaner
+ // way to fake the reflect package (almost---DeepEqual is fine).
+ // One approach would be not to even load its source code, but
+ // provide fake source files. This would guarantee that no bad
+ // information leaks into other packages.
+ if r := i.prog.ImportedPackage("reflect"); r != nil {
+ rV := r.Object.Scope().Lookup("Value").Type().(*types.Named)
+
+ // delete bodies of the old methods
+ mset := i.prog.MethodSets.MethodSet(rV)
+ for j := 0; j < mset.Len(); j++ {
+ i.prog.Method(mset.At(j)).Blocks = nil
+ }
+
+ tEface := types.NewInterface(nil, nil).Complete()
+ rV.SetUnderlying(types.NewStruct([]*types.Var{
+ types.NewField(token.NoPos, r.Object, "t", tEface, false), // a lie
+ types.NewField(token.NoPos, r.Object, "v", tEface, false),
+ }, nil))
+ }
+
+ i.rtypeMethods = methodSet{
+ "Bits": newMethod(i.reflectPackage, rtypeType, "Bits"),
+ "Elem": newMethod(i.reflectPackage, rtypeType, "Elem"),
+ "Field": newMethod(i.reflectPackage, rtypeType, "Field"),
+ "In": newMethod(i.reflectPackage, rtypeType, "In"),
+ "Kind": newMethod(i.reflectPackage, rtypeType, "Kind"),
+ "NumField": newMethod(i.reflectPackage, rtypeType, "NumField"),
+ "NumIn": newMethod(i.reflectPackage, rtypeType, "NumIn"),
+ "NumMethod": newMethod(i.reflectPackage, rtypeType, "NumMethod"),
+ "NumOut": newMethod(i.reflectPackage, rtypeType, "NumOut"),
+ "Out": newMethod(i.reflectPackage, rtypeType, "Out"),
+ "Size": newMethod(i.reflectPackage, rtypeType, "Size"),
+ "String": newMethod(i.reflectPackage, rtypeType, "String"),
+ }
+ i.errorMethods = methodSet{
+ "Error": newMethod(i.reflectPackage, errorType, "Error"),
+ }
+}
diff --git a/go/ssa/interp/testdata/a_test.go b/go/ssa/interp/testdata/a_test.go
new file mode 100644
index 0000000..844ec5c
--- /dev/null
+++ b/go/ssa/interp/testdata/a_test.go
@@ -0,0 +1,17 @@
+package a
+
+import "testing"
+
+func TestFoo(t *testing.T) {
+ t.Error("foo")
+}
+
+func TestBar(t *testing.T) {
+ t.Error("bar")
+}
+
+func BenchmarkWiz(b *testing.B) {
+ b.Error("wiz")
+}
+
+// Don't test Examples since that testing package needs pipe(2) for that.
diff --git a/go/ssa/interp/testdata/b_test.go b/go/ssa/interp/testdata/b_test.go
new file mode 100644
index 0000000..4a30e96
--- /dev/null
+++ b/go/ssa/interp/testdata/b_test.go
@@ -0,0 +1,11 @@
+package b
+
+import "testing"
+
+func NotATest(t *testing.T) {
+ t.Error("foo")
+}
+
+func NotABenchmark(b *testing.B) {
+ b.Error("wiz")
+}
diff --git a/go/ssa/interp/testdata/boundmeth.go b/go/ssa/interp/testdata/boundmeth.go
new file mode 100644
index 0000000..255cc60
--- /dev/null
+++ b/go/ssa/interp/testdata/boundmeth.go
@@ -0,0 +1,144 @@
+// Tests of bound method closures.
+
+package main
+
+import "fmt"
+
+func assert(b bool) {
+ if !b {
+ panic("oops")
+ }
+}
+
+type I int
+
+func (i I) add(x int) int {
+ return int(i) + x
+}
+
+func valueReceiver() {
+ var three I = 3
+ assert(three.add(5) == 8)
+ var add3 func(int) int = three.add
+ assert(add3(5) == 8)
+}
+
+type S struct{ x int }
+
+func (s *S) incr() {
+ s.x++
+}
+
+func (s *S) get() int {
+ return s.x
+}
+
+func pointerReceiver() {
+ ps := new(S)
+ incr := ps.incr
+ get := ps.get
+ assert(get() == 0)
+ incr()
+ incr()
+ incr()
+ assert(get() == 3)
+}
+
+func addressibleValuePointerReceiver() {
+ var s S
+ incr := s.incr
+ get := s.get
+ assert(get() == 0)
+ incr()
+ incr()
+ incr()
+ assert(get() == 3)
+}
+
+type S2 struct {
+ S
+}
+
+func promotedReceiver() {
+ var s2 S2
+ incr := s2.incr
+ get := s2.get
+ assert(get() == 0)
+ incr()
+ incr()
+ incr()
+ assert(get() == 3)
+}
+
+func anonStruct() {
+ var s struct{ S }
+ incr := s.incr
+ get := s.get
+ assert(get() == 0)
+ incr()
+ incr()
+ incr()
+ assert(get() == 3)
+}
+
+func typeCheck() {
+ var i interface{}
+ i = (*S).incr
+ _ = i.(func(*S)) // type assertion: receiver type prepended to params
+
+ var s S
+ i = s.incr
+ _ = i.(func()) // type assertion: receiver type disappears
+}
+
+type errString string
+
+func (err errString) Error() string {
+ return string(err)
+}
+
+// Regression test for a builder crash.
+func regress1(x error) func() string {
+ return x.Error
+}
+
+// Regression test for b/7269:
+// taking the value of an interface method performs a nil check.
+func nilInterfaceMethodValue() {
+ err := fmt.Errorf("ok")
+ f := err.Error
+ if got := f(); got != "ok" {
+ panic(got)
+ }
+
+ err = nil
+ if got := f(); got != "ok" {
+ panic(got)
+ }
+
+ defer func() {
+ r := fmt.Sprint(recover())
+ // runtime panic string varies across toolchains
+ if r != "runtime error: interface conversion: interface is nil, not error" &&
+ r != "runtime error: invalid memory address or nil pointer dereference" {
+ panic("want runtime panic from nil interface method value, got " + r)
+ }
+ }()
+ f = err.Error // runtime panic: err is nil
+ panic("unreachable")
+}
+
+func main() {
+ valueReceiver()
+ pointerReceiver()
+ addressibleValuePointerReceiver()
+ promotedReceiver()
+ anonStruct()
+ typeCheck()
+
+ if e := regress1(errString("hi"))(); e != "hi" {
+ panic(e)
+ }
+
+ nilInterfaceMethodValue()
+}
diff --git a/go/ssa/interp/testdata/callstack.go b/go/ssa/interp/testdata/callstack.go
new file mode 100644
index 0000000..56f3b28
--- /dev/null
+++ b/go/ssa/interp/testdata/callstack.go
@@ -0,0 +1,52 @@
+package main
+
+import (
+ "fmt"
+ "path"
+ "runtime"
+ "strings"
+)
+
+var stack string
+
+func f() {
+ pc := make([]uintptr, 6)
+ pc = pc[:runtime.Callers(1, pc)]
+ for _, f := range pc {
+ Func := runtime.FuncForPC(f)
+ name := Func.Name()
+ if strings.Contains(name, "$") || strings.Contains(name, ".func") {
+ name = "func" // anon funcs vary across toolchains
+ }
+ file, line := Func.FileLine(0)
+ stack += fmt.Sprintf("%s at %s:%d\n", name, path.Base(file), line)
+ }
+}
+
+func g() { f() }
+func h() { g() }
+func i() { func() { h() }() }
+
+// Hack: the 'func' and the call to Caller are on the same line,
+// to paper over differences between toolchains.
+// (The interpreter's location info isn't yet complete.)
+func runtimeCaller0() (uintptr, string, int, bool) { return runtime.Caller(0) }
+
+func main() {
+ i()
+ if stack != `main.f at callstack.go:12
+main.g at callstack.go:26
+main.h at callstack.go:27
+func at callstack.go:28
+main.i at callstack.go:28
+main.main at callstack.go:35
+` {
+ panic("unexpected stack: " + stack)
+ }
+
+ pc, file, line, _ := runtimeCaller0()
+ got := fmt.Sprintf("%s @ %s:%d", runtime.FuncForPC(pc).Name(), path.Base(file), line)
+ if got != "main.runtimeCaller0 @ callstack.go:33" {
+ panic("runtime.Caller: " + got)
+ }
+}
diff --git a/go/ssa/interp/testdata/complit.go b/go/ssa/interp/testdata/complit.go
new file mode 100644
index 0000000..02f9916
--- /dev/null
+++ b/go/ssa/interp/testdata/complit.go
@@ -0,0 +1,168 @@
+package main
+
+// Tests of composite literals.
+
+import "fmt"
+
+// Map literals.
+func init() {
+ type M map[int]int
+ m1 := []*M{{1: 1}, &M{2: 2}}
+ want := "map[1:1] map[2:2]"
+ if got := fmt.Sprint(*m1[0], *m1[1]); got != want {
+ panic(got)
+ }
+ m2 := []M{{1: 1}, M{2: 2}}
+ if got := fmt.Sprint(m2[0], m2[1]); got != want {
+ panic(got)
+ }
+}
+
+// Nonliteral keys in composite literal.
+func init() {
+ const zero int = 1
+ var v = []int{1 + zero: 42}
+ if x := fmt.Sprint(v); x != "[0 0 42]" {
+ panic(x)
+ }
+}
+
+// Test for in-place initialization.
+func init() {
+ // struct
+ type S struct {
+ a, b int
+ }
+ s := S{1, 2}
+ s = S{b: 3}
+ if s.a != 0 {
+ panic("s.a != 0")
+ }
+ if s.b != 3 {
+ panic("s.b != 3")
+ }
+ s = S{}
+ if s.a != 0 {
+ panic("s.a != 0")
+ }
+ if s.b != 0 {
+ panic("s.b != 0")
+ }
+
+ // array
+ type A [4]int
+ a := A{2, 4, 6, 8}
+ a = A{1: 6, 2: 4}
+ if a[0] != 0 {
+ panic("a[0] != 0")
+ }
+ if a[1] != 6 {
+ panic("a[1] != 6")
+ }
+ if a[2] != 4 {
+ panic("a[2] != 4")
+ }
+ if a[3] != 0 {
+ panic("a[3] != 0")
+ }
+ a = A{}
+ if a[0] != 0 {
+ panic("a[0] != 0")
+ }
+ if a[1] != 0 {
+ panic("a[1] != 0")
+ }
+ if a[2] != 0 {
+ panic("a[2] != 0")
+ }
+ if a[3] != 0 {
+ panic("a[3] != 0")
+ }
+}
+
+// Regression test for https://github.com/golang/go/issues/10127:
+// composite literal clobbers destination before reading from it.
+func init() {
+ // map
+ {
+ type M map[string]int
+ m := M{"x": 1, "y": 2}
+ m = M{"x": m["y"], "y": m["x"]}
+ if m["x"] != 2 || m["y"] != 1 {
+ panic(fmt.Sprint(m))
+ }
+
+ n := M{"x": 3}
+ m, n = M{"x": n["x"]}, M{"x": m["x"]} // parallel assignment
+ if got := fmt.Sprint(m["x"], n["x"]); got != "3 2" {
+ panic(got)
+ }
+ }
+
+ // struct
+ {
+ type T struct{ x, y, z int }
+ t := T{x: 1, y: 2, z: 3}
+
+ t = T{x: t.y, y: t.z, z: t.x} // all fields
+ if got := fmt.Sprint(t); got != "{2 3 1}" {
+ panic(got)
+ }
+
+ t = T{x: t.y, y: t.z + 3} // not all fields
+ if got := fmt.Sprint(t); got != "{3 4 0}" {
+ panic(got)
+ }
+
+ u := T{x: 5, y: 6, z: 7}
+ t, u = T{x: u.x}, T{x: t.x} // parallel assignment
+ if got := fmt.Sprint(t, u); got != "{5 0 0} {3 0 0}" {
+ panic(got)
+ }
+ }
+
+ // array
+ {
+ a := [3]int{0: 1, 1: 2, 2: 3}
+
+ a = [3]int{0: a[1], 1: a[2], 2: a[0]} // all elements
+ if got := fmt.Sprint(a); got != "[2 3 1]" {
+ panic(got)
+ }
+
+ a = [3]int{0: a[1], 1: a[2] + 3} // not all elements
+ if got := fmt.Sprint(a); got != "[3 4 0]" {
+ panic(got)
+ }
+
+ b := [3]int{0: 5, 1: 6, 2: 7}
+ a, b = [3]int{0: b[0]}, [3]int{0: a[0]} // parallel assignment
+ if got := fmt.Sprint(a, b); got != "[5 0 0] [3 0 0]" {
+ panic(got)
+ }
+ }
+
+ // slice
+ {
+ s := []int{0: 1, 1: 2, 2: 3}
+
+ s = []int{0: s[1], 1: s[2], 2: s[0]} // all elements
+ if got := fmt.Sprint(s); got != "[2 3 1]" {
+ panic(got)
+ }
+
+ s = []int{0: s[1], 1: s[2] + 3} // not all elements
+ if got := fmt.Sprint(s); got != "[3 4]" {
+ panic(got)
+ }
+
+ t := []int{0: 5, 1: 6, 2: 7}
+ s, t = []int{0: t[0]}, []int{0: s[0]} // parallel assignment
+ if got := fmt.Sprint(s, t); got != "[5] [3]" {
+ panic(got)
+ }
+ }
+}
+
+func main() {
+}
diff --git a/go/ssa/interp/testdata/coverage.go b/go/ssa/interp/testdata/coverage.go
new file mode 100644
index 0000000..0bc0586
--- /dev/null
+++ b/go/ssa/interp/testdata/coverage.go
@@ -0,0 +1,534 @@
+// This interpreter test is designed to run very quickly yet provide
+// some coverage of a broad selection of constructs.
+//
+// Validate this file with 'go run' after editing.
+// TODO(adonovan): break this into small files organized by theme.
+
+package main
+
+import (
+ "fmt"
+ "reflect"
+)
+
+func init() {
+ // Call of variadic function with (implicit) empty slice.
+ if x := fmt.Sprint(); x != "" {
+ panic(x)
+ }
+}
+
+type empty interface{}
+
+type I interface {
+ f() int
+}
+
+type T struct{ z int }
+
+func (t T) f() int { return t.z }
+
+func use(interface{}) {}
+
+var counter = 2
+
+// Test initialization, including init blocks containing 'return'.
+// Assertion is in main.
+func init() {
+ counter *= 3
+ return
+ counter *= 3
+}
+
+func init() {
+ counter *= 5
+ return
+ counter *= 5
+}
+
+// Recursion.
+func fib(x int) int {
+ if x < 2 {
+ return x
+ }
+ return fib(x-1) + fib(x-2)
+}
+
+func fibgen(ch chan int) {
+ for x := 0; x < 10; x++ {
+ ch <- fib(x)
+ }
+ close(ch)
+}
+
+// Goroutines and channels.
+func init() {
+ ch := make(chan int)
+ go fibgen(ch)
+ var fibs []int
+ for v := range ch {
+ fibs = append(fibs, v)
+ if len(fibs) == 10 {
+ break
+ }
+ }
+ if x := fmt.Sprint(fibs); x != "[0 1 1 2 3 5 8 13 21 34]" {
+ panic(x)
+ }
+}
+
+// Test of aliasing.
+func init() {
+ type S struct {
+ a, b string
+ }
+
+ s1 := []string{"foo", "bar"}
+ s2 := s1 // creates an alias
+ s2[0] = "wiz"
+ if x := fmt.Sprint(s1, s2); x != "[wiz bar] [wiz bar]" {
+ panic(x)
+ }
+
+ pa1 := &[2]string{"foo", "bar"}
+ pa2 := pa1 // creates an alias
+ pa2[0] = "wiz"
+ if x := fmt.Sprint(*pa1, *pa2); x != "[wiz bar] [wiz bar]" {
+ panic(x)
+ }
+
+ a1 := [2]string{"foo", "bar"}
+ a2 := a1 // creates a copy
+ a2[0] = "wiz"
+ if x := fmt.Sprint(a1, a2); x != "[foo bar] [wiz bar]" {
+ panic(x)
+ }
+
+ t1 := S{"foo", "bar"}
+ t2 := t1 // copy
+ t2.a = "wiz"
+ if x := fmt.Sprint(t1, t2); x != "{foo bar} {wiz bar}" {
+ panic(x)
+ }
+}
+
+func main() {
+ print() // legal
+
+ if counter != 2*3*5 {
+ panic(counter)
+ }
+
+ // Test builtins (e.g. complex) preserve named argument types.
+ type N complex128
+ var n N
+ n = complex(1.0, 2.0)
+ if n != complex(1.0, 2.0) {
+ panic(n)
+ }
+ if x := reflect.TypeOf(n).String(); x != "main.N" {
+ panic(x)
+ }
+ if real(n) != 1.0 || imag(n) != 2.0 {
+ panic(n)
+ }
+
+ // Channel + select.
+ ch := make(chan int, 1)
+ select {
+ case ch <- 1:
+ // ok
+ default:
+ panic("couldn't send")
+ }
+ if <-ch != 1 {
+ panic("couldn't receive")
+ }
+ // A "receive" select-case that doesn't declare its vars. (regression test)
+ anint := 0
+ ok := false
+ select {
+ case anint, ok = <-ch:
+ case anint = <-ch:
+ default:
+ }
+ _ = anint
+ _ = ok
+
+ // Anon structs with methods.
+ anon := struct{ T }{T: T{z: 1}}
+ if x := anon.f(); x != 1 {
+ panic(x)
+ }
+ var i I = anon
+ if x := i.f(); x != 1 {
+ panic(x)
+ }
+ // NB. precise output of reflect.Type.String is undefined.
+ if x := reflect.TypeOf(i).String(); x != "struct { main.T }" && x != "struct{main.T}" {
+ panic(x)
+ }
+
+ // fmt.
+ const message = "Hello, World!"
+ if fmt.Sprintf("%s, %s!", "Hello", "World") != message {
+ panic("oops")
+ }
+
+ // Type assertion.
+ type S struct {
+ f int
+ }
+ var e empty = S{f: 42}
+ switch v := e.(type) {
+ case S:
+ if v.f != 42 {
+ panic(v.f)
+ }
+ default:
+ panic(reflect.TypeOf(v))
+ }
+ if i, ok := e.(I); ok {
+ panic(i)
+ }
+
+ // Switch.
+ var x int
+ switch x {
+ case 1:
+ panic(x)
+ fallthrough
+ case 2, 3:
+ panic(x)
+ default:
+ // ok
+ }
+ // empty switch
+ switch {
+ }
+ // empty switch
+ switch {
+ default:
+ }
+ // empty switch
+ switch {
+ default:
+ fallthrough
+ case false:
+ }
+
+ // string -> []rune conversion.
+ use([]rune("foo"))
+
+ // Calls of form x.f().
+ type S2 struct {
+ f func() int
+ }
+ S2{f: func() int { return 1 }}.f() // field is a func value
+ T{}.f() // method call
+ i.f() // interface method invocation
+ (interface {
+ f() int
+ }(T{})).f() // anon interface method invocation
+
+ // Map lookup.
+ if v, ok := map[string]string{}["foo5"]; v != "" || ok {
+ panic("oops")
+ }
+
+ // Regression test: implicit address-taken struct literal
+ // inside literal map element.
+ _ = map[int]*struct{}{0: {}}
+}
+
+type mybool bool
+
+func (mybool) f() {}
+
+func init() {
+ type mybool bool
+ var b mybool
+ var i interface{} = b || b // result preserves types of operands
+ _ = i.(mybool)
+
+ i = false && b // result preserves type of "typed" operand
+ _ = i.(mybool)
+
+ i = b || true // result preserves type of "typed" operand
+ _ = i.(mybool)
+}
+
+func init() {
+ var x, y int
+ var b mybool = x == y // x==y is an untyped bool
+ b.f()
+}
+
+// Simple closures.
+func init() {
+ b := 3
+ f := func(a int) int {
+ return a + b
+ }
+ b++
+ if x := f(1); x != 5 { // 1+4 == 5
+ panic(x)
+ }
+ b++
+ if x := f(2); x != 7 { // 2+5 == 7
+ panic(x)
+ }
+ if b := f(1) < 16 || f(2) < 17; !b {
+ panic("oops")
+ }
+}
+
+// Shifts.
+func init() {
+ var i int64 = 1
+ var u uint64 = 1 << 32
+ if x := i << uint32(u); x != 1 {
+ panic(x)
+ }
+ if x := i << uint64(u); x != 0 {
+ panic(x)
+ }
+}
+
+// Implicit conversion of delete() key operand.
+func init() {
+ type I interface{}
+ m := make(map[I]bool)
+ m[1] = true
+ m[I(2)] = true
+ if len(m) != 2 {
+ panic(m)
+ }
+ delete(m, I(1))
+ delete(m, 2)
+ if len(m) != 0 {
+ panic(m)
+ }
+}
+
+// An I->I conversion always succeeds.
+func init() {
+ var x I
+ if I(x) != I(nil) {
+ panic("I->I conversion failed")
+ }
+}
+
+// An I->I type-assert fails iff the value is nil.
+func init() {
+ defer func() {
+ r := fmt.Sprint(recover())
+ // Exact error varies by toolchain.
+ if r != "runtime error: interface conversion: interface is nil, not main.I" &&
+ r != "interface conversion: interface is nil, not main.I" {
+ panic("I->I type assertion succeeded for nil value")
+ }
+ }()
+ var x I
+ _ = x.(I)
+}
+
+//////////////////////////////////////////////////////////////////////
+// Variadic bridge methods and interface thunks.
+
+type VT int
+
+var vcount = 0
+
+func (VT) f(x int, y ...string) {
+ vcount++
+ if x != 1 {
+ panic(x)
+ }
+ if len(y) != 2 || y[0] != "foo" || y[1] != "bar" {
+ panic(y)
+ }
+}
+
+type VS struct {
+ VT
+}
+
+type VI interface {
+ f(x int, y ...string)
+}
+
+func init() {
+ foobar := []string{"foo", "bar"}
+ var s VS
+ s.f(1, "foo", "bar")
+ s.f(1, foobar...)
+ if vcount != 2 {
+ panic("s.f not called twice")
+ }
+
+ fn := VI.f
+ fn(s, 1, "foo", "bar")
+ fn(s, 1, foobar...)
+ if vcount != 4 {
+ panic("I.f not called twice")
+ }
+}
+
+// Multiple labels on same statement.
+func multipleLabels() {
+ var trace []int
+ i := 0
+one:
+two:
+ for ; i < 3; i++ {
+ trace = append(trace, i)
+ switch i {
+ case 0:
+ continue two
+ case 1:
+ i++
+ goto one
+ case 2:
+ break two
+ }
+ }
+ if x := fmt.Sprint(trace); x != "[0 1 2]" {
+ panic(x)
+ }
+}
+
+func init() {
+ multipleLabels()
+}
+
+func init() {
+ // Struct equivalence ignores blank fields.
+ type s struct{ x, _, z int }
+ s1 := s{x: 1, z: 3}
+ s2 := s{x: 1, z: 3}
+ if s1 != s2 {
+ panic("not equal")
+ }
+}
+
+func init() {
+ // A slice var can be compared to const []T nil.
+ var i interface{} = []string{"foo"}
+ var j interface{} = []string(nil)
+ if i.([]string) == nil {
+ panic("expected i non-nil")
+ }
+ if j.([]string) != nil {
+ panic("expected j nil")
+ }
+ // But two slices cannot be compared, even if one is nil.
+ defer func() {
+ r := fmt.Sprint(recover())
+ if r != "runtime error: comparing uncomparable type []string" {
+ panic("want panic from slice comparison, got " + r)
+ }
+ }()
+ _ = i == j // interface comparison recurses on types
+}
+
+func init() {
+ // Regression test for SSA renaming bug.
+ var ints []int
+ for _ = range "foo" {
+ var x int
+ x++
+ ints = append(ints, x)
+ }
+ if fmt.Sprint(ints) != "[1 1 1]" {
+ panic(ints)
+ }
+}
+
+// Regression test for issue 6949:
+// []byte("foo") is not a constant since it allocates memory.
+func init() {
+ var r string
+ for i, b := range "ABC" {
+ x := []byte("abc")
+ x[i] = byte(b)
+ r += string(x)
+ }
+ if r != "AbcaBcabC" {
+ panic(r)
+ }
+}
+
+// Test of 3-operand x[lo:hi:max] slice.
+func init() {
+ s := []int{0, 1, 2, 3}
+ lenCapLoHi := func(x []int) [4]int { return [4]int{len(x), cap(x), x[0], x[len(x)-1]} }
+ if got := lenCapLoHi(s[1:3]); got != [4]int{2, 3, 1, 2} {
+ panic(got)
+ }
+ if got := lenCapLoHi(s[1:3:3]); got != [4]int{2, 2, 1, 2} {
+ panic(got)
+ }
+ max := 3
+ if "a"[0] == 'a' {
+ max = 2 // max is non-constant, even in SSA form
+ }
+ if got := lenCapLoHi(s[1:2:max]); got != [4]int{1, 1, 1, 1} {
+ panic(got)
+ }
+}
+
+var one = 1 // not a constant
+
+// Test makeslice.
+func init() {
+ check := func(s []string, wantLen, wantCap int) {
+ if len(s) != wantLen {
+ panic(len(s))
+ }
+ if cap(s) != wantCap {
+ panic(cap(s))
+ }
+ }
+ // SSA form:
+ check(make([]string, 10), 10, 10) // new([10]string)[:10]
+ check(make([]string, one), 1, 1) // make([]string, one, one)
+ check(make([]string, 0, 10), 0, 10) // new([10]string)[:0]
+ check(make([]string, 0, one), 0, 1) // make([]string, 0, one)
+ check(make([]string, one, 10), 1, 10) // new([10]string)[:one]
+ check(make([]string, one, one), 1, 1) // make([]string, one, one)
+}
+
+// Test that a nice error is issued by indirection wrappers.
+func init() {
+ var ptr *T
+ var i I = ptr
+
+ defer func() {
+ r := fmt.Sprint(recover())
+ // Exact error varies by toolchain:
+ if r != "runtime error: value method (main.T).f called using nil *main.T pointer" &&
+ r != "value method main.T.f called using nil *T pointer" {
+ panic("want panic from call with nil receiver, got " + r)
+ }
+ }()
+ i.f()
+ panic("unreachable")
+}
+
+// Regression test for a subtle bug in which copying values would causes
+// subcomponents of aggregate variables to change address, breaking
+// aliases.
+func init() {
+ type T struct{ f int }
+ var x T
+ p := &x.f
+ x = T{}
+ *p = 1
+ if x.f != 1 {
+ panic("lost store")
+ }
+ if p != &x.f {
+ panic("unstable address")
+ }
+}
diff --git a/go/ssa/interp/testdata/defer.go b/go/ssa/interp/testdata/defer.go
new file mode 100644
index 0000000..f5bae6c
--- /dev/null
+++ b/go/ssa/interp/testdata/defer.go
@@ -0,0 +1,53 @@
+package main
+
+// Tests of defer. (Deferred recover() belongs is recover.go.)
+
+import "fmt"
+
+func deferMutatesResults(noArgReturn bool) (a, b int) {
+ defer func() {
+ if a != 1 || b != 2 {
+ panic(fmt.Sprint(a, b))
+ }
+ a, b = 3, 4
+ }()
+ if noArgReturn {
+ a, b = 1, 2
+ return
+ }
+ return 1, 2
+}
+
+func init() {
+ a, b := deferMutatesResults(true)
+ if a != 3 || b != 4 {
+ panic(fmt.Sprint(a, b))
+ }
+ a, b = deferMutatesResults(false)
+ if a != 3 || b != 4 {
+ panic(fmt.Sprint(a, b))
+ }
+}
+
+// We concatenate init blocks to make a single function, but we must
+// run defers at the end of each block, not the combined function.
+var deferCount = 0
+
+func init() {
+ deferCount = 1
+ defer func() {
+ deferCount++
+ }()
+ // defer runs HERE
+}
+
+func init() {
+ // Strictly speaking the spec says deferCount may be 0 or 2
+ // since the relative order of init blocks is unspecified.
+ if deferCount != 2 {
+ panic(deferCount) // defer call has not run!
+ }
+}
+
+func main() {
+}
diff --git a/go/ssa/interp/testdata/fieldprom.go b/go/ssa/interp/testdata/fieldprom.go
new file mode 100644
index 0000000..fc276dd
--- /dev/null
+++ b/go/ssa/interp/testdata/fieldprom.go
@@ -0,0 +1,114 @@
+package main
+
+// Tests of field promotion logic.
+
+type A struct {
+ x int
+ y *int
+}
+
+type B struct {
+ p int
+ q *int
+}
+
+type C struct {
+ A
+ *B
+}
+
+type D struct {
+ a int
+ C
+}
+
+func assert(cond bool) {
+ if !cond {
+ panic("failed")
+ }
+}
+
+func f1(c C) {
+ assert(c.x == c.A.x)
+ assert(c.y == c.A.y)
+ assert(&c.x == &c.A.x)
+ assert(&c.y == &c.A.y)
+
+ assert(c.p == c.B.p)
+ assert(c.q == c.B.q)
+ assert(&c.p == &c.B.p)
+ assert(&c.q == &c.B.q)
+
+ c.x = 1
+ *c.y = 1
+ c.p = 1
+ *c.q = 1
+}
+
+func f2(c *C) {
+ assert(c.x == c.A.x)
+ assert(c.y == c.A.y)
+ assert(&c.x == &c.A.x)
+ assert(&c.y == &c.A.y)
+
+ assert(c.p == c.B.p)
+ assert(c.q == c.B.q)
+ assert(&c.p == &c.B.p)
+ assert(&c.q == &c.B.q)
+
+ c.x = 1
+ *c.y = 1
+ c.p = 1
+ *c.q = 1
+}
+
+func f3(d D) {
+ assert(d.x == d.C.A.x)
+ assert(d.y == d.C.A.y)
+ assert(&d.x == &d.C.A.x)
+ assert(&d.y == &d.C.A.y)
+
+ assert(d.p == d.C.B.p)
+ assert(d.q == d.C.B.q)
+ assert(&d.p == &d.C.B.p)
+ assert(&d.q == &d.C.B.q)
+
+ d.x = 1
+ *d.y = 1
+ d.p = 1
+ *d.q = 1
+}
+
+func f4(d *D) {
+ assert(d.x == d.C.A.x)
+ assert(d.y == d.C.A.y)
+ assert(&d.x == &d.C.A.x)
+ assert(&d.y == &d.C.A.y)
+
+ assert(d.p == d.C.B.p)
+ assert(d.q == d.C.B.q)
+ assert(&d.p == &d.C.B.p)
+ assert(&d.q == &d.C.B.q)
+
+ d.x = 1
+ *d.y = 1
+ d.p = 1
+ *d.q = 1
+}
+
+func main() {
+ y := 123
+ c := C{
+ A{x: 42, y: &y},
+ &B{p: 42, q: &y},
+ }
+
+ assert(&c.x == &c.A.x)
+
+ f1(c)
+ f2(&c)
+
+ d := D{C: c}
+ f3(d)
+ f4(&d)
+}
diff --git a/go/ssa/interp/testdata/ifaceconv.go b/go/ssa/interp/testdata/ifaceconv.go
new file mode 100644
index 0000000..96fc105
--- /dev/null
+++ b/go/ssa/interp/testdata/ifaceconv.go
@@ -0,0 +1,83 @@
+package main
+
+// Tests of interface conversions and type assertions.
+
+type I0 interface {
+}
+type I1 interface {
+ f()
+}
+type I2 interface {
+ f()
+ g()
+}
+
+type C0 struct{}
+type C1 struct{}
+
+func (C1) f() {}
+
+type C2 struct{}
+
+func (C2) f() {}
+func (C2) g() {}
+
+func main() {
+ var i0 I0
+ var i1 I1
+ var i2 I2
+
+ // Nil always causes a type assertion to fail, even to the
+ // same type.
+ if _, ok := i0.(I0); ok {
+ panic("nil i0.(I0) succeeded")
+ }
+ if _, ok := i1.(I1); ok {
+ panic("nil i1.(I1) succeeded")
+ }
+ if _, ok := i2.(I2); ok {
+ panic("nil i2.(I2) succeeded")
+ }
+
+ // Conversions can't fail, even with nil.
+ _ = I0(i0)
+
+ _ = I0(i1)
+ _ = I1(i1)
+
+ _ = I0(i2)
+ _ = I1(i2)
+ _ = I2(i2)
+
+ // Non-nil type assertions pass or fail based on the concrete type.
+ i1 = C1{}
+ if _, ok := i1.(I0); !ok {
+ panic("C1 i1.(I0) failed")
+ }
+ if _, ok := i1.(I1); !ok {
+ panic("C1 i1.(I1) failed")
+ }
+ if _, ok := i1.(I2); ok {
+ panic("C1 i1.(I2) succeeded")
+ }
+
+ i1 = C2{}
+ if _, ok := i1.(I0); !ok {
+ panic("C2 i1.(I0) failed")
+ }
+ if _, ok := i1.(I1); !ok {
+ panic("C2 i1.(I1) failed")
+ }
+ if _, ok := i1.(I2); !ok {
+ panic("C2 i1.(I2) failed")
+ }
+
+ // Conversions can't fail.
+ i1 = C1{}
+ if I0(i1) == nil {
+ panic("C1 I0(i1) was nil")
+ }
+ if I1(i1) == nil {
+ panic("C1 I1(i1) was nil")
+ }
+}
diff --git a/go/ssa/interp/testdata/ifaceprom.go b/go/ssa/interp/testdata/ifaceprom.go
new file mode 100644
index 0000000..414dc73
--- /dev/null
+++ b/go/ssa/interp/testdata/ifaceprom.go
@@ -0,0 +1,58 @@
+package main
+
+// Test of promotion of methods of an interface embedded within a
+// struct. In particular, this test exercises that the correct
+// method is called.
+
+type I interface {
+ one() int
+ two() string
+}
+
+type S struct {
+ I
+}
+
+type impl struct{}
+
+func (impl) one() int {
+ return 1
+}
+
+func (impl) two() string {
+ return "two"
+}
+
+func main() {
+ var s S
+ s.I = impl{}
+ if one := s.I.one(); one != 1 {
+ panic(one)
+ }
+ if one := s.one(); one != 1 {
+ panic(one)
+ }
+ closOne := s.I.one
+ if one := closOne(); one != 1 {
+ panic(one)
+ }
+ closOne = s.one
+ if one := closOne(); one != 1 {
+ panic(one)
+ }
+
+ if two := s.I.two(); two != "two" {
+ panic(two)
+ }
+ if two := s.two(); two != "two" {
+ panic(two)
+ }
+ closTwo := s.I.two
+ if two := closTwo(); two != "two" {
+ panic(two)
+ }
+ closTwo = s.two
+ if two := closTwo(); two != "two" {
+ panic(two)
+ }
+}
diff --git a/go/ssa/interp/testdata/initorder.go b/go/ssa/interp/testdata/initorder.go
new file mode 100644
index 0000000..0f26bed
--- /dev/null
+++ b/go/ssa/interp/testdata/initorder.go
@@ -0,0 +1,67 @@
+package main
+
+import "fmt"
+
+// Test of initialization order of package-level vars.
+
+var counter int
+
+func next() int {
+ c := counter
+ counter++
+ return c
+}
+
+func next2() (x int, y int) {
+ x = next()
+ y = next()
+ return
+}
+
+func makeOrder() int {
+ _, _, _, _ = f, b, d, e
+ return 0
+}
+
+func main() {
+ // Initialization constraints:
+ // - {f,b,c/d,e} < order (ref graph traversal)
+ // - order < {a} (lexical order)
+ // - b < c/d < e < f (lexical order)
+ // Solution: a b c/d e f
+ abcdef := [6]int{a, b, c, d, e, f}
+ if abcdef != [6]int{0, 1, 2, 3, 4, 5} {
+ panic(abcdef)
+ }
+}
+
+var order = makeOrder()
+
+var a, b = next(), next()
+var c, d = next2()
+var e, f = next(), next()
+
+// ------------------------------------------------------------------------
+
+var order2 []string
+
+func create(x int, name string) int {
+ order2 = append(order2, name)
+ return x
+}
+
+var C = create(B+1, "C")
+var A, B = create(1, "A"), create(2, "B")
+
+// Initialization order of package-level value specs.
+func init() {
+ x := fmt.Sprint(order2)
+ // Result varies by toolchain. This is a spec bug.
+ if x != "[B C A]" && // gc
+ x != "[A B C]" { // go/types
+ panic(x)
+ }
+ if C != 3 {
+ panic(c)
+ }
+}
diff --git a/go/ssa/interp/testdata/methprom.go b/go/ssa/interp/testdata/methprom.go
new file mode 100644
index 0000000..e8e384c
--- /dev/null
+++ b/go/ssa/interp/testdata/methprom.go
@@ -0,0 +1,93 @@
+package main
+
+// Tests of method promotion logic.
+
+type A struct{ magic int }
+
+func (a A) x() {
+ if a.magic != 1 {
+ panic(a.magic)
+ }
+}
+func (a *A) y() *A {
+ return a
+}
+
+type B struct{ magic int }
+
+func (b B) p() {
+ if b.magic != 2 {
+ panic(b.magic)
+ }
+}
+func (b *B) q() {
+ if b != theC.B {
+ panic("oops")
+ }
+}
+
+type I interface {
+ f()
+}
+
+type impl struct{ magic int }
+
+func (i impl) f() {
+ if i.magic != 3 {
+ panic("oops")
+ }
+}
+
+type C struct {
+ A
+ *B
+ I
+}
+
+func assert(cond bool) {
+ if !cond {
+ panic("failed")
+ }
+}
+
+var theC = C{
+ A: A{1},
+ B: &B{2},
+ I: impl{3},
+}
+
+func addr() *C {
+ return &theC
+}
+
+func value() C {
+ return theC
+}
+
+func main() {
+ // address
+ addr().x()
+ if addr().y() != &theC.A {
+ panic("oops")
+ }
+ addr().p()
+ addr().q()
+ addr().f()
+
+ // addressable value
+ var c C = value()
+ c.x()
+ if c.y() != &c.A {
+ panic("oops")
+ }
+ c.p()
+ c.q()
+ c.f()
+
+ // non-addressable value
+ value().x()
+ // value().y() // not in method set
+ value().p()
+ value().q()
+ value().f()
+}
diff --git a/go/ssa/interp/testdata/mrvchain.go b/go/ssa/interp/testdata/mrvchain.go
new file mode 100644
index 0000000..70dfd02
--- /dev/null
+++ b/go/ssa/interp/testdata/mrvchain.go
@@ -0,0 +1,75 @@
+// Tests of call chaining f(g()) when g has multiple return values (MRVs).
+// See https://code.google.com/p/go/issues/detail?id=4573.
+
+package main
+
+func assert(actual, expected int) {
+ if actual != expected {
+ panic(actual)
+ }
+}
+
+func g() (int, int) {
+ return 5, 7
+}
+
+func g2() (float64, float64) {
+ return 5, 7
+}
+
+func f1v(x int, v ...int) {
+ assert(x, 5)
+ assert(v[0], 7)
+}
+
+func f2(x, y int) {
+ assert(x, 5)
+ assert(y, 7)
+}
+
+func f2v(x, y int, v ...int) {
+ assert(x, 5)
+ assert(y, 7)
+ assert(len(v), 0)
+}
+
+func complexArgs() (float64, float64) {
+ return 5, 7
+}
+
+func appendArgs() ([]string, string) {
+ return []string{"foo"}, "bar"
+}
+
+func h() (i interface{}, ok bool) {
+ m := map[int]string{1: "hi"}
+ i, ok = m[1] // string->interface{} conversion within multi-valued expression
+ return
+}
+
+func h2() (i interface{}, ok bool) {
+ ch := make(chan string, 1)
+ ch <- "hi"
+ i, ok = <-ch // string->interface{} conversion within multi-valued expression
+ return
+}
+
+func main() {
+ f1v(g())
+ f2(g())
+ f2v(g())
+ if c := complex(complexArgs()); c != 5+7i {
+ panic(c)
+ }
+ if s := append(appendArgs()); len(s) != 2 || s[0] != "foo" || s[1] != "bar" {
+ panic(s)
+ }
+ i, ok := h()
+ if !ok || i.(string) != "hi" {
+ panic(i)
+ }
+ i, ok = h2()
+ if !ok || i.(string) != "hi" {
+ panic(i)
+ }
+}
diff --git a/go/ssa/interp/testdata/range.go b/go/ssa/interp/testdata/range.go
new file mode 100644
index 0000000..da8a421
--- /dev/null
+++ b/go/ssa/interp/testdata/range.go
@@ -0,0 +1,55 @@
+package main
+
+// Tests of range loops.
+
+import "fmt"
+
+// Range over string.
+func init() {
+ if x := len("Hello, 世界"); x != 13 { // bytes
+ panic(x)
+ }
+ var indices []int
+ var runes []rune
+ for i, r := range "Hello, 世界" {
+ runes = append(runes, r)
+ indices = append(indices, i)
+ }
+ if x := fmt.Sprint(runes); x != "[72 101 108 108 111 44 32 19990 30028]" {
+ panic(x)
+ }
+ if x := fmt.Sprint(indices); x != "[0 1 2 3 4 5 6 7 10]" {
+ panic(x)
+ }
+ s := ""
+ for _, r := range runes {
+ s = fmt.Sprintf("%s%c", s, r)
+ }
+ if s != "Hello, 世界" {
+ panic(s)
+ }
+
+ var x int
+ for range "Hello, 世界" {
+ x++
+ }
+ if x != len(indices) {
+ panic(x)
+ }
+}
+
+// Regression test for range of pointer to named array type.
+func init() {
+ type intarr [3]int
+ ia := intarr{1, 2, 3}
+ var count int
+ for _, x := range &ia {
+ count += x
+ }
+ if count != 6 {
+ panic(count)
+ }
+}
+
+func main() {
+}
diff --git a/go/ssa/interp/testdata/recover.go b/go/ssa/interp/testdata/recover.go
new file mode 100644
index 0000000..b560052
--- /dev/null
+++ b/go/ssa/interp/testdata/recover.go
@@ -0,0 +1,34 @@
+package main
+
+// Tests of panic/recover.
+
+import "fmt"
+
+func fortyTwo() (r int) {
+ r = 42
+ // The next two statements simulate a 'return' statement.
+ defer func() { recover() }()
+ panic(nil)
+}
+
+func zero() int {
+ defer func() { recover() }()
+ panic(1)
+}
+
+func zeroEmpty() (int, string) {
+ defer func() { recover() }()
+ panic(1)
+}
+
+func main() {
+ if r := fortyTwo(); r != 42 {
+ panic(r)
+ }
+ if r := zero(); r != 0 {
+ panic(r)
+ }
+ if r, s := zeroEmpty(); r != 0 || s != "" {
+ panic(fmt.Sprint(r, s))
+ }
+}
diff --git a/go/ssa/interp/testdata/reflect.go b/go/ssa/interp/testdata/reflect.go
new file mode 100644
index 0000000..6aa9a67
--- /dev/null
+++ b/go/ssa/interp/testdata/reflect.go
@@ -0,0 +1,11 @@
+package main
+
+import "reflect"
+
+func main() {
+ // Regression test for issue 9462.
+ got := reflect.SliceOf(reflect.TypeOf(byte(0))).String()
+ if got != "[]uint8" && got != "[]byte" { // result varies by toolchain
+ println("BUG: " + got)
+ }
+}
diff --git a/go/ssa/interp/testdata/static.go b/go/ssa/interp/testdata/static.go
new file mode 100644
index 0000000..b115513
--- /dev/null
+++ b/go/ssa/interp/testdata/static.go
@@ -0,0 +1,58 @@
+package main
+
+// Static tests of SSA builder (via the sanity checker).
+// Dynamic semantics are not exercised.
+
+func init() {
+ // Regression test for issue 6806.
+ ch := make(chan int)
+ select {
+ case n, _ := <-ch:
+ _ = n
+ default:
+ // The default case disables the simplification of
+ // select to a simple receive statement.
+ }
+
+ // value,ok-form receive where TypeOf(ok) is a named boolean.
+ type mybool bool
+ var x int
+ var y mybool
+ select {
+ case x, y = <-ch:
+ default:
+ // The default case disables the simplification of
+ // select to a simple receive statement.
+ }
+ _ = x
+ _ = y
+}
+
+var a int
+
+// Regression test for issue 7840 (covered by SSA sanity checker).
+func bug7840() bool {
+ // This creates a single-predecessor block with a φ-node.
+ return false && a == 0 && a == 0
+}
+
+// A blocking select (sans "default:") cannot fall through.
+// Regression test for issue 7022.
+func bug7022() int {
+ var c1, c2 chan int
+ select {
+ case <-c1:
+ return 123
+ case <-c2:
+ return 456
+ }
+}
+
+// Parens should not prevent intrinsic treatment of built-ins.
+// (Regression test for a crash.)
+func init() {
+ _ = (new)(int)
+ _ = (make)([]int, 0)
+}
+
+func main() {}
diff --git a/go/ssa/interp/value.go b/go/ssa/interp/value.go
new file mode 100644
index 0000000..2ab0c04
--- /dev/null
+++ b/go/ssa/interp/value.go
@@ -0,0 +1,497 @@
+// 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 interp
+
+// Values
+//
+// All interpreter values are "boxed" in the empty interface, value.
+// The range of possible dynamic types within value are:
+//
+// - bool
+// - numbers (all built-in int/float/complex types are distinguished)
+// - string
+// - map[value]value --- maps for which usesBuiltinMap(keyType)
+// *hashmap --- maps for which !usesBuiltinMap(keyType)
+// - chan value
+// - []value --- slices
+// - iface --- interfaces.
+// - structure --- structs. Fields are ordered and accessed by numeric indices.
+// - array --- arrays.
+// - *value --- pointers. Careful: *value is a distinct type from *array etc.
+// - *ssa.Function \
+// *ssa.Builtin } --- functions. A nil 'func' is always of type *ssa.Function.
+// *closure /
+// - tuple --- as returned by Return, Next, "value,ok" modes, etc.
+// - iter --- iterators from 'range' over map or string.
+// - bad --- a poison pill for locals that have gone out of scope.
+// - rtype -- the interpreter's concrete implementation of reflect.Type
+//
+// Note that nil is not on this list.
+//
+// Pay close attention to whether or not the dynamic type is a pointer.
+// The compiler cannot help you since value is an empty interface.
+
+import (
+ "bytes"
+ "fmt"
+ "io"
+ "reflect"
+ "strings"
+ "sync"
+ "unsafe"
+
+ "golang.org/x/tools/go/ssa"
+ "golang.org/x/tools/go/types"
+ "golang.org/x/tools/go/types/typeutil"
+)
+
+type value interface{}
+
+type tuple []value
+
+type array []value
+
+type iface struct {
+ t types.Type // never an "untyped" type
+ v value
+}
+
+type structure []value
+
+// For map, array, *array, slice, string or channel.
+type iter interface {
+ // next returns a Tuple (key, value, ok).
+ // key and value are unaliased, e.g. copies of the sequence element.
+ next() tuple
+}
+
+type closure struct {
+ Fn *ssa.Function
+ Env []value
+}
+
+type bad struct{}
+
+type rtype struct {
+ t types.Type
+}
+
+// Hash functions and equivalence relation:
+
+// hashString computes the FNV hash of s.
+func hashString(s string) int {
+ var h uint32
+ for i := 0; i < len(s); i++ {
+ h ^= uint32(s[i])
+ h *= 16777619
+ }
+ return int(h)
+}
+
+var (
+ mu sync.Mutex
+ hasher = typeutil.MakeHasher()
+)
+
+// hashType returns a hash for t such that
+// types.Identical(x, y) => hashType(x) == hashType(y).
+func hashType(t types.Type) int {
+ mu.Lock()
+ h := int(hasher.Hash(t))
+ mu.Unlock()
+ return h
+}
+
+// usesBuiltinMap returns true if the built-in hash function and
+// equivalence relation for type t are consistent with those of the
+// interpreter's representation of type t. Such types are: all basic
+// types (bool, numbers, string), pointers and channels.
+//
+// usesBuiltinMap returns false for types that require a custom map
+// implementation: interfaces, arrays and structs.
+//
+// Panic ensues if t is an invalid map key type: function, map or slice.
+func usesBuiltinMap(t types.Type) bool {
+ switch t := t.(type) {
+ case *types.Basic, *types.Chan, *types.Pointer:
+ return true
+ case *types.Named:
+ return usesBuiltinMap(t.Underlying())
+ case *types.Interface, *types.Array, *types.Struct:
+ return false
+ }
+ panic(fmt.Sprintf("invalid map key type: %T", t))
+}
+
+func (x array) eq(t types.Type, _y interface{}) bool {
+ y := _y.(array)
+ tElt := t.Underlying().(*types.Array).Elem()
+ for i, xi := range x {
+ if !equals(tElt, xi, y[i]) {
+ return false
+ }
+ }
+ return true
+}
+
+func (x array) hash(t types.Type) int {
+ h := 0
+ tElt := t.Underlying().(*types.Array).Elem()
+ for _, xi := range x {
+ h += hash(tElt, xi)
+ }
+ return h
+}
+
+func (x structure) eq(t types.Type, _y interface{}) bool {
+ y := _y.(structure)
+ tStruct := t.Underlying().(*types.Struct)
+ for i, n := 0, tStruct.NumFields(); i < n; i++ {
+ if f := tStruct.Field(i); !f.Anonymous() {
+ if !equals(f.Type(), x[i], y[i]) {
+ return false
+ }
+ }
+ }
+ return true
+}
+
+func (x structure) hash(t types.Type) int {
+ tStruct := t.Underlying().(*types.Struct)
+ h := 0
+ for i, n := 0, tStruct.NumFields(); i < n; i++ {
+ if f := tStruct.Field(i); !f.Anonymous() {
+ h += hash(f.Type(), x[i])
+ }
+ }
+ return h
+}
+
+// nil-tolerant variant of types.Identical.
+func sameType(x, y types.Type) bool {
+ if x == nil {
+ return y == nil
+ }
+ return y != nil && types.Identical(x, y)
+}
+
+func (x iface) eq(t types.Type, _y interface{}) bool {
+ y := _y.(iface)
+ return sameType(x.t, y.t) && (x.t == nil || equals(x.t, x.v, y.v))
+}
+
+func (x iface) hash(_ types.Type) int {
+ return hashType(x.t)*8581 + hash(x.t, x.v)
+}
+
+func (x rtype) hash(_ types.Type) int {
+ return hashType(x.t)
+}
+
+func (x rtype) eq(_ types.Type, y interface{}) bool {
+ return types.Identical(x.t, y.(rtype).t)
+}
+
+// equals returns true iff x and y are equal according to Go's
+// linguistic equivalence relation for type t.
+// In a well-typed program, the dynamic types of x and y are
+// guaranteed equal.
+func equals(t types.Type, x, y value) bool {
+ switch x := x.(type) {
+ case bool:
+ return x == y.(bool)
+ case int:
+ return x == y.(int)
+ case int8:
+ return x == y.(int8)
+ case int16:
+ return x == y.(int16)
+ case int32:
+ return x == y.(int32)
+ case int64:
+ return x == y.(int64)
+ case uint:
+ return x == y.(uint)
+ case uint8:
+ return x == y.(uint8)
+ case uint16:
+ return x == y.(uint16)
+ case uint32:
+ return x == y.(uint32)
+ case uint64:
+ return x == y.(uint64)
+ case uintptr:
+ return x == y.(uintptr)
+ case float32:
+ return x == y.(float32)
+ case float64:
+ return x == y.(float64)
+ case complex64:
+ return x == y.(complex64)
+ case complex128:
+ return x == y.(complex128)
+ case string:
+ return x == y.(string)
+ case *value:
+ return x == y.(*value)
+ case chan value:
+ return x == y.(chan value)
+ case structure:
+ return x.eq(t, y)
+ case array:
+ return x.eq(t, y)
+ case iface:
+ return x.eq(t, y)
+ case rtype:
+ return x.eq(t, y)
+ }
+
+ // Since map, func and slice don't support comparison, this
+ // case is only reachable if one of x or y is literally nil
+ // (handled in eqnil) or via interface{} values.
+ panic(fmt.Sprintf("comparing uncomparable type %s", t))
+}
+
+// Returns an integer hash of x such that equals(x, y) => hash(x) == hash(y).
+func hash(t types.Type, x value) int {
+ switch x := x.(type) {
+ case bool:
+ if x {
+ return 1
+ }
+ return 0
+ case int:
+ return x
+ case int8:
+ return int(x)
+ case int16:
+ return int(x)
+ case int32:
+ return int(x)
+ case int64:
+ return int(x)
+ case uint:
+ return int(x)
+ case uint8:
+ return int(x)
+ case uint16:
+ return int(x)
+ case uint32:
+ return int(x)
+ case uint64:
+ return int(x)
+ case uintptr:
+ return int(x)
+ case float32:
+ return int(x)
+ case float64:
+ return int(x)
+ case complex64:
+ return int(real(x))
+ case complex128:
+ return int(real(x))
+ case string:
+ return hashString(x)
+ case *value:
+ return int(uintptr(unsafe.Pointer(x)))
+ case chan value:
+ return int(uintptr(reflect.ValueOf(x).Pointer()))
+ case structure:
+ return x.hash(t)
+ case array:
+ return x.hash(t)
+ case iface:
+ return x.hash(t)
+ case rtype:
+ return x.hash(t)
+ }
+ panic(fmt.Sprintf("%T is unhashable", x))
+}
+
+// reflect.Value struct values don't have a fixed shape, since the
+// payload can be a scalar or an aggregate depending on the instance.
+// So store (and load) can't simply use recursion over the shape of the
+// rhs value, or the lhs, to copy the value; we need the static type
+// information. (We can't make reflect.Value a new basic data type
+// because its "structness" is exposed to Go programs.)
+
+// load returns the value of type T in *addr.
+func load(T types.Type, addr *value) value {
+ switch T := T.Underlying().(type) {
+ case *types.Struct:
+ v := (*addr).(structure)
+ a := make(structure, len(v))
+ for i := range a {
+ a[i] = load(T.Field(i).Type(), &v[i])
+ }
+ return a
+ case *types.Array:
+ v := (*addr).(array)
+ a := make(array, len(v))
+ for i := range a {
+ a[i] = load(T.Elem(), &v[i])
+ }
+ return a
+ default:
+ return *addr
+ }
+}
+
+// store stores value v of type T into *addr.
+func store(T types.Type, addr *value, v value) {
+ switch T := T.Underlying().(type) {
+ case *types.Struct:
+ lhs := (*addr).(structure)
+ rhs := v.(structure)
+ for i := range lhs {
+ store(T.Field(i).Type(), &lhs[i], rhs[i])
+ }
+ case *types.Array:
+ lhs := (*addr).(array)
+ rhs := v.(array)
+ for i := range lhs {
+ store(T.Elem(), &lhs[i], rhs[i])
+ }
+ default:
+ *addr = v
+ }
+}
+
+// Prints in the style of built-in println.
+// (More or less; in gc println is actually a compiler intrinsic and
+// can distinguish println(1) from println(interface{}(1)).)
+func writeValue(buf *bytes.Buffer, v value) {
+ switch v := v.(type) {
+ case nil, bool, int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64, uintptr, float32, float64, complex64, complex128, string:
+ fmt.Fprintf(buf, "%v", v)
+
+ case map[value]value:
+ buf.WriteString("map[")
+ sep := ""
+ for k, e := range v {
+ buf.WriteString(sep)
+ sep = " "
+ writeValue(buf, k)
+ buf.WriteString(":")
+ writeValue(buf, e)
+ }
+ buf.WriteString("]")
+
+ case *hashmap:
+ buf.WriteString("map[")
+ sep := " "
+ for _, e := range v.table {
+ for e != nil {
+ buf.WriteString(sep)
+ sep = " "
+ writeValue(buf, e.key)
+ buf.WriteString(":")
+ writeValue(buf, e.value)
+ e = e.next
+ }
+ }
+ buf.WriteString("]")
+
+ case chan value:
+ fmt.Fprintf(buf, "%v", v) // (an address)
+
+ case *value:
+ if v == nil {
+ buf.WriteString("<nil>")
+ } else {
+ fmt.Fprintf(buf, "%p", v)
+ }
+
+ case iface:
+ fmt.Fprintf(buf, "(%s, ", v.t)
+ writeValue(buf, v.v)
+ buf.WriteString(")")
+
+ case structure:
+ buf.WriteString("{")
+ for i, e := range v {
+ if i > 0 {
+ buf.WriteString(" ")
+ }
+ writeValue(buf, e)
+ }
+ buf.WriteString("}")
+
+ case array:
+ buf.WriteString("[")
+ for i, e := range v {
+ if i > 0 {
+ buf.WriteString(" ")
+ }
+ writeValue(buf, e)
+ }
+ buf.WriteString("]")
+
+ case []value:
+ buf.WriteString("[")
+ for i, e := range v {
+ if i > 0 {
+ buf.WriteString(" ")
+ }
+ writeValue(buf, e)
+ }
+ buf.WriteString("]")
+
+ case *ssa.Function, *ssa.Builtin, *closure:
+ fmt.Fprintf(buf, "%p", v) // (an address)
+
+ case rtype:
+ buf.WriteString(v.t.String())
+
+ case tuple:
+ // Unreachable in well-formed Go programs
+ buf.WriteString("(")
+ for i, e := range v {
+ if i > 0 {
+ buf.WriteString(", ")
+ }
+ writeValue(buf, e)
+ }
+ buf.WriteString(")")
+
+ default:
+ fmt.Fprintf(buf, "<%T>", v)
+ }
+}
+
+// Implements printing of Go values in the style of built-in println.
+func toString(v value) string {
+ var b bytes.Buffer
+ writeValue(&b, v)
+ return b.String()
+}
+
+// ------------------------------------------------------------------------
+// Iterators
+
+type stringIter struct {
+ *strings.Reader
+ i int
+}
+
+func (it *stringIter) next() tuple {
+ okv := make(tuple, 3)
+ ch, n, err := it.ReadRune()
+ ok := err != io.EOF
+ okv[0] = ok
+ if ok {
+ okv[1] = it.i
+ okv[2] = ch
+ }
+ it.i += n
+ return okv
+}
+
+type mapIter chan [2]value
+
+func (it mapIter) next() tuple {
+ kv, ok := <-it
+ return tuple{ok, kv[0], kv[1]}
+}
diff --git a/go/ssa/lift.go b/go/ssa/lift.go
new file mode 100644
index 0000000..3771f61
--- /dev/null
+++ b/go/ssa/lift.go
@@ -0,0 +1,599 @@
+// 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 ssa
+
+// This file defines the lifting pass which tries to "lift" Alloc
+// cells (new/local variables) into SSA registers, replacing loads
+// with the dominating stored value, eliminating loads and stores, and
+// inserting φ-nodes as needed.
+
+// Cited papers and resources:
+//
+// Ron Cytron et al. 1991. Efficiently computing SSA form...
+// http://doi.acm.org/10.1145/115372.115320
+//
+// Cooper, Harvey, Kennedy. 2001. A Simple, Fast Dominance Algorithm.
+// Software Practice and Experience 2001, 4:1-10.
+// http://www.hipersoft.rice.edu/grads/publications/dom14.pdf
+//
+// Daniel Berlin, llvmdev mailing list, 2012.
+// http://lists.cs.uiuc.edu/pipermail/llvmdev/2012-January/046638.html
+// (Be sure to expand the whole thread.)
+
+// TODO(adonovan): opt: there are many optimizations worth evaluating, and
+// the conventional wisdom for SSA construction is that a simple
+// algorithm well engineered often beats those of better asymptotic
+// complexity on all but the most egregious inputs.
+//
+// Danny Berlin suggests that the Cooper et al. algorithm for
+// computing the dominance frontier is superior to Cytron et al.
+// Furthermore he recommends that rather than computing the DF for the
+// whole function then renaming all alloc cells, it may be cheaper to
+// compute the DF for each alloc cell separately and throw it away.
+//
+// Consider exploiting liveness information to avoid creating dead
+// φ-nodes which we then immediately remove.
+//
+// Integrate lifting with scalar replacement of aggregates (SRA) since
+// the two are synergistic.
+//
+// Also see many other "TODO: opt" suggestions in the code.
+
+import (
+ "fmt"
+ "go/token"
+ "math/big"
+ "os"
+
+ "golang.org/x/tools/go/types"
+)
+
+// If true, perform sanity checking and show diagnostic information at
+// each step of lifting. Very verbose.
+const debugLifting = false
+
+// domFrontier maps each block to the set of blocks in its dominance
+// frontier. The outer slice is conceptually a map keyed by
+// Block.Index. The inner slice is conceptually a set, possibly
+// containing duplicates.
+//
+// TODO(adonovan): opt: measure impact of dups; consider a packed bit
+// representation, e.g. big.Int, and bitwise parallel operations for
+// the union step in the Children loop.
+//
+// domFrontier's methods mutate the slice's elements but not its
+// length, so their receivers needn't be pointers.
+//
+type domFrontier [][]*BasicBlock
+
+func (df domFrontier) add(u, v *BasicBlock) {
+ p := &df[u.Index]
+ *p = append(*p, v)
+}
+
+// build builds the dominance frontier df for the dominator (sub)tree
+// rooted at u, using the Cytron et al. algorithm.
+//
+// TODO(adonovan): opt: consider Berlin approach, computing pruned SSA
+// by pruning the entire IDF computation, rather than merely pruning
+// the DF -> IDF step.
+func (df domFrontier) build(u *BasicBlock) {
+ // Encounter each node u in postorder of dom tree.
+ for _, child := range u.dom.children {
+ df.build(child)
+ }
+ for _, vb := range u.Succs {
+ if v := vb.dom; v.idom != u {
+ df.add(u, vb)
+ }
+ }
+ for _, w := range u.dom.children {
+ for _, vb := range df[w.Index] {
+ // TODO(adonovan): opt: use word-parallel bitwise union.
+ if v := vb.dom; v.idom != u {
+ df.add(u, vb)
+ }
+ }
+ }
+}
+
+func buildDomFrontier(fn *Function) domFrontier {
+ df := make(domFrontier, len(fn.Blocks))
+ df.build(fn.Blocks[0])
+ if fn.Recover != nil {
+ df.build(fn.Recover)
+ }
+ return df
+}
+
+func removeInstr(refs []Instruction, instr Instruction) []Instruction {
+ i := 0
+ for _, ref := range refs {
+ if ref == instr {
+ continue
+ }
+ refs[i] = ref
+ i++
+ }
+ for j := i; j != len(refs); j++ {
+ refs[j] = nil // aid GC
+ }
+ return refs[:i]
+}
+
+// lift attempts to replace local and new Allocs accessed only with
+// load/store by SSA registers, inserting φ-nodes where necessary.
+// The result is a program in classical pruned SSA form.
+//
+// Preconditions:
+// - fn has no dead blocks (blockopt has run).
+// - Def/use info (Operands and Referrers) is up-to-date.
+// - The dominator tree is up-to-date.
+//
+func lift(fn *Function) {
+ // TODO(adonovan): opt: lots of little optimizations may be
+ // worthwhile here, especially if they cause us to avoid
+ // buildDomFrontier. For example:
+ //
+ // - Alloc never loaded? Eliminate.
+ // - Alloc never stored? Replace all loads with a zero constant.
+ // - Alloc stored once? Replace loads with dominating store;
+ // don't forget that an Alloc is itself an effective store
+ // of zero.
+ // - Alloc used only within a single block?
+ // Use degenerate algorithm avoiding φ-nodes.
+ // - Consider synergy with scalar replacement of aggregates (SRA).
+ // e.g. *(&x.f) where x is an Alloc.
+ // Perhaps we'd get better results if we generated this as x.f
+ // i.e. Field(x, .f) instead of Load(FieldIndex(x, .f)).
+ // Unclear.
+ //
+ // But we will start with the simplest correct code.
+ df := buildDomFrontier(fn)
+
+ if debugLifting {
+ title := false
+ for i, blocks := range df {
+ if blocks != nil {
+ if !title {
+ fmt.Fprintf(os.Stderr, "Dominance frontier of %s:\n", fn)
+ title = true
+ }
+ fmt.Fprintf(os.Stderr, "\t%s: %s\n", fn.Blocks[i], blocks)
+ }
+ }
+ }
+
+ newPhis := make(newPhiMap)
+
+ // During this pass we will replace some BasicBlock.Instrs
+ // (allocs, loads and stores) with nil, keeping a count in
+ // BasicBlock.gaps. At the end we will reset Instrs to the
+ // concatenation of all non-dead newPhis and non-nil Instrs
+ // for the block, reusing the original array if space permits.
+
+ // While we're here, we also eliminate 'rundefers'
+ // instructions in functions that contain no 'defer'
+ // instructions.
+ usesDefer := false
+
+ // Determine which allocs we can lift and number them densely.
+ // The renaming phase uses this numbering for compact maps.
+ numAllocs := 0
+ for _, b := range fn.Blocks {
+ b.gaps = 0
+ b.rundefers = 0
+ for _, instr := range b.Instrs {
+ switch instr := instr.(type) {
+ case *Alloc:
+ index := -1
+ if liftAlloc(df, instr, newPhis) {
+ index = numAllocs
+ numAllocs++
+ }
+ instr.index = index
+ case *Defer:
+ usesDefer = true
+ case *RunDefers:
+ b.rundefers++
+ }
+ }
+ }
+
+ // renaming maps an alloc (keyed by index) to its replacement
+ // value. Initially the renaming contains nil, signifying the
+ // zero constant of the appropriate type; we construct the
+ // Const lazily at most once on each path through the domtree.
+ // TODO(adonovan): opt: cache per-function not per subtree.
+ renaming := make([]Value, numAllocs)
+
+ // Renaming.
+ rename(fn.Blocks[0], renaming, newPhis)
+
+ // Eliminate dead new phis, then prepend the live ones to each block.
+ for _, b := range fn.Blocks {
+
+ // Compress the newPhis slice to eliminate unused phis.
+ // TODO(adonovan): opt: compute liveness to avoid
+ // placing phis in blocks for which the alloc cell is
+ // not live.
+ nps := newPhis[b]
+ j := 0
+ for _, np := range nps {
+ if !phiIsLive(np.phi) {
+ // discard it, first removing it from referrers
+ for _, newval := range np.phi.Edges {
+ if refs := newval.Referrers(); refs != nil {
+ *refs = removeInstr(*refs, np.phi)
+ }
+ }
+ continue
+ }
+ nps[j] = np
+ j++
+ }
+ nps = nps[:j]
+
+ rundefersToKill := b.rundefers
+ if usesDefer {
+ rundefersToKill = 0
+ }
+
+ if j+b.gaps+rundefersToKill == 0 {
+ continue // fast path: no new phis or gaps
+ }
+
+ // Compact nps + non-nil Instrs into a new slice.
+ // TODO(adonovan): opt: compact in situ if there is
+ // sufficient space or slack in the slice.
+ dst := make([]Instruction, len(b.Instrs)+j-b.gaps-rundefersToKill)
+ for i, np := range nps {
+ dst[i] = np.phi
+ }
+ for _, instr := range b.Instrs {
+ if instr == nil {
+ continue
+ }
+ if !usesDefer {
+ if _, ok := instr.(*RunDefers); ok {
+ continue
+ }
+ }
+ dst[j] = instr
+ j++
+ }
+ for i, np := range nps {
+ dst[i] = np.phi
+ }
+ b.Instrs = dst
+ }
+
+ // Remove any fn.Locals that were lifted.
+ j := 0
+ for _, l := range fn.Locals {
+ if l.index < 0 {
+ fn.Locals[j] = l
+ j++
+ }
+ }
+ // Nil out fn.Locals[j:] to aid GC.
+ for i := j; i < len(fn.Locals); i++ {
+ fn.Locals[i] = nil
+ }
+ fn.Locals = fn.Locals[:j]
+}
+
+func phiIsLive(phi *Phi) bool {
+ for _, instr := range *phi.Referrers() {
+ if instr == phi {
+ continue // self-refs don't count
+ }
+ if _, ok := instr.(*DebugRef); ok {
+ continue // debug refs don't count
+ }
+ return true
+ }
+ return false
+}
+
+type blockSet struct{ big.Int } // (inherit methods from Int)
+
+// add adds b to the set and returns true if the set changed.
+func (s *blockSet) add(b *BasicBlock) bool {
+ i := b.Index
+ if s.Bit(i) != 0 {
+ return false
+ }
+ s.SetBit(&s.Int, i, 1)
+ return true
+}
+
+// take removes an arbitrary element from a set s and
+// returns its index, or returns -1 if empty.
+func (s *blockSet) take() int {
+ l := s.BitLen()
+ for i := 0; i < l; i++ {
+ if s.Bit(i) == 1 {
+ s.SetBit(&s.Int, i, 0)
+ return i
+ }
+ }
+ return -1
+}
+
+// newPhi is a pair of a newly introduced φ-node and the lifted Alloc
+// it replaces.
+type newPhi struct {
+ phi *Phi
+ alloc *Alloc
+}
+
+// newPhiMap records for each basic block, the set of newPhis that
+// must be prepended to the block.
+type newPhiMap map[*BasicBlock][]newPhi
+
+// liftAlloc determines whether alloc can be lifted into registers,
+// and if so, it populates newPhis with all the φ-nodes it may require
+// and returns true.
+//
+func liftAlloc(df domFrontier, alloc *Alloc, newPhis newPhiMap) bool {
+ // Don't lift aggregates into registers, because we don't have
+ // a way to express their zero-constants.
+ switch deref(alloc.Type()).Underlying().(type) {
+ case *types.Array, *types.Struct:
+ return false
+ }
+
+ // Don't lift named return values in functions that defer
+ // calls that may recover from panic.
+ if fn := alloc.Parent(); fn.Recover != nil {
+ for _, nr := range fn.namedResults {
+ if nr == alloc {
+ return false
+ }
+ }
+ }
+
+ // Compute defblocks, the set of blocks containing a
+ // definition of the alloc cell.
+ var defblocks blockSet
+ for _, instr := range *alloc.Referrers() {
+ // Bail out if we discover the alloc is not liftable;
+ // the only operations permitted to use the alloc are
+ // loads/stores into the cell, and DebugRef.
+ switch instr := instr.(type) {
+ case *Store:
+ if instr.Val == alloc {
+ return false // address used as value
+ }
+ if instr.Addr != alloc {
+ panic("Alloc.Referrers is inconsistent")
+ }
+ defblocks.add(instr.Block())
+ case *UnOp:
+ if instr.Op != token.MUL {
+ return false // not a load
+ }
+ if instr.X != alloc {
+ panic("Alloc.Referrers is inconsistent")
+ }
+ case *DebugRef:
+ // ok
+ default:
+ return false // some other instruction
+ }
+ }
+ // The Alloc itself counts as a (zero) definition of the cell.
+ defblocks.add(alloc.Block())
+
+ if debugLifting {
+ fmt.Fprintln(os.Stderr, "\tlifting ", alloc, alloc.Name())
+ }
+
+ fn := alloc.Parent()
+
+ // Φ-insertion.
+ //
+ // What follows is the body of the main loop of the insert-φ
+ // function described by Cytron et al, but instead of using
+ // counter tricks, we just reset the 'hasAlready' and 'work'
+ // sets each iteration. These are bitmaps so it's pretty cheap.
+ //
+ // TODO(adonovan): opt: recycle slice storage for W,
+ // hasAlready, defBlocks across liftAlloc calls.
+ var hasAlready blockSet
+
+ // Initialize W and work to defblocks.
+ var work blockSet = defblocks // blocks seen
+ var W blockSet // blocks to do
+ W.Set(&defblocks.Int)
+
+ // Traverse iterated dominance frontier, inserting φ-nodes.
+ for i := W.take(); i != -1; i = W.take() {
+ u := fn.Blocks[i]
+ for _, v := range df[u.Index] {
+ if hasAlready.add(v) {
+ // Create φ-node.
+ // It will be prepended to v.Instrs later, if needed.
+ phi := &Phi{
+ Edges: make([]Value, len(v.Preds)),
+ Comment: alloc.Comment,
+ }
+ phi.pos = alloc.Pos()
+ phi.setType(deref(alloc.Type()))
+ phi.block = v
+ if debugLifting {
+ fmt.Fprintf(os.Stderr, "\tplace %s = %s at block %s\n", phi.Name(), phi, v)
+ }
+ newPhis[v] = append(newPhis[v], newPhi{phi, alloc})
+
+ if work.add(v) {
+ W.add(v)
+ }
+ }
+ }
+ }
+
+ return true
+}
+
+// replaceAll replaces all intraprocedural uses of x with y,
+// updating x.Referrers and y.Referrers.
+// Precondition: x.Referrers() != nil, i.e. x must be local to some function.
+//
+func replaceAll(x, y Value) {
+ var rands []*Value
+ pxrefs := x.Referrers()
+ pyrefs := y.Referrers()
+ for _, instr := range *pxrefs {
+ rands = instr.Operands(rands[:0]) // recycle storage
+ for _, rand := range rands {
+ if *rand != nil {
+ if *rand == x {
+ *rand = y
+ }
+ }
+ }
+ if pyrefs != nil {
+ *pyrefs = append(*pyrefs, instr) // dups ok
+ }
+ }
+ *pxrefs = nil // x is now unreferenced
+}
+
+// renamed returns the value to which alloc is being renamed,
+// constructing it lazily if it's the implicit zero initialization.
+//
+func renamed(renaming []Value, alloc *Alloc) Value {
+ v := renaming[alloc.index]
+ if v == nil {
+ v = zeroConst(deref(alloc.Type()))
+ renaming[alloc.index] = v
+ }
+ return v
+}
+
+// rename implements the (Cytron et al) SSA renaming algorithm, a
+// preorder traversal of the dominator tree replacing all loads of
+// Alloc cells with the value stored to that cell by the dominating
+// store instruction. For lifting, we need only consider loads,
+// stores and φ-nodes.
+//
+// renaming is a map from *Alloc (keyed by index number) to its
+// dominating stored value; newPhis[x] is the set of new φ-nodes to be
+// prepended to block x.
+//
+func rename(u *BasicBlock, renaming []Value, newPhis newPhiMap) {
+ // Each φ-node becomes the new name for its associated Alloc.
+ for _, np := range newPhis[u] {
+ phi := np.phi
+ alloc := np.alloc
+ renaming[alloc.index] = phi
+ }
+
+ // Rename loads and stores of allocs.
+ for i, instr := range u.Instrs {
+ switch instr := instr.(type) {
+ case *Alloc:
+ if instr.index >= 0 { // store of zero to Alloc cell
+ // Replace dominated loads by the zero value.
+ renaming[instr.index] = nil
+ if debugLifting {
+ fmt.Fprintf(os.Stderr, "\tkill alloc %s\n", instr)
+ }
+ // Delete the Alloc.
+ u.Instrs[i] = nil
+ u.gaps++
+ }
+
+ case *Store:
+ if alloc, ok := instr.Addr.(*Alloc); ok && alloc.index >= 0 { // store to Alloc cell
+ // Replace dominated loads by the stored value.
+ renaming[alloc.index] = instr.Val
+ if debugLifting {
+ fmt.Fprintf(os.Stderr, "\tkill store %s; new value: %s\n",
+ instr, instr.Val.Name())
+ }
+ // Remove the store from the referrer list of the stored value.
+ if refs := instr.Val.Referrers(); refs != nil {
+ *refs = removeInstr(*refs, instr)
+ }
+ // Delete the Store.
+ u.Instrs[i] = nil
+ u.gaps++
+ }
+
+ case *UnOp:
+ if instr.Op == token.MUL {
+ if alloc, ok := instr.X.(*Alloc); ok && alloc.index >= 0 { // load of Alloc cell
+ newval := renamed(renaming, alloc)
+ if debugLifting {
+ fmt.Fprintf(os.Stderr, "\tupdate load %s = %s with %s\n",
+ instr.Name(), instr, newval.Name())
+ }
+ // Replace all references to
+ // the loaded value by the
+ // dominating stored value.
+ replaceAll(instr, newval)
+ // Delete the Load.
+ u.Instrs[i] = nil
+ u.gaps++
+ }
+ }
+
+ case *DebugRef:
+ if alloc, ok := instr.X.(*Alloc); ok && alloc.index >= 0 { // ref of Alloc cell
+ if instr.IsAddr {
+ instr.X = renamed(renaming, alloc)
+ instr.IsAddr = false
+
+ // Add DebugRef to instr.X's referrers.
+ if refs := instr.X.Referrers(); refs != nil {
+ *refs = append(*refs, instr)
+ }
+ } else {
+ // A source expression denotes the address
+ // of an Alloc that was optimized away.
+ instr.X = nil
+
+ // Delete the DebugRef.
+ u.Instrs[i] = nil
+ u.gaps++
+ }
+ }
+ }
+ }
+
+ // For each φ-node in a CFG successor, rename the edge.
+ for _, v := range u.Succs {
+ phis := newPhis[v]
+ if len(phis) == 0 {
+ continue
+ }
+ i := v.predIndex(u)
+ for _, np := range phis {
+ phi := np.phi
+ alloc := np.alloc
+ newval := renamed(renaming, alloc)
+ if debugLifting {
+ fmt.Fprintf(os.Stderr, "\tsetphi %s edge %s -> %s (#%d) (alloc=%s) := %s\n",
+ phi.Name(), u, v, i, alloc.Name(), newval.Name())
+ }
+ phi.Edges[i] = newval
+ if prefs := newval.Referrers(); prefs != nil {
+ *prefs = append(*prefs, phi)
+ }
+ }
+ }
+
+ // Continue depth-first recursion over domtree, pushing a
+ // fresh copy of the renaming map for each subtree.
+ for _, v := range u.dom.children {
+ // TODO(adonovan): opt: avoid copy on final iteration; use destructive update.
+ r := make([]Value, len(renaming))
+ copy(r, renaming)
+ rename(v, r, newPhis)
+ }
+}
diff --git a/go/ssa/lvalue.go b/go/ssa/lvalue.go
new file mode 100644
index 0000000..4284b1c
--- /dev/null
+++ b/go/ssa/lvalue.go
@@ -0,0 +1,121 @@
+// 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 ssa
+
+// lvalues are the union of addressable expressions and map-index
+// expressions.
+
+import (
+ "go/ast"
+ "go/token"
+
+ "golang.org/x/tools/go/types"
+)
+
+// An lvalue represents an assignable location that may appear on the
+// left-hand side of an assignment. This is a generalization of a
+// pointer to permit updates to elements of maps.
+//
+type lvalue interface {
+ store(fn *Function, v Value) // stores v into the location
+ load(fn *Function) Value // loads the contents of the location
+ address(fn *Function) Value // address of the location
+ typ() types.Type // returns the type of the location
+}
+
+// An address is an lvalue represented by a true pointer.
+type address struct {
+ addr Value
+ pos token.Pos // source position
+ expr ast.Expr // source syntax of the value (not address) [debug mode]
+}
+
+func (a *address) load(fn *Function) Value {
+ load := emitLoad(fn, a.addr)
+ load.pos = a.pos
+ return load
+}
+
+func (a *address) store(fn *Function, v Value) {
+ store := emitStore(fn, a.addr, v, a.pos)
+ if a.expr != nil {
+ // store.Val is v, converted for assignability.
+ emitDebugRef(fn, a.expr, store.Val, false)
+ }
+}
+
+func (a *address) address(fn *Function) Value {
+ if a.expr != nil {
+ emitDebugRef(fn, a.expr, a.addr, true)
+ }
+ return a.addr
+}
+
+func (a *address) typ() types.Type {
+ return deref(a.addr.Type())
+}
+
+// An element is an lvalue represented by m[k], the location of an
+// element of a map or string. These locations are not addressable
+// since pointers cannot be formed from them, but they do support
+// load(), and in the case of maps, store().
+//
+type element struct {
+ m, k Value // map or string
+ t types.Type // map element type or string byte type
+ pos token.Pos // source position of colon ({k:v}) or lbrack (m[k]=v)
+}
+
+func (e *element) load(fn *Function) Value {
+ l := &Lookup{
+ X: e.m,
+ Index: e.k,
+ }
+ l.setPos(e.pos)
+ l.setType(e.t)
+ return fn.emit(l)
+}
+
+func (e *element) store(fn *Function, v Value) {
+ up := &MapUpdate{
+ Map: e.m,
+ Key: e.k,
+ Value: emitConv(fn, v, e.t),
+ }
+ up.pos = e.pos
+ fn.emit(up)
+}
+
+func (e *element) address(fn *Function) Value {
+ panic("map/string elements are not addressable")
+}
+
+func (e *element) typ() types.Type {
+ return e.t
+}
+
+// A blank is a dummy variable whose name is "_".
+// It is not reified: loads are illegal and stores are ignored.
+//
+type blank struct{}
+
+func (bl blank) load(fn *Function) Value {
+ panic("blank.load is illegal")
+}
+
+func (bl blank) store(fn *Function, v Value) {
+ // no-op
+}
+
+func (bl blank) address(fn *Function) Value {
+ panic("blank var is not addressable")
+}
+
+func (bl blank) typ() types.Type {
+ // This should be the type of the blank Ident; the typechecker
+ // doesn't provide this yet, but fortunately, we don't need it
+ // yet either.
+ panic("blank.typ is unimplemented")
+}
diff --git a/go/ssa/methods.go b/go/ssa/methods.go
new file mode 100644
index 0000000..12534de
--- /dev/null
+++ b/go/ssa/methods.go
@@ -0,0 +1,243 @@
+// 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 ssa
+
+// This file defines utilities for population of method sets.
+
+import (
+ "fmt"
+
+ "golang.org/x/tools/go/types"
+)
+
+// Method returns the Function implementing method sel, building
+// wrapper methods on demand. It returns nil if sel denotes an
+// abstract (interface) method.
+//
+// Precondition: sel.Kind() == MethodVal.
+//
+// TODO(adonovan): rename this to MethodValue because of the
+// precondition, and for consistency with functions in source.go.
+//
+// Thread-safe.
+//
+// EXCLUSIVE_LOCKS_ACQUIRED(prog.methodsMu)
+//
+func (prog *Program) Method(sel *types.Selection) *Function {
+ if sel.Kind() != types.MethodVal {
+ panic(fmt.Sprintf("Method(%s) kind != MethodVal", sel))
+ }
+ T := sel.Recv()
+ if isInterface(T) {
+ return nil // abstract method
+ }
+ if prog.mode&LogSource != 0 {
+ defer logStack("Method %s %v", T, sel)()
+ }
+
+ prog.methodsMu.Lock()
+ defer prog.methodsMu.Unlock()
+
+ return prog.addMethod(prog.createMethodSet(T), sel)
+}
+
+// LookupMethod returns the implementation of the method of type T
+// identified by (pkg, name). It returns nil if the method exists but
+// is abstract, and panics if T has no such method.
+//
+func (prog *Program) LookupMethod(T types.Type, pkg *types.Package, name string) *Function {
+ sel := prog.MethodSets.MethodSet(T).Lookup(pkg, name)
+ if sel == nil {
+ panic(fmt.Sprintf("%s has no method %s", T, types.Id(pkg, name)))
+ }
+ return prog.Method(sel)
+}
+
+// methodSet contains the (concrete) methods of a non-interface type.
+type methodSet struct {
+ mapping map[string]*Function // populated lazily
+ complete bool // mapping contains all methods
+}
+
+// Precondition: !isInterface(T).
+// EXCLUSIVE_LOCKS_REQUIRED(prog.methodsMu)
+func (prog *Program) createMethodSet(T types.Type) *methodSet {
+ mset, ok := prog.methodSets.At(T).(*methodSet)
+ if !ok {
+ mset = &methodSet{mapping: make(map[string]*Function)}
+ prog.methodSets.Set(T, mset)
+ }
+ return mset
+}
+
+// EXCLUSIVE_LOCKS_REQUIRED(prog.methodsMu)
+func (prog *Program) addMethod(mset *methodSet, sel *types.Selection) *Function {
+ if sel.Kind() == types.MethodExpr {
+ panic(sel)
+ }
+ id := sel.Obj().Id()
+ fn := mset.mapping[id]
+ if fn == nil {
+ obj := sel.Obj().(*types.Func)
+
+ needsPromotion := len(sel.Index()) > 1
+ needsIndirection := !isPointer(recvType(obj)) && isPointer(sel.Recv())
+ if needsPromotion || needsIndirection {
+ fn = makeWrapper(prog, sel)
+ } else {
+ fn = prog.declaredFunc(obj)
+ }
+ if fn.Signature.Recv() == nil {
+ panic(fn) // missing receiver
+ }
+ mset.mapping[id] = fn
+ }
+ return fn
+}
+
+// RuntimeTypes returns a new unordered slice containing all
+// concrete types in the program for which a complete (non-empty)
+// method set is required at run-time.
+//
+// Thread-safe.
+//
+// EXCLUSIVE_LOCKS_ACQUIRED(prog.methodsMu)
+//
+func (prog *Program) RuntimeTypes() []types.Type {
+ prog.methodsMu.Lock()
+ defer prog.methodsMu.Unlock()
+
+ var res []types.Type
+ prog.methodSets.Iterate(func(T types.Type, v interface{}) {
+ if v.(*methodSet).complete {
+ res = append(res, T)
+ }
+ })
+ return res
+}
+
+// declaredFunc returns the concrete function/method denoted by obj.
+// Panic ensues if there is none.
+//
+func (prog *Program) declaredFunc(obj *types.Func) *Function {
+ if v := prog.packageLevelValue(obj); v != nil {
+ return v.(*Function)
+ }
+ panic("no concrete method: " + obj.String())
+}
+
+// needMethodsOf ensures that runtime type information (including the
+// complete method set) is available for the specified type T and all
+// its subcomponents.
+//
+// needMethodsOf must be called for at least every type that is an
+// operand of some MakeInterface instruction, and for the type of
+// every exported package member.
+//
+// Precondition: T is not a method signature (*Signature with Recv()!=nil).
+//
+// Thread-safe. (Called via emitConv from multiple builder goroutines.)
+//
+// TODO(adonovan): make this faster. It accounts for 20% of SSA build time.
+//
+// EXCLUSIVE_LOCKS_ACQUIRED(prog.methodsMu)
+//
+func (prog *Program) needMethodsOf(T types.Type) {
+ prog.methodsMu.Lock()
+ prog.needMethods(T, false)
+ prog.methodsMu.Unlock()
+}
+
+// Precondition: T is not a method signature (*Signature with Recv()!=nil).
+// Recursive case: skip => don't create methods for T.
+//
+// EXCLUSIVE_LOCKS_REQUIRED(prog.methodsMu)
+//
+func (prog *Program) needMethods(T types.Type, skip bool) {
+ // Each package maintains its own set of types it has visited.
+ if prevSkip, ok := prog.runtimeTypes.At(T).(bool); ok {
+ // needMethods(T) was previously called
+ if !prevSkip || skip {
+ return // already seen, with same or false 'skip' value
+ }
+ }
+ prog.runtimeTypes.Set(T, skip)
+
+ tmset := prog.MethodSets.MethodSet(T)
+
+ if !skip && !isInterface(T) && tmset.Len() > 0 {
+ // Create methods of T.
+ mset := prog.createMethodSet(T)
+ if !mset.complete {
+ mset.complete = true
+ n := tmset.Len()
+ for i := 0; i < n; i++ {
+ prog.addMethod(mset, tmset.At(i))
+ }
+ }
+ }
+
+ // Recursion over signatures of each method.
+ for i := 0; i < tmset.Len(); i++ {
+ sig := tmset.At(i).Type().(*types.Signature)
+ prog.needMethods(sig.Params(), false)
+ prog.needMethods(sig.Results(), false)
+ }
+
+ switch t := T.(type) {
+ case *types.Basic:
+ // nop
+
+ case *types.Interface:
+ // nop---handled by recursion over method set.
+
+ case *types.Pointer:
+ prog.needMethods(t.Elem(), false)
+
+ case *types.Slice:
+ prog.needMethods(t.Elem(), false)
+
+ case *types.Chan:
+ prog.needMethods(t.Elem(), false)
+
+ case *types.Map:
+ prog.needMethods(t.Key(), false)
+ prog.needMethods(t.Elem(), false)
+
+ case *types.Signature:
+ if t.Recv() != nil {
+ panic(fmt.Sprintf("Signature %s has Recv %s", t, t.Recv()))
+ }
+ prog.needMethods(t.Params(), false)
+ prog.needMethods(t.Results(), false)
+
+ case *types.Named:
+ // A pointer-to-named type can be derived from a named
+ // type via reflection. It may have methods too.
+ prog.needMethods(types.NewPointer(T), false)
+
+ // Consider 'type T struct{S}' where S has methods.
+ // Reflection provides no way to get from T to struct{S},
+ // only to S, so the method set of struct{S} is unwanted,
+ // so set 'skip' flag during recursion.
+ prog.needMethods(t.Underlying(), true)
+
+ case *types.Array:
+ prog.needMethods(t.Elem(), false)
+
+ case *types.Struct:
+ for i, n := 0, t.NumFields(); i < n; i++ {
+ prog.needMethods(t.Field(i).Type(), false)
+ }
+
+ case *types.Tuple:
+ for i, n := 0, t.Len(); i < n; i++ {
+ prog.needMethods(t.At(i).Type(), false)
+ }
+
+ default:
+ panic(T)
+ }
+}
diff --git a/go/ssa/mode.go b/go/ssa/mode.go
new file mode 100644
index 0000000..bbd613a
--- /dev/null
+++ b/go/ssa/mode.go
@@ -0,0 +1,107 @@
+// 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 ssa
+
+// This file defines the BuilderMode type and its command-line flag.
+
+import (
+ "bytes"
+ "flag"
+ "fmt"
+)
+
+// BuilderMode is a bitmask of options for diagnostics and checking.
+type BuilderMode uint
+
+const (
+ PrintPackages BuilderMode = 1 << iota // Print package inventory to stdout
+ PrintFunctions // Print function SSA code to stdout
+ LogSource // Log source locations as SSA builder progresses
+ SanityCheckFunctions // Perform sanity checking of function bodies
+ NaiveForm // Build naïve SSA form: don't replace local loads/stores with registers
+ BuildSerially // Build packages serially, not in parallel.
+ GlobalDebug // Enable debug info for all packages
+ BareInits // Build init functions without guards or calls to dependent inits
+)
+
+const modeFlagUsage = `Options controlling the SSA builder.
+The value is a sequence of zero or more of these letters:
+C perform sanity [C]hecking of the SSA form.
+D include [D]ebug info for every function.
+P print [P]ackage inventory.
+F print [F]unction SSA code.
+S log [S]ource locations as SSA builder progresses.
+L build distinct packages seria[L]ly instead of in parallel.
+N build [N]aive SSA form: don't replace local loads/stores with registers.
+I build bare [I]nit functions: no init guards or calls to dependent inits.
+`
+
+// BuilderModeFlag creates a new command line flag of type BuilderMode,
+// adds it to the specified flag set, and returns it.
+//
+// Example:
+// var ssabuild = BuilderModeFlag(flag.CommandLine, "ssabuild", 0)
+//
+func BuilderModeFlag(set *flag.FlagSet, name string, value BuilderMode) *BuilderMode {
+ set.Var((*builderModeValue)(&value), name, modeFlagUsage)
+ return &value
+}
+
+type builderModeValue BuilderMode // satisfies flag.Value and flag.Getter.
+
+func (v *builderModeValue) Set(s string) error {
+ var mode BuilderMode
+ for _, c := range s {
+ switch c {
+ case 'D':
+ mode |= GlobalDebug
+ case 'P':
+ mode |= PrintPackages
+ case 'F':
+ mode |= PrintFunctions
+ case 'S':
+ mode |= LogSource | BuildSerially
+ case 'C':
+ mode |= SanityCheckFunctions
+ case 'N':
+ mode |= NaiveForm
+ case 'L':
+ mode |= BuildSerially
+ default:
+ return fmt.Errorf("unknown BuilderMode option: %q", c)
+ }
+ }
+ *v = builderModeValue(mode)
+ return nil
+}
+
+func (v *builderModeValue) Get() interface{} { return BuilderMode(*v) }
+
+func (v *builderModeValue) String() string {
+ mode := BuilderMode(*v)
+ var buf bytes.Buffer
+ if mode&GlobalDebug != 0 {
+ buf.WriteByte('D')
+ }
+ if mode&PrintPackages != 0 {
+ buf.WriteByte('P')
+ }
+ if mode&PrintFunctions != 0 {
+ buf.WriteByte('F')
+ }
+ if mode&LogSource != 0 {
+ buf.WriteByte('S')
+ }
+ if mode&SanityCheckFunctions != 0 {
+ buf.WriteByte('C')
+ }
+ if mode&NaiveForm != 0 {
+ buf.WriteByte('N')
+ }
+ if mode&BuildSerially != 0 {
+ buf.WriteByte('L')
+ }
+ return buf.String()
+}
diff --git a/go/ssa/print.go b/go/ssa/print.go
new file mode 100644
index 0000000..88c31f6
--- /dev/null
+++ b/go/ssa/print.go
@@ -0,0 +1,427 @@
+// 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 ssa
+
+// This file implements the String() methods for all Value and
+// Instruction types.
+
+import (
+ "bytes"
+ "fmt"
+ "io"
+ "reflect"
+ "sort"
+
+ "golang.org/x/tools/go/types"
+ "golang.org/x/tools/go/types/typeutil"
+)
+
+// relName returns the name of v relative to i.
+// In most cases, this is identical to v.Name(), but references to
+// Functions (including methods) and Globals use RelString and
+// all types are displayed with relType, so that only cross-package
+// references are package-qualified.
+//
+func relName(v Value, i Instruction) string {
+ var from *types.Package
+ if i != nil {
+ from = i.Parent().pkgobj()
+ }
+ switch v := v.(type) {
+ case Member: // *Function or *Global
+ return v.RelString(from)
+ case *Const:
+ return v.RelString(from)
+ }
+ return v.Name()
+}
+
+func relType(t types.Type, from *types.Package) string {
+ return types.TypeString(t, types.RelativeTo(from))
+}
+
+func relString(m Member, from *types.Package) string {
+ // NB: not all globals have an Object (e.g. init$guard),
+ // so use Package().Object not Object.Package().
+ if obj := m.Package().Object; obj != nil && obj != from {
+ return fmt.Sprintf("%s.%s", obj.Path(), m.Name())
+ }
+ return m.Name()
+}
+
+// Value.String()
+//
+// This method is provided only for debugging.
+// It never appears in disassembly, which uses Value.Name().
+
+func (v *Parameter) String() string {
+ from := v.Parent().pkgobj()
+ return fmt.Sprintf("parameter %s : %s", v.Name(), relType(v.Type(), from))
+}
+
+func (v *FreeVar) String() string {
+ from := v.Parent().pkgobj()
+ return fmt.Sprintf("freevar %s : %s", v.Name(), relType(v.Type(), from))
+}
+
+func (v *Builtin) String() string {
+ return fmt.Sprintf("builtin %s", v.Name())
+}
+
+// Instruction.String()
+
+func (v *Alloc) String() string {
+ op := "local"
+ if v.Heap {
+ op = "new"
+ }
+ from := v.Parent().pkgobj()
+ return fmt.Sprintf("%s %s (%s)", op, relType(deref(v.Type()), from), v.Comment)
+}
+
+func (v *Phi) String() string {
+ var b bytes.Buffer
+ b.WriteString("phi [")
+ for i, edge := range v.Edges {
+ if i > 0 {
+ b.WriteString(", ")
+ }
+ // Be robust against malformed CFG.
+ block := -1
+ if v.block != nil && i < len(v.block.Preds) {
+ block = v.block.Preds[i].Index
+ }
+ fmt.Fprintf(&b, "%d: ", block)
+ edgeVal := "<nil>" // be robust
+ if edge != nil {
+ edgeVal = relName(edge, v)
+ }
+ b.WriteString(edgeVal)
+ }
+ b.WriteString("]")
+ if v.Comment != "" {
+ b.WriteString(" #")
+ b.WriteString(v.Comment)
+ }
+ return b.String()
+}
+
+func printCall(v *CallCommon, prefix string, instr Instruction) string {
+ var b bytes.Buffer
+ b.WriteString(prefix)
+ if !v.IsInvoke() {
+ b.WriteString(relName(v.Value, instr))
+ } else {
+ fmt.Fprintf(&b, "invoke %s.%s", relName(v.Value, instr), v.Method.Name())
+ }
+ b.WriteString("(")
+ for i, arg := range v.Args {
+ if i > 0 {
+ b.WriteString(", ")
+ }
+ b.WriteString(relName(arg, instr))
+ }
+ if v.Signature().Variadic() {
+ b.WriteString("...")
+ }
+ b.WriteString(")")
+ return b.String()
+}
+
+func (c *CallCommon) String() string {
+ return printCall(c, "", nil)
+}
+
+func (v *Call) String() string {
+ return printCall(&v.Call, "", v)
+}
+
+func (v *BinOp) String() string {
+ return fmt.Sprintf("%s %s %s", relName(v.X, v), v.Op.String(), relName(v.Y, v))
+}
+
+func (v *UnOp) String() string {
+ return fmt.Sprintf("%s%s%s", v.Op, relName(v.X, v), commaOk(v.CommaOk))
+}
+
+func printConv(prefix string, v, x Value) string {
+ from := v.Parent().pkgobj()
+ return fmt.Sprintf("%s %s <- %s (%s)",
+ prefix,
+ relType(v.Type(), from),
+ relType(x.Type(), from),
+ relName(x, v.(Instruction)))
+}
+
+func (v *ChangeType) String() string { return printConv("changetype", v, v.X) }
+func (v *Convert) String() string { return printConv("convert", v, v.X) }
+func (v *ChangeInterface) String() string { return printConv("change interface", v, v.X) }
+func (v *MakeInterface) String() string { return printConv("make", v, v.X) }
+
+func (v *MakeClosure) String() string {
+ var b bytes.Buffer
+ fmt.Fprintf(&b, "make closure %s", relName(v.Fn, v))
+ if v.Bindings != nil {
+ b.WriteString(" [")
+ for i, c := range v.Bindings {
+ if i > 0 {
+ b.WriteString(", ")
+ }
+ b.WriteString(relName(c, v))
+ }
+ b.WriteString("]")
+ }
+ return b.String()
+}
+
+func (v *MakeSlice) String() string {
+ from := v.Parent().pkgobj()
+ return fmt.Sprintf("make %s %s %s",
+ relType(v.Type(), from),
+ relName(v.Len, v),
+ relName(v.Cap, v))
+}
+
+func (v *Slice) String() string {
+ var b bytes.Buffer
+ b.WriteString("slice ")
+ b.WriteString(relName(v.X, v))
+ b.WriteString("[")
+ if v.Low != nil {
+ b.WriteString(relName(v.Low, v))
+ }
+ b.WriteString(":")
+ if v.High != nil {
+ b.WriteString(relName(v.High, v))
+ }
+ if v.Max != nil {
+ b.WriteString(":")
+ b.WriteString(relName(v.Max, v))
+ }
+ b.WriteString("]")
+ return b.String()
+}
+
+func (v *MakeMap) String() string {
+ res := ""
+ if v.Reserve != nil {
+ res = relName(v.Reserve, v)
+ }
+ from := v.Parent().pkgobj()
+ return fmt.Sprintf("make %s %s", relType(v.Type(), from), res)
+}
+
+func (v *MakeChan) String() string {
+ from := v.Parent().pkgobj()
+ return fmt.Sprintf("make %s %s", relType(v.Type(), from), relName(v.Size, v))
+}
+
+func (v *FieldAddr) String() string {
+ st := deref(v.X.Type()).Underlying().(*types.Struct)
+ // Be robust against a bad index.
+ name := "?"
+ if 0 <= v.Field && v.Field < st.NumFields() {
+ name = st.Field(v.Field).Name()
+ }
+ return fmt.Sprintf("&%s.%s [#%d]", relName(v.X, v), name, v.Field)
+}
+
+func (v *Field) String() string {
+ st := v.X.Type().Underlying().(*types.Struct)
+ // Be robust against a bad index.
+ name := "?"
+ if 0 <= v.Field && v.Field < st.NumFields() {
+ name = st.Field(v.Field).Name()
+ }
+ return fmt.Sprintf("%s.%s [#%d]", relName(v.X, v), name, v.Field)
+}
+
+func (v *IndexAddr) String() string {
+ return fmt.Sprintf("&%s[%s]", relName(v.X, v), relName(v.Index, v))
+}
+
+func (v *Index) String() string {
+ return fmt.Sprintf("%s[%s]", relName(v.X, v), relName(v.Index, v))
+}
+
+func (v *Lookup) String() string {
+ return fmt.Sprintf("%s[%s]%s", relName(v.X, v), relName(v.Index, v), commaOk(v.CommaOk))
+}
+
+func (v *Range) String() string {
+ return "range " + relName(v.X, v)
+}
+
+func (v *Next) String() string {
+ return "next " + relName(v.Iter, v)
+}
+
+func (v *TypeAssert) String() string {
+ from := v.Parent().pkgobj()
+ return fmt.Sprintf("typeassert%s %s.(%s)", commaOk(v.CommaOk), relName(v.X, v), relType(v.AssertedType, from))
+}
+
+func (v *Extract) String() string {
+ return fmt.Sprintf("extract %s #%d", relName(v.Tuple, v), v.Index)
+}
+
+func (s *Jump) String() string {
+ // Be robust against malformed CFG.
+ block := -1
+ if s.block != nil && len(s.block.Succs) == 1 {
+ block = s.block.Succs[0].Index
+ }
+ return fmt.Sprintf("jump %d", block)
+}
+
+func (s *If) String() string {
+ // Be robust against malformed CFG.
+ tblock, fblock := -1, -1
+ if s.block != nil && len(s.block.Succs) == 2 {
+ tblock = s.block.Succs[0].Index
+ fblock = s.block.Succs[1].Index
+ }
+ return fmt.Sprintf("if %s goto %d else %d", relName(s.Cond, s), tblock, fblock)
+}
+
+func (s *Go) String() string {
+ return printCall(&s.Call, "go ", s)
+}
+
+func (s *Panic) String() string {
+ return "panic " + relName(s.X, s)
+}
+
+func (s *Return) String() string {
+ var b bytes.Buffer
+ b.WriteString("return")
+ for i, r := range s.Results {
+ if i == 0 {
+ b.WriteString(" ")
+ } else {
+ b.WriteString(", ")
+ }
+ b.WriteString(relName(r, s))
+ }
+ return b.String()
+}
+
+func (*RunDefers) String() string {
+ return "rundefers"
+}
+
+func (s *Send) String() string {
+ return fmt.Sprintf("send %s <- %s", relName(s.Chan, s), relName(s.X, s))
+}
+
+func (s *Defer) String() string {
+ return printCall(&s.Call, "defer ", s)
+}
+
+func (s *Select) String() string {
+ var b bytes.Buffer
+ for i, st := range s.States {
+ if i > 0 {
+ b.WriteString(", ")
+ }
+ if st.Dir == types.RecvOnly {
+ b.WriteString("<-")
+ b.WriteString(relName(st.Chan, s))
+ } else {
+ b.WriteString(relName(st.Chan, s))
+ b.WriteString("<-")
+ b.WriteString(relName(st.Send, s))
+ }
+ }
+ non := ""
+ if !s.Blocking {
+ non = "non"
+ }
+ return fmt.Sprintf("select %sblocking [%s]", non, b.String())
+}
+
+func (s *Store) String() string {
+ return fmt.Sprintf("*%s = %s", relName(s.Addr, s), relName(s.Val, s))
+}
+
+func (s *MapUpdate) String() string {
+ return fmt.Sprintf("%s[%s] = %s", relName(s.Map, s), relName(s.Key, s), relName(s.Value, s))
+}
+
+func (s *DebugRef) String() string {
+ p := s.Parent().Prog.Fset.Position(s.Pos())
+ var descr interface{}
+ if s.object != nil {
+ descr = s.object // e.g. "var x int"
+ } else {
+ descr = reflect.TypeOf(s.Expr) // e.g. "*ast.CallExpr"
+ }
+ var addr string
+ if s.IsAddr {
+ addr = "address of "
+ }
+ return fmt.Sprintf("; %s%s @ %d:%d is %s", addr, descr, p.Line, p.Column, s.X.Name())
+}
+
+func (p *Package) String() string {
+ return "package " + p.Object.Path()
+}
+
+var _ io.WriterTo = (*Package)(nil) // *Package implements io.Writer
+
+func (p *Package) WriteTo(w io.Writer) (int64, error) {
+ var buf bytes.Buffer
+ WritePackage(&buf, p)
+ n, err := w.Write(buf.Bytes())
+ return int64(n), err
+}
+
+// WritePackage writes to buf a human-readable summary of p.
+func WritePackage(buf *bytes.Buffer, p *Package) {
+ fmt.Fprintf(buf, "%s:\n", p)
+
+ var names []string
+ maxname := 0
+ for name := range p.Members {
+ if l := len(name); l > maxname {
+ maxname = l
+ }
+ names = append(names, name)
+ }
+
+ from := p.Object
+ sort.Strings(names)
+ for _, name := range names {
+ switch mem := p.Members[name].(type) {
+ case *NamedConst:
+ fmt.Fprintf(buf, " const %-*s %s = %s\n",
+ maxname, name, mem.Name(), mem.Value.RelString(from))
+
+ case *Function:
+ fmt.Fprintf(buf, " func %-*s %s\n",
+ maxname, name, relType(mem.Type(), from))
+
+ case *Type:
+ fmt.Fprintf(buf, " type %-*s %s\n",
+ maxname, name, relType(mem.Type().Underlying(), from))
+ for _, meth := range typeutil.IntuitiveMethodSet(mem.Type(), &p.Prog.MethodSets) {
+ fmt.Fprintf(buf, " %s\n", types.SelectionString(meth, types.RelativeTo(from)))
+ }
+
+ case *Global:
+ fmt.Fprintf(buf, " var %-*s %s\n",
+ maxname, name, relType(mem.Type().(*types.Pointer).Elem(), from))
+ }
+ }
+
+ fmt.Fprintf(buf, "\n")
+}
+
+func commaOk(x bool) string {
+ if x {
+ return ",ok"
+ }
+ return ""
+}
diff --git a/go/ssa/sanity.go b/go/ssa/sanity.go
new file mode 100644
index 0000000..b0593d0
--- /dev/null
+++ b/go/ssa/sanity.go
@@ -0,0 +1,520 @@
+// 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 ssa
+
+// An optional pass for sanity-checking invariants of the SSA representation.
+// Currently it checks CFG invariants but little at the instruction level.
+
+import (
+ "fmt"
+ "io"
+ "os"
+ "strings"
+
+ "golang.org/x/tools/go/types"
+)
+
+type sanity struct {
+ reporter io.Writer
+ fn *Function
+ block *BasicBlock
+ instrs map[Instruction]struct{}
+ insane bool
+}
+
+// sanityCheck performs integrity checking of the SSA representation
+// of the function fn and returns true if it was valid. Diagnostics
+// are written to reporter if non-nil, os.Stderr otherwise. Some
+// diagnostics are only warnings and do not imply a negative result.
+//
+// Sanity-checking is intended to facilitate the debugging of code
+// transformation passes.
+//
+func sanityCheck(fn *Function, reporter io.Writer) bool {
+ if reporter == nil {
+ reporter = os.Stderr
+ }
+ return (&sanity{reporter: reporter}).checkFunction(fn)
+}
+
+// mustSanityCheck is like sanityCheck but panics instead of returning
+// a negative result.
+//
+func mustSanityCheck(fn *Function, reporter io.Writer) {
+ if !sanityCheck(fn, reporter) {
+ fn.WriteTo(os.Stderr)
+ panic("SanityCheck failed")
+ }
+}
+
+func (s *sanity) diagnostic(prefix, format string, args ...interface{}) {
+ fmt.Fprintf(s.reporter, "%s: function %s", prefix, s.fn)
+ if s.block != nil {
+ fmt.Fprintf(s.reporter, ", block %s", s.block)
+ }
+ io.WriteString(s.reporter, ": ")
+ fmt.Fprintf(s.reporter, format, args...)
+ io.WriteString(s.reporter, "\n")
+}
+
+func (s *sanity) errorf(format string, args ...interface{}) {
+ s.insane = true
+ s.diagnostic("Error", format, args...)
+}
+
+func (s *sanity) warnf(format string, args ...interface{}) {
+ s.diagnostic("Warning", format, args...)
+}
+
+// findDuplicate returns an arbitrary basic block that appeared more
+// than once in blocks, or nil if all were unique.
+func findDuplicate(blocks []*BasicBlock) *BasicBlock {
+ if len(blocks) < 2 {
+ return nil
+ }
+ if blocks[0] == blocks[1] {
+ return blocks[0]
+ }
+ // Slow path:
+ m := make(map[*BasicBlock]bool)
+ for _, b := range blocks {
+ if m[b] {
+ return b
+ }
+ m[b] = true
+ }
+ return nil
+}
+
+func (s *sanity) checkInstr(idx int, instr Instruction) {
+ switch instr := instr.(type) {
+ case *If, *Jump, *Return, *Panic:
+ s.errorf("control flow instruction not at end of block")
+ case *Phi:
+ if idx == 0 {
+ // It suffices to apply this check to just the first phi node.
+ if dup := findDuplicate(s.block.Preds); dup != nil {
+ s.errorf("phi node in block with duplicate predecessor %s", dup)
+ }
+ } else {
+ prev := s.block.Instrs[idx-1]
+ if _, ok := prev.(*Phi); !ok {
+ s.errorf("Phi instruction follows a non-Phi: %T", prev)
+ }
+ }
+ if ne, np := len(instr.Edges), len(s.block.Preds); ne != np {
+ s.errorf("phi node has %d edges but %d predecessors", ne, np)
+
+ } else {
+ for i, e := range instr.Edges {
+ if e == nil {
+ s.errorf("phi node '%s' has no value for edge #%d from %s", instr.Comment, i, s.block.Preds[i])
+ }
+ }
+ }
+
+ case *Alloc:
+ if !instr.Heap {
+ found := false
+ for _, l := range s.fn.Locals {
+ if l == instr {
+ found = true
+ break
+ }
+ }
+ if !found {
+ s.errorf("local alloc %s = %s does not appear in Function.Locals", instr.Name(), instr)
+ }
+ }
+
+ case *BinOp:
+ case *Call:
+ case *ChangeInterface:
+ case *ChangeType:
+ case *Convert:
+ if _, ok := instr.X.Type().Underlying().(*types.Basic); !ok {
+ if _, ok := instr.Type().Underlying().(*types.Basic); !ok {
+ s.errorf("convert %s -> %s: at least one type must be basic", instr.X.Type(), instr.Type())
+ }
+ }
+
+ case *Defer:
+ case *Extract:
+ case *Field:
+ case *FieldAddr:
+ case *Go:
+ case *Index:
+ case *IndexAddr:
+ case *Lookup:
+ case *MakeChan:
+ case *MakeClosure:
+ numFree := len(instr.Fn.(*Function).FreeVars)
+ numBind := len(instr.Bindings)
+ if numFree != numBind {
+ s.errorf("MakeClosure has %d Bindings for function %s with %d free vars",
+ numBind, instr.Fn, numFree)
+
+ }
+ if recv := instr.Type().(*types.Signature).Recv(); recv != nil {
+ s.errorf("MakeClosure's type includes receiver %s", recv.Type())
+ }
+
+ case *MakeInterface:
+ case *MakeMap:
+ case *MakeSlice:
+ case *MapUpdate:
+ case *Next:
+ case *Range:
+ case *RunDefers:
+ case *Select:
+ case *Send:
+ case *Slice:
+ case *Store:
+ case *TypeAssert:
+ case *UnOp:
+ case *DebugRef:
+ // TODO(adonovan): implement checks.
+ default:
+ panic(fmt.Sprintf("Unknown instruction type: %T", instr))
+ }
+
+ if call, ok := instr.(CallInstruction); ok {
+ if call.Common().Signature() == nil {
+ s.errorf("nil signature: %s", call)
+ }
+ }
+
+ // Check that value-defining instructions have valid types
+ // and a valid referrer list.
+ if v, ok := instr.(Value); ok {
+ t := v.Type()
+ if t == nil {
+ s.errorf("no type: %s = %s", v.Name(), v)
+ } else if t == tRangeIter {
+ // not a proper type; ignore.
+ } else if b, ok := t.Underlying().(*types.Basic); ok && b.Info()&types.IsUntyped != 0 {
+ s.errorf("instruction has 'untyped' result: %s = %s : %s", v.Name(), v, t)
+ }
+ s.checkReferrerList(v)
+ }
+
+ // Untyped constants are legal as instruction Operands(),
+ // for example:
+ // _ = "foo"[0]
+ // or:
+ // if wordsize==64 {...}
+
+ // All other non-Instruction Values can be found via their
+ // enclosing Function or Package.
+}
+
+func (s *sanity) checkFinalInstr(idx int, instr Instruction) {
+ switch instr := instr.(type) {
+ case *If:
+ if nsuccs := len(s.block.Succs); nsuccs != 2 {
+ s.errorf("If-terminated block has %d successors; expected 2", nsuccs)
+ return
+ }
+ if s.block.Succs[0] == s.block.Succs[1] {
+ s.errorf("If-instruction has same True, False target blocks: %s", s.block.Succs[0])
+ return
+ }
+
+ case *Jump:
+ if nsuccs := len(s.block.Succs); nsuccs != 1 {
+ s.errorf("Jump-terminated block has %d successors; expected 1", nsuccs)
+ return
+ }
+
+ case *Return:
+ if nsuccs := len(s.block.Succs); nsuccs != 0 {
+ s.errorf("Return-terminated block has %d successors; expected none", nsuccs)
+ return
+ }
+ if na, nf := len(instr.Results), s.fn.Signature.Results().Len(); nf != na {
+ s.errorf("%d-ary return in %d-ary function", na, nf)
+ }
+
+ case *Panic:
+ if nsuccs := len(s.block.Succs); nsuccs != 0 {
+ s.errorf("Panic-terminated block has %d successors; expected none", nsuccs)
+ return
+ }
+
+ default:
+ s.errorf("non-control flow instruction at end of block")
+ }
+}
+
+func (s *sanity) checkBlock(b *BasicBlock, index int) {
+ s.block = b
+
+ if b.Index != index {
+ s.errorf("block has incorrect Index %d", b.Index)
+ }
+ if b.parent != s.fn {
+ s.errorf("block has incorrect parent %s", b.parent)
+ }
+
+ // Check all blocks are reachable.
+ // (The entry block is always implicitly reachable,
+ // as is the Recover block, if any.)
+ if (index > 0 && b != b.parent.Recover) && len(b.Preds) == 0 {
+ s.warnf("unreachable block")
+ if b.Instrs == nil {
+ // Since this block is about to be pruned,
+ // tolerating transient problems in it
+ // simplifies other optimizations.
+ return
+ }
+ }
+
+ // Check predecessor and successor relations are dual,
+ // and that all blocks in CFG belong to same function.
+ for _, a := range b.Preds {
+ found := false
+ for _, bb := range a.Succs {
+ if bb == b {
+ found = true
+ break
+ }
+ }
+ if !found {
+ s.errorf("expected successor edge in predecessor %s; found only: %s", a, a.Succs)
+ }
+ if a.parent != s.fn {
+ s.errorf("predecessor %s belongs to different function %s", a, a.parent)
+ }
+ }
+ for _, c := range b.Succs {
+ found := false
+ for _, bb := range c.Preds {
+ if bb == b {
+ found = true
+ break
+ }
+ }
+ if !found {
+ s.errorf("expected predecessor edge in successor %s; found only: %s", c, c.Preds)
+ }
+ if c.parent != s.fn {
+ s.errorf("successor %s belongs to different function %s", c, c.parent)
+ }
+ }
+
+ // Check each instruction is sane.
+ n := len(b.Instrs)
+ if n == 0 {
+ s.errorf("basic block contains no instructions")
+ }
+ var rands [10]*Value // reuse storage
+ for j, instr := range b.Instrs {
+ if instr == nil {
+ s.errorf("nil instruction at index %d", j)
+ continue
+ }
+ if b2 := instr.Block(); b2 == nil {
+ s.errorf("nil Block() for instruction at index %d", j)
+ continue
+ } else if b2 != b {
+ s.errorf("wrong Block() (%s) for instruction at index %d ", b2, j)
+ continue
+ }
+ if j < n-1 {
+ s.checkInstr(j, instr)
+ } else {
+ s.checkFinalInstr(j, instr)
+ }
+
+ // Check Instruction.Operands.
+ operands:
+ for i, op := range instr.Operands(rands[:0]) {
+ if op == nil {
+ s.errorf("nil operand pointer %d of %s", i, instr)
+ continue
+ }
+ val := *op
+ if val == nil {
+ continue // a nil operand is ok
+ }
+
+ // Check that "untyped" types only appear on constant operands.
+ if _, ok := (*op).(*Const); !ok {
+ if basic, ok := (*op).Type().(*types.Basic); ok {
+ if basic.Info()&types.IsUntyped != 0 {
+ s.errorf("operand #%d of %s is untyped: %s", i, instr, basic)
+ }
+ }
+ }
+
+ // Check that Operands that are also Instructions belong to same function.
+ // TODO(adonovan): also check their block dominates block b.
+ if val, ok := val.(Instruction); ok {
+ if val.Parent() != s.fn {
+ s.errorf("operand %d of %s is an instruction (%s) from function %s", i, instr, val, val.Parent())
+ }
+ }
+
+ // Check that each function-local operand of
+ // instr refers back to instr. (NB: quadratic)
+ switch val := val.(type) {
+ case *Const, *Global, *Builtin:
+ continue // not local
+ case *Function:
+ if val.parent == nil {
+ continue // only anon functions are local
+ }
+ }
+
+ // TODO(adonovan): check val.Parent() != nil <=> val.Referrers() is defined.
+
+ if refs := val.Referrers(); refs != nil {
+ for _, ref := range *refs {
+ if ref == instr {
+ continue operands
+ }
+ }
+ s.errorf("operand %d of %s (%s) does not refer to us", i, instr, val)
+ } else {
+ s.errorf("operand %d of %s (%s) has no referrers", i, instr, val)
+ }
+ }
+ }
+}
+
+func (s *sanity) checkReferrerList(v Value) {
+ refs := v.Referrers()
+ if refs == nil {
+ s.errorf("%s has missing referrer list", v.Name())
+ return
+ }
+ for i, ref := range *refs {
+ if _, ok := s.instrs[ref]; !ok {
+ s.errorf("%s.Referrers()[%d] = %s is not an instruction belonging to this function", v.Name(), i, ref)
+ }
+ }
+}
+
+func (s *sanity) checkFunction(fn *Function) bool {
+ // TODO(adonovan): check Function invariants:
+ // - check params match signature
+ // - check transient fields are nil
+ // - warn if any fn.Locals do not appear among block instructions.
+ s.fn = fn
+ if fn.Prog == nil {
+ s.errorf("nil Prog")
+ }
+
+ fn.String() // must not crash
+ fn.RelString(fn.pkgobj()) // must not crash
+
+ // All functions have a package, except delegates (which are
+ // shared across packages, or duplicated as weak symbols in a
+ // separate-compilation model), and error.Error.
+ if fn.Pkg == nil {
+ if strings.HasPrefix(fn.Synthetic, "wrapper ") ||
+ strings.HasPrefix(fn.Synthetic, "bound ") ||
+ strings.HasPrefix(fn.Synthetic, "thunk ") ||
+ strings.HasSuffix(fn.name, "Error") {
+ // ok
+ } else {
+ s.errorf("nil Pkg")
+ }
+ }
+ if src, syn := fn.Synthetic == "", fn.Syntax() != nil; src != syn {
+ s.errorf("got fromSource=%t, hasSyntax=%t; want same values", src, syn)
+ }
+ for i, l := range fn.Locals {
+ if l.Parent() != fn {
+ s.errorf("Local %s at index %d has wrong parent", l.Name(), i)
+ }
+ if l.Heap {
+ s.errorf("Local %s at index %d has Heap flag set", l.Name(), i)
+ }
+ }
+ // Build the set of valid referrers.
+ s.instrs = make(map[Instruction]struct{})
+ for _, b := range fn.Blocks {
+ for _, instr := range b.Instrs {
+ s.instrs[instr] = struct{}{}
+ }
+ }
+ for i, p := range fn.Params {
+ if p.Parent() != fn {
+ s.errorf("Param %s at index %d has wrong parent", p.Name(), i)
+ }
+ s.checkReferrerList(p)
+ }
+ for i, fv := range fn.FreeVars {
+ if fv.Parent() != fn {
+ s.errorf("FreeVar %s at index %d has wrong parent", fv.Name(), i)
+ }
+ s.checkReferrerList(fv)
+ }
+
+ if fn.Blocks != nil && len(fn.Blocks) == 0 {
+ // Function _had_ blocks (so it's not external) but
+ // they were "optimized" away, even the entry block.
+ s.errorf("Blocks slice is non-nil but empty")
+ }
+ for i, b := range fn.Blocks {
+ if b == nil {
+ s.warnf("nil *BasicBlock at f.Blocks[%d]", i)
+ continue
+ }
+ s.checkBlock(b, i)
+ }
+ if fn.Recover != nil && fn.Blocks[fn.Recover.Index] != fn.Recover {
+ s.errorf("Recover block is not in Blocks slice")
+ }
+
+ s.block = nil
+ for i, anon := range fn.AnonFuncs {
+ if anon.Parent() != fn {
+ s.errorf("AnonFuncs[%d]=%s but %s.Parent()=%s", i, anon, anon, anon.Parent())
+ }
+ }
+ s.fn = nil
+ return !s.insane
+}
+
+// sanityCheckPackage checks invariants of packages upon creation.
+// It does not require that the package is built.
+// Unlike sanityCheck (for functions), it just panics at the first error.
+func sanityCheckPackage(pkg *Package) {
+ if pkg.Object == nil {
+ panic(fmt.Sprintf("Package %s has no Object", pkg))
+ }
+ pkg.String() // must not crash
+
+ for name, mem := range pkg.Members {
+ if name != mem.Name() {
+ panic(fmt.Sprintf("%s: %T.Name() = %s, want %s",
+ pkg.Object.Path(), mem, mem.Name(), name))
+ }
+ obj := mem.Object()
+ if obj == nil {
+ // This check is sound because fields
+ // {Global,Function}.object have type
+ // types.Object. (If they were declared as
+ // *types.{Var,Func}, we'd have a non-empty
+ // interface containing a nil pointer.)
+
+ continue // not all members have typechecker objects
+ }
+ if obj.Name() != name {
+ if obj.Name() == "init" && strings.HasPrefix(mem.Name(), "init#") {
+ // Ok. The name of a declared init function varies between
+ // its types.Func ("init") and its ssa.Function ("init#%d").
+ } else {
+ panic(fmt.Sprintf("%s: %T.Object().Name() = %s, want %s",
+ pkg.Object.Path(), mem, obj.Name(), name))
+ }
+ }
+ if obj.Pos() != mem.Pos() {
+ panic(fmt.Sprintf("%s Pos=%d obj.Pos=%d", mem, mem.Pos(), obj.Pos()))
+ }
+ }
+}
diff --git a/go/ssa/source.go b/go/ssa/source.go
new file mode 100644
index 0000000..84e6f1d
--- /dev/null
+++ b/go/ssa/source.go
@@ -0,0 +1,294 @@
+// 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 ssa
+
+// This file defines utilities for working with source positions
+// or source-level named entities ("objects").
+
+// TODO(adonovan): test that {Value,Instruction}.Pos() positions match
+// the originating syntax, as specified.
+
+import (
+ "go/ast"
+ "go/token"
+
+ "golang.org/x/tools/go/types"
+)
+
+// EnclosingFunction returns the function that contains the syntax
+// node denoted by path.
+//
+// Syntax associated with package-level variable specifications is
+// enclosed by the package's init() function.
+//
+// Returns nil if not found; reasons might include:
+// - the node is not enclosed by any function.
+// - the node is within an anonymous function (FuncLit) and
+// its SSA function has not been created yet
+// (pkg.Build() has not yet been called).
+//
+func EnclosingFunction(pkg *Package, path []ast.Node) *Function {
+ // Start with package-level function...
+ fn := findEnclosingPackageLevelFunction(pkg, path)
+ if fn == nil {
+ return nil // not in any function
+ }
+
+ // ...then walk down the nested anonymous functions.
+ n := len(path)
+outer:
+ for i := range path {
+ if lit, ok := path[n-1-i].(*ast.FuncLit); ok {
+ for _, anon := range fn.AnonFuncs {
+ if anon.Pos() == lit.Type.Func {
+ fn = anon
+ continue outer
+ }
+ }
+ // SSA function not found:
+ // - package not yet built, or maybe
+ // - builder skipped FuncLit in dead block
+ // (in principle; but currently the Builder
+ // generates even dead FuncLits).
+ return nil
+ }
+ }
+ return fn
+}
+
+// HasEnclosingFunction returns true if the AST node denoted by path
+// is contained within the declaration of some function or
+// package-level variable.
+//
+// Unlike EnclosingFunction, the behaviour of this function does not
+// depend on whether SSA code for pkg has been built, so it can be
+// used to quickly reject check inputs that will cause
+// EnclosingFunction to fail, prior to SSA building.
+//
+func HasEnclosingFunction(pkg *Package, path []ast.Node) bool {
+ return findEnclosingPackageLevelFunction(pkg, path) != nil
+}
+
+// findEnclosingPackageLevelFunction returns the Function
+// corresponding to the package-level function enclosing path.
+//
+func findEnclosingPackageLevelFunction(pkg *Package, path []ast.Node) *Function {
+ if n := len(path); n >= 2 { // [... {Gen,Func}Decl File]
+ switch decl := path[n-2].(type) {
+ case *ast.GenDecl:
+ if decl.Tok == token.VAR && n >= 3 {
+ // Package-level 'var' initializer.
+ return pkg.init
+ }
+
+ case *ast.FuncDecl:
+ if decl.Recv == nil && decl.Name.Name == "init" {
+ // Explicit init() function.
+ for _, b := range pkg.init.Blocks {
+ for _, instr := range b.Instrs {
+ if instr, ok := instr.(*Call); ok {
+ if callee, ok := instr.Call.Value.(*Function); ok && callee.Pkg == pkg && callee.Pos() == decl.Name.NamePos {
+ return callee
+ }
+ }
+ }
+ }
+ // Hack: return non-nil when SSA is not yet
+ // built so that HasEnclosingFunction works.
+ return pkg.init
+ }
+ // Declared function/method.
+ return findNamedFunc(pkg, decl.Name.NamePos)
+ }
+ }
+ return nil // not in any function
+}
+
+// findNamedFunc returns the named function whose FuncDecl.Ident is at
+// position pos.
+//
+func findNamedFunc(pkg *Package, pos token.Pos) *Function {
+ // Look at all package members and method sets of named types.
+ // Not very efficient.
+ for _, mem := range pkg.Members {
+ switch mem := mem.(type) {
+ case *Function:
+ if mem.Pos() == pos {
+ return mem
+ }
+ case *Type:
+ mset := pkg.Prog.MethodSets.MethodSet(types.NewPointer(mem.Type()))
+ for i, n := 0, mset.Len(); i < n; i++ {
+ // Don't call Program.Method: avoid creating wrappers.
+ obj := mset.At(i).Obj().(*types.Func)
+ if obj.Pos() == pos {
+ return pkg.values[obj].(*Function)
+ }
+ }
+ }
+ }
+ return nil
+}
+
+// ValueForExpr returns the SSA Value that corresponds to non-constant
+// expression e.
+//
+// It returns nil if no value was found, e.g.
+// - the expression is not lexically contained within f;
+// - f was not built with debug information; or
+// - e is a constant expression. (For efficiency, no debug
+// information is stored for constants. Use
+// go/types.Info.Types[e].Value instead.)
+// - e is a reference to nil or a built-in function.
+// - the value was optimised away.
+//
+// If e is an addressable expression used in an lvalue context,
+// value is the address denoted by e, and isAddr is true.
+//
+// The types of e (or &e, if isAddr) and the result are equal
+// (modulo "untyped" bools resulting from comparisons).
+//
+// (Tip: to find the ssa.Value given a source position, use
+// importer.PathEnclosingInterval to locate the ast.Node, then
+// EnclosingFunction to locate the Function, then ValueForExpr to find
+// the ssa.Value.)
+//
+func (f *Function) ValueForExpr(e ast.Expr) (value Value, isAddr bool) {
+ if f.debugInfo() { // (opt)
+ e = unparen(e)
+ for _, b := range f.Blocks {
+ for _, instr := range b.Instrs {
+ if ref, ok := instr.(*DebugRef); ok {
+ if ref.Expr == e {
+ return ref.X, ref.IsAddr
+ }
+ }
+ }
+ }
+ }
+ return
+}
+
+// --- Lookup functions for source-level named entities (types.Objects) ---
+
+// Package returns the SSA Package corresponding to the specified
+// type-checker package object.
+// It returns nil if no such SSA package has been created.
+//
+func (prog *Program) Package(obj *types.Package) *Package {
+ return prog.packages[obj]
+}
+
+// packageLevelValue returns the package-level value corresponding to
+// the specified named object, which may be a package-level const
+// (*Const), var (*Global) or func (*Function) of some package in
+// prog. It returns nil if the object is not found.
+//
+func (prog *Program) packageLevelValue(obj types.Object) Value {
+ if pkg, ok := prog.packages[obj.Pkg()]; ok {
+ return pkg.values[obj]
+ }
+ return nil
+}
+
+// FuncValue returns the concrete Function denoted by the source-level
+// named function obj, or nil if obj denotes an interface method.
+//
+// TODO(adonovan): check the invariant that obj.Type() matches the
+// result's Signature, both in the params/results and in the receiver.
+//
+func (prog *Program) FuncValue(obj *types.Func) *Function {
+ fn, _ := prog.packageLevelValue(obj).(*Function)
+ return fn
+}
+
+// ConstValue returns the SSA Value denoted by the source-level named
+// constant obj.
+//
+func (prog *Program) ConstValue(obj *types.Const) *Const {
+ // TODO(adonovan): opt: share (don't reallocate)
+ // Consts for const objects and constant ast.Exprs.
+
+ // Universal constant? {true,false,nil}
+ if obj.Parent() == types.Universe {
+ return NewConst(obj.Val(), obj.Type())
+ }
+ // Package-level named constant?
+ if v := prog.packageLevelValue(obj); v != nil {
+ return v.(*Const)
+ }
+ return NewConst(obj.Val(), obj.Type())
+}
+
+// VarValue returns the SSA Value that corresponds to a specific
+// identifier denoting the source-level named variable obj.
+//
+// VarValue returns nil if a local variable was not found, perhaps
+// because its package was not built, the debug information was not
+// requested during SSA construction, or the value was optimized away.
+//
+// ref is the path to an ast.Ident (e.g. from PathEnclosingInterval),
+// and that ident must resolve to obj.
+//
+// pkg is the package enclosing the reference. (A reference to a var
+// always occurs within a function, so we need to know where to find it.)
+//
+// If the identifier is a field selector and its base expression is
+// non-addressable, then VarValue returns the value of that field.
+// For example:
+// func f() struct {x int}
+// f().x // VarValue(x) returns a *Field instruction of type int
+//
+// All other identifiers denote addressable locations (variables).
+// For them, VarValue may return either the variable's address or its
+// value, even when the expression is evaluated only for its value; the
+// situation is reported by isAddr, the second component of the result.
+//
+// If !isAddr, the returned value is the one associated with the
+// specific identifier. For example,
+// var x int // VarValue(x) returns Const 0 here
+// x = 1 // VarValue(x) returns Const 1 here
+//
+// It is not specified whether the value or the address is returned in
+// any particular case, as it may depend upon optimizations performed
+// during SSA code generation, such as registerization, constant
+// folding, avoidance of materialization of subexpressions, etc.
+//
+func (prog *Program) VarValue(obj *types.Var, pkg *Package, ref []ast.Node) (value Value, isAddr bool) {
+ // All references to a var are local to some function, possibly init.
+ fn := EnclosingFunction(pkg, ref)
+ if fn == nil {
+ return // e.g. def of struct field; SSA not built?
+ }
+
+ id := ref[0].(*ast.Ident)
+
+ // Defining ident of a parameter?
+ if id.Pos() == obj.Pos() {
+ for _, param := range fn.Params {
+ if param.Object() == obj {
+ return param, false
+ }
+ }
+ }
+
+ // Other ident?
+ for _, b := range fn.Blocks {
+ for _, instr := range b.Instrs {
+ if dr, ok := instr.(*DebugRef); ok {
+ if dr.Pos() == id.Pos() {
+ return dr.X, dr.IsAddr
+ }
+ }
+ }
+ }
+
+ // Defining ident of package-level var?
+ if v := prog.packageLevelValue(obj); v != nil {
+ return v.(*Global), true
+ }
+
+ return // e.g. debug info not requested, or var optimized away
+}
diff --git a/go/ssa/source_test.go b/go/ssa/source_test.go
new file mode 100644
index 0000000..75669c1
--- /dev/null
+++ b/go/ssa/source_test.go
@@ -0,0 +1,393 @@
+// 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 ssa_test
+
+// This file defines tests of source-level debugging utilities.
+
+import (
+ "fmt"
+ "go/ast"
+ "go/parser"
+ "go/token"
+ "os"
+ "regexp"
+ "runtime"
+ "strings"
+ "testing"
+
+ "golang.org/x/tools/go/ast/astutil"
+ "golang.org/x/tools/go/exact"
+ "golang.org/x/tools/go/loader"
+ "golang.org/x/tools/go/ssa"
+ "golang.org/x/tools/go/ssa/ssautil"
+ "golang.org/x/tools/go/types"
+)
+
+func TestObjValueLookup(t *testing.T) {
+ if runtime.GOOS == "android" {
+ t.Skipf("no testdata directory on %s", runtime.GOOS)
+ }
+
+ conf := loader.Config{ParserMode: parser.ParseComments}
+ f, err := conf.ParseFile("testdata/objlookup.go", nil)
+ if err != nil {
+ t.Error(err)
+ return
+ }
+ conf.CreateFromFiles("main", f)
+
+ // Maps each var Ident (represented "name:linenum") to the
+ // kind of ssa.Value we expect (represented "Constant", "&Alloc").
+ expectations := make(map[string]string)
+
+ // Find all annotations of form x::BinOp, &y::Alloc, etc.
+ re := regexp.MustCompile(`(\b|&)?(\w*)::(\w*)\b`)
+ for _, c := range f.Comments {
+ text := c.Text()
+ pos := conf.Fset.Position(c.Pos())
+ for _, m := range re.FindAllStringSubmatch(text, -1) {
+ key := fmt.Sprintf("%s:%d", m[2], pos.Line)
+ value := m[1] + m[3]
+ expectations[key] = value
+ }
+ }
+
+ iprog, err := conf.Load()
+ if err != nil {
+ t.Error(err)
+ return
+ }
+
+ prog := ssautil.CreateProgram(iprog, 0 /*|ssa.PrintFunctions*/)
+ mainInfo := iprog.Created[0]
+ mainPkg := prog.Package(mainInfo.Pkg)
+ mainPkg.SetDebugMode(true)
+ mainPkg.Build()
+
+ var varIds []*ast.Ident
+ var varObjs []*types.Var
+ for id, obj := range mainInfo.Defs {
+ // Check invariants for func and const objects.
+ switch obj := obj.(type) {
+ case *types.Func:
+ checkFuncValue(t, prog, obj)
+
+ case *types.Const:
+ checkConstValue(t, prog, obj)
+
+ case *types.Var:
+ if id.Name == "_" {
+ continue
+ }
+ varIds = append(varIds, id)
+ varObjs = append(varObjs, obj)
+ }
+ }
+ for id, obj := range mainInfo.Uses {
+ if obj, ok := obj.(*types.Var); ok {
+ varIds = append(varIds, id)
+ varObjs = append(varObjs, obj)
+ }
+ }
+
+ // Check invariants for var objects.
+ // The result varies based on the specific Ident.
+ for i, id := range varIds {
+ obj := varObjs[i]
+ ref, _ := astutil.PathEnclosingInterval(f, id.Pos(), id.Pos())
+ pos := prog.Fset.Position(id.Pos())
+ exp := expectations[fmt.Sprintf("%s:%d", id.Name, pos.Line)]
+ if exp == "" {
+ t.Errorf("%s: no expectation for var ident %s ", pos, id.Name)
+ continue
+ }
+ wantAddr := false
+ if exp[0] == '&' {
+ wantAddr = true
+ exp = exp[1:]
+ }
+ checkVarValue(t, prog, mainPkg, ref, obj, exp, wantAddr)
+ }
+}
+
+func checkFuncValue(t *testing.T, prog *ssa.Program, obj *types.Func) {
+ fn := prog.FuncValue(obj)
+ // fmt.Printf("FuncValue(%s) = %s\n", obj, fn) // debugging
+ if fn == nil {
+ if obj.Name() != "interfaceMethod" {
+ t.Errorf("FuncValue(%s) == nil", obj)
+ }
+ return
+ }
+ if fnobj := fn.Object(); fnobj != obj {
+ t.Errorf("FuncValue(%s).Object() == %s; value was %s",
+ obj, fnobj, fn.Name())
+ return
+ }
+ if !types.Identical(fn.Type(), obj.Type()) {
+ t.Errorf("FuncValue(%s).Type() == %s", obj, fn.Type())
+ return
+ }
+}
+
+func checkConstValue(t *testing.T, prog *ssa.Program, obj *types.Const) {
+ c := prog.ConstValue(obj)
+ // fmt.Printf("ConstValue(%s) = %s\n", obj, c) // debugging
+ if c == nil {
+ t.Errorf("ConstValue(%s) == nil", obj)
+ return
+ }
+ if !types.Identical(c.Type(), obj.Type()) {
+ t.Errorf("ConstValue(%s).Type() == %s", obj, c.Type())
+ return
+ }
+ if obj.Name() != "nil" {
+ if !exact.Compare(c.Value, token.EQL, obj.Val()) {
+ t.Errorf("ConstValue(%s).Value (%s) != %s",
+ obj, c.Value, obj.Val())
+ return
+ }
+ }
+}
+
+func checkVarValue(t *testing.T, prog *ssa.Program, pkg *ssa.Package, ref []ast.Node, obj *types.Var, expKind string, wantAddr bool) {
+ // The prefix of all assertions messages.
+ prefix := fmt.Sprintf("VarValue(%s @ L%d)",
+ obj, prog.Fset.Position(ref[0].Pos()).Line)
+
+ v, gotAddr := prog.VarValue(obj, pkg, ref)
+
+ // Kind is the concrete type of the ssa Value.
+ gotKind := "nil"
+ if v != nil {
+ gotKind = fmt.Sprintf("%T", v)[len("*ssa."):]
+ }
+
+ // fmt.Printf("%s = %v (kind %q; expect %q) wantAddr=%t gotAddr=%t\n", prefix, v, gotKind, expKind, wantAddr, gotAddr) // debugging
+
+ // Check the kinds match.
+ // "nil" indicates expected failure (e.g. optimized away).
+ if expKind != gotKind {
+ t.Errorf("%s concrete type == %s, want %s", prefix, gotKind, expKind)
+ }
+
+ // Check the types match.
+ // If wantAddr, the expected type is the object's address.
+ if v != nil {
+ expType := obj.Type()
+ if wantAddr {
+ expType = types.NewPointer(expType)
+ if !gotAddr {
+ t.Errorf("%s: got value, want address", prefix)
+ }
+ } else if gotAddr {
+ t.Errorf("%s: got address, want value", prefix)
+ }
+ if !types.Identical(v.Type(), expType) {
+ t.Errorf("%s.Type() == %s, want %s", prefix, v.Type(), expType)
+ }
+ }
+}
+
+// Ensure that, in debug mode, we can determine the ssa.Value
+// corresponding to every ast.Expr.
+func TestValueForExpr(t *testing.T) {
+ if runtime.GOOS == "android" {
+ t.Skipf("no testdata dir on %s", runtime.GOOS)
+ }
+
+ conf := loader.Config{ParserMode: parser.ParseComments}
+ f, err := conf.ParseFile("testdata/valueforexpr.go", nil)
+ if err != nil {
+ t.Error(err)
+ return
+ }
+ conf.CreateFromFiles("main", f)
+
+ iprog, err := conf.Load()
+ if err != nil {
+ t.Error(err)
+ return
+ }
+
+ mainInfo := iprog.Created[0]
+
+ prog := ssautil.CreateProgram(iprog, 0)
+ mainPkg := prog.Package(mainInfo.Pkg)
+ mainPkg.SetDebugMode(true)
+ mainPkg.Build()
+
+ if false {
+ // debugging
+ for _, mem := range mainPkg.Members {
+ if fn, ok := mem.(*ssa.Function); ok {
+ fn.WriteTo(os.Stderr)
+ }
+ }
+ }
+
+ // Find the actual AST node for each canonical position.
+ parenExprByPos := make(map[token.Pos]*ast.ParenExpr)
+ ast.Inspect(f, func(n ast.Node) bool {
+ if n != nil {
+ if e, ok := n.(*ast.ParenExpr); ok {
+ parenExprByPos[e.Pos()] = e
+ }
+ }
+ return true
+ })
+
+ // Find all annotations of form /*@kind*/.
+ for _, c := range f.Comments {
+ text := strings.TrimSpace(c.Text())
+ if text == "" || text[0] != '@' {
+ continue
+ }
+ text = text[1:]
+ pos := c.End() + 1
+ position := prog.Fset.Position(pos)
+ var e ast.Expr
+ if target := parenExprByPos[pos]; target == nil {
+ t.Errorf("%s: annotation doesn't precede ParenExpr: %q", position, text)
+ continue
+ } else {
+ e = target.X
+ }
+
+ path, _ := astutil.PathEnclosingInterval(f, pos, pos)
+ if path == nil {
+ t.Errorf("%s: can't find AST path from root to comment: %s", position, text)
+ continue
+ }
+
+ fn := ssa.EnclosingFunction(mainPkg, path)
+ if fn == nil {
+ t.Errorf("%s: can't find enclosing function", position)
+ continue
+ }
+
+ v, gotAddr := fn.ValueForExpr(e) // (may be nil)
+ got := strings.TrimPrefix(fmt.Sprintf("%T", v), "*ssa.")
+ if want := text; got != want {
+ t.Errorf("%s: got value %q, want %q", position, got, want)
+ }
+ if v != nil {
+ T := v.Type()
+ if gotAddr {
+ T = T.Underlying().(*types.Pointer).Elem() // deref
+ }
+ if !types.Identical(T, mainInfo.TypeOf(e)) {
+ t.Errorf("%s: got type %s, want %s", position, mainInfo.TypeOf(e), T)
+ }
+ }
+ }
+}
+
+// findInterval parses input and returns the [start, end) positions of
+// the first occurrence of substr in input. f==nil indicates failure;
+// an error has already been reported in that case.
+//
+func findInterval(t *testing.T, fset *token.FileSet, input, substr string) (f *ast.File, start, end token.Pos) {
+ f, err := parser.ParseFile(fset, "<input>", input, 0)
+ if err != nil {
+ t.Errorf("parse error: %s", err)
+ return
+ }
+
+ i := strings.Index(input, substr)
+ if i < 0 {
+ t.Errorf("%q is not a substring of input", substr)
+ f = nil
+ return
+ }
+
+ filePos := fset.File(f.Package)
+ return f, filePos.Pos(i), filePos.Pos(i + len(substr))
+}
+
+func TestEnclosingFunction(t *testing.T) {
+ tests := []struct {
+ input string // the input file
+ substr string // first occurrence of this string denotes interval
+ fn string // name of expected containing function
+ }{
+ // We use distinctive numbers as syntactic landmarks.
+
+ // Ordinary function:
+ {`package main
+ func f() { println(1003) }`,
+ "100", "main.f"},
+ // Methods:
+ {`package main
+ type T int
+ func (t T) f() { println(200) }`,
+ "200", "(main.T).f"},
+ // Function literal:
+ {`package main
+ func f() { println(func() { print(300) }) }`,
+ "300", "main.f$1"},
+ // Doubly nested
+ {`package main
+ func f() { println(func() { print(func() { print(350) })})}`,
+ "350", "main.f$1$1"},
+ // Implicit init for package-level var initializer.
+ {"package main; var a = 400", "400", "main.init"},
+ // No code for constants:
+ {"package main; const a = 500", "500", "(none)"},
+ // Explicit init()
+ {"package main; func init() { println(600) }", "600", "main.init#1"},
+ // Multiple explicit init functions:
+ {`package main
+ func init() { println("foo") }
+ func init() { println(800) }`,
+ "800", "main.init#2"},
+ // init() containing FuncLit.
+ {`package main
+ func init() { println(func(){print(900)}) }`,
+ "900", "main.init#1$1"},
+ }
+ for _, test := range tests {
+ conf := loader.Config{Fset: token.NewFileSet()}
+ f, start, end := findInterval(t, conf.Fset, test.input, test.substr)
+ if f == nil {
+ continue
+ }
+ path, exact := astutil.PathEnclosingInterval(f, start, end)
+ if !exact {
+ t.Errorf("EnclosingFunction(%q) not exact", test.substr)
+ continue
+ }
+
+ conf.CreateFromFiles("main", f)
+
+ iprog, err := conf.Load()
+ if err != nil {
+ t.Error(err)
+ continue
+ }
+ prog := ssautil.CreateProgram(iprog, 0)
+ pkg := prog.Package(iprog.Created[0].Pkg)
+ pkg.Build()
+
+ name := "(none)"
+ fn := ssa.EnclosingFunction(pkg, path)
+ if fn != nil {
+ name = fn.String()
+ }
+
+ if name != test.fn {
+ t.Errorf("EnclosingFunction(%q in %q) got %s, want %s",
+ test.substr, test.input, name, test.fn)
+ continue
+ }
+
+ // While we're here: test HasEnclosingFunction.
+ if has := ssa.HasEnclosingFunction(pkg, path); has != (fn != nil) {
+ t.Errorf("HasEnclosingFunction(%q in %q) got %v, want %v",
+ test.substr, test.input, has, fn != nil)
+ continue
+ }
+ }
+}
diff --git a/go/ssa/ssa.go b/go/ssa/ssa.go
new file mode 100644
index 0000000..f4c64bb
--- /dev/null
+++ b/go/ssa/ssa.go
@@ -0,0 +1,1700 @@
+// 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 ssa
+
+// This package defines a high-level intermediate representation for
+// Go programs using static single-assignment (SSA) form.
+
+import (
+ "fmt"
+ "go/ast"
+ "go/token"
+ "sync"
+
+ "golang.org/x/tools/go/exact"
+ "golang.org/x/tools/go/types"
+ "golang.org/x/tools/go/types/typeutil"
+)
+
+// A Program is a partial or complete Go program converted to SSA form.
+type Program struct {
+ Fset *token.FileSet // position information for the files of this Program
+ imported map[string]*Package // all importable Packages, keyed by import path
+ packages map[*types.Package]*Package // all loaded Packages, keyed by object
+ mode BuilderMode // set of mode bits for SSA construction
+ MethodSets typeutil.MethodSetCache // cache of type-checker's method-sets
+
+ methodsMu sync.Mutex // guards the following maps:
+ methodSets typeutil.Map // maps type to its concrete methodSet
+ runtimeTypes typeutil.Map // types for which rtypes are needed
+ canon typeutil.Map // type canonicalization map
+ bounds map[*types.Func]*Function // bounds for curried x.Method closures
+ thunks map[selectionKey]*Function // thunks for T.Method expressions
+}
+
+// A Package is a single analyzed Go package containing Members for
+// all package-level functions, variables, constants and types it
+// declares. These may be accessed directly via Members, or via the
+// type-specific accessor methods Func, Type, Var and Const.
+//
+// Members also contains entries for "init" (the synthetic package
+// initializer) and "init#%d", the nth declared init function,
+// and unspecified other things too.
+//
+type Package struct {
+ Prog *Program // the owning program
+ Object *types.Package // the type checker's package object for this package
+ Members map[string]Member // all package members keyed by name (incl. init and init#%d)
+ values map[types.Object]Value // package members (incl. types and methods), keyed by object
+ init *Function // Func("init"); the package's init function
+ debug bool // include full debug info in this package
+
+ // The following fields are set transiently, then cleared
+ // after building.
+ started int32 // atomically tested and set at start of build phase
+ ninit int32 // number of init functions
+ info *types.Info // package type information
+ files []*ast.File // package ASTs
+}
+
+// A Member is a member of a Go package, implemented by *NamedConst,
+// *Global, *Function, or *Type; they are created by package-level
+// const, var, func and type declarations respectively.
+//
+type Member interface {
+ Name() string // declared name of the package member
+ String() string // package-qualified name of the package member
+ RelString(*types.Package) string // like String, but relative refs are unqualified
+ Object() types.Object // typechecker's object for this member, if any
+ Pos() token.Pos // position of member's declaration, if known
+ Type() types.Type // type of the package member
+ Token() token.Token // token.{VAR,FUNC,CONST,TYPE}
+ Package() *Package // the containing package
+}
+
+// A Type is a Member of a Package representing a package-level named type.
+//
+// Type() returns a *types.Named.
+//
+type Type struct {
+ object *types.TypeName
+ pkg *Package
+}
+
+// A NamedConst is a Member of a Package representing a package-level
+// named constant.
+//
+// Pos() returns the position of the declaring ast.ValueSpec.Names[*]
+// identifier.
+//
+// NB: a NamedConst is not a Value; it contains a constant Value, which
+// it augments with the name and position of its 'const' declaration.
+//
+type NamedConst struct {
+ object *types.Const
+ Value *Const
+ pos token.Pos
+ pkg *Package
+}
+
+// A Value is an SSA value that can be referenced by an instruction.
+type Value interface {
+ // Name returns the name of this value, and determines how
+ // this Value appears when used as an operand of an
+ // Instruction.
+ //
+ // This is the same as the source name for Parameters,
+ // Builtins, Functions, FreeVars, Globals.
+ // For constants, it is a representation of the constant's value
+ // and type. For all other Values this is the name of the
+ // virtual register defined by the instruction.
+ //
+ // The name of an SSA Value is not semantically significant,
+ // and may not even be unique within a function.
+ Name() string
+
+ // If this value is an Instruction, String returns its
+ // disassembled form; otherwise it returns unspecified
+ // human-readable information about the Value, such as its
+ // kind, name and type.
+ String() string
+
+ // Type returns the type of this value. Many instructions
+ // (e.g. IndexAddr) change their behaviour depending on the
+ // types of their operands.
+ Type() types.Type
+
+ // Parent returns the function to which this Value belongs.
+ // It returns nil for named Functions, Builtin, Const and Global.
+ Parent() *Function
+
+ // Referrers returns the list of instructions that have this
+ // value as one of their operands; it may contain duplicates
+ // if an instruction has a repeated operand.
+ //
+ // Referrers actually returns a pointer through which the
+ // caller may perform mutations to the object's state.
+ //
+ // Referrers is currently only defined if Parent()!=nil,
+ // i.e. for the function-local values FreeVar, Parameter,
+ // Functions (iff anonymous) and all value-defining instructions.
+ // It returns nil for named Functions, Builtin, Const and Global.
+ //
+ // Instruction.Operands contains the inverse of this relation.
+ Referrers() *[]Instruction
+
+ // Pos returns the location of the AST token most closely
+ // associated with the operation that gave rise to this value,
+ // or token.NoPos if it was not explicit in the source.
+ //
+ // For each ast.Node type, a particular token is designated as
+ // the closest location for the expression, e.g. the Lparen
+ // for an *ast.CallExpr. This permits a compact but
+ // approximate mapping from Values to source positions for use
+ // in diagnostic messages, for example.
+ //
+ // (Do not use this position to determine which Value
+ // corresponds to an ast.Expr; use Function.ValueForExpr
+ // instead. NB: it requires that the function was built with
+ // debug information.)
+ Pos() token.Pos
+}
+
+// An Instruction is an SSA instruction that computes a new Value or
+// has some effect.
+//
+// An Instruction that defines a value (e.g. BinOp) also implements
+// the Value interface; an Instruction that only has an effect (e.g. Store)
+// does not.
+//
+type Instruction interface {
+ // String returns the disassembled form of this value.
+ //
+ // Examples of Instructions that are Values:
+ // "x + y" (BinOp)
+ // "len([])" (Call)
+ // Note that the name of the Value is not printed.
+ //
+ // Examples of Instructions that are not Values:
+ // "return x" (Return)
+ // "*y = x" (Store)
+ //
+ // (The separation Value.Name() from Value.String() is useful
+ // for some analyses which distinguish the operation from the
+ // value it defines, e.g., 'y = local int' is both an allocation
+ // of memory 'local int' and a definition of a pointer y.)
+ String() string
+
+ // Parent returns the function to which this instruction
+ // belongs.
+ Parent() *Function
+
+ // Block returns the basic block to which this instruction
+ // belongs.
+ Block() *BasicBlock
+
+ // setBlock sets the basic block to which this instruction belongs.
+ setBlock(*BasicBlock)
+
+ // Operands returns the operands of this instruction: the
+ // set of Values it references.
+ //
+ // Specifically, it appends their addresses to rands, a
+ // user-provided slice, and returns the resulting slice,
+ // permitting avoidance of memory allocation.
+ //
+ // The operands are appended in undefined order, but the order
+ // is consistent for a given Instruction; the addresses are
+ // always non-nil but may point to a nil Value. Clients may
+ // store through the pointers, e.g. to effect a value
+ // renaming.
+ //
+ // Value.Referrers is a subset of the inverse of this
+ // relation. (Referrers are not tracked for all types of
+ // Values.)
+ Operands(rands []*Value) []*Value
+
+ // Pos returns the location of the AST token most closely
+ // associated with the operation that gave rise to this
+ // instruction, or token.NoPos if it was not explicit in the
+ // source.
+ //
+ // For each ast.Node type, a particular token is designated as
+ // the closest location for the expression, e.g. the Go token
+ // for an *ast.GoStmt. This permits a compact but approximate
+ // mapping from Instructions to source positions for use in
+ // diagnostic messages, for example.
+ //
+ // (Do not use this position to determine which Instruction
+ // corresponds to an ast.Expr; see the notes for Value.Pos.
+ // This position may be used to determine which non-Value
+ // Instruction corresponds to some ast.Stmts, but not all: If
+ // and Jump instructions have no Pos(), for example.)
+ Pos() token.Pos
+}
+
+// A Node is a node in the SSA value graph. Every concrete type that
+// implements Node is also either a Value, an Instruction, or both.
+//
+// Node contains the methods common to Value and Instruction, plus the
+// Operands and Referrers methods generalized to return nil for
+// non-Instructions and non-Values, respectively.
+//
+// Node is provided to simplify SSA graph algorithms. Clients should
+// use the more specific and informative Value or Instruction
+// interfaces where appropriate.
+//
+type Node interface {
+ // Common methods:
+ String() string
+ Pos() token.Pos
+ Parent() *Function
+
+ // Partial methods:
+ Operands(rands []*Value) []*Value // nil for non-Instructions
+ Referrers() *[]Instruction // nil for non-Values
+}
+
+// Function represents the parameters, results, and code of a function
+// or method.
+//
+// If Blocks is nil, this indicates an external function for which no
+// Go source code is available. In this case, FreeVars and Locals
+// are nil too. Clients performing whole-program analysis must
+// handle external functions specially.
+//
+// Blocks contains the function's control-flow graph (CFG).
+// Blocks[0] is the function entry point; block order is not otherwise
+// semantically significant, though it may affect the readability of
+// the disassembly.
+// To iterate over the blocks in dominance order, use DomPreorder().
+//
+// Recover is an optional second entry point to which control resumes
+// after a recovered panic. The Recover block may contain only a return
+// statement, preceded by a load of the function's named return
+// parameters, if any.
+//
+// A nested function (Parent()!=nil) that refers to one or more
+// lexically enclosing local variables ("free variables") has FreeVars.
+// Such functions cannot be called directly but require a
+// value created by MakeClosure which, via its Bindings, supplies
+// values for these parameters.
+//
+// If the function is a method (Signature.Recv() != nil) then the first
+// element of Params is the receiver parameter.
+//
+// A Go package may declare many functions called "init".
+// For each one, Object().Name() returns "init" but Name() returns
+// "init#1", etc, in declaration order.
+//
+// Pos() returns the declaring ast.FuncLit.Type.Func or the position
+// of the ast.FuncDecl.Name, if the function was explicit in the
+// source. Synthetic wrappers, for which Synthetic != "", may share
+// the same position as the function they wrap.
+// Syntax.Pos() always returns the position of the declaring "func" token.
+//
+// Type() returns the function's Signature.
+//
+type Function struct {
+ name string
+ object types.Object // a declared *types.Func or one of its wrappers
+ method *types.Selection // info about provenance of synthetic methods
+ Signature *types.Signature
+ pos token.Pos
+
+ Synthetic string // provenance of synthetic function; "" for true source functions
+ syntax ast.Node // *ast.Func{Decl,Lit}; replaced with simple ast.Node after build, unless debug mode
+ parent *Function // enclosing function if anon; nil if global
+ Pkg *Package // enclosing package; nil for shared funcs (wrappers and error.Error)
+ Prog *Program // enclosing program
+ Params []*Parameter // function parameters; for methods, includes receiver
+ FreeVars []*FreeVar // free variables whose values must be supplied by closure
+ Locals []*Alloc // local variables of this function
+ Blocks []*BasicBlock // basic blocks of the function; nil => external
+ Recover *BasicBlock // optional; control transfers here after recovered panic
+ AnonFuncs []*Function // anonymous functions directly beneath this one
+ referrers []Instruction // referring instructions (iff Parent() != nil)
+
+ // The following fields are set transiently during building,
+ // then cleared.
+ currentBlock *BasicBlock // where to emit code
+ objects map[types.Object]Value // addresses of local variables
+ namedResults []*Alloc // tuple of named results
+ targets *targets // linked stack of branch targets
+ lblocks map[*ast.Object]*lblock // labelled blocks
+}
+
+// BasicBlock represents an SSA basic block.
+//
+// The final element of Instrs is always an explicit transfer of
+// control (If, Jump, Return, or Panic).
+//
+// A block may contain no Instructions only if it is unreachable,
+// i.e., Preds is nil. Empty blocks are typically pruned.
+//
+// BasicBlocks and their Preds/Succs relation form a (possibly cyclic)
+// graph independent of the SSA Value graph: the control-flow graph or
+// CFG. It is illegal for multiple edges to exist between the same
+// pair of blocks.
+//
+// Each BasicBlock is also a node in the dominator tree of the CFG.
+// The tree may be navigated using Idom()/Dominees() and queried using
+// Dominates().
+//
+// The order of Preds and Succs is significant (to Phi and If
+// instructions, respectively).
+//
+type BasicBlock struct {
+ Index int // index of this block within Parent().Blocks
+ Comment string // optional label; no semantic significance
+ parent *Function // parent function
+ Instrs []Instruction // instructions in order
+ Preds, Succs []*BasicBlock // predecessors and successors
+ succs2 [2]*BasicBlock // initial space for Succs
+ dom domInfo // dominator tree info
+ gaps int // number of nil Instrs (transient)
+ rundefers int // number of rundefers (transient)
+}
+
+// Pure values ----------------------------------------
+
+// A FreeVar represents a free variable of the function to which it
+// belongs.
+//
+// FreeVars are used to implement anonymous functions, whose free
+// variables are lexically captured in a closure formed by
+// MakeClosure. The value of such a free var is an Alloc or another
+// FreeVar and is considered a potentially escaping heap address, with
+// pointer type.
+//
+// FreeVars are also used to implement bound method closures. Such a
+// free var represents the receiver value and may be of any type that
+// has concrete methods.
+//
+// Pos() returns the position of the value that was captured, which
+// belongs to an enclosing function.
+//
+type FreeVar struct {
+ name string
+ typ types.Type
+ pos token.Pos
+ parent *Function
+ referrers []Instruction
+
+ // Transiently needed during building.
+ outer Value // the Value captured from the enclosing context.
+}
+
+// A Parameter represents an input parameter of a function.
+//
+type Parameter struct {
+ name string
+ object types.Object // a *types.Var; nil for non-source locals
+ typ types.Type
+ pos token.Pos
+ parent *Function
+ referrers []Instruction
+}
+
+// A Const represents the value of a constant expression.
+//
+// The underlying type of a constant may be any boolean, numeric, or
+// string type. In addition, a Const may represent the nil value of
+// any reference type---interface, map, channel, pointer, slice, or
+// function---but not "untyped nil".
+//
+// All source-level constant expressions are represented by a Const
+// of the same type and value.
+//
+// Value holds the exact value of the constant, independent of its
+// Type(), using the same representation as package go/exact uses for
+// constants, or nil for a typed nil value.
+//
+// Pos() returns token.NoPos.
+//
+// Example printed form:
+// 42:int
+// "hello":untyped string
+// 3+4i:MyComplex
+//
+type Const struct {
+ typ types.Type
+ Value exact.Value
+}
+
+// A Global is a named Value holding the address of a package-level
+// variable.
+//
+// Pos() returns the position of the ast.ValueSpec.Names[*]
+// identifier.
+//
+type Global struct {
+ name string
+ object types.Object // a *types.Var; may be nil for synthetics e.g. init$guard
+ typ types.Type
+ pos token.Pos
+
+ Pkg *Package
+}
+
+// A Builtin represents a specific use of a built-in function, e.g. len.
+//
+// Builtins are immutable values. Builtins do not have addresses.
+// Builtins can only appear in CallCommon.Func.
+//
+// Name() indicates the function: one of the built-in functions from the
+// Go spec (excluding "make" and "new") or one of these ssa-defined
+// intrinsics:
+//
+// // wrapnilchk returns ptr if non-nil, panics otherwise.
+// // (For use in indirection wrappers.)
+// func ssa:wrapnilchk(ptr *T, recvType, methodName string) *T
+//
+// Object() returns a *types.Builtin for built-ins defined by the spec,
+// nil for others.
+//
+// Type() returns a *types.Signature representing the effective
+// signature of the built-in for this call.
+//
+type Builtin struct {
+ name string
+ sig *types.Signature
+}
+
+// Value-defining instructions ----------------------------------------
+
+// The Alloc instruction reserves space for a variable of the given type,
+// zero-initializes it, and yields its address.
+//
+// Alloc values are always addresses, and have pointer types, so the
+// type of the allocated variable is actually
+// Type().Underlying().(*types.Pointer).Elem().
+//
+// If Heap is false, Alloc allocates space in the function's
+// activation record (frame); we refer to an Alloc(Heap=false) as a
+// "local" alloc. Each local Alloc returns the same address each time
+// it is executed within the same activation; the space is
+// re-initialized to zero.
+//
+// If Heap is true, Alloc allocates space in the heap; we
+// refer to an Alloc(Heap=true) as a "new" alloc. Each new Alloc
+// returns a different address each time it is executed.
+//
+// When Alloc is applied to a channel, map or slice type, it returns
+// the address of an uninitialized (nil) reference of that kind; store
+// the result of MakeSlice, MakeMap or MakeChan in that location to
+// instantiate these types.
+//
+// Pos() returns the ast.CompositeLit.Lbrace for a composite literal,
+// or the ast.CallExpr.Rparen for a call to new() or for a call that
+// allocates a varargs slice.
+//
+// Example printed form:
+// t0 = local int
+// t1 = new int
+//
+type Alloc struct {
+ register
+ Comment string
+ Heap bool
+ index int // dense numbering; for lifting
+}
+
+// The Phi instruction represents an SSA φ-node, which combines values
+// that differ across incoming control-flow edges and yields a new
+// value. Within a block, all φ-nodes must appear before all non-φ
+// nodes.
+//
+// Pos() returns the position of the && or || for short-circuit
+// control-flow joins, or that of the *Alloc for φ-nodes inserted
+// during SSA renaming.
+//
+// Example printed form:
+// t2 = phi [0: t0, 1: t1]
+//
+type Phi struct {
+ register
+ Comment string // a hint as to its purpose
+ Edges []Value // Edges[i] is value for Block().Preds[i]
+}
+
+// The Call instruction represents a function or method call.
+//
+// The Call instruction yields the function result if there is exactly
+// one. Otherwise it returns a tuple, the components of which are
+// accessed via Extract.
+//
+// See CallCommon for generic function call documentation.
+//
+// Pos() returns the ast.CallExpr.Lparen, if explicit in the source.
+//
+// Example printed form:
+// t2 = println(t0, t1)
+// t4 = t3()
+// t7 = invoke t5.Println(...t6)
+//
+type Call struct {
+ register
+ Call CallCommon
+}
+
+// The BinOp instruction yields the result of binary operation X Op Y.
+//
+// Pos() returns the ast.BinaryExpr.OpPos, if explicit in the source.
+//
+// Example printed form:
+// t1 = t0 + 1:int
+//
+type BinOp struct {
+ register
+ // One of:
+ // ADD SUB MUL QUO REM + - * / %
+ // AND OR XOR SHL SHR AND_NOT & | ^ << >> &~
+ // EQL LSS GTR NEQ LEQ GEQ == != < <= < >=
+ Op token.Token
+ X, Y Value
+}
+
+// The UnOp instruction yields the result of Op X.
+// ARROW is channel receive.
+// MUL is pointer indirection (load).
+// XOR is bitwise complement.
+// SUB is negation.
+// NOT is logical negation.
+//
+// If CommaOk and Op=ARROW, the result is a 2-tuple of the value above
+// and a boolean indicating the success of the receive. The
+// components of the tuple are accessed using Extract.
+//
+// Pos() returns the ast.UnaryExpr.OpPos, if explicit in the source.
+// For receive operations (ARROW) implicit in ranging over a channel,
+// Pos() returns the ast.RangeStmt.For.
+// For implicit memory loads (STAR), Pos() returns the position of the
+// most closely associated source-level construct; the details are not
+// specified.
+//
+// Example printed form:
+// t0 = *x
+// t2 = <-t1,ok
+//
+type UnOp struct {
+ register
+ Op token.Token // One of: NOT SUB ARROW MUL XOR ! - <- * ^
+ X Value
+ CommaOk bool
+}
+
+// The ChangeType instruction applies to X a value-preserving type
+// change to Type().
+//
+// Type changes are permitted:
+// - between a named type and its underlying type.
+// - between two named types of the same underlying type.
+// - between (possibly named) pointers to identical base types.
+// - from a bidirectional channel to a read- or write-channel,
+// optionally adding/removing a name.
+//
+// This operation cannot fail dynamically.
+//
+// Pos() returns the ast.CallExpr.Lparen, if the instruction arose
+// from an explicit conversion in the source.
+//
+// Example printed form:
+// t1 = changetype *int <- IntPtr (t0)
+//
+type ChangeType struct {
+ register
+ X Value
+}
+
+// The Convert instruction yields the conversion of value X to type
+// Type(). One or both of those types is basic (but possibly named).
+//
+// A conversion may change the value and representation of its operand.
+// Conversions are permitted:
+// - between real numeric types.
+// - between complex numeric types.
+// - between string and []byte or []rune.
+// - between pointers and unsafe.Pointer.
+// - between unsafe.Pointer and uintptr.
+// - from (Unicode) integer to (UTF-8) string.
+// A conversion may imply a type name change also.
+//
+// This operation cannot fail dynamically.
+//
+// Conversions of untyped string/number/bool constants to a specific
+// representation are eliminated during SSA construction.
+//
+// Pos() returns the ast.CallExpr.Lparen, if the instruction arose
+// from an explicit conversion in the source.
+//
+// Example printed form:
+// t1 = convert []byte <- string (t0)
+//
+type Convert struct {
+ register
+ X Value
+}
+
+// ChangeInterface constructs a value of one interface type from a
+// value of another interface type known to be assignable to it.
+// This operation cannot fail.
+//
+// Pos() returns the ast.CallExpr.Lparen if the instruction arose from
+// an explicit T(e) conversion; the ast.TypeAssertExpr.Lparen if the
+// instruction arose from an explicit e.(T) operation; or token.NoPos
+// otherwise.
+//
+// Example printed form:
+// t1 = change interface interface{} <- I (t0)
+//
+type ChangeInterface struct {
+ register
+ X Value
+}
+
+// MakeInterface constructs an instance of an interface type from a
+// value of a concrete type.
+//
+// Use Program.MethodSets.MethodSet(X.Type()) to find the method-set
+// of X, and Program.Method(m) to find the implementation of a method.
+//
+// To construct the zero value of an interface type T, use:
+// NewConst(exact.MakeNil(), T, pos)
+//
+// Pos() returns the ast.CallExpr.Lparen, if the instruction arose
+// from an explicit conversion in the source.
+//
+// Example printed form:
+// t1 = make interface{} <- int (42:int)
+// t2 = make Stringer <- t0
+//
+type MakeInterface struct {
+ register
+ X Value
+}
+
+// The MakeClosure instruction yields a closure value whose code is
+// Fn and whose free variables' values are supplied by Bindings.
+//
+// Type() returns a (possibly named) *types.Signature.
+//
+// Pos() returns the ast.FuncLit.Type.Func for a function literal
+// closure or the ast.SelectorExpr.Sel for a bound method closure.
+//
+// Example printed form:
+// t0 = make closure anon@1.2 [x y z]
+// t1 = make closure bound$(main.I).add [i]
+//
+type MakeClosure struct {
+ register
+ Fn Value // always a *Function
+ Bindings []Value // values for each free variable in Fn.FreeVars
+}
+
+// The MakeMap instruction creates a new hash-table-based map object
+// and yields a value of kind map.
+//
+// Type() returns a (possibly named) *types.Map.
+//
+// Pos() returns the ast.CallExpr.Lparen, if created by make(map), or
+// the ast.CompositeLit.Lbrack if created by a literal.
+//
+// Example printed form:
+// t1 = make map[string]int t0
+// t1 = make StringIntMap t0
+//
+type MakeMap struct {
+ register
+ Reserve Value // initial space reservation; nil => default
+}
+
+// The MakeChan instruction creates a new channel object and yields a
+// value of kind chan.
+//
+// Type() returns a (possibly named) *types.Chan.
+//
+// Pos() returns the ast.CallExpr.Lparen for the make(chan) that
+// created it.
+//
+// Example printed form:
+// t0 = make chan int 0
+// t0 = make IntChan 0
+//
+type MakeChan struct {
+ register
+ Size Value // int; size of buffer; zero => synchronous.
+}
+
+// The MakeSlice instruction yields a slice of length Len backed by a
+// newly allocated array of length Cap.
+//
+// Both Len and Cap must be non-nil Values of integer type.
+//
+// (Alloc(types.Array) followed by Slice will not suffice because
+// Alloc can only create arrays of constant length.)
+//
+// Type() returns a (possibly named) *types.Slice.
+//
+// Pos() returns the ast.CallExpr.Lparen for the make([]T) that
+// created it.
+//
+// Example printed form:
+// t1 = make []string 1:int t0
+// t1 = make StringSlice 1:int t0
+//
+type MakeSlice struct {
+ register
+ Len Value
+ Cap Value
+}
+
+// The Slice instruction yields a slice of an existing string, slice
+// or *array X between optional integer bounds Low and High.
+//
+// Dynamically, this instruction panics if X evaluates to a nil *array
+// pointer.
+//
+// Type() returns string if the type of X was string, otherwise a
+// *types.Slice with the same element type as X.
+//
+// Pos() returns the ast.SliceExpr.Lbrack if created by a x[:] slice
+// operation, the ast.CompositeLit.Lbrace if created by a literal, or
+// NoPos if not explicit in the source (e.g. a variadic argument slice).
+//
+// Example printed form:
+// t1 = slice t0[1:]
+//
+type Slice struct {
+ register
+ X Value // slice, string, or *array
+ Low, High, Max Value // each may be nil
+}
+
+// The FieldAddr instruction yields the address of Field of *struct X.
+//
+// The field is identified by its index within the field list of the
+// struct type of X.
+//
+// Dynamically, this instruction panics if X evaluates to a nil
+// pointer.
+//
+// Type() returns a (possibly named) *types.Pointer.
+//
+// Pos() returns the position of the ast.SelectorExpr.Sel for the
+// field, if explicit in the source.
+//
+// Example printed form:
+// t1 = &t0.name [#1]
+//
+type FieldAddr struct {
+ register
+ X Value // *struct
+ Field int // index into X.Type().Deref().(*types.Struct).Fields
+}
+
+// The Field instruction yields the Field of struct X.
+//
+// The field is identified by its index within the field list of the
+// struct type of X; by using numeric indices we avoid ambiguity of
+// package-local identifiers and permit compact representations.
+//
+// Pos() returns the position of the ast.SelectorExpr.Sel for the
+// field, if explicit in the source.
+//
+// Example printed form:
+// t1 = t0.name [#1]
+//
+type Field struct {
+ register
+ X Value // struct
+ Field int // index into X.Type().(*types.Struct).Fields
+}
+
+// The IndexAddr instruction yields the address of the element at
+// index Index of collection X. Index is an integer expression.
+//
+// The elements of maps and strings are not addressable; use Lookup or
+// MapUpdate instead.
+//
+// Dynamically, this instruction panics if X evaluates to a nil *array
+// pointer.
+//
+// Type() returns a (possibly named) *types.Pointer.
+//
+// Pos() returns the ast.IndexExpr.Lbrack for the index operation, if
+// explicit in the source.
+//
+// Example printed form:
+// t2 = &t0[t1]
+//
+type IndexAddr struct {
+ register
+ X Value // slice or *array,
+ Index Value // numeric index
+}
+
+// The Index instruction yields element Index of array X.
+//
+// Pos() returns the ast.IndexExpr.Lbrack for the index operation, if
+// explicit in the source.
+//
+// Example printed form:
+// t2 = t0[t1]
+//
+type Index struct {
+ register
+ X Value // array
+ Index Value // integer index
+}
+
+// The Lookup instruction yields element Index of collection X, a map
+// or string. Index is an integer expression if X is a string or the
+// appropriate key type if X is a map.
+//
+// If CommaOk, the result is a 2-tuple of the value above and a
+// boolean indicating the result of a map membership test for the key.
+// The components of the tuple are accessed using Extract.
+//
+// Pos() returns the ast.IndexExpr.Lbrack, if explicit in the source.
+//
+// Example printed form:
+// t2 = t0[t1]
+// t5 = t3[t4],ok
+//
+type Lookup struct {
+ register
+ X Value // string or map
+ Index Value // numeric or key-typed index
+ CommaOk bool // return a value,ok pair
+}
+
+// SelectState is a helper for Select.
+// It represents one goal state and its corresponding communication.
+//
+type SelectState struct {
+ Dir types.ChanDir // direction of case (SendOnly or RecvOnly)
+ Chan Value // channel to use (for send or receive)
+ Send Value // value to send (for send)
+ Pos token.Pos // position of token.ARROW
+ DebugNode ast.Node // ast.SendStmt or ast.UnaryExpr(<-) [debug mode]
+}
+
+// The Select instruction tests whether (or blocks until) one
+// of the specified sent or received states is entered.
+//
+// Let n be the number of States for which Dir==RECV and T_i (0<=i<n)
+// be the element type of each such state's Chan.
+// Select returns an n+2-tuple
+// (index int, recvOk bool, r_0 T_0, ... r_n-1 T_n-1)
+// The tuple's components, described below, must be accessed via the
+// Extract instruction.
+//
+// If Blocking, select waits until exactly one state holds, i.e. a
+// channel becomes ready for the designated operation of sending or
+// receiving; select chooses one among the ready states
+// pseudorandomly, performs the send or receive operation, and sets
+// 'index' to the index of the chosen channel.
+//
+// If !Blocking, select doesn't block if no states hold; instead it
+// returns immediately with index equal to -1.
+//
+// If the chosen channel was used for a receive, the r_i component is
+// set to the received value, where i is the index of that state among
+// all n receive states; otherwise r_i has the zero value of type T_i.
+// Note that the receive index i is not the same as the state
+// index index.
+//
+// The second component of the triple, recvOk, is a boolean whose value
+// is true iff the selected operation was a receive and the receive
+// successfully yielded a value.
+//
+// Pos() returns the ast.SelectStmt.Select.
+//
+// Example printed form:
+// t3 = select nonblocking [<-t0, t1<-t2]
+// t4 = select blocking []
+//
+type Select struct {
+ register
+ States []*SelectState
+ Blocking bool
+}
+
+// The Range instruction yields an iterator over the domain and range
+// of X, which must be a string or map.
+//
+// Elements are accessed via Next.
+//
+// Type() returns an opaque and degenerate "rangeIter" type.
+//
+// Pos() returns the ast.RangeStmt.For.
+//
+// Example printed form:
+// t0 = range "hello":string
+//
+type Range struct {
+ register
+ X Value // string or map
+}
+
+// The Next instruction reads and advances the (map or string)
+// iterator Iter and returns a 3-tuple value (ok, k, v). If the
+// iterator is not exhausted, ok is true and k and v are the next
+// elements of the domain and range, respectively. Otherwise ok is
+// false and k and v are undefined.
+//
+// Components of the tuple are accessed using Extract.
+//
+// The IsString field distinguishes iterators over strings from those
+// over maps, as the Type() alone is insufficient: consider
+// map[int]rune.
+//
+// Type() returns a *types.Tuple for the triple (ok, k, v).
+// The types of k and/or v may be types.Invalid.
+//
+// Example printed form:
+// t1 = next t0
+//
+type Next struct {
+ register
+ Iter Value
+ IsString bool // true => string iterator; false => map iterator.
+}
+
+// The TypeAssert instruction tests whether interface value X has type
+// AssertedType.
+//
+// If !CommaOk, on success it returns v, the result of the conversion
+// (defined below); on failure it panics.
+//
+// If CommaOk: on success it returns a pair (v, true) where v is the
+// result of the conversion; on failure it returns (z, false) where z
+// is AssertedType's zero value. The components of the pair must be
+// accessed using the Extract instruction.
+//
+// If AssertedType is a concrete type, TypeAssert checks whether the
+// dynamic type in interface X is equal to it, and if so, the result
+// of the conversion is a copy of the value in the interface.
+//
+// If AssertedType is an interface, TypeAssert checks whether the
+// dynamic type of the interface is assignable to it, and if so, the
+// result of the conversion is a copy of the interface value X.
+// If AssertedType is a superinterface of X.Type(), the operation will
+// fail iff the operand is nil. (Contrast with ChangeInterface, which
+// performs no nil-check.)
+//
+// Type() reflects the actual type of the result, possibly a
+// 2-types.Tuple; AssertedType is the asserted type.
+//
+// Pos() returns the ast.CallExpr.Lparen if the instruction arose from
+// an explicit T(e) conversion; the ast.TypeAssertExpr.Lparen if the
+// instruction arose from an explicit e.(T) operation; or the
+// ast.CaseClause.Case if the instruction arose from a case of a
+// type-switch statement.
+//
+// Example printed form:
+// t1 = typeassert t0.(int)
+// t3 = typeassert,ok t2.(T)
+//
+type TypeAssert struct {
+ register
+ X Value
+ AssertedType types.Type
+ CommaOk bool
+}
+
+// The Extract instruction yields component Index of Tuple.
+//
+// This is used to access the results of instructions with multiple
+// return values, such as Call, TypeAssert, Next, UnOp(ARROW) and
+// IndexExpr(Map).
+//
+// Example printed form:
+// t1 = extract t0 #1
+//
+type Extract struct {
+ register
+ Tuple Value
+ Index int
+}
+
+// Instructions executed for effect. They do not yield a value. --------------------
+
+// The Jump instruction transfers control to the sole successor of its
+// owning block.
+//
+// A Jump must be the last instruction of its containing BasicBlock.
+//
+// Pos() returns NoPos.
+//
+// Example printed form:
+// jump done
+//
+type Jump struct {
+ anInstruction
+}
+
+// The If instruction transfers control to one of the two successors
+// of its owning block, depending on the boolean Cond: the first if
+// true, the second if false.
+//
+// An If instruction must be the last instruction of its containing
+// BasicBlock.
+//
+// Pos() returns NoPos.
+//
+// Example printed form:
+// if t0 goto done else body
+//
+type If struct {
+ anInstruction
+ Cond Value
+}
+
+// The Return instruction returns values and control back to the calling
+// function.
+//
+// len(Results) is always equal to the number of results in the
+// function's signature.
+//
+// If len(Results) > 1, Return returns a tuple value with the specified
+// components which the caller must access using Extract instructions.
+//
+// There is no instruction to return a ready-made tuple like those
+// returned by a "value,ok"-mode TypeAssert, Lookup or UnOp(ARROW) or
+// a tail-call to a function with multiple result parameters.
+//
+// Return must be the last instruction of its containing BasicBlock.
+// Such a block has no successors.
+//
+// Pos() returns the ast.ReturnStmt.Return, if explicit in the source.
+//
+// Example printed form:
+// return
+// return nil:I, 2:int
+//
+type Return struct {
+ anInstruction
+ Results []Value
+ pos token.Pos
+}
+
+// The RunDefers instruction pops and invokes the entire stack of
+// procedure calls pushed by Defer instructions in this function.
+//
+// It is legal to encounter multiple 'rundefers' instructions in a
+// single control-flow path through a function; this is useful in
+// the combined init() function, for example.
+//
+// Pos() returns NoPos.
+//
+// Example printed form:
+// rundefers
+//
+type RunDefers struct {
+ anInstruction
+}
+
+// The Panic instruction initiates a panic with value X.
+//
+// A Panic instruction must be the last instruction of its containing
+// BasicBlock, which must have no successors.
+//
+// NB: 'go panic(x)' and 'defer panic(x)' do not use this instruction;
+// they are treated as calls to a built-in function.
+//
+// Pos() returns the ast.CallExpr.Lparen if this panic was explicit
+// in the source.
+//
+// Example printed form:
+// panic t0
+//
+type Panic struct {
+ anInstruction
+ X Value // an interface{}
+ pos token.Pos
+}
+
+// The Go instruction creates a new goroutine and calls the specified
+// function within it.
+//
+// See CallCommon for generic function call documentation.
+//
+// Pos() returns the ast.GoStmt.Go.
+//
+// Example printed form:
+// go println(t0, t1)
+// go t3()
+// go invoke t5.Println(...t6)
+//
+type Go struct {
+ anInstruction
+ Call CallCommon
+ pos token.Pos
+}
+
+// The Defer instruction pushes the specified call onto a stack of
+// functions to be called by a RunDefers instruction or by a panic.
+//
+// See CallCommon for generic function call documentation.
+//
+// Pos() returns the ast.DeferStmt.Defer.
+//
+// Example printed form:
+// defer println(t0, t1)
+// defer t3()
+// defer invoke t5.Println(...t6)
+//
+type Defer struct {
+ anInstruction
+ Call CallCommon
+ pos token.Pos
+}
+
+// The Send instruction sends X on channel Chan.
+//
+// Pos() returns the ast.SendStmt.Arrow, if explicit in the source.
+//
+// Example printed form:
+// send t0 <- t1
+//
+type Send struct {
+ anInstruction
+ Chan, X Value
+ pos token.Pos
+}
+
+// The Store instruction stores Val at address Addr.
+// Stores can be of arbitrary types.
+//
+// Pos() returns the position of the source-level construct most closely
+// associated with the memory store operation.
+// Since implicit memory stores are numerous and varied and depend upon
+// implementation choices, the details are not specified.
+//
+// Example printed form:
+// *x = y
+//
+type Store struct {
+ anInstruction
+ Addr Value
+ Val Value
+ pos token.Pos
+}
+
+// The MapUpdate instruction updates the association of Map[Key] to
+// Value.
+//
+// Pos() returns the ast.KeyValueExpr.Colon or ast.IndexExpr.Lbrack,
+// if explicit in the source.
+//
+// Example printed form:
+// t0[t1] = t2
+//
+type MapUpdate struct {
+ anInstruction
+ Map Value
+ Key Value
+ Value Value
+ pos token.Pos
+}
+
+// A DebugRef instruction maps a source-level expression Expr to the
+// SSA value X that represents the value (!IsAddr) or address (IsAddr)
+// of that expression.
+//
+// DebugRef is a pseudo-instruction: it has no dynamic effect.
+//
+// Pos() returns Expr.Pos(), the start position of the source-level
+// expression. This is not the same as the "designated" token as
+// documented at Value.Pos(). e.g. CallExpr.Pos() does not return the
+// position of the ("designated") Lparen token.
+//
+// If Expr is an *ast.Ident denoting a var or func, Object() returns
+// the object; though this information can be obtained from the type
+// checker, including it here greatly facilitates debugging.
+// For non-Ident expressions, Object() returns nil.
+//
+// DebugRefs are generated only for functions built with debugging
+// enabled; see Package.SetDebugMode() and the GlobalDebug builder
+// mode flag.
+//
+// DebugRefs are not emitted for ast.Idents referring to constants or
+// predeclared identifiers, since they are trivial and numerous.
+// Nor are they emitted for ast.ParenExprs.
+//
+// (By representing these as instructions, rather than out-of-band,
+// consistency is maintained during transformation passes by the
+// ordinary SSA renaming machinery.)
+//
+// Example printed form:
+// ; *ast.CallExpr @ 102:9 is t5
+// ; var x float64 @ 109:72 is x
+// ; address of *ast.CompositeLit @ 216:10 is t0
+//
+type DebugRef struct {
+ anInstruction
+ Expr ast.Expr // the referring expression (never *ast.ParenExpr)
+ object types.Object // the identity of the source var/func
+ IsAddr bool // Expr is addressable and X is the address it denotes
+ X Value // the value or address of Expr
+}
+
+// Embeddable mix-ins and helpers for common parts of other structs. -----------
+
+// register is a mix-in embedded by all SSA values that are also
+// instructions, i.e. virtual registers, and provides a uniform
+// implementation of most of the Value interface: Value.Name() is a
+// numbered register (e.g. "t0"); the other methods are field accessors.
+//
+// Temporary names are automatically assigned to each register on
+// completion of building a function in SSA form.
+//
+// Clients must not assume that the 'id' value (and the Name() derived
+// from it) is unique within a function. As always in this API,
+// semantics are determined only by identity; names exist only to
+// facilitate debugging.
+//
+type register struct {
+ anInstruction
+ num int // "name" of virtual register, e.g. "t0". Not guaranteed unique.
+ typ types.Type // type of virtual register
+ pos token.Pos // position of source expression, or NoPos
+ referrers []Instruction
+}
+
+// anInstruction is a mix-in embedded by all Instructions.
+// It provides the implementations of the Block and setBlock methods.
+type anInstruction struct {
+ block *BasicBlock // the basic block of this instruction
+}
+
+// CallCommon is contained by Go, Defer and Call to hold the
+// common parts of a function or method call.
+//
+// Each CallCommon exists in one of two modes, function call and
+// interface method invocation, or "call" and "invoke" for short.
+//
+// 1. "call" mode: when Method is nil (!IsInvoke), a CallCommon
+// represents an ordinary function call of the value in Value,
+// which may be a *Builtin, a *Function or any other value of kind
+// 'func'.
+//
+// Value may be one of:
+// (a) a *Function, indicating a statically dispatched call
+// to a package-level function, an anonymous function, or
+// a method of a named type.
+// (b) a *MakeClosure, indicating an immediately applied
+// function literal with free variables.
+// (c) a *Builtin, indicating a statically dispatched call
+// to a built-in function.
+// (d) any other value, indicating a dynamically dispatched
+// function call.
+// StaticCallee returns the identity of the callee in cases
+// (a) and (b), nil otherwise.
+//
+// Args contains the arguments to the call. If Value is a method,
+// Args[0] contains the receiver parameter.
+//
+// Example printed form:
+// t2 = println(t0, t1)
+// go t3()
+// defer t5(...t6)
+//
+// 2. "invoke" mode: when Method is non-nil (IsInvoke), a CallCommon
+// represents a dynamically dispatched call to an interface method.
+// In this mode, Value is the interface value and Method is the
+// interface's abstract method. Note: an abstract method may be
+// shared by multiple interfaces due to embedding; Value.Type()
+// provides the specific interface used for this call.
+//
+// Value is implicitly supplied to the concrete method implementation
+// as the receiver parameter; in other words, Args[0] holds not the
+// receiver but the first true argument.
+//
+// Example printed form:
+// t1 = invoke t0.String()
+// go invoke t3.Run(t2)
+// defer invoke t4.Handle(...t5)
+//
+// For all calls to variadic functions (Signature().Variadic()),
+// the last element of Args is a slice.
+//
+type CallCommon struct {
+ Value Value // receiver (invoke mode) or func value (call mode)
+ Method *types.Func // abstract method (invoke mode)
+ Args []Value // actual parameters (in static method call, includes receiver)
+ pos token.Pos // position of CallExpr.Lparen, iff explicit in source
+}
+
+// IsInvoke returns true if this call has "invoke" (not "call") mode.
+func (c *CallCommon) IsInvoke() bool {
+ return c.Method != nil
+}
+
+func (c *CallCommon) Pos() token.Pos { return c.pos }
+
+// Signature returns the signature of the called function.
+//
+// For an "invoke"-mode call, the signature of the interface method is
+// returned.
+//
+// In either "call" or "invoke" mode, if the callee is a method, its
+// receiver is represented by sig.Recv, not sig.Params().At(0).
+//
+func (c *CallCommon) Signature() *types.Signature {
+ if c.Method != nil {
+ return c.Method.Type().(*types.Signature)
+ }
+ return c.Value.Type().Underlying().(*types.Signature)
+}
+
+// StaticCallee returns the callee if this is a trivially static
+// "call"-mode call to a function.
+func (c *CallCommon) StaticCallee() *Function {
+ switch fn := c.Value.(type) {
+ case *Function:
+ return fn
+ case *MakeClosure:
+ return fn.Fn.(*Function)
+ }
+ return nil
+}
+
+// Description returns a description of the mode of this call suitable
+// for a user interface, e.g., "static method call".
+func (c *CallCommon) Description() string {
+ switch fn := c.Value.(type) {
+ case *Builtin:
+ return "built-in function call"
+ case *MakeClosure:
+ return "static function closure call"
+ case *Function:
+ if fn.Signature.Recv() != nil {
+ return "static method call"
+ }
+ return "static function call"
+ }
+ if c.IsInvoke() {
+ return "dynamic method call" // ("invoke" mode)
+ }
+ return "dynamic function call"
+}
+
+// The CallInstruction interface, implemented by *Go, *Defer and *Call,
+// exposes the common parts of function-calling instructions,
+// yet provides a way back to the Value defined by *Call alone.
+//
+type CallInstruction interface {
+ Instruction
+ Common() *CallCommon // returns the common parts of the call
+ Value() *Call // returns the result value of the call (*Call) or nil (*Go, *Defer)
+}
+
+func (s *Call) Common() *CallCommon { return &s.Call }
+func (s *Defer) Common() *CallCommon { return &s.Call }
+func (s *Go) Common() *CallCommon { return &s.Call }
+
+func (s *Call) Value() *Call { return s }
+func (s *Defer) Value() *Call { return nil }
+func (s *Go) Value() *Call { return nil }
+
+func (v *Builtin) Type() types.Type { return v.sig }
+func (v *Builtin) Name() string { return v.name }
+func (*Builtin) Referrers() *[]Instruction { return nil }
+func (v *Builtin) Pos() token.Pos { return token.NoPos }
+func (v *Builtin) Object() types.Object { return types.Universe.Lookup(v.name) }
+func (v *Builtin) Parent() *Function { return nil }
+
+func (v *FreeVar) Type() types.Type { return v.typ }
+func (v *FreeVar) Name() string { return v.name }
+func (v *FreeVar) Referrers() *[]Instruction { return &v.referrers }
+func (v *FreeVar) Pos() token.Pos { return v.pos }
+func (v *FreeVar) Parent() *Function { return v.parent }
+
+func (v *Global) Type() types.Type { return v.typ }
+func (v *Global) Name() string { return v.name }
+func (v *Global) Parent() *Function { return nil }
+func (v *Global) Pos() token.Pos { return v.pos }
+func (v *Global) Referrers() *[]Instruction { return nil }
+func (v *Global) Token() token.Token { return token.VAR }
+func (v *Global) Object() types.Object { return v.object }
+func (v *Global) String() string { return v.RelString(nil) }
+func (v *Global) Package() *Package { return v.Pkg }
+func (v *Global) RelString(from *types.Package) string { return relString(v, from) }
+
+func (v *Function) Name() string { return v.name }
+func (v *Function) Type() types.Type { return v.Signature }
+func (v *Function) Pos() token.Pos { return v.pos }
+func (v *Function) Token() token.Token { return token.FUNC }
+func (v *Function) Object() types.Object { return v.object }
+func (v *Function) String() string { return v.RelString(nil) }
+func (v *Function) Package() *Package { return v.Pkg }
+func (v *Function) Parent() *Function { return v.parent }
+func (v *Function) Referrers() *[]Instruction {
+ if v.parent != nil {
+ return &v.referrers
+ }
+ return nil
+}
+
+func (v *Parameter) Type() types.Type { return v.typ }
+func (v *Parameter) Name() string { return v.name }
+func (v *Parameter) Object() types.Object { return v.object }
+func (v *Parameter) Referrers() *[]Instruction { return &v.referrers }
+func (v *Parameter) Pos() token.Pos { return v.pos }
+func (v *Parameter) Parent() *Function { return v.parent }
+
+func (v *Alloc) Type() types.Type { return v.typ }
+func (v *Alloc) Referrers() *[]Instruction { return &v.referrers }
+func (v *Alloc) Pos() token.Pos { return v.pos }
+
+func (v *register) Type() types.Type { return v.typ }
+func (v *register) setType(typ types.Type) { v.typ = typ }
+func (v *register) Name() string { return fmt.Sprintf("t%d", v.num) }
+func (v *register) setNum(num int) { v.num = num }
+func (v *register) Referrers() *[]Instruction { return &v.referrers }
+func (v *register) Pos() token.Pos { return v.pos }
+func (v *register) setPos(pos token.Pos) { v.pos = pos }
+
+func (v *anInstruction) Parent() *Function { return v.block.parent }
+func (v *anInstruction) Block() *BasicBlock { return v.block }
+func (v *anInstruction) setBlock(block *BasicBlock) { v.block = block }
+func (v *anInstruction) Referrers() *[]Instruction { return nil }
+
+func (t *Type) Name() string { return t.object.Name() }
+func (t *Type) Pos() token.Pos { return t.object.Pos() }
+func (t *Type) Type() types.Type { return t.object.Type() }
+func (t *Type) Token() token.Token { return token.TYPE }
+func (t *Type) Object() types.Object { return t.object }
+func (t *Type) String() string { return t.RelString(nil) }
+func (t *Type) Package() *Package { return t.pkg }
+func (t *Type) RelString(from *types.Package) string { return relString(t, from) }
+
+func (c *NamedConst) Name() string { return c.object.Name() }
+func (c *NamedConst) Pos() token.Pos { return c.object.Pos() }
+func (c *NamedConst) String() string { return c.RelString(nil) }
+func (c *NamedConst) Type() types.Type { return c.object.Type() }
+func (c *NamedConst) Token() token.Token { return token.CONST }
+func (c *NamedConst) Object() types.Object { return c.object }
+func (c *NamedConst) Package() *Package { return c.pkg }
+func (c *NamedConst) RelString(from *types.Package) string { return relString(c, from) }
+
+// Func returns the package-level function of the specified name,
+// or nil if not found.
+//
+func (p *Package) Func(name string) (f *Function) {
+ f, _ = p.Members[name].(*Function)
+ return
+}
+
+// Var returns the package-level variable of the specified name,
+// or nil if not found.
+//
+func (p *Package) Var(name string) (g *Global) {
+ g, _ = p.Members[name].(*Global)
+ return
+}
+
+// Const returns the package-level constant of the specified name,
+// or nil if not found.
+//
+func (p *Package) Const(name string) (c *NamedConst) {
+ c, _ = p.Members[name].(*NamedConst)
+ return
+}
+
+// Type returns the package-level type of the specified name,
+// or nil if not found.
+//
+func (p *Package) Type(name string) (t *Type) {
+ t, _ = p.Members[name].(*Type)
+ return
+}
+
+func (v *Call) Pos() token.Pos { return v.Call.pos }
+func (s *Defer) Pos() token.Pos { return s.pos }
+func (s *Go) Pos() token.Pos { return s.pos }
+func (s *MapUpdate) Pos() token.Pos { return s.pos }
+func (s *Panic) Pos() token.Pos { return s.pos }
+func (s *Return) Pos() token.Pos { return s.pos }
+func (s *Send) Pos() token.Pos { return s.pos }
+func (s *Store) Pos() token.Pos { return s.pos }
+func (s *If) Pos() token.Pos { return token.NoPos }
+func (s *Jump) Pos() token.Pos { return token.NoPos }
+func (s *RunDefers) Pos() token.Pos { return token.NoPos }
+func (s *DebugRef) Pos() token.Pos { return s.Expr.Pos() }
+
+// Operands.
+
+func (v *Alloc) Operands(rands []*Value) []*Value {
+ return rands
+}
+
+func (v *BinOp) Operands(rands []*Value) []*Value {
+ return append(rands, &v.X, &v.Y)
+}
+
+func (c *CallCommon) Operands(rands []*Value) []*Value {
+ rands = append(rands, &c.Value)
+ for i := range c.Args {
+ rands = append(rands, &c.Args[i])
+ }
+ return rands
+}
+
+func (s *Go) Operands(rands []*Value) []*Value {
+ return s.Call.Operands(rands)
+}
+
+func (s *Call) Operands(rands []*Value) []*Value {
+ return s.Call.Operands(rands)
+}
+
+func (s *Defer) Operands(rands []*Value) []*Value {
+ return s.Call.Operands(rands)
+}
+
+func (v *ChangeInterface) Operands(rands []*Value) []*Value {
+ return append(rands, &v.X)
+}
+
+func (v *ChangeType) Operands(rands []*Value) []*Value {
+ return append(rands, &v.X)
+}
+
+func (v *Convert) Operands(rands []*Value) []*Value {
+ return append(rands, &v.X)
+}
+
+func (s *DebugRef) Operands(rands []*Value) []*Value {
+ return append(rands, &s.X)
+}
+
+func (v *Extract) Operands(rands []*Value) []*Value {
+ return append(rands, &v.Tuple)
+}
+
+func (v *Field) Operands(rands []*Value) []*Value {
+ return append(rands, &v.X)
+}
+
+func (v *FieldAddr) Operands(rands []*Value) []*Value {
+ return append(rands, &v.X)
+}
+
+func (s *If) Operands(rands []*Value) []*Value {
+ return append(rands, &s.Cond)
+}
+
+func (v *Index) Operands(rands []*Value) []*Value {
+ return append(rands, &v.X, &v.Index)
+}
+
+func (v *IndexAddr) Operands(rands []*Value) []*Value {
+ return append(rands, &v.X, &v.Index)
+}
+
+func (*Jump) Operands(rands []*Value) []*Value {
+ return rands
+}
+
+func (v *Lookup) Operands(rands []*Value) []*Value {
+ return append(rands, &v.X, &v.Index)
+}
+
+func (v *MakeChan) Operands(rands []*Value) []*Value {
+ return append(rands, &v.Size)
+}
+
+func (v *MakeClosure) Operands(rands []*Value) []*Value {
+ rands = append(rands, &v.Fn)
+ for i := range v.Bindings {
+ rands = append(rands, &v.Bindings[i])
+ }
+ return rands
+}
+
+func (v *MakeInterface) Operands(rands []*Value) []*Value {
+ return append(rands, &v.X)
+}
+
+func (v *MakeMap) Operands(rands []*Value) []*Value {
+ return append(rands, &v.Reserve)
+}
+
+func (v *MakeSlice) Operands(rands []*Value) []*Value {
+ return append(rands, &v.Len, &v.Cap)
+}
+
+func (v *MapUpdate) Operands(rands []*Value) []*Value {
+ return append(rands, &v.Map, &v.Key, &v.Value)
+}
+
+func (v *Next) Operands(rands []*Value) []*Value {
+ return append(rands, &v.Iter)
+}
+
+func (s *Panic) Operands(rands []*Value) []*Value {
+ return append(rands, &s.X)
+}
+
+func (v *Phi) Operands(rands []*Value) []*Value {
+ for i := range v.Edges {
+ rands = append(rands, &v.Edges[i])
+ }
+ return rands
+}
+
+func (v *Range) Operands(rands []*Value) []*Value {
+ return append(rands, &v.X)
+}
+
+func (s *Return) Operands(rands []*Value) []*Value {
+ for i := range s.Results {
+ rands = append(rands, &s.Results[i])
+ }
+ return rands
+}
+
+func (*RunDefers) Operands(rands []*Value) []*Value {
+ return rands
+}
+
+func (v *Select) Operands(rands []*Value) []*Value {
+ for i := range v.States {
+ rands = append(rands, &v.States[i].Chan, &v.States[i].Send)
+ }
+ return rands
+}
+
+func (s *Send) Operands(rands []*Value) []*Value {
+ return append(rands, &s.Chan, &s.X)
+}
+
+func (v *Slice) Operands(rands []*Value) []*Value {
+ return append(rands, &v.X, &v.Low, &v.High, &v.Max)
+}
+
+func (s *Store) Operands(rands []*Value) []*Value {
+ return append(rands, &s.Addr, &s.Val)
+}
+
+func (v *TypeAssert) Operands(rands []*Value) []*Value {
+ return append(rands, &v.X)
+}
+
+func (v *UnOp) Operands(rands []*Value) []*Value {
+ return append(rands, &v.X)
+}
+
+// Non-Instruction Values:
+func (v *Builtin) Operands(rands []*Value) []*Value { return rands }
+func (v *FreeVar) Operands(rands []*Value) []*Value { return rands }
+func (v *Const) Operands(rands []*Value) []*Value { return rands }
+func (v *Function) Operands(rands []*Value) []*Value { return rands }
+func (v *Global) Operands(rands []*Value) []*Value { return rands }
+func (v *Parameter) Operands(rands []*Value) []*Value { return rands }
diff --git a/go/ssa/ssautil/load.go b/go/ssa/ssautil/load.go
new file mode 100644
index 0000000..c2b8ce1
--- /dev/null
+++ b/go/ssa/ssautil/load.go
@@ -0,0 +1,95 @@
+// 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 ssautil
+
+// This file defines utility functions for constructing programs in SSA form.
+
+import (
+ "go/ast"
+ "go/token"
+
+ "golang.org/x/tools/go/loader"
+ "golang.org/x/tools/go/ssa"
+ "golang.org/x/tools/go/types"
+)
+
+// CreateProgram returns a new program in SSA form, given a program
+// loaded from source. An SSA package is created for each transitively
+// error-free package of lprog.
+//
+// Code for bodies of functions is not built until BuildAll() is called
+// on the result.
+//
+// mode controls diagnostics and checking during SSA construction.
+//
+func CreateProgram(lprog *loader.Program, mode ssa.BuilderMode) *ssa.Program {
+ prog := ssa.NewProgram(lprog.Fset, mode)
+
+ for _, info := range lprog.AllPackages {
+ if info.TransitivelyErrorFree {
+ prog.CreatePackage(info.Pkg, info.Files, &info.Info, info.Importable)
+ }
+ }
+
+ return prog
+}
+
+// BuildPackage builds an SSA program with IR for a single package.
+//
+// It populates pkg by type-checking the specified file ASTs. All
+// dependencies are loaded using the importer specified by tc, which
+// typically loads compiler export data; SSA code cannot be built for
+// those packages. BuildPackage then constructs an ssa.Program with all
+// dependency packages created, and builds and returns the SSA package
+// corresponding to pkg.
+//
+// The caller must have set pkg.Path() to the import path.
+//
+// The operation fails if there were any type-checking or import errors.
+//
+// See ../ssa/example_test.go for an example.
+//
+func BuildPackage(tc *types.Config, fset *token.FileSet, pkg *types.Package, files []*ast.File, mode ssa.BuilderMode) (*ssa.Package, *types.Info, error) {
+ if fset == nil {
+ panic("no token.FileSet")
+ }
+ if pkg.Path() == "" {
+ panic("package has no import path")
+ }
+
+ info := &types.Info{
+ Types: make(map[ast.Expr]types.TypeAndValue),
+ Defs: make(map[*ast.Ident]types.Object),
+ Uses: make(map[*ast.Ident]types.Object),
+ Implicits: make(map[ast.Node]types.Object),
+ Scopes: make(map[ast.Node]*types.Scope),
+ Selections: make(map[*ast.SelectorExpr]*types.Selection),
+ }
+ if err := types.NewChecker(tc, fset, pkg, info).Files(files); err != nil {
+ return nil, nil, err
+ }
+
+ prog := ssa.NewProgram(fset, mode)
+
+ // Create SSA packages for all imports.
+ // Order is not significant.
+ created := make(map[*types.Package]bool)
+ var createAll func(pkgs []*types.Package)
+ createAll = func(pkgs []*types.Package) {
+ for _, p := range pkgs {
+ if !created[p] {
+ created[p] = true
+ prog.CreatePackage(p, nil, nil, true)
+ createAll(p.Imports())
+ }
+ }
+ }
+ createAll(pkg.Imports())
+
+ // Create and build the primary package.
+ ssapkg := prog.CreatePackage(pkg, files, info, false)
+ ssapkg.Build()
+ return ssapkg, info, nil
+}
diff --git a/go/ssa/ssautil/load_test.go b/go/ssa/ssautil/load_test.go
new file mode 100644
index 0000000..458d2dc
--- /dev/null
+++ b/go/ssa/ssautil/load_test.go
@@ -0,0 +1,65 @@
+// 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 ssautil_test
+
+import (
+ "go/ast"
+ "go/parser"
+ "go/token"
+ "os"
+ "testing"
+
+ "golang.org/x/tools/go/ssa/ssautil"
+ "golang.org/x/tools/go/types"
+
+ _ "golang.org/x/tools/go/gcimporter"
+)
+
+const hello = `package main
+
+import "fmt"
+
+func main() {
+ fmt.Println("Hello, world")
+}
+`
+
+func TestBuildPackage(t *testing.T) {
+ // There is a more substantial test of BuildPackage and the
+ // SSA program it builds in ../ssa/builder_test.go.
+
+ fset := token.NewFileSet()
+ f, err := parser.ParseFile(fset, "hello.go", hello, 0)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ pkg := types.NewPackage("hello", "")
+ ssapkg, _, err := ssautil.BuildPackage(new(types.Config), fset, pkg, []*ast.File{f}, 0)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if pkg.Name() != "main" {
+ t.Errorf("pkg.Name() = %s, want main", pkg.Name())
+ }
+ if ssapkg.Func("main") == nil {
+ ssapkg.WriteTo(os.Stderr)
+ t.Errorf("ssapkg has no main function")
+ }
+}
+
+func TestBuildPackage_MissingImport(t *testing.T) {
+ fset := token.NewFileSet()
+ f, err := parser.ParseFile(fset, "bad.go", `package bad; import "missing"`, 0)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ pkg := types.NewPackage("bad", "")
+ ssapkg, _, err := ssautil.BuildPackage(new(types.Config), fset, pkg, []*ast.File{f}, 0)
+ if err == nil || ssapkg != nil {
+ t.Fatal("BuildPackage succeeded unexpectedly")
+ }
+}
diff --git a/go/ssa/ssautil/switch.go b/go/ssa/ssautil/switch.go
new file mode 100644
index 0000000..70fff9c
--- /dev/null
+++ b/go/ssa/ssautil/switch.go
@@ -0,0 +1,234 @@
+// 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 ssautil
+
+// This file implements discovery of switch and type-switch constructs
+// from low-level control flow.
+//
+// Many techniques exist for compiling a high-level switch with
+// constant cases to efficient machine code. The optimal choice will
+// depend on the data type, the specific case values, the code in the
+// body of each case, and the hardware.
+// Some examples:
+// - a lookup table (for a switch that maps constants to constants)
+// - a computed goto
+// - a binary tree
+// - a perfect hash
+// - a two-level switch (to partition constant strings by their first byte).
+
+import (
+ "bytes"
+ "fmt"
+ "go/token"
+
+ "golang.org/x/tools/go/ssa"
+ "golang.org/x/tools/go/types"
+)
+
+// A ConstCase represents a single constant comparison.
+// It is part of a Switch.
+type ConstCase struct {
+ Block *ssa.BasicBlock // block performing the comparison
+ Body *ssa.BasicBlock // body of the case
+ Value *ssa.Const // case comparand
+}
+
+// A TypeCase represents a single type assertion.
+// It is part of a Switch.
+type TypeCase struct {
+ Block *ssa.BasicBlock // block performing the type assert
+ Body *ssa.BasicBlock // body of the case
+ Type types.Type // case type
+ Binding ssa.Value // value bound by this case
+}
+
+// A Switch is a logical high-level control flow operation
+// (a multiway branch) discovered by analysis of a CFG containing
+// only if/else chains. It is not part of the ssa.Instruction set.
+//
+// One of ConstCases and TypeCases has length >= 2;
+// the other is nil.
+//
+// In a value switch, the list of cases may contain duplicate constants.
+// A type switch may contain duplicate types, or types assignable
+// to an interface type also in the list.
+// TODO(adonovan): eliminate such duplicates.
+//
+type Switch struct {
+ Start *ssa.BasicBlock // block containing start of if/else chain
+ X ssa.Value // the switch operand
+ ConstCases []ConstCase // ordered list of constant comparisons
+ TypeCases []TypeCase // ordered list of type assertions
+ Default *ssa.BasicBlock // successor if all comparisons fail
+}
+
+func (sw *Switch) String() string {
+ // We represent each block by the String() of its
+ // first Instruction, e.g. "print(42:int)".
+ var buf bytes.Buffer
+ if sw.ConstCases != nil {
+ fmt.Fprintf(&buf, "switch %s {\n", sw.X.Name())
+ for _, c := range sw.ConstCases {
+ fmt.Fprintf(&buf, "case %s: %s\n", c.Value, c.Body.Instrs[0])
+ }
+ } else {
+ fmt.Fprintf(&buf, "switch %s.(type) {\n", sw.X.Name())
+ for _, c := range sw.TypeCases {
+ fmt.Fprintf(&buf, "case %s %s: %s\n",
+ c.Binding.Name(), c.Type, c.Body.Instrs[0])
+ }
+ }
+ if sw.Default != nil {
+ fmt.Fprintf(&buf, "default: %s\n", sw.Default.Instrs[0])
+ }
+ fmt.Fprintf(&buf, "}")
+ return buf.String()
+}
+
+// Switches examines the control-flow graph of fn and returns the
+// set of inferred value and type switches. A value switch tests an
+// ssa.Value for equality against two or more compile-time constant
+// values. Switches involving link-time constants (addresses) are
+// ignored. A type switch type-asserts an ssa.Value against two or
+// more types.
+//
+// The switches are returned in dominance order.
+//
+// The resulting switches do not necessarily correspond to uses of the
+// 'switch' keyword in the source: for example, a single source-level
+// switch statement with non-constant cases may result in zero, one or
+// many Switches, one per plural sequence of constant cases.
+// Switches may even be inferred from if/else- or goto-based control flow.
+// (In general, the control flow constructs of the source program
+// cannot be faithfully reproduced from the SSA representation.)
+//
+func Switches(fn *ssa.Function) []Switch {
+ // Traverse the CFG in dominance order, so we don't
+ // enter an if/else-chain in the middle.
+ var switches []Switch
+ seen := make(map[*ssa.BasicBlock]bool) // TODO(adonovan): opt: use ssa.blockSet
+ for _, b := range fn.DomPreorder() {
+ if x, k := isComparisonBlock(b); x != nil {
+ // Block b starts a switch.
+ sw := Switch{Start: b, X: x}
+ valueSwitch(&sw, k, seen)
+ if len(sw.ConstCases) > 1 {
+ switches = append(switches, sw)
+ }
+ }
+
+ if y, x, T := isTypeAssertBlock(b); y != nil {
+ // Block b starts a type switch.
+ sw := Switch{Start: b, X: x}
+ typeSwitch(&sw, y, T, seen)
+ if len(sw.TypeCases) > 1 {
+ switches = append(switches, sw)
+ }
+ }
+ }
+ return switches
+}
+
+func valueSwitch(sw *Switch, k *ssa.Const, seen map[*ssa.BasicBlock]bool) {
+ b := sw.Start
+ x := sw.X
+ for x == sw.X {
+ if seen[b] {
+ break
+ }
+ seen[b] = true
+
+ sw.ConstCases = append(sw.ConstCases, ConstCase{
+ Block: b,
+ Body: b.Succs[0],
+ Value: k,
+ })
+ b = b.Succs[1]
+ if len(b.Instrs) > 2 {
+ // Block b contains not just 'if x == k',
+ // so it may have side effects that
+ // make it unsafe to elide.
+ break
+ }
+ if len(b.Preds) != 1 {
+ // Block b has multiple predecessors,
+ // so it cannot be treated as a case.
+ break
+ }
+ x, k = isComparisonBlock(b)
+ }
+ sw.Default = b
+}
+
+func typeSwitch(sw *Switch, y ssa.Value, T types.Type, seen map[*ssa.BasicBlock]bool) {
+ b := sw.Start
+ x := sw.X
+ for x == sw.X {
+ if seen[b] {
+ break
+ }
+ seen[b] = true
+
+ sw.TypeCases = append(sw.TypeCases, TypeCase{
+ Block: b,
+ Body: b.Succs[0],
+ Type: T,
+ Binding: y,
+ })
+ b = b.Succs[1]
+ if len(b.Instrs) > 4 {
+ // Block b contains not just
+ // {TypeAssert; Extract #0; Extract #1; If}
+ // so it may have side effects that
+ // make it unsafe to elide.
+ break
+ }
+ if len(b.Preds) != 1 {
+ // Block b has multiple predecessors,
+ // so it cannot be treated as a case.
+ break
+ }
+ y, x, T = isTypeAssertBlock(b)
+ }
+ sw.Default = b
+}
+
+// isComparisonBlock returns the operands (v, k) if a block ends with
+// a comparison v==k, where k is a compile-time constant.
+//
+func isComparisonBlock(b *ssa.BasicBlock) (v ssa.Value, k *ssa.Const) {
+ if n := len(b.Instrs); n >= 2 {
+ if i, ok := b.Instrs[n-1].(*ssa.If); ok {
+ if binop, ok := i.Cond.(*ssa.BinOp); ok && binop.Block() == b && binop.Op == token.EQL {
+ if k, ok := binop.Y.(*ssa.Const); ok {
+ return binop.X, k
+ }
+ if k, ok := binop.X.(*ssa.Const); ok {
+ return binop.Y, k
+ }
+ }
+ }
+ }
+ return
+}
+
+// isTypeAssertBlock returns the operands (y, x, T) if a block ends with
+// a type assertion "if y, ok := x.(T); ok {".
+//
+func isTypeAssertBlock(b *ssa.BasicBlock) (y, x ssa.Value, T types.Type) {
+ if n := len(b.Instrs); n >= 4 {
+ if i, ok := b.Instrs[n-1].(*ssa.If); ok {
+ if ext1, ok := i.Cond.(*ssa.Extract); ok && ext1.Block() == b && ext1.Index == 1 {
+ if ta, ok := ext1.Tuple.(*ssa.TypeAssert); ok && ta.Block() == b {
+ // hack: relies upon instruction ordering.
+ if ext0, ok := b.Instrs[n-3].(*ssa.Extract); ok {
+ return ext0, ta.X, ta.AssertedType
+ }
+ }
+ }
+ }
+ }
+ return
+}
diff --git a/go/ssa/ssautil/switch_test.go b/go/ssa/ssautil/switch_test.go
new file mode 100644
index 0000000..a47dbef
--- /dev/null
+++ b/go/ssa/ssautil/switch_test.go
@@ -0,0 +1,74 @@
+// 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 ssautil_test
+
+import (
+ "go/parser"
+ "strings"
+ "testing"
+
+ "golang.org/x/tools/go/loader"
+ "golang.org/x/tools/go/ssa"
+ "golang.org/x/tools/go/ssa/ssautil"
+)
+
+func TestSwitches(t *testing.T) {
+ conf := loader.Config{ParserMode: parser.ParseComments}
+ f, err := conf.ParseFile("testdata/switches.go", nil)
+ if err != nil {
+ t.Error(err)
+ return
+ }
+
+ conf.CreateFromFiles("main", f)
+ iprog, err := conf.Load()
+ if err != nil {
+ t.Error(err)
+ return
+ }
+
+ prog := ssautil.CreateProgram(iprog, 0)
+ mainPkg := prog.Package(iprog.Created[0].Pkg)
+ mainPkg.Build()
+
+ for _, mem := range mainPkg.Members {
+ if fn, ok := mem.(*ssa.Function); ok {
+ if fn.Synthetic != "" {
+ continue // e.g. init()
+ }
+ // Each (multi-line) "switch" comment within
+ // this function must match the printed form
+ // of a ConstSwitch.
+ var wantSwitches []string
+ for _, c := range f.Comments {
+ if fn.Syntax().Pos() <= c.Pos() && c.Pos() < fn.Syntax().End() {
+ text := strings.TrimSpace(c.Text())
+ if strings.HasPrefix(text, "switch ") {
+ wantSwitches = append(wantSwitches, text)
+ }
+ }
+ }
+
+ switches := ssautil.Switches(fn)
+ if len(switches) != len(wantSwitches) {
+ t.Errorf("in %s, found %d switches, want %d", fn, len(switches), len(wantSwitches))
+ }
+ for i, sw := range switches {
+ got := sw.String()
+ if i >= len(wantSwitches) {
+ continue
+ }
+ want := wantSwitches[i]
+ if got != want {
+ t.Errorf("in %s, found switch %d: got <<%s>>, want <<%s>>", fn, i, got, want)
+ }
+ }
+ }
+ }
+}
diff --git a/go/ssa/ssautil/testdata/switches.go b/go/ssa/ssautil/testdata/switches.go
new file mode 100644
index 0000000..8ab4c11
--- /dev/null
+++ b/go/ssa/ssautil/testdata/switches.go
@@ -0,0 +1,357 @@
+// +build ignore
+
+package main
+
+// This file is the input to TestSwitches in switch_test.go.
+// Each multiway conditional with constant or type cases (Switch)
+// discovered by Switches is printed, and compared with the
+// comments.
+//
+// The body of each case is printed as the value of its first
+// instruction.
+
+// -------- Value switches --------
+
+func SimpleSwitch(x, y int) {
+ // switch x {
+ // case 1:int: print(1:int)
+ // case 2:int: print(23:int)
+ // case 3:int: print(23:int)
+ // case 4:int: print(3:int)
+ // default: x == y
+ // }
+ switch x {
+ case 1:
+ print(1)
+ case 2, 3:
+ print(23)
+ fallthrough
+ case 4:
+ print(3)
+ default:
+ print(4)
+ case y:
+ print(5)
+ }
+ print(6)
+}
+
+func four() int { return 4 }
+
+// A non-constant case makes a switch "impure", but its pure
+// cases form two separate switches.
+func SwitchWithNonConstantCase(x int) {
+ // switch x {
+ // case 1:int: print(1:int)
+ // case 2:int: print(23:int)
+ // case 3:int: print(23:int)
+ // default: four()
+ // }
+
+ // switch x {
+ // case 5:int: print(5:int)
+ // case 6:int: print(6:int)
+ // default: print("done":string)
+ // }
+ switch x {
+ case 1:
+ print(1)
+ case 2, 3:
+ print(23)
+ case four():
+ print(3)
+ case 5:
+ print(5)
+ case 6:
+ print(6)
+ }
+ print("done")
+}
+
+// Switches may be found even where the source
+// program doesn't have a switch statement.
+
+func ImplicitSwitches(x, y int) {
+ // switch x {
+ // case 1:int: print(12:int)
+ // case 2:int: print(12:int)
+ // default: x < 5:int
+ // }
+ if x == 1 || 2 == x || x < 5 {
+ print(12)
+ }
+
+ // switch x {
+ // case 3:int: print(34:int)
+ // case 4:int: print(34:int)
+ // default: x == y
+ // }
+ if x == 3 || 4 == x || x == y {
+ print(34)
+ }
+
+ // Not a switch: no consistent variable.
+ if x == 5 || y == 6 {
+ print(56)
+ }
+
+ // Not a switch: only one constant comparison.
+ if x == 7 || x == y {
+ print(78)
+ }
+}
+
+func IfElseBasedSwitch(x int) {
+ // switch x {
+ // case 1:int: print(1:int)
+ // case 2:int: print(2:int)
+ // default: print("else":string)
+ // }
+ if x == 1 {
+ print(1)
+ } else if x == 2 {
+ print(2)
+ } else {
+ print("else")
+ }
+}
+
+func GotoBasedSwitch(x int) {
+ // switch x {
+ // case 1:int: print(1:int)
+ // case 2:int: print(2:int)
+ // default: print("else":string)
+ // }
+ if x == 1 {
+ goto L1
+ }
+ if x == 2 {
+ goto L2
+ }
+ print("else")
+L1:
+ print(1)
+ goto end
+L2:
+ print(2)
+end:
+}
+
+func SwitchInAForLoop(x int) {
+ // switch x {
+ // case 1:int: print(1:int)
+ // case 2:int: print(2:int)
+ // default: print("head":string)
+ // }
+loop:
+ for {
+ print("head")
+ switch x {
+ case 1:
+ print(1)
+ break loop
+ case 2:
+ print(2)
+ break loop
+ }
+ }
+}
+
+// This case is a switch in a for-loop, both constructed using goto.
+// As before, the default case points back to the block containing the
+// switch, but that's ok.
+func SwitchInAForLoopUsingGoto(x int) {
+ // switch x {
+ // case 1:int: print(1:int)
+ // case 2:int: print(2:int)
+ // default: print("head":string)
+ // }
+loop:
+ print("head")
+ if x == 1 {
+ goto L1
+ }
+ if x == 2 {
+ goto L2
+ }
+ goto loop
+L1:
+ print(1)
+ goto end
+L2:
+ print(2)
+end:
+}
+
+func UnstructuredSwitchInAForLoop(x int) {
+ // switch x {
+ // case 1:int: print(1:int)
+ // case 2:int: x == 1:int
+ // default: print("end":string)
+ // }
+ for {
+ if x == 1 {
+ print(1)
+ return
+ }
+ if x == 2 {
+ continue
+ }
+ break
+ }
+ print("end")
+}
+
+func CaseWithMultiplePreds(x int) {
+ for {
+ if x == 1 {
+ print(1)
+ return
+ }
+ loop:
+ // This block has multiple predecessors,
+ // so can't be treated as a switch case.
+ if x == 2 {
+ goto loop
+ }
+ break
+ }
+ print("end")
+}
+
+func DuplicateConstantsAreNotEliminated(x int) {
+ // switch x {
+ // case 1:int: print(1:int)
+ // case 1:int: print("1a":string)
+ // case 2:int: print(2:int)
+ // default: return
+ // }
+ if x == 1 {
+ print(1)
+ } else if x == 1 { // duplicate => unreachable
+ print("1a")
+ } else if x == 2 {
+ print(2)
+ }
+}
+
+// Interface values (created by comparisons) are not constants,
+// so ConstSwitch.X is never of interface type.
+func MakeInterfaceIsNotAConstant(x interface{}) {
+ if x == "foo" {
+ print("foo")
+ } else if x == 1 {
+ print(1)
+ }
+}
+
+func ZeroInitializedVarsAreConstants(x int) {
+ // switch x {
+ // case 0:int: print(1:int)
+ // case 2:int: print(2:int)
+ // default: print("end":string)
+ // }
+ var zero int // SSA construction replaces zero with 0
+ if x == zero {
+ print(1)
+ } else if x == 2 {
+ print(2)
+ }
+ print("end")
+}
+
+// -------- Select --------
+
+// NB, potentially fragile reliance on register number.
+func SelectDesugarsToSwitch(ch chan int) {
+ // switch t1 {
+ // case 0:int: extract t0 #2
+ // case 1:int: println(0:int)
+ // case 2:int: println(1:int)
+ // default: println("default":string)
+ // }
+ select {
+ case x := <-ch:
+ println(x)
+ case <-ch:
+ println(0)
+ case ch <- 1:
+ println(1)
+ default:
+ println("default")
+ }
+}
+
+// NB, potentially fragile reliance on register number.
+func NonblockingSelectDefaultCasePanics(ch chan int) {
+ // switch t1 {
+ // case 0:int: extract t0 #2
+ // case 1:int: println(0:int)
+ // case 2:int: println(1:int)
+ // default: make interface{} <- string ("blocking select m...":string)
+ // }
+ select {
+ case x := <-ch:
+ println(x)
+ case <-ch:
+ println(0)
+ case ch <- 1:
+ println(1)
+ }
+}
+
+// -------- Type switches --------
+
+// NB, reliance on fragile register numbering.
+func SimpleTypeSwitch(x interface{}) {
+ // switch x.(type) {
+ // case t3 int: println(x)
+ // case t7 bool: println(x)
+ // case t10 string: println(t10)
+ // default: println(x)
+ // }
+ switch y := x.(type) {
+ case nil:
+ println(y)
+ case int, bool:
+ println(y)
+ case string:
+ println(y)
+ default:
+ println(y)
+ }
+}
+
+// NB, potentially fragile reliance on register number.
+func DuplicateTypesAreNotEliminated(x interface{}) {
+ // switch x.(type) {
+ // case t1 string: println(1:int)
+ // case t5 interface{}: println(t5)
+ // case t9 int: println(3:int)
+ // default: return
+ // }
+ switch y := x.(type) {
+ case string:
+ println(1)
+ case interface{}:
+ println(y)
+ case int:
+ println(3) // unreachable!
+ }
+}
+
+// NB, potentially fragile reliance on register number.
+func AdHocTypeSwitch(x interface{}) {
+ // switch x.(type) {
+ // case t1 int: println(t1)
+ // case t5 string: println(t5)
+ // default: print("default":string)
+ // }
+ if i, ok := x.(int); ok {
+ println(i)
+ } else if s, ok := x.(string); ok {
+ println(s)
+ } else {
+ print("default")
+ }
+}
diff --git a/go/ssa/ssautil/visit.go b/go/ssa/ssautil/visit.go
new file mode 100644
index 0000000..30843c3
--- /dev/null
+++ b/go/ssa/ssautil/visit.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 ssautil // import "golang.org/x/tools/go/ssa/ssautil"
+
+import "golang.org/x/tools/go/ssa"
+
+// This file defines utilities for visiting the SSA representation of
+// a Program.
+//
+// TODO(adonovan): test coverage.
+
+// AllFunctions finds and returns the set of functions potentially
+// needed by program prog, as determined by a simple linker-style
+// reachability algorithm starting from the members and method-sets of
+// each package. The result may include anonymous functions and
+// synthetic wrappers.
+//
+// Precondition: all packages are built.
+//
+func AllFunctions(prog *ssa.Program) map[*ssa.Function]bool {
+ visit := visitor{
+ prog: prog,
+ seen: make(map[*ssa.Function]bool),
+ }
+ visit.program()
+ return visit.seen
+}
+
+type visitor struct {
+ prog *ssa.Program
+ seen map[*ssa.Function]bool
+}
+
+func (visit *visitor) program() {
+ for _, pkg := range visit.prog.AllPackages() {
+ for _, mem := range pkg.Members {
+ if fn, ok := mem.(*ssa.Function); ok {
+ visit.function(fn)
+ }
+ }
+ }
+ for _, T := range visit.prog.RuntimeTypes() {
+ mset := visit.prog.MethodSets.MethodSet(T)
+ for i, n := 0, mset.Len(); i < n; i++ {
+ visit.function(visit.prog.Method(mset.At(i)))
+ }
+ }
+}
+
+func (visit *visitor) function(fn *ssa.Function) {
+ if !visit.seen[fn] {
+ visit.seen[fn] = true
+ var buf [10]*ssa.Value // avoid alloc in common case
+ for _, b := range fn.Blocks {
+ for _, instr := range b.Instrs {
+ for _, op := range instr.Operands(buf[:0]) {
+ if fn, ok := (*op).(*ssa.Function); ok {
+ visit.function(fn)
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/go/ssa/stdlib_test.go b/go/ssa/stdlib_test.go
new file mode 100644
index 0000000..d339d07
--- /dev/null
+++ b/go/ssa/stdlib_test.go
@@ -0,0 +1,134 @@
+// 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.
+
+// Incomplete source tree on Android.
+
+// +build !android
+
+package ssa_test
+
+// This file runs the SSA builder in sanity-checking mode on all
+// packages beneath $GOROOT and prints some summary information.
+//
+// Run with "go test -cpu=8 to" set GOMAXPROCS.
+
+import (
+ "go/ast"
+ "go/build"
+ "go/token"
+ "runtime"
+ "testing"
+ "time"
+
+ "golang.org/x/tools/go/buildutil"
+ "golang.org/x/tools/go/loader"
+ "golang.org/x/tools/go/ssa"
+ "golang.org/x/tools/go/ssa/ssautil"
+)
+
+func bytesAllocated() uint64 {
+ runtime.GC()
+ var stats runtime.MemStats
+ runtime.ReadMemStats(&stats)
+ return stats.Alloc
+}
+
+func TestStdlib(t *testing.T) {
+ // Load, parse and type-check the program.
+ t0 := time.Now()
+ alloc0 := bytesAllocated()
+
+ // Load, parse and type-check the program.
+ ctxt := build.Default // copy
+ ctxt.GOPATH = "" // disable GOPATH
+ conf := loader.Config{Build: &ctxt}
+ if _, err := conf.FromArgs(buildutil.AllPackages(conf.Build), true); err != nil {
+ t.Errorf("FromArgs failed: %v", err)
+ return
+ }
+
+ iprog, err := conf.Load()
+ if err != nil {
+ t.Fatalf("Load failed: %v", err)
+ }
+
+ t1 := time.Now()
+ alloc1 := bytesAllocated()
+
+ // Create SSA packages.
+ var mode ssa.BuilderMode
+ // Comment out these lines during benchmarking. Approx SSA build costs are noted.
+ mode |= ssa.SanityCheckFunctions // + 2% space, + 4% time
+ mode |= ssa.GlobalDebug // +30% space, +18% time
+ prog := ssautil.CreateProgram(iprog, mode)
+
+ t2 := time.Now()
+
+ // Build SSA.
+ prog.BuildAll()
+
+ t3 := time.Now()
+ alloc3 := bytesAllocated()
+
+ numPkgs := len(prog.AllPackages())
+ if want := 140; numPkgs < want {
+ t.Errorf("Loaded only %d packages, want at least %d", numPkgs, want)
+ }
+
+ // Keep iprog reachable until after we've measured memory usage.
+ if len(iprog.AllPackages) == 0 {
+ print() // unreachable
+ }
+
+ allFuncs := ssautil.AllFunctions(prog)
+
+ // Check that all non-synthetic functions have distinct names.
+ // Synthetic wrappers for exported methods should be distinct too,
+ // except for unexported ones (explained at (*Function).RelString).
+ byName := make(map[string]*ssa.Function)
+ for fn := range allFuncs {
+ if fn.Synthetic == "" || ast.IsExported(fn.Name()) {
+ str := fn.String()
+ prev := byName[str]
+ byName[str] = fn
+ if prev != nil {
+ t.Errorf("%s: duplicate function named %s",
+ prog.Fset.Position(fn.Pos()), str)
+ t.Errorf("%s: (previously defined here)",
+ prog.Fset.Position(prev.Pos()))
+ }
+ }
+ }
+
+ // Dump some statistics.
+ var numInstrs int
+ for fn := range allFuncs {
+ for _, b := range fn.Blocks {
+ numInstrs += len(b.Instrs)
+ }
+ }
+
+ // determine line count
+ var lineCount int
+ prog.Fset.Iterate(func(f *token.File) bool {
+ lineCount += f.LineCount()
+ return true
+ })
+
+ // NB: when benchmarking, don't forget to clear the debug +
+ // sanity builder flags for better performance.
+
+ t.Log("GOMAXPROCS: ", runtime.GOMAXPROCS(0))
+ t.Log("#Source lines: ", lineCount)
+ t.Log("Load/parse/typecheck: ", t1.Sub(t0))
+ t.Log("SSA create: ", t2.Sub(t1))
+ t.Log("SSA build: ", t3.Sub(t2))
+
+ // SSA stats:
+ t.Log("#Packages: ", numPkgs)
+ t.Log("#Functions: ", len(allFuncs))
+ t.Log("#Instructions: ", numInstrs)
+ t.Log("#MB AST+types: ", int64(alloc1-alloc0)/1e6)
+ t.Log("#MB SSA: ", int64(alloc3-alloc1)/1e6)
+}
diff --git a/go/ssa/testdata/objlookup.go b/go/ssa/testdata/objlookup.go
new file mode 100644
index 0000000..1aaa417
--- /dev/null
+++ b/go/ssa/testdata/objlookup.go
@@ -0,0 +1,160 @@
+//+build ignore
+
+package main
+
+// This file is the input to TestObjValueLookup in source_test.go,
+// which ensures that each occurrence of an ident defining or
+// referring to a func, var or const object can be mapped to its
+// corresponding SSA Value.
+//
+// For every reference to a var object, we use annotations in comments
+// to denote both the expected SSA Value kind, and whether to expect
+// its value (x) or its address (&x).
+//
+// For const and func objects, the results don't vary by reference and
+// are always values not addresses, so no annotations are needed. The
+// declaration is enough.
+
+import "fmt"
+import "os"
+
+type J int
+
+func (*J) method() {}
+
+const globalConst = 0
+
+var globalVar int // &globalVar::Global
+
+func globalFunc() {}
+
+type I interface {
+ interfaceMethod()
+}
+
+type S struct {
+ x int // x::nil
+}
+
+func main() {
+ print(globalVar) // globalVar::UnOp
+ globalVar = 1 // globalVar::Const
+
+ var v0 int = 1 // v0::Const (simple local value spec)
+ if v0 > 0 { // v0::Const
+ v0 = 2 // v0::Const
+ }
+ print(v0) // v0::Phi
+
+ // v1 is captured and thus implicitly address-taken.
+ var v1 int = 1 // v1::Const
+ v1 = 2 // v1::Const
+ fmt.Println(v1) // v1::UnOp (load)
+ f := func(param int) { // f::MakeClosure param::Parameter
+ if y := 1; y > 0 { // y::Const
+ print(v1, param) // v1::UnOp (load) param::Parameter
+ }
+ param = 2 // param::Const
+ println(param) // param::Const
+ }
+
+ f(0) // f::MakeClosure
+
+ var v2 int // v2::Const (implicitly zero-initialized local value spec)
+ print(v2) // v2::Const
+
+ m := make(map[string]int) // m::MakeMap
+
+ // Local value spec with multi-valued RHS:
+ var v3, v4 = m[""] // v3::Extract v4::Extract m::MakeMap
+ print(v3) // v3::Extract
+ print(v4) // v4::Extract
+
+ v3++ // v3::BinOp (assign with op)
+ v3 += 2 // v3::BinOp (assign with op)
+
+ v5, v6 := false, "" // v5::Const v6::Const (defining assignment)
+ print(v5) // v5::Const
+ print(v6) // v6::Const
+
+ var v7 S // &v7::Alloc
+ v7.x = 1 // &v7::Alloc &x::FieldAddr
+ print(v7.x) // &v7::Alloc &x::FieldAddr
+
+ var v8 [1]int // &v8::Alloc
+ v8[0] = 0 // &v8::Alloc
+ print(v8[:]) // &v8::Alloc
+ _ = v8[0] // &v8::Alloc
+ _ = v8[:][0] // &v8::Alloc
+ v8ptr := &v8 // v8ptr::Alloc &v8::Alloc
+ _ = v8ptr[0] // v8ptr::Alloc
+ _ = *v8ptr // v8ptr::Alloc
+
+ v8a := make([]int, 1) // v8a::Slice
+ v8a[0] = 0 // v8a::Slice
+ print(v8a[:]) // v8a::Slice
+
+ v9 := S{} // &v9::Alloc
+
+ v10 := &v9 // v10::Alloc &v9::Alloc
+ _ = v10 // v10::Alloc
+
+ var v11 *J = nil // v11::Const
+ v11.method() // v11::Const
+
+ var v12 J // &v12::Alloc
+ v12.method() // &v12::Alloc (implicitly address-taken)
+
+ // NB, in the following, 'method' resolves to the *types.Func
+ // of (*J).method, so it doesn't help us locate the specific
+ // ssa.Values here: a bound-method closure and a promotion
+ // wrapper.
+ _ = v11.method // v11::Const
+ _ = (*struct{ J }).method // J::nil
+
+ // These vars are not optimised away.
+ if false {
+ v13 := 0 // v13::Const
+ println(v13) // v13::Const
+ }
+
+ switch x := 1; x { // x::Const
+ case v0: // v0::Phi
+ }
+
+ for k, v := range m { // k::Extract v::Extract m::MakeMap
+ _ = k // k::Extract
+ v++ // v::BinOp
+ }
+
+ if y := 0; y > 1 { // y::Const y::Const
+ }
+
+ var i interface{} // i::Const (nil interface)
+ i = 1 // i::MakeInterface
+ switch i := i.(type) { // i::MakeInterface i::MakeInterface
+ case int:
+ println(i) // i::Extract
+ }
+
+ ch := make(chan int) // ch::MakeChan
+ select {
+ case x := <-ch: // x::UnOp (receive) ch::MakeChan
+ _ = x // x::UnOp
+ }
+
+ // .Op is an inter-package FieldVal-selection.
+ var err os.PathError // &err::Alloc
+ _ = err.Op // &err::Alloc &Op::FieldAddr
+ _ = &err.Op // &err::Alloc &Op::FieldAddr
+
+ // Exercise corner-cases of lvalues vs rvalues.
+ // (Guessing IsAddr from the 'pointerness' won't cut it here.)
+ type N *N
+ var n N // n::Const
+ n1 := n // n1::Const n::Const
+ n2 := &n1 // n2::Alloc &n1::Alloc
+ n3 := *n2 // n3::UnOp n2::Alloc
+ n4 := **n3 // n4::UnOp n3::UnOp
+ _ = n4 // n4::UnOp
+}
diff --git a/go/ssa/testdata/valueforexpr.go b/go/ssa/testdata/valueforexpr.go
new file mode 100644
index 0000000..028c153
--- /dev/null
+++ b/go/ssa/testdata/valueforexpr.go
@@ -0,0 +1,148 @@
+//+build ignore
+
+package main
+
+// This file is the input to TestValueForExpr in source_test.go, which
+// ensures that each expression e immediately following a /*@kind*/(x)
+// annotation, when passed to Function.ValueForExpr(e), returns a
+// non-nil Value of the same type as e and of kind 'kind'.
+
+func f(spilled, unspilled int) {
+ _ = /*@UnOp*/ (spilled)
+ _ = /*@Parameter*/ (unspilled)
+ _ = /*@<nil>*/ (1 + 2) // (constant)
+ i := 0
+ /*@Call*/ (print( /*@BinOp*/ (i + 1)))
+ ch := /*@MakeChan*/ (make(chan int))
+ /*@UnOp*/ (<-ch)
+ x := /*@UnOp*/ (<-ch)
+ _ = x
+ select {
+ case /*@Extract*/ (<-ch):
+ case x := /*@Extract*/ (<-ch):
+ _ = x
+ }
+ defer /*@Function*/ (func() {
+ })()
+ go /*@Function*/ (func() {
+ })()
+ y := 0
+ if true && /*@BinOp*/ (bool(y > 0)) {
+ y = 1
+ }
+ _ = /*@Phi*/ (y)
+ map1 := /*@MakeMap*/ (make(map[string]string))
+ _ = map1
+ _ = /*@Slice*/ (make([]int, 0))
+ _ = /*@MakeClosure*/ (func() { print(spilled) })
+
+ sl := []int{}
+ _ = /*@Slice*/ (sl[:0])
+
+ _ = /*@<nil>*/ (new(int)) // optimized away
+ tmp := /*@Alloc*/ (new(int))
+ _ = tmp
+ var iface interface{}
+ _ = /*@TypeAssert*/ (iface.(int))
+ _ = /*@UnOp*/ (sl[0])
+ _ = /*@IndexAddr*/ (&sl[0])
+ _ = /*@Index*/ ([2]int{}[0])
+ var p *int
+ _ = /*@UnOp*/ (*p)
+
+ _ = /*@UnOp*/ (global)
+ /*@UnOp*/ (global)[""] = ""
+ /*@Global*/ (global) = map[string]string{}
+
+ var local t
+ /*UnOp*/ (local.x) = 1
+
+ // Exercise corner-cases of lvalues vs rvalues.
+ type N *N
+ var n N
+ /*@UnOp*/ (n) = /*@UnOp*/ (n)
+ /*@ChangeType*/ (n) = /*@Alloc*/ (&n)
+ /*@UnOp*/ (n) = /*@UnOp*/ (*n)
+ /*@UnOp*/ (n) = /*@UnOp*/ (**n)
+}
+
+func complit() {
+ // Composite literals.
+ // We get different results for
+ // - composite literal as value (e.g. operand to print)
+ // - composite literal initializer for addressable value
+ // - composite literal value assigned to blank var
+
+ // 1. Slices
+ print( /*@Slice*/ ([]int{}))
+ print( /*@Alloc*/ (&[]int{}))
+ print(& /*@Slice*/ ([]int{}))
+
+ sl1 := /*@Slice*/ ([]int{})
+ sl2 := /*@Alloc*/ (&[]int{})
+ sl3 := & /*@Slice*/ ([]int{})
+ _, _, _ = sl1, sl2, sl3
+
+ _ = /*@Slice*/ ([]int{})
+ _ = /*@<nil>*/ (& /*@Slice*/ ([]int{})) // & optimized away
+ _ = & /*@Slice*/ ([]int{})
+
+ // 2. Arrays
+ print( /*@UnOp*/ ([1]int{}))
+ print( /*@Alloc*/ (&[1]int{}))
+ print(& /*@Alloc*/ ([1]int{}))
+
+ arr1 := /*@Alloc*/ ([1]int{})
+ arr2 := /*@Alloc*/ (&[1]int{})
+ arr3 := & /*@Alloc*/ ([1]int{})
+ _, _, _ = arr1, arr2, arr3
+
+ _ = /*@UnOp*/ ([1]int{})
+ _ = /*@Alloc*/ (& /*@Alloc*/ ([1]int{}))
+ _ = & /*@Alloc*/ ([1]int{})
+
+ // 3. Maps
+ type M map[int]int
+ print( /*@MakeMap*/ (M{}))
+ print( /*@Alloc*/ (&M{}))
+ print(& /*@MakeMap*/ (M{}))
+
+ m1 := /*@MakeMap*/ (M{})
+ m2 := /*@Alloc*/ (&M{})
+ m3 := & /*@MakeMap*/ (M{})
+ _, _, _ = m1, m2, m3
+
+ _ = /*@MakeMap*/ (M{})
+ _ = /*@<nil>*/ (& /*@MakeMap*/ (M{})) // & optimized away
+ _ = & /*@MakeMap*/ (M{})
+
+ // 4. Structs
+ print( /*@UnOp*/ (struct{}{}))
+ print( /*@Alloc*/ (&struct{}{}))
+ print(& /*@Alloc*/ (struct{}{}))
+
+ s1 := /*@Alloc*/ (struct{}{})
+ s2 := /*@Alloc*/ (&struct{}{})
+ s3 := & /*@Alloc*/ (struct{}{})
+ _, _, _ = s1, s2, s3
+
+ _ = /*@UnOp*/ (struct{}{})
+ _ = /*@Alloc*/ (& /*@Alloc*/ (struct{}{}))
+ _ = & /*@Alloc*/ (struct{}{})
+}
+
+type t struct{ x int }
+
+// Ensure we can locate methods of named types.
+func (t) f(param int) {
+ _ = /*@Parameter*/ (param)
+}
+
+// Ensure we can locate init functions.
+func init() {
+ m := /*@MakeMap*/ (make(map[string]string))
+ _ = m
+}
+
+// Ensure we can locate variables in initializer expressions.
+var global = /*@MakeMap*/ (make(map[string]string))
diff --git a/go/ssa/testmain.go b/go/ssa/testmain.go
new file mode 100644
index 0000000..a7b1242
--- /dev/null
+++ b/go/ssa/testmain.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.
+
+package ssa
+
+// CreateTestMainPackage synthesizes a main package that runs all the
+// tests of the supplied packages.
+// It is closely coupled to $GOROOT/src/cmd/go/test.go and $GOROOT/src/testing.
+
+import (
+ "go/ast"
+ "go/token"
+ "os"
+ "sort"
+ "strings"
+
+ "golang.org/x/tools/go/exact"
+ "golang.org/x/tools/go/types"
+)
+
+// FindTests returns the list of packages that define at least one Test,
+// Example or Benchmark function (as defined by "go test"), and the
+// lists of all such functions.
+//
+func FindTests(pkgs []*Package) (testpkgs []*Package, tests, benchmarks, examples []*Function) {
+ if len(pkgs) == 0 {
+ return
+ }
+ prog := pkgs[0].Prog
+
+ // The first two of these may be nil: if the program doesn't import "testing",
+ // it can't contain any tests, but it may yet contain Examples.
+ var testSig *types.Signature // func(*testing.T)
+ var benchmarkSig *types.Signature // func(*testing.B)
+ var exampleSig = types.NewSignature(nil, nil, nil, false) // func()
+
+ // Obtain the types from the parameters of testing.Main().
+ if testingPkg := prog.ImportedPackage("testing"); testingPkg != nil {
+ params := testingPkg.Func("Main").Signature.Params()
+ testSig = funcField(params.At(1).Type())
+ benchmarkSig = funcField(params.At(2).Type())
+ }
+
+ seen := make(map[*Package]bool)
+ for _, pkg := range pkgs {
+ if pkg.Prog != prog {
+ panic("wrong Program")
+ }
+
+ // TODO(adonovan): use a stable order, e.g. lexical.
+ for _, mem := range pkg.Members {
+ if f, ok := mem.(*Function); ok &&
+ ast.IsExported(f.Name()) &&
+ strings.HasSuffix(prog.Fset.Position(f.Pos()).Filename, "_test.go") {
+
+ switch {
+ case testSig != nil && isTestSig(f, "Test", testSig):
+ tests = append(tests, f)
+ case benchmarkSig != nil && isTestSig(f, "Benchmark", benchmarkSig):
+ benchmarks = append(benchmarks, f)
+ case isTestSig(f, "Example", exampleSig):
+ examples = append(examples, f)
+ default:
+ continue
+ }
+
+ if !seen[pkg] {
+ seen[pkg] = true
+ testpkgs = append(testpkgs, pkg)
+ }
+ }
+ }
+ }
+ return
+}
+
+// Like isTest, but checks the signature too.
+func isTestSig(f *Function, prefix string, sig *types.Signature) bool {
+ return isTest(f.Name(), prefix) && types.Identical(f.Signature, sig)
+}
+
+// If non-nil, testMainStartBodyHook is called immediately after
+// startBody for main.init and main.main, making it easy for users to
+// add custom imports and initialization steps for proprietary build
+// systems that don't exactly follow 'go test' conventions.
+var testMainStartBodyHook func(*Function)
+
+// CreateTestMainPackage creates and returns a synthetic "main"
+// package that runs all the tests of the supplied packages, similar
+// to the one that would be created by the 'go test' tool.
+//
+// It returns nil if the program contains no tests.
+//
+func (prog *Program) CreateTestMainPackage(pkgs ...*Package) *Package {
+ pkgs, tests, benchmarks, examples := FindTests(pkgs)
+ if len(pkgs) == 0 {
+ return nil
+ }
+
+ testmain := &Package{
+ Prog: prog,
+ Members: make(map[string]Member),
+ values: make(map[types.Object]Value),
+ Object: types.NewPackage("test$main", "main"),
+ }
+
+ // Build package's init function.
+ init := &Function{
+ name: "init",
+ Signature: new(types.Signature),
+ Synthetic: "package initializer",
+ Pkg: testmain,
+ Prog: prog,
+ }
+ init.startBody()
+
+ if testMainStartBodyHook != nil {
+ testMainStartBodyHook(init)
+ }
+
+ // Initialize packages to test.
+ var pkgpaths []string
+ for _, pkg := range pkgs {
+ var v Call
+ v.Call.Value = pkg.init
+ v.setType(types.NewTuple())
+ init.emit(&v)
+
+ pkgpaths = append(pkgpaths, pkg.Object.Path())
+ }
+ sort.Strings(pkgpaths)
+ init.emit(new(Return))
+ init.finishBody()
+ testmain.init = init
+ testmain.Object.MarkComplete()
+ testmain.Members[init.name] = init
+
+ // For debugging convenience, define an unexported const
+ // that enumerates the packages.
+ packagesConst := types.NewConst(token.NoPos, testmain.Object, "packages", tString,
+ exact.MakeString(strings.Join(pkgpaths, " ")))
+ memberFromObject(testmain, packagesConst, nil)
+
+ // Create main *types.Func and *ssa.Function
+ mainFunc := types.NewFunc(token.NoPos, testmain.Object, "main", new(types.Signature))
+ memberFromObject(testmain, mainFunc, nil)
+ main := testmain.Func("main")
+ main.Synthetic = "test main function"
+
+ main.startBody()
+
+ if testMainStartBodyHook != nil {
+ testMainStartBodyHook(main)
+ }
+
+ if testingPkg := prog.ImportedPackage("testing"); testingPkg != nil {
+ testingMain := testingPkg.Func("Main")
+ testingMainParams := testingMain.Signature.Params()
+
+ // The generated code is as if compiled from this:
+ //
+ // func main() {
+ // match := func(_, _ string) (bool, error) { return true, nil }
+ // tests := []testing.InternalTest{{"TestFoo", TestFoo}, ...}
+ // benchmarks := []testing.InternalBenchmark{...}
+ // examples := []testing.InternalExample{...}
+ // testing.Main(match, tests, benchmarks, examples)
+ // }
+
+ matcher := &Function{
+ name: "matcher",
+ Signature: testingMainParams.At(0).Type().(*types.Signature),
+ Synthetic: "test matcher predicate",
+ parent: main,
+ Pkg: testmain,
+ Prog: prog,
+ }
+ main.AnonFuncs = append(main.AnonFuncs, matcher)
+ matcher.startBody()
+ matcher.emit(&Return{Results: []Value{vTrue, nilConst(types.Universe.Lookup("error").Type())}})
+ matcher.finishBody()
+
+ // Emit call: testing.Main(matcher, tests, benchmarks, examples).
+ var c Call
+ c.Call.Value = testingMain
+ c.Call.Args = []Value{
+ matcher,
+ testMainSlice(main, tests, testingMainParams.At(1).Type()),
+ testMainSlice(main, benchmarks, testingMainParams.At(2).Type()),
+ testMainSlice(main, examples, testingMainParams.At(3).Type()),
+ }
+ emitTailCall(main, &c)
+ } else {
+ // The program does not import "testing", but FindTests
+ // returned non-nil, which must mean there were Examples
+ // but no Tests or Benchmarks.
+ // We'll simply call them from testmain.main; this will
+ // ensure they don't panic, but will not check any
+ // "Output:" comments.
+ for _, eg := range examples {
+ var c Call
+ c.Call.Value = eg
+ c.setType(types.NewTuple())
+ main.emit(&c)
+ }
+ main.emit(&Return{})
+ main.currentBlock = nil
+ }
+
+ main.finishBody()
+
+ testmain.Members["main"] = main
+
+ if prog.mode&PrintPackages != 0 {
+ printMu.Lock()
+ testmain.WriteTo(os.Stdout)
+ printMu.Unlock()
+ }
+
+ if prog.mode&SanityCheckFunctions != 0 {
+ sanityCheckPackage(testmain)
+ }
+
+ prog.packages[testmain.Object] = testmain
+
+ return testmain
+}
+
+// testMainSlice emits to fn code to construct a slice of type slice
+// (one of []testing.Internal{Test,Benchmark,Example}) for all
+// functions in testfuncs. It returns the slice value.
+//
+func testMainSlice(fn *Function, testfuncs []*Function, slice types.Type) Value {
+ if testfuncs == nil {
+ return nilConst(slice)
+ }
+
+ tElem := slice.(*types.Slice).Elem()
+ tPtrString := types.NewPointer(tString)
+ tPtrElem := types.NewPointer(tElem)
+ tPtrFunc := types.NewPointer(funcField(slice))
+
+ // Emit: array = new [n]testing.InternalTest
+ tArray := types.NewArray(tElem, int64(len(testfuncs)))
+ array := emitNew(fn, tArray, token.NoPos)
+ array.Comment = "test main"
+ for i, testfunc := range testfuncs {
+ // Emit: pitem = &array[i]
+ ia := &IndexAddr{X: array, Index: intConst(int64(i))}
+ ia.setType(tPtrElem)
+ pitem := fn.emit(ia)
+
+ // Emit: pname = &pitem.Name
+ fa := &FieldAddr{X: pitem, Field: 0} // .Name
+ fa.setType(tPtrString)
+ pname := fn.emit(fa)
+
+ // Emit: *pname = "testfunc"
+ emitStore(fn, pname, stringConst(testfunc.Name()), token.NoPos)
+
+ // Emit: pfunc = &pitem.F
+ fa = &FieldAddr{X: pitem, Field: 1} // .F
+ fa.setType(tPtrFunc)
+ pfunc := fn.emit(fa)
+
+ // Emit: *pfunc = testfunc
+ emitStore(fn, pfunc, testfunc, token.NoPos)
+ }
+
+ // Emit: slice array[:]
+ sl := &Slice{X: array}
+ sl.setType(slice)
+ return fn.emit(sl)
+}
+
+// Given the type of one of the three slice parameters of testing.Main,
+// returns the function type.
+func funcField(slice types.Type) *types.Signature {
+ return slice.(*types.Slice).Elem().Underlying().(*types.Struct).Field(1).Type().(*types.Signature)
+}
+
+// Plundered from $GOROOT/src/cmd/go/test.go
+
+// isTest tells whether name looks like a test (or benchmark, according to prefix).
+// It is a Test (say) if there is a character after Test that is not a lower-case letter.
+// We don't want TesticularCancer.
+func isTest(name, prefix string) bool {
+ if !strings.HasPrefix(name, prefix) {
+ return false
+ }
+ if len(name) == len(prefix) { // "Test" is ok
+ return true
+ }
+ return ast.IsExported(name[len(prefix):])
+}
diff --git a/go/ssa/testmain_test.go b/go/ssa/testmain_test.go
new file mode 100644
index 0000000..56cb604
--- /dev/null
+++ b/go/ssa/testmain_test.go
@@ -0,0 +1,123 @@
+// 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 ssa_test
+
+// Tests of FindTests. CreateTestMainPackage is tested via the interpreter.
+// TODO(adonovan): test the 'pkgs' result from FindTests.
+
+import (
+ "fmt"
+ "sort"
+ "testing"
+
+ "golang.org/x/tools/go/loader"
+ "golang.org/x/tools/go/ssa"
+ "golang.org/x/tools/go/ssa/ssautil"
+)
+
+func create(t *testing.T, content string) []*ssa.Package {
+ var conf loader.Config
+ f, err := conf.ParseFile("foo_test.go", content)
+ if err != nil {
+ t.Fatal(err)
+ }
+ conf.CreateFromFiles("foo", f)
+
+ iprog, err := conf.Load()
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ // We needn't call Build.
+ return ssautil.CreateProgram(iprog, ssa.SanityCheckFunctions).AllPackages()
+}
+
+func TestFindTests(t *testing.T) {
+ test := `
+package foo
+
+import "testing"
+
+type T int
+
+// Tests:
+func Test(t *testing.T) {}
+func TestA(t *testing.T) {}
+func TestB(t *testing.T) {}
+
+// Not tests:
+func testC(t *testing.T) {}
+func TestD() {}
+func testE(t *testing.T) int { return 0 }
+func (T) Test(t *testing.T) {}
+
+// Benchmarks:
+func Benchmark(*testing.B) {}
+func BenchmarkA(b *testing.B) {}
+func BenchmarkB(*testing.B) {}
+
+// Not benchmarks:
+func benchmarkC(t *testing.T) {}
+func BenchmarkD() {}
+func benchmarkE(t *testing.T) int { return 0 }
+func (T) Benchmark(t *testing.T) {}
+
+// Examples:
+func Example() {}
+func ExampleA() {}
+
+// Not examples:
+func exampleC() {}
+func ExampleD(t *testing.T) {}
+func exampleE() int { return 0 }
+func (T) Example() {}
+`
+ pkgs := create(t, test)
+ _, tests, benchmarks, examples := ssa.FindTests(pkgs)
+
+ sort.Sort(funcsByPos(tests))
+ if got, want := fmt.Sprint(tests), "[foo.Test foo.TestA foo.TestB]"; got != want {
+ t.Errorf("FindTests.tests = %s, want %s", got, want)
+ }
+
+ sort.Sort(funcsByPos(benchmarks))
+ if got, want := fmt.Sprint(benchmarks), "[foo.Benchmark foo.BenchmarkA foo.BenchmarkB]"; got != want {
+ t.Errorf("FindTests.benchmarks = %s, want %s", got, want)
+ }
+
+ sort.Sort(funcsByPos(examples))
+ if got, want := fmt.Sprint(examples), "[foo.Example foo.ExampleA]"; got != want {
+ t.Errorf("FindTests examples = %s, want %s", got, want)
+ }
+}
+
+func TestFindTestsTesting(t *testing.T) {
+ test := `
+package foo
+
+// foo does not import "testing", but defines Examples.
+
+func Example() {}
+func ExampleA() {}
+`
+ pkgs := create(t, test)
+ _, tests, benchmarks, examples := ssa.FindTests(pkgs)
+ if len(tests) > 0 {
+ t.Errorf("FindTests.tests = %s, want none", tests)
+ }
+ if len(benchmarks) > 0 {
+ t.Errorf("FindTests.benchmarks = %s, want none", benchmarks)
+ }
+ sort.Sort(funcsByPos(examples))
+ if got, want := fmt.Sprint(examples), "[foo.Example foo.ExampleA]"; got != want {
+ t.Errorf("FindTests examples = %s, want %s", got, want)
+ }
+}
+
+type funcsByPos []*ssa.Function
+
+func (p funcsByPos) Len() int { return len(p) }
+func (p funcsByPos) Less(i, j int) bool { return p[i].Pos() < p[j].Pos() }
+func (p funcsByPos) Swap(i, j int) { p[i], p[j] = p[j], p[i] }
diff --git a/go/ssa/util.go b/go/ssa/util.go
new file mode 100644
index 0000000..4f9d43d
--- /dev/null
+++ b/go/ssa/util.go
@@ -0,0 +1,119 @@
+// 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 ssa
+
+// This file defines a number of miscellaneous utility functions.
+
+import (
+ "fmt"
+ "go/ast"
+ "go/token"
+ "io"
+ "os"
+
+ "golang.org/x/tools/go/ast/astutil"
+ "golang.org/x/tools/go/types"
+)
+
+//// AST utilities
+
+func unparen(e ast.Expr) ast.Expr { return astutil.Unparen(e) }
+
+// isBlankIdent returns true iff e is an Ident with name "_".
+// They have no associated types.Object, and thus no type.
+//
+func isBlankIdent(e ast.Expr) bool {
+ id, ok := e.(*ast.Ident)
+ return ok && id.Name == "_"
+}
+
+//// Type utilities. Some of these belong in go/types.
+
+// isPointer returns true for types whose underlying type is a pointer.
+func isPointer(typ types.Type) bool {
+ _, ok := typ.Underlying().(*types.Pointer)
+ return ok
+}
+
+func isInterface(T types.Type) bool { return types.IsInterface(T) }
+
+// deref returns a pointer's element type; otherwise it returns typ.
+func deref(typ types.Type) types.Type {
+ if p, ok := typ.Underlying().(*types.Pointer); ok {
+ return p.Elem()
+ }
+ return typ
+}
+
+// recvType returns the receiver type of method obj.
+func recvType(obj *types.Func) types.Type {
+ return obj.Type().(*types.Signature).Recv().Type()
+}
+
+// DefaultType returns the default "typed" type for an "untyped" type;
+// it returns the incoming type for all other types. The default type
+// for untyped nil is untyped nil.
+//
+// Exported to ssa/interp.
+//
+// TODO(gri): this is a copy of go/types.defaultType; export that function.
+//
+func DefaultType(typ types.Type) types.Type {
+ if t, ok := typ.(*types.Basic); ok {
+ k := t.Kind()
+ switch k {
+ case types.UntypedBool:
+ k = types.Bool
+ case types.UntypedInt:
+ k = types.Int
+ case types.UntypedRune:
+ k = types.Rune
+ case types.UntypedFloat:
+ k = types.Float64
+ case types.UntypedComplex:
+ k = types.Complex128
+ case types.UntypedString:
+ k = types.String
+ }
+ typ = types.Typ[k]
+ }
+ return typ
+}
+
+// logStack prints the formatted "start" message to stderr and
+// returns a closure that prints the corresponding "end" message.
+// Call using 'defer logStack(...)()' to show builder stack on panic.
+// Don't forget trailing parens!
+//
+func logStack(format string, args ...interface{}) func() {
+ msg := fmt.Sprintf(format, args...)
+ io.WriteString(os.Stderr, msg)
+ io.WriteString(os.Stderr, "\n")
+ return func() {
+ io.WriteString(os.Stderr, msg)
+ io.WriteString(os.Stderr, " end\n")
+ }
+}
+
+// newVar creates a 'var' for use in a types.Tuple.
+func newVar(name string, typ types.Type) *types.Var {
+ return types.NewParam(token.NoPos, nil, name, typ)
+}
+
+// anonVar creates an anonymous 'var' for use in a types.Tuple.
+func anonVar(typ types.Type) *types.Var {
+ return newVar("", typ)
+}
+
+var lenResults = types.NewTuple(anonVar(tInt))
+
+// makeLen returns the len builtin specialized to type func(T)int.
+func makeLen(T types.Type) *Builtin {
+ lenParams := types.NewTuple(anonVar(T))
+ return &Builtin{
+ name: "len",
+ sig: types.NewSignature(nil, lenParams, lenResults, false),
+ }
+}
diff --git a/go/ssa/wrappers.go b/go/ssa/wrappers.go
new file mode 100644
index 0000000..ff1eac5
--- /dev/null
+++ b/go/ssa/wrappers.go
@@ -0,0 +1,294 @@
+// 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 ssa
+
+// This file defines synthesis of Functions that delegate to declared
+// methods; they come in three kinds:
+//
+// (1) wrappers: methods that wrap declared methods, performing
+// implicit pointer indirections and embedded field selections.
+//
+// (2) thunks: funcs that wrap declared methods. Like wrappers,
+// thunks perform indirections and field selections. The thunk's
+// first parameter is used as the receiver for the method call.
+//
+// (3) bounds: funcs that wrap declared methods. The bound's sole
+// free variable, supplied by a closure, is used as the receiver
+// for the method call. No indirections or field selections are
+// performed since they can be done before the call.
+
+import (
+ "fmt"
+
+ "golang.org/x/tools/go/types"
+)
+
+// -- wrappers -----------------------------------------------------------
+
+// makeWrapper returns a synthetic method that delegates to the
+// declared method denoted by meth.Obj(), first performing any
+// necessary pointer indirections or field selections implied by meth.
+//
+// The resulting method's receiver type is meth.Recv().
+//
+// This function is versatile but quite subtle! Consider the
+// following axes of variation when making changes:
+// - optional receiver indirection
+// - optional implicit field selections
+// - meth.Obj() may denote a concrete or an interface method
+// - the result may be a thunk or a wrapper.
+//
+// EXCLUSIVE_LOCKS_REQUIRED(prog.methodsMu)
+//
+func makeWrapper(prog *Program, sel *types.Selection) *Function {
+ obj := sel.Obj().(*types.Func) // the declared function
+ sig := sel.Type().(*types.Signature) // type of this wrapper
+
+ var recv *types.Var // wrapper's receiver or thunk's params[0]
+ name := obj.Name()
+ var description string
+ var start int // first regular param
+ if sel.Kind() == types.MethodExpr {
+ name += "$thunk"
+ description = "thunk"
+ recv = sig.Params().At(0)
+ start = 1
+ } else {
+ description = "wrapper"
+ recv = sig.Recv()
+ }
+
+ description = fmt.Sprintf("%s for %s", description, sel.Obj())
+ if prog.mode&LogSource != 0 {
+ defer logStack("make %s to (%s)", description, recv.Type())()
+ }
+ fn := &Function{
+ name: name,
+ method: sel,
+ object: obj,
+ Signature: sig,
+ Synthetic: description,
+ Prog: prog,
+ pos: obj.Pos(),
+ }
+ fn.startBody()
+ fn.addSpilledParam(recv)
+ createParams(fn, start)
+
+ indices := sel.Index()
+
+ var v Value = fn.Locals[0] // spilled receiver
+ if isPointer(sel.Recv()) {
+ v = emitLoad(fn, v)
+
+ // For simple indirection wrappers, perform an informative nil-check:
+ // "value method (T).f called using nil *T pointer"
+ if len(indices) == 1 && !isPointer(recvType(obj)) {
+ var c Call
+ c.Call.Value = &Builtin{
+ name: "ssa:wrapnilchk",
+ sig: types.NewSignature(nil,
+ types.NewTuple(anonVar(sel.Recv()), anonVar(tString), anonVar(tString)),
+ types.NewTuple(anonVar(sel.Recv())), false),
+ }
+ c.Call.Args = []Value{
+ v,
+ stringConst(deref(sel.Recv()).String()),
+ stringConst(sel.Obj().Name()),
+ }
+ c.setType(v.Type())
+ v = fn.emit(&c)
+ }
+ }
+
+ // Invariant: v is a pointer, either
+ // value of *A receiver param, or
+ // address of A spilled receiver.
+
+ // We use pointer arithmetic (FieldAddr possibly followed by
+ // Load) in preference to value extraction (Field possibly
+ // preceded by Load).
+
+ v = emitImplicitSelections(fn, v, indices[:len(indices)-1])
+
+ // Invariant: v is a pointer, either
+ // value of implicit *C field, or
+ // address of implicit C field.
+
+ var c Call
+ if r := recvType(obj); !isInterface(r) { // concrete method
+ if !isPointer(r) {
+ v = emitLoad(fn, v)
+ }
+ c.Call.Value = prog.declaredFunc(obj)
+ c.Call.Args = append(c.Call.Args, v)
+ } else {
+ c.Call.Method = obj
+ c.Call.Value = emitLoad(fn, v)
+ }
+ for _, arg := range fn.Params[1:] {
+ c.Call.Args = append(c.Call.Args, arg)
+ }
+ emitTailCall(fn, &c)
+ fn.finishBody()
+ return fn
+}
+
+// createParams creates parameters for wrapper method fn based on its
+// Signature.Params, which do not include the receiver.
+// start is the index of the first regular parameter to use.
+//
+func createParams(fn *Function, start int) {
+ var last *Parameter
+ tparams := fn.Signature.Params()
+ for i, n := start, tparams.Len(); i < n; i++ {
+ last = fn.addParamObj(tparams.At(i))
+ }
+ if fn.Signature.Variadic() {
+ last.typ = types.NewSlice(last.typ)
+ }
+}
+
+// -- bounds -----------------------------------------------------------
+
+// makeBound returns a bound method wrapper (or "bound"), a synthetic
+// function that delegates to a concrete or interface method denoted
+// by obj. The resulting function has no receiver, but has one free
+// variable which will be used as the method's receiver in the
+// tail-call.
+//
+// Use MakeClosure with such a wrapper to construct a bound method
+// closure. e.g.:
+//
+// type T int or: type T interface { meth() }
+// func (t T) meth()
+// var t T
+// f := t.meth
+// f() // calls t.meth()
+//
+// f is a closure of a synthetic wrapper defined as if by:
+//
+// f := func() { return t.meth() }
+//
+// Unlike makeWrapper, makeBound need perform no indirection or field
+// selections because that can be done before the closure is
+// constructed.
+//
+// EXCLUSIVE_LOCKS_ACQUIRED(meth.Prog.methodsMu)
+//
+func makeBound(prog *Program, obj *types.Func) *Function {
+ prog.methodsMu.Lock()
+ defer prog.methodsMu.Unlock()
+ fn, ok := prog.bounds[obj]
+ if !ok {
+ description := fmt.Sprintf("bound method wrapper for %s", obj)
+ if prog.mode&LogSource != 0 {
+ defer logStack("%s", description)()
+ }
+ fn = &Function{
+ name: obj.Name() + "$bound",
+ object: obj,
+ Signature: changeRecv(obj.Type().(*types.Signature), nil), // drop receiver
+ Synthetic: description,
+ Prog: prog,
+ pos: obj.Pos(),
+ }
+
+ fv := &FreeVar{name: "recv", typ: recvType(obj), parent: fn}
+ fn.FreeVars = []*FreeVar{fv}
+ fn.startBody()
+ createParams(fn, 0)
+ var c Call
+
+ if !isInterface(recvType(obj)) { // concrete
+ c.Call.Value = prog.declaredFunc(obj)
+ c.Call.Args = []Value{fv}
+ } else {
+ c.Call.Value = fv
+ c.Call.Method = obj
+ }
+ for _, arg := range fn.Params {
+ c.Call.Args = append(c.Call.Args, arg)
+ }
+ emitTailCall(fn, &c)
+ fn.finishBody()
+
+ prog.bounds[obj] = fn
+ }
+ return fn
+}
+
+// -- thunks -----------------------------------------------------------
+
+// makeThunk returns a thunk, a synthetic function that delegates to a
+// concrete or interface method denoted by sel.Obj(). The resulting
+// function has no receiver, but has an additional (first) regular
+// parameter.
+//
+// Precondition: sel.Kind() == types.MethodExpr.
+//
+// type T int or: type T interface { meth() }
+// func (t T) meth()
+// f := T.meth
+// var t T
+// f(t) // calls t.meth()
+//
+// f is a synthetic wrapper defined as if by:
+//
+// f := func(t T) { return t.meth() }
+//
+// TODO(adonovan): opt: currently the stub is created even when used
+// directly in a function call: C.f(i, 0). This is less efficient
+// than inlining the stub.
+//
+// EXCLUSIVE_LOCKS_ACQUIRED(meth.Prog.methodsMu)
+//
+func makeThunk(prog *Program, sel *types.Selection) *Function {
+ if sel.Kind() != types.MethodExpr {
+ panic(sel)
+ }
+
+ key := selectionKey{
+ kind: sel.Kind(),
+ recv: sel.Recv(),
+ obj: sel.Obj(),
+ index: fmt.Sprint(sel.Index()),
+ indirect: sel.Indirect(),
+ }
+
+ prog.methodsMu.Lock()
+ defer prog.methodsMu.Unlock()
+
+ // Canonicalize key.recv to avoid constructing duplicate thunks.
+ canonRecv, ok := prog.canon.At(key.recv).(types.Type)
+ if !ok {
+ canonRecv = key.recv
+ prog.canon.Set(key.recv, canonRecv)
+ }
+ key.recv = canonRecv
+
+ fn, ok := prog.thunks[key]
+ if !ok {
+ fn = makeWrapper(prog, sel)
+ if fn.Signature.Recv() != nil {
+ panic(fn) // unexpected receiver
+ }
+ prog.thunks[key] = fn
+ }
+ return fn
+}
+
+func changeRecv(s *types.Signature, recv *types.Var) *types.Signature {
+ return types.NewSignature(recv, s.Params(), s.Results(), s.Variadic())
+}
+
+// selectionKey is like types.Selection but a usable map key.
+type selectionKey struct {
+ kind types.SelectionKind
+ recv types.Type // canonicalized via Program.canon
+ obj types.Object
+ index string
+ indirect bool
+}
diff --git a/go/types/api.go b/go/types/api.go
new file mode 100644
index 0000000..5344a39
--- /dev/null
+++ b/go/types/api.go
@@ -0,0 +1,365 @@
+// 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 types declares the data types and implements
+// the algorithms for type-checking of Go packages.
+// Use Check and Config.Check to invoke the type-checker.
+//
+// Type-checking consists of several interdependent phases:
+//
+// Name resolution maps each identifier (ast.Ident) in the program to the
+// language object (Object) it denotes.
+// Use Info.{Defs,Uses,Implicits} for the results of name resolution.
+//
+// Constant folding computes the exact constant value (exact.Value) for
+// every expression (ast.Expr) that is a compile-time constant.
+// Use Info.Types[expr].Value for the results of constant folding.
+//
+// Type inference computes the type (Type) of every expression (ast.Expr)
+// and checks for compliance with the language specification.
+// Use Info.Types[expr].Type for the results of type inference.
+//
+package types // import "golang.org/x/tools/go/types"
+
+import (
+ "bytes"
+ "fmt"
+ "go/ast"
+ "go/token"
+
+ "golang.org/x/tools/go/exact"
+)
+
+// Check type-checks a package and returns the resulting complete package
+// object, or a nil package and the first error. The package is specified
+// by a list of *ast.Files and corresponding file set, and the import path
+// the package is identified with. The clean path must not be empty or dot (".").
+//
+// For more control over type-checking and results, use Config.Check.
+func Check(path string, fset *token.FileSet, files []*ast.File) (*Package, error) {
+ var conf Config
+ pkg, err := conf.Check(path, fset, files, nil)
+ if err != nil {
+ return nil, err
+ }
+ return pkg, nil
+}
+
+// An Error describes a type-checking error; it implements the error interface.
+// A "soft" error is an error that still permits a valid interpretation of a
+// package (such as "unused variable"); "hard" errors may lead to unpredictable
+// behavior if ignored.
+type Error struct {
+ Fset *token.FileSet // file set for interpretation of Pos
+ Pos token.Pos // error position
+ Msg string // error message
+ Soft bool // if set, error is "soft"
+}
+
+// Error returns an error string formatted as follows:
+// filename:line:column: message
+func (err Error) Error() string {
+ return fmt.Sprintf("%s: %s", err.Fset.Position(err.Pos), err.Msg)
+}
+
+// An importer resolves import paths to Packages.
+// The imports map records packages already known,
+// indexed by package path. The type-checker
+// will invoke Import with Config.Packages.
+// An importer must determine the canonical package path and
+// check imports to see if it is already present in the map.
+// If so, the Importer can return the map entry. Otherwise,
+// the importer must load the package data for the given path
+// into a new *Package, record it in imports map, and return
+// the package.
+// TODO(gri) Need to be clearer about requirements of completeness.
+type Importer func(map[string]*Package, string) (*Package, error)
+
+// A Config specifies the configuration for type checking.
+// The zero value for Config is a ready-to-use default configuration.
+type Config struct {
+ // If IgnoreFuncBodies is set, function bodies are not
+ // type-checked.
+ IgnoreFuncBodies bool
+
+ // If FakeImportC is set, `import "C"` (for packages requiring Cgo)
+ // declares an empty "C" package and errors are omitted for qualified
+ // identifiers referring to package C (which won't find an object).
+ // This feature is intended for the standard library cmd/api tool.
+ //
+ // Caution: Effects may be unpredictable due to follow-up errors.
+ // Do not use casually!
+ FakeImportC bool
+
+ // Packages is used to look up (and thus canonicalize) packages by
+ // package path. If Packages is nil, it is set to a new empty map.
+ // During type-checking, imported packages are added to the map.
+ Packages map[string]*Package
+
+ // If Error != nil, it is called with each error found
+ // during type checking; err has dynamic type Error.
+ // Secondary errors (for instance, to enumerate all types
+ // involved in an invalid recursive type declaration) have
+ // error strings that start with a '\t' character.
+ // If Error == nil, type-checking stops with the first
+ // error found.
+ Error func(err error)
+
+ // If Import != nil, it is called for each imported package.
+ // Otherwise, DefaultImport is called.
+ Import Importer
+
+ // If Sizes != nil, it provides the sizing functions for package unsafe.
+ // Otherwise &StdSizes{WordSize: 8, MaxAlign: 8} is used instead.
+ Sizes Sizes
+
+ // If DisableUnusedImportCheck is set, packages are not checked
+ // for unused imports.
+ DisableUnusedImportCheck bool
+}
+
+// DefaultImport is the default importer invoked if Config.Import == nil.
+// The declaration:
+//
+// import _ "golang.org/x/tools/go/gcimporter"
+//
+// in a client of go/types will initialize DefaultImport to gcimporter.Import.
+var DefaultImport Importer
+
+// Info holds result type information for a type-checked package.
+// Only the information for which a map is provided is collected.
+// If the package has type errors, the collected information may
+// be incomplete.
+type Info struct {
+ // Types maps expressions to their types, and for constant
+ // expressions, their values. Invalid expressions are omitted.
+ //
+ // For (possibly parenthesized) identifiers denoting built-in
+ // functions, the recorded signatures are call-site specific:
+ // if the call result is not a constant, the recorded type is
+ // an argument-specific signature. Otherwise, the recorded type
+ // is invalid.
+ //
+ // Identifiers on the lhs of declarations (i.e., the identifiers
+ // which are being declared) are collected in the Defs map.
+ // Identifiers denoting packages are collected in the Uses maps.
+ Types map[ast.Expr]TypeAndValue
+
+ // Defs maps identifiers to the objects they define (including
+ // package names, dots "." of dot-imports, and blank "_" identifiers).
+ // For identifiers that do not denote objects (e.g., the package name
+ // in package clauses, or symbolic variables t in t := x.(type) of
+ // type switch headers), the corresponding objects are nil.
+ //
+ // For an anonymous field, Defs returns the field *Var it defines.
+ //
+ // Invariant: Defs[id] == nil || Defs[id].Pos() == id.Pos()
+ Defs map[*ast.Ident]Object
+
+ // Uses maps identifiers to the objects they denote.
+ //
+ // For an anonymous field, Uses returns the *TypeName it denotes.
+ //
+ // Invariant: Uses[id].Pos() != id.Pos()
+ Uses map[*ast.Ident]Object
+
+ // Implicits maps nodes to their implicitly declared objects, if any.
+ // The following node and object types may appear:
+ //
+ // node declared object
+ //
+ // *ast.ImportSpec *PkgName for dot-imports and imports without renames
+ // *ast.CaseClause type-specific *Var for each type switch case clause (incl. default)
+ // *ast.Field anonymous struct field or parameter *Var
+ //
+ Implicits map[ast.Node]Object
+
+ // Selections maps selector expressions (excluding qualified identifiers)
+ // to their corresponding selections.
+ Selections map[*ast.SelectorExpr]*Selection
+
+ // Scopes maps ast.Nodes to the scopes they define. Package scopes are not
+ // associated with a specific node but with all files belonging to a package.
+ // Thus, the package scope can be found in the type-checked Package object.
+ // Scopes nest, with the Universe scope being the outermost scope, enclosing
+ // the package scope, which contains (one or more) files scopes, which enclose
+ // function scopes which in turn enclose statement and function literal scopes.
+ // Note that even though package-level functions are declared in the package
+ // scope, the function scopes are embedded in the file scope of the file
+ // containing the function declaration.
+ //
+ // The following node types may appear in Scopes:
+ //
+ // *ast.File
+ // *ast.FuncType
+ // *ast.BlockStmt
+ // *ast.IfStmt
+ // *ast.SwitchStmt
+ // *ast.TypeSwitchStmt
+ // *ast.CaseClause
+ // *ast.CommClause
+ // *ast.ForStmt
+ // *ast.RangeStmt
+ //
+ Scopes map[ast.Node]*Scope
+
+ // InitOrder is the list of package-level initializers in the order in which
+ // they must be executed. Initializers referring to variables related by an
+ // initialization dependency appear in topological order, the others appear
+ // in source order. Variables without an initialization expression do not
+ // appear in this list.
+ InitOrder []*Initializer
+}
+
+// TypeOf returns the type of expression e, or nil if not found.
+// Precondition: the Types, Uses and Defs maps are populated.
+//
+func (info *Info) TypeOf(e ast.Expr) Type {
+ if t, ok := info.Types[e]; ok {
+ return t.Type
+ }
+ if id, _ := e.(*ast.Ident); id != nil {
+ if obj := info.ObjectOf(id); obj != nil {
+ return obj.Type()
+ }
+ }
+ return nil
+}
+
+// ObjectOf returns the object denoted by the specified id,
+// or nil if not found.
+//
+// If id is an anonymous struct field, ObjectOf returns the field (*Var)
+// it uses, not the type (*TypeName) it defines.
+//
+// Precondition: the Uses and Defs maps are populated.
+//
+func (info *Info) ObjectOf(id *ast.Ident) Object {
+ if obj, _ := info.Defs[id]; obj != nil {
+ return obj
+ }
+ return info.Uses[id]
+}
+
+// TypeAndValue reports the type and value (for constants)
+// of the corresponding expression.
+type TypeAndValue struct {
+ mode operandMode
+ Type Type
+ Value exact.Value
+}
+
+// TODO(gri) Consider eliminating the IsVoid predicate. Instead, report
+// "void" values as regular values but with the empty tuple type.
+
+// IsVoid reports whether the corresponding expression
+// is a function call without results.
+func (tv TypeAndValue) IsVoid() bool {
+ return tv.mode == novalue
+}
+
+// IsType reports whether the corresponding expression specifies a type.
+func (tv TypeAndValue) IsType() bool {
+ return tv.mode == typexpr
+}
+
+// IsBuiltin reports whether the corresponding expression denotes
+// a (possibly parenthesized) built-in function.
+func (tv TypeAndValue) IsBuiltin() bool {
+ return tv.mode == builtin
+}
+
+// IsValue reports whether the corresponding expression is a value.
+// Builtins are not considered values. Constant values have a non-
+// nil Value.
+func (tv TypeAndValue) IsValue() bool {
+ switch tv.mode {
+ case constant, variable, mapindex, value, commaok:
+ return true
+ }
+ return false
+}
+
+// IsNil reports whether the corresponding expression denotes the
+// predeclared value nil.
+func (tv TypeAndValue) IsNil() bool {
+ return tv.mode == value && tv.Type == Typ[UntypedNil]
+}
+
+// Addressable reports whether the corresponding expression
+// is addressable (http://golang.org/ref/spec#Address_operators).
+func (tv TypeAndValue) Addressable() bool {
+ return tv.mode == variable
+}
+
+// Assignable reports whether the corresponding expression
+// is assignable to (provided a value of the right type).
+func (tv TypeAndValue) Assignable() bool {
+ return tv.mode == variable || tv.mode == mapindex
+}
+
+// HasOk reports whether the corresponding expression may be
+// used on the lhs of a comma-ok assignment.
+func (tv TypeAndValue) HasOk() bool {
+ return tv.mode == commaok || tv.mode == mapindex
+}
+
+// An Initializer describes a package-level variable, or a list of variables in case
+// of a multi-valued initialization expression, and the corresponding initialization
+// expression.
+type Initializer struct {
+ Lhs []*Var // var Lhs = Rhs
+ Rhs ast.Expr
+}
+
+func (init *Initializer) String() string {
+ var buf bytes.Buffer
+ for i, lhs := range init.Lhs {
+ if i > 0 {
+ buf.WriteString(", ")
+ }
+ buf.WriteString(lhs.Name())
+ }
+ buf.WriteString(" = ")
+ WriteExpr(&buf, init.Rhs)
+ return buf.String()
+}
+
+// Check type-checks a package and returns the resulting package object,
+// the first error if any, and if info != nil, additional type information.
+// The package is marked as complete if no errors occurred, otherwise it is
+// incomplete. See Config.Error for controlling behavior in the presence of
+// errors.
+//
+// The package is specified by a list of *ast.Files and corresponding
+// file set, and the package path the package is identified with.
+// The clean path must not be empty or dot (".").
+func (conf *Config) Check(path string, fset *token.FileSet, files []*ast.File, info *Info) (*Package, error) {
+ pkg := NewPackage(path, "")
+ return pkg, NewChecker(conf, fset, pkg, info).Files(files)
+}
+
+// AssertableTo reports whether a value of type V can be asserted to have type T.
+func AssertableTo(V *Interface, T Type) bool {
+ m, _ := assertableTo(V, T)
+ return m == nil
+}
+
+// AssignableTo reports whether a value of type V is assignable to a variable of type T.
+func AssignableTo(V, T Type) bool {
+ x := operand{mode: value, typ: V}
+ return x.assignableTo(nil, T) // config not needed for non-constant x
+}
+
+// ConvertibleTo reports whether a value of type V is convertible to a value of type T.
+func ConvertibleTo(V, T Type) bool {
+ x := operand{mode: value, typ: V}
+ return x.convertibleTo(nil, T) // config not needed for non-constant x
+}
+
+// Implements reports whether type V implements interface T.
+func Implements(V Type, T *Interface) bool {
+ f, _ := MissingMethod(V, T, true)
+ return f == nil
+}
diff --git a/go/types/api_test.go b/go/types/api_test.go
new file mode 100644
index 0000000..5a0535f
--- /dev/null
+++ b/go/types/api_test.go
@@ -0,0 +1,1060 @@
+// 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 types_test
+
+import (
+ "bytes"
+ "fmt"
+ "go/ast"
+ "go/parser"
+ "go/token"
+ "reflect"
+ "regexp"
+ "runtime"
+ "strings"
+ "testing"
+
+ _ "golang.org/x/tools/go/gcimporter"
+ . "golang.org/x/tools/go/types"
+)
+
+// skipSpecialPlatforms causes the test to be skipped for platforms where
+// builders (build.golang.org) don't have access to compiled packages for
+// import.
+func skipSpecialPlatforms(t *testing.T) {
+ switch platform := runtime.GOOS + "-" + runtime.GOARCH; platform {
+ case "android-arm",
+ "nacl-amd64p32",
+ "nacl-386",
+ "nacl-arm",
+ "darwin-arm",
+ "darwin-arm64":
+ t.Skipf("no compiled packages available for import on %s", platform)
+ }
+}
+
+func pkgFor(path, source string, info *Info) (*Package, error) {
+ fset := token.NewFileSet()
+ f, err := parser.ParseFile(fset, path, source, 0)
+ if err != nil {
+ return nil, err
+ }
+
+ var conf Config
+ return conf.Check(f.Name.Name, fset, []*ast.File{f}, info)
+}
+
+func mustTypecheck(t *testing.T, path, source string, info *Info) string {
+ pkg, err := pkgFor(path, source, info)
+ if err != nil {
+ name := path
+ if pkg != nil {
+ name = "package " + pkg.Name()
+ }
+ t.Fatalf("%s: didn't type-check (%s)", name, err)
+ }
+ return pkg.Name()
+}
+
+func TestValuesInfo(t *testing.T) {
+ var tests = []struct {
+ src string
+ expr string // constant expression
+ typ string // constant type
+ val string // constant value
+ }{
+ {`package a0; const _ = false`, `false`, `untyped bool`, `false`},
+ {`package a1; const _ = 0`, `0`, `untyped int`, `0`},
+ {`package a2; const _ = 'A'`, `'A'`, `untyped rune`, `65`},
+ {`package a3; const _ = 0.`, `0.`, `untyped float`, `0`},
+ {`package a4; const _ = 0i`, `0i`, `untyped complex`, `0`},
+ {`package a5; const _ = "foo"`, `"foo"`, `untyped string`, `"foo"`},
+
+ {`package b0; var _ = false`, `false`, `bool`, `false`},
+ {`package b1; var _ = 0`, `0`, `int`, `0`},
+ {`package b2; var _ = 'A'`, `'A'`, `rune`, `65`},
+ {`package b3; var _ = 0.`, `0.`, `float64`, `0`},
+ {`package b4; var _ = 0i`, `0i`, `complex128`, `0`},
+ {`package b5; var _ = "foo"`, `"foo"`, `string`, `"foo"`},
+
+ {`package c0a; var _ = bool(false)`, `false`, `bool`, `false`},
+ {`package c0b; var _ = bool(false)`, `bool(false)`, `bool`, `false`},
+ {`package c0c; type T bool; var _ = T(false)`, `T(false)`, `c0c.T`, `false`},
+
+ {`package c1a; var _ = int(0)`, `0`, `int`, `0`},
+ {`package c1b; var _ = int(0)`, `int(0)`, `int`, `0`},
+ {`package c1c; type T int; var _ = T(0)`, `T(0)`, `c1c.T`, `0`},
+
+ {`package c2a; var _ = rune('A')`, `'A'`, `rune`, `65`},
+ {`package c2b; var _ = rune('A')`, `rune('A')`, `rune`, `65`},
+ {`package c2c; type T rune; var _ = T('A')`, `T('A')`, `c2c.T`, `65`},
+
+ {`package c3a; var _ = float32(0.)`, `0.`, `float32`, `0`},
+ {`package c3b; var _ = float32(0.)`, `float32(0.)`, `float32`, `0`},
+ {`package c3c; type T float32; var _ = T(0.)`, `T(0.)`, `c3c.T`, `0`},
+
+ {`package c4a; var _ = complex64(0i)`, `0i`, `complex64`, `0`},
+ {`package c4b; var _ = complex64(0i)`, `complex64(0i)`, `complex64`, `0`},
+ {`package c4c; type T complex64; var _ = T(0i)`, `T(0i)`, `c4c.T`, `0`},
+
+ {`package c5a; var _ = string("foo")`, `"foo"`, `string`, `"foo"`},
+ {`package c5b; var _ = string("foo")`, `string("foo")`, `string`, `"foo"`},
+ {`package c5c; type T string; var _ = T("foo")`, `T("foo")`, `c5c.T`, `"foo"`},
+
+ {`package d0; var _ = []byte("foo")`, `"foo"`, `string`, `"foo"`},
+ {`package d1; var _ = []byte(string("foo"))`, `"foo"`, `string`, `"foo"`},
+ {`package d2; var _ = []byte(string("foo"))`, `string("foo")`, `string`, `"foo"`},
+ {`package d3; type T []byte; var _ = T("foo")`, `"foo"`, `string`, `"foo"`},
+
+ {`package e0; const _ = float32( 1e-200)`, `float32(1e-200)`, `float32`, `0`},
+ {`package e1; const _ = float32(-1e-200)`, `float32(-1e-200)`, `float32`, `0`},
+ {`package e2; const _ = float64( 1e-2000)`, `float64(1e-2000)`, `float64`, `0`},
+ {`package e3; const _ = float64(-1e-2000)`, `float64(-1e-2000)`, `float64`, `0`},
+ {`package e4; const _ = complex64( 1e-200)`, `complex64(1e-200)`, `complex64`, `0`},
+ {`package e5; const _ = complex64(-1e-200)`, `complex64(-1e-200)`, `complex64`, `0`},
+ {`package e6; const _ = complex128( 1e-2000)`, `complex128(1e-2000)`, `complex128`, `0`},
+ {`package e7; const _ = complex128(-1e-2000)`, `complex128(-1e-2000)`, `complex128`, `0`},
+
+ {`package f0 ; var _ float32 = 1e-200`, `1e-200`, `float32`, `0`},
+ {`package f1 ; var _ float32 = -1e-200`, `-1e-200`, `float32`, `0`},
+ {`package f2a; var _ float64 = 1e-2000`, `1e-2000`, `float64`, `0`},
+ {`package f3a; var _ float64 = -1e-2000`, `-1e-2000`, `float64`, `0`},
+ {`package f2b; var _ = 1e-2000`, `1e-2000`, `float64`, `0`},
+ {`package f3b; var _ = -1e-2000`, `-1e-2000`, `float64`, `0`},
+ {`package f4 ; var _ complex64 = 1e-200 `, `1e-200`, `complex64`, `0`},
+ {`package f5 ; var _ complex64 = -1e-200 `, `-1e-200`, `complex64`, `0`},
+ {`package f6a; var _ complex128 = 1e-2000i`, `1e-2000i`, `complex128`, `0`},
+ {`package f7a; var _ complex128 = -1e-2000i`, `-1e-2000i`, `complex128`, `0`},
+ {`package f6b; var _ = 1e-2000i`, `1e-2000i`, `complex128`, `0`},
+ {`package f7b; var _ = -1e-2000i`, `-1e-2000i`, `complex128`, `0`},
+ }
+
+ for _, test := range tests {
+ info := Info{
+ Types: make(map[ast.Expr]TypeAndValue),
+ }
+ name := mustTypecheck(t, "ValuesInfo", test.src, &info)
+
+ // look for constant expression
+ var expr ast.Expr
+ for e := range info.Types {
+ if ExprString(e) == test.expr {
+ expr = e
+ break
+ }
+ }
+ if expr == nil {
+ t.Errorf("package %s: no expression found for %s", name, test.expr)
+ continue
+ }
+ tv := info.Types[expr]
+
+ // check that type is correct
+ if got := tv.Type.String(); got != test.typ {
+ t.Errorf("package %s: got type %s; want %s", name, got, test.typ)
+ continue
+ }
+
+ // check that value is correct
+ if got := tv.Value.String(); got != test.val {
+ t.Errorf("package %s: got value %s; want %s", name, got, test.val)
+ }
+ }
+}
+
+func TestTypesInfo(t *testing.T) {
+ var tests = []struct {
+ src string
+ expr string // expression
+ typ string // value type
+ }{
+ // single-valued expressions of untyped constants
+ {`package b0; var x interface{} = false`, `false`, `bool`},
+ {`package b1; var x interface{} = 0`, `0`, `int`},
+ {`package b2; var x interface{} = 0.`, `0.`, `float64`},
+ {`package b3; var x interface{} = 0i`, `0i`, `complex128`},
+ {`package b4; var x interface{} = "foo"`, `"foo"`, `string`},
+
+ // comma-ok expressions
+ {`package p0; var x interface{}; var _, _ = x.(int)`,
+ `x.(int)`,
+ `(int, bool)`,
+ },
+ {`package p1; var x interface{}; func _() { _, _ = x.(int) }`,
+ `x.(int)`,
+ `(int, bool)`,
+ },
+ // TODO(gri): uncomment if we accept issue 8189.
+ // {`package p2; type mybool bool; var m map[string]complex128; var b mybool; func _() { _, b = m["foo"] }`,
+ // `m["foo"]`,
+ // `(complex128, p2.mybool)`,
+ // },
+ // TODO(gri): remove if we accept issue 8189.
+ {`package p2; var m map[string]complex128; var b bool; func _() { _, b = m["foo"] }`,
+ `m["foo"]`,
+ `(complex128, bool)`,
+ },
+ {`package p3; var c chan string; var _, _ = <-c`,
+ `<-c`,
+ `(string, bool)`,
+ },
+
+ // issue 6796
+ {`package issue6796_a; var x interface{}; var _, _ = (x.(int))`,
+ `x.(int)`,
+ `(int, bool)`,
+ },
+ {`package issue6796_b; var c chan string; var _, _ = (<-c)`,
+ `(<-c)`,
+ `(string, bool)`,
+ },
+ {`package issue6796_c; var c chan string; var _, _ = (<-c)`,
+ `<-c`,
+ `(string, bool)`,
+ },
+ {`package issue6796_d; var c chan string; var _, _ = ((<-c))`,
+ `(<-c)`,
+ `(string, bool)`,
+ },
+ {`package issue6796_e; func f(c chan string) { _, _ = ((<-c)) }`,
+ `(<-c)`,
+ `(string, bool)`,
+ },
+
+ // issue 7060
+ {`package issue7060_a; var ( m map[int]string; x, ok = m[0] )`,
+ `m[0]`,
+ `(string, bool)`,
+ },
+ {`package issue7060_b; var ( m map[int]string; x, ok interface{} = m[0] )`,
+ `m[0]`,
+ `(string, bool)`,
+ },
+ {`package issue7060_c; func f(x interface{}, ok bool, m map[int]string) { x, ok = m[0] }`,
+ `m[0]`,
+ `(string, bool)`,
+ },
+ {`package issue7060_d; var ( ch chan string; x, ok = <-ch )`,
+ `<-ch`,
+ `(string, bool)`,
+ },
+ {`package issue7060_e; var ( ch chan string; x, ok interface{} = <-ch )`,
+ `<-ch`,
+ `(string, bool)`,
+ },
+ {`package issue7060_f; func f(x interface{}, ok bool, ch chan string) { x, ok = <-ch }`,
+ `<-ch`,
+ `(string, bool)`,
+ },
+ }
+
+ for _, test := range tests {
+ info := Info{Types: make(map[ast.Expr]TypeAndValue)}
+ name := mustTypecheck(t, "TypesInfo", test.src, &info)
+
+ // look for expression type
+ var typ Type
+ for e, tv := range info.Types {
+ if ExprString(e) == test.expr {
+ typ = tv.Type
+ break
+ }
+ }
+ if typ == nil {
+ t.Errorf("package %s: no type found for %s", name, test.expr)
+ continue
+ }
+
+ // check that type is correct
+ if got := typ.String(); got != test.typ {
+ t.Errorf("package %s: got %s; want %s", name, got, test.typ)
+ }
+ }
+}
+
+func predString(tv TypeAndValue) string {
+ var buf bytes.Buffer
+ pred := func(b bool, s string) {
+ if b {
+ if buf.Len() > 0 {
+ buf.WriteString(", ")
+ }
+ buf.WriteString(s)
+ }
+ }
+
+ pred(tv.IsVoid(), "void")
+ pred(tv.IsType(), "type")
+ pred(tv.IsBuiltin(), "builtin")
+ pred(tv.IsValue() && tv.Value != nil, "const")
+ pred(tv.IsValue() && tv.Value == nil, "value")
+ pred(tv.IsNil(), "nil")
+ pred(tv.Addressable(), "addressable")
+ pred(tv.Assignable(), "assignable")
+ pred(tv.HasOk(), "hasOk")
+
+ if buf.Len() == 0 {
+ return "invalid"
+ }
+ return buf.String()
+}
+
+func TestPredicatesInfo(t *testing.T) {
+ skipSpecialPlatforms(t)
+
+ var tests = []struct {
+ src string
+ expr string
+ pred string
+ }{
+ // void
+ {`package n0; func f() { f() }`, `f()`, `void`},
+
+ // types
+ {`package t0; type _ int`, `int`, `type`},
+ {`package t1; type _ []int`, `[]int`, `type`},
+ {`package t2; type _ func()`, `func()`, `type`},
+
+ // built-ins
+ {`package b0; var _ = len("")`, `len`, `builtin`},
+ {`package b1; var _ = (len)("")`, `(len)`, `builtin`},
+
+ // constants
+ {`package c0; var _ = 42`, `42`, `const`},
+ {`package c1; var _ = "foo" + "bar"`, `"foo" + "bar"`, `const`},
+ {`package c2; const (i = 1i; _ = i)`, `i`, `const`},
+
+ // values
+ {`package v0; var (a, b int; _ = a + b)`, `a + b`, `value`},
+ {`package v1; var _ = &[]int{1}`, `([]int literal)`, `value`},
+ {`package v2; var _ = func(){}`, `(func() literal)`, `value`},
+ {`package v4; func f() { _ = f }`, `f`, `value`},
+ {`package v3; var _ *int = nil`, `nil`, `value, nil`},
+ {`package v3; var _ *int = (nil)`, `(nil)`, `value, nil`},
+
+ // addressable (and thus assignable) operands
+ {`package a0; var (x int; _ = x)`, `x`, `value, addressable, assignable`},
+ {`package a1; var (p *int; _ = *p)`, `*p`, `value, addressable, assignable`},
+ {`package a2; var (s []int; _ = s[0])`, `s[0]`, `value, addressable, assignable`},
+ {`package a3; var (s struct{f int}; _ = s.f)`, `s.f`, `value, addressable, assignable`},
+ {`package a4; var (a [10]int; _ = a[0])`, `a[0]`, `value, addressable, assignable`},
+ {`package a5; func _(x int) { _ = x }`, `x`, `value, addressable, assignable`},
+ {`package a6; func _()(x int) { _ = x; return }`, `x`, `value, addressable, assignable`},
+ {`package a7; type T int; func (x T) _() { _ = x }`, `x`, `value, addressable, assignable`},
+ // composite literals are not addressable
+
+ // assignable but not addressable values
+ {`package s0; var (m map[int]int; _ = m[0])`, `m[0]`, `value, assignable, hasOk`},
+ {`package s1; var (m map[int]int; _, _ = m[0])`, `m[0]`, `value, assignable, hasOk`},
+
+ // hasOk expressions
+ {`package k0; var (ch chan int; _ = <-ch)`, `<-ch`, `value, hasOk`},
+ {`package k1; var (ch chan int; _, _ = <-ch)`, `<-ch`, `value, hasOk`},
+
+ // missing entries
+ // - package names are collected in the Uses map
+ // - identifiers being declared are collected in the Defs map
+ {`package m0; import "os"; func _() { _ = os.Stdout }`, `os`, `<missing>`},
+ {`package m1; import p "os"; func _() { _ = p.Stdout }`, `p`, `<missing>`},
+ {`package m2; const c = 0`, `c`, `<missing>`},
+ {`package m3; type T int`, `T`, `<missing>`},
+ {`package m4; var v int`, `v`, `<missing>`},
+ {`package m5; func f() {}`, `f`, `<missing>`},
+ {`package m6; func _(x int) {}`, `x`, `<missing>`},
+ {`package m6; func _()(x int) { return }`, `x`, `<missing>`},
+ {`package m6; type T int; func (x T) _() {}`, `x`, `<missing>`},
+ }
+
+ for _, test := range tests {
+ info := Info{Types: make(map[ast.Expr]TypeAndValue)}
+ name := mustTypecheck(t, "PredicatesInfo", test.src, &info)
+
+ // look for expression predicates
+ got := "<missing>"
+ for e, tv := range info.Types {
+ //println(name, ExprString(e))
+ if ExprString(e) == test.expr {
+ got = predString(tv)
+ break
+ }
+ }
+
+ if got != test.pred {
+ t.Errorf("package %s: got %s; want %s", name, got, test.pred)
+ }
+ }
+}
+
+func TestScopesInfo(t *testing.T) {
+ skipSpecialPlatforms(t)
+
+ var tests = []struct {
+ src string
+ scopes []string // list of scope descriptors of the form kind:varlist
+ }{
+ {`package p0`, []string{
+ "file:",
+ }},
+ {`package p1; import ( "fmt"; m "math"; _ "os" ); var ( _ = fmt.Println; _ = m.Pi )`, []string{
+ "file:fmt m",
+ }},
+ {`package p2; func _() {}`, []string{
+ "file:", "func:",
+ }},
+ {`package p3; func _(x, y int) {}`, []string{
+ "file:", "func:x y",
+ }},
+ {`package p4; func _(x, y int) { x, z := 1, 2; _ = z }`, []string{
+ "file:", "func:x y z", // redeclaration of x
+ }},
+ {`package p5; func _(x, y int) (u, _ int) { return }`, []string{
+ "file:", "func:u x y",
+ }},
+ {`package p6; func _() { { var x int; _ = x } }`, []string{
+ "file:", "func:", "block:x",
+ }},
+ {`package p7; func _() { if true {} }`, []string{
+ "file:", "func:", "if:", "block:",
+ }},
+ {`package p8; func _() { if x := 0; x < 0 { y := x; _ = y } }`, []string{
+ "file:", "func:", "if:x", "block:y",
+ }},
+ {`package p9; func _() { switch x := 0; x {} }`, []string{
+ "file:", "func:", "switch:x",
+ }},
+ {`package p10; func _() { switch x := 0; x { case 1: y := x; _ = y; default: }}`, []string{
+ "file:", "func:", "switch:x", "case:y", "case:",
+ }},
+ {`package p11; func _(t interface{}) { switch t.(type) {} }`, []string{
+ "file:", "func:t", "type switch:",
+ }},
+ {`package p12; func _(t interface{}) { switch t := t; t.(type) {} }`, []string{
+ "file:", "func:t", "type switch:t",
+ }},
+ {`package p13; func _(t interface{}) { switch x := t.(type) { case int: _ = x } }`, []string{
+ "file:", "func:t", "type switch:", "case:x", // x implicitly declared
+ }},
+ {`package p14; func _() { select{} }`, []string{
+ "file:", "func:",
+ }},
+ {`package p15; func _(c chan int) { select{ case <-c: } }`, []string{
+ "file:", "func:c", "comm:",
+ }},
+ {`package p16; func _(c chan int) { select{ case i := <-c: x := i; _ = x} }`, []string{
+ "file:", "func:c", "comm:i x",
+ }},
+ {`package p17; func _() { for{} }`, []string{
+ "file:", "func:", "for:", "block:",
+ }},
+ {`package p18; func _(n int) { for i := 0; i < n; i++ { _ = i } }`, []string{
+ "file:", "func:n", "for:i", "block:",
+ }},
+ {`package p19; func _(a []int) { for i := range a { _ = i} }`, []string{
+ "file:", "func:a", "range:i", "block:",
+ }},
+ {`package p20; var s int; func _(a []int) { for i, x := range a { s += x; _ = i } }`, []string{
+ "file:", "func:a", "range:i x", "block:",
+ }},
+ }
+
+ for _, test := range tests {
+ info := Info{Scopes: make(map[ast.Node]*Scope)}
+ name := mustTypecheck(t, "ScopesInfo", test.src, &info)
+
+ // number of scopes must match
+ if len(info.Scopes) != len(test.scopes) {
+ t.Errorf("package %s: got %d scopes; want %d", name, len(info.Scopes), len(test.scopes))
+ }
+
+ // scope descriptions must match
+ for node, scope := range info.Scopes {
+ kind := "<unknown node kind>"
+ switch node.(type) {
+ case *ast.File:
+ kind = "file"
+ case *ast.FuncType:
+ kind = "func"
+ case *ast.BlockStmt:
+ kind = "block"
+ case *ast.IfStmt:
+ kind = "if"
+ case *ast.SwitchStmt:
+ kind = "switch"
+ case *ast.TypeSwitchStmt:
+ kind = "type switch"
+ case *ast.CaseClause:
+ kind = "case"
+ case *ast.CommClause:
+ kind = "comm"
+ case *ast.ForStmt:
+ kind = "for"
+ case *ast.RangeStmt:
+ kind = "range"
+ }
+
+ // look for matching scope description
+ desc := kind + ":" + strings.Join(scope.Names(), " ")
+ found := false
+ for _, d := range test.scopes {
+ if desc == d {
+ found = true
+ break
+ }
+ }
+ if !found {
+ t.Errorf("package %s: no matching scope found for %s", name, desc)
+ }
+ }
+ }
+}
+
+func TestInitOrderInfo(t *testing.T) {
+ var tests = []struct {
+ src string
+ inits []string
+ }{
+ {`package p0; var (x = 1; y = x)`, []string{
+ "x = 1", "y = x",
+ }},
+ {`package p1; var (a = 1; b = 2; c = 3)`, []string{
+ "a = 1", "b = 2", "c = 3",
+ }},
+ {`package p2; var (a, b, c = 1, 2, 3)`, []string{
+ "a = 1", "b = 2", "c = 3",
+ }},
+ {`package p3; var _ = f(); func f() int { return 1 }`, []string{
+ "_ = f()", // blank var
+ }},
+ {`package p4; var (a = 0; x = y; y = z; z = 0)`, []string{
+ "a = 0", "z = 0", "y = z", "x = y",
+ }},
+ {`package p5; var (a, _ = m[0]; m map[int]string)`, []string{
+ "a, _ = m[0]", // blank var
+ }},
+ {`package p6; var a, b = f(); func f() (_, _ int) { return z, z }; var z = 0`, []string{
+ "z = 0", "a, b = f()",
+ }},
+ {`package p7; var (a = func() int { return b }(); b = 1)`, []string{
+ "b = 1", "a = (func() int literal)()",
+ }},
+ {`package p8; var (a, b = func() (_, _ int) { return c, c }(); c = 1)`, []string{
+ "c = 1", "a, b = (func() (_, _ int) literal)()",
+ }},
+ {`package p9; type T struct{}; func (T) m() int { _ = y; return 0 }; var x, y = T.m, 1`, []string{
+ "y = 1", "x = T.m",
+ }},
+ {`package p10; var (d = c + b; a = 0; b = 0; c = 0)`, []string{
+ "a = 0", "b = 0", "c = 0", "d = c + b",
+ }},
+ {`package p11; var (a = e + c; b = d + c; c = 0; d = 0; e = 0)`, []string{
+ "c = 0", "d = 0", "b = d + c", "e = 0", "a = e + c",
+ }},
+ // emit an initializer for n:1 initializations only once (not for each node
+ // on the lhs which may appear in different order in the dependency graph)
+ {`package p12; var (a = x; b = 0; x, y = m[0]; m map[int]int)`, []string{
+ "b = 0", "x, y = m[0]", "a = x",
+ }},
+ // test case from spec section on package initialization
+ {`package p12
+
+ var (
+ a = c + b
+ b = f()
+ c = f()
+ d = 3
+ )
+
+ func f() int {
+ d++
+ return d
+ }`, []string{
+ "d = 3", "b = f()", "c = f()", "a = c + b",
+ }},
+ // test case for issue 7131
+ {`package main
+
+ var counter int
+ func next() int { counter++; return counter }
+
+ var _ = makeOrder()
+ func makeOrder() []int { return []int{f, b, d, e, c, a} }
+
+ var a = next()
+ var b, c = next(), next()
+ var d, e, f = next(), next(), next()
+ `, []string{
+ "a = next()", "b = next()", "c = next()", "d = next()", "e = next()", "f = next()", "_ = makeOrder()",
+ }},
+ }
+
+ for _, test := range tests {
+ info := Info{}
+ name := mustTypecheck(t, "InitOrderInfo", test.src, &info)
+
+ // number of initializers must match
+ if len(info.InitOrder) != len(test.inits) {
+ t.Errorf("package %s: got %d initializers; want %d", name, len(info.InitOrder), len(test.inits))
+ continue
+ }
+
+ // initializers must match
+ for i, want := range test.inits {
+ got := info.InitOrder[i].String()
+ if got != want {
+ t.Errorf("package %s, init %d: got %s; want %s", name, i, got, want)
+ continue
+ }
+ }
+ }
+}
+
+func TestMultiFileInitOrder(t *testing.T) {
+ fset := token.NewFileSet()
+ mustParse := func(src string) *ast.File {
+ f, err := parser.ParseFile(fset, "main", src, 0)
+ if err != nil {
+ t.Fatal(err)
+ }
+ return f
+ }
+
+ fileA := mustParse(`package main; var a = 1`)
+ fileB := mustParse(`package main; var b = 2`)
+
+ // The initialization order must not depend on the parse
+ // order of the files, only on the presentation order to
+ // the type-checker.
+ for _, test := range []struct {
+ files []*ast.File
+ want string
+ }{
+ {[]*ast.File{fileA, fileB}, "[a = 1 b = 2]"},
+ {[]*ast.File{fileB, fileA}, "[b = 2 a = 1]"},
+ } {
+ var info Info
+ if _, err := new(Config).Check("main", fset, test.files, &info); err != nil {
+ t.Fatal(err)
+ }
+ if got := fmt.Sprint(info.InitOrder); got != test.want {
+ t.Fatalf("got %s; want %s", got, test.want)
+ }
+ }
+}
+
+func TestFiles(t *testing.T) {
+ var sources = []string{
+ "package p; type T struct{}; func (T) m1() {}",
+ "package p; func (T) m2() {}; var x interface{ m1(); m2() } = T{}",
+ "package p; func (T) m3() {}; var y interface{ m1(); m2(); m3() } = T{}",
+ "package p",
+ }
+
+ var conf Config
+ fset := token.NewFileSet()
+ pkg := NewPackage("p", "p")
+ var info Info
+ check := NewChecker(&conf, fset, pkg, &info)
+
+ for i, src := range sources {
+ filename := fmt.Sprintf("sources%d", i)
+ f, err := parser.ParseFile(fset, filename, src, 0)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if err := check.Files([]*ast.File{f}); err != nil {
+ t.Error(err)
+ }
+ }
+
+ // check InitOrder is [x y]
+ var vars []string
+ for _, init := range info.InitOrder {
+ for _, v := range init.Lhs {
+ vars = append(vars, v.Name())
+ }
+ }
+ if got, want := fmt.Sprint(vars), "[x y]"; got != want {
+ t.Errorf("InitOrder == %s, want %s", got, want)
+ }
+}
+
+func TestSelection(t *testing.T) {
+ selections := make(map[*ast.SelectorExpr]*Selection)
+
+ fset := token.NewFileSet()
+ conf := Config{
+ Packages: make(map[string]*Package),
+ Import: func(imports map[string]*Package, path string) (*Package, error) {
+ return imports[path], nil
+ },
+ }
+ makePkg := func(path, src string) {
+ f, err := parser.ParseFile(fset, path+".go", src, 0)
+ if err != nil {
+ t.Fatal(err)
+ }
+ pkg, err := conf.Check(path, fset, []*ast.File{f}, &Info{Selections: selections})
+ if err != nil {
+ t.Fatal(err)
+ }
+ conf.Packages[path] = pkg
+ }
+
+ const libSrc = `
+package lib
+type T float64
+const C T = 3
+var V T
+func F() {}
+func (T) M() {}
+`
+ const mainSrc = `
+package main
+import "lib"
+
+type A struct {
+ *B
+ C
+}
+
+type B struct {
+ b int
+}
+
+func (B) f(int)
+
+type C struct {
+ c int
+}
+
+func (C) g()
+func (*C) h()
+
+func main() {
+ // qualified identifiers
+ var _ lib.T
+ _ = lib.C
+ _ = lib.F
+ _ = lib.V
+ _ = lib.T.M
+
+ // fields
+ _ = A{}.B
+ _ = new(A).B
+
+ _ = A{}.C
+ _ = new(A).C
+
+ _ = A{}.b
+ _ = new(A).b
+
+ _ = A{}.c
+ _ = new(A).c
+
+ // methods
+ _ = A{}.f
+ _ = new(A).f
+ _ = A{}.g
+ _ = new(A).g
+ _ = new(A).h
+
+ _ = B{}.f
+ _ = new(B).f
+
+ _ = C{}.g
+ _ = new(C).g
+ _ = new(C).h
+
+ // method expressions
+ _ = A.f
+ _ = (*A).f
+ _ = B.f
+ _ = (*B).f
+}`
+
+ wantOut := map[string][2]string{
+ "lib.T.M": {"method expr (lib.T) M(lib.T)", ".[0]"},
+
+ "A{}.B": {"field (main.A) B *main.B", ".[0]"},
+ "new(A).B": {"field (*main.A) B *main.B", "->[0]"},
+ "A{}.C": {"field (main.A) C main.C", ".[1]"},
+ "new(A).C": {"field (*main.A) C main.C", "->[1]"},
+ "A{}.b": {"field (main.A) b int", "->[0 0]"},
+ "new(A).b": {"field (*main.A) b int", "->[0 0]"},
+ "A{}.c": {"field (main.A) c int", ".[1 0]"},
+ "new(A).c": {"field (*main.A) c int", "->[1 0]"},
+
+ "A{}.f": {"method (main.A) f(int)", "->[0 0]"},
+ "new(A).f": {"method (*main.A) f(int)", "->[0 0]"},
+ "A{}.g": {"method (main.A) g()", ".[1 0]"},
+ "new(A).g": {"method (*main.A) g()", "->[1 0]"},
+ "new(A).h": {"method (*main.A) h()", "->[1 1]"}, // TODO(gri) should this report .[1 1] ?
+ "B{}.f": {"method (main.B) f(int)", ".[0]"},
+ "new(B).f": {"method (*main.B) f(int)", "->[0]"},
+ "C{}.g": {"method (main.C) g()", ".[0]"},
+ "new(C).g": {"method (*main.C) g()", "->[0]"},
+ "new(C).h": {"method (*main.C) h()", "->[1]"}, // TODO(gri) should this report .[1] ?
+
+ "A.f": {"method expr (main.A) f(main.A, int)", "->[0 0]"},
+ "(*A).f": {"method expr (*main.A) f(*main.A, int)", "->[0 0]"},
+ "B.f": {"method expr (main.B) f(main.B, int)", ".[0]"},
+ "(*B).f": {"method expr (*main.B) f(*main.B, int)", "->[0]"},
+ }
+
+ makePkg("lib", libSrc)
+ makePkg("main", mainSrc)
+
+ for e, sel := range selections {
+ sel.String() // assertion: must not panic
+
+ start := fset.Position(e.Pos()).Offset
+ end := fset.Position(e.End()).Offset
+ syntax := mainSrc[start:end] // (all SelectorExprs are in main, not lib)
+
+ direct := "."
+ if sel.Indirect() {
+ direct = "->"
+ }
+ got := [2]string{
+ sel.String(),
+ fmt.Sprintf("%s%v", direct, sel.Index()),
+ }
+ want := wantOut[syntax]
+ if want != got {
+ t.Errorf("%s: got %q; want %q", syntax, got, want)
+ }
+ delete(wantOut, syntax)
+
+ // We must explicitly assert properties of the
+ // Signature's receiver since it doesn't participate
+ // in Identical() or String().
+ sig, _ := sel.Type().(*Signature)
+ if sel.Kind() == MethodVal {
+ got := sig.Recv().Type()
+ want := sel.Recv()
+ if !Identical(got, want) {
+ t.Errorf("%s: Recv() = %s, want %s", syntax, got, want)
+ }
+ } else if sig != nil && sig.Recv() != nil {
+ t.Errorf("%s: signature has receiver %s", sig, sig.Recv().Type())
+ }
+ }
+ // Assert that all wantOut entries were used exactly once.
+ for syntax := range wantOut {
+ t.Errorf("no ast.Selection found with syntax %q", syntax)
+ }
+}
+
+func TestIssue8518(t *testing.T) {
+ fset := token.NewFileSet()
+ conf := Config{
+ Packages: make(map[string]*Package),
+ Error: func(err error) { t.Log(err) }, // don't exit after first error
+ Import: func(imports map[string]*Package, path string) (*Package, error) {
+ return imports[path], nil
+ },
+ }
+ makePkg := func(path, src string) {
+ f, err := parser.ParseFile(fset, path, src, 0)
+ if err != nil {
+ t.Fatal(err)
+ }
+ pkg, _ := conf.Check(path, fset, []*ast.File{f}, nil) // errors logged via conf.Error
+ conf.Packages[path] = pkg
+ }
+
+ const libSrc = `
+package a
+import "missing"
+const C1 = foo
+const C2 = missing.C
+`
+
+ const mainSrc = `
+package main
+import "a"
+var _ = a.C1
+var _ = a.C2
+`
+
+ makePkg("a", libSrc)
+ makePkg("main", mainSrc) // don't crash when type-checking this package
+}
+
+func TestLookupFieldOrMethod(t *testing.T) {
+ // Test cases assume a lookup of the form a.f or x.f, where a stands for an
+ // addressable value, and x for a non-addressable value (even though a variable
+ // for ease of test case writing).
+ var tests = []struct {
+ src string
+ found bool
+ index []int
+ indirect bool
+ }{
+ // field lookups
+ {"var x T; type T struct{}", false, nil, false},
+ {"var x T; type T struct{ f int }", true, []int{0}, false},
+ {"var x T; type T struct{ a, b, f, c int }", true, []int{2}, false},
+
+ // method lookups
+ {"var a T; type T struct{}; func (T) f() {}", true, []int{0}, false},
+ {"var a *T; type T struct{}; func (T) f() {}", true, []int{0}, true},
+ {"var a T; type T struct{}; func (*T) f() {}", true, []int{0}, false},
+ {"var a *T; type T struct{}; func (*T) f() {}", true, []int{0}, true}, // TODO(gri) should this report indirect = false?
+
+ // collisions
+ {"type ( E1 struct{ f int }; E2 struct{ f int }; x struct{ E1; *E2 })", false, []int{1, 0}, false},
+ {"type ( E1 struct{ f int }; E2 struct{}; x struct{ E1; *E2 }); func (E2) f() {}", false, []int{1, 0}, false},
+
+ // outside methodset
+ // (*T).f method exists, but value of type T is not addressable
+ {"var x T; type T struct{}; func (*T) f() {}", false, nil, true},
+ }
+
+ for _, test := range tests {
+ pkg, err := pkgFor("test", "package p;"+test.src, nil)
+ if err != nil {
+ t.Errorf("%s: incorrect test case: %s", test.src, err)
+ continue
+ }
+
+ obj := pkg.Scope().Lookup("a")
+ if obj == nil {
+ if obj = pkg.Scope().Lookup("x"); obj == nil {
+ t.Errorf("%s: incorrect test case - no object a or x", test.src)
+ continue
+ }
+ }
+
+ f, index, indirect := LookupFieldOrMethod(obj.Type(), obj.Name() == "a", pkg, "f")
+ if (f != nil) != test.found {
+ if f == nil {
+ t.Errorf("%s: got no object; want one", test.src)
+ } else {
+ t.Errorf("%s: got object = %v; want none", test.src, f)
+ }
+ }
+ if !sameSlice(index, test.index) {
+ t.Errorf("%s: got index = %v; want %v", test.src, index, test.index)
+ }
+ if indirect != test.indirect {
+ t.Errorf("%s: got indirect = %v; want %v", test.src, indirect, test.indirect)
+ }
+ }
+}
+
+func sameSlice(a, b []int) bool {
+ if len(a) != len(b) {
+ return false
+ }
+ for i, x := range a {
+ if x != b[i] {
+ return false
+ }
+ }
+ return true
+}
+
+// TestScopeLookupParent ensures that (*Scope).LookupParent returns
+// the correct result at various positions with the source.
+func TestScopeLookupParent(t *testing.T) {
+ fset := token.NewFileSet()
+ conf := Config{
+ Packages: make(map[string]*Package),
+ Import: func(imports map[string]*Package, path string) (*Package, error) {
+ return imports[path], nil
+ },
+ }
+ mustParse := func(src string) *ast.File {
+ f, err := parser.ParseFile(fset, "dummy.go", src, parser.ParseComments)
+ if err != nil {
+ t.Fatal(err)
+ }
+ return f
+ }
+ var info Info
+ makePkg := func(path string, files ...*ast.File) {
+ conf.Packages[path], _ = conf.Check(path, fset, files, &info)
+ }
+
+ makePkg("lib", mustParse("package lib; var X int"))
+ // Each /*name=kind:line*/ comment makes the test look up the
+ // name at that point and checks that it resolves to a decl of
+ // the specified kind and line number. "undef" means undefined.
+ mainSrc := `
+package main
+import "lib"
+var Y = lib.X
+func f() {
+ print(Y) /*Y=var:4*/
+ z /*z=undef*/ := /*z=undef*/ 1 /*z=var:7*/
+ print(z)
+ /*f=func:5*/ /*lib=pkgname:3*/
+ type /*T=undef*/ T /*T=typename:10*/ *T
+}
+`
+ info.Uses = make(map[*ast.Ident]Object)
+ f := mustParse(mainSrc)
+ makePkg("main", f)
+ mainScope := conf.Packages["main"].Scope()
+ rx := regexp.MustCompile(`^/\*(\w*)=([\w:]*)\*/$`)
+ for _, group := range f.Comments {
+ for _, comment := range group.List {
+ // Parse the assertion in the comment.
+ m := rx.FindStringSubmatch(comment.Text)
+ if m == nil {
+ t.Errorf("%s: bad comment: %s",
+ fset.Position(comment.Pos()), comment.Text)
+ continue
+ }
+ name, want := m[1], m[2]
+
+ // Look up the name in the innermost enclosing scope.
+ inner := mainScope.Innermost(comment.Pos())
+ if inner == nil {
+ t.Errorf("%s: at %s: can't find innermost scope",
+ fset.Position(comment.Pos()), comment.Text)
+ continue
+ }
+ got := "undef"
+ if _, obj := inner.LookupParent(name, comment.Pos()); obj != nil {
+ kind := strings.ToLower(strings.TrimPrefix(reflect.TypeOf(obj).String(), "*types."))
+ got = fmt.Sprintf("%s:%d", kind, fset.Position(obj.Pos()).Line)
+ }
+ if got != want {
+ t.Errorf("%s: at %s: %s resolved to %s, want %s",
+ fset.Position(comment.Pos()), comment.Text, name, got, want)
+ }
+ }
+ }
+
+ // Check that for each referring identifier,
+ // a lookup of its name on the innermost
+ // enclosing scope returns the correct object.
+
+ for id, wantObj := range info.Uses {
+ inner := mainScope.Innermost(id.Pos())
+ if inner == nil {
+ t.Errorf("%s: can't find innermost scope enclosing %q",
+ fset.Position(id.Pos()), id.Name)
+ continue
+ }
+
+ // Exclude selectors and qualified identifiers---lexical
+ // refs only. (Ideally, we'd see if the AST parent is a
+ // SelectorExpr, but that requires PathEnclosingInterval
+ // from golang.org/x/tools/go/ast/astutil.)
+ if id.Name == "X" {
+ continue
+ }
+
+ _, gotObj := inner.LookupParent(id.Name, id.Pos())
+ if gotObj != wantObj {
+ t.Errorf("%s: got %v, want %v",
+ fset.Position(id.Pos()), gotObj, wantObj)
+ continue
+ }
+ }
+}
diff --git a/go/types/assignments.go b/go/types/assignments.go
new file mode 100644
index 0000000..93b842e
--- /dev/null
+++ b/go/types/assignments.go
@@ -0,0 +1,328 @@
+// 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 initialization and assignment checks.
+
+package types
+
+import (
+ "go/ast"
+ "go/token"
+)
+
+// assignment reports whether x can be assigned to a variable of type T,
+// if necessary by attempting to convert untyped values to the appropriate
+// type. If x.mode == invalid upon return, then assignment has already
+// issued an error message and the caller doesn't have to report another.
+// Use T == nil to indicate assignment to an untyped blank identifier.
+//
+// TODO(gri) Should find a better way to handle in-band errors.
+//
+func (check *Checker) assignment(x *operand, T Type) bool {
+ switch x.mode {
+ case invalid:
+ return true // error reported before
+ case constant, variable, mapindex, value, commaok:
+ // ok
+ default:
+ unreachable()
+ }
+
+ // x must be a single value
+ // (tuple types are never named - no need for underlying type)
+ if t, _ := x.typ.(*Tuple); t != nil {
+ assert(t.Len() > 1)
+ check.errorf(x.pos(), "%d-valued expression %s used as single value", t.Len(), x)
+ x.mode = invalid
+ return false
+ }
+
+ if isUntyped(x.typ) {
+ target := T
+ // spec: "If an untyped constant is assigned to a variable of interface
+ // type or the blank identifier, the constant is first converted to type
+ // bool, rune, int, float64, complex128 or string respectively, depending
+ // on whether the value is a boolean, rune, integer, floating-point, complex,
+ // or string constant."
+ if T == nil || IsInterface(T) {
+ if T == nil && x.typ == Typ[UntypedNil] {
+ check.errorf(x.pos(), "use of untyped nil")
+ x.mode = invalid
+ return false
+ }
+ target = defaultType(x.typ)
+ }
+ check.convertUntyped(x, target)
+ if x.mode == invalid {
+ return false
+ }
+ }
+
+ // spec: "If a left-hand side is the blank identifier, any typed or
+ // non-constant value except for the predeclared identifier nil may
+ // be assigned to it."
+ return T == nil || x.assignableTo(check.conf, T)
+}
+
+func (check *Checker) initConst(lhs *Const, x *operand) {
+ if x.mode == invalid || x.typ == Typ[Invalid] || lhs.typ == Typ[Invalid] {
+ if lhs.typ == nil {
+ lhs.typ = Typ[Invalid]
+ }
+ return
+ }
+
+ // rhs must be a constant
+ if x.mode != constant {
+ check.errorf(x.pos(), "%s is not constant", x)
+ if lhs.typ == nil {
+ lhs.typ = Typ[Invalid]
+ }
+ return
+ }
+ assert(isConstType(x.typ))
+
+ // If the lhs doesn't have a type yet, use the type of x.
+ if lhs.typ == nil {
+ lhs.typ = x.typ
+ }
+
+ if !check.assignment(x, lhs.typ) {
+ if x.mode != invalid {
+ check.errorf(x.pos(), "cannot define constant %s (type %s) as %s", lhs.Name(), lhs.typ, x)
+ }
+ return
+ }
+
+ lhs.val = x.val
+}
+
+// If result is set, lhs is a function result parameter and x is a return result.
+func (check *Checker) initVar(lhs *Var, x *operand, result bool) Type {
+ if x.mode == invalid || x.typ == Typ[Invalid] || lhs.typ == Typ[Invalid] {
+ if lhs.typ == nil {
+ lhs.typ = Typ[Invalid]
+ }
+ return nil
+ }
+
+ // If the lhs doesn't have a type yet, use the type of x.
+ if lhs.typ == nil {
+ typ := x.typ
+ if isUntyped(typ) {
+ // convert untyped types to default types
+ if typ == Typ[UntypedNil] {
+ check.errorf(x.pos(), "use of untyped nil")
+ lhs.typ = Typ[Invalid]
+ return nil
+ }
+ typ = defaultType(typ)
+ }
+ lhs.typ = typ
+ }
+
+ if !check.assignment(x, lhs.typ) {
+ if x.mode != invalid {
+ if result {
+ // don't refer to lhs.name because it may be an anonymous result parameter
+ check.errorf(x.pos(), "cannot return %s as value of type %s", x, lhs.typ)
+ } else {
+ check.errorf(x.pos(), "cannot initialize %s with %s", lhs, x)
+ }
+ }
+ return nil
+ }
+
+ return x.typ
+}
+
+func (check *Checker) assignVar(lhs ast.Expr, x *operand) Type {
+ if x.mode == invalid || x.typ == Typ[Invalid] {
+ return nil
+ }
+
+ // Determine if the lhs is a (possibly parenthesized) identifier.
+ ident, _ := unparen(lhs).(*ast.Ident)
+
+ // Don't evaluate lhs if it is the blank identifier.
+ if ident != nil && ident.Name == "_" {
+ check.recordDef(ident, nil)
+ if !check.assignment(x, nil) {
+ assert(x.mode == invalid)
+ x.typ = nil
+ }
+ return x.typ
+ }
+
+ // If the lhs is an identifier denoting a variable v, this assignment
+ // is not a 'use' of v. Remember current value of v.used and restore
+ // after evaluating the lhs via check.expr.
+ var v *Var
+ var v_used bool
+ if ident != nil {
+ if _, obj := check.scope.LookupParent(ident.Name, token.NoPos); obj != nil {
+ v, _ = obj.(*Var)
+ if v != nil {
+ v_used = v.used
+ }
+ }
+ }
+
+ var z operand
+ check.expr(&z, lhs)
+ if v != nil {
+ v.used = v_used // restore v.used
+ }
+
+ if z.mode == invalid || z.typ == Typ[Invalid] {
+ return nil
+ }
+
+ // spec: "Each left-hand side operand must be addressable, a map index
+ // expression, or the blank identifier. Operands may be parenthesized."
+ switch z.mode {
+ case invalid:
+ return nil
+ case variable, mapindex:
+ // ok
+ default:
+ check.errorf(z.pos(), "cannot assign to %s", &z)
+ return nil
+ }
+
+ if !check.assignment(x, z.typ) {
+ if x.mode != invalid {
+ check.errorf(x.pos(), "cannot assign %s to %s", x, &z)
+ }
+ return nil
+ }
+
+ return x.typ
+}
+
+// If returnPos is valid, initVars is called to type-check the assignment of
+// return expressions, and returnPos is the position of the return statement.
+func (check *Checker) initVars(lhs []*Var, rhs []ast.Expr, returnPos token.Pos) {
+ l := len(lhs)
+ get, r, commaOk := unpack(func(x *operand, i int) { check.expr(x, rhs[i]) }, len(rhs), l == 2 && !returnPos.IsValid())
+ if get == nil || l != r {
+ // invalidate lhs and use rhs
+ for _, obj := range lhs {
+ if obj.typ == nil {
+ obj.typ = Typ[Invalid]
+ }
+ }
+ if get == nil {
+ return // error reported by unpack
+ }
+ check.useGetter(get, r)
+ if returnPos.IsValid() {
+ check.errorf(returnPos, "wrong number of return values (want %d, got %d)", l, r)
+ return
+ }
+ check.errorf(rhs[0].Pos(), "assignment count mismatch (%d vs %d)", l, r)
+ return
+ }
+
+ var x operand
+ if commaOk {
+ var a [2]Type
+ for i := range a {
+ get(&x, i)
+ a[i] = check.initVar(lhs[i], &x, returnPos.IsValid())
+ }
+ check.recordCommaOkTypes(rhs[0], a)
+ return
+ }
+
+ for i, lhs := range lhs {
+ get(&x, i)
+ check.initVar(lhs, &x, returnPos.IsValid())
+ }
+}
+
+func (check *Checker) assignVars(lhs, rhs []ast.Expr) {
+ l := len(lhs)
+ get, r, commaOk := unpack(func(x *operand, i int) { check.expr(x, rhs[i]) }, len(rhs), l == 2)
+ if get == nil {
+ return // error reported by unpack
+ }
+ if l != r {
+ check.useGetter(get, r)
+ check.errorf(rhs[0].Pos(), "assignment count mismatch (%d vs %d)", l, r)
+ return
+ }
+
+ var x operand
+ if commaOk {
+ var a [2]Type
+ for i := range a {
+ get(&x, i)
+ a[i] = check.assignVar(lhs[i], &x)
+ }
+ check.recordCommaOkTypes(rhs[0], a)
+ return
+ }
+
+ for i, lhs := range lhs {
+ get(&x, i)
+ check.assignVar(lhs, &x)
+ }
+}
+
+func (check *Checker) shortVarDecl(pos token.Pos, lhs, rhs []ast.Expr) {
+ scope := check.scope
+
+ // collect lhs variables
+ var newVars []*Var
+ var lhsVars = make([]*Var, len(lhs))
+ for i, lhs := range lhs {
+ var obj *Var
+ if ident, _ := lhs.(*ast.Ident); ident != nil {
+ // Use the correct obj if the ident is redeclared. The
+ // variable's scope starts after the declaration; so we
+ // must use Scope.Lookup here and call Scope.Insert
+ // (via check.declare) later.
+ name := ident.Name
+ if alt := scope.Lookup(name); alt != nil {
+ // redeclared object must be a variable
+ if alt, _ := alt.(*Var); alt != nil {
+ obj = alt
+ } else {
+ check.errorf(lhs.Pos(), "cannot assign to %s", lhs)
+ }
+ check.recordUse(ident, alt)
+ } else {
+ // declare new variable, possibly a blank (_) variable
+ obj = NewVar(ident.Pos(), check.pkg, name, nil)
+ if name != "_" {
+ newVars = append(newVars, obj)
+ }
+ check.recordDef(ident, obj)
+ }
+ } else {
+ check.errorf(lhs.Pos(), "cannot declare %s", lhs)
+ }
+ if obj == nil {
+ obj = NewVar(lhs.Pos(), check.pkg, "_", nil) // dummy variable
+ }
+ lhsVars[i] = obj
+ }
+
+ check.initVars(lhsVars, rhs, token.NoPos)
+
+ // declare new variables
+ if len(newVars) > 0 {
+ // spec: "The scope of a constant or variable identifier declared inside
+ // a function begins at the end of the ConstSpec or VarSpec (ShortVarDecl
+ // for short variable declarations) and ends at the end of the innermost
+ // containing block."
+ scopePos := rhs[len(rhs)-1].End()
+ for _, obj := range newVars {
+ check.declare(scope, nil, obj, scopePos) // recordObject already called
+ }
+ } else {
+ check.softErrorf(pos, "no new variables on left side of :=")
+ }
+}
diff --git a/go/types/builtins.go b/go/types/builtins.go
new file mode 100644
index 0000000..f45f930
--- /dev/null
+++ b/go/types/builtins.go
@@ -0,0 +1,628 @@
+// 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 implements typechecking of builtin function calls.
+
+package types
+
+import (
+ "go/ast"
+ "go/token"
+
+ "golang.org/x/tools/go/exact"
+)
+
+// builtin type-checks a call to the built-in specified by id and
+// returns true if the call is valid, with *x holding the result;
+// but x.expr is not set. If the call is invalid, the result is
+// false, and *x is undefined.
+//
+func (check *Checker) builtin(x *operand, call *ast.CallExpr, id builtinId) (_ bool) {
+ // append is the only built-in that permits the use of ... for the last argument
+ bin := predeclaredFuncs[id]
+ if call.Ellipsis.IsValid() && id != _Append {
+ check.invalidOp(call.Ellipsis, "invalid use of ... with built-in %s", bin.name)
+ check.use(call.Args...)
+ return
+ }
+
+ // For len(x) and cap(x) we need to know if x contains any function calls or
+ // receive operations. Save/restore current setting and set hasCallOrRecv to
+ // false for the evaluation of x so that we can check it afterwards.
+ // Note: We must do this _before_ calling unpack because unpack evaluates the
+ // first argument before we even call arg(x, 0)!
+ if id == _Len || id == _Cap {
+ defer func(b bool) {
+ check.hasCallOrRecv = b
+ }(check.hasCallOrRecv)
+ check.hasCallOrRecv = false
+ }
+
+ // determine actual arguments
+ var arg getter
+ nargs := len(call.Args)
+ switch id {
+ default:
+ // make argument getter
+ arg, nargs, _ = unpack(func(x *operand, i int) { check.expr(x, call.Args[i]) }, nargs, false)
+ if arg == nil {
+ return
+ }
+ // evaluate first argument, if present
+ if nargs > 0 {
+ arg(x, 0)
+ if x.mode == invalid {
+ return
+ }
+ }
+ case _Make, _New, _Offsetof, _Trace:
+ // arguments require special handling
+ }
+
+ // check argument count
+ {
+ msg := ""
+ if nargs < bin.nargs {
+ msg = "not enough"
+ } else if !bin.variadic && nargs > bin.nargs {
+ msg = "too many"
+ }
+ if msg != "" {
+ check.invalidOp(call.Rparen, "%s arguments for %s (expected %d, found %d)", msg, call, bin.nargs, nargs)
+ return
+ }
+ }
+
+ switch id {
+ case _Append:
+ // append(s S, x ...T) S, where T is the element type of S
+ // spec: "The variadic function append appends zero or more values x to s of type
+ // S, which must be a slice type, and returns the resulting slice, also of type S.
+ // The values x are passed to a parameter of type ...T where T is the element type
+ // of S and the respective parameter passing rules apply."
+ S := x.typ
+ var T Type
+ if s, _ := S.Underlying().(*Slice); s != nil {
+ T = s.elem
+ } else {
+ check.invalidArg(x.pos(), "%s is not a slice", x)
+ return
+ }
+
+ // remember arguments that have been evaluated already
+ alist := []operand{*x}
+
+ // spec: "As a special case, append also accepts a first argument assignable
+ // to type []byte with a second argument of string type followed by ... .
+ // This form appends the bytes of the string.
+ if nargs == 2 && call.Ellipsis.IsValid() && x.assignableTo(check.conf, NewSlice(universeByte)) {
+ arg(x, 1)
+ if x.mode == invalid {
+ return
+ }
+ if isString(x.typ) {
+ if check.Types != nil {
+ sig := makeSig(S, S, x.typ)
+ sig.variadic = true
+ check.recordBuiltinType(call.Fun, sig)
+ }
+ x.mode = value
+ x.typ = S
+ break
+ }
+ alist = append(alist, *x)
+ // fallthrough
+ }
+
+ // check general case by creating custom signature
+ sig := makeSig(S, S, NewSlice(T)) // []T required for variadic signature
+ sig.variadic = true
+ check.arguments(x, call, sig, func(x *operand, i int) {
+ // only evaluate arguments that have not been evaluated before
+ if i < len(alist) {
+ *x = alist[i]
+ return
+ }
+ arg(x, i)
+ }, nargs)
+ // ok to continue even if check.arguments reported errors
+
+ x.mode = value
+ x.typ = S
+ if check.Types != nil {
+ check.recordBuiltinType(call.Fun, sig)
+ }
+
+ case _Cap, _Len:
+ // cap(x)
+ // len(x)
+ mode := invalid
+ var typ Type
+ var val exact.Value
+ switch typ = implicitArrayDeref(x.typ.Underlying()); t := typ.(type) {
+ case *Basic:
+ if isString(t) && id == _Len {
+ if x.mode == constant {
+ mode = constant
+ val = exact.MakeInt64(int64(len(exact.StringVal(x.val))))
+ } else {
+ mode = value
+ }
+ }
+
+ case *Array:
+ mode = value
+ // spec: "The expressions len(s) and cap(s) are constants
+ // if the type of s is an array or pointer to an array and
+ // the expression s does not contain channel receives or
+ // function calls; in this case s is not evaluated."
+ if !check.hasCallOrRecv {
+ mode = constant
+ val = exact.MakeInt64(t.len)
+ }
+
+ case *Slice, *Chan:
+ mode = value
+
+ case *Map:
+ if id == _Len {
+ mode = value
+ }
+ }
+
+ if mode == invalid {
+ check.invalidArg(x.pos(), "%s for %s", x, bin.name)
+ return
+ }
+
+ x.mode = mode
+ x.typ = Typ[Int]
+ x.val = val
+ if check.Types != nil && mode != constant {
+ check.recordBuiltinType(call.Fun, makeSig(x.typ, typ))
+ }
+
+ case _Close:
+ // close(c)
+ c, _ := x.typ.Underlying().(*Chan)
+ if c == nil {
+ check.invalidArg(x.pos(), "%s is not a channel", x)
+ return
+ }
+ if c.dir == RecvOnly {
+ check.invalidArg(x.pos(), "%s must not be a receive-only channel", x)
+ return
+ }
+
+ x.mode = novalue
+ if check.Types != nil {
+ check.recordBuiltinType(call.Fun, makeSig(nil, c))
+ }
+
+ case _Complex:
+ // complex(x, y realT) complexT
+ if !check.complexArg(x) {
+ return
+ }
+
+ var y operand
+ arg(&y, 1)
+ if y.mode == invalid {
+ return
+ }
+ if !check.complexArg(&y) {
+ return
+ }
+
+ check.convertUntyped(x, y.typ)
+ if x.mode == invalid {
+ return
+ }
+ check.convertUntyped(&y, x.typ)
+ if y.mode == invalid {
+ return
+ }
+
+ if !Identical(x.typ, y.typ) {
+ check.invalidArg(x.pos(), "mismatched types %s and %s", x.typ, y.typ)
+ return
+ }
+
+ if x.mode == constant && y.mode == constant {
+ x.val = exact.BinaryOp(x.val, token.ADD, exact.MakeImag(y.val))
+ } else {
+ x.mode = value
+ }
+
+ realT := x.typ
+ complexT := Typ[Invalid]
+ switch realT.Underlying().(*Basic).kind {
+ case Float32:
+ complexT = Typ[Complex64]
+ case Float64:
+ complexT = Typ[Complex128]
+ case UntypedInt, UntypedRune, UntypedFloat:
+ if x.mode == constant {
+ realT = defaultType(realT).(*Basic)
+ complexT = Typ[UntypedComplex]
+ } else {
+ // untyped but not constant; probably because one
+ // operand is a non-constant shift of untyped lhs
+ realT = Typ[Float64]
+ complexT = Typ[Complex128]
+ }
+ default:
+ check.invalidArg(x.pos(), "float32 or float64 arguments expected")
+ return
+ }
+
+ x.typ = complexT
+ if check.Types != nil && x.mode != constant {
+ check.recordBuiltinType(call.Fun, makeSig(complexT, realT, realT))
+ }
+
+ if x.mode != constant {
+ // The arguments have now their final types, which at run-
+ // time will be materialized. Update the expression trees.
+ // If the current types are untyped, the materialized type
+ // is the respective default type.
+ // (If the result is constant, the arguments are never
+ // materialized and there is nothing to do.)
+ check.updateExprType(x.expr, realT, true)
+ check.updateExprType(y.expr, realT, true)
+ }
+
+ case _Copy:
+ // copy(x, y []T) int
+ var dst Type
+ if t, _ := x.typ.Underlying().(*Slice); t != nil {
+ dst = t.elem
+ }
+
+ var y operand
+ arg(&y, 1)
+ if y.mode == invalid {
+ return
+ }
+ var src Type
+ switch t := y.typ.Underlying().(type) {
+ case *Basic:
+ if isString(y.typ) {
+ src = universeByte
+ }
+ case *Slice:
+ src = t.elem
+ }
+
+ if dst == nil || src == nil {
+ check.invalidArg(x.pos(), "copy expects slice arguments; found %s and %s", x, &y)
+ return
+ }
+
+ if !Identical(dst, src) {
+ check.invalidArg(x.pos(), "arguments to copy %s and %s have different element types %s and %s", x, &y, dst, src)
+ return
+ }
+
+ if check.Types != nil {
+ check.recordBuiltinType(call.Fun, makeSig(Typ[Int], x.typ, y.typ))
+ }
+ x.mode = value
+ x.typ = Typ[Int]
+
+ case _Delete:
+ // delete(m, k)
+ m, _ := x.typ.Underlying().(*Map)
+ if m == nil {
+ check.invalidArg(x.pos(), "%s is not a map", x)
+ return
+ }
+ arg(x, 1) // k
+ if x.mode == invalid {
+ return
+ }
+
+ if !x.assignableTo(check.conf, m.key) {
+ check.invalidArg(x.pos(), "%s is not assignable to %s", x, m.key)
+ return
+ }
+
+ x.mode = novalue
+ if check.Types != nil {
+ check.recordBuiltinType(call.Fun, makeSig(nil, m, m.key))
+ }
+
+ case _Imag, _Real:
+ // imag(complexT) realT
+ // real(complexT) realT
+ if !isComplex(x.typ) {
+ check.invalidArg(x.pos(), "%s must be a complex number", x)
+ return
+ }
+ if x.mode == constant {
+ if id == _Real {
+ x.val = exact.Real(x.val)
+ } else {
+ x.val = exact.Imag(x.val)
+ }
+ } else {
+ x.mode = value
+ }
+ var k BasicKind
+ switch x.typ.Underlying().(*Basic).kind {
+ case Complex64:
+ k = Float32
+ case Complex128:
+ k = Float64
+ case UntypedComplex:
+ k = UntypedFloat
+ default:
+ unreachable()
+ }
+
+ if check.Types != nil && x.mode != constant {
+ check.recordBuiltinType(call.Fun, makeSig(Typ[k], x.typ))
+ }
+ x.typ = Typ[k]
+
+ case _Make:
+ // make(T, n)
+ // make(T, n, m)
+ // (no argument evaluated yet)
+ arg0 := call.Args[0]
+ T := check.typ(arg0)
+ if T == Typ[Invalid] {
+ return
+ }
+
+ var min int // minimum number of arguments
+ switch T.Underlying().(type) {
+ case *Slice:
+ min = 2
+ case *Map, *Chan:
+ min = 1
+ default:
+ check.invalidArg(arg0.Pos(), "cannot make %s; type must be slice, map, or channel", arg0)
+ return
+ }
+ if nargs < min || min+1 < nargs {
+ check.errorf(call.Pos(), "%s expects %d or %d arguments; found %d", call, min, min+1, nargs)
+ return
+ }
+ var sizes []int64 // constant integer arguments, if any
+ for _, arg := range call.Args[1:] {
+ if s, ok := check.index(arg, -1); ok && s >= 0 {
+ sizes = append(sizes, s)
+ }
+ }
+ if len(sizes) == 2 && sizes[0] > sizes[1] {
+ check.invalidArg(call.Args[1].Pos(), "length and capacity swapped")
+ // safe to continue
+ }
+ x.mode = value
+ x.typ = T
+ if check.Types != nil {
+ params := [...]Type{T, Typ[Int], Typ[Int]}
+ check.recordBuiltinType(call.Fun, makeSig(x.typ, params[:1+len(sizes)]...))
+ }
+
+ case _New:
+ // new(T)
+ // (no argument evaluated yet)
+ T := check.typ(call.Args[0])
+ if T == Typ[Invalid] {
+ return
+ }
+
+ x.mode = value
+ x.typ = &Pointer{base: T}
+ if check.Types != nil {
+ check.recordBuiltinType(call.Fun, makeSig(x.typ, T))
+ }
+
+ case _Panic:
+ // panic(x)
+ T := new(Interface)
+ if !check.assignment(x, T) {
+ assert(x.mode == invalid)
+ return
+ }
+
+ x.mode = novalue
+ if check.Types != nil {
+ check.recordBuiltinType(call.Fun, makeSig(nil, T))
+ }
+
+ case _Print, _Println:
+ // print(x, y, ...)
+ // println(x, y, ...)
+ var params []Type
+ if nargs > 0 {
+ params = make([]Type, nargs)
+ for i := 0; i < nargs; i++ {
+ if i > 0 {
+ arg(x, i) // first argument already evaluated
+ }
+ if !check.assignment(x, nil) {
+ assert(x.mode == invalid)
+ return
+ }
+ params[i] = x.typ
+ }
+ }
+
+ x.mode = novalue
+ if check.Types != nil {
+ check.recordBuiltinType(call.Fun, makeSig(nil, params...))
+ }
+
+ case _Recover:
+ // recover() interface{}
+ x.mode = value
+ x.typ = new(Interface)
+ if check.Types != nil {
+ check.recordBuiltinType(call.Fun, makeSig(x.typ))
+ }
+
+ case _Alignof:
+ // unsafe.Alignof(x T) uintptr
+ if !check.assignment(x, nil) {
+ assert(x.mode == invalid)
+ return
+ }
+
+ x.mode = constant
+ x.val = exact.MakeInt64(check.conf.alignof(x.typ))
+ x.typ = Typ[Uintptr]
+ // result is constant - no need to record signature
+
+ case _Offsetof:
+ // unsafe.Offsetof(x T) uintptr, where x must be a selector
+ // (no argument evaluated yet)
+ arg0 := call.Args[0]
+ selx, _ := unparen(arg0).(*ast.SelectorExpr)
+ if selx == nil {
+ check.invalidArg(arg0.Pos(), "%s is not a selector expression", arg0)
+ check.use(arg0)
+ return
+ }
+
+ check.expr(x, selx.X)
+ if x.mode == invalid {
+ return
+ }
+
+ base := derefStructPtr(x.typ)
+ sel := selx.Sel.Name
+ obj, index, indirect := LookupFieldOrMethod(base, false, check.pkg, sel)
+ switch obj.(type) {
+ case nil:
+ check.invalidArg(x.pos(), "%s has no single field %s", base, sel)
+ return
+ case *Func:
+ // TODO(gri) Using derefStructPtr may result in methods being found
+ // that don't actually exist. An error either way, but the error
+ // message is confusing. See: http://play.golang.org/p/al75v23kUy ,
+ // but go/types reports: "invalid argument: x.m is a method value".
+ check.invalidArg(arg0.Pos(), "%s is a method value", arg0)
+ return
+ }
+ if indirect {
+ check.invalidArg(x.pos(), "field %s is embedded via a pointer in %s", sel, base)
+ return
+ }
+
+ // TODO(gri) Should we pass x.typ instead of base (and indirect report if derefStructPtr indirected)?
+ check.recordSelection(selx, FieldVal, base, obj, index, false)
+
+ offs := check.conf.offsetof(base, index)
+ x.mode = constant
+ x.val = exact.MakeInt64(offs)
+ x.typ = Typ[Uintptr]
+ // result is constant - no need to record signature
+
+ case _Sizeof:
+ // unsafe.Sizeof(x T) uintptr
+ if !check.assignment(x, nil) {
+ assert(x.mode == invalid)
+ return
+ }
+
+ x.mode = constant
+ x.val = exact.MakeInt64(check.conf.sizeof(x.typ))
+ x.typ = Typ[Uintptr]
+ // result is constant - no need to record signature
+
+ case _Assert:
+ // assert(pred) causes a typechecker error if pred is false.
+ // The result of assert is the value of pred if there is no error.
+ // Note: assert is only available in self-test mode.
+ if x.mode != constant || !isBoolean(x.typ) {
+ check.invalidArg(x.pos(), "%s is not a boolean constant", x)
+ return
+ }
+ if x.val.Kind() != exact.Bool {
+ check.errorf(x.pos(), "internal error: value of %s should be a boolean constant", x)
+ return
+ }
+ if !exact.BoolVal(x.val) {
+ check.errorf(call.Pos(), "%s failed", call)
+ // compile-time assertion failure - safe to continue
+ }
+ // result is constant - no need to record signature
+
+ case _Trace:
+ // trace(x, y, z, ...) dumps the positions, expressions, and
+ // values of its arguments. The result of trace is the value
+ // of the first argument.
+ // Note: trace is only available in self-test mode.
+ // (no argument evaluated yet)
+ if nargs == 0 {
+ check.dump("%s: trace() without arguments", call.Pos())
+ x.mode = novalue
+ break
+ }
+ var t operand
+ x1 := x
+ for _, arg := range call.Args {
+ check.rawExpr(x1, arg, nil) // permit trace for types, e.g.: new(trace(T))
+ check.dump("%s: %s", x1.pos(), x1)
+ x1 = &t // use incoming x only for first argument
+ }
+ // trace is only available in test mode - no need to record signature
+
+ default:
+ unreachable()
+ }
+
+ return true
+}
+
+// makeSig makes a signature for the given argument and result types.
+// Default types are used for untyped arguments, and res may be nil.
+func makeSig(res Type, args ...Type) *Signature {
+ list := make([]*Var, len(args))
+ for i, param := range args {
+ list[i] = NewVar(token.NoPos, nil, "", defaultType(param))
+ }
+ params := NewTuple(list...)
+ var result *Tuple
+ if res != nil {
+ assert(!isUntyped(res))
+ result = NewTuple(NewVar(token.NoPos, nil, "", res))
+ }
+ return &Signature{params: params, results: result}
+}
+
+// implicitArrayDeref returns A if typ is of the form *A and A is an array;
+// otherwise it returns typ.
+//
+func implicitArrayDeref(typ Type) Type {
+ if p, ok := typ.(*Pointer); ok {
+ if a, ok := p.base.Underlying().(*Array); ok {
+ return a
+ }
+ }
+ return typ
+}
+
+// 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
+ }
+}
+
+func (check *Checker) complexArg(x *operand) bool {
+ t, _ := x.typ.Underlying().(*Basic)
+ if t != nil && (t.info&IsFloat != 0 || t.kind == UntypedInt || t.kind == UntypedRune) {
+ return true
+ }
+ check.invalidArg(x.pos(), "%s must be a float32, float64, or an untyped non-complex numeric constant", x)
+ return false
+}
diff --git a/go/types/builtins_test.go b/go/types/builtins_test.go
new file mode 100644
index 0000000..e785799
--- /dev/null
+++ b/go/types/builtins_test.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.
+
+package types_test
+
+import (
+ "fmt"
+ "go/ast"
+ "go/parser"
+ "testing"
+
+ _ "golang.org/x/tools/go/gcimporter"
+ . "golang.org/x/tools/go/types"
+)
+
+var builtinCalls = []struct {
+ name, src, sig string
+}{
+ {"append", `var s []int; _ = append(s)`, `func([]int, ...int) []int`},
+ {"append", `var s []int; _ = append(s, 0)`, `func([]int, ...int) []int`},
+ {"append", `var s []int; _ = (append)(s, 0)`, `func([]int, ...int) []int`},
+ {"append", `var s []byte; _ = ((append))(s, 0)`, `func([]byte, ...byte) []byte`},
+ {"append", `var s []byte; _ = append(s, "foo"...)`, `func([]byte, string...) []byte`},
+ {"append", `type T []byte; var s T; var str string; _ = append(s, str...)`, `func(p.T, string...) p.T`},
+ {"append", `type T []byte; type U string; var s T; var str U; _ = append(s, str...)`, `func(p.T, p.U...) p.T`},
+
+ {"cap", `var s [10]int; _ = cap(s)`, `invalid type`}, // constant
+ {"cap", `var s [10]int; _ = cap(&s)`, `invalid type`}, // constant
+ {"cap", `var s []int64; _ = cap(s)`, `func([]int64) int`},
+ {"cap", `var c chan<-bool; _ = cap(c)`, `func(chan<- bool) int`},
+
+ {"len", `_ = len("foo")`, `invalid type`}, // constant
+ {"len", `var s string; _ = len(s)`, `func(string) int`},
+ {"len", `var s [10]int; _ = len(s)`, `invalid type`}, // constant
+ {"len", `var s [10]int; _ = len(&s)`, `invalid type`}, // constant
+ {"len", `var s []int64; _ = len(s)`, `func([]int64) int`},
+ {"len", `var c chan<-bool; _ = len(c)`, `func(chan<- bool) int`},
+ {"len", `var m map[string]float32; _ = len(m)`, `func(map[string]float32) int`},
+
+ {"close", `var c chan int; close(c)`, `func(chan int)`},
+ {"close", `var c chan<- chan string; close(c)`, `func(chan<- chan string)`},
+
+ {"complex", `_ = complex(1, 0)`, `invalid type`}, // constant
+ {"complex", `var re float32; _ = complex(re, 1.0)`, `func(float32, float32) complex64`},
+ {"complex", `var im float64; _ = complex(1, im)`, `func(float64, float64) complex128`},
+ {"complex", `type F32 float32; var re, im F32; _ = complex(re, im)`, `func(p.F32, p.F32) complex64`},
+ {"complex", `type F64 float64; var re, im F64; _ = complex(re, im)`, `func(p.F64, p.F64) complex128`},
+
+ {"copy", `var src, dst []byte; copy(dst, src)`, `func([]byte, []byte) int`},
+ {"copy", `type T [][]int; var src, dst T; _ = copy(dst, src)`, `func(p.T, p.T) int`},
+ {"copy", `var src string; var dst []byte; copy(dst, src)`, `func([]byte, string) int`},
+ {"copy", `type T string; type U []byte; var src T; var dst U; copy(dst, src)`, `func(p.U, p.T) int`},
+ {"copy", `var dst []byte; copy(dst, "hello")`, `func([]byte, string) int`},
+
+ {"delete", `var m map[string]bool; delete(m, "foo")`, `func(map[string]bool, string)`},
+ {"delete", `type (K string; V int); var m map[K]V; delete(m, "foo")`, `func(map[p.K]p.V, p.K)`},
+
+ {"imag", `_ = imag(1i)`, `invalid type`}, // constant
+ {"imag", `var c complex64; _ = imag(c)`, `func(complex64) float32`},
+ {"imag", `var c complex128; _ = imag(c)`, `func(complex128) float64`},
+ {"imag", `type C64 complex64; var c C64; _ = imag(c)`, `func(p.C64) float32`},
+ {"imag", `type C128 complex128; var c C128; _ = imag(c)`, `func(p.C128) float64`},
+
+ {"real", `_ = real(1i)`, `invalid type`}, // constant
+ {"real", `var c complex64; _ = real(c)`, `func(complex64) float32`},
+ {"real", `var c complex128; _ = real(c)`, `func(complex128) float64`},
+ {"real", `type C64 complex64; var c C64; _ = real(c)`, `func(p.C64) float32`},
+ {"real", `type C128 complex128; var c C128; _ = real(c)`, `func(p.C128) float64`},
+
+ {"make", `_ = make([]int, 10)`, `func([]int, int) []int`},
+ {"make", `type T []byte; _ = make(T, 10, 20)`, `func(p.T, int, int) p.T`},
+
+ {"new", `_ = new(int)`, `func(int) *int`},
+ {"new", `type T struct{}; _ = new(T)`, `func(p.T) *p.T`},
+
+ {"panic", `panic(0)`, `func(interface{})`},
+ {"panic", `panic("foo")`, `func(interface{})`},
+
+ {"print", `print()`, `func()`},
+ {"print", `print(0)`, `func(int)`},
+ {"print", `print(1, 2.0, "foo", true)`, `func(int, float64, string, bool)`},
+
+ {"println", `println()`, `func()`},
+ {"println", `println(0)`, `func(int)`},
+ {"println", `println(1, 2.0, "foo", true)`, `func(int, float64, string, bool)`},
+
+ {"recover", `recover()`, `func() interface{}`},
+ {"recover", `_ = recover()`, `func() interface{}`},
+
+ {"Alignof", `_ = unsafe.Alignof(0)`, `invalid type`}, // constant
+ {"Alignof", `var x struct{}; _ = unsafe.Alignof(x)`, `invalid type`}, // constant
+
+ {"Offsetof", `var x struct{f bool}; _ = unsafe.Offsetof(x.f)`, `invalid type`}, // constant
+ {"Offsetof", `var x struct{_ int; f bool}; _ = unsafe.Offsetof((&x).f)`, `invalid type`}, // constant
+
+ {"Sizeof", `_ = unsafe.Sizeof(0)`, `invalid type`}, // constant
+ {"Sizeof", `var x struct{}; _ = unsafe.Sizeof(x)`, `invalid type`}, // constant
+
+ {"assert", `assert(true)`, `invalid type`}, // constant
+ {"assert", `type B bool; const pred B = 1 < 2; assert(pred)`, `invalid type`}, // constant
+
+ // no tests for trace since it produces output as a side-effect
+}
+
+func TestBuiltinSignatures(t *testing.T) {
+ DefPredeclaredTestFuncs()
+
+ seen := map[string]bool{"trace": true} // no test for trace built-in; add it manually
+ for _, call := range builtinCalls {
+ testBuiltinSignature(t, call.name, call.src, call.sig)
+ seen[call.name] = true
+ }
+
+ // make sure we didn't miss one
+ for _, name := range Universe.Names() {
+ if _, ok := Universe.Lookup(name).(*Builtin); ok && !seen[name] {
+ t.Errorf("missing test for %s", name)
+ }
+ }
+ for _, name := range Unsafe.Scope().Names() {
+ if _, ok := Unsafe.Scope().Lookup(name).(*Builtin); ok && !seen[name] {
+ t.Errorf("missing test for unsafe.%s", name)
+ }
+ }
+}
+
+func testBuiltinSignature(t *testing.T, name, src0, want string) {
+ src := fmt.Sprintf(`package p; import "unsafe"; type _ unsafe.Pointer /* use unsafe */; func _() { %s }`, src0)
+ f, err := parser.ParseFile(fset, "", src, 0)
+ if err != nil {
+ t.Errorf("%s: %s", src0, err)
+ return
+ }
+
+ var conf Config
+ uses := make(map[*ast.Ident]Object)
+ types := make(map[ast.Expr]TypeAndValue)
+ _, err = conf.Check(f.Name.Name, fset, []*ast.File{f}, &Info{Uses: uses, Types: types})
+ if err != nil {
+ t.Errorf("%s: %s", src0, err)
+ return
+ }
+
+ // find called function
+ n := 0
+ var fun ast.Expr
+ for x := range types {
+ if call, _ := x.(*ast.CallExpr); call != nil {
+ fun = call.Fun
+ n++
+ }
+ }
+ if n != 1 {
+ t.Errorf("%s: got %d CallExprs; want 1", src0, n)
+ return
+ }
+
+ // check recorded types for fun and descendents (may be parenthesized)
+ for {
+ // the recorded type for the built-in must match the wanted signature
+ typ := types[fun].Type
+ if typ == nil {
+ t.Errorf("%s: no type recorded for %s", src0, ExprString(fun))
+ return
+ }
+ if got := typ.String(); got != want {
+ t.Errorf("%s: got type %s; want %s", src0, got, want)
+ return
+ }
+
+ // called function must be a (possibly parenthesized, qualified)
+ // identifier denoting the expected built-in
+ switch p := fun.(type) {
+ case *ast.Ident:
+ obj := uses[p]
+ if obj == nil {
+ t.Errorf("%s: no object found for %s", src0, p)
+ return
+ }
+ bin, _ := obj.(*Builtin)
+ if bin == nil {
+ t.Errorf("%s: %s does not denote a built-in", src0, p)
+ return
+ }
+ if bin.Name() != name {
+ t.Errorf("%s: got built-in %s; want %s", src0, bin.Name(), name)
+ return
+ }
+ return // we're done
+
+ case *ast.ParenExpr:
+ fun = p.X // unpack
+
+ case *ast.SelectorExpr:
+ // built-in from package unsafe - ignore details
+ return // we're done
+
+ default:
+ t.Errorf("%s: invalid function call", src0)
+ return
+ }
+ }
+}
diff --git a/go/types/call.go b/go/types/call.go
new file mode 100644
index 0000000..1e94212
--- /dev/null
+++ b/go/types/call.go
@@ -0,0 +1,441 @@
+// 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 typechecking of call and selector expressions.
+
+package types
+
+import (
+ "go/ast"
+ "go/token"
+)
+
+func (check *Checker) call(x *operand, e *ast.CallExpr) exprKind {
+ check.exprOrType(x, e.Fun)
+
+ switch x.mode {
+ case invalid:
+ check.use(e.Args...)
+ x.mode = invalid
+ x.expr = e
+ return statement
+
+ case typexpr:
+ // conversion
+ T := x.typ
+ x.mode = invalid
+ switch n := len(e.Args); n {
+ case 0:
+ check.errorf(e.Rparen, "missing argument in conversion to %s", T)
+ case 1:
+ check.expr(x, e.Args[0])
+ if x.mode != invalid {
+ check.conversion(x, T)
+ }
+ default:
+ check.errorf(e.Args[n-1].Pos(), "too many arguments in conversion to %s", T)
+ }
+ x.expr = e
+ return conversion
+
+ case builtin:
+ id := x.id
+ if !check.builtin(x, e, id) {
+ x.mode = invalid
+ }
+ x.expr = e
+ // a non-constant result implies a function call
+ if x.mode != invalid && x.mode != constant {
+ check.hasCallOrRecv = true
+ }
+ return predeclaredFuncs[id].kind
+
+ default:
+ // function/method call
+ sig, _ := x.typ.Underlying().(*Signature)
+ if sig == nil {
+ check.invalidOp(x.pos(), "cannot call non-function %s", x)
+ x.mode = invalid
+ x.expr = e
+ return statement
+ }
+
+ arg, n, _ := unpack(func(x *operand, i int) { check.expr(x, e.Args[i]) }, len(e.Args), false)
+ if arg == nil {
+ x.mode = invalid
+ x.expr = e
+ return statement
+ }
+
+ check.arguments(x, e, sig, arg, n)
+
+ // determine result
+ switch sig.results.Len() {
+ case 0:
+ x.mode = novalue
+ case 1:
+ x.mode = value
+ x.typ = sig.results.vars[0].typ // unpack tuple
+ default:
+ x.mode = value
+ x.typ = sig.results
+ }
+ x.expr = e
+ check.hasCallOrRecv = true
+
+ return statement
+ }
+}
+
+// use type-checks each argument.
+// Useful to make sure expressions are evaluated
+// (and variables are "used") in the presence of other errors.
+func (check *Checker) use(arg ...ast.Expr) {
+ var x operand
+ for _, e := range arg {
+ check.rawExpr(&x, e, nil)
+ }
+}
+
+// useGetter is like use, but takes a getter instead of a list of expressions.
+// It should be called instead of use if a getter is present to avoid repeated
+// evaluation of the first argument (since the getter was likely obtained via
+// unpack, which may have evaluated the first argument already).
+func (check *Checker) useGetter(get getter, n int) {
+ var x operand
+ for i := 0; i < n; i++ {
+ get(&x, i)
+ }
+}
+
+// A getter sets x as the i'th operand, where 0 <= i < n and n is the total
+// number of operands (context-specific, and maintained elsewhere). A getter
+// type-checks the i'th operand; the details of the actual check are getter-
+// specific.
+type getter func(x *operand, i int)
+
+// unpack takes a getter get and a number of operands n. If n == 1, unpack
+// calls the incoming getter for the first operand. If that operand is
+// invalid, unpack returns (nil, 0, false). Otherwise, if that operand is a
+// function call, or a comma-ok expression and allowCommaOk is set, the result
+// is a new getter and operand count providing access to the function results,
+// or comma-ok values, respectively. The third result value reports if it
+// is indeed the comma-ok case. In all other cases, the incoming getter and
+// operand count are returned unchanged, and the third result value is false.
+//
+// In other words, if there's exactly one operand that - after type-checking
+// by calling get - stands for multiple operands, the resulting getter provides
+// access to those operands instead.
+//
+// If the returned getter is called at most once for a given operand index i
+// (including i == 0), that operand is guaranteed to cause only one call of
+// the incoming getter with that i.
+//
+func unpack(get getter, n int, allowCommaOk bool) (getter, int, bool) {
+ if n == 1 {
+ // possibly result of an n-valued function call or comma,ok value
+ var x0 operand
+ get(&x0, 0)
+ if x0.mode == invalid {
+ return nil, 0, false
+ }
+
+ if t, ok := x0.typ.(*Tuple); ok {
+ // result of an n-valued function call
+ return func(x *operand, i int) {
+ x.mode = value
+ x.expr = x0.expr
+ x.typ = t.At(i).typ
+ }, t.Len(), false
+ }
+
+ if x0.mode == mapindex || x0.mode == commaok {
+ // comma-ok value
+ if allowCommaOk {
+ a := [2]Type{x0.typ, Typ[UntypedBool]}
+ return func(x *operand, i int) {
+ x.mode = value
+ x.expr = x0.expr
+ x.typ = a[i]
+ }, 2, true
+ }
+ x0.mode = value
+ }
+
+ // single value
+ return func(x *operand, i int) {
+ if i != 0 {
+ unreachable()
+ }
+ *x = x0
+ }, 1, false
+ }
+
+ // zero or multiple values
+ return get, n, false
+}
+
+// arguments checks argument passing for the call with the given signature.
+// The arg function provides the operand for the i'th argument.
+func (check *Checker) arguments(x *operand, call *ast.CallExpr, sig *Signature, arg getter, n int) {
+ if call.Ellipsis.IsValid() {
+ // last argument is of the form x...
+ if len(call.Args) == 1 && n > 1 {
+ // f()... is not permitted if f() is multi-valued
+ check.errorf(call.Ellipsis, "cannot use ... with %d-valued expression %s", n, call.Args[0])
+ check.useGetter(arg, n)
+ return
+ }
+ if !sig.variadic {
+ check.errorf(call.Ellipsis, "cannot use ... in call to non-variadic %s", call.Fun)
+ check.useGetter(arg, n)
+ return
+ }
+ }
+
+ // evaluate arguments
+ for i := 0; i < n; i++ {
+ arg(x, i)
+ if x.mode != invalid {
+ var ellipsis token.Pos
+ if i == n-1 && call.Ellipsis.IsValid() {
+ ellipsis = call.Ellipsis
+ }
+ check.argument(sig, i, x, ellipsis)
+ }
+ }
+
+ // check argument count
+ if sig.variadic {
+ // a variadic function accepts an "empty"
+ // last argument: count one extra
+ n++
+ }
+ if n < sig.params.Len() {
+ check.errorf(call.Rparen, "too few arguments in call to %s", call.Fun)
+ // ok to continue
+ }
+}
+
+// argument checks passing of argument x to the i'th parameter of the given signature.
+// If ellipsis is valid, the argument is followed by ... at that position in the call.
+func (check *Checker) argument(sig *Signature, i int, x *operand, ellipsis token.Pos) {
+ n := sig.params.Len()
+
+ // determine parameter type
+ var typ Type
+ switch {
+ case i < n:
+ typ = sig.params.vars[i].typ
+ case sig.variadic:
+ typ = sig.params.vars[n-1].typ
+ if debug {
+ if _, ok := typ.(*Slice); !ok {
+ check.dump("%s: expected unnamed slice type, got %s", sig.params.vars[n-1].Pos(), typ)
+ }
+ }
+ default:
+ check.errorf(x.pos(), "too many arguments")
+ return
+ }
+
+ if ellipsis.IsValid() {
+ // argument is of the form x...
+ if i != n-1 {
+ check.errorf(ellipsis, "can only use ... with matching parameter")
+ return
+ }
+ switch t := x.typ.Underlying().(type) {
+ case *Slice:
+ // ok
+ case *Tuple:
+ check.errorf(ellipsis, "cannot use ... with %d-valued expression %s", t.Len(), x)
+ return
+ default:
+ check.errorf(x.pos(), "cannot use %s as parameter of type %s", x, typ)
+ return
+ }
+ } else if sig.variadic && i >= n-1 {
+ // use the variadic parameter slice's element type
+ typ = typ.(*Slice).elem
+ }
+
+ if !check.assignment(x, typ) && x.mode != invalid {
+ check.errorf(x.pos(), "cannot pass argument %s to parameter of type %s", x, typ)
+ }
+}
+
+func (check *Checker) selector(x *operand, e *ast.SelectorExpr) {
+ // these must be declared before the "goto Error" statements
+ var (
+ obj Object
+ index []int
+ indirect bool
+ )
+
+ sel := e.Sel.Name
+ // If the identifier refers to a package, handle everything here
+ // so we don't need a "package" mode for operands: package names
+ // can only appear in qualified identifiers which are mapped to
+ // selector expressions.
+ if ident, ok := e.X.(*ast.Ident); ok {
+ _, obj := check.scope.LookupParent(ident.Name, check.pos)
+ if pkg, _ := obj.(*PkgName); pkg != nil {
+ assert(pkg.pkg == check.pkg)
+ check.recordUse(ident, pkg)
+ pkg.used = true
+ exp := pkg.imported.scope.Lookup(sel)
+ if exp == nil {
+ if !pkg.imported.fake {
+ check.errorf(e.Pos(), "%s not declared by package %s", sel, ident)
+ }
+ goto Error
+ }
+ if !exp.Exported() {
+ check.errorf(e.Pos(), "%s not exported by package %s", sel, ident)
+ // ok to continue
+ }
+ check.recordUse(e.Sel, exp)
+ // Simplified version of the code for *ast.Idents:
+ // - imported objects are always fully initialized
+ switch exp := exp.(type) {
+ case *Const:
+ assert(exp.Val() != nil)
+ x.mode = constant
+ x.typ = exp.typ
+ x.val = exp.val
+ case *TypeName:
+ x.mode = typexpr
+ x.typ = exp.typ
+ case *Var:
+ x.mode = variable
+ x.typ = exp.typ
+ case *Func:
+ x.mode = value
+ x.typ = exp.typ
+ case *Builtin:
+ x.mode = builtin
+ x.typ = exp.typ
+ x.id = exp.id
+ default:
+ unreachable()
+ }
+ x.expr = e
+ return
+ }
+ }
+
+ check.exprOrType(x, e.X)
+ if x.mode == invalid {
+ goto Error
+ }
+
+ obj, index, indirect = LookupFieldOrMethod(x.typ, x.mode == variable, check.pkg, sel)
+ if obj == nil {
+ switch {
+ case index != nil:
+ // TODO(gri) should provide actual type where the conflict happens
+ check.invalidOp(e.Pos(), "ambiguous selector %s", sel)
+ case indirect:
+ check.invalidOp(e.Pos(), "%s is not in method set of %s", sel, x.typ)
+ default:
+ check.invalidOp(e.Pos(), "%s has no field or method %s", x, sel)
+ }
+ goto Error
+ }
+
+ if x.mode == typexpr {
+ // method expression
+ m, _ := obj.(*Func)
+ if m == nil {
+ check.invalidOp(e.Pos(), "%s has no method %s", x, sel)
+ goto Error
+ }
+
+ check.recordSelection(e, MethodExpr, x.typ, m, index, indirect)
+
+ // the receiver type becomes the type of the first function
+ // argument of the method expression's function type
+ var params []*Var
+ sig := m.typ.(*Signature)
+ if sig.params != nil {
+ params = sig.params.vars
+ }
+ x.mode = value
+ x.typ = &Signature{
+ params: NewTuple(append([]*Var{NewVar(token.NoPos, check.pkg, "", x.typ)}, params...)...),
+ results: sig.results,
+ variadic: sig.variadic,
+ }
+
+ check.addDeclDep(m)
+
+ } else {
+ // regular selector
+ switch obj := obj.(type) {
+ case *Var:
+ check.recordSelection(e, FieldVal, x.typ, obj, index, indirect)
+ if x.mode == variable || indirect {
+ x.mode = variable
+ } else {
+ x.mode = value
+ }
+ x.typ = obj.typ
+
+ case *Func:
+ // TODO(gri) If we needed to take into account the receiver's
+ // addressability, should we report the type &(x.typ) instead?
+ check.recordSelection(e, MethodVal, x.typ, obj, index, indirect)
+
+ if debug {
+ // Verify that LookupFieldOrMethod and MethodSet.Lookup agree.
+ typ := x.typ
+ if x.mode == variable {
+ // If typ is not an (unnamed) pointer or an interface,
+ // use *typ instead, because the method set of *typ
+ // includes the methods of typ.
+ // Variables are addressable, so we can always take their
+ // address.
+ if _, ok := typ.(*Pointer); !ok && !IsInterface(typ) {
+ typ = &Pointer{base: typ}
+ }
+ }
+ // If we created a synthetic pointer type above, we will throw
+ // away the method set computed here after use.
+ // TODO(gri) Method set computation should probably always compute
+ // both, the value and the pointer receiver method set and represent
+ // them in a single structure.
+ // TODO(gri) Consider also using a method set cache for the lifetime
+ // of checker once we rely on MethodSet lookup instead of individual
+ // lookup.
+ mset := NewMethodSet(typ)
+ if m := mset.Lookup(check.pkg, sel); m == nil || m.obj != obj {
+ check.dump("%s: (%s).%v -> %s", e.Pos(), typ, obj.name, m)
+ check.dump("%s\n", mset)
+ panic("method sets and lookup don't agree")
+ }
+ }
+
+ x.mode = value
+
+ // remove receiver
+ sig := *obj.typ.(*Signature)
+ sig.recv = nil
+ x.typ = &sig
+
+ check.addDeclDep(obj)
+
+ default:
+ unreachable()
+ }
+ }
+
+ // everything went well
+ x.expr = e
+ return
+
+Error:
+ x.mode = invalid
+ x.expr = e
+}
diff --git a/go/types/check.go b/go/types/check.go
new file mode 100644
index 0000000..964d2bd
--- /dev/null
+++ b/go/types/check.go
@@ -0,0 +1,364 @@
+// 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 file implements the Check function, which drives type-checking.
+
+package types
+
+import (
+ "go/ast"
+ "go/token"
+
+ "golang.org/x/tools/go/exact"
+)
+
+// debugging/development support
+const (
+ debug = false // leave on during development
+ trace = false // turn on for detailed type resolution traces
+)
+
+// If Strict is set, the type-checker enforces additional
+// rules not specified by the Go 1 spec, but which will
+// catch guaranteed run-time errors if the respective
+// code is executed. In other words, programs passing in
+// Strict mode are Go 1 compliant, but not all Go 1 programs
+// will pass in Strict mode. The additional rules are:
+//
+// - A type assertion x.(T) where T is an interface type
+// is invalid if any (statically known) method that exists
+// for both x and T have different signatures.
+//
+const strict = false
+
+// exprInfo stores information about an untyped expression.
+type exprInfo struct {
+ isLhs bool // expression is lhs operand of a shift with delayed type-check
+ mode operandMode
+ typ *Basic
+ val exact.Value // constant value; or nil (if not a constant)
+}
+
+// funcInfo stores the information required for type-checking a function.
+type funcInfo struct {
+ name string // for debugging/tracing only
+ decl *declInfo // for cycle detection
+ sig *Signature
+ body *ast.BlockStmt
+}
+
+// A context represents the context within which an object is type-checked.
+type context struct {
+ decl *declInfo // package-level declaration whose init expression/function body is checked
+ scope *Scope // top-most scope for lookups
+ iota exact.Value // value of iota in a constant declaration; nil otherwise
+ sig *Signature // function signature if inside a function; nil otherwise
+ hasLabel bool // set if a function makes use of labels (only ~1% of functions); unused outside functions
+ hasCallOrRecv bool // set if an expression contains a function call or channel receive operation
+}
+
+// A Checker maintains the state of the type checker.
+// It must be created with NewChecker.
+type Checker struct {
+ // package information
+ // (initialized by NewChecker, valid for the life-time of checker)
+ conf *Config
+ fset *token.FileSet
+ pkg *Package
+ *Info
+ objMap map[Object]*declInfo // maps package-level object to declaration info
+
+ // information collected during type-checking of a set of package files
+ // (initialized by Files, valid only for the duration of check.Files;
+ // maps and lists are allocated on demand)
+ files []*ast.File // package files
+ unusedDotImports map[*Scope]map[*Package]token.Pos // positions of unused dot-imported packages for each file scope
+
+ firstErr error // first error encountered
+ methods map[string][]*Func // maps type names to associated methods
+ untyped map[ast.Expr]exprInfo // map of expressions without final type
+ funcs []funcInfo // list of functions to type-check
+ delayed []func() // delayed checks requiring fully setup types
+
+ // context within which the current object is type-checked
+ // (valid only for the duration of type-checking a specific object)
+ context
+ pos token.Pos // if valid, identifiers are looked up as if at position pos (used by Eval)
+
+ // debugging
+ indent int // indentation for tracing
+}
+
+// addUnusedImport adds the position of a dot-imported package
+// pkg to the map of dot imports for the given file scope.
+func (check *Checker) addUnusedDotImport(scope *Scope, pkg *Package, pos token.Pos) {
+ mm := check.unusedDotImports
+ if mm == nil {
+ mm = make(map[*Scope]map[*Package]token.Pos)
+ check.unusedDotImports = mm
+ }
+ m := mm[scope]
+ if m == nil {
+ m = make(map[*Package]token.Pos)
+ mm[scope] = m
+ }
+ m[pkg] = pos
+}
+
+// addDeclDep adds the dependency edge (check.decl -> to) if check.decl exists
+func (check *Checker) addDeclDep(to Object) {
+ from := check.decl
+ if from == nil {
+ return // not in a package-level init expression
+ }
+ if _, found := check.objMap[to]; !found {
+ return // to is not a package-level object
+ }
+ from.addDep(to)
+}
+
+func (check *Checker) assocMethod(tname string, meth *Func) {
+ m := check.methods
+ if m == nil {
+ m = make(map[string][]*Func)
+ check.methods = m
+ }
+ m[tname] = append(m[tname], meth)
+}
+
+func (check *Checker) rememberUntyped(e ast.Expr, lhs bool, mode operandMode, typ *Basic, val exact.Value) {
+ m := check.untyped
+ if m == nil {
+ m = make(map[ast.Expr]exprInfo)
+ check.untyped = m
+ }
+ m[e] = exprInfo{lhs, mode, typ, val}
+}
+
+func (check *Checker) later(name string, decl *declInfo, sig *Signature, body *ast.BlockStmt) {
+ check.funcs = append(check.funcs, funcInfo{name, decl, sig, body})
+}
+
+func (check *Checker) delay(f func()) {
+ check.delayed = append(check.delayed, f)
+}
+
+// NewChecker returns a new Checker instance for a given package.
+// Package files may be added incrementally via checker.Files.
+func NewChecker(conf *Config, fset *token.FileSet, pkg *Package, info *Info) *Checker {
+ // make sure we have a configuration
+ if conf == nil {
+ conf = new(Config)
+ }
+
+ // make sure we have a package canonicalization map
+ if conf.Packages == nil {
+ conf.Packages = make(map[string]*Package)
+ }
+
+ // make sure we have an info struct
+ if info == nil {
+ info = new(Info)
+ }
+
+ return &Checker{
+ conf: conf,
+ fset: fset,
+ pkg: pkg,
+ Info: info,
+ objMap: make(map[Object]*declInfo),
+ }
+}
+
+// initFiles initializes the files-specific portion of checker.
+// The provided files must all belong to the same package.
+func (check *Checker) initFiles(files []*ast.File) {
+ // start with a clean slate (check.Files may be called multiple times)
+ check.files = nil
+ check.unusedDotImports = nil
+
+ check.firstErr = nil
+ check.methods = nil
+ check.untyped = nil
+ check.funcs = nil
+ check.delayed = nil
+
+ // determine package name and collect valid files
+ pkg := check.pkg
+ for _, file := range files {
+ switch name := file.Name.Name; pkg.name {
+ case "":
+ if name != "_" {
+ pkg.name = name
+ } else {
+ check.errorf(file.Name.Pos(), "invalid package name _")
+ }
+ fallthrough
+
+ case name:
+ check.files = append(check.files, file)
+
+ default:
+ check.errorf(file.Package, "package %s; expected %s", name, pkg.name)
+ // ignore this file
+ }
+ }
+}
+
+// A bailout panic is used for early termination.
+type bailout struct{}
+
+func (check *Checker) handleBailout(err *error) {
+ switch p := recover().(type) {
+ case nil, bailout:
+ // normal return or early exit
+ *err = check.firstErr
+ default:
+ // re-panic
+ panic(p)
+ }
+}
+
+// Files checks the provided files as part of the checker's package.
+func (check *Checker) Files(files []*ast.File) (err error) {
+ defer check.handleBailout(&err)
+
+ check.initFiles(files)
+
+ check.collectObjects()
+
+ check.packageObjects(check.resolveOrder())
+
+ check.functionBodies()
+
+ check.initOrder()
+
+ if !check.conf.DisableUnusedImportCheck {
+ check.unusedImports()
+ }
+
+ // perform delayed checks
+ for _, f := range check.delayed {
+ f()
+ }
+
+ check.recordUntyped()
+
+ check.pkg.complete = true
+ return
+}
+
+func (check *Checker) recordUntyped() {
+ if !debug && check.Types == nil {
+ return // nothing to do
+ }
+
+ for x, info := range check.untyped {
+ if debug && isTyped(info.typ) {
+ check.dump("%s: %s (type %s) is typed", x.Pos(), x, info.typ)
+ unreachable()
+ }
+ check.recordTypeAndValue(x, info.mode, info.typ, info.val)
+ }
+}
+
+func (check *Checker) recordTypeAndValue(x ast.Expr, mode operandMode, typ Type, val exact.Value) {
+ assert(x != nil)
+ assert(typ != nil)
+ if mode == invalid {
+ return // omit
+ }
+ assert(typ != nil)
+ if mode == constant {
+ assert(val != nil)
+ assert(typ == Typ[Invalid] || isConstType(typ))
+ }
+ if m := check.Types; m != nil {
+ m[x] = TypeAndValue{mode, typ, val}
+ }
+}
+
+func (check *Checker) recordBuiltinType(f ast.Expr, sig *Signature) {
+ // f must be a (possibly parenthesized) identifier denoting a built-in
+ // (built-ins in package unsafe always produce a constant result and
+ // we don't record their signatures, so we don't see qualified idents
+ // here): record the signature for f and possible children.
+ for {
+ check.recordTypeAndValue(f, builtin, sig, nil)
+ switch p := f.(type) {
+ case *ast.Ident:
+ return // we're done
+ case *ast.ParenExpr:
+ f = p.X
+ default:
+ unreachable()
+ }
+ }
+}
+
+func (check *Checker) recordCommaOkTypes(x ast.Expr, a [2]Type) {
+ assert(x != nil)
+ if a[0] == nil || a[1] == nil {
+ return
+ }
+ assert(isTyped(a[0]) && isTyped(a[1]) && isBoolean(a[1]))
+ if m := check.Types; m != nil {
+ for {
+ tv := m[x]
+ assert(tv.Type != nil) // should have been recorded already
+ pos := x.Pos()
+ tv.Type = NewTuple(
+ NewVar(pos, check.pkg, "", a[0]),
+ NewVar(pos, check.pkg, "", a[1]),
+ )
+ m[x] = tv
+ // if x is a parenthesized expression (p.X), update p.X
+ p, _ := x.(*ast.ParenExpr)
+ if p == nil {
+ break
+ }
+ x = p.X
+ }
+ }
+}
+
+func (check *Checker) recordDef(id *ast.Ident, obj Object) {
+ assert(id != nil)
+ if m := check.Defs; m != nil {
+ m[id] = obj
+ }
+}
+
+func (check *Checker) recordUse(id *ast.Ident, obj Object) {
+ assert(id != nil)
+ assert(obj != nil)
+ if m := check.Uses; m != nil {
+ m[id] = obj
+ }
+}
+
+func (check *Checker) recordImplicit(node ast.Node, obj Object) {
+ assert(node != nil)
+ assert(obj != nil)
+ if m := check.Implicits; m != nil {
+ m[node] = obj
+ }
+}
+
+func (check *Checker) recordSelection(x *ast.SelectorExpr, kind SelectionKind, recv Type, obj Object, index []int, indirect bool) {
+ assert(obj != nil && (recv == nil || len(index) > 0))
+ check.recordUse(x.Sel, obj)
+ // TODO(gri) Should we also call recordTypeAndValue?
+ if m := check.Selections; m != nil {
+ m[x] = &Selection{kind, recv, obj, index, indirect}
+ }
+}
+
+func (check *Checker) recordScope(node ast.Node, scope *Scope) {
+ assert(node != nil)
+ assert(scope != nil)
+ if m := check.Scopes; m != nil {
+ m[node] = scope
+ }
+}
diff --git a/go/types/check_test.go b/go/types/check_test.go
new file mode 100644
index 0000000..fd4dadb
--- /dev/null
+++ b/go/types/check_test.go
@@ -0,0 +1,303 @@
+// 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 file implements a typechecker test harness. The packages specified
+// in tests are typechecked. Error messages reported by the typechecker are
+// compared against the error messages expected in the test files.
+//
+// Expected errors are indicated in the test files by putting a comment
+// of the form /* ERROR "rx" */ immediately following an offending token.
+// The harness will verify that an error matching the regular expression
+// rx is reported at that source position. Consecutive comments may be
+// used to indicate multiple errors for the same token position.
+//
+// For instance, the following test file indicates that a "not declared"
+// error should be reported for the undeclared variable x:
+//
+// package p
+// func f() {
+// _ = x /* ERROR "not declared" */ + 1
+// }
+
+package types_test
+
+import (
+ "flag"
+ "go/ast"
+ "go/parser"
+ "go/scanner"
+ "go/token"
+ "io/ioutil"
+ "regexp"
+ "runtime"
+ "strings"
+ "testing"
+
+ _ "golang.org/x/tools/go/gcimporter"
+ . "golang.org/x/tools/go/types"
+)
+
+var (
+ listErrors = flag.Bool("list", false, "list errors")
+ testFiles = flag.String("files", "", "space-separated list of test files")
+)
+
+// The test filenames do not end in .go so that they are invisible
+// to gofmt since they contain comments that must not change their
+// positions relative to surrounding tokens.
+
+// Each tests entry is list of files belonging to the same package.
+var tests = []struct {
+ files string // blank-separated list of file names
+ cond func() bool // condition under which the test should be run; nil means always
+}{
+ {"testdata/errors.src", nil},
+ {"testdata/importdecl0a.src testdata/importdecl0b.src", nil},
+ {"testdata/importdecl1a.src testdata/importdecl1b.src", nil},
+ {"testdata/cycles.src", nil},
+ {"testdata/cycles1.src", nil},
+ {"testdata/cycles2.src", nil},
+ {"testdata/cycles3.src", nil},
+ {"testdata/cycles4.src", nil},
+ {"testdata/init0.src", nil},
+ {"testdata/init1.src", nil},
+ {"testdata/init2.src", nil},
+ {"testdata/decls0.src", nil},
+ {"testdata/decls1.src", nil},
+ {"testdata/decls2a.src testdata/decls2b.src", nil},
+ {"testdata/decls3.src", nil},
+ {"testdata/const0.src", nil},
+ {"testdata/const1.src", nil},
+ {"testdata/constdecl.src", notGo1_4}, // Go 1.4 parser doesn't report certain errors
+ {"testdata/vardecl.src", notGo1_4}, // Go 1.4 parser doesn't report certain errors
+ {"testdata/expr0.src", nil},
+ {"testdata/expr1.src", nil},
+ {"testdata/expr2.src", nil},
+ {"testdata/expr3.src", notGo1_4}, // Go 1.4 parser doesn't permit omitting key type in map literals
+ {"testdata/methodsets.src", nil},
+ {"testdata/shifts.src", nil},
+ {"testdata/builtins.src", nil},
+ {"testdata/conversions.src", nil},
+ {"testdata/stmt0.src", nil},
+ {"testdata/stmt1.src", nil},
+ {"testdata/gotos.src", nil},
+ {"testdata/labels.src", nil},
+ {"testdata/issues.src", nil},
+ {"testdata/blank.src", nil},
+}
+
+func notGo1_4() bool {
+ return !strings.HasPrefix(runtime.Version(), "go1.4")
+}
+
+var fset = token.NewFileSet()
+
+// Positioned errors are of the form filename:line:column: message .
+var posMsgRx = regexp.MustCompile(`^(.*:[0-9]+:[0-9]+): *(.*)`)
+
+// splitError splits an error's error message into a position string
+// and the actual error message. If there's no position information,
+// pos is the empty string, and msg is the entire error message.
+//
+func splitError(err error) (pos, msg string) {
+ msg = err.Error()
+ if m := posMsgRx.FindStringSubmatch(msg); len(m) == 3 {
+ pos = m[1]
+ msg = m[2]
+ }
+ return
+}
+
+func parseFiles(t *testing.T, filenames string) ([]*ast.File, []error) {
+ var files []*ast.File
+ var errlist []error
+ for _, filename := range strings.Split(filenames, " ") {
+ file, err := parser.ParseFile(fset, filename, nil, parser.AllErrors)
+ if file == nil {
+ t.Fatalf("%s: %s", filename, err)
+ }
+ files = append(files, file)
+ if err != nil {
+ if list, _ := err.(scanner.ErrorList); len(list) > 0 {
+ for _, err := range list {
+ errlist = append(errlist, err)
+ }
+ } else {
+ errlist = append(errlist, err)
+ }
+ }
+ }
+ return files, errlist
+}
+
+// ERROR comments must start with text `ERROR "rx"` or `ERROR rx` where
+// rx is a regular expression that matches the expected error message.
+// Space around "rx" or rx is ignored. Use the form `ERROR HERE "rx"`
+// for error messages that are located immediately after rather than
+// at a token's position.
+//
+var errRx = regexp.MustCompile(`^ *ERROR *(HERE)? *"?([^"]*)"?`)
+
+// errMap collects the regular expressions of ERROR comments found
+// in files and returns them as a map of error positions to error messages.
+//
+func errMap(t *testing.T, testname string, files []*ast.File) map[string][]string {
+ // map of position strings to lists of error message patterns
+ errmap := make(map[string][]string)
+
+ for _, file := range files {
+ filename := fset.Position(file.Package).Filename
+ src, err := ioutil.ReadFile(filename)
+ if err != nil {
+ t.Fatalf("%s: could not read %s", testname, filename)
+ }
+
+ var s scanner.Scanner
+ s.Init(fset.AddFile(filename, -1, len(src)), src, nil, scanner.ScanComments)
+ var prev token.Pos // position of last non-comment, non-semicolon token
+ var here token.Pos // position immediately after the token at position prev
+
+ scanFile:
+ for {
+ pos, tok, lit := s.Scan()
+ switch tok {
+ case token.EOF:
+ break scanFile
+ case token.COMMENT:
+ if lit[1] == '*' {
+ lit = lit[:len(lit)-2] // strip trailing */
+ }
+ if s := errRx.FindStringSubmatch(lit[2:]); len(s) == 3 {
+ pos := prev
+ if s[1] == "HERE" {
+ pos = here
+ }
+ p := fset.Position(pos).String()
+ errmap[p] = append(errmap[p], strings.TrimSpace(s[2]))
+ }
+ case token.SEMICOLON:
+ // ignore automatically inserted semicolon
+ if lit == "\n" {
+ continue scanFile
+ }
+ fallthrough
+ default:
+ prev = pos
+ var l int // token length
+ if tok.IsLiteral() {
+ l = len(lit)
+ } else {
+ l = len(tok.String())
+ }
+ here = prev + token.Pos(l)
+ }
+ }
+ }
+
+ return errmap
+}
+
+func eliminate(t *testing.T, errmap map[string][]string, errlist []error) {
+ for _, err := range errlist {
+ pos, gotMsg := splitError(err)
+ list := errmap[pos]
+ index := -1 // list index of matching message, if any
+ // we expect one of the messages in list to match the error at pos
+ for i, wantRx := range list {
+ rx, err := regexp.Compile(wantRx)
+ if err != nil {
+ t.Errorf("%s: %v", pos, err)
+ continue
+ }
+ if rx.MatchString(gotMsg) {
+ index = i
+ break
+ }
+ }
+ if index >= 0 {
+ // eliminate from list
+ if n := len(list) - 1; n > 0 {
+ // not the last entry - swap in last element and shorten list by 1
+ list[index] = list[n]
+ errmap[pos] = list[:n]
+ } else {
+ // last entry - remove list from map
+ delete(errmap, pos)
+ }
+ } else {
+ t.Errorf("%s: no error expected: %q", pos, gotMsg)
+ }
+ }
+}
+
+func checkFiles(t *testing.T, filenames string) {
+ // parse files and collect parser errors
+ files, errlist := parseFiles(t, filenames)
+
+ pkgName := "<no package>"
+ if len(files) > 0 {
+ pkgName = files[0].Name.Name
+ }
+
+ if *listErrors && len(errlist) > 0 {
+ t.Errorf("--- %s:", pkgName)
+ for _, err := range errlist {
+ t.Error(err)
+ }
+ }
+
+ // typecheck and collect typechecker errors
+ var conf Config
+ conf.Error = func(err error) {
+ if *listErrors {
+ t.Error(err)
+ return
+ }
+ // Ignore secondary error messages starting with "\t";
+ // they are clarifying messages for a primary error.
+ if !strings.Contains(err.Error(), ": \t") {
+ errlist = append(errlist, err)
+ }
+ }
+ conf.Check(pkgName, fset, files, nil)
+
+ if *listErrors {
+ return
+ }
+
+ // match and eliminate errors;
+ // we are expecting the following errors
+ errmap := errMap(t, pkgName, files)
+ eliminate(t, errmap, errlist)
+
+ // there should be no expected errors left
+ if len(errmap) > 0 {
+ t.Errorf("--- %s: %d source positions with expected (but not reported) errors:", pkgName, len(errmap))
+ for pos, list := range errmap {
+ for _, rx := range list {
+ t.Errorf("%s: %q", pos, rx)
+ }
+ }
+ }
+}
+
+func TestCheck(t *testing.T) {
+ skipSpecialPlatforms(t)
+
+ // Declare builtins for testing.
+ DefPredeclaredTestFuncs()
+
+ // If explicit test files are specified, only check those.
+ if *testFiles != "" {
+ checkFiles(t, *testFiles)
+ return
+ }
+
+ // Otherwise, run all the tests.
+ for _, test := range tests {
+ if test.cond == nil || test.cond() {
+ checkFiles(t, test.files)
+ }
+ }
+}
diff --git a/go/types/conversions.go b/go/types/conversions.go
new file mode 100644
index 0000000..6e279ca
--- /dev/null
+++ b/go/types/conversions.go
@@ -0,0 +1,146 @@
+// 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 implements typechecking of conversions.
+
+package types
+
+import "golang.org/x/tools/go/exact"
+
+// Conversion type-checks the conversion T(x).
+// The result is in x.
+func (check *Checker) conversion(x *operand, T Type) {
+ constArg := x.mode == constant
+
+ var ok bool
+ switch {
+ case constArg && isConstType(T):
+ // constant conversion
+ switch t := T.Underlying().(*Basic); {
+ case representableConst(x.val, check.conf, t.kind, &x.val):
+ ok = true
+ case isInteger(x.typ) && isString(t):
+ codepoint := int64(-1)
+ if i, ok := exact.Int64Val(x.val); ok {
+ codepoint = i
+ }
+ // If codepoint < 0 the absolute value is too large (or unknown) for
+ // conversion. This is the same as converting any other out-of-range
+ // value - let string(codepoint) do the work.
+ x.val = exact.MakeString(string(codepoint))
+ ok = true
+ }
+ case x.convertibleTo(check.conf, T):
+ // non-constant conversion
+ x.mode = value
+ ok = true
+ }
+
+ if !ok {
+ check.errorf(x.pos(), "cannot convert %s to %s", x, T)
+ x.mode = invalid
+ return
+ }
+
+ // The conversion argument types are final. For untyped values the
+ // conversion provides the type, per the spec: "A constant may be
+ // given a type explicitly by a constant declaration or conversion,...".
+ final := x.typ
+ if isUntyped(x.typ) {
+ final = T
+ // - For conversions to interfaces, use the argument's default type.
+ // - For conversions of untyped constants to non-constant types, also
+ // use the default type (e.g., []byte("foo") should report string
+ // not []byte as type for the constant "foo").
+ // - Keep untyped nil for untyped nil arguments.
+ if IsInterface(T) || constArg && !isConstType(T) {
+ final = defaultType(x.typ)
+ }
+ check.updateExprType(x.expr, final, true)
+ }
+
+ x.typ = T
+}
+
+func (x *operand) convertibleTo(conf *Config, T Type) bool {
+ // "x is assignable to T"
+ if x.assignableTo(conf, T) {
+ return true
+ }
+
+ // "x's type and T have identical underlying types"
+ V := x.typ
+ Vu := V.Underlying()
+ Tu := T.Underlying()
+ if Identical(Vu, Tu) {
+ return true
+ }
+
+ // "x's type and T are unnamed pointer types and their pointer base types have identical underlying types"
+ if V, ok := V.(*Pointer); ok {
+ if T, ok := T.(*Pointer); ok {
+ if Identical(V.base.Underlying(), T.base.Underlying()) {
+ return true
+ }
+ }
+ }
+
+ // "x's type and T are both integer or floating point types"
+ if (isInteger(V) || isFloat(V)) && (isInteger(T) || isFloat(T)) {
+ return true
+ }
+
+ // "x's type and T are both complex types"
+ if isComplex(V) && isComplex(T) {
+ return true
+ }
+
+ // "x is an integer or a slice of bytes or runes and T is a string type"
+ if (isInteger(V) || isBytesOrRunes(Vu)) && isString(T) {
+ return true
+ }
+
+ // "x is a string and T is a slice of bytes or runes"
+ if isString(V) && isBytesOrRunes(Tu) {
+ return true
+ }
+
+ // package unsafe:
+ // "any pointer or value of underlying type uintptr can be converted into a unsafe.Pointer"
+ if (isPointer(Vu) || isUintptr(Vu)) && isUnsafePointer(T) {
+ return true
+ }
+ // "and vice versa"
+ if isUnsafePointer(V) && (isPointer(Tu) || isUintptr(Tu)) {
+ return true
+ }
+
+ return false
+}
+
+func isUintptr(typ Type) bool {
+ t, ok := typ.Underlying().(*Basic)
+ return ok && t.kind == Uintptr
+}
+
+func isUnsafePointer(typ Type) bool {
+ // TODO(gri): Is this (typ.Underlying() instead of just typ) correct?
+ // The spec does not say so, but gc claims it is. See also
+ // issue 6326.
+ t, ok := typ.Underlying().(*Basic)
+ return ok && t.kind == UnsafePointer
+}
+
+func isPointer(typ Type) bool {
+ _, ok := typ.Underlying().(*Pointer)
+ return ok
+}
+
+func isBytesOrRunes(typ Type) bool {
+ if s, ok := typ.(*Slice); ok {
+ t, ok := s.elem.Underlying().(*Basic)
+ return ok && (t.kind == Byte || t.kind == Rune)
+ }
+ return false
+}
diff --git a/go/types/decl.go b/go/types/decl.go
new file mode 100644
index 0000000..9eba85c
--- /dev/null
+++ b/go/types/decl.go
@@ -0,0 +1,431 @@
+// 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 types
+
+import (
+ "go/ast"
+ "go/token"
+
+ "golang.org/x/tools/go/exact"
+)
+
+func (check *Checker) reportAltDecl(obj Object) {
+ if pos := obj.Pos(); pos.IsValid() {
+ // We use "other" rather than "previous" here because
+ // the first declaration seen may not be textually
+ // earlier in the source.
+ check.errorf(pos, "\tother declaration of %s", obj.Name()) // secondary error, \t indented
+ }
+}
+
+func (check *Checker) declare(scope *Scope, id *ast.Ident, obj Object, pos token.Pos) {
+ // spec: "The blank identifier, represented by the underscore
+ // character _, may be used in a declaration like any other
+ // identifier but the declaration does not introduce a new
+ // binding."
+ if obj.Name() != "_" {
+ if alt := scope.Insert(obj); alt != nil {
+ check.errorf(obj.Pos(), "%s redeclared in this block", obj.Name())
+ check.reportAltDecl(alt)
+ return
+ }
+ obj.setScopePos(pos)
+ }
+ if id != nil {
+ check.recordDef(id, obj)
+ }
+}
+
+// objDecl type-checks the declaration of obj in its respective (file) context.
+// See check.typ for the details on def and path.
+func (check *Checker) objDecl(obj Object, def *Named, path []*TypeName) {
+ if obj.Type() != nil {
+ return // already checked - nothing to do
+ }
+
+ if trace {
+ check.trace(obj.Pos(), "-- declaring %s", obj.Name())
+ check.indent++
+ defer func() {
+ check.indent--
+ check.trace(obj.Pos(), "=> %s", obj)
+ }()
+ }
+
+ d := check.objMap[obj]
+ if d == nil {
+ check.dump("%s: %s should have been declared", obj.Pos(), obj.Name())
+ unreachable()
+ }
+
+ // save/restore current context and setup object context
+ defer func(ctxt context) {
+ check.context = ctxt
+ }(check.context)
+ check.context = context{
+ scope: d.file,
+ }
+
+ // Const and var declarations must not have initialization
+ // cycles. We track them by remembering the current declaration
+ // in check.decl. Initialization expressions depending on other
+ // consts, vars, or functions, add dependencies to the current
+ // check.decl.
+ switch obj := obj.(type) {
+ case *Const:
+ check.decl = d // new package-level const decl
+ check.constDecl(obj, d.typ, d.init)
+ case *Var:
+ check.decl = d // new package-level var decl
+ check.varDecl(obj, d.lhs, d.typ, d.init)
+ case *TypeName:
+ // invalid recursive types are detected via path
+ check.typeDecl(obj, d.typ, def, path)
+ case *Func:
+ // functions may be recursive - no need to track dependencies
+ check.funcDecl(obj, d)
+ default:
+ unreachable()
+ }
+}
+
+func (check *Checker) constDecl(obj *Const, typ, init ast.Expr) {
+ assert(obj.typ == nil)
+
+ if obj.visited {
+ obj.typ = Typ[Invalid]
+ return
+ }
+ obj.visited = true
+
+ // use the correct value of iota
+ assert(check.iota == nil)
+ check.iota = obj.val
+ defer func() { check.iota = nil }()
+
+ // provide valid constant value under all circumstances
+ obj.val = exact.MakeUnknown()
+
+ // determine type, if any
+ if typ != nil {
+ t := check.typ(typ)
+ if !isConstType(t) {
+ check.errorf(typ.Pos(), "invalid constant type %s", t)
+ obj.typ = Typ[Invalid]
+ return
+ }
+ obj.typ = t
+ }
+
+ // check initialization
+ var x operand
+ if init != nil {
+ check.expr(&x, init)
+ }
+ check.initConst(obj, &x)
+}
+
+func (check *Checker) varDecl(obj *Var, lhs []*Var, typ, init ast.Expr) {
+ assert(obj.typ == nil)
+
+ if obj.visited {
+ obj.typ = Typ[Invalid]
+ return
+ }
+ obj.visited = true
+
+ // var declarations cannot use iota
+ assert(check.iota == nil)
+
+ // determine type, if any
+ if typ != nil {
+ obj.typ = check.typ(typ)
+ }
+
+ // check initialization
+ if init == nil {
+ if typ == nil {
+ // error reported before by arityMatch
+ obj.typ = Typ[Invalid]
+ }
+ return
+ }
+
+ if lhs == nil || len(lhs) == 1 {
+ assert(lhs == nil || lhs[0] == obj)
+ var x operand
+ check.expr(&x, init)
+ check.initVar(obj, &x, false)
+ return
+ }
+
+ if debug {
+ // obj must be one of lhs
+ found := false
+ for _, lhs := range lhs {
+ if obj == lhs {
+ found = true
+ break
+ }
+ }
+ if !found {
+ panic("inconsistent lhs")
+ }
+ }
+ check.initVars(lhs, []ast.Expr{init}, token.NoPos)
+}
+
+// underlying returns the underlying type of typ; possibly by following
+// forward chains of named types. Such chains only exist while named types
+// are incomplete.
+func underlying(typ Type) Type {
+ for {
+ n, _ := typ.(*Named)
+ if n == nil {
+ break
+ }
+ typ = n.underlying
+ }
+ return typ
+}
+
+func (n *Named) setUnderlying(typ Type) {
+ if n != nil {
+ n.underlying = typ
+ }
+}
+
+func (check *Checker) typeDecl(obj *TypeName, typ ast.Expr, def *Named, path []*TypeName) {
+ assert(obj.typ == nil)
+
+ // type declarations cannot use iota
+ assert(check.iota == nil)
+
+ named := &Named{obj: obj}
+ def.setUnderlying(named)
+ obj.typ = named // make sure recursive type declarations terminate
+
+ // determine underlying type of named
+ check.typExpr(typ, named, append(path, obj))
+
+ // The underlying type of named may be itself a named type that is
+ // incomplete:
+ //
+ // type (
+ // A B
+ // B *C
+ // C A
+ // )
+ //
+ // The type of C is the (named) type of A which is incomplete,
+ // and which has as its underlying type the named type B.
+ // Determine the (final, unnamed) underlying type by resolving
+ // any forward chain (they always end in an unnamed type).
+ named.underlying = underlying(named.underlying)
+
+ // check and add associated methods
+ // TODO(gri) It's easy to create pathological cases where the
+ // current approach is incorrect: In general we need to know
+ // and add all methods _before_ type-checking the type.
+ // See http://play.golang.org/p/WMpE0q2wK8
+ check.addMethodDecls(obj)
+}
+
+func (check *Checker) addMethodDecls(obj *TypeName) {
+ // get associated methods
+ methods := check.methods[obj.name]
+ if len(methods) == 0 {
+ return // no methods
+ }
+ delete(check.methods, obj.name)
+
+ // use an objset to check for name conflicts
+ var mset objset
+
+ // spec: "If the base type is a struct type, the non-blank method
+ // and field names must be distinct."
+ base := obj.typ.(*Named)
+ if t, _ := base.underlying.(*Struct); t != nil {
+ for _, fld := range t.fields {
+ if fld.name != "_" {
+ assert(mset.insert(fld) == nil)
+ }
+ }
+ }
+
+ // Checker.Files may be called multiple times; additional package files
+ // may add methods to already type-checked types. Add pre-existing methods
+ // so that we can detect redeclarations.
+ for _, m := range base.methods {
+ assert(m.name != "_")
+ assert(mset.insert(m) == nil)
+ }
+
+ // type-check methods
+ for _, m := range methods {
+ // spec: "For a base type, the non-blank names of methods bound
+ // to it must be unique."
+ if m.name != "_" {
+ if alt := mset.insert(m); alt != nil {
+ switch alt.(type) {
+ case *Var:
+ check.errorf(m.pos, "field and method with the same name %s", m.name)
+ case *Func:
+ check.errorf(m.pos, "method %s already declared for %s", m.name, base)
+ default:
+ unreachable()
+ }
+ check.reportAltDecl(alt)
+ continue
+ }
+ }
+ check.objDecl(m, nil, nil)
+ // methods with blank _ names cannot be found - don't keep them
+ if m.name != "_" {
+ base.methods = append(base.methods, m)
+ }
+ }
+}
+
+func (check *Checker) funcDecl(obj *Func, decl *declInfo) {
+ assert(obj.typ == nil)
+
+ // func declarations cannot use iota
+ assert(check.iota == nil)
+
+ sig := new(Signature)
+ obj.typ = sig // guard against cycles
+ fdecl := decl.fdecl
+ check.funcType(sig, fdecl.Recv, fdecl.Type)
+ if sig.recv == nil && obj.name == "init" && (sig.params.Len() > 0 || sig.results.Len() > 0) {
+ check.errorf(fdecl.Pos(), "func init must have no arguments and no return values")
+ // ok to continue
+ }
+
+ // function body must be type-checked after global declarations
+ // (functions implemented elsewhere have no body)
+ if !check.conf.IgnoreFuncBodies && fdecl.Body != nil {
+ check.later(obj.name, decl, sig, fdecl.Body)
+ }
+}
+
+func (check *Checker) declStmt(decl ast.Decl) {
+ pkg := check.pkg
+
+ switch d := decl.(type) {
+ case *ast.BadDecl:
+ // ignore
+
+ case *ast.GenDecl:
+ var last *ast.ValueSpec // last ValueSpec with type or init exprs seen
+ for iota, spec := range d.Specs {
+ switch s := spec.(type) {
+ case *ast.ValueSpec:
+ switch d.Tok {
+ case token.CONST:
+ // determine which init exprs to use
+ switch {
+ case s.Type != nil || len(s.Values) > 0:
+ last = s
+ case last == nil:
+ last = new(ast.ValueSpec) // make sure last exists
+ }
+
+ // declare all constants
+ lhs := make([]*Const, len(s.Names))
+ for i, name := range s.Names {
+ obj := NewConst(name.Pos(), pkg, name.Name, nil, exact.MakeInt64(int64(iota)))
+ lhs[i] = obj
+
+ var init ast.Expr
+ if i < len(last.Values) {
+ init = last.Values[i]
+ }
+
+ check.constDecl(obj, last.Type, init)
+ }
+
+ check.arityMatch(s, last)
+
+ // spec: "The scope of a constant or variable identifier declared
+ // inside a function begins at the end of the ConstSpec or VarSpec
+ // (ShortVarDecl for short variable declarations) and ends at the
+ // end of the innermost containing block."
+ scopePos := s.End()
+ for i, name := range s.Names {
+ check.declare(check.scope, name, lhs[i], scopePos)
+ }
+
+ case token.VAR:
+ lhs0 := make([]*Var, len(s.Names))
+ for i, name := range s.Names {
+ lhs0[i] = NewVar(name.Pos(), pkg, name.Name, nil)
+ }
+
+ // initialize all variables
+ for i, obj := range lhs0 {
+ var lhs []*Var
+ var init ast.Expr
+ switch len(s.Values) {
+ case len(s.Names):
+ // lhs and rhs match
+ init = s.Values[i]
+ case 1:
+ // rhs is expected to be a multi-valued expression
+ lhs = lhs0
+ init = s.Values[0]
+ default:
+ if i < len(s.Values) {
+ init = s.Values[i]
+ }
+ }
+ check.varDecl(obj, lhs, s.Type, init)
+ if len(s.Values) == 1 {
+ // If we have a single lhs variable we are done either way.
+ // If we have a single rhs expression, it must be a multi-
+ // valued expression, in which case handling the first lhs
+ // variable will cause all lhs variables to have a type
+ // assigned, and we are done as well.
+ if debug {
+ for _, obj := range lhs0 {
+ assert(obj.typ != nil)
+ }
+ }
+ break
+ }
+ }
+
+ check.arityMatch(s, nil)
+
+ // declare all variables
+ // (only at this point are the variable scopes (parents) set)
+ scopePos := s.End() // see constant declarations
+ for i, name := range s.Names {
+ // see constant declarations
+ check.declare(check.scope, name, lhs0[i], scopePos)
+ }
+
+ default:
+ check.invalidAST(s.Pos(), "invalid token %s", d.Tok)
+ }
+
+ case *ast.TypeSpec:
+ obj := NewTypeName(s.Name.Pos(), pkg, s.Name.Name, nil)
+ // spec: "The scope of a type identifier declared inside a function
+ // begins at the identifier in the TypeSpec and ends at the end of
+ // the innermost containing block."
+ scopePos := s.Name.Pos()
+ check.declare(check.scope, s.Name, obj, scopePos)
+ check.typeDecl(obj, s.Type, nil, nil)
+
+ default:
+ check.invalidAST(s.Pos(), "const, type, or var declaration expected")
+ }
+ }
+
+ default:
+ check.invalidAST(d.Pos(), "unknown ast.Decl node %T", d)
+ }
+}
diff --git a/go/types/errors.go b/go/types/errors.go
new file mode 100644
index 0000000..0c0049b
--- /dev/null
+++ b/go/types/errors.go
@@ -0,0 +1,103 @@
+// 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 implements various error reporters.
+
+package types
+
+import (
+ "fmt"
+ "go/ast"
+ "go/token"
+ "strings"
+)
+
+func assert(p bool) {
+ if !p {
+ panic("assertion failed")
+ }
+}
+
+func unreachable() {
+ panic("unreachable")
+}
+
+func (check *Checker) qualifier(pkg *Package) string {
+ if pkg != check.pkg {
+ return pkg.path
+ }
+ return ""
+}
+
+func (check *Checker) sprintf(format string, args ...interface{}) string {
+ for i, arg := range args {
+ switch a := arg.(type) {
+ case nil:
+ arg = "<nil>"
+ case operand:
+ panic("internal error: should always pass *operand")
+ case *operand:
+ arg = operandString(a, check.qualifier)
+ case token.Pos:
+ arg = check.fset.Position(a).String()
+ case ast.Expr:
+ arg = ExprString(a)
+ case Object:
+ arg = ObjectString(a, check.qualifier)
+ case Type:
+ arg = TypeString(a, check.qualifier)
+ }
+ args[i] = arg
+ }
+ return fmt.Sprintf(format, args...)
+}
+
+func (check *Checker) trace(pos token.Pos, format string, args ...interface{}) {
+ fmt.Printf("%s:\t%s%s\n",
+ check.fset.Position(pos),
+ strings.Repeat(". ", check.indent),
+ check.sprintf(format, args...),
+ )
+}
+
+// dump is only needed for debugging
+func (check *Checker) dump(format string, args ...interface{}) {
+ fmt.Println(check.sprintf(format, args...))
+}
+
+func (check *Checker) err(pos token.Pos, msg string, soft bool) {
+ err := Error{check.fset, pos, msg, soft}
+ if check.firstErr == nil {
+ check.firstErr = err
+ }
+ f := check.conf.Error
+ if f == nil {
+ panic(bailout{}) // report only first error
+ }
+ f(err)
+}
+
+func (check *Checker) error(pos token.Pos, msg string) {
+ check.err(pos, msg, false)
+}
+
+func (check *Checker) errorf(pos token.Pos, format string, args ...interface{}) {
+ check.err(pos, check.sprintf(format, args...), false)
+}
+
+func (check *Checker) softErrorf(pos token.Pos, format string, args ...interface{}) {
+ check.err(pos, check.sprintf(format, args...), true)
+}
+
+func (check *Checker) invalidAST(pos token.Pos, format string, args ...interface{}) {
+ check.errorf(pos, "invalid AST: "+format, args...)
+}
+
+func (check *Checker) invalidArg(pos token.Pos, format string, args ...interface{}) {
+ check.errorf(pos, "invalid argument: "+format, args...)
+}
+
+func (check *Checker) invalidOp(pos token.Pos, format string, args ...interface{}) {
+ check.errorf(pos, "invalid operation: "+format, args...)
+}
diff --git a/go/types/eval.go b/go/types/eval.go
new file mode 100644
index 0000000..c09f2a3
--- /dev/null
+++ b/go/types/eval.go
@@ -0,0 +1,87 @@
+// 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 types
+
+import (
+ "fmt"
+ "go/parser"
+ "go/token"
+)
+
+// Eval returns the type and, if constant, the value for the
+// expression expr, evaluated at position pos of package pkg,
+// which must have been derived from type-checking an AST with
+// complete position information relative to the provided file
+// set.
+//
+// If the expression contains function literals, their bodies
+// are ignored (i.e., the bodies are not type-checked).
+//
+// If pkg == nil, the Universe scope is used and the provided
+// position pos is ignored. If pkg != nil, and pos is invalid,
+// the package scope is used. Otherwise, pos must belong to the
+// package.
+//
+// An error is returned if pos is not within the package or
+// if the node cannot be evaluated.
+//
+// Note: Eval should not be used instead of running Check to compute
+// types and values, but in addition to Check. Eval will re-evaluate
+// its argument each time, and it also does not know about the context
+// in which an expression is used (e.g., an assignment). Thus, top-
+// level untyped constants will return an untyped type rather then the
+// respective context-specific type.
+//
+func Eval(fset *token.FileSet, pkg *Package, pos token.Pos, expr string) (tv TypeAndValue, err error) {
+ // determine scope
+ var scope *Scope
+ if pkg == nil {
+ scope = Universe
+ pos = token.NoPos
+ } else if !pos.IsValid() {
+ scope = pkg.scope
+ } else {
+ // The package scope extent (position information) may be
+ // incorrect (files spread accross a wide range of fset
+ // positions) - ignore it and just consider its children
+ // (file scopes).
+ for _, fscope := range pkg.scope.children {
+ if scope = fscope.Innermost(pos); scope != nil {
+ break
+ }
+ }
+ if scope == nil || debug {
+ s := scope
+ for s != nil && s != pkg.scope {
+ s = s.parent
+ }
+ // s == nil || s == pkg.scope
+ if s == nil {
+ return TypeAndValue{}, fmt.Errorf("no position %s found in package %s", fset.Position(pos), pkg.name)
+ }
+ }
+ }
+
+ // parse expressions
+ // BUG(gri) In case of type-checking errors below, the type checker
+ // doesn't have the correct file set for expr. The correct
+ // solution requires a ParseExpr that uses the incoming
+ // file set fset.
+ node, err := parser.ParseExpr(expr)
+ if err != nil {
+ return TypeAndValue{}, err
+ }
+
+ // initialize checker
+ check := NewChecker(nil, fset, pkg, nil)
+ check.scope = scope
+ check.pos = pos
+ defer check.handleBailout(&err)
+
+ // evaluate node
+ var x operand
+ check.rawExpr(&x, node, nil)
+ return TypeAndValue{x.mode, x.typ, x.val}, err
+}
diff --git a/go/types/eval_test.go b/go/types/eval_test.go
new file mode 100644
index 0000000..b68b244
--- /dev/null
+++ b/go/types/eval_test.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.
+
+// This file contains tests for Eval.
+
+package types_test
+
+import (
+ "go/ast"
+ "go/parser"
+ "go/token"
+ "strings"
+ "testing"
+
+ _ "golang.org/x/tools/go/gcimporter"
+ . "golang.org/x/tools/go/types"
+)
+
+func testEval(t *testing.T, fset *token.FileSet, pkg *Package, pos token.Pos, expr string, typ Type, typStr, valStr string) {
+ gotTv, err := Eval(fset, pkg, pos, expr)
+ if err != nil {
+ t.Errorf("Eval(%q) failed: %s", expr, err)
+ return
+ }
+ if gotTv.Type == nil {
+ t.Errorf("Eval(%q) got nil type but no error", expr)
+ return
+ }
+
+ // compare types
+ if typ != nil {
+ // we have a type, check identity
+ if !Identical(gotTv.Type, typ) {
+ t.Errorf("Eval(%q) got type %s, want %s", expr, gotTv.Type, typ)
+ return
+ }
+ } else {
+ // we have a string, compare type string
+ gotStr := gotTv.Type.String()
+ if gotStr != typStr {
+ t.Errorf("Eval(%q) got type %s, want %s", expr, gotStr, typStr)
+ return
+ }
+ }
+
+ // compare values
+ gotStr := ""
+ if gotTv.Value != nil {
+ gotStr = gotTv.Value.String()
+ }
+ if gotStr != valStr {
+ t.Errorf("Eval(%q) got value %s, want %s", expr, gotStr, valStr)
+ }
+}
+
+func TestEvalBasic(t *testing.T) {
+ fset := token.NewFileSet()
+ for _, typ := range Typ[Bool : String+1] {
+ testEval(t, fset, nil, token.NoPos, typ.Name(), typ, "", "")
+ }
+}
+
+func TestEvalComposite(t *testing.T) {
+ fset := token.NewFileSet()
+ for _, test := range independentTestTypes {
+ testEval(t, fset, nil, token.NoPos, test.src, nil, test.str, "")
+ }
+}
+
+func TestEvalArith(t *testing.T) {
+ var tests = []string{
+ `true`,
+ `false == false`,
+ `12345678 + 87654321 == 99999999`,
+ `10 * 20 == 200`,
+ `(1<<1000)*2 >> 100 == 2<<900`,
+ `"foo" + "bar" == "foobar"`,
+ `"abc" <= "bcd"`,
+ `len([10]struct{}{}) == 2*5`,
+ }
+ fset := token.NewFileSet()
+ for _, test := range tests {
+ testEval(t, fset, nil, token.NoPos, test, Typ[UntypedBool], "", "true")
+ }
+}
+
+func TestEvalPos(t *testing.T) {
+ skipSpecialPlatforms(t)
+
+ // The contents of /*-style comments are of the form
+ // expr => value, type
+ // where value may be the empty string.
+ // Each expr is evaluated at the position of the comment
+ // and the result is compared with the expected value
+ // and type.
+ var sources = []string{
+ `
+ package p
+ import "fmt"
+ import m "math"
+ const c = 3.0
+ type T []int
+ func f(a int, s string) float64 {
+ fmt.Println("calling f")
+ _ = m.Pi // use package math
+ const d int = c + 1
+ var x int
+ x = a + len(s)
+ return float64(x)
+ /* true => true, untyped bool */
+ /* fmt.Println => , func(a ...interface{}) (n int, err error) */
+ /* c => 3, untyped float */
+ /* T => , p.T */
+ /* a => , int */
+ /* s => , string */
+ /* d => 4, int */
+ /* x => , int */
+ /* d/c => 1, int */
+ /* c/2 => 3/2, untyped float */
+ /* m.Pi < m.E => false, untyped bool */
+ }
+ `,
+ `
+ package p
+ /* c => 3, untyped float */
+ type T1 /* T1 => , p.T1 */ struct {}
+ var v1 /* v1 => , int */ = 42
+ func /* f1 => , func(v1 float64) */ f1(v1 float64) {
+ /* f1 => , func(v1 float64) */
+ /* v1 => , float64 */
+ var c /* c => 3, untyped float */ = "foo" /* c => , string */
+ {
+ var c struct {
+ c /* c => , string */ int
+ }
+ /* c => , struct{c int} */
+ _ = c
+ }
+ _ = func(a, b, c int) /* c => , string */ {
+ /* c => , int */
+ }
+ _ = c
+ type FT /* FT => , p.FT */ interface{}
+ }
+ `,
+ `
+ package p
+ /* T => , p.T */
+ `,
+ }
+
+ fset := token.NewFileSet()
+ var files []*ast.File
+ for i, src := range sources {
+ file, err := parser.ParseFile(fset, "p", src, parser.ParseComments)
+ if err != nil {
+ t.Fatalf("could not parse file %d: %s", i, err)
+ }
+ files = append(files, file)
+ }
+
+ pkg, err := Check("p", fset, files)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ for _, file := range files {
+ for _, group := range file.Comments {
+ for _, comment := range group.List {
+ s := comment.Text
+ if len(s) >= 4 && s[:2] == "/*" && s[len(s)-2:] == "*/" {
+ str, typ := split(s[2:len(s)-2], ", ")
+ str, val := split(str, "=>")
+ testEval(t, fset, pkg, comment.Pos(), str, nil, typ, val)
+ }
+ }
+ }
+ }
+}
+
+// split splits string s at the first occurrence of s.
+func split(s, sep string) (string, string) {
+ i := strings.Index(s, sep)
+ return strings.TrimSpace(s[:i]), strings.TrimSpace(s[i+len(sep):])
+}
diff --git a/go/types/expr.go b/go/types/expr.go
new file mode 100644
index 0000000..6efc7b4
--- /dev/null
+++ b/go/types/expr.go
@@ -0,0 +1,1497 @@
+// 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 implements typechecking of expressions.
+
+package types
+
+import (
+ "fmt"
+ "go/ast"
+ "go/token"
+ "math"
+
+ "golang.org/x/tools/go/exact"
+)
+
+/*
+Basic algorithm:
+
+Expressions are checked recursively, top down. Expression checker functions
+are generally of the form:
+
+ func f(x *operand, e *ast.Expr, ...)
+
+where e is the expression to be checked, and x is the result of the check.
+The check performed by f may fail in which case x.mode == invalid, and
+related error messages will have been issued by f.
+
+If a hint argument is present, it is the composite literal element type
+of an outer composite literal; it is used to type-check composite literal
+elements that have no explicit type specification in the source
+(e.g.: []T{{...}, {...}}, the hint is the type T in this case).
+
+All expressions are checked via rawExpr, which dispatches according
+to expression kind. Upon returning, rawExpr is recording the types and
+constant values for all expressions that have an untyped type (those types
+may change on the way up in the expression tree). Usually these are constants,
+but the results of comparisons or non-constant shifts of untyped constants
+may also be untyped, but not constant.
+
+Untyped expressions may eventually become fully typed (i.e., not untyped),
+typically when the value is assigned to a variable, or is used otherwise.
+The updateExprType method is used to record this final type and update
+the recorded types: the type-checked expression tree is again traversed down,
+and the new type is propagated as needed. Untyped constant expression values
+that become fully typed must now be representable by the full type (constant
+sub-expression trees are left alone except for their roots). This mechanism
+ensures that a client sees the actual (run-time) type an untyped value would
+have. It also permits type-checking of lhs shift operands "as if the shift
+were not present": when updateExprType visits an untyped lhs shift operand
+and assigns it it's final type, that type must be an integer type, and a
+constant lhs must be representable as an integer.
+
+When an expression gets its final type, either on the way out from rawExpr,
+on the way down in updateExprType, or at the end of the type checker run,
+the type (and constant value, if any) is recorded via Info.Types, if present.
+*/
+
+type opPredicates map[token.Token]func(Type) bool
+
+var unaryOpPredicates = opPredicates{
+ token.ADD: isNumeric,
+ token.SUB: isNumeric,
+ token.XOR: isInteger,
+ token.NOT: isBoolean,
+}
+
+func (check *Checker) op(m opPredicates, x *operand, op token.Token) bool {
+ if pred := m[op]; pred != nil {
+ if !pred(x.typ) {
+ check.invalidOp(x.pos(), "operator %s not defined for %s", op, x)
+ return false
+ }
+ } else {
+ check.invalidAST(x.pos(), "unknown operator %s", op)
+ return false
+ }
+ return true
+}
+
+// The unary expression e may be nil. It's passed in for better error messages only.
+func (check *Checker) unary(x *operand, e *ast.UnaryExpr, op token.Token) {
+ switch op {
+ case token.AND:
+ // spec: "As an exception to the addressability
+ // requirement x may also be a composite literal."
+ if _, ok := unparen(x.expr).(*ast.CompositeLit); !ok && x.mode != variable {
+ check.invalidOp(x.pos(), "cannot take address of %s", x)
+ x.mode = invalid
+ return
+ }
+ x.mode = value
+ x.typ = &Pointer{base: x.typ}
+ return
+
+ case token.ARROW:
+ typ, ok := x.typ.Underlying().(*Chan)
+ if !ok {
+ check.invalidOp(x.pos(), "cannot receive from non-channel %s", x)
+ x.mode = invalid
+ return
+ }
+ if typ.dir == SendOnly {
+ check.invalidOp(x.pos(), "cannot receive from send-only channel %s", x)
+ x.mode = invalid
+ return
+ }
+ x.mode = commaok
+ x.typ = typ.elem
+ check.hasCallOrRecv = true
+ return
+ }
+
+ if !check.op(unaryOpPredicates, x, op) {
+ x.mode = invalid
+ return
+ }
+
+ if x.mode == constant {
+ typ := x.typ.Underlying().(*Basic)
+ size := -1
+ if isUnsigned(typ) {
+ size = int(check.conf.sizeof(typ))
+ }
+ x.val = exact.UnaryOp(op, x.val, size)
+ // Typed constants must be representable in
+ // their type after each constant operation.
+ if isTyped(typ) {
+ if e != nil {
+ x.expr = e // for better error message
+ }
+ check.representable(x, typ)
+ }
+ return
+ }
+
+ x.mode = value
+ // x.typ remains unchanged
+}
+
+func isShift(op token.Token) bool {
+ return op == token.SHL || op == token.SHR
+}
+
+func isComparison(op token.Token) bool {
+ // Note: tokens are not ordered well to make this much easier
+ switch op {
+ case token.EQL, token.NEQ, token.LSS, token.LEQ, token.GTR, token.GEQ:
+ return true
+ }
+ return false
+}
+
+func fitsFloat32(x exact.Value) bool {
+ f32, _ := exact.Float32Val(x)
+ f := float64(f32)
+ return !math.IsInf(f, 0)
+}
+
+func roundFloat32(x exact.Value) exact.Value {
+ f32, _ := exact.Float32Val(x)
+ f := float64(f32)
+ if !math.IsInf(f, 0) {
+ return exact.MakeFloat64(f)
+ }
+ return nil
+}
+
+func fitsFloat64(x exact.Value) bool {
+ f, _ := exact.Float64Val(x)
+ return !math.IsInf(f, 0)
+}
+
+func roundFloat64(x exact.Value) exact.Value {
+ f, _ := exact.Float64Val(x)
+ if !math.IsInf(f, 0) {
+ return exact.MakeFloat64(f)
+ }
+ return nil
+}
+
+// representableConst reports whether x can be represented as
+// value of the given basic type kind and for the configuration
+// provided (only needed for int/uint sizes).
+//
+// If rounded != nil, *rounded is set to the rounded value of x for
+// representable floating-point values; it is left alone otherwise.
+// It is ok to provide the addressof the first argument for rounded.
+func representableConst(x exact.Value, conf *Config, as BasicKind, rounded *exact.Value) bool {
+ switch x.Kind() {
+ case exact.Unknown:
+ return true
+
+ case exact.Bool:
+ return as == Bool || as == UntypedBool
+
+ case exact.Int:
+ if x, ok := exact.Int64Val(x); ok {
+ switch as {
+ case Int:
+ var s = uint(conf.sizeof(Typ[as])) * 8
+ return int64(-1)<<(s-1) <= x && x <= int64(1)<<(s-1)-1
+ case Int8:
+ const s = 8
+ return -1<<(s-1) <= x && x <= 1<<(s-1)-1
+ case Int16:
+ const s = 16
+ return -1<<(s-1) <= x && x <= 1<<(s-1)-1
+ case Int32:
+ const s = 32
+ return -1<<(s-1) <= x && x <= 1<<(s-1)-1
+ case Int64:
+ return true
+ case Uint, Uintptr:
+ if s := uint(conf.sizeof(Typ[as])) * 8; s < 64 {
+ return 0 <= x && x <= int64(1)<<s-1
+ }
+ return 0 <= x
+ case Uint8:
+ const s = 8
+ return 0 <= x && x <= 1<<s-1
+ case Uint16:
+ const s = 16
+ return 0 <= x && x <= 1<<s-1
+ case Uint32:
+ const s = 32
+ return 0 <= x && x <= 1<<s-1
+ case Uint64:
+ return 0 <= x
+ case Float32, Float64, Complex64, Complex128,
+ UntypedInt, UntypedFloat, UntypedComplex:
+ return true
+ }
+ }
+
+ n := exact.BitLen(x)
+ switch as {
+ case Uint, Uintptr:
+ var s = uint(conf.sizeof(Typ[as])) * 8
+ return exact.Sign(x) >= 0 && n <= int(s)
+ case Uint64:
+ return exact.Sign(x) >= 0 && n <= 64
+ case Float32, Complex64:
+ if rounded == nil {
+ return fitsFloat32(x)
+ }
+ r := roundFloat32(x)
+ if r != nil {
+ *rounded = r
+ return true
+ }
+ case Float64, Complex128:
+ if rounded == nil {
+ return fitsFloat64(x)
+ }
+ r := roundFloat64(x)
+ if r != nil {
+ *rounded = r
+ return true
+ }
+ case UntypedInt, UntypedFloat, UntypedComplex:
+ return true
+ }
+
+ case exact.Float:
+ switch as {
+ case Float32, Complex64:
+ if rounded == nil {
+ return fitsFloat32(x)
+ }
+ r := roundFloat32(x)
+ if r != nil {
+ *rounded = r
+ return true
+ }
+ case Float64, Complex128:
+ if rounded == nil {
+ return fitsFloat64(x)
+ }
+ r := roundFloat64(x)
+ if r != nil {
+ *rounded = r
+ return true
+ }
+ case UntypedFloat, UntypedComplex:
+ return true
+ }
+
+ case exact.Complex:
+ switch as {
+ case Complex64:
+ if rounded == nil {
+ return fitsFloat32(exact.Real(x)) && fitsFloat32(exact.Imag(x))
+ }
+ re := roundFloat32(exact.Real(x))
+ im := roundFloat32(exact.Imag(x))
+ if re != nil && im != nil {
+ *rounded = exact.BinaryOp(re, token.ADD, exact.MakeImag(im))
+ return true
+ }
+ case Complex128:
+ if rounded == nil {
+ return fitsFloat64(exact.Real(x)) && fitsFloat64(exact.Imag(x))
+ }
+ re := roundFloat64(exact.Real(x))
+ im := roundFloat64(exact.Imag(x))
+ if re != nil && im != nil {
+ *rounded = exact.BinaryOp(re, token.ADD, exact.MakeImag(im))
+ return true
+ }
+ case UntypedComplex:
+ return true
+ }
+
+ case exact.String:
+ return as == String || as == UntypedString
+
+ default:
+ unreachable()
+ }
+
+ return false
+}
+
+// representable checks that a constant operand is representable in the given basic type.
+func (check *Checker) representable(x *operand, typ *Basic) {
+ assert(x.mode == constant)
+ if !representableConst(x.val, check.conf, typ.kind, &x.val) {
+ var msg string
+ if isNumeric(x.typ) && isNumeric(typ) {
+ // numeric conversion : error msg
+ //
+ // integer -> integer : overflows
+ // integer -> float : overflows (actually not possible)
+ // float -> integer : truncated
+ // float -> float : overflows
+ //
+ if !isInteger(x.typ) && isInteger(typ) {
+ msg = "%s truncated to %s"
+ } else {
+ msg = "%s overflows %s"
+ }
+ } else {
+ msg = "cannot convert %s to %s"
+ }
+ check.errorf(x.pos(), msg, x, typ)
+ x.mode = invalid
+ }
+}
+
+// updateExprType updates the type of x to typ and invokes itself
+// recursively for the operands of x, depending on expression kind.
+// If typ is still an untyped and not the final type, updateExprType
+// only updates the recorded untyped type for x and possibly its
+// operands. Otherwise (i.e., typ is not an untyped type anymore,
+// or it is the final type for x), the type and value are recorded.
+// Also, if x is a constant, it must be representable as a value of typ,
+// and if x is the (formerly untyped) lhs operand of a non-constant
+// shift, it must be an integer value.
+//
+func (check *Checker) updateExprType(x ast.Expr, typ Type, final bool) {
+ old, found := check.untyped[x]
+ if !found {
+ return // nothing to do
+ }
+
+ // update operands of x if necessary
+ switch x := x.(type) {
+ case *ast.BadExpr,
+ *ast.FuncLit,
+ *ast.CompositeLit,
+ *ast.IndexExpr,
+ *ast.SliceExpr,
+ *ast.TypeAssertExpr,
+ *ast.StarExpr,
+ *ast.KeyValueExpr,
+ *ast.ArrayType,
+ *ast.StructType,
+ *ast.FuncType,
+ *ast.InterfaceType,
+ *ast.MapType,
+ *ast.ChanType:
+ // These expression are never untyped - nothing to do.
+ // The respective sub-expressions got their final types
+ // upon assignment or use.
+ if debug {
+ check.dump("%s: found old type(%s): %s (new: %s)", x.Pos(), x, old.typ, typ)
+ unreachable()
+ }
+ return
+
+ case *ast.CallExpr:
+ // Resulting in an untyped constant (e.g., built-in complex).
+ // The respective calls take care of calling updateExprType
+ // for the arguments if necessary.
+
+ case *ast.Ident, *ast.BasicLit, *ast.SelectorExpr:
+ // An identifier denoting a constant, a constant literal,
+ // or a qualified identifier (imported untyped constant).
+ // No operands to take care of.
+
+ case *ast.ParenExpr:
+ check.updateExprType(x.X, typ, final)
+
+ case *ast.UnaryExpr:
+ // If x is a constant, the operands were constants.
+ // They don't need to be updated since they never
+ // get "materialized" into a typed value; and they
+ // will be processed at the end of the type check.
+ if old.val != nil {
+ break
+ }
+ check.updateExprType(x.X, typ, final)
+
+ case *ast.BinaryExpr:
+ if old.val != nil {
+ break // see comment for unary expressions
+ }
+ if isComparison(x.Op) {
+ // The result type is independent of operand types
+ // and the operand types must have final types.
+ } else if isShift(x.Op) {
+ // The result type depends only on lhs operand.
+ // The rhs type was updated when checking the shift.
+ check.updateExprType(x.X, typ, final)
+ } else {
+ // The operand types match the result type.
+ check.updateExprType(x.X, typ, final)
+ check.updateExprType(x.Y, typ, final)
+ }
+
+ default:
+ unreachable()
+ }
+
+ // If the new type is not final and still untyped, just
+ // update the recorded type.
+ if !final && isUntyped(typ) {
+ old.typ = typ.Underlying().(*Basic)
+ check.untyped[x] = old
+ return
+ }
+
+ // Otherwise we have the final (typed or untyped type).
+ // Remove it from the map of yet untyped expressions.
+ delete(check.untyped, x)
+
+ // If x is the lhs of a shift, its final type must be integer.
+ // We already know from the shift check that it is representable
+ // as an integer if it is a constant.
+ if old.isLhs && !isInteger(typ) {
+ check.invalidOp(x.Pos(), "shifted operand %s (type %s) must be integer", x, typ)
+ return
+ }
+
+ // Everything's fine, record final type and value for x.
+ check.recordTypeAndValue(x, old.mode, typ, old.val)
+}
+
+// updateExprVal updates the value of x to val.
+func (check *Checker) updateExprVal(x ast.Expr, val exact.Value) {
+ if info, ok := check.untyped[x]; ok {
+ info.val = val
+ check.untyped[x] = info
+ }
+}
+
+// convertUntyped attempts to set the type of an untyped value to the target type.
+func (check *Checker) convertUntyped(x *operand, target Type) {
+ if x.mode == invalid || isTyped(x.typ) || target == Typ[Invalid] {
+ return
+ }
+
+ // TODO(gri) Sloppy code - clean up. This function is central
+ // to assignment and expression checking.
+
+ if isUntyped(target) {
+ // both x and target are untyped
+ xkind := x.typ.(*Basic).kind
+ tkind := target.(*Basic).kind
+ if isNumeric(x.typ) && isNumeric(target) {
+ if xkind < tkind {
+ x.typ = target
+ check.updateExprType(x.expr, target, false)
+ }
+ } else if xkind != tkind {
+ goto Error
+ }
+ return
+ }
+
+ // typed target
+ switch t := target.Underlying().(type) {
+ case *Basic:
+ if x.mode == constant {
+ check.representable(x, t)
+ if x.mode == invalid {
+ return
+ }
+ // expression value may have been rounded - update if needed
+ // TODO(gri) A floating-point value may silently underflow to
+ // zero. If it was negative, the sign is lost. See issue 6898.
+ check.updateExprVal(x.expr, x.val)
+ } else {
+ // Non-constant untyped values may appear as the
+ // result of comparisons (untyped bool), intermediate
+ // (delayed-checked) rhs operands of shifts, and as
+ // the value nil.
+ switch x.typ.(*Basic).kind {
+ case UntypedBool:
+ if !isBoolean(target) {
+ goto Error
+ }
+ case UntypedInt, UntypedRune, UntypedFloat, UntypedComplex:
+ if !isNumeric(target) {
+ goto Error
+ }
+ case UntypedString:
+ // Non-constant untyped string values are not
+ // permitted by the spec and should not occur.
+ unreachable()
+ case UntypedNil:
+ // Unsafe.Pointer is a basic type that includes nil.
+ if !hasNil(target) {
+ goto Error
+ }
+ default:
+ goto Error
+ }
+ }
+ case *Interface:
+ if !x.isNil() && !t.Empty() /* empty interfaces are ok */ {
+ goto Error
+ }
+ // Update operand types to the default type rather then
+ // the target (interface) type: values must have concrete
+ // dynamic types. If the value is nil, keep it untyped
+ // (this is important for tools such as go vet which need
+ // the dynamic type for argument checking of say, print
+ // functions)
+ if x.isNil() {
+ target = Typ[UntypedNil]
+ } else {
+ // cannot assign untyped values to non-empty interfaces
+ if !t.Empty() {
+ goto Error
+ }
+ target = defaultType(x.typ)
+ }
+ case *Pointer, *Signature, *Slice, *Map, *Chan:
+ if !x.isNil() {
+ goto Error
+ }
+ // keep nil untyped - see comment for interfaces, above
+ target = Typ[UntypedNil]
+ default:
+ goto Error
+ }
+
+ x.typ = target
+ check.updateExprType(x.expr, target, true) // UntypedNils are final
+ return
+
+Error:
+ check.errorf(x.pos(), "cannot convert %s to %s", x, target)
+ x.mode = invalid
+}
+
+func (check *Checker) comparison(x, y *operand, op token.Token) {
+ // spec: "In any comparison, the first operand must be assignable
+ // to the type of the second operand, or vice versa."
+ err := ""
+ if x.assignableTo(check.conf, y.typ) || y.assignableTo(check.conf, x.typ) {
+ defined := false
+ switch op {
+ case token.EQL, token.NEQ:
+ // spec: "The equality operators == and != apply to operands that are comparable."
+ defined = Comparable(x.typ) || x.isNil() && hasNil(y.typ) || y.isNil() && hasNil(x.typ)
+ case token.LSS, token.LEQ, token.GTR, token.GEQ:
+ // spec: The ordering operators <, <=, >, and >= apply to operands that are ordered."
+ defined = isOrdered(x.typ)
+ default:
+ unreachable()
+ }
+ if !defined {
+ typ := x.typ
+ if x.isNil() {
+ typ = y.typ
+ }
+ err = check.sprintf("operator %s not defined for %s", op, typ)
+ }
+ } else {
+ err = check.sprintf("mismatched types %s and %s", x.typ, y.typ)
+ }
+
+ if err != "" {
+ check.errorf(x.pos(), "cannot compare %s %s %s (%s)", x.expr, op, y.expr, err)
+ x.mode = invalid
+ return
+ }
+
+ if x.mode == constant && y.mode == constant {
+ x.val = exact.MakeBool(exact.Compare(x.val, op, y.val))
+ // The operands are never materialized; no need to update
+ // their types.
+ } else {
+ x.mode = value
+ // The operands have now their final types, which at run-
+ // time will be materialized. Update the expression trees.
+ // If the current types are untyped, the materialized type
+ // is the respective default type.
+ check.updateExprType(x.expr, defaultType(x.typ), true)
+ check.updateExprType(y.expr, defaultType(y.typ), true)
+ }
+
+ // spec: "Comparison operators compare two operands and yield
+ // an untyped boolean value."
+ x.typ = Typ[UntypedBool]
+}
+
+func (check *Checker) shift(x, y *operand, op token.Token) {
+ untypedx := isUntyped(x.typ)
+
+ // The lhs must be of integer type or be representable
+ // as an integer; otherwise the shift has no chance.
+ if !x.isInteger() {
+ check.invalidOp(x.pos(), "shifted operand %s must be integer", x)
+ x.mode = invalid
+ return
+ }
+
+ // spec: "The right operand in a shift expression must have unsigned
+ // integer type or be an untyped constant that can be converted to
+ // unsigned integer type."
+ switch {
+ case isInteger(y.typ) && isUnsigned(y.typ):
+ // nothing to do
+ case isUntyped(y.typ):
+ check.convertUntyped(y, Typ[UntypedInt])
+ if y.mode == invalid {
+ x.mode = invalid
+ return
+ }
+ default:
+ check.invalidOp(y.pos(), "shift count %s must be unsigned integer", y)
+ x.mode = invalid
+ return
+ }
+
+ if x.mode == constant {
+ if y.mode == constant {
+ // rhs must be an integer value
+ if !y.isInteger() {
+ check.invalidOp(y.pos(), "shift count %s must be unsigned integer", y)
+ x.mode = invalid
+ return
+ }
+ // rhs must be within reasonable bounds
+ const stupidShift = 1023 - 1 + 52 // so we can express smallestFloat64
+ s, ok := exact.Uint64Val(y.val)
+ if !ok || s > stupidShift {
+ check.invalidOp(y.pos(), "stupid shift count %s", y)
+ x.mode = invalid
+ return
+ }
+ // The lhs is representable as an integer but may not be an integer
+ // (e.g., 2.0, an untyped float) - this can only happen for untyped
+ // non-integer numeric constants. Correct the type so that the shift
+ // result is of integer type.
+ if !isInteger(x.typ) {
+ x.typ = Typ[UntypedInt]
+ }
+ x.val = exact.Shift(x.val, op, uint(s))
+ return
+ }
+
+ // non-constant shift with constant lhs
+ if untypedx {
+ // spec: "If the left operand of a non-constant shift
+ // expression is an untyped constant, the type of the
+ // constant is what it would be if the shift expression
+ // were replaced by its left operand alone.".
+ //
+ // Delay operand checking until we know the final type:
+ // The lhs expression must be in the untyped map, mark
+ // the entry as lhs shift operand.
+ info, found := check.untyped[x.expr]
+ assert(found)
+ info.isLhs = true
+ check.untyped[x.expr] = info
+ // keep x's type
+ x.mode = value
+ return
+ }
+ }
+
+ // constant rhs must be >= 0
+ if y.mode == constant && exact.Sign(y.val) < 0 {
+ check.invalidOp(y.pos(), "shift count %s must not be negative", y)
+ }
+
+ // non-constant shift - lhs must be an integer
+ if !isInteger(x.typ) {
+ check.invalidOp(x.pos(), "shifted operand %s must be integer", x)
+ x.mode = invalid
+ return
+ }
+
+ x.mode = value
+}
+
+var binaryOpPredicates = opPredicates{
+ token.ADD: func(typ Type) bool { return isNumeric(typ) || isString(typ) },
+ token.SUB: isNumeric,
+ token.MUL: isNumeric,
+ token.QUO: isNumeric,
+ token.REM: isInteger,
+
+ token.AND: isInteger,
+ token.OR: isInteger,
+ token.XOR: isInteger,
+ token.AND_NOT: isInteger,
+
+ token.LAND: isBoolean,
+ token.LOR: isBoolean,
+}
+
+// The binary expression e may be nil. It's passed in for better error messages only.
+func (check *Checker) binary(x *operand, e *ast.BinaryExpr, lhs, rhs ast.Expr, op token.Token) {
+ var y operand
+
+ check.expr(x, lhs)
+ check.expr(&y, rhs)
+
+ if x.mode == invalid {
+ return
+ }
+ if y.mode == invalid {
+ x.mode = invalid
+ x.expr = y.expr
+ return
+ }
+
+ if isShift(op) {
+ check.shift(x, &y, op)
+ return
+ }
+
+ check.convertUntyped(x, y.typ)
+ if x.mode == invalid {
+ return
+ }
+ check.convertUntyped(&y, x.typ)
+ if y.mode == invalid {
+ x.mode = invalid
+ return
+ }
+
+ if isComparison(op) {
+ check.comparison(x, &y, op)
+ return
+ }
+
+ if !Identical(x.typ, y.typ) {
+ // only report an error if we have valid types
+ // (otherwise we had an error reported elsewhere already)
+ if x.typ != Typ[Invalid] && y.typ != Typ[Invalid] {
+ check.invalidOp(x.pos(), "mismatched types %s and %s", x.typ, y.typ)
+ }
+ x.mode = invalid
+ return
+ }
+
+ if !check.op(binaryOpPredicates, x, op) {
+ x.mode = invalid
+ return
+ }
+
+ if (op == token.QUO || op == token.REM) && (x.mode == constant || isInteger(x.typ)) && y.mode == constant && exact.Sign(y.val) == 0 {
+ check.invalidOp(y.pos(), "division by zero")
+ x.mode = invalid
+ return
+ }
+
+ if x.mode == constant && y.mode == constant {
+ typ := x.typ.Underlying().(*Basic)
+ // force integer division of integer operands
+ if op == token.QUO && isInteger(typ) {
+ op = token.QUO_ASSIGN
+ }
+ x.val = exact.BinaryOp(x.val, op, y.val)
+ // Typed constants must be representable in
+ // their type after each constant operation.
+ if isTyped(typ) {
+ if e != nil {
+ x.expr = e // for better error message
+ }
+ check.representable(x, typ)
+ }
+ return
+ }
+
+ x.mode = value
+ // x.typ is unchanged
+}
+
+// index checks an index expression for validity.
+// If max >= 0, it is the upper bound for index.
+// If index is valid and the result i >= 0, then i is the constant value of index.
+func (check *Checker) index(index ast.Expr, max int64) (i int64, valid bool) {
+ var x operand
+ check.expr(&x, index)
+ if x.mode == invalid {
+ return
+ }
+
+ // an untyped constant must be representable as Int
+ check.convertUntyped(&x, Typ[Int])
+ if x.mode == invalid {
+ return
+ }
+
+ // the index must be of integer type
+ if !isInteger(x.typ) {
+ check.invalidArg(x.pos(), "index %s must be integer", &x)
+ return
+ }
+
+ // a constant index i must be in bounds
+ if x.mode == constant {
+ if exact.Sign(x.val) < 0 {
+ check.invalidArg(x.pos(), "index %s must not be negative", &x)
+ return
+ }
+ i, valid = exact.Int64Val(x.val)
+ if !valid || max >= 0 && i >= max {
+ check.errorf(x.pos(), "index %s is out of bounds", &x)
+ return i, false
+ }
+ // 0 <= i [ && i < max ]
+ return i, true
+ }
+
+ return -1, true
+}
+
+// indexElts checks the elements (elts) of an array or slice composite literal
+// against the literal's element type (typ), and the element indices against
+// the literal length if known (length >= 0). It returns the length of the
+// literal (maximum index value + 1).
+//
+func (check *Checker) indexedElts(elts []ast.Expr, typ Type, length int64) int64 {
+ visited := make(map[int64]bool, len(elts))
+ var index, max int64
+ for _, e := range elts {
+ // determine and check index
+ validIndex := false
+ eval := e
+ if kv, _ := e.(*ast.KeyValueExpr); kv != nil {
+ if i, ok := check.index(kv.Key, length); ok {
+ if i >= 0 {
+ index = i
+ validIndex = true
+ } else {
+ check.errorf(e.Pos(), "index %s must be integer constant", kv.Key)
+ }
+ }
+ eval = kv.Value
+ } else if length >= 0 && index >= length {
+ check.errorf(e.Pos(), "index %d is out of bounds (>= %d)", index, length)
+ } else {
+ validIndex = true
+ }
+
+ // if we have a valid index, check for duplicate entries
+ if validIndex {
+ if visited[index] {
+ check.errorf(e.Pos(), "duplicate index %d in array or slice literal", index)
+ }
+ visited[index] = true
+ }
+ index++
+ if index > max {
+ max = index
+ }
+
+ // check element against composite literal element type
+ var x operand
+ check.exprWithHint(&x, eval, typ)
+ if !check.assignment(&x, typ) && x.mode != invalid {
+ check.errorf(x.pos(), "cannot use %s as %s value in array or slice literal", &x, typ)
+ }
+ }
+ return max
+}
+
+// exprKind describes the kind of an expression; the kind
+// determines if an expression is valid in 'statement context'.
+type exprKind int
+
+const (
+ conversion exprKind = iota
+ expression
+ statement
+)
+
+// rawExpr typechecks expression e and initializes x with the expression
+// value or type. If an error occurred, x.mode is set to invalid.
+// If hint != nil, it is the type of a composite literal element.
+//
+func (check *Checker) rawExpr(x *operand, e ast.Expr, hint Type) exprKind {
+ if trace {
+ check.trace(e.Pos(), "%s", e)
+ check.indent++
+ defer func() {
+ check.indent--
+ check.trace(e.Pos(), "=> %s", x)
+ }()
+ }
+
+ kind := check.exprInternal(x, e, hint)
+
+ // convert x into a user-friendly set of values
+ // TODO(gri) this code can be simplified
+ var typ Type
+ var val exact.Value
+ switch x.mode {
+ case invalid:
+ typ = Typ[Invalid]
+ case novalue:
+ typ = (*Tuple)(nil)
+ case constant:
+ typ = x.typ
+ val = x.val
+ default:
+ typ = x.typ
+ }
+ assert(x.expr != nil && typ != nil)
+
+ if isUntyped(typ) {
+ // delay type and value recording until we know the type
+ // or until the end of type checking
+ check.rememberUntyped(x.expr, false, x.mode, typ.(*Basic), val)
+ } else {
+ check.recordTypeAndValue(e, x.mode, typ, val)
+ }
+
+ return kind
+}
+
+// exprInternal contains the core of type checking of expressions.
+// Must only be called by rawExpr.
+//
+func (check *Checker) exprInternal(x *operand, e ast.Expr, hint Type) exprKind {
+ // make sure x has a valid state in case of bailout
+ // (was issue 5770)
+ x.mode = invalid
+ x.typ = Typ[Invalid]
+
+ switch e := e.(type) {
+ case *ast.BadExpr:
+ goto Error // error was reported before
+
+ case *ast.Ident:
+ check.ident(x, e, nil, nil)
+
+ case *ast.Ellipsis:
+ // ellipses are handled explicitly where they are legal
+ // (array composite literals and parameter lists)
+ check.error(e.Pos(), "invalid use of '...'")
+ goto Error
+
+ case *ast.BasicLit:
+ x.setConst(e.Kind, e.Value)
+ if x.mode == invalid {
+ check.invalidAST(e.Pos(), "invalid literal %v", e.Value)
+ goto Error
+ }
+
+ case *ast.FuncLit:
+ if sig, ok := check.typ(e.Type).(*Signature); ok {
+ // Anonymous functions are considered part of the
+ // init expression/func declaration which contains
+ // them: use existing package-level declaration info.
+ check.funcBody(check.decl, "", sig, e.Body)
+ x.mode = value
+ x.typ = sig
+ } else {
+ check.invalidAST(e.Pos(), "invalid function literal %s", e)
+ goto Error
+ }
+
+ case *ast.CompositeLit:
+ typ := hint
+ openArray := false
+ if e.Type != nil {
+ // [...]T array types may only appear with composite literals.
+ // Check for them here so we don't have to handle ... in general.
+ typ = nil
+ if atyp, _ := e.Type.(*ast.ArrayType); atyp != nil && atyp.Len != nil {
+ if ellip, _ := atyp.Len.(*ast.Ellipsis); ellip != nil && ellip.Elt == nil {
+ // We have an "open" [...]T array type.
+ // Create a new ArrayType with unknown length (-1)
+ // and finish setting it up after analyzing the literal.
+ typ = &Array{len: -1, elem: check.typ(atyp.Elt)}
+ openArray = true
+ }
+ }
+ if typ == nil {
+ typ = check.typ(e.Type)
+ }
+ }
+ if typ == nil {
+ // TODO(gri) provide better error messages depending on context
+ check.error(e.Pos(), "missing type in composite literal")
+ goto Error
+ }
+
+ switch typ, _ := deref(typ); utyp := typ.Underlying().(type) {
+ case *Struct:
+ if len(e.Elts) == 0 {
+ break
+ }
+ fields := utyp.fields
+ if _, ok := e.Elts[0].(*ast.KeyValueExpr); ok {
+ // all elements must have keys
+ visited := make([]bool, len(fields))
+ for _, e := range e.Elts {
+ kv, _ := e.(*ast.KeyValueExpr)
+ if kv == nil {
+ check.error(e.Pos(), "mixture of field:value and value elements in struct literal")
+ continue
+ }
+ key, _ := kv.Key.(*ast.Ident)
+ if key == nil {
+ check.errorf(kv.Pos(), "invalid field name %s in struct literal", kv.Key)
+ continue
+ }
+ i := fieldIndex(utyp.fields, check.pkg, key.Name)
+ if i < 0 {
+ check.errorf(kv.Pos(), "unknown field %s in struct literal", key.Name)
+ continue
+ }
+ fld := fields[i]
+ check.recordUse(key, fld)
+ // 0 <= i < len(fields)
+ if visited[i] {
+ check.errorf(kv.Pos(), "duplicate field name %s in struct literal", key.Name)
+ continue
+ }
+ visited[i] = true
+ check.expr(x, kv.Value)
+ etyp := fld.typ
+ if !check.assignment(x, etyp) {
+ if x.mode != invalid {
+ check.errorf(x.pos(), "cannot use %s as %s value in struct literal", x, etyp)
+ }
+ continue
+ }
+ }
+ } else {
+ // no element must have a key
+ for i, e := range e.Elts {
+ if kv, _ := e.(*ast.KeyValueExpr); kv != nil {
+ check.error(kv.Pos(), "mixture of field:value and value elements in struct literal")
+ continue
+ }
+ check.expr(x, e)
+ if i >= len(fields) {
+ check.error(x.pos(), "too many values in struct literal")
+ break // cannot continue
+ }
+ // i < len(fields)
+ fld := fields[i]
+ if !fld.Exported() && fld.pkg != check.pkg {
+ check.errorf(x.pos(), "implicit assignment to unexported field %s in %s literal", fld.name, typ)
+ continue
+ }
+ etyp := fld.typ
+ if !check.assignment(x, etyp) {
+ if x.mode != invalid {
+ check.errorf(x.pos(), "cannot use %s as %s value in struct literal", x, etyp)
+ }
+ continue
+ }
+ }
+ if len(e.Elts) < len(fields) {
+ check.error(e.Rbrace, "too few values in struct literal")
+ // ok to continue
+ }
+ }
+
+ case *Array:
+ n := check.indexedElts(e.Elts, utyp.elem, utyp.len)
+ // if we have an "open" [...]T array, set the length now that we know it
+ if openArray {
+ utyp.len = n
+ }
+
+ case *Slice:
+ check.indexedElts(e.Elts, utyp.elem, -1)
+
+ case *Map:
+ visited := make(map[interface{}][]Type, len(e.Elts))
+ for _, e := range e.Elts {
+ kv, _ := e.(*ast.KeyValueExpr)
+ if kv == nil {
+ check.error(e.Pos(), "missing key in map literal")
+ continue
+ }
+ check.exprWithHint(x, kv.Key, utyp.key)
+ if !check.assignment(x, utyp.key) {
+ if x.mode != invalid {
+ check.errorf(x.pos(), "cannot use %s as %s key in map literal", x, utyp.key)
+ }
+ continue
+ }
+ if x.mode == constant {
+ duplicate := false
+ // if the key is of interface type, the type is also significant when checking for duplicates
+ if _, ok := utyp.key.Underlying().(*Interface); ok {
+ for _, vtyp := range visited[x.val] {
+ if Identical(vtyp, x.typ) {
+ duplicate = true
+ break
+ }
+ }
+ visited[x.val] = append(visited[x.val], x.typ)
+ } else {
+ _, duplicate = visited[x.val]
+ visited[x.val] = nil
+ }
+ if duplicate {
+ check.errorf(x.pos(), "duplicate key %s in map literal", x.val)
+ continue
+ }
+ }
+ check.exprWithHint(x, kv.Value, utyp.elem)
+ if !check.assignment(x, utyp.elem) {
+ if x.mode != invalid {
+ check.errorf(x.pos(), "cannot use %s as %s value in map literal", x, utyp.elem)
+ }
+ continue
+ }
+ }
+
+ default:
+ // if utyp is invalid, an error was reported before
+ if utyp != Typ[Invalid] {
+ check.errorf(e.Pos(), "invalid composite literal type %s", typ)
+ goto Error
+ }
+ }
+
+ x.mode = value
+ x.typ = typ
+
+ case *ast.ParenExpr:
+ kind := check.rawExpr(x, e.X, nil)
+ x.expr = e
+ return kind
+
+ case *ast.SelectorExpr:
+ check.selector(x, e)
+
+ case *ast.IndexExpr:
+ check.expr(x, e.X)
+ if x.mode == invalid {
+ goto Error
+ }
+
+ valid := false
+ length := int64(-1) // valid if >= 0
+ switch typ := x.typ.Underlying().(type) {
+ case *Basic:
+ if isString(typ) {
+ valid = true
+ if x.mode == constant {
+ length = int64(len(exact.StringVal(x.val)))
+ }
+ // an indexed string always yields a byte value
+ // (not a constant) even if the string and the
+ // index are constant
+ x.mode = value
+ x.typ = universeByte // use 'byte' name
+ }
+
+ case *Array:
+ valid = true
+ length = typ.len
+ if x.mode != variable {
+ x.mode = value
+ }
+ x.typ = typ.elem
+
+ case *Pointer:
+ if typ, _ := typ.base.Underlying().(*Array); typ != nil {
+ valid = true
+ length = typ.len
+ x.mode = variable
+ x.typ = typ.elem
+ }
+
+ case *Slice:
+ valid = true
+ x.mode = variable
+ x.typ = typ.elem
+
+ case *Map:
+ var key operand
+ check.expr(&key, e.Index)
+ if !check.assignment(&key, typ.key) {
+ if key.mode != invalid {
+ check.invalidOp(key.pos(), "cannot use %s as map index of type %s", &key, typ.key)
+ }
+ goto Error
+ }
+ x.mode = mapindex
+ x.typ = typ.elem
+ x.expr = e
+ return expression
+ }
+
+ if !valid {
+ check.invalidOp(x.pos(), "cannot index %s", x)
+ goto Error
+ }
+
+ if e.Index == nil {
+ check.invalidAST(e.Pos(), "missing index for %s", x)
+ goto Error
+ }
+
+ check.index(e.Index, length)
+ // ok to continue
+
+ case *ast.SliceExpr:
+ check.expr(x, e.X)
+ if x.mode == invalid {
+ goto Error
+ }
+
+ valid := false
+ length := int64(-1) // valid if >= 0
+ switch typ := x.typ.Underlying().(type) {
+ case *Basic:
+ if isString(typ) {
+ if slice3(e) {
+ check.invalidOp(x.pos(), "3-index slice of string")
+ goto Error
+ }
+ valid = true
+ if x.mode == constant {
+ length = int64(len(exact.StringVal(x.val)))
+ }
+ // spec: "For untyped string operands the result
+ // is a non-constant value of type string."
+ if typ.kind == UntypedString {
+ x.typ = Typ[String]
+ }
+ }
+
+ case *Array:
+ valid = true
+ length = typ.len
+ if x.mode != variable {
+ check.invalidOp(x.pos(), "cannot slice %s (value not addressable)", x)
+ goto Error
+ }
+ x.typ = &Slice{elem: typ.elem}
+
+ case *Pointer:
+ if typ, _ := typ.base.Underlying().(*Array); typ != nil {
+ valid = true
+ length = typ.len
+ x.typ = &Slice{elem: typ.elem}
+ }
+
+ case *Slice:
+ valid = true
+ // x.typ doesn't change
+ }
+
+ if !valid {
+ check.invalidOp(x.pos(), "cannot slice %s", x)
+ goto Error
+ }
+
+ x.mode = value
+
+ // spec: "Only the first index may be omitted; it defaults to 0."
+ if slice3(e) && (e.High == nil || sliceMax(e) == nil) {
+ check.error(e.Rbrack, "2nd and 3rd index required in 3-index slice")
+ goto Error
+ }
+
+ // check indices
+ var ind [3]int64
+ for i, expr := range []ast.Expr{e.Low, e.High, sliceMax(e)} {
+ x := int64(-1)
+ switch {
+ case expr != nil:
+ // The "capacity" is only known statically for strings, arrays,
+ // and pointers to arrays, and it is the same as the length for
+ // those types.
+ max := int64(-1)
+ if length >= 0 {
+ max = length + 1
+ }
+ if t, ok := check.index(expr, max); ok && t >= 0 {
+ x = t
+ }
+ case i == 0:
+ // default is 0 for the first index
+ x = 0
+ case length >= 0:
+ // default is length (== capacity) otherwise
+ x = length
+ }
+ ind[i] = x
+ }
+
+ // constant indices must be in range
+ // (check.index already checks that existing indices >= 0)
+ L:
+ for i, x := range ind[:len(ind)-1] {
+ if x > 0 {
+ for _, y := range ind[i+1:] {
+ if y >= 0 && x > y {
+ check.errorf(e.Rbrack, "invalid slice indices: %d > %d", x, y)
+ break L // only report one error, ok to continue
+ }
+ }
+ }
+ }
+
+ case *ast.TypeAssertExpr:
+ check.expr(x, e.X)
+ if x.mode == invalid {
+ goto Error
+ }
+ xtyp, _ := x.typ.Underlying().(*Interface)
+ if xtyp == nil {
+ check.invalidOp(x.pos(), "%s is not an interface", x)
+ goto Error
+ }
+ // x.(type) expressions are handled explicitly in type switches
+ if e.Type == nil {
+ check.invalidAST(e.Pos(), "use of .(type) outside type switch")
+ goto Error
+ }
+ T := check.typ(e.Type)
+ if T == Typ[Invalid] {
+ goto Error
+ }
+ check.typeAssertion(x.pos(), x, xtyp, T)
+ x.mode = commaok
+ x.typ = T
+
+ case *ast.CallExpr:
+ return check.call(x, e)
+
+ case *ast.StarExpr:
+ check.exprOrType(x, e.X)
+ switch x.mode {
+ case invalid:
+ goto Error
+ case typexpr:
+ x.typ = &Pointer{base: x.typ}
+ default:
+ if typ, ok := x.typ.Underlying().(*Pointer); ok {
+ x.mode = variable
+ x.typ = typ.base
+ } else {
+ check.invalidOp(x.pos(), "cannot indirect %s", x)
+ goto Error
+ }
+ }
+
+ case *ast.UnaryExpr:
+ check.expr(x, e.X)
+ if x.mode == invalid {
+ goto Error
+ }
+ check.unary(x, e, e.Op)
+ if x.mode == invalid {
+ goto Error
+ }
+ if e.Op == token.ARROW {
+ x.expr = e
+ return statement // receive operations may appear in statement context
+ }
+
+ case *ast.BinaryExpr:
+ check.binary(x, e, e.X, e.Y, e.Op)
+ if x.mode == invalid {
+ goto Error
+ }
+
+ case *ast.KeyValueExpr:
+ // key:value expressions are handled in composite literals
+ check.invalidAST(e.Pos(), "no key:value expected")
+ goto Error
+
+ case *ast.ArrayType, *ast.StructType, *ast.FuncType,
+ *ast.InterfaceType, *ast.MapType, *ast.ChanType:
+ x.mode = typexpr
+ x.typ = check.typ(e)
+ // Note: rawExpr (caller of exprInternal) will call check.recordTypeAndValue
+ // even though check.typ has already called it. This is fine as both
+ // times the same expression and type are recorded. It is also not a
+ // performance issue because we only reach here for composite literal
+ // types, which are comparatively rare.
+
+ default:
+ panic(fmt.Sprintf("%s: unknown expression type %T", check.fset.Position(e.Pos()), e))
+ }
+
+ // everything went well
+ x.expr = e
+ return expression
+
+Error:
+ x.mode = invalid
+ x.expr = e
+ return statement // avoid follow-up errors
+}
+
+// typeAssertion checks that x.(T) is legal; xtyp must be the type of x.
+func (check *Checker) typeAssertion(pos token.Pos, x *operand, xtyp *Interface, T Type) {
+ method, wrongType := assertableTo(xtyp, T)
+ if method == nil {
+ return
+ }
+
+ var msg string
+ if wrongType {
+ msg = "wrong type for method"
+ } else {
+ msg = "missing method"
+ }
+ check.errorf(pos, "%s cannot have dynamic type %s (%s %s)", x, T, msg, method.name)
+}
+
+// expr typechecks expression e and initializes x with the expression value.
+// If an error occurred, x.mode is set to invalid.
+//
+func (check *Checker) expr(x *operand, e ast.Expr) {
+ check.rawExpr(x, e, nil)
+ var msg string
+ switch x.mode {
+ default:
+ return
+ case novalue:
+ msg = "used as value"
+ case builtin:
+ msg = "must be called"
+ case typexpr:
+ msg = "is not an expression"
+ }
+ check.errorf(x.pos(), "%s %s", x, msg)
+ x.mode = invalid
+}
+
+// exprWithHint typechecks expression e and initializes x with the expression value.
+// If an error occurred, x.mode is set to invalid.
+// If hint != nil, it is the type of a composite literal element.
+//
+func (check *Checker) exprWithHint(x *operand, e ast.Expr, hint Type) {
+ assert(hint != nil)
+ check.rawExpr(x, e, hint)
+ var msg string
+ switch x.mode {
+ default:
+ return
+ case novalue:
+ msg = "used as value"
+ case builtin:
+ msg = "must be called"
+ case typexpr:
+ msg = "is not an expression"
+ }
+ check.errorf(x.pos(), "%s %s", x, msg)
+ x.mode = invalid
+}
+
+// exprOrType typechecks expression or type e and initializes x with the expression value or type.
+// If an error occurred, x.mode is set to invalid.
+//
+func (check *Checker) exprOrType(x *operand, e ast.Expr) {
+ check.rawExpr(x, e, nil)
+ if x.mode == novalue {
+ check.errorf(x.pos(), "%s used as value or type", x)
+ x.mode = invalid
+ }
+}
diff --git a/go/types/exprstring.go b/go/types/exprstring.go
new file mode 100644
index 0000000..370bdf3
--- /dev/null
+++ b/go/types/exprstring.go
@@ -0,0 +1,220 @@
+// 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 printing of expressions.
+
+package types
+
+import (
+ "bytes"
+ "go/ast"
+)
+
+// ExprString returns the (possibly simplified) string representation for x.
+func ExprString(x ast.Expr) string {
+ var buf bytes.Buffer
+ WriteExpr(&buf, x)
+ return buf.String()
+}
+
+// WriteExpr writes the (possibly simplified) string representation for x to buf.
+func WriteExpr(buf *bytes.Buffer, x ast.Expr) {
+ // The AST preserves source-level parentheses so there is
+ // no need to introduce them here to correct for different
+ // operator precedences. (This assumes that the AST was
+ // generated by a Go parser.)
+
+ switch x := x.(type) {
+ default:
+ buf.WriteString("(bad expr)") // nil, ast.BadExpr, ast.KeyValueExpr
+
+ case *ast.Ident:
+ buf.WriteString(x.Name)
+
+ case *ast.Ellipsis:
+ buf.WriteString("...")
+ if x.Elt != nil {
+ WriteExpr(buf, x.Elt)
+ }
+
+ case *ast.BasicLit:
+ buf.WriteString(x.Value)
+
+ case *ast.FuncLit:
+ buf.WriteByte('(')
+ WriteExpr(buf, x.Type)
+ buf.WriteString(" literal)") // simplified
+
+ case *ast.CompositeLit:
+ buf.WriteByte('(')
+ WriteExpr(buf, x.Type)
+ buf.WriteString(" literal)") // simplified
+
+ case *ast.ParenExpr:
+ buf.WriteByte('(')
+ WriteExpr(buf, x.X)
+ buf.WriteByte(')')
+
+ case *ast.SelectorExpr:
+ WriteExpr(buf, x.X)
+ buf.WriteByte('.')
+ buf.WriteString(x.Sel.Name)
+
+ case *ast.IndexExpr:
+ WriteExpr(buf, x.X)
+ buf.WriteByte('[')
+ WriteExpr(buf, x.Index)
+ buf.WriteByte(']')
+
+ case *ast.SliceExpr:
+ WriteExpr(buf, x.X)
+ buf.WriteByte('[')
+ if x.Low != nil {
+ WriteExpr(buf, x.Low)
+ }
+ buf.WriteByte(':')
+ if x.High != nil {
+ WriteExpr(buf, x.High)
+ }
+ if x.Slice3 {
+ buf.WriteByte(':')
+ if x.Max != nil {
+ WriteExpr(buf, x.Max)
+ }
+ }
+ buf.WriteByte(']')
+
+ case *ast.TypeAssertExpr:
+ WriteExpr(buf, x.X)
+ buf.WriteString(".(")
+ WriteExpr(buf, x.Type)
+ buf.WriteByte(')')
+
+ case *ast.CallExpr:
+ WriteExpr(buf, x.Fun)
+ buf.WriteByte('(')
+ for i, arg := range x.Args {
+ if i > 0 {
+ buf.WriteString(", ")
+ }
+ WriteExpr(buf, arg)
+ }
+ if x.Ellipsis.IsValid() {
+ buf.WriteString("...")
+ }
+ buf.WriteByte(')')
+
+ case *ast.StarExpr:
+ buf.WriteByte('*')
+ WriteExpr(buf, x.X)
+
+ case *ast.UnaryExpr:
+ buf.WriteString(x.Op.String())
+ WriteExpr(buf, x.X)
+
+ case *ast.BinaryExpr:
+ WriteExpr(buf, x.X)
+ buf.WriteByte(' ')
+ buf.WriteString(x.Op.String())
+ buf.WriteByte(' ')
+ WriteExpr(buf, x.Y)
+
+ case *ast.ArrayType:
+ buf.WriteByte('[')
+ if x.Len != nil {
+ WriteExpr(buf, x.Len)
+ }
+ buf.WriteByte(']')
+ WriteExpr(buf, x.Elt)
+
+ case *ast.StructType:
+ buf.WriteString("struct{")
+ writeFieldList(buf, x.Fields, "; ", false)
+ buf.WriteByte('}')
+
+ case *ast.FuncType:
+ buf.WriteString("func")
+ writeSigExpr(buf, x)
+
+ case *ast.InterfaceType:
+ buf.WriteString("interface{")
+ writeFieldList(buf, x.Methods, "; ", true)
+ buf.WriteByte('}')
+
+ case *ast.MapType:
+ buf.WriteString("map[")
+ WriteExpr(buf, x.Key)
+ buf.WriteByte(']')
+ WriteExpr(buf, x.Value)
+
+ case *ast.ChanType:
+ var s string
+ switch x.Dir {
+ case ast.SEND:
+ s = "chan<- "
+ case ast.RECV:
+ s = "<-chan "
+ default:
+ s = "chan "
+ }
+ buf.WriteString(s)
+ WriteExpr(buf, x.Value)
+ }
+}
+
+func writeSigExpr(buf *bytes.Buffer, sig *ast.FuncType) {
+ buf.WriteByte('(')
+ writeFieldList(buf, sig.Params, ", ", false)
+ buf.WriteByte(')')
+
+ res := sig.Results
+ n := res.NumFields()
+ if n == 0 {
+ // no result
+ return
+ }
+
+ buf.WriteByte(' ')
+ if n == 1 && len(res.List[0].Names) == 0 {
+ // single unnamed result
+ WriteExpr(buf, res.List[0].Type)
+ return
+ }
+
+ // multiple or named result(s)
+ buf.WriteByte('(')
+ writeFieldList(buf, res, ", ", false)
+ buf.WriteByte(')')
+}
+
+func writeFieldList(buf *bytes.Buffer, fields *ast.FieldList, sep string, iface bool) {
+ for i, f := range fields.List {
+ if i > 0 {
+ buf.WriteString(sep)
+ }
+
+ // field list names
+ for i, name := range f.Names {
+ if i > 0 {
+ buf.WriteString(", ")
+ }
+ buf.WriteString(name.Name)
+ }
+
+ // types of interface methods consist of signatures only
+ if sig, _ := f.Type.(*ast.FuncType); sig != nil && iface {
+ writeSigExpr(buf, sig)
+ continue
+ }
+
+ // named fields are separated with a blank from the field type
+ if len(f.Names) > 0 {
+ buf.WriteByte(' ')
+ }
+
+ WriteExpr(buf, f.Type)
+
+ // ignore tag
+ }
+}
diff --git a/go/types/exprstring_test.go b/go/types/exprstring_test.go
new file mode 100644
index 0000000..cfd1472
--- /dev/null
+++ b/go/types/exprstring_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.
+
+package types_test
+
+import (
+ "go/parser"
+ "testing"
+
+ . "golang.org/x/tools/go/types"
+)
+
+var testExprs = []testEntry{
+ // basic type literals
+ dup("x"),
+ dup("true"),
+ dup("42"),
+ dup("3.1415"),
+ dup("2.71828i"),
+ dup(`'a'`),
+ dup(`"foo"`),
+ dup("`bar`"),
+
+ // func and composite literals
+ {"func(){}", "(func() literal)"},
+ {"func(x int) complex128 {}", "(func(x int) complex128 literal)"},
+ {"[]int{1, 2, 3}", "([]int literal)"},
+
+ // non-type expressions
+ dup("(x)"),
+ dup("x.f"),
+ dup("a[i]"),
+
+ dup("s[:]"),
+ dup("s[i:]"),
+ dup("s[:j]"),
+ dup("s[i:j]"),
+ dup("s[:j:k]"),
+ dup("s[i:j:k]"),
+
+ dup("x.(T)"),
+
+ dup("x.([10]int)"),
+ dup("x.([...]int)"),
+
+ dup("x.(struct{})"),
+ dup("x.(struct{x int; y, z float32; E})"),
+
+ dup("x.(func())"),
+ dup("x.(func(x int))"),
+ dup("x.(func() int)"),
+ dup("x.(func(x, y int, z float32) (r int))"),
+ dup("x.(func(a, b, c int))"),
+ dup("x.(func(x ...T))"),
+
+ dup("x.(interface{})"),
+ dup("x.(interface{m(); n(x int); E})"),
+ dup("x.(interface{m(); n(x int) T; E; F})"),
+
+ dup("x.(map[K]V)"),
+
+ dup("x.(chan E)"),
+ dup("x.(<-chan E)"),
+ dup("x.(chan<- chan int)"),
+ dup("x.(chan<- <-chan int)"),
+ dup("x.(<-chan chan int)"),
+ dup("x.(chan (<-chan int))"),
+
+ dup("f()"),
+ dup("f(x)"),
+ dup("int(x)"),
+ dup("f(x, x + y)"),
+ dup("f(s...)"),
+ dup("f(a, s...)"),
+
+ dup("*x"),
+ dup("&x"),
+ dup("x + y"),
+ dup("x + y << (2 * s)"),
+}
+
+func TestExprString(t *testing.T) {
+ for _, test := range testExprs {
+ x, err := parser.ParseExpr(test.src)
+ if err != nil {
+ t.Errorf("%s: %s", test.src, err)
+ continue
+ }
+ if got := ExprString(x); got != test.str {
+ t.Errorf("%s: got %s, want %s", test.src, got, test.str)
+ }
+ }
+}
diff --git a/go/types/go11.go b/go/types/go11.go
new file mode 100644
index 0000000..cf41cab
--- /dev/null
+++ b/go/types/go11.go
@@ -0,0 +1,17 @@
+// 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 !go1.2
+
+package types
+
+import "go/ast"
+
+func slice3(x *ast.SliceExpr) bool {
+ return false
+}
+
+func sliceMax(x *ast.SliceExpr) ast.Expr {
+ return nil
+}
diff --git a/go/types/go12.go b/go/types/go12.go
new file mode 100644
index 0000000..2017442
--- /dev/null
+++ b/go/types/go12.go
@@ -0,0 +1,17 @@
+// 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 go1.2
+
+package types
+
+import "go/ast"
+
+func slice3(x *ast.SliceExpr) bool {
+ return x.Slice3
+}
+
+func sliceMax(x *ast.SliceExpr) ast.Expr {
+ return x.Max
+}
diff --git a/go/types/hilbert_test.go b/go/types/hilbert_test.go
new file mode 100644
index 0000000..b555721
--- /dev/null
+++ b/go/types/hilbert_test.go
@@ -0,0 +1,232 @@
+// 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 types_test
+
+import (
+ "bytes"
+ "flag"
+ "fmt"
+ "go/ast"
+ "go/parser"
+ "go/token"
+ "io/ioutil"
+ "testing"
+
+ . "golang.org/x/tools/go/types"
+)
+
+var (
+ H = flag.Int("H", 5, "Hilbert matrix size")
+ out = flag.String("out", "", "write generated program to out")
+)
+
+func TestHilbert(t *testing.T) {
+ // generate source
+ src := program(*H, *out)
+ if *out != "" {
+ ioutil.WriteFile(*out, src, 0666)
+ return
+ }
+
+ // parse source
+ fset := token.NewFileSet()
+ f, err := parser.ParseFile(fset, "hilbert.go", src, 0)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ // type-check file
+ DefPredeclaredTestFuncs() // define assert built-in
+ _, err = Check(f.Name.Name, fset, []*ast.File{f})
+ if err != nil {
+ t.Fatal(err)
+ }
+}
+
+func program(n int, out string) []byte {
+ var g gen
+
+ g.p(`// WARNING: GENERATED FILE - DO NOT MODIFY MANUALLY!
+// (To generate, in go/types directory: go test -run=Hilbert -H=%d -out=%q)
+
+// This program tests arbitrary precision constant arithmetic
+// by generating the constant elements of a Hilbert matrix H,
+// its inverse I, and the product P = H*I. The product should
+// be the identity matrix.
+package main
+
+func main() {
+ if !ok {
+ printProduct()
+ return
+ }
+ println("PASS")
+}
+
+`, n, out)
+ g.hilbert(n)
+ g.inverse(n)
+ g.product(n)
+ g.verify(n)
+ g.printProduct(n)
+ g.binomials(2*n - 1)
+ g.factorials(2*n - 1)
+
+ return g.Bytes()
+}
+
+type gen struct {
+ bytes.Buffer
+}
+
+func (g *gen) p(format string, args ...interface{}) {
+ fmt.Fprintf(&g.Buffer, format, args...)
+}
+
+func (g *gen) hilbert(n int) {
+ g.p(`// Hilbert matrix, n = %d
+const (
+`, n)
+ for i := 0; i < n; i++ {
+ g.p("\t")
+ for j := 0; j < n; j++ {
+ if j > 0 {
+ g.p(", ")
+ }
+ g.p("h%d_%d", i, j)
+ }
+ if i == 0 {
+ g.p(" = ")
+ for j := 0; j < n; j++ {
+ if j > 0 {
+ g.p(", ")
+ }
+ g.p("1.0/(iota + %d)", j+1)
+ }
+ }
+ g.p("\n")
+ }
+ g.p(")\n\n")
+}
+
+func (g *gen) inverse(n int) {
+ g.p(`// Inverse Hilbert matrix
+const (
+`)
+ for i := 0; i < n; i++ {
+ for j := 0; j < n; j++ {
+ s := "+"
+ if (i+j)&1 != 0 {
+ s = "-"
+ }
+ g.p("\ti%d_%d = %s%d * b%d_%d * b%d_%d * b%d_%d * b%d_%d\n",
+ i, j, s, i+j+1, n+i, n-j-1, n+j, n-i-1, i+j, i, i+j, i)
+ }
+ g.p("\n")
+ }
+ g.p(")\n\n")
+}
+
+func (g *gen) product(n int) {
+ g.p(`// Product matrix
+const (
+`)
+ for i := 0; i < n; i++ {
+ for j := 0; j < n; j++ {
+ g.p("\tp%d_%d = ", i, j)
+ for k := 0; k < n; k++ {
+ if k > 0 {
+ g.p(" + ")
+ }
+ g.p("h%d_%d*i%d_%d", i, k, k, j)
+ }
+ g.p("\n")
+ }
+ g.p("\n")
+ }
+ g.p(")\n\n")
+}
+
+func (g *gen) verify(n int) {
+ g.p(`// Verify that product is the identity matrix
+const ok =
+`)
+ for i := 0; i < n; i++ {
+ for j := 0; j < n; j++ {
+ if j == 0 {
+ g.p("\t")
+ } else {
+ g.p(" && ")
+ }
+ v := 0
+ if i == j {
+ v = 1
+ }
+ g.p("p%d_%d == %d", i, j, v)
+ }
+ g.p(" &&\n")
+ }
+ g.p("\ttrue\n\n")
+
+ // verify ok at type-check time
+ if *out == "" {
+ g.p("const _ = assert(ok)\n\n")
+ }
+}
+
+func (g *gen) printProduct(n int) {
+ g.p("func printProduct() {\n")
+ for i := 0; i < n; i++ {
+ g.p("\tprintln(")
+ for j := 0; j < n; j++ {
+ if j > 0 {
+ g.p(", ")
+ }
+ g.p("p%d_%d", i, j)
+ }
+ g.p(")\n")
+ }
+ g.p("}\n\n")
+}
+
+func (g *gen) mulRange(a, b int) {
+ if a > b {
+ g.p("1")
+ return
+ }
+ for i := a; i <= b; i++ {
+ if i > a {
+ g.p("*")
+ }
+ g.p("%d", i)
+ }
+}
+
+func (g *gen) binomials(n int) {
+ g.p(`// Binomials
+const (
+`)
+ for j := 0; j <= n; j++ {
+ if j > 0 {
+ g.p("\n")
+ }
+ for k := 0; k <= j; k++ {
+ g.p("\tb%d_%d = f%d / (f%d*f%d)\n", j, k, j, k, j-k)
+ }
+ }
+ g.p(")\n\n")
+}
+
+func (g *gen) factorials(n int) {
+ g.p(`// Factorials
+const (
+ f0 = 1
+ f1 = 1
+`)
+ for i := 2; i <= n; i++ {
+ g.p("\tf%d = f%d * %d\n", i, i-1, i)
+ }
+ g.p(")\n\n")
+}
diff --git a/go/types/initorder.go b/go/types/initorder.go
new file mode 100644
index 0000000..0fd567b
--- /dev/null
+++ b/go/types/initorder.go
@@ -0,0 +1,222 @@
+// 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 types
+
+import (
+ "container/heap"
+ "fmt"
+)
+
+// initOrder computes the Info.InitOrder for package variables.
+func (check *Checker) initOrder() {
+ // An InitOrder may already have been computed if a package is
+ // built from several calls to (*Checker).Files. Clear it.
+ check.Info.InitOrder = check.Info.InitOrder[:0]
+
+ // compute the object dependency graph and
+ // initialize a priority queue with the list
+ // of graph nodes
+ pq := nodeQueue(dependencyGraph(check.objMap))
+ heap.Init(&pq)
+
+ const debug = false
+ if debug {
+ fmt.Printf("package %s: object dependency graph\n", check.pkg.Name())
+ for _, n := range pq {
+ for _, o := range n.out {
+ fmt.Printf("\t%s -> %s\n", n.obj.Name(), o.obj.Name())
+ }
+ }
+ fmt.Println()
+ fmt.Printf("package %s: initialization order\n", check.pkg.Name())
+ }
+
+ // determine initialization order by removing the highest priority node
+ // (the one with the fewest dependencies) and its edges from the graph,
+ // repeatedly, until there are no nodes left.
+ // In a valid Go program, those nodes always have zero dependencies (after
+ // removing all incoming dependencies), otherwise there are initialization
+ // cycles.
+ mark := 0
+ emitted := make(map[*declInfo]bool)
+ for len(pq) > 0 {
+ // get the next node
+ n := heap.Pop(&pq).(*objNode)
+
+ // if n still depends on other nodes, we have a cycle
+ if n.in > 0 {
+ mark++ // mark nodes using a different value each time
+ cycle := findPath(n, n, mark)
+ if i := valIndex(cycle); i >= 0 {
+ check.reportCycle(cycle, i)
+ }
+ // ok to continue, but the variable initialization order
+ // will be incorrect at this point since it assumes no
+ // cycle errors
+ }
+
+ // reduce dependency count of all dependent nodes
+ // and update priority queue
+ for _, out := range n.out {
+ out.in--
+ heap.Fix(&pq, out.index)
+ }
+
+ // record the init order for variables with initializers only
+ v, _ := n.obj.(*Var)
+ info := check.objMap[v]
+ if v == nil || !info.hasInitializer() {
+ continue
+ }
+
+ // n:1 variable declarations such as: a, b = f()
+ // introduce a node for each lhs variable (here: a, b);
+ // but they all have the same initializer - emit only
+ // one, for the first variable seen
+ if emitted[info] {
+ continue // initializer already emitted, if any
+ }
+ emitted[info] = true
+
+ infoLhs := info.lhs // possibly nil (see declInfo.lhs field comment)
+ if infoLhs == nil {
+ infoLhs = []*Var{v}
+ }
+ init := &Initializer{infoLhs, info.init}
+ check.Info.InitOrder = append(check.Info.InitOrder, init)
+
+ if debug {
+ fmt.Printf("\t%s\n", init)
+ }
+ }
+
+ if debug {
+ fmt.Println()
+ }
+}
+
+// findPath returns the (reversed) list of nodes z, ... c, b, a,
+// such that there is a path (list of edges) from a to z.
+// If there is no such path, the result is nil.
+// Nodes marked with the value mark are considered "visited";
+// unvisited nodes are marked during the graph search.
+func findPath(a, z *objNode, mark int) []*objNode {
+ if a.mark == mark {
+ return nil // node already seen
+ }
+ a.mark = mark
+
+ for _, n := range a.out {
+ if n == z {
+ return []*objNode{z}
+ }
+ if P := findPath(n, z, mark); P != nil {
+ return append(P, n)
+ }
+ }
+
+ return nil
+}
+
+// valIndex returns the index of the first constant or variable in a,
+// if any; or a value < 0.
+func valIndex(a []*objNode) int {
+ for i, n := range a {
+ switch n.obj.(type) {
+ case *Const, *Var:
+ return i
+ }
+ }
+ return -1
+}
+
+// reportCycle reports an error for the cycle starting at i.
+func (check *Checker) reportCycle(cycle []*objNode, i int) {
+ obj := cycle[i].obj
+ check.errorf(obj.Pos(), "initialization cycle for %s", obj.Name())
+ // print cycle
+ for _ = range cycle {
+ check.errorf(obj.Pos(), "\t%s refers to", obj.Name()) // secondary error, \t indented
+ i++
+ if i >= len(cycle) {
+ i = 0
+ }
+ obj = cycle[i].obj
+ }
+ check.errorf(obj.Pos(), "\t%s", obj.Name())
+}
+
+// An objNode represents a node in the object dependency graph.
+// Each node b in a.out represents an edge a->b indicating that
+// b depends on a.
+// Nodes may be marked for cycle detection. A node n is marked
+// if n.mark corresponds to the current mark value.
+type objNode struct {
+ obj Object // object represented by this node
+ in int // number of nodes this node depends on
+ out []*objNode // list of nodes that depend on this node
+ index int // node index in list of nodes
+ mark int // for cycle detection
+}
+
+// dependencyGraph computes the transposed object dependency graph
+// from the given objMap. The transposed graph is returned as a list
+// of nodes; an edge d->n indicates that node n depends on node d.
+func dependencyGraph(objMap map[Object]*declInfo) []*objNode {
+ // M maps each object to its corresponding node
+ M := make(map[Object]*objNode, len(objMap))
+ for obj := range objMap {
+ M[obj] = &objNode{obj: obj}
+ }
+
+ // G is the graph of nodes n
+ G := make([]*objNode, len(M))
+ i := 0
+ for obj, n := range M {
+ deps := objMap[obj].deps
+ n.in = len(deps)
+ for d := range deps {
+ d := M[d] // node n depends on node d
+ d.out = append(d.out, n) // add edge d->n
+ }
+
+ G[i] = n
+ n.index = i
+ i++
+ }
+
+ return G
+}
+
+// nodeQueue implements the container/heap interface;
+// a nodeQueue may be used as a priority queue.
+type nodeQueue []*objNode
+
+func (a nodeQueue) Len() int { return len(a) }
+
+func (a nodeQueue) Swap(i, j int) {
+ x, y := a[i], a[j]
+ a[i], a[j] = y, x
+ x.index, y.index = j, i
+}
+
+func (a nodeQueue) Less(i, j int) bool {
+ x, y := a[i], a[j]
+ // nodes are prioritized by number of incoming dependencies (1st key)
+ // and source order (2nd key)
+ return x.in < y.in || x.in == y.in && x.obj.order() < y.obj.order()
+}
+
+func (a *nodeQueue) Push(x interface{}) {
+ panic("unreachable")
+}
+
+func (a *nodeQueue) Pop() interface{} {
+ n := len(*a)
+ x := (*a)[n-1]
+ x.index = -1 // for safety
+ *a = (*a)[:n-1]
+ return x
+}
diff --git a/go/types/issues_test.go b/go/types/issues_test.go
new file mode 100644
index 0000000..04d8b37
--- /dev/null
+++ b/go/types/issues_test.go
@@ -0,0 +1,205 @@
+// 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 tests for various issues.
+
+package types_test
+
+import (
+ "fmt"
+ "go/ast"
+ "go/parser"
+ "sort"
+ "strings"
+ "testing"
+
+ _ "golang.org/x/tools/go/gcimporter"
+ . "golang.org/x/tools/go/types"
+)
+
+func TestIssue5770(t *testing.T) {
+ src := `package p; type S struct{T}`
+ f, err := parser.ParseFile(fset, "", src, 0)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ _, err = Check(f.Name.Name, fset, []*ast.File{f}) // do not crash
+ want := "undeclared name: T"
+ if err == nil || !strings.Contains(err.Error(), want) {
+ t.Errorf("got: %v; want: %s", err, want)
+ }
+}
+
+func TestIssue5849(t *testing.T) {
+ src := `
+package p
+var (
+ s uint
+ _ = uint8(8)
+ _ = uint16(16) << s
+ _ = uint32(32 << s)
+ _ = uint64(64 << s + s)
+ _ = (interface{})("foo")
+ _ = (interface{})(nil)
+)`
+ f, err := parser.ParseFile(fset, "", src, 0)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ var conf Config
+ types := make(map[ast.Expr]TypeAndValue)
+ _, err = conf.Check(f.Name.Name, fset, []*ast.File{f}, &Info{Types: types})
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ for x, tv := range types {
+ var want Type
+ switch x := x.(type) {
+ case *ast.BasicLit:
+ switch x.Value {
+ case `8`:
+ want = Typ[Uint8]
+ case `16`:
+ want = Typ[Uint16]
+ case `32`:
+ want = Typ[Uint32]
+ case `64`:
+ want = Typ[Uint] // because of "+ s", s is of type uint
+ case `"foo"`:
+ want = Typ[String]
+ }
+ case *ast.Ident:
+ if x.Name == "nil" {
+ want = Typ[UntypedNil]
+ }
+ }
+ if want != nil && !Identical(tv.Type, want) {
+ t.Errorf("got %s; want %s", tv.Type, want)
+ }
+ }
+}
+
+func TestIssue6413(t *testing.T) {
+ src := `
+package p
+func f() int {
+ defer f()
+ go f()
+ return 0
+}
+`
+ f, err := parser.ParseFile(fset, "", src, 0)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ var conf Config
+ types := make(map[ast.Expr]TypeAndValue)
+ _, err = conf.Check(f.Name.Name, fset, []*ast.File{f}, &Info{Types: types})
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ want := Typ[Int]
+ n := 0
+ for x, tv := range types {
+ if _, ok := x.(*ast.CallExpr); ok {
+ if tv.Type != want {
+ t.Errorf("%s: got %s; want %s", fset.Position(x.Pos()), tv.Type, want)
+ }
+ n++
+ }
+ }
+
+ if n != 2 {
+ t.Errorf("got %d CallExprs; want 2", n)
+ }
+}
+
+func TestIssue7245(t *testing.T) {
+ src := `
+package p
+func (T) m() (res bool) { return }
+type T struct{} // receiver type after method declaration
+`
+ f, err := parser.ParseFile(fset, "", src, 0)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ var conf Config
+ defs := make(map[*ast.Ident]Object)
+ _, err = conf.Check(f.Name.Name, fset, []*ast.File{f}, &Info{Defs: defs})
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ m := f.Decls[0].(*ast.FuncDecl)
+ res1 := defs[m.Name].(*Func).Type().(*Signature).Results().At(0)
+ res2 := defs[m.Type.Results.List[0].Names[0]].(*Var)
+
+ if res1 != res2 {
+ t.Errorf("got %s (%p) != %s (%p)", res1, res2, res1, res2)
+ }
+}
+
+// This tests that uses of existing vars on the LHS of an assignment
+// are Uses, not Defs; and also that the (illegal) use of a non-var on
+// the LHS of an assignment is a Use nonetheless.
+func TestIssue7827(t *testing.T) {
+ const src = `
+package p
+func _() {
+ const w = 1 // defs w
+ x, y := 2, 3 // defs x, y
+ w, x, z := 4, 5, 6 // uses w, x, defs z; error: cannot assign to w
+ _, _, _ = x, y, z // uses x, y, z
+}
+`
+ const want = `L3 defs func p._()
+L4 defs const w untyped int
+L5 defs var x int
+L5 defs var y int
+L6 defs var z int
+L6 uses const w untyped int
+L6 uses var x int
+L7 uses var x int
+L7 uses var y int
+L7 uses var z int`
+
+ f, err := parser.ParseFile(fset, "", src, 0)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ // don't abort at the first error
+ conf := Config{Error: func(err error) { t.Log(err) }}
+ defs := make(map[*ast.Ident]Object)
+ uses := make(map[*ast.Ident]Object)
+ _, err = conf.Check(f.Name.Name, fset, []*ast.File{f}, &Info{Defs: defs, Uses: uses})
+ if s := fmt.Sprint(err); !strings.HasSuffix(s, "cannot assign to w") {
+ t.Errorf("Check: unexpected error: %s", s)
+ }
+
+ var facts []string
+ for id, obj := range defs {
+ if obj != nil {
+ fact := fmt.Sprintf("L%d defs %s", fset.Position(id.Pos()).Line, obj)
+ facts = append(facts, fact)
+ }
+ }
+ for id, obj := range uses {
+ fact := fmt.Sprintf("L%d uses %s", fset.Position(id.Pos()).Line, obj)
+ facts = append(facts, fact)
+ }
+ sort.Strings(facts)
+
+ got := strings.Join(facts, "\n")
+ if got != want {
+ t.Errorf("Unexpected defs/uses\ngot:\n%s\nwant:\n%s", got, want)
+ }
+}
diff --git a/go/types/labels.go b/go/types/labels.go
new file mode 100644
index 0000000..7364d4d
--- /dev/null
+++ b/go/types/labels.go
@@ -0,0 +1,268 @@
+// 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 types
+
+import (
+ "go/ast"
+ "go/token"
+)
+
+// labels checks correct label use in body.
+func (check *Checker) labels(body *ast.BlockStmt) {
+ // set of all labels in this body
+ all := NewScope(nil, body.Pos(), body.End(), "label")
+
+ fwdJumps := check.blockBranches(all, nil, nil, body.List)
+
+ // If there are any forward jumps left, no label was found for
+ // the corresponding goto statements. Either those labels were
+ // never defined, or they are inside blocks and not reachable
+ // for the respective gotos.
+ for _, jmp := range fwdJumps {
+ var msg string
+ name := jmp.Label.Name
+ if alt := all.Lookup(name); alt != nil {
+ msg = "goto %s jumps into block"
+ alt.(*Label).used = true // avoid another error
+ } else {
+ msg = "label %s not declared"
+ }
+ check.errorf(jmp.Label.Pos(), msg, name)
+ }
+
+ // spec: "It is illegal to define a label that is never used."
+ for _, obj := range all.elems {
+ if lbl := obj.(*Label); !lbl.used {
+ check.softErrorf(lbl.pos, "label %s declared but not used", lbl.name)
+ }
+ }
+}
+
+// A block tracks label declarations in a block and its enclosing blocks.
+type block struct {
+ parent *block // enclosing block
+ lstmt *ast.LabeledStmt // labeled statement to which this block belongs, or nil
+ labels map[string]*ast.LabeledStmt // allocated lazily
+}
+
+// insert records a new label declaration for the current block.
+// The label must not have been declared before in any block.
+func (b *block) insert(s *ast.LabeledStmt) {
+ name := s.Label.Name
+ if debug {
+ assert(b.gotoTarget(name) == nil)
+ }
+ labels := b.labels
+ if labels == nil {
+ labels = make(map[string]*ast.LabeledStmt)
+ b.labels = labels
+ }
+ labels[name] = s
+}
+
+// gotoTarget returns the labeled statement in the current
+// or an enclosing block with the given label name, or nil.
+func (b *block) gotoTarget(name string) *ast.LabeledStmt {
+ for s := b; s != nil; s = s.parent {
+ if t := s.labels[name]; t != nil {
+ return t
+ }
+ }
+ return nil
+}
+
+// enclosingTarget returns the innermost enclosing labeled
+// statement with the given label name, or nil.
+func (b *block) enclosingTarget(name string) *ast.LabeledStmt {
+ for s := b; s != nil; s = s.parent {
+ if t := s.lstmt; t != nil && t.Label.Name == name {
+ return t
+ }
+ }
+ return nil
+}
+
+// blockBranches processes a block's statement list and returns the set of outgoing forward jumps.
+// all is the scope of all declared labels, parent the set of labels declared in the immediately
+// enclosing block, and lstmt is the labeled statement this block is associated with (or nil).
+func (check *Checker) blockBranches(all *Scope, parent *block, lstmt *ast.LabeledStmt, list []ast.Stmt) []*ast.BranchStmt {
+ b := &block{parent: parent, lstmt: lstmt}
+
+ var (
+ varDeclPos token.Pos
+ fwdJumps, badJumps []*ast.BranchStmt
+ )
+
+ // All forward jumps jumping over a variable declaration are possibly
+ // invalid (they may still jump out of the block and be ok).
+ // recordVarDecl records them for the given position.
+ recordVarDecl := func(pos token.Pos) {
+ varDeclPos = pos
+ badJumps = append(badJumps[:0], fwdJumps...) // copy fwdJumps to badJumps
+ }
+
+ jumpsOverVarDecl := func(jmp *ast.BranchStmt) bool {
+ if varDeclPos.IsValid() {
+ for _, bad := range badJumps {
+ if jmp == bad {
+ return true
+ }
+ }
+ }
+ return false
+ }
+
+ blockBranches := func(lstmt *ast.LabeledStmt, list []ast.Stmt) {
+ // Unresolved forward jumps inside the nested block
+ // become forward jumps in the current block.
+ fwdJumps = append(fwdJumps, check.blockBranches(all, b, lstmt, list)...)
+ }
+
+ var stmtBranches func(ast.Stmt)
+ stmtBranches = func(s ast.Stmt) {
+ switch s := s.(type) {
+ case *ast.DeclStmt:
+ if d, _ := s.Decl.(*ast.GenDecl); d != nil && d.Tok == token.VAR {
+ recordVarDecl(d.Pos())
+ }
+
+ case *ast.LabeledStmt:
+ // declare non-blank label
+ if name := s.Label.Name; name != "_" {
+ lbl := NewLabel(s.Label.Pos(), check.pkg, name)
+ if alt := all.Insert(lbl); alt != nil {
+ check.softErrorf(lbl.pos, "label %s already declared", name)
+ check.reportAltDecl(alt)
+ // ok to continue
+ } else {
+ b.insert(s)
+ check.recordDef(s.Label, lbl)
+ }
+ // resolve matching forward jumps and remove them from fwdJumps
+ i := 0
+ for _, jmp := range fwdJumps {
+ if jmp.Label.Name == name {
+ // match
+ lbl.used = true
+ check.recordUse(jmp.Label, lbl)
+ if jumpsOverVarDecl(jmp) {
+ check.softErrorf(
+ jmp.Label.Pos(),
+ "goto %s jumps over variable declaration at line %d",
+ name,
+ check.fset.Position(varDeclPos).Line,
+ )
+ // ok to continue
+ }
+ } else {
+ // no match - record new forward jump
+ fwdJumps[i] = jmp
+ i++
+ }
+ }
+ fwdJumps = fwdJumps[:i]
+ lstmt = s
+ }
+ stmtBranches(s.Stmt)
+
+ case *ast.BranchStmt:
+ if s.Label == nil {
+ return // checked in 1st pass (check.stmt)
+ }
+
+ // determine and validate target
+ name := s.Label.Name
+ switch s.Tok {
+ case token.BREAK:
+ // spec: "If there is a label, it must be that of an enclosing
+ // "for", "switch", or "select" statement, and that is the one
+ // whose execution terminates."
+ valid := false
+ if t := b.enclosingTarget(name); t != nil {
+ switch t.Stmt.(type) {
+ case *ast.SwitchStmt, *ast.TypeSwitchStmt, *ast.SelectStmt, *ast.ForStmt, *ast.RangeStmt:
+ valid = true
+ }
+ }
+ if !valid {
+ check.errorf(s.Label.Pos(), "invalid break label %s", name)
+ return
+ }
+
+ case token.CONTINUE:
+ // spec: "If there is a label, it must be that of an enclosing
+ // "for" statement, and that is the one whose execution advances."
+ valid := false
+ if t := b.enclosingTarget(name); t != nil {
+ switch t.Stmt.(type) {
+ case *ast.ForStmt, *ast.RangeStmt:
+ valid = true
+ }
+ }
+ if !valid {
+ check.errorf(s.Label.Pos(), "invalid continue label %s", name)
+ return
+ }
+
+ case token.GOTO:
+ if b.gotoTarget(name) == nil {
+ // label may be declared later - add branch to forward jumps
+ fwdJumps = append(fwdJumps, s)
+ return
+ }
+
+ default:
+ check.invalidAST(s.Pos(), "branch statement: %s %s", s.Tok, name)
+ return
+ }
+
+ // record label use
+ obj := all.Lookup(name)
+ obj.(*Label).used = true
+ check.recordUse(s.Label, obj)
+
+ case *ast.AssignStmt:
+ if s.Tok == token.DEFINE {
+ recordVarDecl(s.Pos())
+ }
+
+ case *ast.BlockStmt:
+ blockBranches(lstmt, s.List)
+
+ case *ast.IfStmt:
+ stmtBranches(s.Body)
+ if s.Else != nil {
+ stmtBranches(s.Else)
+ }
+
+ case *ast.CaseClause:
+ blockBranches(nil, s.Body)
+
+ case *ast.SwitchStmt:
+ stmtBranches(s.Body)
+
+ case *ast.TypeSwitchStmt:
+ stmtBranches(s.Body)
+
+ case *ast.CommClause:
+ blockBranches(nil, s.Body)
+
+ case *ast.SelectStmt:
+ stmtBranches(s.Body)
+
+ case *ast.ForStmt:
+ stmtBranches(s.Body)
+
+ case *ast.RangeStmt:
+ stmtBranches(s.Body)
+ }
+ }
+
+ for _, s := range list {
+ stmtBranches(s)
+ }
+
+ return fwdJumps
+}
diff --git a/go/types/lookup.go b/go/types/lookup.go
new file mode 100644
index 0000000..3caca55
--- /dev/null
+++ b/go/types/lookup.go
@@ -0,0 +1,341 @@
+// 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 various field and method lookup functions.
+
+package types
+
+// LookupFieldOrMethod looks up a field or method with given package and name
+// in T and returns the corresponding *Var or *Func, an index sequence, and a
+// bool indicating if there were any pointer indirections on the path to the
+// field or method. If addressable is set, T is the type of an addressable
+// variable (only matters for method lookups).
+//
+// The last index entry is the field or method index in the (possibly embedded)
+// type where the entry was found, either:
+//
+// 1) the list of declared methods of a named type; or
+// 2) the list of all methods (method set) of an interface type; or
+// 3) the list of fields of a struct type.
+//
+// The earlier index entries are the indices of the anonymous struct fields
+// traversed to get to the found entry, starting at depth 0.
+//
+// If no entry is found, a nil object is returned. In this case, the returned
+// index and indirect values have the following meaning:
+//
+// - If index != nil, the index sequence points to an ambiguous entry
+// (the same name appeared more than once at the same embedding level).
+//
+// - If indirect is set, a method with a pointer receiver type was found
+// but there was no pointer on the path from the actual receiver type to
+// the method's formal receiver base type, nor was the receiver addressable.
+//
+func LookupFieldOrMethod(T Type, addressable bool, pkg *Package, name string) (obj Object, index []int, indirect bool) {
+ // Methods cannot be associated to a named pointer type
+ // (spec: "The type denoted by T is called the receiver base type;
+ // it must not be a pointer or interface type and it must be declared
+ // in the same package as the method.").
+ // Thus, if we have a named pointer type, proceed with the underlying
+ // pointer type but discard the result if it is a method since we would
+ // not have found it for T (see also issue 8590).
+ if t, _ := T.(*Named); t != nil {
+ if p, _ := t.underlying.(*Pointer); p != nil {
+ obj, index, indirect = lookupFieldOrMethod(p, false, pkg, name)
+ if _, ok := obj.(*Func); ok {
+ return nil, nil, false
+ }
+ return
+ }
+ }
+
+ return lookupFieldOrMethod(T, addressable, pkg, name)
+}
+
+// TODO(gri) The named type consolidation and seen maps below must be
+// indexed by unique keys for a given type. Verify that named
+// types always have only one representation (even when imported
+// indirectly via different packages.)
+
+func lookupFieldOrMethod(T Type, addressable bool, pkg *Package, name string) (obj Object, index []int, indirect bool) {
+ // WARNING: The code in this function is extremely subtle - do not modify casually!
+ // This function and NewMethodSet should be kept in sync.
+
+ if name == "_" {
+ return // blank fields/methods are never found
+ }
+
+ typ, isPtr := deref(T)
+ named, _ := typ.(*Named)
+
+ // *typ where typ is an interface has no methods.
+ if isPtr {
+ utyp := typ
+ if named != nil {
+ utyp = named.underlying
+ }
+ if _, ok := utyp.(*Interface); ok {
+ return
+ }
+ }
+
+ // Start with typ as single entry at shallowest depth.
+ // If typ is not a named type, insert a nil type instead.
+ current := []embeddedType{{named, nil, isPtr, false}}
+
+ // named types that we have seen already, allocated lazily
+ var seen map[*Named]bool
+
+ // search current depth
+ for len(current) > 0 {
+ var next []embeddedType // embedded types found at current depth
+
+ // look for (pkg, name) in all types at current depth
+ for _, e := range current {
+ // The very first time only, e.typ may be nil.
+ // In this case, we don't have a named type and
+ // we simply continue with the underlying type.
+ if e.typ != nil {
+ if seen[e.typ] {
+ // We have seen this type before, at a more shallow depth
+ // (note that multiples of this type at the current depth
+ // were consolidated before). The type at that depth shadows
+ // this same type at the current depth, so we can ignore
+ // this one.
+ continue
+ }
+ if seen == nil {
+ seen = make(map[*Named]bool)
+ }
+ seen[e.typ] = true
+
+ // look for a matching attached method
+ if i, m := lookupMethod(e.typ.methods, pkg, name); m != nil {
+ // potential match
+ assert(m.typ != nil)
+ index = concat(e.index, i)
+ if obj != nil || e.multiples {
+ return nil, index, false // collision
+ }
+ obj = m
+ indirect = e.indirect
+ continue // we can't have a matching field or interface method
+ }
+
+ // continue with underlying type
+ typ = e.typ.underlying
+ }
+
+ switch t := typ.(type) {
+ case *Struct:
+ // look for a matching field and collect embedded types
+ for i, f := range t.fields {
+ if f.sameId(pkg, name) {
+ assert(f.typ != nil)
+ index = concat(e.index, i)
+ if obj != nil || e.multiples {
+ return nil, index, false // collision
+ }
+ obj = f
+ indirect = e.indirect
+ continue // we can't have a matching interface method
+ }
+ // Collect embedded struct fields for searching the next
+ // lower depth, but only if we have not seen a match yet
+ // (if we have a match it is either the desired field or
+ // we have a name collision on the same depth; in either
+ // case we don't need to look further).
+ // Embedded fields are always of the form T or *T where
+ // T is a named type. If e.typ appeared multiple times at
+ // this depth, f.typ appears multiple times at the next
+ // depth.
+ if obj == nil && f.anonymous {
+ // Ignore embedded basic types - only user-defined
+ // named types can have methods or struct fields.
+ typ, isPtr := deref(f.typ)
+ if t, _ := typ.(*Named); t != nil {
+ next = append(next, embeddedType{t, concat(e.index, i), e.indirect || isPtr, e.multiples})
+ }
+ }
+ }
+
+ case *Interface:
+ // look for a matching method
+ // TODO(gri) t.allMethods is sorted - use binary search
+ if i, m := lookupMethod(t.allMethods, pkg, name); m != nil {
+ assert(m.typ != nil)
+ index = concat(e.index, i)
+ if obj != nil || e.multiples {
+ return nil, index, false // collision
+ }
+ obj = m
+ indirect = e.indirect
+ }
+ }
+ }
+
+ if obj != nil {
+ // found a potential match
+ // spec: "A method call x.m() is valid if the method set of (the type of) x
+ // contains m and the argument list can be assigned to the parameter
+ // list of m. If x is addressable and &x's method set contains m, x.m()
+ // is shorthand for (&x).m()".
+ if f, _ := obj.(*Func); f != nil && ptrRecv(f) && !indirect && !addressable {
+ return nil, nil, true // pointer/addressable receiver required
+ }
+ return
+ }
+
+ current = consolidateMultiples(next)
+ }
+
+ return nil, nil, false // not found
+}
+
+// embeddedType represents an embedded named type
+type embeddedType struct {
+ typ *Named // nil means use the outer typ variable instead
+ index []int // embedded field indices, starting with index at depth 0
+ indirect bool // if set, there was a pointer indirection on the path to this field
+ multiples bool // if set, typ appears multiple times at this depth
+}
+
+// consolidateMultiples collects multiple list entries with the same type
+// into a single entry marked as containing multiples. The result is the
+// consolidated list.
+func consolidateMultiples(list []embeddedType) []embeddedType {
+ if len(list) <= 1 {
+ return list // at most one entry - nothing to do
+ }
+
+ n := 0 // number of entries w/ unique type
+ prev := make(map[*Named]int) // index at which type was previously seen
+ for _, e := range list {
+ if i, found := prev[e.typ]; found {
+ list[i].multiples = true
+ // ignore this entry
+ } else {
+ prev[e.typ] = n
+ list[n] = e
+ n++
+ }
+ }
+ return list[:n]
+}
+
+// MissingMethod returns (nil, false) if V implements T, otherwise it
+// returns a missing method required by T and whether it is missing or
+// just has the wrong type.
+//
+// For non-interface types V, or if static is set, V implements T if all
+// methods of T are present in V. Otherwise (V is an interface and static
+// is not set), MissingMethod only checks that methods of T which are also
+// present in V have matching types (e.g., for a type assertion x.(T) where
+// x is of interface type V).
+//
+func MissingMethod(V Type, T *Interface, static bool) (method *Func, wrongType bool) {
+ // fast path for common case
+ if T.Empty() {
+ return
+ }
+
+ // TODO(gri) Consider using method sets here. Might be more efficient.
+
+ if ityp, _ := V.Underlying().(*Interface); ityp != nil {
+ // TODO(gri) allMethods is sorted - can do this more efficiently
+ for _, m := range T.allMethods {
+ _, obj := lookupMethod(ityp.allMethods, m.pkg, m.name)
+ switch {
+ case obj == nil:
+ if static {
+ return m, false
+ }
+ case !Identical(obj.Type(), m.typ):
+ return m, true
+ }
+ }
+ return
+ }
+
+ // A concrete type implements T if it implements all methods of T.
+ for _, m := range T.allMethods {
+ obj, _, _ := lookupFieldOrMethod(V, false, m.pkg, m.name)
+
+ f, _ := obj.(*Func)
+ if f == nil {
+ return m, false
+ }
+
+ if !Identical(f.typ, m.typ) {
+ return m, true
+ }
+ }
+
+ return
+}
+
+// assertableTo reports whether a value of type V can be asserted to have type T.
+// It returns (nil, false) as affirmative answer. Otherwise it returns a missing
+// method required by V and whether it is missing or just has the wrong type.
+func assertableTo(V *Interface, T Type) (method *Func, wrongType bool) {
+ // no static check is required if T is an interface
+ // spec: "If T is an interface type, x.(T) asserts that the
+ // dynamic type of x implements the interface T."
+ if _, ok := T.Underlying().(*Interface); ok && !strict {
+ return
+ }
+ return MissingMethod(T, V, false)
+}
+
+// deref dereferences typ if it is a *Pointer and returns its base and true.
+// Otherwise it returns (typ, false).
+func deref(typ Type) (Type, bool) {
+ if p, _ := typ.(*Pointer); p != nil {
+ return p.base, true
+ }
+ return typ, false
+}
+
+// derefStructPtr dereferences typ if it is a (named or unnamed) pointer to a
+// (named or unnamed) struct and returns its base. Otherwise it returns typ.
+func derefStructPtr(typ Type) Type {
+ if p, _ := typ.Underlying().(*Pointer); p != nil {
+ if _, ok := p.base.Underlying().(*Struct); ok {
+ return p.base
+ }
+ }
+ return typ
+}
+
+// concat returns the result of concatenating list and i.
+// The result does not share its underlying array with list.
+func concat(list []int, i int) []int {
+ var t []int
+ t = append(t, list...)
+ return append(t, i)
+}
+
+// fieldIndex returns the index for the field with matching package and name, or a value < 0.
+func fieldIndex(fields []*Var, pkg *Package, name string) int {
+ if name != "_" {
+ for i, f := range fields {
+ if f.sameId(pkg, name) {
+ return i
+ }
+ }
+ }
+ return -1
+}
+
+// lookupMethod returns the index of and method with matching package and name, or (-1, nil).
+func lookupMethod(methods []*Func, pkg *Package, name string) (int, *Func) {
+ if name != "_" {
+ for i, m := range methods {
+ if m.sameId(pkg, name) {
+ return i, m
+ }
+ }
+ }
+ return -1, nil
+}
diff --git a/go/types/methodset.go b/go/types/methodset.go
new file mode 100644
index 0000000..8aff6f9
--- /dev/null
+++ b/go/types/methodset.go
@@ -0,0 +1,271 @@
+// 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 method sets.
+
+package types
+
+import (
+ "bytes"
+ "fmt"
+ "sort"
+)
+
+// A MethodSet is an ordered set of concrete or abstract (interface) methods;
+// a method is a MethodVal selection, and they are ordered by ascending m.Obj().Id().
+// The zero value for a MethodSet is a ready-to-use empty method set.
+type MethodSet struct {
+ list []*Selection
+}
+
+func (s *MethodSet) String() string {
+ if s.Len() == 0 {
+ return "MethodSet {}"
+ }
+
+ var buf bytes.Buffer
+ fmt.Fprintln(&buf, "MethodSet {")
+ for _, f := range s.list {
+ fmt.Fprintf(&buf, "\t%s\n", f)
+ }
+ fmt.Fprintln(&buf, "}")
+ return buf.String()
+}
+
+// Len returns the number of methods in s.
+func (s *MethodSet) Len() int { return len(s.list) }
+
+// At returns the i'th method in s for 0 <= i < s.Len().
+func (s *MethodSet) At(i int) *Selection { return s.list[i] }
+
+// Lookup returns the method with matching package and name, or nil if not found.
+func (s *MethodSet) Lookup(pkg *Package, name string) *Selection {
+ if s.Len() == 0 {
+ return nil
+ }
+
+ key := Id(pkg, name)
+ i := sort.Search(len(s.list), func(i int) bool {
+ m := s.list[i]
+ return m.obj.Id() >= key
+ })
+ if i < len(s.list) {
+ m := s.list[i]
+ if m.obj.Id() == key {
+ return m
+ }
+ }
+ return nil
+}
+
+// Shared empty method set.
+var emptyMethodSet MethodSet
+
+// NewMethodSet returns the method set for the given type T. It
+// always returns a non-nil method set, even if it is empty.
+//
+// A MethodSetCache handles repeat queries more efficiently.
+//
+func NewMethodSet(T Type) *MethodSet {
+ // WARNING: The code in this function is extremely subtle - do not modify casually!
+ // This function and lookupFieldOrMethod should be kept in sync.
+
+ // method set up to the current depth, allocated lazily
+ var base methodSet
+
+ typ, isPtr := deref(T)
+ named, _ := typ.(*Named)
+
+ // *typ where typ is an interface has no methods.
+ if isPtr {
+ utyp := typ
+ if named != nil {
+ utyp = named.underlying
+ }
+ if _, ok := utyp.(*Interface); ok {
+ return &emptyMethodSet
+ }
+ }
+
+ // Start with typ as single entry at shallowest depth.
+ // If typ is not a named type, insert a nil type instead.
+ current := []embeddedType{{named, nil, isPtr, false}}
+
+ // named types that we have seen already, allocated lazily
+ var seen map[*Named]bool
+
+ // collect methods at current depth
+ for len(current) > 0 {
+ var next []embeddedType // embedded types found at current depth
+
+ // field and method sets at current depth, allocated lazily
+ var fset fieldSet
+ var mset methodSet
+
+ for _, e := range current {
+ // The very first time only, e.typ may be nil.
+ // In this case, we don't have a named type and
+ // we simply continue with the underlying type.
+ if e.typ != nil {
+ if seen[e.typ] {
+ // We have seen this type before, at a more shallow depth
+ // (note that multiples of this type at the current depth
+ // were consolidated before). The type at that depth shadows
+ // this same type at the current depth, so we can ignore
+ // this one.
+ continue
+ }
+ if seen == nil {
+ seen = make(map[*Named]bool)
+ }
+ seen[e.typ] = true
+
+ mset = mset.add(e.typ.methods, e.index, e.indirect, e.multiples)
+
+ // continue with underlying type
+ typ = e.typ.underlying
+ }
+
+ switch t := typ.(type) {
+ case *Struct:
+ for i, f := range t.fields {
+ fset = fset.add(f, e.multiples)
+
+ // Embedded fields are always of the form T or *T where
+ // T is a named type. If typ appeared multiple times at
+ // this depth, f.Type appears multiple times at the next
+ // depth.
+ if f.anonymous {
+ // Ignore embedded basic types - only user-defined
+ // named types can have methods or struct fields.
+ typ, isPtr := deref(f.typ)
+ if t, _ := typ.(*Named); t != nil {
+ next = append(next, embeddedType{t, concat(e.index, i), e.indirect || isPtr, e.multiples})
+ }
+ }
+ }
+
+ case *Interface:
+ mset = mset.add(t.allMethods, e.index, true, e.multiples)
+ }
+ }
+
+ // Add methods and collisions at this depth to base if no entries with matching
+ // names exist already.
+ for k, m := range mset {
+ if _, found := base[k]; !found {
+ // Fields collide with methods of the same name at this depth.
+ if _, found := fset[k]; found {
+ m = nil // collision
+ }
+ if base == nil {
+ base = make(methodSet)
+ }
+ base[k] = m
+ }
+ }
+
+ // Multiple fields with matching names collide at this depth and shadow all
+ // entries further down; add them as collisions to base if no entries with
+ // matching names exist already.
+ for k, f := range fset {
+ if f == nil {
+ if _, found := base[k]; !found {
+ if base == nil {
+ base = make(methodSet)
+ }
+ base[k] = nil // collision
+ }
+ }
+ }
+
+ current = consolidateMultiples(next)
+ }
+
+ if len(base) == 0 {
+ return &emptyMethodSet
+ }
+
+ // collect methods
+ var list []*Selection
+ for _, m := range base {
+ if m != nil {
+ m.recv = T
+ list = append(list, m)
+ }
+ }
+ sort.Sort(byUniqueName(list))
+ return &MethodSet{list}
+}
+
+// A fieldSet is a set of fields and name collisions.
+// A collision indicates that multiple fields with the
+// same unique id appeared.
+type fieldSet map[string]*Var // a nil entry indicates a name collision
+
+// Add adds field f to the field set s.
+// If multiples is set, f appears multiple times
+// and is treated as a collision.
+func (s fieldSet) add(f *Var, multiples bool) fieldSet {
+ if s == nil {
+ s = make(fieldSet)
+ }
+ key := f.Id()
+ // if f is not in the set, add it
+ if !multiples {
+ if _, found := s[key]; !found {
+ s[key] = f
+ return s
+ }
+ }
+ s[key] = nil // collision
+ return s
+}
+
+// A methodSet is a set of methods and name collisions.
+// A collision indicates that multiple methods with the
+// same unique id appeared.
+type methodSet map[string]*Selection // a nil entry indicates a name collision
+
+// Add adds all functions in list to the method set s.
+// If multiples is set, every function in list appears multiple times
+// and is treated as a collision.
+func (s methodSet) add(list []*Func, index []int, indirect bool, multiples bool) methodSet {
+ if len(list) == 0 {
+ return s
+ }
+ if s == nil {
+ s = make(methodSet)
+ }
+ for i, f := range list {
+ key := f.Id()
+ // if f is not in the set, add it
+ if !multiples {
+ // TODO(gri) A found method may not be added because it's not in the method set
+ // (!indirect && ptrRecv(f)). A 2nd method on the same level may be in the method
+ // set and may not collide with the first one, thus leading to a false positive.
+ // Is that possible? Investigate.
+ if _, found := s[key]; !found && (indirect || !ptrRecv(f)) {
+ s[key] = &Selection{MethodVal, nil, f, concat(index, i), indirect}
+ continue
+ }
+ }
+ s[key] = nil // collision
+ }
+ return s
+}
+
+// ptrRecv reports whether the receiver is of the form *T.
+// The receiver must exist.
+func ptrRecv(f *Func) bool {
+ _, isPtr := deref(f.typ.(*Signature).recv.typ)
+ return isPtr
+}
+
+// byUniqueName function lists can be sorted by their unique names.
+type byUniqueName []*Selection
+
+func (a byUniqueName) Len() int { return len(a) }
+func (a byUniqueName) Less(i, j int) bool { return a[i].obj.Id() < a[j].obj.Id() }
+func (a byUniqueName) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
diff --git a/go/types/object.go b/go/types/object.go
new file mode 100644
index 0000000..a9b6c43
--- /dev/null
+++ b/go/types/object.go
@@ -0,0 +1,361 @@
+// 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 types
+
+import (
+ "bytes"
+ "fmt"
+ "go/ast"
+ "go/token"
+
+ "golang.org/x/tools/go/exact"
+)
+
+// TODO(gri) Document factory, accessor methods, and fields. General clean-up.
+
+// An Object describes a named language entity such as a package,
+// constant, type, variable, function (incl. methods), or label.
+// All objects implement the Object interface.
+//
+type Object interface {
+ Parent() *Scope // scope in which this object is declared
+ Pos() token.Pos // position of object identifier in declaration
+ Pkg() *Package // nil for objects in the Universe scope and labels
+ Name() string // package local object name
+ Type() Type // object type
+ Exported() bool // reports whether the name starts with a capital letter
+ Id() string // object id (see Id below)
+
+ // String returns a human-readable string of the object.
+ String() string
+
+ // order reflects a package-level object's source order: if object
+ // a is before object b in the source, then a.order() < b.order().
+ // order returns a value > 0 for package-level objects; it returns
+ // 0 for all other objects (including objects in file scopes).
+ order() uint32
+
+ // setOrder sets the order number of the object. It must be > 0.
+ setOrder(uint32)
+
+ // setParent sets the parent scope of the object.
+ setParent(*Scope)
+
+ // sameId reports whether obj.Id() and Id(pkg, name) are the same.
+ sameId(pkg *Package, name string) bool
+
+ // scopePos returns the start position of the scope of this Object
+ scopePos() token.Pos
+
+ // setScopePos sets the start position of the scope for this Object.
+ setScopePos(pos token.Pos)
+}
+
+// Id returns name if it is exported, otherwise it
+// returns the name qualified with the package path.
+func Id(pkg *Package, name string) string {
+ if ast.IsExported(name) {
+ return name
+ }
+ // unexported names need the package path for differentiation
+ // (if there's no package, make sure we don't start with '.'
+ // as that may change the order of methods between a setup
+ // inside a package and outside a package - which breaks some
+ // tests)
+ path := "_"
+ // TODO(gri): shouldn't !ast.IsExported(name) => pkg != nil be an precondition?
+ // if pkg == nil {
+ // panic("nil package in lookup of unexported name")
+ // }
+ if pkg != nil {
+ path = pkg.path
+ if path == "" {
+ path = "_"
+ }
+ }
+ return path + "." + name
+}
+
+// An object implements the common parts of an Object.
+type object struct {
+ parent *Scope
+ pos token.Pos
+ pkg *Package
+ name string
+ typ Type
+ order_ uint32
+ scopePos_ token.Pos
+}
+
+func (obj *object) Parent() *Scope { return obj.parent }
+func (obj *object) Pos() token.Pos { return obj.pos }
+func (obj *object) Pkg() *Package { return obj.pkg }
+func (obj *object) Name() string { return obj.name }
+func (obj *object) Type() Type { return obj.typ }
+func (obj *object) Exported() bool { return ast.IsExported(obj.name) }
+func (obj *object) Id() string { return Id(obj.pkg, obj.name) }
+func (obj *object) String() string { panic("abstract") }
+func (obj *object) order() uint32 { return obj.order_ }
+func (obj *object) scopePos() token.Pos { return obj.scopePos_ }
+
+func (obj *object) setParent(parent *Scope) { obj.parent = parent }
+func (obj *object) setOrder(order uint32) { assert(order > 0); obj.order_ = order }
+func (obj *object) setScopePos(pos token.Pos) { obj.scopePos_ = pos }
+
+func (obj *object) sameId(pkg *Package, name string) bool {
+ // spec:
+ // "Two identifiers are different if they are spelled differently,
+ // or if they appear in different packages and are not exported.
+ // Otherwise, they are the same."
+ if name != obj.name {
+ return false
+ }
+ // obj.Name == name
+ if obj.Exported() {
+ return true
+ }
+ // not exported, so packages must be the same (pkg == nil for
+ // fields in Universe scope; this can only happen for types
+ // introduced via Eval)
+ if pkg == nil || obj.pkg == nil {
+ return pkg == obj.pkg
+ }
+ // pkg != nil && obj.pkg != nil
+ return pkg.path == obj.pkg.path
+}
+
+// A PkgName represents an imported Go package.
+type PkgName struct {
+ object
+ imported *Package
+ used bool // set if the package was used
+}
+
+func NewPkgName(pos token.Pos, pkg *Package, name string, imported *Package) *PkgName {
+ return &PkgName{object{nil, pos, pkg, name, Typ[Invalid], 0, token.NoPos}, imported, false}
+}
+
+// Imported returns the package that was imported.
+// It is distinct from Pkg(), which is the package containing the import statement.
+func (obj *PkgName) Imported() *Package { return obj.imported }
+
+// A Const represents a declared constant.
+type Const struct {
+ object
+ val exact.Value
+ visited bool // for initialization cycle detection
+}
+
+func NewConst(pos token.Pos, pkg *Package, name string, typ Type, val exact.Value) *Const {
+ return &Const{object{nil, pos, pkg, name, typ, 0, token.NoPos}, val, false}
+}
+
+func (obj *Const) Val() exact.Value { return obj.val }
+
+// A TypeName represents a declared type.
+type TypeName struct {
+ object
+}
+
+func NewTypeName(pos token.Pos, pkg *Package, name string, typ Type) *TypeName {
+ return &TypeName{object{nil, pos, pkg, name, typ, 0, token.NoPos}}
+}
+
+// A Variable represents a declared variable (including function parameters and results, and struct fields).
+type Var struct {
+ object
+ anonymous bool // if set, the variable is an anonymous struct field, and name is the type name
+ visited bool // for initialization cycle detection
+ isField bool // var is struct field
+ used bool // set if the variable was used
+}
+
+func NewVar(pos token.Pos, pkg *Package, name string, typ Type) *Var {
+ return &Var{object: object{nil, pos, pkg, name, typ, 0, token.NoPos}}
+}
+
+func NewParam(pos token.Pos, pkg *Package, name string, typ Type) *Var {
+ return &Var{object: object{nil, pos, pkg, name, typ, 0, token.NoPos}, used: true} // parameters are always 'used'
+}
+
+func NewField(pos token.Pos, pkg *Package, name string, typ Type, anonymous bool) *Var {
+ return &Var{object: object{nil, pos, pkg, name, typ, 0, token.NoPos}, anonymous: anonymous, isField: true}
+}
+
+func (obj *Var) Anonymous() bool { return obj.anonymous }
+
+func (obj *Var) IsField() bool { return obj.isField }
+
+// A Func represents a declared function, concrete method, or abstract
+// (interface) method. Its Type() is always a *Signature.
+// An abstract method may belong to many interfaces due to embedding.
+type Func struct {
+ object
+}
+
+func NewFunc(pos token.Pos, pkg *Package, name string, sig *Signature) *Func {
+ // don't store a nil signature
+ var typ Type
+ if sig != nil {
+ typ = sig
+ }
+ return &Func{object{nil, pos, pkg, name, typ, 0, token.NoPos}}
+}
+
+// FullName returns the package- or receiver-type-qualified name of
+// function or method obj.
+func (obj *Func) FullName() string {
+ var buf bytes.Buffer
+ writeFuncName(&buf, obj, nil)
+ return buf.String()
+}
+
+func (obj *Func) Scope() *Scope {
+ return obj.typ.(*Signature).scope
+}
+
+// A Label represents a declared label.
+type Label struct {
+ object
+ used bool // set if the label was used
+}
+
+func NewLabel(pos token.Pos, pkg *Package, name string) *Label {
+ return &Label{object{pos: pos, pkg: pkg, name: name, typ: Typ[Invalid]}, false}
+}
+
+// A Builtin represents a built-in function.
+// Builtins don't have a valid type.
+type Builtin struct {
+ object
+ id builtinId
+}
+
+func newBuiltin(id builtinId) *Builtin {
+ return &Builtin{object{name: predeclaredFuncs[id].name, typ: Typ[Invalid]}, id}
+}
+
+// Nil represents the predeclared value nil.
+type Nil struct {
+ object
+}
+
+func writeObject(buf *bytes.Buffer, obj Object, qf Qualifier) {
+ typ := obj.Type()
+ switch obj := obj.(type) {
+ case *PkgName:
+ fmt.Fprintf(buf, "package %s", obj.Name())
+ if path := obj.imported.path; path != "" && path != obj.name {
+ fmt.Fprintf(buf, " (%q)", path)
+ }
+ return
+
+ case *Const:
+ buf.WriteString("const")
+
+ case *TypeName:
+ buf.WriteString("type")
+ typ = typ.Underlying()
+
+ case *Var:
+ if obj.isField {
+ buf.WriteString("field")
+ } else {
+ buf.WriteString("var")
+ }
+
+ case *Func:
+ buf.WriteString("func ")
+ writeFuncName(buf, obj, qf)
+ if typ != nil {
+ WriteSignature(buf, typ.(*Signature), qf)
+ }
+ return
+
+ case *Label:
+ buf.WriteString("label")
+ typ = nil
+
+ case *Builtin:
+ buf.WriteString("builtin")
+ typ = nil
+
+ case *Nil:
+ buf.WriteString("nil")
+ return
+
+ default:
+ panic(fmt.Sprintf("writeObject(%T)", obj))
+ }
+
+ buf.WriteByte(' ')
+
+ // For package-level objects, qualify the name.
+ if obj.Pkg() != nil && obj.Pkg().scope.Lookup(obj.Name()) == obj {
+ writePackage(buf, obj.Pkg(), qf)
+ }
+ buf.WriteString(obj.Name())
+ if typ != nil {
+ buf.WriteByte(' ')
+ WriteType(buf, typ, qf)
+ }
+}
+
+func writePackage(buf *bytes.Buffer, pkg *Package, qf Qualifier) {
+ if pkg == nil {
+ return
+ }
+ var s string
+ if qf != nil {
+ s = qf(pkg)
+ } else {
+ s = pkg.Path()
+ }
+ if s != "" {
+ buf.WriteString(s)
+ buf.WriteByte('.')
+ }
+}
+
+// ObjectString returns the string form of obj.
+// The Qualifier controls the printing of
+// package-level objects, and may be nil.
+func ObjectString(obj Object, qf Qualifier) string {
+ var buf bytes.Buffer
+ writeObject(&buf, obj, qf)
+ return buf.String()
+}
+
+func (obj *PkgName) String() string { return ObjectString(obj, nil) }
+func (obj *Const) String() string { return ObjectString(obj, nil) }
+func (obj *TypeName) String() string { return ObjectString(obj, nil) }
+func (obj *Var) String() string { return ObjectString(obj, nil) }
+func (obj *Func) String() string { return ObjectString(obj, nil) }
+func (obj *Label) String() string { return ObjectString(obj, nil) }
+func (obj *Builtin) String() string { return ObjectString(obj, nil) }
+func (obj *Nil) String() string { return ObjectString(obj, nil) }
+
+func writeFuncName(buf *bytes.Buffer, f *Func, qf Qualifier) {
+ if f.typ != nil {
+ sig := f.typ.(*Signature)
+ if recv := sig.Recv(); recv != nil {
+ buf.WriteByte('(')
+ if _, ok := recv.Type().(*Interface); ok {
+ // gcimporter creates abstract methods of
+ // named interfaces using the interface type
+ // (not the named type) as the receiver.
+ // Don't print it in full.
+ buf.WriteString("interface")
+ } else {
+ WriteType(buf, recv.Type(), qf)
+ }
+ buf.WriteByte(')')
+ buf.WriteByte('.')
+ } else if f.pkg != nil {
+ writePackage(buf, f.pkg, qf)
+ }
+ }
+ buf.WriteString(f.name)
+}
diff --git a/go/types/objset.go b/go/types/objset.go
new file mode 100644
index 0000000..55eb74a
--- /dev/null
+++ b/go/types/objset.go
@@ -0,0 +1,31 @@
+// 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 objsets.
+//
+// An objset is similar to a Scope but objset elements
+// are identified by their unique id, instead of their
+// object name.
+
+package types
+
+// An objset is a set of objects identified by their unique id.
+// The zero value for objset is a ready-to-use empty objset.
+type objset map[string]Object // initialized lazily
+
+// insert attempts to insert an object obj into objset s.
+// If s already contains an alternative object alt with
+// the same name, insert leaves s unchanged and returns alt.
+// Otherwise it inserts obj and returns nil.
+func (s *objset) insert(obj Object) Object {
+ id := obj.Id()
+ if alt := (*s)[id]; alt != nil {
+ return alt
+ }
+ if *s == nil {
+ *s = make(map[string]Object)
+ }
+ (*s)[id] = obj
+ return nil
+}
diff --git a/go/types/operand.go b/go/types/operand.go
new file mode 100644
index 0000000..d52b30e
--- /dev/null
+++ b/go/types/operand.go
@@ -0,0 +1,288 @@
+// 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 defines operands and associated operations.
+
+package types
+
+import (
+ "bytes"
+ "go/ast"
+ "go/token"
+
+ "golang.org/x/tools/go/exact"
+)
+
+// An operandMode specifies the (addressing) mode of an operand.
+type operandMode byte
+
+const (
+ invalid operandMode = iota // operand is invalid
+ novalue // operand represents no value (result of a function call w/o result)
+ builtin // operand is a built-in function
+ typexpr // operand is a type
+ constant // operand is a constant; the operand's typ is a Basic type
+ variable // operand is an addressable variable
+ mapindex // operand is a map index expression (acts like a variable on lhs, commaok on rhs of an assignment)
+ value // operand is a computed value
+ commaok // like value, but operand may be used in a comma,ok expression
+)
+
+var operandModeString = [...]string{
+ invalid: "invalid operand",
+ novalue: "no value",
+ builtin: "built-in",
+ typexpr: "type",
+ constant: "constant",
+ variable: "variable",
+ mapindex: "map index expression",
+ value: "value",
+ commaok: "comma, ok expression",
+}
+
+// An operand represents an intermediate value during type checking.
+// Operands have an (addressing) mode, the expression evaluating to
+// the operand, the operand's type, a value for constants, and an id
+// for built-in functions.
+// The zero value of operand is a ready to use invalid operand.
+//
+type operand struct {
+ mode operandMode
+ expr ast.Expr
+ typ Type
+ val exact.Value
+ id builtinId
+}
+
+// pos returns the position of the expression corresponding to x.
+// If x is invalid the position is token.NoPos.
+//
+func (x *operand) pos() token.Pos {
+ // x.expr may not be set if x is invalid
+ if x.expr == nil {
+ return token.NoPos
+ }
+ return x.expr.Pos()
+}
+
+// Operand string formats
+// (not all "untyped" cases can appear due to the type system,
+// but they fall out naturally here)
+//
+// mode format
+//
+// invalid <expr> ( <mode> )
+// novalue <expr> ( <mode> )
+// builtin <expr> ( <mode> )
+// typexpr <expr> ( <mode> )
+//
+// constant <expr> (<untyped kind> <mode> )
+// constant <expr> ( <mode> of type <typ>)
+// constant <expr> (<untyped kind> <mode> <val> )
+// constant <expr> ( <mode> <val> of type <typ>)
+//
+// variable <expr> (<untyped kind> <mode> )
+// variable <expr> ( <mode> of type <typ>)
+//
+// mapindex <expr> (<untyped kind> <mode> )
+// mapindex <expr> ( <mode> of type <typ>)
+//
+// value <expr> (<untyped kind> <mode> )
+// value <expr> ( <mode> of type <typ>)
+//
+// commaok <expr> (<untyped kind> <mode> )
+// commaok <expr> ( <mode> of type <typ>)
+//
+func operandString(x *operand, qf Qualifier) string {
+ var buf bytes.Buffer
+
+ var expr string
+ if x.expr != nil {
+ expr = ExprString(x.expr)
+ } else {
+ switch x.mode {
+ case builtin:
+ expr = predeclaredFuncs[x.id].name
+ case typexpr:
+ expr = TypeString(x.typ, qf)
+ case constant:
+ expr = x.val.String()
+ }
+ }
+
+ // <expr> (
+ if expr != "" {
+ buf.WriteString(expr)
+ buf.WriteString(" (")
+ }
+
+ // <untyped kind>
+ hasType := false
+ switch x.mode {
+ case invalid, novalue, builtin, typexpr:
+ // no type
+ default:
+ // has type
+ if isUntyped(x.typ) {
+ buf.WriteString(x.typ.(*Basic).name)
+ buf.WriteByte(' ')
+ break
+ }
+ hasType = true
+ }
+
+ // <mode>
+ buf.WriteString(operandModeString[x.mode])
+
+ // <val>
+ if x.mode == constant {
+ if s := x.val.String(); s != expr {
+ buf.WriteByte(' ')
+ buf.WriteString(s)
+ }
+ }
+
+ // <typ>
+ if hasType {
+ if x.typ != Typ[Invalid] {
+ buf.WriteString(" of type ")
+ WriteType(&buf, x.typ, qf)
+ } else {
+ buf.WriteString(" with invalid type")
+ }
+ }
+
+ // )
+ if expr != "" {
+ buf.WriteByte(')')
+ }
+
+ return buf.String()
+}
+
+func (x *operand) String() string {
+ return operandString(x, nil)
+}
+
+// setConst sets x to the untyped constant for literal lit.
+func (x *operand) setConst(tok token.Token, lit string) {
+ val := exact.MakeFromLiteral(lit, tok)
+ if val == nil {
+ // TODO(gri) Should we make it an unknown constant instead?
+ x.mode = invalid
+ return
+ }
+
+ var kind BasicKind
+ switch tok {
+ case token.INT:
+ kind = UntypedInt
+ case token.FLOAT:
+ kind = UntypedFloat
+ case token.IMAG:
+ kind = UntypedComplex
+ case token.CHAR:
+ kind = UntypedRune
+ case token.STRING:
+ kind = UntypedString
+ }
+
+ x.mode = constant
+ x.typ = Typ[kind]
+ x.val = val
+}
+
+// isNil reports whether x is the nil value.
+func (x *operand) isNil() bool {
+ return x.mode == value && x.typ == Typ[UntypedNil]
+}
+
+// TODO(gri) The functions operand.assignableTo, checker.convertUntyped,
+// checker.representable, and checker.assignment are
+// overlapping in functionality. Need to simplify and clean up.
+
+// assignableTo reports whether x is assignable to a variable of type T.
+func (x *operand) assignableTo(conf *Config, T Type) bool {
+ if x.mode == invalid || T == Typ[Invalid] {
+ return true // avoid spurious errors
+ }
+
+ V := x.typ
+
+ // x's type is identical to T
+ if Identical(V, T) {
+ return true
+ }
+
+ Vu := V.Underlying()
+ Tu := T.Underlying()
+
+ // T is an interface type and x implements T
+ // (Do this check first as it might succeed early.)
+ if Ti, ok := Tu.(*Interface); ok {
+ if Implements(x.typ, Ti) {
+ return true
+ }
+ }
+
+ // x's type V and T have identical underlying types
+ // and at least one of V or T is not a named type
+ if Identical(Vu, Tu) && (!isNamed(V) || !isNamed(T)) {
+ return true
+ }
+
+ // x is a bidirectional channel value, T is a channel
+ // type, x's type V and T have identical element types,
+ // and at least one of V or T is not a named type
+ if Vc, ok := Vu.(*Chan); ok && Vc.dir == SendRecv {
+ if Tc, ok := Tu.(*Chan); ok && Identical(Vc.elem, Tc.elem) {
+ return !isNamed(V) || !isNamed(T)
+ }
+ }
+
+ // x is the predeclared identifier nil and T is a pointer,
+ // function, slice, map, channel, or interface type
+ if x.isNil() {
+ switch t := Tu.(type) {
+ case *Basic:
+ if t.kind == UnsafePointer {
+ return true
+ }
+ case *Pointer, *Signature, *Slice, *Map, *Chan, *Interface:
+ return true
+ }
+ return false
+ }
+
+ // x is an untyped constant representable by a value of type T
+ // TODO(gri) This is borrowing from checker.convertUntyped and
+ // checker.representable. Need to clean up.
+ if isUntyped(Vu) {
+ switch t := Tu.(type) {
+ case *Basic:
+ if x.mode == constant {
+ return representableConst(x.val, conf, t.kind, nil)
+ }
+ // The result of a comparison is an untyped boolean,
+ // but may not be a constant.
+ if Vb, _ := Vu.(*Basic); Vb != nil {
+ return Vb.kind == UntypedBool && isBoolean(Tu)
+ }
+ case *Interface:
+ return x.isNil() || t.Empty()
+ case *Pointer, *Signature, *Slice, *Map, *Chan:
+ return x.isNil()
+ }
+ }
+
+ return false
+}
+
+// isInteger reports whether x is a value of integer type
+// or an untyped constant representable as an integer.
+func (x *operand) isInteger() bool {
+ return x.mode == invalid ||
+ isInteger(x.typ) ||
+ isUntyped(x.typ) && x.mode == constant && representableConst(x.val, nil, UntypedInt, nil) // no *Config required for UntypedInt
+}
diff --git a/go/types/ordering.go b/go/types/ordering.go
new file mode 100644
index 0000000..6bb98f2
--- /dev/null
+++ b/go/types/ordering.go
@@ -0,0 +1,127 @@
+// 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 resolveOrder.
+
+package types
+
+import (
+ "go/ast"
+ "sort"
+)
+
+// resolveOrder computes the order in which package-level objects
+// must be type-checked.
+//
+// Interface types appear first in the list, sorted topologically
+// by dependencies on embedded interfaces that are also declared
+// in this package, followed by all other objects sorted in source
+// order.
+//
+// TODO(gri) Consider sorting all types by dependencies here, and
+// in the process check _and_ report type cycles. This may simplify
+// the full type-checking phase.
+//
+func (check *Checker) resolveOrder() []Object {
+ var ifaces, others []Object
+
+ // collect interface types with their dependencies, and all other objects
+ for obj := range check.objMap {
+ if ityp := check.interfaceFor(obj); ityp != nil {
+ ifaces = append(ifaces, obj)
+ // determine dependencies on embedded interfaces
+ for _, f := range ityp.Methods.List {
+ if len(f.Names) == 0 {
+ // Embedded interface: The type must be a (possibly
+ // qualified) identifier denoting another interface.
+ // Imported interfaces are already fully resolved,
+ // so we can ignore qualified identifiers.
+ if ident, _ := f.Type.(*ast.Ident); ident != nil {
+ embedded := check.pkg.scope.Lookup(ident.Name)
+ if check.interfaceFor(embedded) != nil {
+ check.objMap[obj].addDep(embedded)
+ }
+ }
+ }
+ }
+ } else {
+ others = append(others, obj)
+ }
+ }
+
+ // final object order
+ var order []Object
+
+ // sort interface types topologically by dependencies,
+ // and in source order if there are no dependencies
+ sort.Sort(inSourceOrder(ifaces))
+ if debug {
+ for _, obj := range ifaces {
+ assert(check.objMap[obj].mark == 0)
+ }
+ }
+ for _, obj := range ifaces {
+ check.appendInPostOrder(&order, obj)
+ }
+
+ // sort everything else in source order
+ sort.Sort(inSourceOrder(others))
+
+ return append(order, others...)
+}
+
+// interfaceFor returns the AST interface denoted by obj, or nil.
+func (check *Checker) interfaceFor(obj Object) *ast.InterfaceType {
+ tname, _ := obj.(*TypeName)
+ if tname == nil {
+ return nil // not a type
+ }
+ d := check.objMap[obj]
+ if d == nil {
+ check.dump("%s: %s should have been declared", obj.Pos(), obj.Name())
+ unreachable()
+ }
+ if d.typ == nil {
+ return nil // invalid AST - ignore (will be handled later)
+ }
+ ityp, _ := d.typ.(*ast.InterfaceType)
+ return ityp
+}
+
+func (check *Checker) appendInPostOrder(order *[]Object, obj Object) {
+ d := check.objMap[obj]
+ if d.mark != 0 {
+ // We've already seen this object; either because it's
+ // already added to order, or because we have a cycle.
+ // In both cases we stop. Cycle errors are reported
+ // when type-checking types.
+ return
+ }
+ d.mark = 1
+
+ for _, obj := range orderedSetObjects(d.deps) {
+ check.appendInPostOrder(order, obj)
+ }
+
+ *order = append(*order, obj)
+}
+
+func orderedSetObjects(set map[Object]bool) []Object {
+ list := make([]Object, len(set))
+ i := 0
+ for obj := range set {
+ // we don't care about the map element value
+ list[i] = obj
+ i++
+ }
+ sort.Sort(inSourceOrder(list))
+ return list
+}
+
+// inSourceOrder implements the sort.Sort interface.
+type inSourceOrder []Object
+
+func (a inSourceOrder) Len() int { return len(a) }
+func (a inSourceOrder) Less(i, j int) bool { return a[i].order() < a[j].order() }
+func (a inSourceOrder) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
diff --git a/go/types/package.go b/go/types/package.go
new file mode 100644
index 0000000..48fe839
--- /dev/null
+++ b/go/types/package.go
@@ -0,0 +1,65 @@
+// 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 types
+
+import (
+ "fmt"
+ "go/token"
+)
+
+// A Package describes a Go package.
+type Package struct {
+ path string
+ name string
+ scope *Scope
+ complete bool
+ imports []*Package
+ fake bool // scope lookup errors are silently dropped if package is fake (internal use only)
+}
+
+// NewPackage returns a new Package for the given package path and name;
+// the name must not be the blank identifier.
+// The package is not complete and contains no explicit imports.
+func NewPackage(path, name string) *Package {
+ if name == "_" {
+ panic("invalid package name _")
+ }
+ scope := NewScope(Universe, token.NoPos, token.NoPos, fmt.Sprintf("package %q", path))
+ return &Package{path: path, name: name, scope: scope}
+}
+
+// Path returns the package path.
+func (pkg *Package) Path() string { return pkg.path }
+
+// Name returns the package name.
+func (pkg *Package) Name() string { return pkg.name }
+
+// Scope returns the (complete or incomplete) package scope
+// holding the objects declared at package level (TypeNames,
+// Consts, Vars, and Funcs).
+func (pkg *Package) Scope() *Scope { return pkg.scope }
+
+// A package is complete if its scope contains (at least) all
+// exported objects; otherwise it is incomplete.
+func (pkg *Package) Complete() bool { return pkg.complete }
+
+// MarkComplete marks a package as complete.
+func (pkg *Package) MarkComplete() { pkg.complete = true }
+
+// Imports returns the list of packages directly imported by
+// pkg; the list is in source order. Package unsafe is excluded.
+//
+// If pkg was loaded from export data, Imports includes packages that
+// provide package-level objects referenced by pkg. This may be more or
+// less than the set of packages directly imported by pkg's source code.
+func (pkg *Package) Imports() []*Package { return pkg.imports }
+
+// SetImports sets the list of explicitly imported packages to list.
+// It is the caller's responsibility to make sure list elements are unique.
+func (pkg *Package) SetImports(list []*Package) { pkg.imports = list }
+
+func (pkg *Package) String() string {
+ return fmt.Sprintf("package %s (%q)", pkg.name, pkg.path)
+}
diff --git a/go/types/predicates.go b/go/types/predicates.go
new file mode 100644
index 0000000..993c6d2
--- /dev/null
+++ b/go/types/predicates.go
@@ -0,0 +1,309 @@
+// 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 implements commonly used type predicates.
+
+package types
+
+import "sort"
+
+func isNamed(typ Type) bool {
+ if _, ok := typ.(*Basic); ok {
+ return ok
+ }
+ _, ok := typ.(*Named)
+ return ok
+}
+
+func isBoolean(typ Type) bool {
+ t, ok := typ.Underlying().(*Basic)
+ return ok && t.info&IsBoolean != 0
+}
+
+func isInteger(typ Type) bool {
+ t, ok := typ.Underlying().(*Basic)
+ return ok && t.info&IsInteger != 0
+}
+
+func isUnsigned(typ Type) bool {
+ t, ok := typ.Underlying().(*Basic)
+ return ok && t.info&IsUnsigned != 0
+}
+
+func isFloat(typ Type) bool {
+ t, ok := typ.Underlying().(*Basic)
+ return ok && t.info&IsFloat != 0
+}
+
+func isComplex(typ Type) bool {
+ t, ok := typ.Underlying().(*Basic)
+ return ok && t.info&IsComplex != 0
+}
+
+func isNumeric(typ Type) bool {
+ t, ok := typ.Underlying().(*Basic)
+ return ok && t.info&IsNumeric != 0
+}
+
+func isString(typ Type) bool {
+ t, ok := typ.Underlying().(*Basic)
+ return ok && t.info&IsString != 0
+}
+
+func isTyped(typ Type) bool {
+ t, ok := typ.Underlying().(*Basic)
+ return !ok || t.info&IsUntyped == 0
+}
+
+func isUntyped(typ Type) bool {
+ t, ok := typ.Underlying().(*Basic)
+ return ok && t.info&IsUntyped != 0
+}
+
+func isOrdered(typ Type) bool {
+ t, ok := typ.Underlying().(*Basic)
+ return ok && t.info&IsOrdered != 0
+}
+
+func isConstType(typ Type) bool {
+ t, ok := typ.Underlying().(*Basic)
+ return ok && t.info&IsConstType != 0
+}
+
+// IsInterface reports whether typ is an interface type.
+func IsInterface(typ Type) bool {
+ _, ok := typ.Underlying().(*Interface)
+ return ok
+}
+
+// Comparable reports whether values of type T are comparable.
+func Comparable(T Type) bool {
+ switch t := T.Underlying().(type) {
+ case *Basic:
+ // assume invalid types to be comparable
+ // to avoid follow-up errors
+ return t.kind != UntypedNil
+ case *Pointer, *Interface, *Chan:
+ return true
+ case *Struct:
+ for _, f := range t.fields {
+ if !Comparable(f.typ) {
+ return false
+ }
+ }
+ return true
+ case *Array:
+ return Comparable(t.elem)
+ }
+ return false
+}
+
+// hasNil reports whether a type includes the nil value.
+func hasNil(typ Type) bool {
+ switch t := typ.Underlying().(type) {
+ case *Basic:
+ return t.kind == UnsafePointer
+ case *Slice, *Pointer, *Signature, *Interface, *Map, *Chan:
+ return true
+ }
+ return false
+}
+
+// Identical reports whether x and y are identical.
+func Identical(x, y Type) bool {
+ return identical(x, y, nil)
+}
+
+// An ifacePair is a node in a stack of interface type pairs compared for identity.
+type ifacePair struct {
+ x, y *Interface
+ prev *ifacePair
+}
+
+func (p *ifacePair) identical(q *ifacePair) bool {
+ return p.x == q.x && p.y == q.y || p.x == q.y && p.y == q.x
+}
+
+func identical(x, y Type, p *ifacePair) bool {
+ if x == y {
+ return true
+ }
+
+ switch x := x.(type) {
+ case *Basic:
+ // Basic types are singletons except for the rune and byte
+ // aliases, thus we cannot solely rely on the x == y check
+ // above.
+ if y, ok := y.(*Basic); ok {
+ return x.kind == y.kind
+ }
+
+ case *Array:
+ // Two array types are identical if they have identical element types
+ // and the same array length.
+ if y, ok := y.(*Array); ok {
+ return x.len == y.len && identical(x.elem, y.elem, p)
+ }
+
+ case *Slice:
+ // Two slice types are identical if they have identical element types.
+ if y, ok := y.(*Slice); ok {
+ return identical(x.elem, y.elem, p)
+ }
+
+ case *Struct:
+ // Two struct types are identical if they have the same sequence of fields,
+ // and if corresponding fields have the same names, and identical types,
+ // and identical tags. Two anonymous fields are considered to have the same
+ // name. Lower-case field names from different packages are always different.
+ if y, ok := y.(*Struct); ok {
+ if x.NumFields() == y.NumFields() {
+ for i, f := range x.fields {
+ g := y.fields[i]
+ if f.anonymous != g.anonymous ||
+ x.Tag(i) != y.Tag(i) ||
+ !f.sameId(g.pkg, g.name) ||
+ !identical(f.typ, g.typ, p) {
+ return false
+ }
+ }
+ return true
+ }
+ }
+
+ case *Pointer:
+ // Two pointer types are identical if they have identical base types.
+ if y, ok := y.(*Pointer); ok {
+ return identical(x.base, y.base, p)
+ }
+
+ case *Tuple:
+ // Two tuples types are identical if they have the same number of elements
+ // and corresponding elements have identical types.
+ if y, ok := y.(*Tuple); ok {
+ if x.Len() == y.Len() {
+ if x != nil {
+ for i, v := range x.vars {
+ w := y.vars[i]
+ if !identical(v.typ, w.typ, p) {
+ return false
+ }
+ }
+ }
+ return true
+ }
+ }
+
+ case *Signature:
+ // Two function types are identical if they have the same number of parameters
+ // and result values, corresponding parameter and result types are identical,
+ // and either both functions are variadic or neither is. Parameter and result
+ // names are not required to match.
+ if y, ok := y.(*Signature); ok {
+ return x.variadic == y.variadic &&
+ identical(x.params, y.params, p) &&
+ identical(x.results, y.results, p)
+ }
+
+ case *Interface:
+ // Two interface types are identical if they have the same set of methods with
+ // the same names and identical function types. Lower-case method names from
+ // different packages are always different. The order of the methods is irrelevant.
+ if y, ok := y.(*Interface); ok {
+ a := x.allMethods
+ b := y.allMethods
+ if len(a) == len(b) {
+ // Interface types are the only types where cycles can occur
+ // that are not "terminated" via named types; and such cycles
+ // can only be created via method parameter types that are
+ // anonymous interfaces (directly or indirectly) embedding
+ // the current interface. Example:
+ //
+ // type T interface {
+ // m() interface{T}
+ // }
+ //
+ // If two such (differently named) interfaces are compared,
+ // endless recursion occurs if the cycle is not detected.
+ //
+ // If x and y were compared before, they must be equal
+ // (if they were not, the recursion would have stopped);
+ // search the ifacePair stack for the same pair.
+ //
+ // This is a quadratic algorithm, but in practice these stacks
+ // are extremely short (bounded by the nesting depth of interface
+ // type declarations that recur via parameter types, an extremely
+ // rare occurrence). An alternative implementation might use a
+ // "visited" map, but that is probably less efficient overall.
+ q := &ifacePair{x, y, p}
+ for p != nil {
+ if p.identical(q) {
+ return true // same pair was compared before
+ }
+ p = p.prev
+ }
+ if debug {
+ assert(sort.IsSorted(byUniqueMethodName(a)))
+ assert(sort.IsSorted(byUniqueMethodName(b)))
+ }
+ for i, f := range a {
+ g := b[i]
+ if f.Id() != g.Id() || !identical(f.typ, g.typ, q) {
+ return false
+ }
+ }
+ return true
+ }
+ }
+
+ case *Map:
+ // Two map types are identical if they have identical key and value types.
+ if y, ok := y.(*Map); ok {
+ return identical(x.key, y.key, p) && identical(x.elem, y.elem, p)
+ }
+
+ case *Chan:
+ // Two channel types are identical if they have identical value types
+ // and the same direction.
+ if y, ok := y.(*Chan); ok {
+ return x.dir == y.dir && identical(x.elem, y.elem, p)
+ }
+
+ case *Named:
+ // Two named types are identical if their type names originate
+ // in the same type declaration.
+ if y, ok := y.(*Named); ok {
+ return x.obj == y.obj
+ }
+
+ default:
+ unreachable()
+ }
+
+ return false
+}
+
+// defaultType returns the default "typed" type for an "untyped" type;
+// it returns the incoming type for all other types. The default type
+// for untyped nil is untyped nil.
+//
+func defaultType(typ Type) Type {
+ if t, ok := typ.(*Basic); ok {
+ switch t.kind {
+ case UntypedBool:
+ return Typ[Bool]
+ case UntypedInt:
+ return Typ[Int]
+ case UntypedRune:
+ return universeRune // use 'rune' name
+ case UntypedFloat:
+ return Typ[Float64]
+ case UntypedComplex:
+ return Typ[Complex128]
+ case UntypedString:
+ return Typ[String]
+ }
+ }
+ return typ
+}
diff --git a/go/types/resolver.go b/go/types/resolver.go
new file mode 100644
index 0000000..374ffc2
--- /dev/null
+++ b/go/types/resolver.go
@@ -0,0 +1,453 @@
+// 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 types
+
+import (
+ "errors"
+ "fmt"
+ "go/ast"
+ "go/token"
+ pathLib "path"
+ "strconv"
+ "strings"
+ "unicode"
+
+ "golang.org/x/tools/go/exact"
+)
+
+// A declInfo describes a package-level const, type, var, or func declaration.
+type declInfo struct {
+ file *Scope // scope of file containing this declaration
+ lhs []*Var // lhs of n:1 variable declarations, or nil
+ typ ast.Expr // type, or nil
+ init ast.Expr // init expression, or nil
+ fdecl *ast.FuncDecl // func declaration, or nil
+
+ deps map[Object]bool // type and init dependencies; lazily allocated
+ mark int // for dependency analysis
+}
+
+// hasInitializer reports whether the declared object has an initialization
+// expression or function body.
+func (d *declInfo) hasInitializer() bool {
+ return d.init != nil || d.fdecl != nil && d.fdecl.Body != nil
+}
+
+// addDep adds obj as a dependency to d.
+func (d *declInfo) addDep(obj Object) {
+ m := d.deps
+ if m == nil {
+ m = make(map[Object]bool)
+ d.deps = m
+ }
+ m[obj] = true
+}
+
+// arityMatch checks that the lhs and rhs of a const or var decl
+// have the appropriate number of names and init exprs. For const
+// decls, init is the value spec providing the init exprs; for
+// var decls, init is nil (the init exprs are in s in this case).
+func (check *Checker) arityMatch(s, init *ast.ValueSpec) {
+ l := len(s.Names)
+ r := len(s.Values)
+ if init != nil {
+ r = len(init.Values)
+ }
+
+ switch {
+ case init == nil && r == 0:
+ // var decl w/o init expr
+ if s.Type == nil {
+ check.errorf(s.Pos(), "missing type or init expr")
+ }
+ case l < r:
+ if l < len(s.Values) {
+ // init exprs from s
+ n := s.Values[l]
+ check.errorf(n.Pos(), "extra init expr %s", n)
+ // TODO(gri) avoid declared but not used error here
+ } else {
+ // init exprs "inherited"
+ check.errorf(s.Pos(), "extra init expr at %s", init.Pos())
+ // TODO(gri) avoid declared but not used error here
+ }
+ case l > r && (init != nil || r != 1):
+ n := s.Names[r]
+ check.errorf(n.Pos(), "missing init expr for %s", n)
+ }
+}
+
+func validatedImportPath(path string) (string, error) {
+ s, err := strconv.Unquote(path)
+ if err != nil {
+ return "", err
+ }
+ if s == "" {
+ return "", fmt.Errorf("empty string")
+ }
+ const illegalChars = `!"#$%&'()*,:;<=>?[\]^{|}` + "`\uFFFD"
+ for _, r := range s {
+ if !unicode.IsGraphic(r) || unicode.IsSpace(r) || strings.ContainsRune(illegalChars, r) {
+ return s, fmt.Errorf("invalid character %#U", r)
+ }
+ }
+ return s, nil
+}
+
+// declarePkgObj declares obj in the package scope, records its ident -> obj mapping,
+// and updates check.objMap. The object must not be a function or method.
+func (check *Checker) declarePkgObj(ident *ast.Ident, obj Object, d *declInfo) {
+ assert(ident.Name == obj.Name())
+
+ // spec: "A package-scope or file-scope identifier with name init
+ // may only be declared to be a function with this (func()) signature."
+ if ident.Name == "init" {
+ check.errorf(ident.Pos(), "cannot declare init - must be func")
+ return
+ }
+
+ check.declare(check.pkg.scope, ident, obj, token.NoPos)
+ check.objMap[obj] = d
+ obj.setOrder(uint32(len(check.objMap)))
+}
+
+// filename returns a filename suitable for debugging output.
+func (check *Checker) filename(fileNo int) string {
+ file := check.files[fileNo]
+ if pos := file.Pos(); pos.IsValid() {
+ return check.fset.File(pos).Name()
+ }
+ return fmt.Sprintf("file[%d]", fileNo)
+}
+
+// collectObjects collects all file and package objects and inserts them
+// into their respective scopes. It also performs imports and associates
+// methods with receiver base type names.
+func (check *Checker) collectObjects() {
+ pkg := check.pkg
+
+ importer := check.conf.Import
+ if importer == nil {
+ if DefaultImport != nil {
+ importer = DefaultImport
+ } else {
+ // Panic if we encounter an import.
+ importer = func(map[string]*Package, string) (*Package, error) {
+ panic(`no Config.Import or DefaultImport (missing import _ "golang.org/x/tools/go/gcimporter"?)`)
+ }
+ }
+ }
+
+ // pkgImports is the set of packages already imported by any package file seen
+ // so far. Used to avoid duplicate entries in pkg.imports. Allocate and populate
+ // it (pkg.imports may not be empty if we are checking test files incrementally).
+ var pkgImports = make(map[*Package]bool)
+ for _, imp := range pkg.imports {
+ pkgImports[imp] = true
+ }
+
+ for fileNo, file := range check.files {
+ // The package identifier denotes the current package,
+ // but there is no corresponding package object.
+ check.recordDef(file.Name, nil)
+
+ // Use the actual source file extent rather than *ast.File extent since the
+ // latter doesn't include comments which appear at the start or end of the file.
+ // Be conservative and use the *ast.File extent if we don't have a *token.File.
+ pos, end := file.Pos(), file.End()
+ if f := check.fset.File(file.Pos()); f != nil {
+ pos, end = token.Pos(f.Base()), token.Pos(f.Base()+f.Size())
+ }
+ fileScope := NewScope(check.pkg.scope, pos, end, check.filename(fileNo))
+ check.recordScope(file, fileScope)
+
+ for _, decl := range file.Decls {
+ switch d := decl.(type) {
+ case *ast.BadDecl:
+ // ignore
+
+ case *ast.GenDecl:
+ var last *ast.ValueSpec // last ValueSpec with type or init exprs seen
+ for iota, spec := range d.Specs {
+ switch s := spec.(type) {
+ case *ast.ImportSpec:
+ // import package
+ var imp *Package
+ path, err := validatedImportPath(s.Path.Value)
+ if err != nil {
+ check.errorf(s.Path.Pos(), "invalid import path (%s)", err)
+ continue
+ }
+ if path == "C" && check.conf.FakeImportC {
+ // TODO(gri) shouldn't create a new one each time
+ imp = NewPackage("C", "C")
+ imp.fake = true
+ } else {
+ var err error
+ imp, err = importer(check.conf.Packages, path)
+ if imp == nil && err == nil {
+ err = errors.New("Config.Import returned nil but no error")
+ }
+ if err != nil {
+ check.errorf(s.Path.Pos(), "could not import %s (%s)", path, err)
+ continue
+ }
+ }
+
+ // add package to list of explicit imports
+ // (this functionality is provided as a convenience
+ // for clients; it is not needed for type-checking)
+ if !pkgImports[imp] {
+ pkgImports[imp] = true
+ if imp != Unsafe {
+ pkg.imports = append(pkg.imports, imp)
+ }
+ }
+
+ // local name overrides imported package name
+ name := imp.name
+ if s.Name != nil {
+ name = s.Name.Name
+ if name == "init" {
+ check.errorf(s.Name.Pos(), "cannot declare init - must be func")
+ continue
+ }
+ }
+
+ obj := NewPkgName(s.Pos(), pkg, name, imp)
+ if s.Name != nil {
+ // in a dot-import, the dot represents the package
+ check.recordDef(s.Name, obj)
+ } else {
+ check.recordImplicit(s, obj)
+ }
+
+ // add import to file scope
+ if name == "." {
+ // merge imported scope with file scope
+ for _, obj := range imp.scope.elems {
+ // A package scope may contain non-exported objects,
+ // do not import them!
+ if obj.Exported() {
+ // TODO(gri) When we import a package, we create
+ // a new local package object. We should do the
+ // same for each dot-imported object. That way
+ // they can have correct position information.
+ // (We must not modify their existing position
+ // information because the same package - found
+ // via Config.Packages - may be dot-imported in
+ // another package!)
+ check.declare(fileScope, nil, obj, token.NoPos)
+ check.recordImplicit(s, obj)
+ }
+ }
+ // add position to set of dot-import positions for this file
+ // (this is only needed for "imported but not used" errors)
+ check.addUnusedDotImport(fileScope, imp, s.Pos())
+ } else {
+ // declare imported package object in file scope
+ check.declare(fileScope, nil, obj, token.NoPos)
+ }
+
+ case *ast.ValueSpec:
+ switch d.Tok {
+ case token.CONST:
+ // determine which initialization expressions to use
+ switch {
+ case s.Type != nil || len(s.Values) > 0:
+ last = s
+ case last == nil:
+ last = new(ast.ValueSpec) // make sure last exists
+ }
+
+ // declare all constants
+ for i, name := range s.Names {
+ obj := NewConst(name.Pos(), pkg, name.Name, nil, exact.MakeInt64(int64(iota)))
+
+ var init ast.Expr
+ if i < len(last.Values) {
+ init = last.Values[i]
+ }
+
+ d := &declInfo{file: fileScope, typ: last.Type, init: init}
+ check.declarePkgObj(name, obj, d)
+ }
+
+ check.arityMatch(s, last)
+
+ case token.VAR:
+ lhs := make([]*Var, len(s.Names))
+ // If there's exactly one rhs initializer, use
+ // the same declInfo d1 for all lhs variables
+ // so that each lhs variable depends on the same
+ // rhs initializer (n:1 var declaration).
+ var d1 *declInfo
+ if len(s.Values) == 1 {
+ // The lhs elements are only set up after the for loop below,
+ // but that's ok because declareVar only collects the declInfo
+ // for a later phase.
+ d1 = &declInfo{file: fileScope, lhs: lhs, typ: s.Type, init: s.Values[0]}
+ }
+
+ // declare all variables
+ for i, name := range s.Names {
+ obj := NewVar(name.Pos(), pkg, name.Name, nil)
+ lhs[i] = obj
+
+ d := d1
+ if d == nil {
+ // individual assignments
+ var init ast.Expr
+ if i < len(s.Values) {
+ init = s.Values[i]
+ }
+ d = &declInfo{file: fileScope, typ: s.Type, init: init}
+ }
+
+ check.declarePkgObj(name, obj, d)
+ }
+
+ check.arityMatch(s, nil)
+
+ default:
+ check.invalidAST(s.Pos(), "invalid token %s", d.Tok)
+ }
+
+ case *ast.TypeSpec:
+ obj := NewTypeName(s.Name.Pos(), pkg, s.Name.Name, nil)
+ check.declarePkgObj(s.Name, obj, &declInfo{file: fileScope, typ: s.Type})
+
+ default:
+ check.invalidAST(s.Pos(), "unknown ast.Spec node %T", s)
+ }
+ }
+
+ case *ast.FuncDecl:
+ name := d.Name.Name
+ obj := NewFunc(d.Name.Pos(), pkg, name, nil)
+ if d.Recv == nil {
+ // regular function
+ if name == "init" {
+ // don't declare init functions in the package scope - they are invisible
+ obj.parent = pkg.scope
+ check.recordDef(d.Name, obj)
+ // init functions must have a body
+ if d.Body == nil {
+ check.softErrorf(obj.pos, "missing function body")
+ }
+ } else {
+ check.declare(pkg.scope, d.Name, obj, token.NoPos)
+ }
+ } else {
+ // method
+ check.recordDef(d.Name, obj)
+ // Associate method with receiver base type name, if possible.
+ // Ignore methods that have an invalid receiver, or a blank _
+ // receiver name. They will be type-checked later, with regular
+ // functions.
+ if list := d.Recv.List; len(list) > 0 {
+ typ := list[0].Type
+ if ptr, _ := typ.(*ast.StarExpr); ptr != nil {
+ typ = ptr.X
+ }
+ if base, _ := typ.(*ast.Ident); base != nil && base.Name != "_" {
+ check.assocMethod(base.Name, obj)
+ }
+ }
+ }
+ info := &declInfo{file: fileScope, fdecl: d}
+ check.objMap[obj] = info
+ obj.setOrder(uint32(len(check.objMap)))
+
+ default:
+ check.invalidAST(d.Pos(), "unknown ast.Decl node %T", d)
+ }
+ }
+ }
+
+ // verify that objects in package and file scopes have different names
+ for _, scope := range check.pkg.scope.children /* file scopes */ {
+ for _, obj := range scope.elems {
+ if alt := pkg.scope.Lookup(obj.Name()); alt != nil {
+ if pkg, ok := obj.(*PkgName); ok {
+ check.errorf(alt.Pos(), "%s already declared through import of %s", alt.Name(), pkg.Imported())
+ check.reportAltDecl(pkg)
+ } else {
+ check.errorf(alt.Pos(), "%s already declared through dot-import of %s", alt.Name(), obj.Pkg())
+ // TODO(gri) dot-imported objects don't have a position; reportAltDecl won't print anything
+ check.reportAltDecl(obj)
+ }
+ }
+ }
+ }
+}
+
+// packageObjects typechecks all package objects in objList, but not function bodies.
+func (check *Checker) packageObjects(objList []Object) {
+ // add new methods to already type-checked types (from a prior Checker.Files call)
+ for _, obj := range objList {
+ if obj, _ := obj.(*TypeName); obj != nil && obj.typ != nil {
+ check.addMethodDecls(obj)
+ }
+ }
+
+ // pre-allocate space for type declaration paths so that the underlying array is reused
+ typePath := make([]*TypeName, 0, 8)
+
+ for _, obj := range objList {
+ check.objDecl(obj, nil, typePath)
+ }
+
+ // At this point we may have a non-empty check.methods map; this means that not all
+ // entries were deleted at the end of typeDecl because the respective receiver base
+ // types were not found. In that case, an error was reported when declaring those
+ // methods. We can now safely discard this map.
+ check.methods = nil
+}
+
+// functionBodies typechecks all function bodies.
+func (check *Checker) functionBodies() {
+ for _, f := range check.funcs {
+ check.funcBody(f.decl, f.name, f.sig, f.body)
+ }
+}
+
+// unusedImports checks for unused imports.
+func (check *Checker) unusedImports() {
+ // if function bodies are not checked, packages' uses are likely missing - don't check
+ if check.conf.IgnoreFuncBodies {
+ return
+ }
+
+ // spec: "It is illegal (...) to directly import a package without referring to
+ // any of its exported identifiers. To import a package solely for its side-effects
+ // (initialization), use the blank identifier as explicit package name."
+
+ // check use of regular imported packages
+ for _, scope := range check.pkg.scope.children /* file scopes */ {
+ for _, obj := range scope.elems {
+ if obj, ok := obj.(*PkgName); ok {
+ // Unused "blank imports" are automatically ignored
+ // since _ identifiers are not entered into scopes.
+ if !obj.used {
+ path := obj.imported.path
+ base := pathLib.Base(path)
+ if obj.name == base {
+ check.softErrorf(obj.pos, "%q imported but not used", path)
+ } else {
+ check.softErrorf(obj.pos, "%q imported but not used as %s", path, obj.name)
+ }
+ }
+ }
+ }
+ }
+
+ // check use of dot-imported packages
+ for _, unusedDotImports := range check.unusedDotImports {
+ for pkg, pos := range unusedDotImports {
+ check.softErrorf(pos, "%q imported but not used", pkg.path)
+ }
+ }
+}
diff --git a/go/types/resolver_test.go b/go/types/resolver_test.go
new file mode 100644
index 0000000..2ef1f18
--- /dev/null
+++ b/go/types/resolver_test.go
@@ -0,0 +1,189 @@
+// 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 types_test
+
+import (
+ "fmt"
+ "go/ast"
+ "go/parser"
+ "go/token"
+ "sort"
+ "testing"
+
+ _ "golang.org/x/tools/go/gcimporter"
+ . "golang.org/x/tools/go/types"
+)
+
+func TestResolveIdents(t *testing.T) {
+ skipSpecialPlatforms(t)
+
+ sources := []string{
+ `
+ package p
+ import "fmt"
+ import "math"
+ const pi = math.Pi
+ func sin(x float64) float64 {
+ return math.Sin(x)
+ }
+ var Println = fmt.Println
+ `,
+ `
+ package p
+ import "fmt"
+ type errorStringer struct { fmt.Stringer; error }
+ func f() string {
+ _ = "foo"
+ return fmt.Sprintf("%d", g())
+ }
+ func g() (x int) { return }
+ `,
+ `
+ package p
+ import . "go/parser"
+ import "sync"
+ func h() Mode { return ImportsOnly }
+ var _, x int = 1, 2
+ func init() {}
+ type T struct{ *sync.Mutex; a, b, c int}
+ type I interface{ m() }
+ var _ = T{a: 1, b: 2, c: 3}
+ func (_ T) m() {}
+ func (T) _() {}
+ var i I
+ var _ = i.m
+ func _(s []int) { for i, x := range s { _, _ = i, x } }
+ func _(x interface{}) {
+ switch x := x.(type) {
+ case int:
+ _ = x
+ }
+ switch {} // implicit 'true' tag
+ }
+ `,
+ `
+ package p
+ type S struct{}
+ func (T) _() {}
+ func (T) _() {}
+ `,
+ `
+ package p
+ func _() {
+ L0:
+ L1:
+ goto L0
+ for {
+ goto L1
+ }
+ if true {
+ goto L2
+ }
+ L2:
+ }
+ `,
+ }
+
+ pkgnames := []string{
+ "fmt",
+ "math",
+ }
+
+ // parse package files
+ fset := token.NewFileSet()
+ var files []*ast.File
+ for i, src := range sources {
+ f, err := parser.ParseFile(fset, fmt.Sprintf("sources[%d]", i), src, parser.DeclarationErrors)
+ if err != nil {
+ t.Fatal(err)
+ }
+ files = append(files, f)
+ }
+
+ // resolve and type-check package AST
+ var conf Config
+ uses := make(map[*ast.Ident]Object)
+ defs := make(map[*ast.Ident]Object)
+ _, err := conf.Check("testResolveIdents", fset, files, &Info{Defs: defs, Uses: uses})
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ // check that all packages were imported
+ for _, name := range pkgnames {
+ if conf.Packages[name] == nil {
+ t.Errorf("package %s not imported", name)
+ }
+ }
+
+ // check that qualified identifiers are resolved
+ for _, f := range files {
+ ast.Inspect(f, func(n ast.Node) bool {
+ if s, ok := n.(*ast.SelectorExpr); ok {
+ if x, ok := s.X.(*ast.Ident); ok {
+ obj := uses[x]
+ if obj == nil {
+ t.Errorf("%s: unresolved qualified identifier %s", fset.Position(x.Pos()), x.Name)
+ return false
+ }
+ if _, ok := obj.(*PkgName); ok && uses[s.Sel] == nil {
+ t.Errorf("%s: unresolved selector %s", fset.Position(s.Sel.Pos()), s.Sel.Name)
+ return false
+ }
+ return false
+ }
+ return false
+ }
+ return true
+ })
+ }
+
+ for id, obj := range uses {
+ if obj == nil {
+ t.Errorf("%s: Uses[%s] == nil", fset.Position(id.Pos()), id.Name)
+ }
+ }
+
+ // check that each identifier in the source is found in uses or defs or both
+ var both []string
+ for _, f := range files {
+ ast.Inspect(f, func(n ast.Node) bool {
+ if x, ok := n.(*ast.Ident); ok {
+ var objects int
+ if _, found := uses[x]; found {
+ objects |= 1
+ delete(uses, x)
+ }
+ if _, found := defs[x]; found {
+ objects |= 2
+ delete(defs, x)
+ }
+ if objects == 0 {
+ t.Errorf("%s: unresolved identifier %s", fset.Position(x.Pos()), x.Name)
+ } else if objects == 3 {
+ both = append(both, x.Name)
+ }
+ return false
+ }
+ return true
+ })
+ }
+
+ // check the expected set of idents that are simultaneously uses and defs
+ sort.Strings(both)
+ if got, want := fmt.Sprint(both), "[Mutex Stringer error]"; got != want {
+ t.Errorf("simultaneous uses/defs = %s, want %s", got, want)
+ }
+
+ // any left-over identifiers didn't exist in the source
+ for x := range uses {
+ t.Errorf("%s: identifier %s not present in source", fset.Position(x.Pos()), x.Name)
+ }
+ for x := range defs {
+ t.Errorf("%s: identifier %s not present in source", fset.Position(x.Pos()), x.Name)
+ }
+
+ // TODO(gri) add tests to check ImplicitObj callbacks
+}
diff --git a/go/types/return.go b/go/types/return.go
new file mode 100644
index 0000000..6628985
--- /dev/null
+++ b/go/types/return.go
@@ -0,0 +1,185 @@
+// 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 isTerminating.
+
+package types
+
+import (
+ "go/ast"
+ "go/token"
+)
+
+// isTerminating reports if s is a terminating statement.
+// If s is labeled, label is the label name; otherwise s
+// is "".
+func (check *Checker) isTerminating(s ast.Stmt, label string) bool {
+ switch s := s.(type) {
+ default:
+ unreachable()
+
+ case *ast.BadStmt, *ast.DeclStmt, *ast.EmptyStmt, *ast.SendStmt,
+ *ast.IncDecStmt, *ast.AssignStmt, *ast.GoStmt, *ast.DeferStmt,
+ *ast.RangeStmt:
+ // no chance
+
+ case *ast.LabeledStmt:
+ return check.isTerminating(s.Stmt, s.Label.Name)
+
+ case *ast.ExprStmt:
+ // the predeclared (possibly parenthesized) panic() function is terminating
+ if call, _ := unparen(s.X).(*ast.CallExpr); call != nil {
+ if id, _ := call.Fun.(*ast.Ident); id != nil {
+ if _, obj := check.scope.LookupParent(id.Name, token.NoPos); obj != nil {
+ if b, _ := obj.(*Builtin); b != nil && b.id == _Panic {
+ return true
+ }
+ }
+ }
+ }
+
+ case *ast.ReturnStmt:
+ return true
+
+ case *ast.BranchStmt:
+ if s.Tok == token.GOTO || s.Tok == token.FALLTHROUGH {
+ return true
+ }
+
+ case *ast.BlockStmt:
+ return check.isTerminatingList(s.List, "")
+
+ case *ast.IfStmt:
+ if s.Else != nil &&
+ check.isTerminating(s.Body, "") &&
+ check.isTerminating(s.Else, "") {
+ return true
+ }
+
+ case *ast.SwitchStmt:
+ return check.isTerminatingSwitch(s.Body, label)
+
+ case *ast.TypeSwitchStmt:
+ return check.isTerminatingSwitch(s.Body, label)
+
+ case *ast.SelectStmt:
+ for _, s := range s.Body.List {
+ cc := s.(*ast.CommClause)
+ if !check.isTerminatingList(cc.Body, "") || hasBreakList(cc.Body, label, true) {
+ return false
+ }
+
+ }
+ return true
+
+ case *ast.ForStmt:
+ if s.Cond == nil && !hasBreak(s.Body, label, true) {
+ return true
+ }
+ }
+
+ return false
+}
+
+func (check *Checker) isTerminatingList(list []ast.Stmt, label string) bool {
+ n := len(list)
+ return n > 0 && check.isTerminating(list[n-1], label)
+}
+
+func (check *Checker) isTerminatingSwitch(body *ast.BlockStmt, label string) bool {
+ hasDefault := false
+ for _, s := range body.List {
+ cc := s.(*ast.CaseClause)
+ if cc.List == nil {
+ hasDefault = true
+ }
+ if !check.isTerminatingList(cc.Body, "") || hasBreakList(cc.Body, label, true) {
+ return false
+ }
+ }
+ return hasDefault
+}
+
+// TODO(gri) For nested breakable statements, the current implementation of hasBreak
+// will traverse the same subtree repeatedly, once for each label. Replace
+// with a single-pass label/break matching phase.
+
+// hasBreak reports if s is or contains a break statement
+// referring to the label-ed statement or implicit-ly the
+// closest outer breakable statement.
+func hasBreak(s ast.Stmt, label string, implicit bool) bool {
+ switch s := s.(type) {
+ default:
+ unreachable()
+
+ case *ast.BadStmt, *ast.DeclStmt, *ast.EmptyStmt, *ast.ExprStmt,
+ *ast.SendStmt, *ast.IncDecStmt, *ast.AssignStmt, *ast.GoStmt,
+ *ast.DeferStmt, *ast.ReturnStmt:
+ // no chance
+
+ case *ast.LabeledStmt:
+ return hasBreak(s.Stmt, label, implicit)
+
+ case *ast.BranchStmt:
+ if s.Tok == token.BREAK {
+ if s.Label == nil {
+ return implicit
+ }
+ if s.Label.Name == label {
+ return true
+ }
+ }
+
+ case *ast.BlockStmt:
+ return hasBreakList(s.List, label, implicit)
+
+ case *ast.IfStmt:
+ if hasBreak(s.Body, label, implicit) ||
+ s.Else != nil && hasBreak(s.Else, label, implicit) {
+ return true
+ }
+
+ case *ast.CaseClause:
+ return hasBreakList(s.Body, label, implicit)
+
+ case *ast.SwitchStmt:
+ if label != "" && hasBreak(s.Body, label, false) {
+ return true
+ }
+
+ case *ast.TypeSwitchStmt:
+ if label != "" && hasBreak(s.Body, label, false) {
+ return true
+ }
+
+ case *ast.CommClause:
+ return hasBreakList(s.Body, label, implicit)
+
+ case *ast.SelectStmt:
+ if label != "" && hasBreak(s.Body, label, false) {
+ return true
+ }
+
+ case *ast.ForStmt:
+ if label != "" && hasBreak(s.Body, label, false) {
+ return true
+ }
+
+ case *ast.RangeStmt:
+ if label != "" && hasBreak(s.Body, label, false) {
+ return true
+ }
+ }
+
+ return false
+}
+
+func hasBreakList(list []ast.Stmt, label string, implicit bool) bool {
+ for _, s := range list {
+ if hasBreak(s, label, implicit) {
+ return true
+ }
+ }
+ return false
+}
diff --git a/go/types/scope.go b/go/types/scope.go
new file mode 100644
index 0000000..3502840
--- /dev/null
+++ b/go/types/scope.go
@@ -0,0 +1,190 @@
+// 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 Scopes.
+
+package types
+
+import (
+ "bytes"
+ "fmt"
+ "go/token"
+ "io"
+ "sort"
+ "strings"
+)
+
+// TODO(gri) Provide scopes with a name or other mechanism so that
+// objects can use that information for better printing.
+
+// A Scope maintains a set of objects and links to its containing
+// (parent) and contained (children) scopes. Objects may be inserted
+// and looked up by name. The zero value for Scope is a ready-to-use
+// empty scope.
+type Scope struct {
+ parent *Scope
+ children []*Scope
+ elems map[string]Object // lazily allocated
+ pos, end token.Pos // scope extent; may be invalid
+ comment string // for debugging only
+}
+
+// NewScope returns a new, empty scope contained in the given parent
+// scope, if any. The comment is for debugging only.
+func NewScope(parent *Scope, pos, end token.Pos, comment string) *Scope {
+ s := &Scope{parent, nil, nil, pos, end, comment}
+ // don't add children to Universe scope!
+ if parent != nil && parent != Universe {
+ parent.children = append(parent.children, s)
+ }
+ return s
+}
+
+// Parent returns the scope's containing (parent) scope.
+func (s *Scope) Parent() *Scope { return s.parent }
+
+// Len() returns the number of scope elements.
+func (s *Scope) Len() int { return len(s.elems) }
+
+// Names returns the scope's element names in sorted order.
+func (s *Scope) Names() []string {
+ names := make([]string, len(s.elems))
+ i := 0
+ for name := range s.elems {
+ names[i] = name
+ i++
+ }
+ sort.Strings(names)
+ return names
+}
+
+// NumChildren() returns the number of scopes nested in s.
+func (s *Scope) NumChildren() int { return len(s.children) }
+
+// Child returns the i'th child scope for 0 <= i < NumChildren().
+func (s *Scope) Child(i int) *Scope { return s.children[i] }
+
+// Lookup returns the object in scope s with the given name if such an
+// object exists; otherwise the result is nil.
+func (s *Scope) Lookup(name string) Object {
+ return s.elems[name]
+}
+
+// LookupParent follows the parent chain of scopes starting with s until
+// it finds a scope where Lookup(name) returns a non-nil object, and then
+// returns that scope and object. If a valid position pos is provided,
+// only objects that were declared at or before pos are considered.
+// If no such scope and object exists, the result is (nil, nil).
+//
+// Note that obj.Parent() may be different from the returned scope if the
+// object was inserted into the scope and already had a parent at that
+// time (see Insert, below). This can only happen for dot-imported objects
+// whose scope is the scope of the package that exported them.
+func (s *Scope) LookupParent(name string, pos token.Pos) (*Scope, Object) {
+ for ; s != nil; s = s.parent {
+ if obj := s.elems[name]; obj != nil && (!pos.IsValid() || obj.scopePos() <= pos) {
+ return s, obj
+ }
+ }
+ return nil, nil
+}
+
+// Insert attempts to insert an object obj into scope s.
+// If s already contains an alternative object alt with
+// the same name, Insert leaves s unchanged and returns alt.
+// Otherwise it inserts obj, sets the object's parent scope
+// if not already set, and returns nil.
+func (s *Scope) Insert(obj Object) Object {
+ name := obj.Name()
+ if alt := s.elems[name]; alt != nil {
+ return alt
+ }
+ if s.elems == nil {
+ s.elems = make(map[string]Object)
+ }
+ s.elems[name] = obj
+ if obj.Parent() == nil {
+ obj.setParent(s)
+ }
+ return nil
+}
+
+// Pos and End describe the scope's source code extent [pos, end).
+// The results are guaranteed to be valid only if the type-checked
+// AST has complete position information. The extent is undefined
+// for Universe and package scopes.
+func (s *Scope) Pos() token.Pos { return s.pos }
+func (s *Scope) End() token.Pos { return s.end }
+
+// Contains returns true if pos is within the scope's extent.
+// The result is guaranteed to be valid only if the type-checked
+// AST has complete position information.
+func (s *Scope) Contains(pos token.Pos) bool {
+ return s.pos <= pos && pos < s.end
+}
+
+// Innermost returns the innermost (child) scope containing
+// pos. If pos is not within any scope, the result is nil.
+// The result is also nil for the Universe scope.
+// The result is guaranteed to be valid only if the type-checked
+// AST has complete position information.
+func (s *Scope) Innermost(pos token.Pos) *Scope {
+ // Package scopes do not have extents since they may be
+ // discontiguous, so iterate over the package's files.
+ if s.parent == Universe {
+ for _, s := range s.children {
+ if inner := s.Innermost(pos); inner != nil {
+ return inner
+ }
+ }
+ }
+
+ if s.Contains(pos) {
+ for _, s := range s.children {
+ if s.Contains(pos) {
+ return s.Innermost(pos)
+ }
+ }
+ return s
+ }
+ return nil
+}
+
+// WriteTo writes a string representation of the scope to w,
+// with the scope elements sorted by name.
+// The level of indentation is controlled by n >= 0, with
+// n == 0 for no indentation.
+// If recurse is set, it also writes nested (children) scopes.
+func (s *Scope) WriteTo(w io.Writer, n int, recurse bool) {
+ const ind = ". "
+ indn := strings.Repeat(ind, n)
+
+ fmt.Fprintf(w, "%s%s scope %p {", indn, s.comment, s)
+ if len(s.elems) == 0 {
+ fmt.Fprintf(w, "}\n")
+ return
+ }
+
+ fmt.Fprintln(w)
+ indn1 := indn + ind
+ for _, name := range s.Names() {
+ fmt.Fprintf(w, "%s%s\n", indn1, s.elems[name])
+ }
+
+ if recurse {
+ for _, s := range s.children {
+ fmt.Fprintln(w)
+ s.WriteTo(w, n+1, recurse)
+ }
+ }
+
+ fmt.Fprintf(w, "%s}", indn)
+}
+
+// String returns a string representation of the scope, for debugging.
+func (s *Scope) String() string {
+ var buf bytes.Buffer
+ s.WriteTo(&buf, 0, false)
+ return buf.String()
+}
diff --git a/go/types/selection.go b/go/types/selection.go
new file mode 100644
index 0000000..124e0d3
--- /dev/null
+++ b/go/types/selection.go
@@ -0,0 +1,143 @@
+// 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 Selections.
+
+package types
+
+import (
+ "bytes"
+ "fmt"
+)
+
+// SelectionKind describes the kind of a selector expression x.f
+// (excluding qualified identifiers).
+type SelectionKind int
+
+const (
+ FieldVal SelectionKind = iota // x.f is a struct field selector
+ MethodVal // x.f is a method selector
+ MethodExpr // x.f is a method expression
+)
+
+// A Selection describes a selector expression x.f.
+// For the declarations:
+//
+// type T struct{ x int; E }
+// type E struct{}
+// func (e E) m() {}
+// var p *T
+//
+// the following relations exist:
+//
+// Selector Kind Recv Obj Type Index Indirect
+//
+// p.x FieldVal T x int {0} true
+// p.m MethodVal *T m func (e *T) m() {1, 0} true
+// T.m MethodExpr T m func m(_ T) {1, 0} false
+//
+type Selection struct {
+ kind SelectionKind
+ recv Type // type of x
+ obj Object // object denoted by x.f
+ index []int // path from x to x.f
+ indirect bool // set if there was any pointer indirection on the path
+}
+
+// Kind returns the selection kind.
+func (s *Selection) Kind() SelectionKind { return s.kind }
+
+// Recv returns the type of x in x.f.
+func (s *Selection) Recv() Type { return s.recv }
+
+// Obj returns the object denoted by x.f; a *Var for
+// a field selection, and a *Func in all other cases.
+func (s *Selection) Obj() Object { return s.obj }
+
+// Type returns the type of x.f, which may be different from the type of f.
+// See Selection for more information.
+func (s *Selection) Type() Type {
+ switch s.kind {
+ case MethodVal:
+ // The type of x.f is a method with its receiver type set
+ // to the type of x.
+ sig := *s.obj.(*Func).typ.(*Signature)
+ recv := *sig.recv
+ recv.typ = s.recv
+ sig.recv = &recv
+ return &sig
+
+ case MethodExpr:
+ // The type of x.f is a function (without receiver)
+ // and an additional first argument with the same type as x.
+ // TODO(gri) Similar code is already in call.go - factor!
+ // TODO(gri) Compute this eagerly to avoid allocations.
+ sig := *s.obj.(*Func).typ.(*Signature)
+ arg0 := *sig.recv
+ sig.recv = nil
+ arg0.typ = s.recv
+ var params []*Var
+ if sig.params != nil {
+ params = sig.params.vars
+ }
+ sig.params = NewTuple(append([]*Var{&arg0}, params...)...)
+ return &sig
+ }
+
+ // In all other cases, the type of x.f is the type of x.
+ return s.obj.Type()
+}
+
+// Index describes the path from x to f in x.f.
+// The last index entry is the field or method index of the type declaring f;
+// either:
+//
+// 1) the list of declared methods of a named type; or
+// 2) the list of methods of an interface type; or
+// 3) the list of fields of a struct type.
+//
+// The earlier index entries are the indices of the embedded fields implicitly
+// traversed to get from (the type of) x to f, starting at embedding depth 0.
+func (s *Selection) Index() []int { return s.index }
+
+// Indirect reports whether any pointer indirection was required to get from
+// x to f in x.f.
+func (s *Selection) Indirect() bool { return s.indirect }
+
+func (s *Selection) String() string { return SelectionString(s, nil) }
+
+// SelectionString returns the string form of s.
+// The Qualifier controls the printing of
+// package-level objects, and may be nil.
+//
+// Examples:
+// "field (T) f int"
+// "method (T) f(X) Y"
+// "method expr (T) f(X) Y"
+//
+func SelectionString(s *Selection, qf Qualifier) string {
+ var k string
+ switch s.kind {
+ case FieldVal:
+ k = "field "
+ case MethodVal:
+ k = "method "
+ case MethodExpr:
+ k = "method expr "
+ default:
+ unreachable()
+ }
+ var buf bytes.Buffer
+ buf.WriteString(k)
+ buf.WriteByte('(')
+ WriteType(&buf, s.Recv(), qf)
+ fmt.Fprintf(&buf, ") %s", s.obj.Name())
+ if T := s.Type(); s.kind == FieldVal {
+ buf.WriteByte(' ')
+ WriteType(&buf, T, qf)
+ } else {
+ WriteSignature(&buf, T.(*Signature), qf)
+ }
+ return buf.String()
+}
diff --git a/go/types/self_test.go b/go/types/self_test.go
new file mode 100644
index 0000000..01d12c7
--- /dev/null
+++ b/go/types/self_test.go
@@ -0,0 +1,101 @@
+// 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 types_test
+
+import (
+ "flag"
+ "fmt"
+ "go/ast"
+ "go/parser"
+ "go/token"
+ "path/filepath"
+ "testing"
+ "time"
+
+ _ "golang.org/x/tools/go/gcimporter"
+ . "golang.org/x/tools/go/types"
+)
+
+var benchmark = flag.Bool("b", false, "run benchmarks")
+
+func TestSelf(t *testing.T) {
+ fset := token.NewFileSet()
+ files, err := pkgFiles(fset, ".")
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ _, err = Check("go/types", fset, files)
+ if err != nil {
+ // Importing go.tools/go/exact doensn't work in the
+ // build dashboard environment. Don't report an error
+ // for now so that the build remains green.
+ // TODO(gri) fix this
+ t.Log(err) // replace w/ t.Fatal eventually
+ return
+ }
+}
+
+func TestBenchmark(t *testing.T) {
+ if !*benchmark {
+ return
+ }
+
+ // We're not using testing's benchmarking mechanism directly
+ // because we want custom output.
+
+ for _, p := range []string{"types", "exact", "gcimporter"} {
+ path := filepath.Join("..", p)
+ runbench(t, path, false)
+ runbench(t, path, true)
+ fmt.Println()
+ }
+}
+
+func runbench(t *testing.T, path string, ignoreFuncBodies bool) {
+ fset := token.NewFileSet()
+ files, err := pkgFiles(fset, path)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ b := testing.Benchmark(func(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ conf := Config{IgnoreFuncBodies: ignoreFuncBodies}
+ conf.Check(path, fset, files, nil)
+ }
+ })
+
+ // determine line count
+ lines := 0
+ fset.Iterate(func(f *token.File) bool {
+ lines += f.LineCount()
+ return true
+ })
+
+ d := time.Duration(b.NsPerOp())
+ fmt.Printf(
+ "%s: %s for %d lines (%d lines/s), ignoreFuncBodies = %v\n",
+ filepath.Base(path), d, lines, int64(float64(lines)/d.Seconds()), ignoreFuncBodies,
+ )
+}
+
+func pkgFiles(fset *token.FileSet, path string) ([]*ast.File, error) {
+ filenames, err := pkgFilenames(path) // from stdlib_test.go
+ if err != nil {
+ return nil, err
+ }
+
+ var files []*ast.File
+ for _, filename := range filenames {
+ file, err := parser.ParseFile(fset, filename, nil, 0)
+ if err != nil {
+ return nil, err
+ }
+ files = append(files, file)
+ }
+
+ return files, nil
+}
diff --git a/go/types/sizes.go b/go/types/sizes.go
new file mode 100644
index 0000000..56fb310
--- /dev/null
+++ b/go/types/sizes.go
@@ -0,0 +1,211 @@
+// 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 Sizes.
+
+package types
+
+// Sizes defines the sizing functions for package unsafe.
+type Sizes interface {
+ // Alignof returns the alignment of a variable of type T.
+ // Alignof must implement the alignment guarantees required by the spec.
+ Alignof(T Type) int64
+
+ // Offsetsof returns the offsets of the given struct fields, in bytes.
+ // Offsetsof must implement the offset guarantees required by the spec.
+ Offsetsof(fields []*Var) []int64
+
+ // Sizeof returns the size of a variable of type T.
+ // Sizeof must implement the size guarantees required by the spec.
+ Sizeof(T Type) int64
+}
+
+// StdSizes is a convenience type for creating commonly used Sizes.
+// It makes the following simplifying assumptions:
+//
+// - The size of explicitly sized basic types (int16, etc.) is the
+// specified size.
+// - The size of strings and interfaces is 2*WordSize.
+// - The size of slices is 3*WordSize.
+// - The size of an array of n elements corresponds to the size of
+// a struct of n consecutive fields of the array's element type.
+// - The size of a struct is the offset of the last field plus that
+// field's size. As with all element types, if the struct is used
+// in an array its size must first be aligned to a multiple of the
+// struct's alignment.
+// - All other types have size WordSize.
+// - Arrays and structs are aligned per spec definition; all other
+// types are naturally aligned with a maximum alignment MaxAlign.
+//
+// *StdSizes implements Sizes.
+//
+type StdSizes struct {
+ WordSize int64 // word size in bytes - must be >= 4 (32bits)
+ MaxAlign int64 // maximum alignment in bytes - must be >= 1
+}
+
+func (s *StdSizes) Alignof(T Type) int64 {
+ // For arrays and structs, alignment is defined in terms
+ // of alignment of the elements and fields, respectively.
+ switch t := T.Underlying().(type) {
+ case *Array:
+ // spec: "For a variable x of array type: unsafe.Alignof(x)
+ // is the same as unsafe.Alignof(x[0]), but at least 1."
+ return s.Alignof(t.elem)
+ case *Struct:
+ // spec: "For a variable x of struct type: unsafe.Alignof(x)
+ // is the largest of the values unsafe.Alignof(x.f) for each
+ // field f of x, but at least 1."
+ max := int64(1)
+ for _, f := range t.fields {
+ if a := s.Alignof(f.typ); a > max {
+ max = a
+ }
+ }
+ return max
+ }
+ a := s.Sizeof(T) // may be 0
+ // spec: "For a variable x of any type: unsafe.Alignof(x) is at least 1."
+ if a < 1 {
+ return 1
+ }
+ if a > s.MaxAlign {
+ return s.MaxAlign
+ }
+ return a
+}
+
+func (s *StdSizes) Offsetsof(fields []*Var) []int64 {
+ offsets := make([]int64, len(fields))
+ var o int64
+ for i, f := range fields {
+ a := s.Alignof(f.typ)
+ o = align(o, a)
+ offsets[i] = o
+ o += s.Sizeof(f.typ)
+ }
+ return offsets
+}
+
+var basicSizes = [...]byte{
+ Bool: 1,
+ Int8: 1,
+ Int16: 2,
+ Int32: 4,
+ Int64: 8,
+ Uint8: 1,
+ Uint16: 2,
+ Uint32: 4,
+ Uint64: 8,
+ Float32: 4,
+ Float64: 8,
+ Complex64: 8,
+ Complex128: 16,
+}
+
+func (s *StdSizes) Sizeof(T Type) int64 {
+ switch t := T.Underlying().(type) {
+ case *Basic:
+ assert(isTyped(T))
+ k := t.kind
+ if int(k) < len(basicSizes) {
+ if s := basicSizes[k]; s > 0 {
+ return int64(s)
+ }
+ }
+ if k == String {
+ return s.WordSize * 2
+ }
+ case *Array:
+ n := t.len
+ if n == 0 {
+ return 0
+ }
+ a := s.Alignof(t.elem)
+ z := s.Sizeof(t.elem)
+ return align(z, a)*(n-1) + z
+ case *Slice:
+ return s.WordSize * 3
+ case *Struct:
+ n := t.NumFields()
+ if n == 0 {
+ return 0
+ }
+ offsets := t.offsets
+ if t.offsets == nil {
+ // compute offsets on demand
+ offsets = s.Offsetsof(t.fields)
+ t.offsets = offsets
+ }
+ return offsets[n-1] + s.Sizeof(t.fields[n-1].typ)
+ case *Interface:
+ return s.WordSize * 2
+ }
+ return s.WordSize // catch-all
+}
+
+// stdSizes is used if Config.Sizes == nil.
+var stdSizes = StdSizes{8, 8}
+
+func (conf *Config) alignof(T Type) int64 {
+ if s := conf.Sizes; s != nil {
+ if a := s.Alignof(T); a >= 1 {
+ return a
+ }
+ panic("Config.Sizes.Alignof returned an alignment < 1")
+ }
+ return stdSizes.Alignof(T)
+}
+
+func (conf *Config) offsetsof(T *Struct) []int64 {
+ offsets := T.offsets
+ if offsets == nil && T.NumFields() > 0 {
+ // compute offsets on demand
+ if s := conf.Sizes; s != nil {
+ offsets = s.Offsetsof(T.fields)
+ // sanity checks
+ if len(offsets) != T.NumFields() {
+ panic("Config.Sizes.Offsetsof returned the wrong number of offsets")
+ }
+ for _, o := range offsets {
+ if o < 0 {
+ panic("Config.Sizes.Offsetsof returned an offset < 0")
+ }
+ }
+ } else {
+ offsets = stdSizes.Offsetsof(T.fields)
+ }
+ T.offsets = offsets
+ }
+ return offsets
+}
+
+// offsetof returns the offset of the field specified via
+// the index sequence relative to typ. All embedded fields
+// must be structs (rather than pointer to structs).
+func (conf *Config) offsetof(typ Type, index []int) int64 {
+ var o int64
+ for _, i := range index {
+ s := typ.Underlying().(*Struct)
+ o += conf.offsetsof(s)[i]
+ typ = s.fields[i].typ
+ }
+ return o
+}
+
+func (conf *Config) sizeof(T Type) int64 {
+ if s := conf.Sizes; s != nil {
+ if z := s.Sizeof(T); z >= 0 {
+ return z
+ }
+ panic("Config.Sizes.Sizeof returned a size < 0")
+ }
+ return stdSizes.Sizeof(T)
+}
+
+// align returns the smallest y >= x such that y % a == 0.
+func align(x, a int64) int64 {
+ y := x + a - 1
+ return y - y%a
+}
diff --git a/go/types/stdlib_test.go b/go/types/stdlib_test.go
new file mode 100644
index 0000000..d6aa82a
--- /dev/null
+++ b/go/types/stdlib_test.go
@@ -0,0 +1,270 @@
+// 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 tests types.Check by using it to
+// typecheck the standard library and tests.
+
+package types_test
+
+import (
+ "fmt"
+ "go/ast"
+ "go/build"
+ "go/parser"
+ "go/scanner"
+ "go/token"
+ "io/ioutil"
+ "os"
+ "path/filepath"
+ "runtime"
+ "strings"
+ "testing"
+ "time"
+
+ _ "golang.org/x/tools/go/gcimporter"
+ . "golang.org/x/tools/go/types"
+)
+
+var (
+ pkgCount int // number of packages processed
+ start = time.Now()
+)
+
+func TestStdlib(t *testing.T) {
+ skipSpecialPlatforms(t)
+
+ walkDirs(t, filepath.Join(runtime.GOROOT(), "src"))
+ if testing.Verbose() {
+ fmt.Println(pkgCount, "packages typechecked in", time.Since(start))
+ }
+}
+
+// firstComment returns the contents of the first comment in
+// the given file, assuming there's one within the first KB.
+func firstComment(filename string) string {
+ f, err := os.Open(filename)
+ if err != nil {
+ return ""
+ }
+ defer f.Close()
+
+ var src [1 << 10]byte // read at most 1KB
+ n, _ := f.Read(src[:])
+
+ var s scanner.Scanner
+ s.Init(fset.AddFile("", fset.Base(), n), src[:n], nil, scanner.ScanComments)
+ for {
+ _, tok, lit := s.Scan()
+ switch tok {
+ case token.COMMENT:
+ // remove trailing */ of multi-line comment
+ if lit[1] == '*' {
+ lit = lit[:len(lit)-2]
+ }
+ return strings.TrimSpace(lit[2:])
+ case token.EOF:
+ return ""
+ }
+ }
+}
+
+func testTestDir(t *testing.T, path string, ignore ...string) {
+ files, err := ioutil.ReadDir(path)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ excluded := make(map[string]bool)
+ for _, filename := range ignore {
+ excluded[filename] = true
+ }
+
+ fset := token.NewFileSet()
+ for _, f := range files {
+ // filter directory contents
+ if f.IsDir() || !strings.HasSuffix(f.Name(), ".go") || excluded[f.Name()] {
+ continue
+ }
+
+ // get per-file instructions
+ expectErrors := false
+ filename := filepath.Join(path, f.Name())
+ if cmd := firstComment(filename); cmd != "" {
+ switch cmd {
+ case "skip", "compiledir":
+ continue // ignore this file
+ case "errorcheck":
+ expectErrors = true
+ }
+ }
+
+ // parse and type-check file
+ file, err := parser.ParseFile(fset, filename, nil, 0)
+ if err == nil {
+ _, err = Check(filename, fset, []*ast.File{file})
+ }
+
+ if expectErrors {
+ if err == nil {
+ t.Errorf("expected errors but found none in %s", filename)
+ }
+ } else {
+ if err != nil {
+ t.Error(err)
+ }
+ }
+ }
+}
+
+func TestStdTest(t *testing.T) {
+ skipSpecialPlatforms(t)
+
+ // test/recover4.go is only built for Linux and Darwin.
+ // TODO(gri) Remove once tests consider +build tags (issue 10370).
+ if runtime.GOOS != "linux" && runtime.GOOS != "darwin" {
+ return
+ }
+
+ testTestDir(t, filepath.Join(runtime.GOROOT(), "test"),
+ "cmplxdivide.go", // also needs file cmplxdivide1.go - ignore
+ "sigchld.go", // don't work on Windows; testTestDir should consult build tags
+ )
+}
+
+func TestStdFixed(t *testing.T) {
+ skipSpecialPlatforms(t)
+
+ testTestDir(t, filepath.Join(runtime.GOROOT(), "test", "fixedbugs"),
+ "bug248.go", "bug302.go", "bug369.go", // complex test instructions - ignore
+ "bug459.go", // possibly incorrect test - see issue 6703 (pending spec clarification)
+ "issue3924.go", // possibly incorrect test - see issue 6671 (pending spec clarification)
+ "issue6889.go", // gc-specific test
+ "issue7746.go", // large constants - consumes too much memory
+ "issue11326.go", // large constants
+ "issue11326b.go", // large constants
+ )
+}
+
+func TestStdKen(t *testing.T) {
+ skipSpecialPlatforms(t)
+
+ testTestDir(t, filepath.Join(runtime.GOROOT(), "test", "ken"))
+}
+
+// Package paths of excluded packages.
+var excluded = map[string]bool{
+ "builtin": true,
+}
+
+// typecheck typechecks the given package files.
+func typecheck(t *testing.T, path string, filenames []string) {
+ fset := token.NewFileSet()
+
+ // parse package files
+ var files []*ast.File
+ for _, filename := range filenames {
+ file, err := parser.ParseFile(fset, filename, nil, parser.AllErrors)
+ if err != nil {
+ // the parser error may be a list of individual errors; report them all
+ if list, ok := err.(scanner.ErrorList); ok {
+ for _, err := range list {
+ t.Error(err)
+ }
+ return
+ }
+ t.Error(err)
+ return
+ }
+
+ if testing.Verbose() {
+ if len(files) == 0 {
+ fmt.Println("package", file.Name.Name)
+ }
+ fmt.Println("\t", filename)
+ }
+
+ files = append(files, file)
+ }
+
+ // typecheck package files
+ var conf Config
+ conf.Error = func(err error) { t.Error(err) }
+ info := Info{Uses: make(map[*ast.Ident]Object)}
+ conf.Check(path, fset, files, &info)
+ pkgCount++
+
+ // Perform checks of API invariants.
+
+ // All Objects have a package, except predeclared ones.
+ errorError := Universe.Lookup("error").Type().Underlying().(*Interface).ExplicitMethod(0) // (error).Error
+ for id, obj := range info.Uses {
+ predeclared := obj == Universe.Lookup(obj.Name()) || obj == errorError
+ if predeclared == (obj.Pkg() != nil) {
+ posn := fset.Position(id.Pos())
+ if predeclared {
+ t.Errorf("%s: predeclared object with package: %s", posn, obj)
+ } else {
+ t.Errorf("%s: user-defined object without package: %s", posn, obj)
+ }
+ }
+ }
+}
+
+// pkgFilenames returns the list of package filenames for the given directory.
+func pkgFilenames(dir string) ([]string, error) {
+ ctxt := build.Default
+ ctxt.CgoEnabled = false
+ pkg, err := ctxt.ImportDir(dir, 0)
+ if err != nil {
+ if _, nogo := err.(*build.NoGoError); nogo {
+ return nil, nil // no *.go files, not an error
+ }
+ return nil, err
+ }
+ if excluded[pkg.ImportPath] {
+ return nil, nil
+ }
+ var filenames []string
+ for _, name := range pkg.GoFiles {
+ filenames = append(filenames, filepath.Join(pkg.Dir, name))
+ }
+ for _, name := range pkg.TestGoFiles {
+ filenames = append(filenames, filepath.Join(pkg.Dir, name))
+ }
+ return filenames, nil
+}
+
+// Note: Could use filepath.Walk instead of walkDirs but that wouldn't
+// necessarily be shorter or clearer after adding the code to
+// terminate early for -short tests.
+
+func walkDirs(t *testing.T, dir string) {
+ // limit run time for short tests
+ if testing.Short() && time.Since(start) >= 750*time.Millisecond {
+ return
+ }
+
+ fis, err := ioutil.ReadDir(dir)
+ if err != nil {
+ t.Error(err)
+ return
+ }
+
+ // typecheck package in directory
+ files, err := pkgFilenames(dir)
+ if err != nil {
+ t.Error(err)
+ return
+ }
+ if files != nil {
+ typecheck(t, dir, files)
+ }
+
+ // traverse subdirectories, but don't walk into testdata
+ for _, fi := range fis {
+ if fi.IsDir() && fi.Name() != "testdata" {
+ walkDirs(t, filepath.Join(dir, fi.Name()))
+ }
+ }
+}
diff --git a/go/types/stmt.go b/go/types/stmt.go
new file mode 100644
index 0000000..eeb2c31
--- /dev/null
+++ b/go/types/stmt.go
@@ -0,0 +1,745 @@
+// 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 implements typechecking of statements.
+
+package types
+
+import (
+ "fmt"
+ "go/ast"
+ "go/token"
+
+ "golang.org/x/tools/go/exact"
+)
+
+func (check *Checker) funcBody(decl *declInfo, name string, sig *Signature, body *ast.BlockStmt) {
+ if trace {
+ if name == "" {
+ name = "<function literal>"
+ }
+ fmt.Printf("--- %s: %s {\n", name, sig)
+ defer fmt.Println("--- <end>")
+ }
+
+ // set function scope extent
+ sig.scope.pos = body.Pos()
+ sig.scope.end = body.End()
+
+ // save/restore current context and setup function context
+ // (and use 0 indentation at function start)
+ defer func(ctxt context, indent int) {
+ check.context = ctxt
+ check.indent = indent
+ }(check.context, check.indent)
+ check.context = context{
+ decl: decl,
+ scope: sig.scope,
+ sig: sig,
+ }
+ check.indent = 0
+
+ check.stmtList(0, body.List)
+
+ if check.hasLabel {
+ check.labels(body)
+ }
+
+ if sig.results.Len() > 0 && !check.isTerminating(body, "") {
+ check.error(body.Rbrace, "missing return")
+ }
+
+ // spec: "Implementation restriction: A compiler may make it illegal to
+ // declare a variable inside a function body if the variable is never used."
+ // (One could check each scope after use, but that distributes this check
+ // over several places because CloseScope is not always called explicitly.)
+ check.usage(sig.scope)
+}
+
+func (check *Checker) usage(scope *Scope) {
+ for _, obj := range scope.elems {
+ if v, _ := obj.(*Var); v != nil && !v.used {
+ check.softErrorf(v.pos, "%s declared but not used", v.name)
+ }
+ }
+ for _, scope := range scope.children {
+ check.usage(scope)
+ }
+}
+
+// stmtContext is a bitset describing which
+// control-flow statements are permissible.
+type stmtContext uint
+
+const (
+ breakOk stmtContext = 1 << iota
+ continueOk
+ fallthroughOk
+)
+
+func (check *Checker) simpleStmt(s ast.Stmt) {
+ if s != nil {
+ check.stmt(0, s)
+ }
+}
+
+func (check *Checker) stmtList(ctxt stmtContext, list []ast.Stmt) {
+ ok := ctxt&fallthroughOk != 0
+ inner := ctxt &^ fallthroughOk
+ for i, s := range list {
+ inner := inner
+ if ok && i+1 == len(list) {
+ inner |= fallthroughOk
+ }
+ check.stmt(inner, s)
+ }
+}
+
+func (check *Checker) multipleDefaults(list []ast.Stmt) {
+ var first ast.Stmt
+ for _, s := range list {
+ var d ast.Stmt
+ switch c := s.(type) {
+ case *ast.CaseClause:
+ if len(c.List) == 0 {
+ d = s
+ }
+ case *ast.CommClause:
+ if c.Comm == nil {
+ d = s
+ }
+ default:
+ check.invalidAST(s.Pos(), "case/communication clause expected")
+ }
+ if d != nil {
+ if first != nil {
+ check.errorf(d.Pos(), "multiple defaults (first at %s)", first.Pos())
+ } else {
+ first = d
+ }
+ }
+ }
+}
+
+func (check *Checker) openScope(s ast.Stmt, comment string) {
+ scope := NewScope(check.scope, s.Pos(), s.End(), comment)
+ check.recordScope(s, scope)
+ check.scope = scope
+}
+
+func (check *Checker) closeScope() {
+ check.scope = check.scope.Parent()
+}
+
+func assignOp(op token.Token) token.Token {
+ // token_test.go verifies the token ordering this function relies on
+ if token.ADD_ASSIGN <= op && op <= token.AND_NOT_ASSIGN {
+ return op + (token.ADD - token.ADD_ASSIGN)
+ }
+ return token.ILLEGAL
+}
+
+func (check *Checker) suspendedCall(keyword string, call *ast.CallExpr) {
+ var x operand
+ var msg string
+ switch check.rawExpr(&x, call, nil) {
+ case conversion:
+ msg = "requires function call, not conversion"
+ case expression:
+ msg = "discards result of"
+ case statement:
+ return
+ default:
+ unreachable()
+ }
+ check.errorf(x.pos(), "%s %s %s", keyword, msg, &x)
+}
+
+func (check *Checker) caseValues(x operand /* copy argument (not *operand!) */, values []ast.Expr) {
+ // No duplicate checking for now. See issue 4524.
+ for _, e := range values {
+ var y operand
+ check.expr(&y, e)
+ if y.mode == invalid {
+ return
+ }
+ // TODO(gri) The convertUntyped call pair below appears in other places. Factor!
+ // Order matters: By comparing y against x, error positions are at the case values.
+ check.convertUntyped(&y, x.typ)
+ if y.mode == invalid {
+ return
+ }
+ check.convertUntyped(&x, y.typ)
+ if x.mode == invalid {
+ return
+ }
+ check.comparison(&y, &x, token.EQL)
+ }
+}
+
+func (check *Checker) caseTypes(x *operand, xtyp *Interface, types []ast.Expr, seen map[Type]token.Pos) (T Type) {
+L:
+ for _, e := range types {
+ T = check.typOrNil(e)
+ if T == Typ[Invalid] {
+ continue
+ }
+ // complain about duplicate types
+ // TODO(gri) use a type hash to avoid quadratic algorithm
+ for t, pos := range seen {
+ if T == nil && t == nil || T != nil && t != nil && Identical(T, t) {
+ // talk about "case" rather than "type" because of nil case
+ check.error(e.Pos(), "duplicate case in type switch")
+ check.errorf(pos, "\tprevious case %s", T) // secondary error, \t indented
+ continue L
+ }
+ }
+ seen[T] = e.Pos()
+ if T != nil {
+ check.typeAssertion(e.Pos(), x, xtyp, T)
+ }
+ }
+ return
+}
+
+// stmt typechecks statement s.
+func (check *Checker) stmt(ctxt stmtContext, s ast.Stmt) {
+ // statements cannot use iota in general
+ // (constant declarations set it explicitly)
+ assert(check.iota == nil)
+
+ // statements must end with the same top scope as they started with
+ if debug {
+ defer func(scope *Scope) {
+ // don't check if code is panicking
+ if p := recover(); p != nil {
+ panic(p)
+ }
+ assert(scope == check.scope)
+ }(check.scope)
+ }
+
+ inner := ctxt &^ fallthroughOk
+ switch s := s.(type) {
+ case *ast.BadStmt, *ast.EmptyStmt:
+ // ignore
+
+ case *ast.DeclStmt:
+ check.declStmt(s.Decl)
+
+ case *ast.LabeledStmt:
+ check.hasLabel = true
+ check.stmt(ctxt, s.Stmt)
+
+ case *ast.ExprStmt:
+ // spec: "With the exception of specific built-in functions,
+ // function and method calls and receive operations can appear
+ // in statement context. Such statements may be parenthesized."
+ var x operand
+ kind := check.rawExpr(&x, s.X, nil)
+ var msg string
+ switch x.mode {
+ default:
+ if kind == statement {
+ return
+ }
+ msg = "is not used"
+ case builtin:
+ msg = "must be called"
+ case typexpr:
+ msg = "is not an expression"
+ }
+ check.errorf(x.pos(), "%s %s", &x, msg)
+
+ case *ast.SendStmt:
+ var ch, x operand
+ check.expr(&ch, s.Chan)
+ check.expr(&x, s.Value)
+ if ch.mode == invalid || x.mode == invalid {
+ return
+ }
+ if tch, ok := ch.typ.Underlying().(*Chan); !ok || tch.dir == RecvOnly || !check.assignment(&x, tch.elem) {
+ if x.mode != invalid {
+ check.invalidOp(ch.pos(), "cannot send %s to channel %s", &x, &ch)
+ }
+ }
+
+ case *ast.IncDecStmt:
+ var op token.Token
+ switch s.Tok {
+ case token.INC:
+ op = token.ADD
+ case token.DEC:
+ op = token.SUB
+ default:
+ check.invalidAST(s.TokPos, "unknown inc/dec operation %s", s.Tok)
+ return
+ }
+ var x operand
+ Y := &ast.BasicLit{ValuePos: s.X.Pos(), Kind: token.INT, Value: "1"} // use x's position
+ check.binary(&x, nil, s.X, Y, op)
+ if x.mode == invalid {
+ return
+ }
+ check.assignVar(s.X, &x)
+
+ case *ast.AssignStmt:
+ switch s.Tok {
+ case token.ASSIGN, token.DEFINE:
+ if len(s.Lhs) == 0 {
+ check.invalidAST(s.Pos(), "missing lhs in assignment")
+ return
+ }
+ if s.Tok == token.DEFINE {
+ check.shortVarDecl(s.TokPos, s.Lhs, s.Rhs)
+ } else {
+ // regular assignment
+ check.assignVars(s.Lhs, s.Rhs)
+ }
+
+ default:
+ // assignment operations
+ if len(s.Lhs) != 1 || len(s.Rhs) != 1 {
+ check.errorf(s.TokPos, "assignment operation %s requires single-valued expressions", s.Tok)
+ return
+ }
+ op := assignOp(s.Tok)
+ if op == token.ILLEGAL {
+ check.invalidAST(s.TokPos, "unknown assignment operation %s", s.Tok)
+ return
+ }
+ var x operand
+ check.binary(&x, nil, s.Lhs[0], s.Rhs[0], op)
+ if x.mode == invalid {
+ return
+ }
+ check.assignVar(s.Lhs[0], &x)
+ }
+
+ case *ast.GoStmt:
+ check.suspendedCall("go", s.Call)
+
+ case *ast.DeferStmt:
+ check.suspendedCall("defer", s.Call)
+
+ case *ast.ReturnStmt:
+ res := check.sig.results
+ if res.Len() > 0 {
+ // function returns results
+ // (if one, say the first, result parameter is named, all of them are named)
+ if len(s.Results) == 0 && res.vars[0].name != "" {
+ // spec: "Implementation restriction: A compiler may disallow an empty expression
+ // list in a "return" statement if a different entity (constant, type, or variable)
+ // with the same name as a result parameter is in scope at the place of the return."
+ for _, obj := range res.vars {
+ if _, alt := check.scope.LookupParent(obj.name, check.pos); alt != nil && alt != obj {
+ check.errorf(s.Pos(), "result parameter %s not in scope at return", obj.name)
+ check.errorf(alt.Pos(), "\tinner declaration of %s", obj)
+ // ok to continue
+ }
+ }
+ } else {
+ // return has results or result parameters are unnamed
+ check.initVars(res.vars, s.Results, s.Return)
+ }
+ } else if len(s.Results) > 0 {
+ check.error(s.Results[0].Pos(), "no result values expected")
+ check.use(s.Results...)
+ }
+
+ case *ast.BranchStmt:
+ if s.Label != nil {
+ check.hasLabel = true
+ return // checked in 2nd pass (check.labels)
+ }
+ switch s.Tok {
+ case token.BREAK:
+ if ctxt&breakOk == 0 {
+ check.error(s.Pos(), "break not in for, switch, or select statement")
+ }
+ case token.CONTINUE:
+ if ctxt&continueOk == 0 {
+ check.error(s.Pos(), "continue not in for statement")
+ }
+ case token.FALLTHROUGH:
+ if ctxt&fallthroughOk == 0 {
+ check.error(s.Pos(), "fallthrough statement out of place")
+ }
+ default:
+ check.invalidAST(s.Pos(), "branch statement: %s", s.Tok)
+ }
+
+ case *ast.BlockStmt:
+ check.openScope(s, "block")
+ defer check.closeScope()
+
+ check.stmtList(inner, s.List)
+
+ case *ast.IfStmt:
+ check.openScope(s, "if")
+ defer check.closeScope()
+
+ check.simpleStmt(s.Init)
+ var x operand
+ check.expr(&x, s.Cond)
+ if x.mode != invalid && !isBoolean(x.typ) {
+ check.error(s.Cond.Pos(), "non-boolean condition in if statement")
+ }
+ check.stmt(inner, s.Body)
+ if s.Else != nil {
+ check.stmt(inner, s.Else)
+ }
+
+ case *ast.SwitchStmt:
+ inner |= breakOk
+ check.openScope(s, "switch")
+ defer check.closeScope()
+
+ check.simpleStmt(s.Init)
+ var x operand
+ if s.Tag != nil {
+ check.expr(&x, s.Tag)
+ } else {
+ // spec: "A missing switch expression is
+ // equivalent to the boolean value true."
+ x.mode = constant
+ x.typ = Typ[Bool]
+ x.val = exact.MakeBool(true)
+ x.expr = &ast.Ident{NamePos: s.Body.Lbrace, Name: "true"}
+ }
+
+ check.multipleDefaults(s.Body.List)
+
+ for i, c := range s.Body.List {
+ clause, _ := c.(*ast.CaseClause)
+ if clause == nil {
+ check.invalidAST(c.Pos(), "incorrect expression switch case")
+ continue
+ }
+ if x.mode != invalid {
+ check.caseValues(x, clause.List)
+ }
+ check.openScope(clause, "case")
+ inner := inner
+ if i+1 < len(s.Body.List) {
+ inner |= fallthroughOk
+ }
+ check.stmtList(inner, clause.Body)
+ check.closeScope()
+ }
+
+ case *ast.TypeSwitchStmt:
+ inner |= breakOk
+ check.openScope(s, "type switch")
+ defer check.closeScope()
+
+ check.simpleStmt(s.Init)
+
+ // A type switch guard must be of the form:
+ //
+ // TypeSwitchGuard = [ identifier ":=" ] PrimaryExpr "." "(" "type" ")" .
+ //
+ // The parser is checking syntactic correctness;
+ // remaining syntactic errors are considered AST errors here.
+ // TODO(gri) better factoring of error handling (invalid ASTs)
+ //
+ var lhs *ast.Ident // lhs identifier or nil
+ var rhs ast.Expr
+ switch guard := s.Assign.(type) {
+ case *ast.ExprStmt:
+ rhs = guard.X
+ case *ast.AssignStmt:
+ if len(guard.Lhs) != 1 || guard.Tok != token.DEFINE || len(guard.Rhs) != 1 {
+ check.invalidAST(s.Pos(), "incorrect form of type switch guard")
+ return
+ }
+
+ lhs, _ = guard.Lhs[0].(*ast.Ident)
+ if lhs == nil {
+ check.invalidAST(s.Pos(), "incorrect form of type switch guard")
+ return
+ }
+
+ if lhs.Name == "_" {
+ // _ := x.(type) is an invalid short variable declaration
+ check.softErrorf(lhs.Pos(), "no new variable on left side of :=")
+ lhs = nil // avoid declared but not used error below
+ } else {
+ check.recordDef(lhs, nil) // lhs variable is implicitly declared in each cause clause
+ }
+
+ rhs = guard.Rhs[0]
+
+ default:
+ check.invalidAST(s.Pos(), "incorrect form of type switch guard")
+ return
+ }
+
+ // rhs must be of the form: expr.(type) and expr must be an interface
+ expr, _ := rhs.(*ast.TypeAssertExpr)
+ if expr == nil || expr.Type != nil {
+ check.invalidAST(s.Pos(), "incorrect form of type switch guard")
+ return
+ }
+ var x operand
+ check.expr(&x, expr.X)
+ if x.mode == invalid {
+ return
+ }
+ xtyp, _ := x.typ.Underlying().(*Interface)
+ if xtyp == nil {
+ check.errorf(x.pos(), "%s is not an interface", &x)
+ return
+ }
+
+ check.multipleDefaults(s.Body.List)
+
+ var lhsVars []*Var // list of implicitly declared lhs variables
+ seen := make(map[Type]token.Pos) // map of seen types to positions
+ for _, s := range s.Body.List {
+ clause, _ := s.(*ast.CaseClause)
+ if clause == nil {
+ check.invalidAST(s.Pos(), "incorrect type switch case")
+ continue
+ }
+ // Check each type in this type switch case.
+ T := check.caseTypes(&x, xtyp, clause.List, seen)
+ check.openScope(clause, "case")
+ // If lhs exists, declare a corresponding variable in the case-local scope.
+ if lhs != nil {
+ // spec: "The TypeSwitchGuard may include a short variable declaration.
+ // When that form is used, the variable is declared at the beginning of
+ // the implicit block in each clause. In clauses with a case listing
+ // exactly one type, the variable has that type; otherwise, the variable
+ // has the type of the expression in the TypeSwitchGuard."
+ if len(clause.List) != 1 || T == nil {
+ T = x.typ
+ }
+ obj := NewVar(lhs.Pos(), check.pkg, lhs.Name, T)
+ scopePos := clause.End()
+ if len(clause.Body) > 0 {
+ scopePos = clause.Body[0].Pos()
+ }
+ check.declare(check.scope, nil, obj, scopePos)
+ check.recordImplicit(clause, obj)
+ // For the "declared but not used" error, all lhs variables act as
+ // one; i.e., if any one of them is 'used', all of them are 'used'.
+ // Collect them for later analysis.
+ lhsVars = append(lhsVars, obj)
+ }
+ check.stmtList(inner, clause.Body)
+ check.closeScope()
+ }
+
+ // If lhs exists, we must have at least one lhs variable that was used.
+ if lhs != nil {
+ var used bool
+ for _, v := range lhsVars {
+ if v.used {
+ used = true
+ }
+ v.used = true // avoid usage error when checking entire function
+ }
+ if !used {
+ check.softErrorf(lhs.Pos(), "%s declared but not used", lhs.Name)
+ }
+ }
+
+ case *ast.SelectStmt:
+ inner |= breakOk
+
+ check.multipleDefaults(s.Body.List)
+
+ for _, s := range s.Body.List {
+ clause, _ := s.(*ast.CommClause)
+ if clause == nil {
+ continue // error reported before
+ }
+
+ // clause.Comm must be a SendStmt, RecvStmt, or default case
+ valid := false
+ var rhs ast.Expr // rhs of RecvStmt, or nil
+ switch s := clause.Comm.(type) {
+ case nil, *ast.SendStmt:
+ valid = true
+ case *ast.AssignStmt:
+ if len(s.Rhs) == 1 {
+ rhs = s.Rhs[0]
+ }
+ case *ast.ExprStmt:
+ rhs = s.X
+ }
+
+ // if present, rhs must be a receive operation
+ if rhs != nil {
+ if x, _ := unparen(rhs).(*ast.UnaryExpr); x != nil && x.Op == token.ARROW {
+ valid = true
+ }
+ }
+
+ if !valid {
+ check.error(clause.Comm.Pos(), "select case must be send or receive (possibly with assignment)")
+ continue
+ }
+
+ check.openScope(s, "case")
+ if clause.Comm != nil {
+ check.stmt(inner, clause.Comm)
+ }
+ check.stmtList(inner, clause.Body)
+ check.closeScope()
+ }
+
+ case *ast.ForStmt:
+ inner |= breakOk | continueOk
+ check.openScope(s, "for")
+ defer check.closeScope()
+
+ check.simpleStmt(s.Init)
+ if s.Cond != nil {
+ var x operand
+ check.expr(&x, s.Cond)
+ if x.mode != invalid && !isBoolean(x.typ) {
+ check.error(s.Cond.Pos(), "non-boolean condition in for statement")
+ }
+ }
+ check.simpleStmt(s.Post)
+ // spec: "The init statement may be a short variable
+ // declaration, but the post statement must not."
+ if s, _ := s.Post.(*ast.AssignStmt); s != nil && s.Tok == token.DEFINE {
+ check.softErrorf(s.Pos(), "cannot declare in post statement")
+ check.use(s.Lhs...) // avoid follow-up errors
+ }
+ check.stmt(inner, s.Body)
+
+ case *ast.RangeStmt:
+ inner |= breakOk | continueOk
+ check.openScope(s, "for")
+ defer check.closeScope()
+
+ // check expression to iterate over
+ var x operand
+ check.expr(&x, s.X)
+
+ // determine key/value types
+ var key, val Type
+ if x.mode != invalid {
+ switch typ := x.typ.Underlying().(type) {
+ case *Basic:
+ if isString(typ) {
+ key = Typ[Int]
+ val = universeRune // use 'rune' name
+ }
+ case *Array:
+ key = Typ[Int]
+ val = typ.elem
+ case *Slice:
+ key = Typ[Int]
+ val = typ.elem
+ case *Pointer:
+ if typ, _ := typ.base.Underlying().(*Array); typ != nil {
+ key = Typ[Int]
+ val = typ.elem
+ }
+ case *Map:
+ key = typ.key
+ val = typ.elem
+ case *Chan:
+ key = typ.elem
+ val = Typ[Invalid]
+ if typ.dir == SendOnly {
+ check.errorf(x.pos(), "cannot range over send-only channel %s", &x)
+ // ok to continue
+ }
+ if s.Value != nil {
+ check.errorf(s.Value.Pos(), "iteration over %s permits only one iteration variable", &x)
+ // ok to continue
+ }
+ }
+ }
+
+ if key == nil {
+ check.errorf(x.pos(), "cannot range over %s", &x)
+ // ok to continue
+ }
+
+ // check assignment to/declaration of iteration variables
+ // (irregular assignment, cannot easily map to existing assignment checks)
+
+ // lhs expressions and initialization value (rhs) types
+ lhs := [2]ast.Expr{s.Key, s.Value}
+ rhs := [2]Type{key, val} // key, val may be nil
+
+ if s.Tok == token.DEFINE {
+ // short variable declaration; variable scope starts after the range clause
+ // (the for loop opens a new scope, so variables on the lhs never redeclare
+ // previously declared variables)
+ var vars []*Var
+ for i, lhs := range lhs {
+ if lhs == nil {
+ continue
+ }
+
+ // determine lhs variable
+ var obj *Var
+ if ident, _ := lhs.(*ast.Ident); ident != nil {
+ // declare new variable
+ name := ident.Name
+ obj = NewVar(ident.Pos(), check.pkg, name, nil)
+ check.recordDef(ident, obj)
+ // _ variables don't count as new variables
+ if name != "_" {
+ vars = append(vars, obj)
+ }
+ } else {
+ check.errorf(lhs.Pos(), "cannot declare %s", lhs)
+ obj = NewVar(lhs.Pos(), check.pkg, "_", nil) // dummy variable
+ }
+
+ // initialize lhs variable
+ if typ := rhs[i]; typ != nil {
+ x.mode = value
+ x.expr = lhs // we don't have a better rhs expression to use here
+ x.typ = typ
+ check.initVar(obj, &x, false)
+ } else {
+ obj.typ = Typ[Invalid]
+ obj.used = true // don't complain about unused variable
+ }
+ }
+
+ // declare variables
+ if len(vars) > 0 {
+ for _, obj := range vars {
+ // spec: "The scope of a constant or variable identifier declared inside
+ // a function begins at the end of the ConstSpec or VarSpec (ShortVarDecl
+ // for short variable declarations) and ends at the end of the innermost
+ // containing block."
+ scopePos := s.End()
+ check.declare(check.scope, nil /* recordDef already called */, obj, scopePos)
+ }
+ } else {
+ check.error(s.TokPos, "no new variables on left side of :=")
+ }
+ } else {
+ // ordinary assignment
+ for i, lhs := range lhs {
+ if lhs == nil {
+ continue
+ }
+ if typ := rhs[i]; typ != nil {
+ x.mode = value
+ x.expr = lhs // we don't have a better rhs expression to use here
+ x.typ = typ
+ check.assignVar(lhs, &x)
+ }
+ }
+ }
+
+ check.stmt(inner, s.Body)
+
+ default:
+ check.error(s.Pos(), "invalid statement")
+ }
+}
diff --git a/go/types/testdata/blank.src b/go/types/testdata/blank.src
new file mode 100644
index 0000000..6a2507f
--- /dev/null
+++ b/go/types/testdata/blank.src
@@ -0,0 +1,5 @@
+// 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 _ /* ERROR invalid package name */
diff --git a/go/types/testdata/builtins.src b/go/types/testdata/builtins.src
new file mode 100644
index 0000000..9eb551d
--- /dev/null
+++ b/go/types/testdata/builtins.src
@@ -0,0 +1,881 @@
+// 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.
+
+// builtin calls
+
+package builtins
+
+import "unsafe"
+
+func f0() {}
+
+func append1() {
+ var b byte
+ var x int
+ var s []byte
+ _ = append() // ERROR not enough arguments
+ _ = append("foo" /* ERROR not a slice */ )
+ _ = append(nil /* ERROR not a slice */ , s)
+ _ = append(x /* ERROR not a slice */ , s)
+ _ = append(s)
+ append /* ERROR not used */ (s)
+
+ _ = append(s, b)
+ _ = append(s, x /* ERROR cannot pass argument x */ )
+ _ = append(s, s /* ERROR cannot pass argument s */ )
+ _ = append(s... /* ERROR can only use ... with matching parameter */ )
+ _ = append(s, b, s... /* ERROR can only use ... with matching parameter */ )
+ _ = append(s, 1, 2, 3)
+ _ = append(s, 1, 2, 3, x /* ERROR cannot pass argument x */ , 5, 6, 6)
+ _ = append(s, 1, 2, s... /* ERROR can only use ... with matching parameter */ )
+ _ = append([]interface{}(nil), 1, 2, "foo", x, 3.1425, false)
+
+ type S []byte
+ type T string
+ var t T
+ _ = append(s, "foo" /* ERROR cannot convert */ )
+ _ = append(s, "foo"...)
+ _ = append(S(s), "foo" /* ERROR cannot convert */ )
+ _ = append(S(s), "foo"...)
+ _ = append(s, t /* ERROR cannot pass argument t */ )
+ _ = append(s, t...)
+ _ = append(s, T("foo")...)
+ _ = append(S(s), t /* ERROR cannot pass argument t */ )
+ _ = append(S(s), t...)
+ _ = append(S(s), T("foo")...)
+ _ = append([]string{}, t /* ERROR cannot pass argument t */ , "foo")
+ _ = append([]T{}, t, "foo")
+}
+
+// from the spec
+func append2() {
+ s0 := []int{0, 0}
+ s1 := append(s0, 2) // append a single element s1 == []int{0, 0, 2}
+ s2 := append(s1, 3, 5, 7) // append multiple elements s2 == []int{0, 0, 2, 3, 5, 7}
+ s3 := append(s2, s0...) // append a slice s3 == []int{0, 0, 2, 3, 5, 7, 0, 0}
+ s4 := append(s3[3:6], s3[2:]...) // append overlapping slice s4 == []int{3, 5, 7, 2, 3, 5, 7, 0, 0}
+
+ var t []interface{}
+ t = append(t, 42, 3.1415, "foo") // t == []interface{}{42, 3.1415, "foo"}
+
+ var b []byte
+ b = append(b, "bar"...) // append string contents b == []byte{'b', 'a', 'r' }
+
+ _ = s4
+}
+
+func append3() {
+ f1 := func() (s []int) { return }
+ f2 := func() (s []int, x int) { return }
+ f3 := func() (s []int, x, y int) { return }
+ f5 := func() (s []interface{}, x int, y float32, z string, b bool) { return }
+ ff := func() (int, float32) { return 0, 0 }
+ _ = append(f0 /* ERROR used as value */ ())
+ _ = append(f1())
+ _ = append(f2())
+ _ = append(f3())
+ _ = append(f5())
+ _ = append(ff /* ERROR not a slice */ ()) // TODO(gri) better error message
+}
+
+func cap1() {
+ var a [10]bool
+ var p *[20]int
+ var c chan string
+ _ = cap() // ERROR not enough arguments
+ _ = cap(1, 2) // ERROR too many arguments
+ _ = cap(42 /* ERROR invalid */)
+ const _3 = cap(a)
+ assert(_3 == 10)
+ const _4 = cap(p)
+ assert(_4 == 20)
+ _ = cap(c)
+ cap /* ERROR not used */ (c)
+
+ // issue 4744
+ type T struct{ a [10]int }
+ const _ = cap(((*T)(nil)).a)
+
+ var s [][]byte
+ _ = cap(s)
+ _ = cap(s... /* ERROR invalid use of \.\.\. */ )
+}
+
+func cap2() {
+ f1a := func() (a [10]int) { return }
+ f1s := func() (s []int) { return }
+ f2 := func() (s []int, x int) { return }
+ _ = cap(f0 /* ERROR used as value */ ())
+ _ = cap(f1a())
+ _ = cap(f1s())
+ _ = cap(f2()) // ERROR too many arguments
+}
+
+// test cases for issue 7387
+func cap3() {
+ var f = func() int { return 0 }
+ var x = f()
+ const (
+ _ = cap([4]int{})
+ _ = cap([4]int{x})
+ _ = cap /* ERROR not constant */ ([4]int{f()})
+ _ = cap /* ERROR not constant */ ([4]int{cap([]int{})})
+ _ = cap([4]int{cap([4]int{})})
+ )
+ var y float64
+ var z complex128
+ const (
+ _ = cap([4]float64{})
+ _ = cap([4]float64{y})
+ _ = cap([4]float64{real(2i)})
+ _ = cap /* ERROR not constant */ ([4]float64{real(z)})
+ )
+ var ch chan [10]int
+ const (
+ _ = cap /* ERROR not constant */ (<-ch)
+ _ = cap /* ERROR not constant */ ([4]int{(<-ch)[0]})
+ )
+}
+
+func close1() {
+ var c chan int
+ var r <-chan int
+ close() // ERROR not enough arguments
+ close(1, 2) // ERROR too many arguments
+ close(42 /* ERROR not a channel */)
+ close(r /* ERROR receive-only channel */)
+ close(c)
+ _ = close /* ERROR used as value */ (c)
+
+ var s []chan int
+ close(s... /* ERROR invalid use of \.\.\. */ )
+}
+
+func close2() {
+ f1 := func() (ch chan int) { return }
+ f2 := func() (ch chan int, x int) { return }
+ close(f0 /* ERROR used as value */ ())
+ close(f1())
+ close(f2()) // ERROR too many arguments
+}
+
+func complex1() {
+ var i32 int32
+ var f32 float32
+ var f64 float64
+ var c64 complex64
+ var c128 complex128
+ _ = complex() // ERROR not enough arguments
+ _ = complex(1) // ERROR not enough arguments
+ _ = complex(true /* ERROR invalid argument */ , 0)
+ _ = complex(i32 /* ERROR invalid argument */ , 0)
+ _ = complex("foo" /* ERROR invalid argument */ , 0)
+ _ = complex(c64 /* ERROR invalid argument */ , 0)
+ _ = complex(0, true /* ERROR invalid argument */ )
+ _ = complex(0, i32 /* ERROR invalid argument */ )
+ _ = complex(0, "foo" /* ERROR invalid argument */ )
+ _ = complex(0, c64 /* ERROR invalid argument */ )
+ _ = complex(f32, f32)
+ _ = complex(f32, 1)
+ _ = complex(f32, 1.0)
+ _ = complex(f32, 'a')
+ _ = complex(f64, f64)
+ _ = complex(f64, 1)
+ _ = complex(f64, 1.0)
+ _ = complex(f64, 'a')
+ _ = complex(f32 /* ERROR mismatched types */ , f64)
+ _ = complex(f64 /* ERROR mismatched types */ , f32)
+ _ = complex(1, 1)
+ _ = complex(1, 1.1)
+ _ = complex(1, 'a')
+ complex /* ERROR not used */ (1, 2)
+
+ var _ complex64 = complex(f32, f32)
+ var _ complex64 = complex /* ERROR cannot initialize */ (f64, f64)
+
+ var _ complex128 = complex /* ERROR cannot initialize */ (f32, f32)
+ var _ complex128 = complex(f64, f64)
+
+ // untyped constants
+ const _ int = complex(1, 0)
+ const _ float32 = complex(1, 0)
+ const _ complex64 = complex(1, 0)
+ const _ complex128 = complex(1, 0)
+
+ const _ int = complex /* ERROR int */ (1.1, 0)
+ const _ float32 = complex /* ERROR float32 */ (1, 2)
+
+ // untyped values
+ var s uint
+ _ = complex(1 /* ERROR integer */ <<s, 0)
+ const _ = complex /* ERROR not constant */ (1 /* ERROR integer */ <<s, 0)
+ var _ int = complex /* ERROR cannot initialize */ (1 /* ERROR integer */ <<s, 0)
+
+ // floating-point argument types must be identical
+ type F32 float32
+ type F64 float64
+ var x32 F32
+ var x64 F64
+ c64 = complex(x32, x32)
+ _ = complex(x32 /* ERROR mismatched types */ , f32)
+ _ = complex(f32 /* ERROR mismatched types */ , x32)
+ c128 = complex(x64, x64)
+ _ = c128
+ _ = complex(x64 /* ERROR mismatched types */ , f64)
+ _ = complex(f64 /* ERROR mismatched types */ , x64)
+
+ var t []float32
+ _ = complex(t... /* ERROR invalid use of \.\.\. */ )
+}
+
+func complex2() {
+ f1 := func() (x float32) { return }
+ f2 := func() (x, y float32) { return }
+ f3 := func() (x, y, z float32) { return }
+ _ = complex(f0 /* ERROR used as value */ ())
+ _ = complex(f1()) // ERROR not enough arguments
+ _ = complex(f2())
+ _ = complex(f3()) // ERROR too many arguments
+}
+
+func copy1() {
+ copy() // ERROR not enough arguments
+ copy("foo") // ERROR not enough arguments
+ copy([ /* ERROR copy expects slice arguments */ ...]int{}, []int{})
+ copy([ /* ERROR copy expects slice arguments */ ]int{}, [...]int{})
+ copy([ /* ERROR different element types */ ]int8{}, "foo")
+
+ // spec examples
+ var a = [...]int{0, 1, 2, 3, 4, 5, 6, 7}
+ var s = make([]int, 6)
+ var b = make([]byte, 5)
+ n1 := copy(s, a[0:]) // n1 == 6, s == []int{0, 1, 2, 3, 4, 5}
+ n2 := copy(s, s[2:]) // n2 == 4, s == []int{2, 3, 4, 5, 4, 5}
+ n3 := copy(b, "Hello, World!") // n3 == 5, b == []byte("Hello")
+ _, _, _ = n1, n2, n3
+
+ var t [][]int
+ copy(t, t)
+ copy(t /* ERROR copy expects slice arguments */ , nil)
+ copy(nil /* ERROR copy expects slice arguments */ , t)
+ copy(nil /* ERROR copy expects slice arguments */ , nil)
+ copy(t... /* ERROR invalid use of \.\.\. */ )
+}
+
+func copy2() {
+ f1 := func() (a []int) { return }
+ f2 := func() (a, b []int) { return }
+ f3 := func() (a, b, c []int) { return }
+ copy(f0 /* ERROR used as value */ ())
+ copy(f1()) // ERROR not enough arguments
+ copy(f2())
+ copy(f3()) // ERROR too many arguments
+}
+
+func delete1() {
+ var m map[string]int
+ var s string
+ delete() // ERROR not enough arguments
+ delete(1) // ERROR not enough arguments
+ delete(1, 2, 3) // ERROR too many arguments
+ delete(m, 0 /* ERROR not assignable */)
+ delete(m, s)
+ _ = delete /* ERROR used as value */ (m, s)
+
+ var t []map[string]string
+ delete(t... /* ERROR invalid use of \.\.\. */ )
+}
+
+func delete2() {
+ f1 := func() (m map[string]int) { return }
+ f2 := func() (m map[string]int, k string) { return }
+ f3 := func() (m map[string]int, k string, x float32) { return }
+ delete(f0 /* ERROR used as value */ ())
+ delete(f1()) // ERROR not enough arguments
+ delete(f2())
+ delete(f3()) // ERROR too many arguments
+}
+
+func imag1() {
+ var f32 float32
+ var f64 float64
+ var c64 complex64
+ var c128 complex128
+ _ = imag() // ERROR not enough arguments
+ _ = imag(1, 2) // ERROR too many arguments
+ _ = imag(10 /* ERROR must be a complex number */)
+ _ = imag(2.7182818 /* ERROR must be a complex number */)
+ _ = imag("foo" /* ERROR must be a complex number */)
+ const _5 = imag(1 + 2i)
+ assert(_5 == 2)
+ f32 = _5
+ f64 = _5
+ const _6 = imag(0i)
+ assert(_6 == 0)
+ f32 = imag(c64)
+ f64 = imag(c128)
+ f32 = imag /* ERROR cannot assign */ (c128)
+ f64 = imag /* ERROR cannot assign */ (c64)
+ imag /* ERROR not used */ (c64)
+ _, _ = f32, f64
+
+ // complex type may not be predeclared
+ type C64 complex64
+ type C128 complex128
+ var x64 C64
+ var x128 C128
+ f32 = imag(x64)
+ f64 = imag(x128)
+
+ var s []complex64
+ _ = imag(s... /* ERROR invalid use of \.\.\. */ )
+}
+
+func imag2() {
+ f1 := func() (x complex128) { return }
+ f2 := func() (x, y complex128) { return }
+ _ = imag(f0 /* ERROR used as value */ ())
+ _ = imag(f1())
+ _ = imag(f2()) // ERROR too many arguments
+}
+
+func len1() {
+ const c = "foobar"
+ var a [10]bool
+ var p *[20]int
+ var m map[string]complex128
+ _ = len() // ERROR not enough arguments
+ _ = len(1, 2) // ERROR too many arguments
+ _ = len(42 /* ERROR invalid */)
+ const _3 = len(c)
+ assert(_3 == 6)
+ const _4 = len(a)
+ assert(_4 == 10)
+ const _5 = len(p)
+ assert(_5 == 20)
+ _ = len(m)
+ len /* ERROR not used */ (c)
+
+ // esoteric case
+ var t string
+ var hash map[interface{}][]*[10]int
+ const n = len /* ERROR not constant */ (hash[recover()][len(t)])
+ assert(n == 10) // ok because n has unknown value and no error is reported
+ var ch <-chan int
+ const nn = len /* ERROR not constant */ (hash[<-ch][len(t)])
+
+ // issue 4744
+ type T struct{ a [10]int }
+ const _ = len(((*T)(nil)).a)
+
+ var s [][]byte
+ _ = len(s)
+ _ = len(s... /* ERROR invalid use of \.\.\. */ )
+}
+
+func len2() {
+ f1 := func() (x []int) { return }
+ f2 := func() (x, y []int) { return }
+ _ = len(f0 /* ERROR used as value */ ())
+ _ = len(f1())
+ _ = len(f2()) // ERROR too many arguments
+}
+
+// test cases for issue 7387
+func len3() {
+ var f = func() int { return 0 }
+ var x = f()
+ const (
+ _ = len([4]int{})
+ _ = len([4]int{x})
+ _ = len /* ERROR not constant */ ([4]int{f()})
+ _ = len /* ERROR not constant */ ([4]int{len([]int{})})
+ _ = len([4]int{len([4]int{})})
+ )
+ var y float64
+ var z complex128
+ const (
+ _ = len([4]float64{})
+ _ = len([4]float64{y})
+ _ = len([4]float64{real(2i)})
+ _ = len /* ERROR not constant */ ([4]float64{real(z)})
+ )
+ var ch chan [10]int
+ const (
+ _ = len /* ERROR not constant */ (<-ch)
+ _ = len /* ERROR not constant */ ([4]int{(<-ch)[0]})
+ )
+}
+
+func make1() {
+ var n int
+ var m float32
+ var s uint
+
+ _ = make() // ERROR not enough arguments
+ _ = make(1 /* ERROR not a type */)
+ _ = make(int /* ERROR cannot make */)
+
+ // slices
+ _ = make/* ERROR arguments */ ([]int)
+ _ = make/* ERROR arguments */ ([]int, 2, 3, 4)
+ _ = make([]int, int /* ERROR not an expression */)
+ _ = make([]int, 10, float32 /* ERROR not an expression */)
+ _ = make([]int, "foo" /* ERROR cannot convert */)
+ _ = make([]int, 10, 2.3 /* ERROR truncated */)
+ _ = make([]int, 5, 10.0)
+ _ = make([]int, 0i)
+ _ = make([]int, 1.0)
+ _ = make([]int, 1.0<<s)
+ _ = make([]int, 1.1 /* ERROR int */ <<s)
+ _ = make([]int, - /* ERROR must not be negative */ 1, 10)
+ _ = make([]int, 0, - /* ERROR must not be negative */ 1)
+ _ = make([]int, - /* ERROR must not be negative */ 1, - /* ERROR must not be negative */ 1)
+ _ = make([]int, 1 /* ERROR overflows */ <<100, 1 /* ERROR overflows */ <<100)
+ _ = make([]int, 10 /* ERROR length and capacity swapped */ , 9)
+ _ = make([]int, 1 /* ERROR overflows */ <<100, 12345)
+ _ = make([]int, m /* ERROR must be integer */ )
+ _ = &make /* ERROR cannot take address */ ([]int, 0)
+
+ // maps
+ _ = make /* ERROR arguments */ (map[int]string, 10, 20)
+ _ = make(map[int]float32, int /* ERROR not an expression */)
+ _ = make(map[int]float32, "foo" /* ERROR cannot convert */)
+ _ = make(map[int]float32, 10)
+ _ = make(map[int]float32, n)
+ _ = make(map[int]float32, int64(n))
+ _ = make(map[string]bool, 10.0)
+ _ = make(map[string]bool, 10.0<<s)
+ _ = &make /* ERROR cannot take address */ (map[string]bool)
+
+ // channels
+ _ = make /* ERROR arguments */ (chan int, 10, 20)
+ _ = make(chan int, int /* ERROR not an expression */)
+ _ = make(chan<- int, "foo" /* ERROR cannot convert */)
+ _ = make(chan int, - /* ERROR must not be negative */ 10)
+ _ = make(<-chan float64, 10)
+ _ = make(chan chan int, n)
+ _ = make(chan string, int64(n))
+ _ = make(chan bool, 10.0)
+ _ = make(chan bool, 10.0<<s)
+ _ = &make /* ERROR cannot take address */ (chan bool)
+
+ make /* ERROR not used */ ([]int, 10)
+
+ var t []int
+ _ = make([]int, t[0], t[1])
+ _ = make([]int, t... /* ERROR invalid use of \.\.\. */ )
+}
+
+func make2() {
+ f1 /* ERROR not used */ := func() (x []int) { return }
+ _ = make(f0 /* ERROR not a type */ ())
+ _ = make(f1 /* ERROR not a type */ ())
+}
+
+func new1() {
+ _ = new() // ERROR not enough arguments
+ _ = new(1, 2) // ERROR too many arguments
+ _ = new("foo" /* ERROR not a type */)
+ p := new(float64)
+ _ = new(struct{ x, y int })
+ q := new(*float64)
+ _ = *p == **q
+ new /* ERROR not used */ (int)
+ _ = &new /* ERROR cannot take address */ (int)
+
+ _ = new(int... /* ERROR invalid use of \.\.\. */ )
+}
+
+func new2() {
+ f1 /* ERROR not used */ := func() (x []int) { return }
+ _ = new(f0 /* ERROR not a type */ ())
+ _ = new(f1 /* ERROR not a type */ ())
+}
+
+func panic1() {
+ panic() // ERROR not enough arguments
+ panic(1, 2) // ERROR too many arguments
+ panic(0)
+ panic("foo")
+ panic(false)
+ panic(1<<10)
+ panic(1 /* ERROR overflows */ <<1000)
+ _ = panic /* ERROR used as value */ (0)
+
+ var s []byte
+ panic(s)
+ panic(s... /* ERROR invalid use of \.\.\. */ )
+}
+
+func panic2() {
+ f1 := func() (x int) { return }
+ f2 := func() (x, y int) { return }
+ panic(f0 /* ERROR used as value */ ())
+ panic(f1())
+ panic(f2()) // ERROR too many arguments
+}
+
+func print1() {
+ print()
+ print(1)
+ print(1, 2)
+ print("foo")
+ print(2.718281828)
+ print(false)
+ print(1<<10)
+ print(1 /* ERROR overflows */ <<1000)
+ println(nil /* ERROR untyped nil */ )
+
+ var s []int
+ print(s... /* ERROR invalid use of \.\.\. */ )
+ _ = print /* ERROR used as value */ ()
+}
+
+func print2() {
+ f1 := func() (x int) { return }
+ f2 := func() (x, y int) { return }
+ f3 := func() (x int, y float32, z string) { return }
+ print(f0 /* ERROR used as value */ ())
+ print(f1())
+ print(f2())
+ print(f3())
+}
+
+func println1() {
+ println()
+ println(1)
+ println(1, 2)
+ println("foo")
+ println(2.718281828)
+ println(false)
+ println(1<<10)
+ println(1 /* ERROR overflows */ <<1000)
+ println(nil /* ERROR untyped nil */ )
+
+ var s []int
+ println(s... /* ERROR invalid use of \.\.\. */ )
+ _ = println /* ERROR used as value */ ()
+}
+
+func println2() {
+ f1 := func() (x int) { return }
+ f2 := func() (x, y int) { return }
+ f3 := func() (x int, y float32, z string) { return }
+ println(f0 /* ERROR used as value */ ())
+ println(f1())
+ println(f2())
+ println(f3())
+}
+
+func real1() {
+ var f32 float32
+ var f64 float64
+ var c64 complex64
+ var c128 complex128
+ _ = real() // ERROR not enough arguments
+ _ = real(1, 2) // ERROR too many arguments
+ _ = real(10 /* ERROR must be a complex number */)
+ _ = real(2.7182818 /* ERROR must be a complex number */)
+ _ = real("foo" /* ERROR must be a complex number */)
+ const _5 = real(1 + 2i)
+ assert(_5 == 1)
+ f32 = _5
+ f64 = _5
+ const _6 = real(0i)
+ assert(_6 == 0)
+ f32 = real(c64)
+ f64 = real(c128)
+ f32 = real /* ERROR cannot assign */ (c128)
+ f64 = real /* ERROR cannot assign */ (c64)
+ real /* ERROR not used */ (c64)
+
+ // complex type may not be predeclared
+ type C64 complex64
+ type C128 complex128
+ var x64 C64
+ var x128 C128
+ f32 = imag(x64)
+ f64 = imag(x128)
+
+ var s []complex64
+ _ = real(s... /* ERROR invalid use of \.\.\. */ )
+ _, _ = f32, f64
+}
+
+func real2() {
+ f1 := func() (x complex128) { return }
+ f2 := func() (x, y complex128) { return }
+ _ = real(f0 /* ERROR used as value */ ())
+ _ = real(f1())
+ _ = real(f2()) // ERROR too many arguments
+}
+
+func recover1() {
+ _ = recover()
+ _ = recover(10) // ERROR too many arguments
+ recover()
+
+ var s []int
+ recover(s... /* ERROR invalid use of \.\.\. */ )
+}
+
+func recover2() {
+ f1 := func() (x int) { return }
+ f2 := func() (x, y int) { return }
+ _ = recover(f0 /* ERROR used as value */ ())
+ _ = recover(f1()) // ERROR too many arguments
+ _ = recover(f2()) // ERROR too many arguments
+}
+
+// assuming types.DefaultPtrSize == 8
+type S0 struct{ // offset
+ a bool // 0
+ b rune // 4
+ c *int // 8
+ d bool // 16
+ e complex128 // 24
+} // 40
+
+type S1 struct{ // offset
+ x float32 // 0
+ y string // 8
+ z *S1 // 24
+ S0 // 32
+} // 72
+
+type S2 struct{ // offset
+ *S1 // 0
+} // 8
+
+type S3 struct { // offset
+ a int64 // 0
+ b int32 // 8
+} // 12
+
+type S4 struct { // offset
+ S3 // 0
+ int32 // 12
+} // 16
+
+type S5 struct { // offset
+ a [3]int32 // 0
+ b int32 // 12
+} // 16
+
+func (S2) m() {}
+
+func Alignof1() {
+ var x int
+ _ = unsafe.Alignof() // ERROR not enough arguments
+ _ = unsafe.Alignof(1, 2) // ERROR too many arguments
+ _ = unsafe.Alignof(int /* ERROR not an expression */)
+ _ = unsafe.Alignof(42)
+ _ = unsafe.Alignof(new(struct{}))
+ _ = unsafe.Alignof(1<<10)
+ _ = unsafe.Alignof(1 /* ERROR overflows */ <<1000)
+ _ = unsafe.Alignof(nil /* ERROR "untyped nil */ )
+ unsafe /* ERROR not used */ .Alignof(x)
+
+ var y S0
+ assert(unsafe.Alignof(y.a) == 1)
+ assert(unsafe.Alignof(y.b) == 4)
+ assert(unsafe.Alignof(y.c) == 8)
+ assert(unsafe.Alignof(y.d) == 1)
+ assert(unsafe.Alignof(y.e) == 8)
+
+ var s []byte
+ _ = unsafe.Alignof(s)
+ _ = unsafe.Alignof(s... /* ERROR invalid use of \.\.\. */ )
+}
+
+func Alignof2() {
+ f1 := func() (x int32) { return }
+ f2 := func() (x, y int32) { return }
+ _ = unsafe.Alignof(f0 /* ERROR used as value */ ())
+ assert(unsafe.Alignof(f1()) == 4)
+ _ = unsafe.Alignof(f2()) // ERROR too many arguments
+}
+
+func Offsetof1() {
+ var x struct{ f int }
+ _ = unsafe.Offsetof() // ERROR not enough arguments
+ _ = unsafe.Offsetof(1, 2) // ERROR too many arguments
+ _ = unsafe.Offsetof(int /* ERROR not a selector expression */ )
+ _ = unsafe.Offsetof(x /* ERROR not a selector expression */ )
+ _ = unsafe.Offsetof(nil /* ERROR not a selector expression */ )
+ _ = unsafe.Offsetof(x.f)
+ _ = unsafe.Offsetof((x.f))
+ _ = unsafe.Offsetof((((((((x))).f)))))
+ unsafe /* ERROR not used */ .Offsetof(x.f)
+
+ var y0 S0
+ assert(unsafe.Offsetof(y0.a) == 0)
+ assert(unsafe.Offsetof(y0.b) == 4)
+ assert(unsafe.Offsetof(y0.c) == 8)
+ assert(unsafe.Offsetof(y0.d) == 16)
+ assert(unsafe.Offsetof(y0.e) == 24)
+
+ var y1 S1
+ assert(unsafe.Offsetof(y1.x) == 0)
+ assert(unsafe.Offsetof(y1.y) == 8)
+ assert(unsafe.Offsetof(y1.z) == 24)
+ assert(unsafe.Offsetof(y1.S0) == 32)
+
+ assert(unsafe.Offsetof(y1.S0.a) == 0) // relative to S0
+ assert(unsafe.Offsetof(y1.a) == 32) // relative to S1
+ assert(unsafe.Offsetof(y1.b) == 36) // relative to S1
+ assert(unsafe.Offsetof(y1.c) == 40) // relative to S1
+ assert(unsafe.Offsetof(y1.d) == 48) // relative to S1
+ assert(unsafe.Offsetof(y1.e) == 56) // relative to S1
+
+ var y1p *S1
+ assert(unsafe.Offsetof(y1p.S0) == 32)
+
+ type P *S1
+ var p P = y1p
+ assert(unsafe.Offsetof(p.S0) == 32)
+
+ var y2 S2
+ assert(unsafe.Offsetof(y2.S1) == 0)
+ _ = unsafe.Offsetof(y2 /* ERROR embedded via a pointer */ .x)
+ _ = unsafe.Offsetof(y2 /* ERROR method value */ .m)
+
+ var s []byte
+ _ = unsafe.Offsetof(s... /* ERROR invalid use of \.\.\. */ )
+}
+
+func Offsetof2() {
+ f1 := func() (x int32) { return }
+ f2 := func() (x, y int32) { return }
+ _ = unsafe.Offsetof(f0 /* ERROR not a selector expression */ ())
+ _ = unsafe.Offsetof(f1 /* ERROR not a selector expression */ ())
+ _ = unsafe.Offsetof(f2 /* ERROR not a selector expression */ ())
+}
+
+func Sizeof1() {
+ var x int
+ _ = unsafe.Sizeof() // ERROR not enough arguments
+ _ = unsafe.Sizeof(1, 2) // ERROR too many arguments
+ _ = unsafe.Sizeof(int /* ERROR not an expression */)
+ _ = unsafe.Sizeof(42)
+ _ = unsafe.Sizeof(new(complex128))
+ _ = unsafe.Sizeof(1<<10)
+ _ = unsafe.Sizeof(1 /* ERROR overflows */ <<1000)
+ _ = unsafe.Sizeof(nil /* ERROR untyped nil */ )
+ unsafe /* ERROR not used */ .Sizeof(x)
+
+ // basic types have size guarantees
+ assert(unsafe.Sizeof(byte(0)) == 1)
+ assert(unsafe.Sizeof(uint8(0)) == 1)
+ assert(unsafe.Sizeof(int8(0)) == 1)
+ assert(unsafe.Sizeof(uint16(0)) == 2)
+ assert(unsafe.Sizeof(int16(0)) == 2)
+ assert(unsafe.Sizeof(uint32(0)) == 4)
+ assert(unsafe.Sizeof(int32(0)) == 4)
+ assert(unsafe.Sizeof(float32(0)) == 4)
+ assert(unsafe.Sizeof(uint64(0)) == 8)
+ assert(unsafe.Sizeof(int64(0)) == 8)
+ assert(unsafe.Sizeof(float64(0)) == 8)
+ assert(unsafe.Sizeof(complex64(0)) == 8)
+ assert(unsafe.Sizeof(complex128(0)) == 16)
+
+ var y0 S0
+ assert(unsafe.Sizeof(y0.a) == 1)
+ assert(unsafe.Sizeof(y0.b) == 4)
+ assert(unsafe.Sizeof(y0.c) == 8)
+ assert(unsafe.Sizeof(y0.d) == 1)
+ assert(unsafe.Sizeof(y0.e) == 16)
+ assert(unsafe.Sizeof(y0) == 40)
+
+ var y1 S1
+ assert(unsafe.Sizeof(y1) == 72)
+
+ var y2 S2
+ assert(unsafe.Sizeof(y2) == 8)
+
+ var y3 S3
+ assert(unsafe.Sizeof(y3) == 12)
+
+ var y4 S4
+ assert(unsafe.Sizeof(y4) == 16)
+
+ var y5 S5
+ assert(unsafe.Sizeof(y5) == 16)
+
+ var a3 [10]S3
+ assert(unsafe.Sizeof(a3) == 156)
+
+ // test case for issue 5670
+ type T struct {
+ a int32
+ _ int32
+ c int32
+ }
+ assert(unsafe.Sizeof(T{}) == 12)
+
+ var s []byte
+ _ = unsafe.Sizeof(s)
+ _ = unsafe.Sizeof(s... /* ERROR invalid use of \.\.\. */ )
+}
+
+func Sizeof2() {
+ f1 := func() (x int64) { return }
+ f2 := func() (x, y int64) { return }
+ _ = unsafe.Sizeof(f0 /* ERROR used as value */ ())
+ assert(unsafe.Sizeof(f1()) == 8)
+ _ = unsafe.Sizeof(f2()) // ERROR too many arguments
+}
+
+// self-testing only
+func assert1() {
+ var x int
+ assert() /* ERROR not enough arguments */
+ assert(1, 2) /* ERROR too many arguments */
+ assert("foo" /* ERROR boolean constant */ )
+ assert(x /* ERROR boolean constant */)
+ assert(true)
+ assert /* ERROR failed */ (false)
+ _ = assert(true)
+
+ var s []byte
+ assert(s... /* ERROR invalid use of \.\.\. */ )
+}
+
+func assert2() {
+ f1 := func() (x bool) { return }
+ f2 := func() (x bool) { return }
+ assert(f0 /* ERROR used as value */ ())
+ assert(f1 /* ERROR boolean constant */ ())
+ assert(f2 /* ERROR boolean constant */ ())
+}
+
+// self-testing only
+func trace1() {
+ // Uncomment the code below to test trace - will produce console output
+ // _ = trace /* ERROR no value */ ()
+ // _ = trace(1)
+ // _ = trace(true, 1.2, '\'', "foo", 42i, "foo" <= "bar")
+
+ var s []byte
+ trace(s... /* ERROR invalid use of \.\.\. */ )
+}
+
+func trace2() {
+ f1 := func() (x int) { return }
+ f2 := func() (x int, y string) { return }
+ f3 := func() (x int, y string, z []int) { return }
+ _ = f1
+ _ = f2
+ _ = f3
+ // Uncomment the code below to test trace - will produce console output
+ // trace(f0())
+ // trace(f1())
+ // trace(f2())
+ // trace(f3())
+ // trace(f0(), 1)
+ // trace(f1(), 1, 2)
+ // trace(f2(), 1, 2, 3)
+ // trace(f3(), 1, 2, 3, 4)
+}
diff --git a/go/types/testdata/const0.src b/go/types/testdata/const0.src
new file mode 100644
index 0000000..c4419ab
--- /dev/null
+++ b/go/types/testdata/const0.src
@@ -0,0 +1,282 @@
+// 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.
+
+// constant declarations
+
+package const0
+
+// constants declarations must be initialized by constants
+var x = 0
+const c0 = x /* ERROR "not constant" */
+
+// typed constants must have constant types
+const _ interface /* ERROR invalid constant type */ {} = 0
+
+func _ () {
+ const _ interface /* ERROR invalid constant type */ {} = 0
+ for i := 0; i < 10; i++ {} // don't crash with non-nil iota here
+}
+
+// untyped constants
+const (
+ // boolean values
+ ub0 = false
+ ub1 = true
+ ub2 = 2 < 1
+ ub3 = ui1 == uf1
+ ub4 = true /* ERROR "cannot convert" */ == 0
+
+ // integer values
+ ui0 = 0
+ ui1 = 1
+ ui2 = 42
+ ui3 = 3141592653589793238462643383279502884197169399375105820974944592307816406286
+ ui4 = -10
+
+ ui5 = ui0 + ui1
+ ui6 = ui1 - ui1
+ ui7 = ui2 * ui1
+ ui8 = ui3 / ui3
+ ui9 = ui3 % ui3
+
+ ui10 = 1 / 0 /* ERROR "division by zero" */
+ ui11 = ui1 / 0 /* ERROR "division by zero" */
+ ui12 = ui3 / ui0 /* ERROR "division by zero" */
+ ui13 = 1 % 0 /* ERROR "division by zero" */
+ ui14 = ui1 % 0 /* ERROR "division by zero" */
+ ui15 = ui3 % ui0 /* ERROR "division by zero" */
+
+ ui16 = ui2 & ui3
+ ui17 = ui2 | ui3
+ ui18 = ui2 ^ ui3
+ ui19 = 1 /* ERROR "invalid operation" */ % 1.0
+
+ // floating point values
+ uf0 = 0.
+ uf1 = 1.
+ uf2 = 4.2e1
+ uf3 = 3.141592653589793238462643383279502884197169399375105820974944592307816406286
+ uf4 = 1e-1
+
+ uf5 = uf0 + uf1
+ uf6 = uf1 - uf1
+ uf7 = uf2 * uf1
+ uf8 = uf3 / uf3
+ uf9 = uf3 /* ERROR "not defined" */ % uf3
+
+ uf10 = 1 / 0 /* ERROR "division by zero" */
+ uf11 = uf1 / 0 /* ERROR "division by zero" */
+ uf12 = uf3 / uf0 /* ERROR "division by zero" */
+
+ uf16 = uf2 /* ERROR "not defined" */ & uf3
+ uf17 = uf2 /* ERROR "not defined" */ | uf3
+ uf18 = uf2 /* ERROR "not defined" */ ^ uf3
+
+ // complex values
+ uc0 = 0.i
+ uc1 = 1.i
+ uc2 = 4.2e1i
+ uc3 = 3.141592653589793238462643383279502884197169399375105820974944592307816406286i
+ uc4 = 1e-1i
+
+ uc5 = uc0 + uc1
+ uc6 = uc1 - uc1
+ uc7 = uc2 * uc1
+ uc8 = uc3 / uc3
+ uc9 = uc3 /* ERROR "not defined" */ % uc3
+
+ uc10 = 1 / 0 /* ERROR "division by zero" */
+ uc11 = uc1 / 0 /* ERROR "division by zero" */
+ uc12 = uc3 / uc0 /* ERROR "division by zero" */
+
+ uc16 = uc2 /* ERROR "not defined" */ & uc3
+ uc17 = uc2 /* ERROR "not defined" */ | uc3
+ uc18 = uc2 /* ERROR "not defined" */ ^ uc3
+)
+
+type (
+ mybool bool
+ myint int
+ myfloat float64
+ mycomplex complex128
+)
+
+// typed constants
+const (
+ // boolean values
+ tb0 bool = false
+ tb1 bool = true
+ tb2 mybool = 2 < 1
+ tb3 mybool = ti1 /* ERROR "mismatched types" */ == tf1
+
+ // integer values
+ ti0 int8 = ui0
+ ti1 int32 = ui1
+ ti2 int64 = ui2
+ ti3 myint = ui3 /* ERROR "overflows" */
+ ti4 myint = ui4
+
+ ti5 = ti0 /* ERROR "mismatched types" */ + ti1
+ ti6 = ti1 - ti1
+ ti7 = ti2 /* ERROR "mismatched types" */ * ti1
+ ti8 = ti3 / ti3
+ ti9 = ti3 % ti3
+
+ ti10 = 1 / 0 /* ERROR "division by zero" */
+ ti11 = ti1 / 0 /* ERROR "division by zero" */
+ ti12 = ti3 /* ERROR "mismatched types" */ / ti0
+ ti13 = 1 % 0 /* ERROR "division by zero" */
+ ti14 = ti1 % 0 /* ERROR "division by zero" */
+ ti15 = ti3 /* ERROR "mismatched types" */ % ti0
+
+ ti16 = ti2 /* ERROR "mismatched types" */ & ti3
+ ti17 = ti2 /* ERROR "mismatched types" */ | ti4
+ ti18 = ti2 ^ ti5 // no mismatched types error because the type of ti5 is unknown
+
+ // floating point values
+ tf0 float32 = 0.
+ tf1 float32 = 1.
+ tf2 float64 = 4.2e1
+ tf3 myfloat = 3.141592653589793238462643383279502884197169399375105820974944592307816406286
+ tf4 myfloat = 1e-1
+
+ tf5 = tf0 + tf1
+ tf6 = tf1 - tf1
+ tf7 = tf2 /* ERROR "mismatched types" */ * tf1
+ tf8 = tf3 / tf3
+ tf9 = tf3 /* ERROR "not defined" */ % tf3
+
+ tf10 = 1 / 0 /* ERROR "division by zero" */
+ tf11 = tf1 / 0 /* ERROR "division by zero" */
+ tf12 = tf3 /* ERROR "mismatched types" */ / tf0
+
+ tf16 = tf2 /* ERROR "mismatched types" */ & tf3
+ tf17 = tf2 /* ERROR "mismatched types" */ | tf3
+ tf18 = tf2 /* ERROR "mismatched types" */ ^ tf3
+
+ // complex values
+ tc0 = 0.i
+ tc1 = 1.i
+ tc2 = 4.2e1i
+ tc3 = 3.141592653589793238462643383279502884197169399375105820974944592307816406286i
+ tc4 = 1e-1i
+
+ tc5 = tc0 + tc1
+ tc6 = tc1 - tc1
+ tc7 = tc2 * tc1
+ tc8 = tc3 / tc3
+ tc9 = tc3 /* ERROR "not defined" */ % tc3
+
+ tc10 = 1 / 0 /* ERROR "division by zero" */
+ tc11 = tc1 / 0 /* ERROR "division by zero" */
+ tc12 = tc3 / tc0 /* ERROR "division by zero" */
+
+ tc16 = tc2 /* ERROR "not defined" */ & tc3
+ tc17 = tc2 /* ERROR "not defined" */ | tc3
+ tc18 = tc2 /* ERROR "not defined" */ ^ tc3
+)
+
+// initialization cycles
+const (
+ a /* ERROR "initialization cycle" */ = a
+ b /* ERROR "initialization cycle" */ , c /* ERROR "initialization cycle" */, d, e = e, d, c, b // TODO(gri) should only have one cycle error
+ f float64 = d
+)
+
+// multiple initialization
+const (
+ a1, a2, a3 = 7, 3.1415926, "foo"
+ b1, b2, b3 = b3, b1, 42
+ c1, c2, c3 /* ERROR "missing init expr for c3" */ = 1, 2
+ d1, d2, d3 = 1, 2, 3, 4 /* ERROR "extra init expr 4" */
+ _p0 = assert(a1 == 7)
+ _p1 = assert(a2 == 3.1415926)
+ _p2 = assert(a3 == "foo")
+ _p3 = assert(b1 == 42)
+ _p4 = assert(b2 == 42)
+ _p5 = assert(b3 == 42)
+)
+
+func _() {
+ const (
+ a1, a2, a3 = 7, 3.1415926, "foo"
+ b1, b2, b3 = b3, b1, 42
+ c1, c2, c3 /* ERROR "missing init expr for c3" */ = 1, 2
+ d1, d2, d3 = 1, 2, 3, 4 /* ERROR "extra init expr 4" */
+ _p0 = assert(a1 == 7)
+ _p1 = assert(a2 == 3.1415926)
+ _p2 = assert(a3 == "foo")
+ _p3 = assert(b1 == 42)
+ _p4 = assert(b2 == 42)
+ _p5 = assert(b3 == 42)
+ )
+}
+
+// iota
+const (
+ iota0 = iota
+ iota1 = iota
+ iota2 = iota*2
+ _a0 = assert(iota0 == 0)
+ _a1 = assert(iota1 == 1)
+ _a2 = assert(iota2 == 4)
+ iota6 = iota*3
+
+ iota7
+ iota8
+ _a3 = assert(iota7 == 21)
+ _a4 = assert(iota8 == 24)
+)
+
+const (
+ _b0 = iota
+ _b1 = assert(iota + iota2 == 5)
+ _b2 = len([iota]int{}) // iota may appear in a type!
+ _b3 = assert(_b2 == 2)
+ _b4 = len(A{})
+)
+
+type A [iota /* ERROR "cannot use iota" */ ]int
+
+// constant expressions with operands accross different
+// constant declarations must use the right iota values
+const (
+ _c0 = iota
+ _c1
+ _c2
+ _x = _c2 + _d1 + _e0 // 3
+)
+
+const (
+ _d0 = iota
+ _d1
+)
+
+const (
+ _e0 = iota
+)
+
+var _ = assert(_x == 3)
+
+// special cases
+const (
+ _n0 = nil /* ERROR "not constant" */
+ _n1 = [ /* ERROR "not constant" */ ]int{}
+)
+
+// iotas must not be usable in expressions outside constant declarations
+type _ [iota /* ERROR "iota outside constant decl" */ ]byte
+var _ = iota /* ERROR "iota outside constant decl" */
+func _() {
+ _ = iota /* ERROR "iota outside constant decl" */
+ const _ = iota
+ _ = iota /* ERROR "iota outside constant decl" */
+}
+
+func _() {
+ iota := 123
+ const x = iota /* ERROR "is not constant" */
+ var y = iota
+ _ = y
+}
diff --git a/go/types/testdata/const1.src b/go/types/testdata/const1.src
new file mode 100644
index 0000000..88e9fad
--- /dev/null
+++ b/go/types/testdata/const1.src
@@ -0,0 +1,314 @@
+// 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.
+
+// constant conversions
+
+package const1
+
+const(
+ mi = ^int(0)
+ mu = ^uint(0)
+ mp = ^uintptr(0)
+
+ logSizeofInt = uint(mi>>8&1 + mi>>16&1 + mi>>32&1)
+ logSizeofUint = uint(mu>>8&1 + mu>>16&1 + mu>>32&1)
+ logSizeofUintptr = uint(mp>>8&1 + mp>>16&1 + mp>>32&1)
+)
+
+const (
+ minInt8 = -1<<(8<<iota - 1)
+ minInt16
+ minInt32
+ minInt64
+ minInt = -1<<(8<<logSizeofInt - 1)
+)
+
+const (
+ maxInt8 = 1<<(8<<iota - 1) - 1
+ maxInt16
+ maxInt32
+ maxInt64
+ maxInt = 1<<(8<<logSizeofInt - 1) - 1
+)
+
+const (
+ maxUint8 = 1<<(8<<iota) - 1
+ maxUint16
+ maxUint32
+ maxUint64
+ maxUint = 1<<(8<<logSizeofUint) - 1
+ maxUintptr = 1<<(8<<logSizeofUintptr) - 1
+)
+
+const (
+ smallestFloat32 = 1.0 / (1<<(127 - 1 + 23))
+ smallestFloat64 = 1.0 / (1<<(1023 - 1 + 52))
+)
+
+const (
+ _ = assert(smallestFloat32 > 0)
+ _ = assert(smallestFloat64 > 0)
+)
+
+const (
+ maxFloat32 = 1<<127 * (1<<24 - 1) / (1.0<<23)
+ maxFloat64 = 1<<1023 * (1<<53 - 1) / (1.0<<52)
+)
+
+const (
+ _ int8 = minInt8 /* ERROR "overflows" */ - 1
+ _ int8 = minInt8
+ _ int8 = maxInt8
+ _ int8 = maxInt8 /* ERROR "overflows" */ + 1
+ _ int8 = smallestFloat64 /* ERROR "truncated" */
+
+ _ = int8(minInt8 /* ERROR "cannot convert" */ - 1)
+ _ = int8(minInt8)
+ _ = int8(maxInt8)
+ _ = int8(maxInt8 /* ERROR "cannot convert" */ + 1)
+ _ = int8(smallestFloat64 /* ERROR "cannot convert" */)
+)
+
+const (
+ _ int16 = minInt16 /* ERROR "overflows" */ - 1
+ _ int16 = minInt16
+ _ int16 = maxInt16
+ _ int16 = maxInt16 /* ERROR "overflows" */ + 1
+ _ int16 = smallestFloat64 /* ERROR "truncated" */
+
+ _ = int16(minInt16 /* ERROR "cannot convert" */ - 1)
+ _ = int16(minInt16)
+ _ = int16(maxInt16)
+ _ = int16(maxInt16 /* ERROR "cannot convert" */ + 1)
+ _ = int16(smallestFloat64 /* ERROR "cannot convert" */)
+)
+
+const (
+ _ int32 = minInt32 /* ERROR "overflows" */ - 1
+ _ int32 = minInt32
+ _ int32 = maxInt32
+ _ int32 = maxInt32 /* ERROR "overflows" */ + 1
+ _ int32 = smallestFloat64 /* ERROR "truncated" */
+
+ _ = int32(minInt32 /* ERROR "cannot convert" */ - 1)
+ _ = int32(minInt32)
+ _ = int32(maxInt32)
+ _ = int32(maxInt32 /* ERROR "cannot convert" */ + 1)
+ _ = int32(smallestFloat64 /* ERROR "cannot convert" */)
+)
+
+const (
+ _ int64 = minInt64 /* ERROR "overflows" */ - 1
+ _ int64 = minInt64
+ _ int64 = maxInt64
+ _ int64 = maxInt64 /* ERROR "overflows" */ + 1
+ _ int64 = smallestFloat64 /* ERROR "truncated" */
+
+ _ = int64(minInt64 /* ERROR "cannot convert" */ - 1)
+ _ = int64(minInt64)
+ _ = int64(maxInt64)
+ _ = int64(maxInt64 /* ERROR "cannot convert" */ + 1)
+ _ = int64(smallestFloat64 /* ERROR "cannot convert" */)
+)
+
+const (
+ _ int = minInt /* ERROR "overflows" */ - 1
+ _ int = minInt
+ _ int = maxInt
+ _ int = maxInt /* ERROR "overflows" */ + 1
+ _ int = smallestFloat64 /* ERROR "truncated" */
+
+ _ = int(minInt /* ERROR "cannot convert" */ - 1)
+ _ = int(minInt)
+ _ = int(maxInt)
+ _ = int(maxInt /* ERROR "cannot convert" */ + 1)
+ _ = int(smallestFloat64 /* ERROR "cannot convert" */)
+)
+
+const (
+ _ uint8 = 0 /* ERROR "overflows" */ - 1
+ _ uint8 = 0
+ _ uint8 = maxUint8
+ _ uint8 = maxUint8 /* ERROR "overflows" */ + 1
+ _ uint8 = smallestFloat64 /* ERROR "truncated" */
+
+ _ = uint8(0 /* ERROR "cannot convert" */ - 1)
+ _ = uint8(0)
+ _ = uint8(maxUint8)
+ _ = uint8(maxUint8 /* ERROR "cannot convert" */ + 1)
+ _ = uint8(smallestFloat64 /* ERROR "cannot convert" */)
+)
+
+const (
+ _ uint16 = 0 /* ERROR "overflows" */ - 1
+ _ uint16 = 0
+ _ uint16 = maxUint16
+ _ uint16 = maxUint16 /* ERROR "overflows" */ + 1
+ _ uint16 = smallestFloat64 /* ERROR "truncated" */
+
+ _ = uint16(0 /* ERROR "cannot convert" */ - 1)
+ _ = uint16(0)
+ _ = uint16(maxUint16)
+ _ = uint16(maxUint16 /* ERROR "cannot convert" */ + 1)
+ _ = uint16(smallestFloat64 /* ERROR "cannot convert" */)
+)
+
+const (
+ _ uint32 = 0 /* ERROR "overflows" */ - 1
+ _ uint32 = 0
+ _ uint32 = maxUint32
+ _ uint32 = maxUint32 /* ERROR "overflows" */ + 1
+ _ uint32 = smallestFloat64 /* ERROR "truncated" */
+
+ _ = uint32(0 /* ERROR "cannot convert" */ - 1)
+ _ = uint32(0)
+ _ = uint32(maxUint32)
+ _ = uint32(maxUint32 /* ERROR "cannot convert" */ + 1)
+ _ = uint32(smallestFloat64 /* ERROR "cannot convert" */)
+)
+
+const (
+ _ uint64 = 0 /* ERROR "overflows" */ - 1
+ _ uint64 = 0
+ _ uint64 = maxUint64
+ _ uint64 = maxUint64 /* ERROR "overflows" */ + 1
+ _ uint64 = smallestFloat64 /* ERROR "truncated" */
+
+ _ = uint64(0 /* ERROR "cannot convert" */ - 1)
+ _ = uint64(0)
+ _ = uint64(maxUint64)
+ _ = uint64(maxUint64 /* ERROR "cannot convert" */ + 1)
+ _ = uint64(smallestFloat64 /* ERROR "cannot convert" */)
+)
+
+const (
+ _ uint = 0 /* ERROR "overflows" */ - 1
+ _ uint = 0
+ _ uint = maxUint
+ _ uint = maxUint /* ERROR "overflows" */ + 1
+ _ uint = smallestFloat64 /* ERROR "truncated" */
+
+ _ = uint(0 /* ERROR "cannot convert" */ - 1)
+ _ = uint(0)
+ _ = uint(maxUint)
+ _ = uint(maxUint /* ERROR "cannot convert" */ + 1)
+ _ = uint(smallestFloat64 /* ERROR "cannot convert" */)
+)
+
+const (
+ _ uintptr = 0 /* ERROR "overflows" */ - 1
+ _ uintptr = 0
+ _ uintptr = maxUintptr
+ _ uintptr = maxUintptr /* ERROR "overflows" */ + 1
+ _ uintptr = smallestFloat64 /* ERROR "truncated" */
+
+ _ = uintptr(0 /* ERROR "cannot convert" */ - 1)
+ _ = uintptr(0)
+ _ = uintptr(maxUintptr)
+ _ = uintptr(maxUintptr /* ERROR "cannot convert" */ + 1)
+ _ = uintptr(smallestFloat64 /* ERROR "cannot convert" */)
+)
+
+const (
+ _ float32 = minInt64
+ _ float64 = minInt64
+ _ complex64 = minInt64
+ _ complex128 = minInt64
+
+ _ = float32(minInt64)
+ _ = float64(minInt64)
+ _ = complex64(minInt64)
+ _ = complex128(minInt64)
+)
+
+const (
+ _ float32 = maxUint64
+ _ float64 = maxUint64
+ _ complex64 = maxUint64
+ _ complex128 = maxUint64
+
+ _ = float32(maxUint64)
+ _ = float64(maxUint64)
+ _ = complex64(maxUint64)
+ _ = complex128(maxUint64)
+)
+
+// TODO(gri) find smaller deltas below
+
+const delta32 = maxFloat32/(1 << 23)
+
+const (
+ _ float32 = - /* ERROR "overflow" */ (maxFloat32 + delta32)
+ _ float32 = -maxFloat32
+ _ float32 = maxFloat32
+ _ float32 = maxFloat32 /* ERROR "overflow" */ + delta32
+
+ _ = float32(- /* ERROR "cannot convert" */ (maxFloat32 + delta32))
+ _ = float32(-maxFloat32)
+ _ = float32(maxFloat32)
+ _ = float32(maxFloat32 /* ERROR "cannot convert" */ + delta32)
+
+ _ = assert(float32(smallestFloat32) == smallestFloat32)
+ _ = assert(float32(smallestFloat32/2) == 0)
+ _ = assert(float32(smallestFloat64) == 0)
+ _ = assert(float32(smallestFloat64/2) == 0)
+)
+
+const delta64 = maxFloat64/(1 << 52)
+
+const (
+ _ float64 = - /* ERROR "overflow" */ (maxFloat64 + delta64)
+ _ float64 = -maxFloat64
+ _ float64 = maxFloat64
+ _ float64 = maxFloat64 /* ERROR "overflow" */ + delta64
+
+ _ = float64(- /* ERROR "cannot convert" */ (maxFloat64 + delta64))
+ _ = float64(-maxFloat64)
+ _ = float64(maxFloat64)
+ _ = float64(maxFloat64 /* ERROR "cannot convert" */ + delta64)
+
+ _ = assert(float64(smallestFloat32) == smallestFloat32)
+ _ = assert(float64(smallestFloat32/2) == smallestFloat32/2)
+ _ = assert(float64(smallestFloat64) == smallestFloat64)
+ _ = assert(float64(smallestFloat64/2) == 0)
+)
+
+const (
+ _ complex64 = - /* ERROR "overflow" */ (maxFloat32 + delta32)
+ _ complex64 = -maxFloat32
+ _ complex64 = maxFloat32
+ _ complex64 = maxFloat32 /* ERROR "overflow" */ + delta32
+
+ _ = complex64(- /* ERROR "cannot convert" */ (maxFloat32 + delta32))
+ _ = complex64(-maxFloat32)
+ _ = complex64(maxFloat32)
+ _ = complex64(maxFloat32 /* ERROR "cannot convert" */ + delta32)
+)
+
+const (
+ _ complex128 = - /* ERROR "overflow" */ (maxFloat64 + delta64)
+ _ complex128 = -maxFloat64
+ _ complex128 = maxFloat64
+ _ complex128 = maxFloat64 /* ERROR "overflow" */ + delta64
+
+ _ = complex128(- /* ERROR "cannot convert" */ (maxFloat64 + delta64))
+ _ = complex128(-maxFloat64)
+ _ = complex128(maxFloat64)
+ _ = complex128(maxFloat64 /* ERROR "cannot convert" */ + delta64)
+)
+
+// Initialization of typed constant and conversion are the same:
+const (
+ f32 = 1 + smallestFloat32
+ x32 float32 = f32
+ y32 = float32(f32)
+ _ = assert(x32 - y32 == 0)
+)
+
+const (
+ f64 = 1 + smallestFloat64
+ x64 float64 = f64
+ y64 = float64(f64)
+ _ = assert(x64 - y64 == 0)
+)
diff --git a/go/types/testdata/constdecl.src b/go/types/testdata/constdecl.src
new file mode 100644
index 0000000..6de9b13
--- /dev/null
+++ b/go/types/testdata/constdecl.src
@@ -0,0 +1,97 @@
+// 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 constdecl
+
+import "math"
+
+var v int
+
+// Const decls must be initialized by constants.
+const _ = v /* ERROR "not constant" */
+const _ = math /* ERROR "not constant" */ .Sin(0)
+const _ = int /* ERROR "not an expression" */
+
+func _() {
+ const _ = v /* ERROR "not constant" */
+ const _ = math /* ERROR "not constant" */ .Sin(0)
+ const _ = int /* ERROR "not an expression" */
+}
+
+// Identifier and expression arity must match.
+// The first error message is produced by the parser.
+// In a real-world scenario, the type-checker would not be run
+// in this case and the 2nd error message would not appear.
+const _ /* ERROR "missing constant value" */ /* ERROR "missing init expr for _" */
+const _ = 1, 2 /* ERROR "extra init expr 2" */
+
+const _ /* ERROR "missing constant value" */ /* ERROR "missing init expr for _" */ int
+const _ int = 1, 2 /* ERROR "extra init expr 2" */
+
+const (
+ _ /* ERROR "missing constant value" */ /* ERROR "missing init expr for _" */
+ _ = 1, 2 /* ERROR "extra init expr 2" */
+
+ _ /* ERROR "missing constant value" */ /* ERROR "missing init expr for _" */ int
+ _ int = 1, 2 /* ERROR "extra init expr 2" */
+)
+
+const (
+ _ = 1
+ _
+ _, _ /* ERROR "missing init expr for _" */
+ _
+)
+
+const (
+ _, _ = 1, 2
+ _, _
+ _ /* ERROR "extra init expr at" */
+ _, _
+ _, _, _ /* ERROR "missing init expr for _" */
+ _, _
+)
+
+func _() {
+ const _ /* ERROR "missing constant value" */ /* ERROR "missing init expr for _" */
+ const _ = 1, 2 /* ERROR "extra init expr 2" */
+
+ const _ /* ERROR "missing constant value" */ /* ERROR "missing init expr for _" */ int
+ const _ int = 1, 2 /* ERROR "extra init expr 2" */
+
+ const (
+ _ /* ERROR "missing constant value" */ /* ERROR "missing init expr for _" */
+ _ = 1, 2 /* ERROR "extra init expr 2" */
+
+ _ /* ERROR "missing constant value" */ /* ERROR "missing init expr for _" */ int
+ _ int = 1, 2 /* ERROR "extra init expr 2" */
+ )
+
+ const (
+ _ = 1
+ _
+ _, _ /* ERROR "missing init expr for _" */
+ _
+ )
+
+ const (
+ _, _ = 1, 2
+ _, _
+ _ /* ERROR "extra init expr at" */
+ _, _
+ _, _, _ /* ERROR "missing init expr for _" */
+ _, _
+ )
+}
+
+// Test case for constant with invalid initialization.
+// Caused panic because the constant value was not set up (gri - 7/8/2014).
+func _() {
+ const (
+ x string = missing /* ERROR "undeclared name" */
+ y = x + ""
+ )
+}
+
+// TODO(gri) move extra tests from testdata/const0.src into here
diff --git a/go/types/testdata/conversions.src b/go/types/testdata/conversions.src
new file mode 100644
index 0000000..e1336c0
--- /dev/null
+++ b/go/types/testdata/conversions.src
@@ -0,0 +1,93 @@
+// 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.
+
+// conversions
+
+package conversions
+
+import "unsafe"
+
+// argument count
+var (
+ _ = int() /* ERROR "missing argument" */
+ _ = int(1, 2 /* ERROR "too many arguments" */ )
+)
+
+// numeric constant conversions are in const1.src.
+
+func string_conversions() {
+ const A = string(65)
+ assert(A == "A")
+ const E = string(-1)
+ assert(E == "\uFFFD")
+ assert(E == string(1234567890))
+
+ type myint int
+ assert(A == string(myint(65)))
+
+ type mystring string
+ const _ mystring = mystring("foo")
+
+ const _ = string(true /* ERROR "cannot convert" */ )
+ const _ = string(1.2 /* ERROR "cannot convert" */ )
+ const _ = string(nil /* ERROR "cannot convert" */ )
+
+ // issues 11357, 11353: argument must be of integer type
+ _ = string(0.0 /* ERROR "cannot convert" */ )
+ _ = string(0i /* ERROR "cannot convert" */ )
+ _ = string(1 /* ERROR "cannot convert" */ + 2i)
+}
+
+func interface_conversions() {
+ type E interface{}
+
+ type I1 interface{
+ m1()
+ }
+
+ type I2 interface{
+ m1()
+ m2(x int)
+ }
+
+ type I3 interface{
+ m1()
+ m2() int
+ }
+
+ var e E
+ var i1 I1
+ var i2 I2
+ var i3 I3
+
+ _ = E(0)
+ _ = E(nil)
+ _ = E(e)
+ _ = E(i1)
+ _ = E(i2)
+
+ _ = I1(0 /* ERROR "cannot convert" */ )
+ _ = I1(nil)
+ _ = I1(i1)
+ _ = I1(e /* ERROR "cannot convert" */ )
+ _ = I1(i2)
+
+ _ = I2(nil)
+ _ = I2(i1 /* ERROR "cannot convert" */ )
+ _ = I2(i2)
+ _ = I2(i3 /* ERROR "cannot convert" */ )
+
+ _ = I3(nil)
+ _ = I3(i1 /* ERROR "cannot convert" */ )
+ _ = I3(i2 /* ERROR "cannot convert" */ )
+ _ = I3(i3)
+
+ // TODO(gri) add more tests, improve error message
+}
+
+func issue6326() {
+ type T unsafe.Pointer
+ var x T
+ _ = uintptr(x) // see issue 6326
+}
diff --git a/go/types/testdata/cycles.src b/go/types/testdata/cycles.src
new file mode 100644
index 0000000..621d83c
--- /dev/null
+++ b/go/types/testdata/cycles.src
@@ -0,0 +1,143 @@
+// 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 cycles
+
+type (
+ T0 int
+ T1 /* ERROR cycle */ T1
+ T2 *T2
+
+ T3 /* ERROR cycle */ T4
+ T4 T5
+ T5 T3
+
+ T6 T7
+ T7 *T8
+ T8 T6
+
+ // arrays
+ A0 /* ERROR cycle */ [10]A0
+ A1 [10]*A1
+
+ A2 /* ERROR cycle */ [10]A3
+ A3 [10]A4
+ A4 A2
+
+ A5 [10]A6
+ A6 *A5
+
+ // slices
+ L0 []L0
+
+ // structs
+ S0 /* ERROR cycle */ struct{ _ S0 }
+ S1 /* ERROR cycle */ struct{ S1 }
+ S2 struct{ _ *S2 }
+ S3 struct{ *S3 }
+
+ S4 /* ERROR cycle */ struct{ S5 }
+ S5 struct{ S6 }
+ S6 S4
+
+ // pointers
+ P0 *P0
+
+ // functions
+ F0 func(F0)
+ F1 func() F1
+ F2 func(F2) F2
+
+ // interfaces
+ I0 /* ERROR cycle */ interface{ I0 }
+
+ I1 interface{ I2 }
+ I2 interface{ I3 }
+ I3 /* ERROR cycle */ interface{ I1 }
+
+ I4 interface{ f(I4) }
+
+ // testcase for issue 5090
+ I5 interface{ f(I6) }
+ I6 interface{ I5 }
+
+ // maps
+ M0 map[M0 /* ERROR invalid map key */ ]M0
+
+ // channels
+ C0 chan C0
+)
+
+func _() {
+ type (
+ t1 /* ERROR cycle */ t1
+ t2 *t2
+
+ t3 t4 /* ERROR undeclared */
+ t4 t5 /* ERROR undeclared */
+ t5 t3
+
+ // arrays
+ a0 /* ERROR cycle */ [10]a0
+ a1 [10]*a1
+
+ // slices
+ l0 []l0
+
+ // structs
+ s0 /* ERROR cycle */ struct{ _ s0 }
+ s1 /* ERROR cycle */ struct{ s1 }
+ s2 struct{ _ *s2 }
+ s3 struct{ *s3 }
+
+ // pointers
+ p0 *p0
+
+ // functions
+ f0 func(f0)
+ f1 func() f1
+ f2 func(f2) f2
+
+ // interfaces
+ i0 /* ERROR cycle */ interface{ i0 }
+
+ // maps
+ m0 map[m0 /* ERROR invalid map key */ ]m0
+
+ // channels
+ c0 chan c0
+ )
+}
+
+// test cases for issue 6667
+
+type A [10]map[A /* ERROR invalid map key */ ]bool
+
+type S struct {
+ m map[S /* ERROR invalid map key */ ]bool
+}
+
+// test cases for issue 7236
+// (cycle detection must not be dependent on starting point of resolution)
+
+type (
+ P1 *T9
+ T9 /* ERROR cycle */ T9
+
+ T10 /* ERROR cycle */ T10
+ P2 *T10
+)
+
+func (T11) m() {}
+
+type T11 /* ERROR cycle */ struct{ T11 }
+
+type T12 /* ERROR cycle */ struct{ T12 }
+
+func (*T12) m() {}
+
+type (
+ P3 *T13
+ T13 /* ERROR cycle */ T13
+)
\ No newline at end of file
diff --git a/go/types/testdata/cycles1.src b/go/types/testdata/cycles1.src
new file mode 100644
index 0000000..ae2b38e
--- /dev/null
+++ b/go/types/testdata/cycles1.src
@@ -0,0 +1,77 @@
+// 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 p
+
+type (
+ A interface {
+ a() interface {
+ ABC1
+ }
+ }
+ B interface {
+ b() interface {
+ ABC2
+ }
+ }
+ C interface {
+ c() interface {
+ ABC3
+ }
+ }
+
+ AB interface {
+ A
+ B
+ }
+ BC interface {
+ B
+ C
+ }
+
+ ABC1 interface {
+ A
+ B
+ C
+ }
+ ABC2 interface {
+ AB
+ C
+ }
+ ABC3 interface {
+ A
+ BC
+ }
+)
+
+var (
+ x1 ABC1
+ x2 ABC2
+ x3 ABC3
+)
+
+func _() {
+ // all types have the same method set
+ x1 = x2
+ x2 = x1
+
+ x1 = x3
+ x3 = x1
+
+ x2 = x3
+ x3 = x2
+
+ // all methods return the same type again
+ x1 = x1.a()
+ x1 = x1.b()
+ x1 = x1.c()
+
+ x2 = x2.a()
+ x2 = x2.b()
+ x2 = x2.c()
+
+ x3 = x3.a()
+ x3 = x3.b()
+ x3 = x3.c()
+}
diff --git a/go/types/testdata/cycles2.src b/go/types/testdata/cycles2.src
new file mode 100644
index 0000000..345ab56
--- /dev/null
+++ b/go/types/testdata/cycles2.src
@@ -0,0 +1,118 @@
+// 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 p
+
+import "unsafe"
+
+// Test case for issue 5090
+
+type t interface {
+ f(u)
+}
+
+type u interface {
+ t
+}
+
+func _() {
+ var t t
+ var u u
+
+ t.f(t)
+ t.f(u)
+
+ u.f(t)
+ u.f(u)
+}
+
+
+// Test case for issue 6589.
+
+type A interface {
+ a() interface {
+ AB
+ }
+}
+
+type B interface {
+ a() interface {
+ AB
+ }
+}
+
+type AB interface {
+ a() interface {
+ A
+ B /* ERROR a redeclared */
+ }
+ b() interface {
+ A
+ B /* ERROR a redeclared */
+ }
+}
+
+var x AB
+var y interface {
+ A
+ B /* ERROR a redeclared */
+}
+var _ = x /* ERROR cannot compare */ == y
+
+
+// Test case for issue 6638.
+
+type T interface {
+ m() [T /* ERROR no value */ (nil).m()[0]]int
+}
+
+// Variations of this test case.
+
+type T1 interface {
+ m() [x1 /* ERROR no value */ .m()[0]]int
+}
+
+var x1 T1
+
+type T2 interface {
+ m() [len(x2 /* ERROR no value */ .m())]int
+}
+
+var x2 T2
+
+type T3 interface {
+ m() [unsafe.Sizeof(x3.m)]int
+}
+
+var x3 T3
+
+// The test case below should also report an error for
+// the cast inside the T4 interface (like it does for the
+// variable initialization). The reason why it does not is
+// that inside T4, the method x4.m depends on T4 which is not
+// fully set up yet. The x4.m method happens to have an empty
+// signature which is why the cast is permitted.
+// TODO(gri) Consider marking methods as incomplete and provide
+// a better error message in that case.
+
+type T4 interface {
+ m() [unsafe.Sizeof(cast4(x4.m))]int
+}
+
+var x4 T4
+var _ = cast4(x4 /* ERROR cannot convert */.m)
+
+type cast4 func()
+
+// This test is symmetric to the T4 case: Here the cast is
+// "correct", but it doesn't work inside the T5 interface.
+
+type T5 interface {
+ m() [unsafe.Sizeof(cast5(x5 /* ERROR cannot convert */ .m))]int
+}
+
+var x5 T5
+var _ = cast5(x5.m)
+
+type cast5 func() [0]int
diff --git a/go/types/testdata/cycles3.src b/go/types/testdata/cycles3.src
new file mode 100644
index 0000000..3da4fb5
--- /dev/null
+++ b/go/types/testdata/cycles3.src
@@ -0,0 +1,60 @@
+// 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 p
+
+import "unsafe"
+
+var (
+ _ A = A(nil).a().b().c().d().e().f()
+ _ A = A(nil).b().c().d().e().f()
+ _ A = A(nil).c().d().e().f()
+ _ A = A(nil).d().e().f()
+ _ A = A(nil).e().f()
+ _ A = A(nil).f()
+ _ A = A(nil)
+)
+
+type (
+ A interface {
+ a() B
+ B
+ }
+
+ B interface {
+ b() C
+ C
+ }
+
+ C interface {
+ c() D
+ D
+ }
+
+ D interface {
+ d() E
+ E
+ }
+
+ E interface {
+ e() F
+ F
+ }
+
+ F interface {
+ f() A
+ }
+)
+
+type (
+ U interface {
+ V
+ }
+
+ V interface {
+ v() [unsafe.Sizeof(u)]int
+ }
+)
+
+var u U
diff --git a/go/types/testdata/cycles4.src b/go/types/testdata/cycles4.src
new file mode 100644
index 0000000..445babc
--- /dev/null
+++ b/go/types/testdata/cycles4.src
@@ -0,0 +1,110 @@
+// 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 p
+
+// Check that all methods of T are collected before
+// determining the result type of m (which embeds
+// all methods of T).
+
+type T interface {
+ m() interface {T}
+ E
+}
+
+var _ = T.m(nil).m().e()
+
+type E interface {
+ e() int
+}
+
+// Check that unresolved forward chains are followed
+// (see also comment in resolver.go, checker.typeDecl).
+
+var _ = C.m(nil).m().e()
+
+type A B
+
+type B interface {
+ m() interface{C}
+ E
+}
+
+type C A
+
+// Check that interface type comparison for identity
+// does not recur endlessly.
+
+type T1 interface {
+ m() interface{T1}
+}
+
+type T2 interface {
+ m() interface{T2}
+}
+
+func _(x T1, y T2) {
+ // Checking for assignability of interfaces must check
+ // if all methods of x are present in y, and that they
+ // have identical signatures. The signatures recur via
+ // the result type, which is an interface that embeds
+ // a single method m that refers to the very interface
+ // that contains it. This requires cycle detection in
+ // identity checks for interface types.
+ x = y
+}
+
+type T3 interface {
+ m() interface{T4}
+}
+
+type T4 interface {
+ m() interface{T3}
+}
+
+func _(x T1, y T3) {
+ x = y
+}
+
+// Check that interfaces are type-checked in order of
+// (embedded interface) dependencies (was issue 7158).
+
+var x1 T5 = T7(nil)
+
+type T5 interface {
+ T6
+}
+
+type T6 interface {
+ m() T7
+}
+type T7 interface {
+ T5
+}
+
+// Actual test case from issue 7158.
+
+func wrapNode() Node {
+ return wrapElement()
+}
+
+func wrapElement() Element {
+ return nil
+}
+
+type EventTarget interface {
+ AddEventListener(Event)
+}
+
+type Node interface {
+ EventTarget
+}
+
+type Element interface {
+ Node
+}
+
+type Event interface {
+ Target() Element
+}
diff --git a/go/types/testdata/decls0.src b/go/types/testdata/decls0.src
new file mode 100644
index 0000000..21baafe
--- /dev/null
+++ b/go/types/testdata/decls0.src
@@ -0,0 +1,207 @@
+// 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.
+
+// type declarations
+
+package decls0
+
+import "unsafe"
+
+const pi = 3.1415
+
+type (
+ N undeclared /* ERROR "undeclared" */
+ B bool
+ I int32
+ A [10]P
+ T struct {
+ x, y P
+ }
+ P *T
+ R (*R)
+ F func(A) I
+ Y interface {
+ f(A) I
+ }
+ S [](((P)))
+ M map[I]F
+ C chan<- I
+
+ // blank types must be typechecked
+ _ pi /* ERROR "not a type" */
+ _ struct{}
+ _ struct{ pi /* ERROR "not a type" */ }
+)
+
+
+// declarations of init
+const _, init /* ERROR "cannot declare init" */ , _ = 0, 1, 2
+type init /* ERROR "cannot declare init" */ struct{}
+var _, init /* ERROR "cannot declare init" */ int
+
+func init() {}
+func init /* ERROR "missing function body" */ ()
+
+func _() { const init = 0 }
+func _() { type init int }
+func _() { var init int; _ = init }
+
+// invalid array types
+type (
+ iA0 [... /* ERROR "invalid use of '...'" */ ]byte
+ iA1 [1 /* ERROR "invalid array length" */ <<100]int
+ iA2 [- /* ERROR "invalid array length" */ 1]complex128
+ iA3 ["foo" /* ERROR "must be integer" */ ]string
+ iA4 [float64 /* ERROR "must be integer" */ (0)]int
+)
+
+
+type (
+ p1 pi /* ERROR "no field or method foo" */ .foo
+ p2 unsafe.Pointer
+)
+
+
+type (
+ Pi pi /* ERROR "not a type" */
+
+ a /* ERROR "illegal cycle" */ a
+ a /* ERROR "redeclared" */ int
+
+ // where the cycle error appears depends on the
+ // order in which declarations are processed
+ // (which depends on the order in which a map
+ // is iterated through)
+ b /* ERROR "illegal cycle" */ c
+ c d
+ d e
+ e b
+
+ t *t
+
+ U V
+ V *W
+ W U
+
+ P1 *S2
+ P2 P1
+
+ S0 struct {
+ }
+ S1 struct {
+ a, b, c int
+ u, v, a /* ERROR "redeclared" */ float32
+ }
+ S2 struct {
+ S0 // anonymous field
+ S0 /* ERROR "redeclared" */ int
+ }
+ S3 struct {
+ x S2
+ }
+ S4/* ERROR "illegal cycle" */ struct {
+ S4
+ }
+ S5 /* ERROR "illegal cycle" */ struct {
+ S6
+ }
+ S6 struct {
+ field S7
+ }
+ S7 struct {
+ S5
+ }
+
+ L1 []L1
+ L2 []int
+
+ A1 [10.0]int
+ A2 /* ERROR "illegal cycle" */ [10]A2
+ A3 /* ERROR "illegal cycle" */ [10]struct {
+ x A4
+ }
+ A4 [10]A3
+
+ F1 func()
+ F2 func(x, y, z float32)
+ F3 func(x, y, x /* ERROR "redeclared" */ float32)
+ F4 func() (x, y, x /* ERROR "redeclared" */ float32)
+ F5 func(x int) (x /* ERROR "redeclared" */ float32)
+ F6 func(x ...int)
+
+ I1 interface{}
+ I2 interface {
+ m1()
+ }
+ I3 interface {
+ m1()
+ m1 /* ERROR "redeclared" */ ()
+ }
+ I4 interface {
+ m1(x, y, x /* ERROR "redeclared" */ float32)
+ m2() (x, y, x /* ERROR "redeclared" */ float32)
+ m3(x int) (x /* ERROR "redeclared" */ float32)
+ }
+ I5 interface {
+ m1(I5)
+ }
+ I6 interface {
+ S0 /* ERROR "not an interface" */
+ }
+ I7 interface {
+ I1
+ I1
+ }
+ I8 /* ERROR "illegal cycle" */ interface {
+ I8
+ }
+ I9 interface {
+ I10
+ }
+ I10 interface {
+ I11
+ }
+ I11 /* ERROR "illegal cycle" */ interface {
+ I9
+ }
+
+ C1 chan int
+ C2 <-chan int
+ C3 chan<- C3
+ C4 chan C5
+ C5 chan C6
+ C6 chan C4
+
+ M1 map[Last]string
+ M2 map[string]M2
+
+ Last int
+)
+
+// cycles in function/method declarations
+// (test cases for issue 5217 and variants)
+func f1(x f1 /* ERROR "not a type" */ ) {}
+func f2(x *f2 /* ERROR "not a type" */ ) {}
+func f3() (x f3 /* ERROR "not a type" */ ) { return }
+func f4() (x *f4 /* ERROR "not a type" */ ) { return }
+
+func (S0) m1(x S0 /* ERROR "field or method" */ .m1) {}
+func (S0) m2(x *S0 /* ERROR "field or method" */ .m2) {}
+func (S0) m3() (x S0 /* ERROR "field or method" */ .m3) { return }
+func (S0) m4() (x *S0 /* ERROR "field or method" */ .m4) { return }
+
+// interfaces may not have any blank methods
+type BlankI interface {
+ _ /* ERROR "invalid method name" */ ()
+ _ /* ERROR "invalid method name" */ (float32) int
+ m()
+}
+
+// non-interface types may have multiple blank methods
+type BlankT struct{}
+
+func (BlankT) _() {}
+func (BlankT) _(int) {}
+func (BlankT) _() int { return 0 }
+func (BlankT) _(int) int { return 0}
diff --git a/go/types/testdata/decls1.src b/go/types/testdata/decls1.src
new file mode 100644
index 0000000..7855e46
--- /dev/null
+++ b/go/types/testdata/decls1.src
@@ -0,0 +1,144 @@
+// 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.
+
+// variable declarations
+
+package decls1
+
+import (
+ "math"
+)
+
+// Global variables without initialization
+var (
+ a, b bool
+ c byte
+ d uint8
+ r rune
+ i int
+ j, k, l int
+ x, y float32
+ xx, yy float64
+ u, v complex64
+ uu, vv complex128
+ s, t string
+ array []byte
+ iface interface{}
+
+ blank _ /* ERROR "cannot use _" */
+)
+
+// Global variables with initialization
+var (
+ s1 = i + j
+ s2 = i /* ERROR "mismatched types" */ + x
+ s3 = c + d
+ s4 = s + t
+ s5 = s /* ERROR "invalid operation" */ / t
+ s6 = array[t1]
+ s7 = array[x /* ERROR "integer" */]
+ s8 = &a
+ s10 = &42 /* ERROR "cannot take address" */
+ s11 = &v
+ s12 = -(u + *t11) / *&v
+ s13 = a /* ERROR "shifted operand" */ << d
+ s14 = i << j /* ERROR "must be unsigned" */
+ s18 = math.Pi * 10.0
+ s19 = s1 /* ERROR "cannot call" */ ()
+ s20 = f0 /* ERROR "no value" */ ()
+ s21 = f6(1, s1, i)
+ s22 = f6(1, s1, uu /* ERROR "cannot pass argument" */ )
+
+ t1 int = i + j
+ t2 int = i /* ERROR "mismatched types" */ + x
+ t3 int = c /* ERROR "cannot initialize" */ + d
+ t4 string = s + t
+ t5 string = s /* ERROR "invalid operation" */ / t
+ t6 byte = array[t1]
+ t7 byte = array[x /* ERROR "must be integer" */]
+ t8 *int = & /* ERROR "cannot initialize" */ a
+ t10 *int = &42 /* ERROR "cannot take address" */
+ t11 *complex64 = &v
+ t12 complex64 = -(u + *t11) / *&v
+ t13 int = a /* ERROR "shifted operand" */ << d
+ t14 int = i << j /* ERROR "must be unsigned" */
+ t15 math /* ERROR "not in selector" */
+ t16 math /* ERROR "not declared" */ .xxx
+ t17 math /* ERROR "not a type" */ .Pi
+ t18 float64 = math.Pi * 10.0
+ t19 int = t1 /* ERROR "cannot call" */ ()
+ t20 int = f0 /* ERROR "no value" */ ()
+ t21 int = a /* ERROR "cannot initialize" */
+)
+
+// Various more complex expressions
+var (
+ u1 = x /* ERROR "not an interface" */ .(int)
+ u2 = iface.([]int)
+ u3 = iface.(a /* ERROR "not a type" */ )
+ u4, ok = iface.(int)
+ u5, ok2, ok3 = iface /* ERROR "assignment count mismatch" */ .(int)
+)
+
+// Constant expression initializations
+var (
+ v1 = 1 /* ERROR "cannot convert" */ + "foo"
+ v2 = c + 255
+ v3 = c + 256 /* ERROR "overflows" */
+ v4 = r + 2147483647
+ v5 = r + 2147483648 /* ERROR "overflows" */
+ v6 = 42
+ v7 = v6 + 9223372036854775807
+ v8 = v6 + 9223372036854775808 /* ERROR "overflows" */
+ v9 = i + 1 << 10
+ v10 byte = 1024 /* ERROR "overflows" */
+ v11 = xx/yy*yy - xx
+ v12 = true && false
+ v13 = nil /* ERROR "use of untyped nil" */
+)
+
+// Multiple assignment expressions
+var (
+ m1a, m1b = 1, 2
+ m2a, m2b, m2c /* ERROR "missing init expr for m2c" */ = 1, 2
+ m3a, m3b = 1, 2, 3 /* ERROR "extra init expr 3" */
+)
+
+func _() {
+ var (
+ m1a, m1b = 1, 2
+ m2a, m2b, m2c /* ERROR "missing init expr for m2c" */ = 1, 2
+ m3a, m3b = 1, 2, 3 /* ERROR "extra init expr 3" */
+ )
+
+ _, _ = m1a, m1b
+ _, _, _ = m2a, m2b, m2c
+ _, _ = m3a, m3b
+}
+
+// Declaration of parameters and results
+func f0() {}
+func f1(a /* ERROR "not a type" */) {}
+func f2(a, b, c d /* ERROR "not a type" */) {}
+
+func f3() int { return 0 }
+func f4() a /* ERROR "not a type" */ { return 0 }
+func f5() (a, b, c d /* ERROR "not a type" */) { return }
+
+func f6(a, b, c int) complex128 { return 0 }
+
+// Declaration of receivers
+type T struct{}
+
+func (T) m0() {}
+func (*T) m1() {}
+func (x T) m2() {}
+func (x *T) m3() {}
+
+// Initialization functions
+func init() {}
+func /* ERROR "no arguments and no return values" */ init(int) {}
+func /* ERROR "no arguments and no return values" */ init() int { return 0 }
+func /* ERROR "no arguments and no return values" */ init(int) int { return 0 }
+func (T) init(int) int { return 0 }
diff --git a/go/types/testdata/decls2a.src b/go/types/testdata/decls2a.src
new file mode 100644
index 0000000..bdbecd9
--- /dev/null
+++ b/go/types/testdata/decls2a.src
@@ -0,0 +1,111 @@
+// 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.
+
+// method declarations
+
+package decls2
+
+import "time"
+import "unsafe"
+
+// T1 declared before its methods.
+type T1 struct{
+ f int
+}
+
+func (T1) m() {}
+func (T1) m /* ERROR "already declared" */ () {}
+func (x *T1) f /* ERROR "field and method" */ () {}
+
+// Conflict between embedded field and method name,
+// with the embedded field being a basic type.
+type T1b struct {
+ int
+}
+
+func (T1b) int /* ERROR "field and method" */ () {}
+
+type T1c struct {
+ time.Time
+}
+
+func (T1c) Time /* ERROR "field and method" */ () int { return 0 }
+
+// Disabled for now: LookupFieldOrMethod will find Pointer even though
+// it's double-declared (it would cost extra in the common case to verify
+// this). But the MethodSet computation will not find it due to the name
+// collision caused by the double-declaration, leading to an internal
+// inconsistency while we are verifying one computation against the other.
+// var _ = T1c{}.Pointer
+
+// T2's method declared before the type.
+func (*T2) f /* ERROR "field and method" */ () {}
+
+type T2 struct {
+ f int
+}
+
+// Methods declared without a declared type.
+func (undeclared /* ERROR "undeclared" */) m() {}
+func (x *undeclared /* ERROR "undeclared" */) m() {}
+
+func (pi /* ERROR "not a type" */) m1() {}
+func (x pi /* ERROR "not a type" */) m2() {}
+func (x *pi /* ERROR "not a type" */ ) m3() {}
+
+// Blank types.
+type _ struct { m int }
+type _ struct { m int }
+
+func (_ /* ERROR "cannot use _" */) m() {}
+func m(_ /* ERROR "cannot use _" */) {}
+
+// Methods with receiver base type declared in another file.
+func (T3) m1() {}
+func (*T3) m2() {}
+func (x T3) m3() {}
+func (x *T3) f /* ERROR "field and method" */ () {}
+
+// Methods of non-struct type.
+type T4 func()
+
+func (self T4) m() func() { return self }
+
+// Methods associated with an interface.
+type T5 interface {
+ m() int
+}
+
+func (T5 /* ERROR "invalid receiver" */ ) m1() {}
+func (T5 /* ERROR "invalid receiver" */ ) m2() {}
+
+// Methods associated with a named pointer type.
+type ptr *int
+func (ptr /* ERROR "invalid receiver" */ ) _() {}
+func (* /* ERROR "invalid receiver" */ ptr) _() {}
+
+// Methods with zero or multiple receivers.
+func ( /* ERROR "missing receiver" */ ) _() {}
+func (T3, * /* ERROR "exactly one receiver" */ T3) _() {}
+func (T3, T3, T3 /* ERROR "exactly one receiver" */ ) _() {}
+func (a, b /* ERROR "exactly one receiver" */ T3) _() {}
+func (a, b, c /* ERROR "exactly one receiver" */ T3) _() {}
+
+// Methods associated with non-local or unnamed types.
+func (int /* ERROR "invalid receiver" */ ) m() {}
+func ([ /* ERROR "invalid receiver" */ ]int) m() {}
+func (time /* ERROR "invalid receiver" */ .Time) m() {}
+func (* /* ERROR "invalid receiver" */ time.Time) m() {}
+func (x /* ERROR "invalid receiver" */ interface{}) m() {}
+
+// Unsafe.Pointer is treated like a pointer when used as receiver type.
+type UP unsafe.Pointer
+func (UP /* ERROR "invalid" */ ) m1() {}
+func (* /* ERROR "invalid" */ UP) m2() {}
+
+// Double declarations across package files
+const c_double = 0
+type t_double int
+var v_double int
+func f_double() {}
diff --git a/go/types/testdata/decls2b.src b/go/types/testdata/decls2b.src
new file mode 100644
index 0000000..e7bc394
--- /dev/null
+++ b/go/types/testdata/decls2b.src
@@ -0,0 +1,65 @@
+// 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.
+
+// method declarations
+
+package decls2
+
+import "io"
+
+const pi = 3.1415
+
+func (T1) m /* ERROR "already declared" */ () {}
+func (T2) m(io.Writer) {}
+
+type T3 struct {
+ f *T3
+}
+
+type T6 struct {
+ x int
+}
+
+func (t *T6) m1() int {
+ return t.x
+}
+
+func f() {
+ var t *T6
+ t.m1()
+}
+
+// Double declarations across package files
+const c_double /* ERROR "redeclared" */ = 0
+type t_double /* ERROR "redeclared" */ int
+var v_double /* ERROR "redeclared" */ int
+func f_double /* ERROR "redeclared" */ () {}
+
+// Blank methods need to be type-checked.
+// Verify by checking that errors are reported.
+func (T /* ERROR "undeclared" */ ) _() {}
+func (T1) _(undeclared /* ERROR "undeclared" */ ) {}
+func (T1) _() int { return "foo" /* ERROR "cannot convert" */ }
+
+// Methods with undeclared receiver type can still be checked.
+// Verify by checking that errors are reported.
+func (Foo /* ERROR "undeclared" */ ) m() {}
+func (Foo /* ERROR "undeclared" */ ) m(undeclared /* ERROR "undeclared" */ ) {}
+func (Foo /* ERROR "undeclared" */ ) m() int { return "foo" /* ERROR "cannot convert" */ }
+
+func (Foo /* ERROR "undeclared" */ ) _() {}
+func (Foo /* ERROR "undeclared" */ ) _(undeclared /* ERROR "undeclared" */ ) {}
+func (Foo /* ERROR "undeclared" */ ) _() int { return "foo" /* ERROR "cannot convert" */ }
+
+// Receiver declarations are regular parameter lists;
+// receiver types may use parentheses, and the list
+// may have a trailing comma.
+type T7 struct {}
+
+func (T7) m1() {}
+func ((T7)) m2() {}
+func ((*T7)) m3() {}
+func (x *(T7),) m4() {}
+func (x (*(T7)),) m5() {}
+func (x ((*((T7)))),) m6() {}
diff --git a/go/types/testdata/decls3.src b/go/types/testdata/decls3.src
new file mode 100644
index 0000000..80d2bc8
--- /dev/null
+++ b/go/types/testdata/decls3.src
@@ -0,0 +1,309 @@
+// 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.
+
+// embedded types
+
+package decls3
+
+import "unsafe"
+import "fmt"
+
+// fields with the same name at the same level cancel each other out
+
+func _() {
+ type (
+ T1 struct { X int }
+ T2 struct { X int }
+ T3 struct { T1; T2 } // X is embedded twice at the same level via T1->X, T2->X
+ )
+
+ var t T3
+ _ = t /* ERROR "ambiguous selector" */ .X
+}
+
+func _() {
+ type (
+ T1 struct { X int }
+ T2 struct { T1 }
+ T3 struct { T1 }
+ T4 struct { T2; T3 } // X is embedded twice at the same level via T2->T1->X, T3->T1->X
+ )
+
+ var t T4
+ _ = t /* ERROR "ambiguous selector" */ .X
+}
+
+func issue4355() {
+ type (
+ T1 struct {X int}
+ T2 struct {T1}
+ T3 struct {T2}
+ T4 struct {T2}
+ T5 struct {T3; T4} // X is embedded twice at the same level via T3->T2->T1->X, T4->T2->T1->X
+ )
+
+ var t T5
+ _ = t /* ERROR "ambiguous selector" */ .X
+}
+
+func _() {
+ type State int
+ type A struct{ State }
+ type B struct{ fmt.State }
+ type T struct{ A; B }
+
+ var t T
+ _ = t /* ERROR "ambiguous selector" */ .State
+}
+
+// Embedded fields can be predeclared types.
+
+func _() {
+ type T0 struct{
+ int
+ float32
+ f int
+ }
+ var x T0
+ _ = x.int
+ _ = x.float32
+ _ = x.f
+
+ type T1 struct{
+ T0
+ }
+ var y T1
+ _ = y.int
+ _ = y.float32
+ _ = y.f
+}
+
+// Restrictions on embedded field types.
+
+func _() {
+ type I1 interface{}
+ type I2 interface{}
+ type P1 *int
+ type P2 *int
+ type UP unsafe.Pointer
+
+ type T1 struct {
+ I1
+ * /* ERROR "cannot be a pointer to an interface" */ I2
+ * /* ERROR "cannot be a pointer to an interface" */ error
+ P1 /* ERROR "cannot be a pointer" */
+ * /* ERROR "cannot be a pointer" */ P2
+ }
+
+ // unsafe.Pointers are treated like regular pointers when embedded
+ type T2 struct {
+ unsafe /* ERROR "cannot be unsafe.Pointer" */ .Pointer
+ */* ERROR "cannot be unsafe.Pointer" */ unsafe.Pointer
+ UP /* ERROR "cannot be unsafe.Pointer" */
+ * /* ERROR "cannot be unsafe.Pointer" */ UP
+ }
+}
+
+// Named types that are pointers.
+
+type S struct{ x int }
+func (*S) m() {}
+type P *S
+
+func _() {
+ var s *S
+ _ = s.x
+ _ = s.m
+
+ var p P
+ _ = p.x
+ _ = p /* ERROR "no field or method" */ .m
+ _ = P /* ERROR "no field or method" */ .m
+}
+
+// Borrowed from the FieldByName test cases in reflect/all_test.go.
+
+type D1 struct {
+ d int
+}
+type D2 struct {
+ d int
+}
+
+type S0 struct {
+ A, B, C int
+ D1
+ D2
+}
+
+type S1 struct {
+ B int
+ S0
+}
+
+type S2 struct {
+ A int
+ *S1
+}
+
+type S1x struct {
+ S1
+}
+
+type S1y struct {
+ S1
+}
+
+type S3 struct {
+ S1x
+ S2
+ D, E int
+ *S1y
+}
+
+type S4 struct {
+ *S4
+ A int
+}
+
+// The X in S6 and S7 annihilate, but they also block the X in S8.S9.
+type S5 struct {
+ S6
+ S7
+ S8
+}
+
+type S6 struct {
+ X int
+}
+
+type S7 S6
+
+type S8 struct {
+ S9
+}
+
+type S9 struct {
+ X int
+ Y int
+}
+
+// The X in S11.S6 and S12.S6 annihilate, but they also block the X in S13.S8.S9.
+type S10 struct {
+ S11
+ S12
+ S13
+}
+
+type S11 struct {
+ S6
+}
+
+type S12 struct {
+ S6
+}
+
+type S13 struct {
+ S8
+}
+
+func _() {
+ _ = struct /* ERROR "no field or method" */ {}{}.Foo
+ _ = S0{}.A
+ _ = S0 /* ERROR "no field or method" */ {}.D
+ _ = S1{}.A
+ _ = S1{}.B
+ _ = S1{}.S0
+ _ = S1{}.C
+ _ = S2{}.A
+ _ = S2{}.S1
+ _ = S2{}.B
+ _ = S2{}.C
+ _ = S2 /* ERROR "no field or method" */ {}.D
+ _ = S3 /* ERROR "ambiguous selector" */ {}.S1
+ _ = S3{}.A
+ _ = S3 /* ERROR "ambiguous selector" */ {}.B
+ _ = S3{}.D
+ _ = S3{}.E
+ _ = S4{}.A
+ _ = S4 /* ERROR "no field or method" */ {}.B
+ _ = S5 /* ERROR "ambiguous selector" */ {}.X
+ _ = S5{}.Y
+ _ = S10 /* ERROR "ambiguous selector" */ {}.X
+ _ = S10{}.Y
+}
+
+// Borrowed from the FieldByName benchmark in reflect/all_test.go.
+
+type R0 struct {
+ *R1
+ *R2
+ *R3
+ *R4
+}
+
+type R1 struct {
+ *R5
+ *R6
+ *R7
+ *R8
+}
+
+type R2 R1
+type R3 R1
+type R4 R1
+
+type R5 struct {
+ *R9
+ *R10
+ *R11
+ *R12
+}
+
+type R6 R5
+type R7 R5
+type R8 R5
+
+type R9 struct {
+ *R13
+ *R14
+ *R15
+ *R16
+}
+
+type R10 R9
+type R11 R9
+type R12 R9
+
+type R13 struct {
+ *R17
+ *R18
+ *R19
+ *R20
+}
+
+type R14 R13
+type R15 R13
+type R16 R13
+
+type R17 struct {
+ *R21
+ *R22
+ *R23
+ *R24
+}
+
+type R18 R17
+type R19 R17
+type R20 R17
+
+type R21 struct {
+ X int
+}
+
+type R22 R21
+type R23 R21
+type R24 R21
+
+var _ = R0 /* ERROR "ambiguous selector" */ {}.X
\ No newline at end of file
diff --git a/go/types/testdata/errors.src b/go/types/testdata/errors.src
new file mode 100644
index 0000000..45bd45a
--- /dev/null
+++ b/go/types/testdata/errors.src
@@ -0,0 +1,55 @@
+// 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 errors
+
+// Testing precise operand formatting in error messages
+// (matching messages are regular expressions, hence the \'s).
+func f(x int, m map[string]int) {
+ // no values
+ _ = f /* ERROR "f\(0, m\) \(no value\) used as value" */ (0, m)
+
+ // built-ins
+ _ = println /* ERROR "println \(built-in\) must be called" */
+
+ // types
+ _ = complex128 /* ERROR "complex128 \(type\) is not an expression" */
+
+ // constants
+ const c1 = 991
+ const c2 float32 = 0.5
+ 0 /* ERROR "0 \(untyped int constant\) is not used" */
+ c1 /* ERROR "c1 \(untyped int constant 991\) is not used" */
+ c2 /* ERROR "c2 \(constant 1/2 of type float32\) is not used" */
+ c1 /* ERROR "c1 \+ c2 \(constant 1983/2 of type float32\) is not used" */ + c2
+
+ // variables
+ x /* ERROR "x \(variable of type int\) is not used" */
+
+ // values
+ x /* ERROR "x != x \(untyped bool value\) is not used" */ != x
+ x /* ERROR "x \+ x \(value of type int\) is not used" */ + x
+
+ // value, ok's
+ const s = "foo"
+ m /* ERROR "m\[s\] \(map index expression of type int\) is not used" */ [s]
+}
+
+// Valid ERROR comments can have a variety of forms.
+func _() {
+ 0 /* ERROR "0 .* is not used" */
+ 0 /* ERROR 0 .* is not used */
+ 0 // ERROR "0 .* is not used"
+ 0 // ERROR 0 .* is not used
+}
+
+// Don't report spurious errors as a consequence of earlier errors.
+// Add more tests as needed.
+func _() {
+ if err := foo /* ERROR undeclared */ (); err != nil /* no error here */ {}
+}
+
+// Use unqualified names for package-local objects.
+type T struct{}
+var _ int = T /* ERROR value of type T */ {} // use T in error message rather then errors.T
diff --git a/go/types/testdata/expr0.src b/go/types/testdata/expr0.src
new file mode 100644
index 0000000..3120c6f
--- /dev/null
+++ b/go/types/testdata/expr0.src
@@ -0,0 +1,174 @@
+// 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.
+
+// unary expressions
+
+package expr0
+
+type mybool bool
+
+var (
+ // bool
+ b0 = true
+ b1 bool = b0
+ b2 = !true
+ b3 = !b1
+ b4 bool = !true
+ b5 bool = !b4
+ b6 = +b0 /* ERROR "not defined" */
+ b7 = -b0 /* ERROR "not defined" */
+ b8 = ^b0 /* ERROR "not defined" */
+ b9 = *b0 /* ERROR "cannot indirect" */
+ b10 = &true /* ERROR "cannot take address" */
+ b11 = &b0
+ b12 = <-b0 /* ERROR "cannot receive" */
+ b13 = & & /* ERROR "cannot take address" */ b0
+
+ // byte
+ _ = byte(0)
+ _ = byte(- /* ERROR "cannot convert" */ 1)
+ _ = - /* ERROR "-byte\(1\) \(constant -1 of type byte\) overflows byte" */ byte(1) // test for issue 11367
+ _ = byte /* ERROR "overflows byte" */ (0) - byte(1)
+
+ // int
+ i0 = 1
+ i1 int = i0
+ i2 = +1
+ i3 = +i0
+ i4 int = +1
+ i5 int = +i4
+ i6 = -1
+ i7 = -i0
+ i8 int = -1
+ i9 int = -i4
+ i10 = !i0 /* ERROR "not defined" */
+ i11 = ^1
+ i12 = ^i0
+ i13 int = ^1
+ i14 int = ^i4
+ i15 = *i0 /* ERROR "cannot indirect" */
+ i16 = &i0
+ i17 = *i16
+ i18 = <-i16 /* ERROR "cannot receive" */
+
+ // uint
+ u0 = uint(1)
+ u1 uint = u0
+ u2 = +1
+ u3 = +u0
+ u4 uint = +1
+ u5 uint = +u4
+ u6 = -1
+ u7 = -u0
+ u8 uint = - /* ERROR "overflows" */ 1
+ u9 uint = -u4
+ u10 = !u0 /* ERROR "not defined" */
+ u11 = ^1
+ u12 = ^i0
+ u13 uint = ^ /* ERROR "overflows" */ 1
+ u14 uint = ^u4
+ u15 = *u0 /* ERROR "cannot indirect" */
+ u16 = &u0
+ u17 = *u16
+ u18 = <-u16 /* ERROR "cannot receive" */
+ u19 = ^uint(0)
+
+ // float64
+ f0 = float64(1)
+ f1 float64 = f0
+ f2 = +1
+ f3 = +f0
+ f4 float64 = +1
+ f5 float64 = +f4
+ f6 = -1
+ f7 = -f0
+ f8 float64 = -1
+ f9 float64 = -f4
+ f10 = !f0 /* ERROR "not defined" */
+ f11 = ^1
+ f12 = ^i0
+ f13 float64 = ^1
+ f14 float64 = ^f4 /* ERROR "not defined" */
+ f15 = *f0 /* ERROR "cannot indirect" */
+ f16 = &f0
+ f17 = *u16
+ f18 = <-u16 /* ERROR "cannot receive" */
+
+ // complex128
+ c0 = complex128(1)
+ c1 complex128 = c0
+ c2 = +1
+ c3 = +c0
+ c4 complex128 = +1
+ c5 complex128 = +c4
+ c6 = -1
+ c7 = -c0
+ c8 complex128 = -1
+ c9 complex128 = -c4
+ c10 = !c0 /* ERROR "not defined" */
+ c11 = ^1
+ c12 = ^i0
+ c13 complex128 = ^1
+ c14 complex128 = ^c4 /* ERROR "not defined" */
+ c15 = *c0 /* ERROR "cannot indirect" */
+ c16 = &c0
+ c17 = *u16
+ c18 = <-u16 /* ERROR "cannot receive" */
+
+ // string
+ s0 = "foo"
+ s1 = +"foo" /* ERROR "not defined" */
+ s2 = -s0 /* ERROR "not defined" */
+ s3 = !s0 /* ERROR "not defined" */
+ s4 = ^s0 /* ERROR "not defined" */
+ s5 = *s4
+ s6 = &s4
+ s7 = *s6
+ s8 = <-s7
+
+ // channel
+ ch chan int
+ rc <-chan float64
+ sc chan <- string
+ ch0 = +ch /* ERROR "not defined" */
+ ch1 = -ch /* ERROR "not defined" */
+ ch2 = !ch /* ERROR "not defined" */
+ ch3 = ^ch /* ERROR "not defined" */
+ ch4 = *ch /* ERROR "cannot indirect" */
+ ch5 = &ch
+ ch6 = *ch5
+ ch7 = <-ch
+ ch8 = <-rc
+ ch9 = <-sc /* ERROR "cannot receive" */
+ ch10, ok = <-ch
+ // ok is of type bool
+ ch11, myok = <-ch
+ _ mybool = myok /* ERROR "cannot initialize" */
+)
+
+// address of composite literals
+type T struct{x, y int}
+
+func f() T { return T{} }
+
+var (
+ _ = &T{1, 2}
+ _ = &[...]int{}
+ _ = &[]int{}
+ _ = &[]int{}
+ _ = &map[string]T{}
+ _ = &(T{1, 2})
+ _ = &((((T{1, 2}))))
+ _ = &f /* ERROR "cannot take address" */ ()
+)
+
+// recursive pointer types
+type P *P
+
+var (
+ p1 P = new(P)
+ p2 P = *p1
+ p3 P = &p2
+)
+
diff --git a/go/types/testdata/expr1.src b/go/types/testdata/expr1.src
new file mode 100644
index 0000000..8ef0aed
--- /dev/null
+++ b/go/types/testdata/expr1.src
@@ -0,0 +1,7 @@
+// 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.
+
+// binary expressions
+
+package expr1
diff --git a/go/types/testdata/expr2.src b/go/types/testdata/expr2.src
new file mode 100644
index 0000000..31dc5f0
--- /dev/null
+++ b/go/types/testdata/expr2.src
@@ -0,0 +1,247 @@
+// 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.
+
+// comparisons
+
+package expr2
+
+func _bool() {
+ const t = true == true
+ const f = true == false
+ _ = t /* ERROR "cannot compare" */ < f
+ _ = 0 /* ERROR "cannot convert" */ == t
+ var b bool
+ var x, y float32
+ b = x < y
+ _ = b
+ _ = struct{b bool}{x < y}
+}
+
+// corner cases
+var (
+ v0 = nil /* ERROR "cannot compare" */ == nil
+)
+
+func arrays() {
+ // basics
+ var a, b [10]int
+ _ = a == b
+ _ = a != b
+ _ = a /* ERROR < not defined */ < b
+ _ = a == nil /* ERROR cannot convert */
+
+ type C [10]int
+ var c C
+ _ = a == c
+
+ type D [10]int
+ var d D
+ _ = c /* ERROR mismatched types */ == d
+
+ var e [10]func() int
+ _ = e /* ERROR == not defined */ == e
+}
+
+func structs() {
+ // basics
+ var s, t struct {
+ x int
+ a [10]float32
+ _ bool
+ }
+ _ = s == t
+ _ = s != t
+ _ = s /* ERROR < not defined */ < t
+ _ = s == nil /* ERROR cannot convert */
+
+ type S struct {
+ x int
+ a [10]float32
+ _ bool
+ }
+ type T struct {
+ x int
+ a [10]float32
+ _ bool
+ }
+ var ss S
+ var tt T
+ _ = s == ss
+ _ = ss /* ERROR mismatched types */ == tt
+
+ var u struct {
+ x int
+ a [10]map[string]int
+ }
+ _ = u /* ERROR cannot compare */ == u
+}
+
+func pointers() {
+ // nil
+ _ = nil /* ERROR == not defined */ == nil
+ _ = nil /* ERROR != not defined */ != nil
+ _ = nil /* ERROR < not defined */ < nil
+ _ = nil /* ERROR <= not defined */ <= nil
+ _ = nil /* ERROR > not defined */ > nil
+ _ = nil /* ERROR >= not defined */ >= nil
+
+ // basics
+ var p, q *int
+ _ = p == q
+ _ = p != q
+
+ _ = p == nil
+ _ = p != nil
+ _ = nil == q
+ _ = nil != q
+
+ _ = p /* ERROR < not defined */ < q
+ _ = p /* ERROR <= not defined */ <= q
+ _ = p /* ERROR > not defined */ > q
+ _ = p /* ERROR >= not defined */ >= q
+
+ // various element types
+ type (
+ S1 struct{}
+ S2 struct{}
+ P1 *S1
+ P2 *S2
+ )
+ var (
+ ps1 *S1
+ ps2 *S2
+ p1 P1
+ p2 P2
+ )
+ _ = ps1 == ps1
+ _ = ps1 /* ERROR mismatched types */ == ps2
+ _ = ps2 /* ERROR mismatched types */ == ps1
+
+ _ = p1 == p1
+ _ = p1 /* ERROR mismatched types */ == p2
+
+ _ = p1 == ps1
+}
+
+func channels() {
+ // basics
+ var c, d chan int
+ _ = c == d
+ _ = c != d
+ _ = c == nil
+ _ = c /* ERROR < not defined */ < d
+
+ // various element types (named types)
+ type (
+ C1 chan int
+ C1r <-chan int
+ C1s chan<- int
+ C2 chan float32
+ )
+ var (
+ c1 C1
+ c1r C1r
+ c1s C1s
+ c1a chan int
+ c2 C2
+ )
+ _ = c1 == c1
+ _ = c1 /* ERROR mismatched types */ == c1r
+ _ = c1 /* ERROR mismatched types */ == c1s
+ _ = c1r /* ERROR mismatched types */ == c1s
+ _ = c1 == c1a
+ _ = c1a == c1
+ _ = c1 /* ERROR mismatched types */ == c2
+ _ = c1a /* ERROR mismatched types */ == c2
+
+ // various element types (unnamed types)
+ var (
+ d1 chan int
+ d1r <-chan int
+ d1s chan<- int
+ d1a chan<- int
+ d2 chan float32
+ )
+ _ = d1 == d1
+ _ = d1 == d1r
+ _ = d1 == d1s
+ _ = d1r /* ERROR mismatched types */ == d1s
+ _ = d1 == d1a
+ _ = d1a == d1
+ _ = d1 /* ERROR mismatched types */ == d2
+ _ = d1a /* ERROR mismatched types */ == d2
+}
+
+// for interfaces test
+type S1 struct{}
+type S11 struct{}
+type S2 struct{}
+func (*S1) m() int
+func (*S11) m() int
+func (*S11) n()
+func (*S2) m() float32
+
+func interfaces() {
+ // basics
+ var i, j interface{ m() int }
+ _ = i == j
+ _ = i != j
+ _ = i == nil
+ _ = i /* ERROR < not defined */ < j
+
+ // various interfaces
+ var ii interface { m() int; n() }
+ var k interface { m() float32 }
+ _ = i == ii
+ _ = i /* ERROR mismatched types */ == k
+
+ // interfaces vs values
+ var s1 S1
+ var s11 S11
+ var s2 S2
+
+ _ = i == 0 /* ERROR cannot convert */
+ _ = i /* ERROR mismatched types */ == s1
+ _ = i == &s1
+ _ = i == &s11
+
+ _ = i /* ERROR mismatched types */ == s2
+ _ = i /* ERROR mismatched types */ == &s2
+}
+
+func slices() {
+ // basics
+ var s []int
+ _ = s == nil
+ _ = s != nil
+ _ = s /* ERROR < not defined */ < nil
+
+ // slices are not otherwise comparable
+ _ = s /* ERROR == not defined */ == s
+ _ = s /* ERROR < not defined */ < s
+}
+
+func maps() {
+ // basics
+ var m map[string]int
+ _ = m == nil
+ _ = m != nil
+ _ = m /* ERROR < not defined */ < nil
+
+ // maps are not otherwise comparable
+ _ = m /* ERROR == not defined */ == m
+ _ = m /* ERROR < not defined */ < m
+}
+
+func funcs() {
+ // basics
+ var f func(int) float32
+ _ = f == nil
+ _ = f != nil
+ _ = f /* ERROR < not defined */ < nil
+
+ // funcs are not otherwise comparable
+ _ = f /* ERROR == not defined */ == f
+ _ = f /* ERROR < not defined */ < f
+}
diff --git a/go/types/testdata/expr3.src b/go/types/testdata/expr3.src
new file mode 100644
index 0000000..5772095
--- /dev/null
+++ b/go/types/testdata/expr3.src
@@ -0,0 +1,534 @@
+// 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 expr3
+
+import "time"
+
+func indexes() {
+ _ = 1 /* ERROR "cannot index" */ [0]
+ _ = indexes /* ERROR "cannot index" */ [0]
+ _ = ( /* ERROR "cannot slice" */ 12 + 3)[1:2]
+
+ var a [10]int
+ _ = a[true /* ERROR "cannot convert" */ ]
+ _ = a["foo" /* ERROR "cannot convert" */ ]
+ _ = a[1.1 /* ERROR "truncated" */ ]
+ _ = a[1.0]
+ _ = a[- /* ERROR "negative" */ 1]
+ _ = a[- /* ERROR "negative" */ 1 :]
+ _ = a[: - /* ERROR "negative" */ 1]
+ _ = a[: /* ERROR "2nd index required" */ : /* ERROR "3rd index required" */ ]
+ _ = a[0: /* ERROR "2nd index required" */ : /* ERROR "3rd index required" */ ]
+ _ = a[0: /* ERROR "2nd index required" */ :10]
+ _ = a[:10:10]
+
+ var a0 int
+ a0 = a[0]
+ _ = a0
+ var a1 int32
+ a1 = a /* ERROR "cannot assign" */ [1]
+ _ = a1
+
+ _ = a[9]
+ _ = a[10 /* ERROR "index .* out of bounds" */ ]
+ _ = a[1 /* ERROR "overflows" */ <<100]
+ _ = a[10:]
+ _ = a[:10]
+ _ = a[10:10]
+ _ = a[11 /* ERROR "index .* out of bounds" */ :]
+ _ = a[: 11 /* ERROR "index .* out of bounds" */ ]
+ _ = a[: 1 /* ERROR "overflows" */ <<100]
+ _ = a[:10:10]
+ _ = a[:11 /* ERROR "index .* out of bounds" */ :10]
+ _ = a[:10:11 /* ERROR "index .* out of bounds" */ ]
+ _ = a[10:0:10] /* ERROR "invalid slice indices" */
+ _ = a[0:10:0] /* ERROR "invalid slice indices" */
+ _ = a[10:0:0] /* ERROR "invalid slice indices" */
+ _ = &a /* ERROR "cannot take address" */ [:10]
+
+ pa := &a
+ _ = pa[9]
+ _ = pa[10 /* ERROR "index .* out of bounds" */ ]
+ _ = pa[1 /* ERROR "overflows" */ <<100]
+ _ = pa[10:]
+ _ = pa[:10]
+ _ = pa[10:10]
+ _ = pa[11 /* ERROR "index .* out of bounds" */ :]
+ _ = pa[: 11 /* ERROR "index .* out of bounds" */ ]
+ _ = pa[: 1 /* ERROR "overflows" */ <<100]
+ _ = pa[:10:10]
+ _ = pa[:11 /* ERROR "index .* out of bounds" */ :10]
+ _ = pa[:10:11 /* ERROR "index .* out of bounds" */ ]
+ _ = pa[10:0:10] /* ERROR "invalid slice indices" */
+ _ = pa[0:10:0] /* ERROR "invalid slice indices" */
+ _ = pa[10:0:0] /* ERROR "invalid slice indices" */
+ _ = &pa /* ERROR "cannot take address" */ [:10]
+
+ var b [0]int
+ _ = b[0 /* ERROR "index .* out of bounds" */ ]
+ _ = b[:]
+ _ = b[0:]
+ _ = b[:0]
+ _ = b[0:0]
+ _ = b[0:0:0]
+ _ = b[1 /* ERROR "index .* out of bounds" */ :0:0]
+
+ var s []int
+ _ = s[- /* ERROR "negative" */ 1]
+ _ = s[- /* ERROR "negative" */ 1 :]
+ _ = s[: - /* ERROR "negative" */ 1]
+ _ = s[0]
+ _ = s[1:2]
+ _ = s[2:1] /* ERROR "invalid slice indices" */
+ _ = s[2:]
+ _ = s[: 1 /* ERROR "overflows" */ <<100]
+ _ = s[1 /* ERROR "overflows" */ <<100 :]
+ _ = s[1 /* ERROR "overflows" */ <<100 : 1 /* ERROR "overflows" */ <<100]
+ _ = s[: /* ERROR "2nd index required" */ : /* ERROR "3rd index required" */ ]
+ _ = s[:10:10]
+ _ = s[10:0:10] /* ERROR "invalid slice indices" */
+ _ = s[0:10:0] /* ERROR "invalid slice indices" */
+ _ = s[10:0:0] /* ERROR "invalid slice indices" */
+ _ = &s /* ERROR "cannot take address" */ [:10]
+
+ var m map[string]int
+ _ = m[0 /* ERROR "cannot convert" */ ]
+ _ = m /* ERROR "cannot slice" */ ["foo" : "bar"]
+ _ = m["foo"]
+ // ok is of type bool
+ type mybool bool
+ var ok mybool
+ _, ok = m["bar"]
+ _ = ok
+
+ var t string
+ _ = t[- /* ERROR "negative" */ 1]
+ _ = t[- /* ERROR "negative" */ 1 :]
+ _ = t[: - /* ERROR "negative" */ 1]
+ _ = t /* ERROR "3-index slice of string" */ [1:2:3]
+ _ = "foo" /* ERROR "3-index slice of string" */ [1:2:3]
+ var t0 byte
+ t0 = t[0]
+ _ = t0
+ var t1 rune
+ t1 = t /* ERROR "cannot assign" */ [2]
+ _ = t1
+ _ = ("foo" + "bar")[5]
+ _ = ("foo" + "bar")[6 /* ERROR "index .* out of bounds" */ ]
+
+ const c = "foo"
+ _ = c[- /* ERROR "negative" */ 1]
+ _ = c[- /* ERROR "negative" */ 1 :]
+ _ = c[: - /* ERROR "negative" */ 1]
+ var c0 byte
+ c0 = c[0]
+ _ = c0
+ var c2 float32
+ c2 = c /* ERROR "cannot assign" */ [2]
+ _ = c[3 /* ERROR "index .* out of bounds" */ ]
+ _ = ""[0 /* ERROR "index .* out of bounds" */ ]
+ _ = c2
+
+ _ = s[1<<30] // no compile-time error here
+
+ // issue 4913
+ type mystring string
+ var ss string
+ var ms mystring
+ var i, j int
+ ss = "foo"[1:2]
+ ss = "foo"[i:j]
+ ms = "foo" /* ERROR "cannot assign" */ [1:2]
+ ms = "foo" /* ERROR "cannot assign" */ [i:j]
+ _, _ = ss, ms
+}
+
+type T struct {
+ x int
+ y func()
+}
+
+func (*T) m() {}
+
+func method_expressions() {
+ _ = T /* ERROR "no field or method" */ .a
+ _ = T /* ERROR "has no method" */ .x
+ _ = T /* ERROR "not in method set" */ .m
+ _ = (*T).m
+
+ var f func(*T) = T /* ERROR "not in method set" */ .m
+ var g func(*T) = (*T).m
+ _, _ = f, g
+
+ _ = T /* ERROR "has no method" */ .y
+ _ = ( /* ERROR "has no method" */ *T).y
+}
+
+func struct_literals() {
+ type T0 struct {
+ a, b, c int
+ }
+
+ type T1 struct {
+ T0
+ a, b int
+ u float64
+ s string
+ }
+
+ // keyed elements
+ _ = T1{}
+ _ = T1{a: 0, 1 /* ERROR "mixture of .* elements" */ }
+ _ = T1{aa /* ERROR "unknown field" */ : 0}
+ _ = T1{1 /* ERROR "invalid field name" */ : 0}
+ _ = T1{a: 0, s: "foo", u: 0, a /* ERROR "duplicate field" */: 10}
+ _ = T1{a: "foo" /* ERROR "cannot convert" */ }
+ _ = T1{c /* ERROR "unknown field" */ : 0}
+ _ = T1{T0: { /* ERROR "missing type" */ }} // struct literal element type may not be elided
+ _ = T1{T0: T0{}}
+ _ = T1{T0 /* ERROR "invalid field name" */ .a: 0}
+
+ // unkeyed elements
+ _ = T0{1, 2, 3}
+ _ = T0{1, b /* ERROR "mixture" */ : 2, 3}
+ _ = T0{1, 2} /* ERROR "too few values" */
+ _ = T0{1, 2, 3, 4 /* ERROR "too many values" */ }
+ _ = T0{1, "foo" /* ERROR "cannot convert" */, 3.4 /* ERROR "truncated" */}
+
+ // invalid type
+ type P *struct{
+ x int
+ }
+ _ = P /* ERROR "invalid composite literal type" */ {}
+
+ // unexported fields
+ _ = time.Time{}
+ _ = time.Time{sec /* ERROR "unknown field" */ : 0}
+ _ = time.Time{
+ 0 /* ERROR implicit assignment to unexported field sec in time.Time literal */,
+ 0 /* ERROR implicit assignment */ ,
+ nil /* ERROR implicit assignment */ ,
+ }
+}
+
+func array_literals() {
+ type A0 [0]int
+ _ = A0{}
+ _ = A0{0 /* ERROR "index .* out of bounds" */}
+ _ = A0{0 /* ERROR "index .* out of bounds" */ : 0}
+
+ type A1 [10]int
+ _ = A1{}
+ _ = A1{0, 1, 2}
+ _ = A1{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
+ _ = A1{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 /* ERROR "index .* out of bounds" */ }
+ _ = A1{- /* ERROR "negative" */ 1: 0}
+ _ = A1{8: 8, 9}
+ _ = A1{8: 8, 9, 10 /* ERROR "index .* out of bounds" */ }
+ _ = A1{0, 1, 2, 0 /* ERROR "duplicate index" */ : 0, 3: 3, 4}
+ _ = A1{5: 5, 6, 7, 3: 3, 4}
+ _ = A1{5: 5, 6, 7, 3: 3, 4, 5 /* ERROR "duplicate index" */ }
+ _ = A1{10 /* ERROR "index .* out of bounds" */ : 10, 10 /* ERROR "index .* out of bounds" */ : 10}
+ _ = A1{5: 5, 6, 7, 3: 3, 1 /* ERROR "overflows" */ <<100: 4, 5 /* ERROR "duplicate index" */ }
+ _ = A1{5: 5, 6, 7, 4: 4, 1 /* ERROR "overflows" */ <<100: 4}
+ _ = A1{2.0}
+ _ = A1{2.1 /* ERROR "truncated" */ }
+ _ = A1{"foo" /* ERROR "cannot convert" */ }
+
+ // indices must be integer constants
+ i := 1
+ const f = 2.1
+ const s = "foo"
+ _ = A1{i /* ERROR "index i must be integer constant" */ : 0}
+ _ = A1{f /* ERROR "truncated" */ : 0}
+ _ = A1{s /* ERROR "cannot convert" */ : 0}
+
+ a0 := [...]int{}
+ assert(len(a0) == 0)
+
+ a1 := [...]int{0, 1, 2}
+ assert(len(a1) == 3)
+ var a13 [3]int
+ var a14 [4]int
+ a13 = a1
+ a14 = a1 /* ERROR "cannot assign" */
+ _, _ = a13, a14
+
+ a2 := [...]int{- /* ERROR "negative" */ 1: 0}
+ _ = a2
+
+ a3 := [...]int{0, 1, 2, 0 /* ERROR "duplicate index" */ : 0, 3: 3, 4}
+ assert(len(a3) == 5) // somewhat arbitrary
+
+ a4 := [...]complex128{0, 1, 2, 1<<10-2: -1i, 1i, 400: 10, 12, 14}
+ assert(len(a4) == 1024)
+
+ // composite literal element types may be elided
+ type T []int
+ _ = [10]T{T{}, {}, 5: T{1, 2, 3}, 7: {1, 2, 3}}
+ a6 := [...]T{T{}, {}, 5: T{1, 2, 3}, 7: {1, 2, 3}}
+ assert(len(a6) == 8)
+
+ // recursively so
+ _ = [10][10]T{{}, [10]T{{}}, {{1, 2, 3}}}
+
+ // from the spec
+ type Point struct { x, y float32 }
+ _ = [...]Point{Point{1.5, -3.5}, Point{0, 0}}
+ _ = [...]Point{{1.5, -3.5}, {0, 0}}
+ _ = [][]int{[]int{1, 2, 3}, []int{4, 5}}
+ _ = [][]int{{1, 2, 3}, {4, 5}}
+ _ = [...]*Point{&Point{1.5, -3.5}, &Point{0, 0}}
+ _ = [...]*Point{{1.5, -3.5}, {0, 0}}
+}
+
+func slice_literals() {
+ type S0 []int
+ _ = S0{}
+ _ = S0{0, 1, 2}
+ _ = S0{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
+ _ = S0{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
+ _ = S0{- /* ERROR "negative" */ 1: 0}
+ _ = S0{8: 8, 9}
+ _ = S0{8: 8, 9, 10}
+ _ = S0{0, 1, 2, 0 /* ERROR "duplicate index" */ : 0, 3: 3, 4}
+ _ = S0{5: 5, 6, 7, 3: 3, 4}
+ _ = S0{5: 5, 6, 7, 3: 3, 4, 5 /* ERROR "duplicate index" */ }
+ _ = S0{10: 10, 10 /* ERROR "duplicate index" */ : 10}
+ _ = S0{5: 5, 6, 7, 3: 3, 1 /* ERROR "overflows" */ <<100: 4, 5 /* ERROR "duplicate index" */ }
+ _ = S0{5: 5, 6, 7, 4: 4, 1 /* ERROR "overflows" */ <<100: 4}
+ _ = S0{2.0}
+ _ = S0{2.1 /* ERROR "truncated" */ }
+ _ = S0{"foo" /* ERROR "cannot convert" */ }
+
+ // indices must be resolved correctly
+ const index1 = 1
+ _ = S0{index1: 1}
+ _ = S0{index2: 2}
+ _ = S0{index3 /* ERROR "undeclared name" */ : 3}
+
+ // indices must be integer constants
+ i := 1
+ const f = 2.1
+ const s = "foo"
+ _ = S0{i /* ERROR "index i must be integer constant" */ : 0}
+ _ = S0{f /* ERROR "truncated" */ : 0}
+ _ = S0{s /* ERROR "cannot convert" */ : 0}
+
+ // composite literal element types may be elided
+ type T []int
+ _ = []T{T{}, {}, 5: T{1, 2, 3}, 7: {1, 2, 3}}
+ _ = [][]int{{1, 2, 3}, {4, 5}}
+
+ // recursively so
+ _ = [][]T{{}, []T{{}}, {{1, 2, 3}}}
+}
+
+const index2 int = 2
+
+type N int
+func (N) f() {}
+
+func map_literals() {
+ type M0 map[string]int
+ type M1 map[bool]int
+ type M2 map[*int]int
+
+ _ = M0{}
+ _ = M0{1 /* ERROR "missing key" */ }
+ _ = M0{1 /* ERROR "cannot convert" */ : 2}
+ _ = M0{"foo": "bar" /* ERROR "cannot convert" */ }
+ _ = M0{"foo": 1, "bar": 2, "foo" /* ERROR "duplicate key" */ : 3 }
+
+ _ = map[interface{}]int{2: 1, 2 /* ERROR "duplicate key" */ : 1}
+ _ = map[interface{}]int{int(2): 1, int16(2): 1}
+ _ = map[interface{}]int{int16(2): 1, int16 /* ERROR "duplicate key" */ (2): 1}
+
+ type S string
+
+ _ = map[interface{}]int{"a": 1, "a" /* ERROR "duplicate key" */ : 1}
+ _ = map[interface{}]int{"a": 1, S("a"): 1}
+ _ = map[interface{}]int{S("a"): 1, S /* ERROR "duplicate key" */ ("a"): 1}
+
+ type I interface {
+ f()
+ }
+
+ _ = map[I]int{N(0): 1, N(2): 1}
+ _ = map[I]int{N(2): 1, N /* ERROR "duplicate key" */ (2): 1}
+
+ // map keys must be resolved correctly
+ key1 := "foo"
+ _ = M0{key1: 1}
+ _ = M0{key2: 2}
+ _ = M0{key3 /* ERROR "undeclared name" */ : 2}
+
+ var value int
+ _ = M1{true: 1, false: 0}
+ _ = M2{nil: 0, &value: 1}
+
+ // composite literal element types may be elided
+ type T [2]int
+ _ = map[int]T{0: T{3, 4}, 1: {5, 6}}
+
+ // recursively so
+ _ = map[int][]T{0: {}, 1: {{}, T{1, 2}}}
+
+ // composite literal key types may be elided
+ _ = map[T]int{T{3, 4}: 0, {5, 6}: 1}
+
+ // recursively so
+ _ = map[[2]T]int{{}: 0, {{}}: 1, [2]T{{}}: 2, {T{1, 2}}: 3}
+
+ // composite literal element and key types may be elided
+ _ = map[T]T{{}: {}, {1, 2}: T{3, 4}, T{4, 5}: {}}
+ _ = map[T]M0{{} : {}, T{1, 2}: M0{"foo": 0}, {1, 3}: {"foo": 1}}
+
+ // recursively so
+ _ = map[[2]T][]T{{}: {}, {{}}: {{}, T{1, 2}}, [2]T{{}}: nil, {T{1, 2}}: {{}, {}}}
+
+ // from the spec
+ type Point struct { x, y float32 }
+ _ = map[string]Point{"orig": {0, 0}}
+ _ = map[*Point]string{{0, 0}: "orig"}
+}
+
+var key2 string = "bar"
+
+type I interface {
+ m()
+}
+
+type I2 interface {
+ m(int)
+}
+
+type T1 struct{}
+type T2 struct{}
+
+func (T2) m(int) {}
+
+type mybool bool
+
+func type_asserts() {
+ var x int
+ _ = x /* ERROR "not an interface" */ .(int)
+
+ var e interface{}
+ var ok bool
+ x, ok = e.(int)
+ _ = ok
+
+ // ok value is of type bool
+ var myok mybool
+ _, myok = e.(int)
+ _ = myok
+
+ var t I
+ _ = t /* ERROR "use of .* outside type switch" */ .(type)
+ _ = t /* ERROR "missing method m" */ .(T)
+ _ = t.(*T)
+ _ = t /* ERROR "missing method m" */ .(T1)
+ _ = t /* ERROR "wrong type for method m" */ .(T2)
+ _ = t /* STRICT "wrong type for method m" */ .(I2) // only an error in strict mode (issue 8561)
+
+ // e doesn't statically have an m, but may have one dynamically.
+ _ = e.(I2)
+}
+
+func f0() {}
+func f1(x int) {}
+func f2(u float32, s string) {}
+func fs(s []byte) {}
+func fv(x ...int) {}
+func fi(x ... interface{}) {}
+func (T) fm(x ...int)
+
+func g0() {}
+func g1() int { return 0}
+func g2() (u float32, s string) { return }
+func gs() []byte { return nil }
+
+func _calls() {
+ var x int
+ var y float32
+ var s []int
+
+ f0()
+ _ = f0 /* ERROR "used as value" */ ()
+ f0(g0 /* ERROR "too many arguments" */ )
+
+ f1(0)
+ f1(x)
+ f1(10.0)
+ f1() /* ERROR "too few arguments" */
+ f1(x, y /* ERROR "too many arguments" */ )
+ f1(s /* ERROR "cannot pass" */ )
+ f1(x ... /* ERROR "cannot use ..." */ )
+ f1(g0 /* ERROR "used as value" */ ())
+ f1(g1())
+ // f1(g2()) // TODO(gri) missing position in error message
+
+ f2() /* ERROR "too few arguments" */
+ f2(3.14) /* ERROR "too few arguments" */
+ f2(3.14, "foo")
+ f2(x /* ERROR "cannot pass" */ , "foo")
+ f2(g0 /* ERROR "used as value" */ ())
+ f2(g1 /* ERROR "cannot pass" */ ()) /* ERROR "too few arguments" */
+ f2(g2())
+
+ fs() /* ERROR "too few arguments" */
+ fs(g0 /* ERROR "used as value" */ ())
+ fs(g1 /* ERROR "cannot pass" */ ())
+ fs(g2 /* ERROR "cannot pass" */ /* ERROR "too many arguments" */ ())
+ fs(gs())
+
+ fv()
+ fv(1, 2.0, x)
+ fv(s /* ERROR "cannot pass" */ )
+ fv(s...)
+ fv(x /* ERROR "cannot use" */ ...)
+ fv(1, s... /* ERROR "can only use ... with matching parameter" */ )
+ fv(gs /* ERROR "cannot pass" */ ())
+ fv(gs /* ERROR "cannot pass" */ ()...)
+
+ var t T
+ t.fm()
+ t.fm(1, 2.0, x)
+ t.fm(s /* ERROR "cannot pass" */ )
+ t.fm(g1())
+ t.fm(1, s... /* ERROR "can only use ... with matching parameter" */ )
+ t.fm(gs /* ERROR "cannot pass" */ ())
+ t.fm(gs /* ERROR "cannot pass" */ ()...)
+
+ T.fm(t, )
+ T.fm(t, 1, 2.0, x)
+ T.fm(t, s /* ERROR "cannot pass" */ )
+ T.fm(t, g1())
+ T.fm(t, 1, s... /* ERROR "can only use ... with matching parameter" */ )
+ T.fm(t, gs /* ERROR "cannot pass" */ ())
+ T.fm(t, gs /* ERROR "cannot pass" */ ()...)
+
+ var i interface{ fm(x ...int) } = t
+ i.fm()
+ i.fm(1, 2.0, x)
+ i.fm(s /* ERROR "cannot pass" */ )
+ i.fm(g1())
+ i.fm(1, s... /* ERROR "can only use ... with matching parameter" */ )
+ i.fm(gs /* ERROR "cannot pass" */ ())
+ i.fm(gs /* ERROR "cannot pass" */ ()...)
+
+ fi()
+ fi(1, 2.0, x, 3.14, "foo")
+ fi(g2())
+ fi(0, g2)
+ fi(0, g2 /* ERROR "2-valued expression" */ ())
+}
+
+func issue6344() {
+ type T []interface{}
+ var x T
+ fi(x...) // ... applies also to named slices
+}
diff --git a/go/types/testdata/gotos.src b/go/types/testdata/gotos.src
new file mode 100644
index 0000000..0c7ee44
--- /dev/null
+++ b/go/types/testdata/gotos.src
@@ -0,0 +1,560 @@
+// 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 file is a modified copy of $GOROOT/test/goto.go.
+
+package gotos
+
+var (
+ i, n int
+ x []int
+ c chan int
+ m map[int]int
+ s string
+)
+
+// goto after declaration okay
+func _() {
+ x := 1
+ goto L
+L:
+ _ = x
+}
+
+// goto before declaration okay
+func _() {
+ goto L
+L:
+ x := 1
+ _ = x
+}
+
+// goto across declaration not okay
+func _() {
+ goto L /* ERROR "goto L jumps over variable declaration at line 36" */
+ x := 1
+ _ = x
+L:
+}
+
+// goto across declaration in inner scope okay
+func _() {
+ goto L
+ {
+ x := 1
+ _ = x
+ }
+L:
+}
+
+// goto across declaration after inner scope not okay
+func _() {
+ goto L /* ERROR "goto L jumps over variable declaration at line 58" */
+ {
+ x := 1
+ _ = x
+ }
+ x := 1
+ _ = x
+L:
+}
+
+// goto across declaration in reverse okay
+func _() {
+L:
+ x := 1
+ _ = x
+ goto L
+}
+
+func _() {
+L: L1:
+ x := 1
+ _ = x
+ goto L
+ goto L1
+}
+
+// error shows first offending variable
+func _() {
+ goto L /* ERROR "goto L jumps over variable declaration at line 84" */
+ x := 1
+ _ = x
+ y := 1
+ _ = y
+L:
+}
+
+// goto not okay even if code path is dead
+func _() {
+ goto L /* ERROR "goto L jumps over variable declaration" */
+ x := 1
+ _ = x
+ y := 1
+ _ = y
+ return
+L:
+}
+
+// goto into outer block okay
+func _() {
+ {
+ goto L
+ }
+L:
+}
+
+func _() {
+ {
+ goto L
+ goto L1
+ }
+L: L1:
+}
+
+// goto backward into outer block okay
+func _() {
+L:
+ {
+ goto L
+ }
+}
+
+func _() {
+L: L1:
+ {
+ goto L
+ goto L1
+ }
+}
+
+// goto into inner block not okay
+func _() {
+ goto L /* ERROR "goto L jumps into block" */
+ {
+ L:
+ }
+}
+
+func _() {
+ goto L /* ERROR "goto L jumps into block" */
+ goto L1 /* ERROR "goto L1 jumps into block" */
+ {
+ L: L1:
+ }
+}
+
+// goto backward into inner block still not okay
+func _() {
+ {
+ L:
+ }
+ goto L /* ERROR "goto L jumps into block" */
+}
+
+func _() {
+ {
+ L: L1:
+ }
+ goto L /* ERROR "goto L jumps into block" */
+ goto L1 /* ERROR "goto L1 jumps into block" */
+}
+
+// error shows first (outermost) offending block
+func _() {
+ goto L /* ERROR "goto L jumps into block" */
+ {
+ {
+ {
+ L:
+ }
+ }
+ }
+}
+
+// error prefers block diagnostic over declaration diagnostic
+func _() {
+ goto L /* ERROR "goto L jumps into block" */
+ x := 1
+ _ = x
+ {
+ L:
+ }
+}
+
+// many kinds of blocks, all invalid to jump into or among,
+// but valid to jump out of
+
+// if
+
+func _() {
+L:
+ if true {
+ goto L
+ }
+}
+
+func _() {
+L:
+ if true {
+ goto L
+ } else {
+ }
+}
+
+func _() {
+L:
+ if false {
+ } else {
+ goto L
+ }
+}
+
+func _() {
+ goto L /* ERROR "goto L jumps into block" */
+ if true {
+ L:
+ }
+}
+
+func _() {
+ goto L /* ERROR "goto L jumps into block" */
+ if true {
+ L:
+ } else {
+ }
+}
+
+func _() {
+ goto L /* ERROR "goto L jumps into block" */
+ if true {
+ } else {
+ L:
+ }
+}
+
+func _() {
+ if false {
+ L:
+ } else {
+ goto L /* ERROR "goto L jumps into block" */
+ }
+}
+
+func _() {
+ if true {
+ goto L /* ERROR "goto L jumps into block" */
+ } else {
+ L:
+ }
+}
+
+func _() {
+ if true {
+ goto L /* ERROR "goto L jumps into block" */
+ } else if false {
+ L:
+ }
+}
+
+func _() {
+ if true {
+ goto L /* ERROR "goto L jumps into block" */
+ } else if false {
+ L:
+ } else {
+ }
+}
+
+func _() {
+ if true {
+ goto L /* ERROR "goto L jumps into block" */
+ } else if false {
+ } else {
+ L:
+ }
+}
+
+func _() {
+ if true {
+ goto L /* ERROR "goto L jumps into block" */
+ } else {
+ L:
+ }
+}
+
+func _() {
+ if true {
+ L:
+ } else {
+ goto L /* ERROR "goto L jumps into block" */
+ }
+}
+
+// for
+
+func _() {
+ for {
+ goto L
+ }
+L:
+}
+
+func _() {
+ for {
+ goto L
+ L:
+ }
+}
+
+func _() {
+ for {
+ L:
+ }
+ goto L /* ERROR "goto L jumps into block" */
+}
+
+func _() {
+ for {
+ goto L
+ L1:
+ }
+L:
+ goto L1 /* ERROR "goto L1 jumps into block" */
+}
+
+func _() {
+ for i < n {
+ L:
+ }
+ goto L /* ERROR "goto L jumps into block" */
+}
+
+func _() {
+ for i = 0; i < n; i++ {
+ L:
+ }
+ goto L /* ERROR "goto L jumps into block" */
+}
+
+func _() {
+ for i = range x {
+ L:
+ }
+ goto L /* ERROR "goto L jumps into block" */
+}
+
+func _() {
+ for i = range c {
+ L:
+ }
+ goto L /* ERROR "goto L jumps into block" */
+}
+
+func _() {
+ for i = range m {
+ L:
+ }
+ goto L /* ERROR "goto L jumps into block" */
+}
+
+func _() {
+ for i = range s {
+ L:
+ }
+ goto L /* ERROR "goto L jumps into block" */
+}
+
+// switch
+
+func _() {
+L:
+ switch i {
+ case 0:
+ goto L
+ }
+}
+
+func _() {
+L:
+ switch i {
+ case 0:
+
+ default:
+ goto L
+ }
+}
+
+func _() {
+ switch i {
+ case 0:
+
+ default:
+ L:
+ goto L
+ }
+}
+
+func _() {
+ switch i {
+ case 0:
+
+ default:
+ goto L
+ L:
+ }
+}
+
+func _() {
+ switch i {
+ case 0:
+ goto L
+ L:
+ ;
+ default:
+ }
+}
+
+func _() {
+ goto L /* ERROR "goto L jumps into block" */
+ switch i {
+ case 0:
+ L:
+ }
+}
+
+func _() {
+ goto L /* ERROR "goto L jumps into block" */
+ switch i {
+ case 0:
+ L:
+ ;
+ default:
+ }
+}
+
+func _() {
+ goto L /* ERROR "goto L jumps into block" */
+ switch i {
+ case 0:
+ default:
+ L:
+ }
+}
+
+func _() {
+ switch i {
+ default:
+ goto L /* ERROR "goto L jumps into block" */
+ case 0:
+ L:
+ }
+}
+
+func _() {
+ switch i {
+ case 0:
+ L:
+ ;
+ default:
+ goto L /* ERROR "goto L jumps into block" */
+ }
+}
+
+// select
+// different from switch. the statement has no implicit block around it.
+
+func _() {
+L:
+ select {
+ case <-c:
+ goto L
+ }
+}
+
+func _() {
+L:
+ select {
+ case c <- 1:
+
+ default:
+ goto L
+ }
+}
+
+func _() {
+ select {
+ case <-c:
+
+ default:
+ L:
+ goto L
+ }
+}
+
+func _() {
+ select {
+ case c <- 1:
+
+ default:
+ goto L
+ L:
+ }
+}
+
+func _() {
+ select {
+ case <-c:
+ goto L
+ L:
+ ;
+ default:
+ }
+}
+
+func _() {
+ goto L /* ERROR "goto L jumps into block" */
+ select {
+ case c <- 1:
+ L:
+ }
+}
+
+func _() {
+ goto L /* ERROR "goto L jumps into block" */
+ select {
+ case c <- 1:
+ L:
+ ;
+ default:
+ }
+}
+
+func _() {
+ goto L /* ERROR "goto L jumps into block" */
+ select {
+ case <-c:
+ default:
+ L:
+ }
+}
+
+func _() {
+ select {
+ default:
+ goto L /* ERROR "goto L jumps into block" */
+ case <-c:
+ L:
+ }
+}
+
+func _() {
+ select {
+ case <-c:
+ L:
+ ;
+ default:
+ goto L /* ERROR "goto L jumps into block" */
+ }
+}
diff --git a/go/types/testdata/importdecl0a.src b/go/types/testdata/importdecl0a.src
new file mode 100644
index 0000000..463dcd0
--- /dev/null
+++ b/go/types/testdata/importdecl0a.src
@@ -0,0 +1,53 @@
+// 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 importdecl0
+
+import ()
+
+import (
+ // we can have multiple blank imports (was bug)
+ _ "math"
+ _ "net/rpc"
+ init /* ERROR "cannot declare init" */ "fmt"
+ // reflect defines a type "flag" which shows up in the gc export data
+ "reflect"
+ . /* ERROR "imported but not used" */ "reflect"
+)
+
+import "math" /* ERROR "imported but not used" */
+import m /* ERROR "imported but not used as m" */ "math"
+import _ "math"
+
+import (
+ "math/big" /* ERROR "imported but not used" */
+ b /* ERROR "imported but not used" */ "math/big"
+ _ "math/big"
+)
+
+import "fmt"
+import f1 "fmt"
+import f2 "fmt"
+
+// reflect.flag must not be visible in this package
+type flag int
+type _ reflect /* ERROR "not exported" */ .flag
+
+// imported package name may conflict with local objects
+type reflect /* ERROR "reflect already declared" */ int
+
+// dot-imported exported objects may conflict with local objects
+type Value /* ERROR "Value already declared through dot-import of package reflect" */ struct{}
+
+var _ = fmt.Println // use "fmt"
+
+func _() {
+ f1.Println() // use "fmt"
+}
+
+func _() {
+ _ = func() {
+ f2.Println() // use "fmt"
+ }
+}
diff --git a/go/types/testdata/importdecl0b.src b/go/types/testdata/importdecl0b.src
new file mode 100644
index 0000000..6844e70
--- /dev/null
+++ b/go/types/testdata/importdecl0b.src
@@ -0,0 +1,33 @@
+// 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 importdecl0
+
+import "math"
+import m "math"
+
+import . "testing" // declares T in file scope
+import . /* ERROR "imported but not used" */ "unsafe"
+import . "fmt" // declares Println in file scope
+
+import (
+ // TODO(gri) At the moment, 2 errors are reported because both go/parser
+ // and the type checker report it. Eventually, this test should not be
+ // done by the parser anymore.
+ "" /* ERROR invalid import path */ /* ERROR invalid import path */
+ "a!b" /* ERROR invalid import path */ /* ERROR invalid import path */
+ "abc\xffdef" /* ERROR invalid import path */ /* ERROR invalid import path */
+)
+
+// using "math" in this file doesn't affect its use in other files
+const Pi0 = math.Pi
+const Pi1 = m.Pi
+
+type _ T // use "testing"
+
+func _() func() interface{} {
+ return func() interface{} {
+ return Println // use "fmt"
+ }
+}
diff --git a/go/types/testdata/importdecl1a.src b/go/types/testdata/importdecl1a.src
new file mode 100644
index 0000000..8301820
--- /dev/null
+++ b/go/types/testdata/importdecl1a.src
@@ -0,0 +1,11 @@
+// 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.
+
+// Test case for issue 8969.
+
+package importdecl1
+
+import . "unsafe"
+
+var _ Pointer // use dot-imported package unsafe
diff --git a/go/types/testdata/importdecl1b.src b/go/types/testdata/importdecl1b.src
new file mode 100644
index 0000000..f24bb9a
--- /dev/null
+++ b/go/types/testdata/importdecl1b.src
@@ -0,0 +1,7 @@
+// 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 importdecl1
+
+import . /* ERROR "imported but not used" */ "unsafe"
diff --git a/go/types/testdata/init0.src b/go/types/testdata/init0.src
new file mode 100644
index 0000000..ef0349c
--- /dev/null
+++ b/go/types/testdata/init0.src
@@ -0,0 +1,106 @@
+// 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.
+
+// initialization cycles
+
+package init0
+
+// initialization cycles (we don't know the types)
+const (
+ s0 /* ERROR initialization cycle */ = s0
+
+ x0 /* ERROR initialization cycle */ = y0
+ y0 = x0
+
+ a0 = b0
+ b0 /* ERROR initialization cycle */ = c0
+ c0 = d0
+ d0 = b0
+)
+
+var (
+ s1 /* ERROR initialization cycle */ = s1
+
+ x1 /* ERROR initialization cycle */ = y1
+ y1 = x1
+
+ a1 = b1
+ b1 /* ERROR initialization cycle */ = c1
+ c1 = d1
+ d1 = b1
+)
+
+// initialization cycles (we know the types)
+const (
+ s2 /* ERROR initialization cycle */ int = s2
+
+ x2 /* ERROR initialization cycle */ int = y2
+ y2 = x2
+
+ a2 = b2
+ b2 /* ERROR initialization cycle */ int = c2
+ c2 = d2
+ d2 = b2
+)
+
+var (
+ s3 /* ERROR initialization cycle */ int = s3
+
+ x3 /* ERROR initialization cycle */ int = y3
+ y3 = x3
+
+ a3 = b3
+ b3 /* ERROR initialization cycle */ int = c3
+ c3 = d3
+ d3 = b3
+)
+
+// cycles via struct fields
+
+type S1 struct {
+ f int
+}
+const cx3 S1 /* ERROR invalid constant type */ = S1{cx3.f}
+var vx3 /* ERROR initialization cycle */ S1 = S1{vx3.f}
+
+// cycles via functions
+
+var x4 = x5
+var x5 /* ERROR initialization cycle */ = f1()
+func f1() int { return x5*10 }
+
+var x6, x7 /* ERROR initialization cycle */ = f2()
+var x8 = x7
+func f2() (int, int) { return f3() + f3(), 0 }
+func f3() int { return x8 }
+
+// cycles via closures
+
+var x9 /* ERROR initialization cycle */ = func() int { return x9 }()
+
+var x10 /* ERROR initialization cycle */ = f4()
+
+func f4() int {
+ _ = func() {
+ _ = x10
+ }
+ return 0
+}
+
+// cycles via method expressions
+
+type T1 struct{}
+
+func (T1) m() bool { _ = x11; return false }
+
+var x11 /* ERROR initialization cycle */ = T1.m(T1{})
+
+// cycles via method values
+
+type T2 struct{}
+
+func (T2) m() bool { _ = x12; return false }
+
+var t1 T2
+var x12 /* ERROR initialization cycle */ = t1.m
diff --git a/go/types/testdata/init1.src b/go/types/testdata/init1.src
new file mode 100644
index 0000000..39ca314
--- /dev/null
+++ b/go/types/testdata/init1.src
@@ -0,0 +1,97 @@
+// 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.
+
+// initialization cycles
+
+package init1
+
+// issue 6683 (marked as WorkingAsIntended)
+
+type T0 struct{}
+
+func (T0) m() int { return y0 }
+
+var x0 = T0{}
+
+var y0 /* ERROR initialization cycle */ = x0.m()
+
+type T1 struct{}
+
+func (T1) m() int { return y1 }
+
+var x1 interface {
+ m() int
+} = T1{}
+
+var y1 = x1.m() // no cycle reported, x1 is of interface type
+
+// issue 6703 (modified)
+
+var x2 /* ERROR initialization cycle */ = T2.m
+
+var y2 = x2
+
+type T2 struct{}
+
+func (T2) m() int {
+ _ = y2
+ return 0
+}
+
+var x3 /* ERROR initialization cycle */ = T3.m(T3{}) // <<<< added (T3{})
+
+var y3 = x3
+
+type T3 struct{}
+
+func (T3) m() int {
+ _ = y3
+ return 0
+}
+
+var x4 /* ERROR initialization cycle */ = T4{}.m // <<<< added {}
+
+var y4 = x4
+
+type T4 struct{}
+
+func (T4) m() int {
+ _ = y4
+ return 0
+}
+
+var x5 /* ERROR initialization cycle */ = T5{}.m() // <<<< added ()
+
+var y5 = x5
+
+type T5 struct{}
+
+func (T5) m() int {
+ _ = y5
+ return 0
+}
+
+// issue 4847
+// simplified test case
+
+var x6 = f6
+var y6 /* ERROR initialization cycle */ = f6
+func f6() { _ = y6 }
+
+// full test case
+
+type (
+ E int
+ S int
+)
+
+type matcher func(s *S) E
+
+func matchList(s *S) E { return matcher(matchAnyFn)(s) }
+
+var foo = matcher(matchList)
+
+var matchAny /* ERROR initialization cycle */ = matcher(matchList)
+
+func matchAnyFn(s *S) (err E) { return matchAny(s) }
\ No newline at end of file
diff --git a/go/types/testdata/init2.src b/go/types/testdata/init2.src
new file mode 100644
index 0000000..614db6c
--- /dev/null
+++ b/go/types/testdata/init2.src
@@ -0,0 +1,139 @@
+// 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.
+
+// initialization cycles
+
+package init2
+
+// cycles through functions
+
+func f1() int { _ = x1; return 0 }
+var x1 /* ERROR initialization cycle */ = f1
+
+func f2() int { _ = x2; return 0 }
+var x2 /* ERROR initialization cycle */ = f2()
+
+// cycles through method expressions
+
+type T3 int
+func (T3) m() int { _ = x3; return 0 }
+var x3 /* ERROR initialization cycle */ = T3.m
+
+type T4 int
+func (T4) m() int { _ = x4; return 0 }
+var x4 /* ERROR initialization cycle */ = T4.m(0)
+
+type T3p int
+func (*T3p) m() int { _ = x3p; return 0 }
+var x3p /* ERROR initialization cycle */ = (*T3p).m
+
+type T4p int
+func (*T4p) m() int { _ = x4p; return 0 }
+var x4p /* ERROR initialization cycle */ = (*T4p).m(nil)
+
+// cycles through method expressions of embedded methods
+
+type T5 struct { E5 }
+type E5 int
+func (E5) m() int { _ = x5; return 0 }
+var x5 /* ERROR initialization cycle */ = T5.m
+
+type T6 struct { E6 }
+type E6 int
+func (E6) m() int { _ = x6; return 0 }
+var x6 /* ERROR initialization cycle */ = T6.m(T6{0})
+
+type T5p struct { E5p }
+type E5p int
+func (*E5p) m() int { _ = x5p; return 0 }
+var x5p /* ERROR initialization cycle */ = (*T5p).m
+
+type T6p struct { E6p }
+type E6p int
+func (*E6p) m() int { _ = x6p; return 0 }
+var x6p /* ERROR initialization cycle */ = (*T6p).m(nil)
+
+// cycles through method values
+
+type T7 int
+func (T7) m() int { _ = x7; return 0 }
+var x7 /* ERROR initialization cycle */ = T7(0).m
+
+type T8 int
+func (T8) m() int { _ = x8; return 0 }
+var x8 /* ERROR initialization cycle */ = T8(0).m()
+
+type T7p int
+func (*T7p) m() int { _ = x7p; return 0 }
+var x7p /* ERROR initialization cycle */ = new(T7p).m
+
+type T8p int
+func (*T8p) m() int { _ = x8p; return 0 }
+var x8p /* ERROR initialization cycle */ = new(T8p).m()
+
+type T7v int
+func (T7v) m() int { _ = x7v; return 0 }
+var x7var T7v
+var x7v /* ERROR initialization cycle */ = x7var.m
+
+type T8v int
+func (T8v) m() int { _ = x8v; return 0 }
+var x8var T8v
+var x8v /* ERROR initialization cycle */ = x8var.m()
+
+type T7pv int
+func (*T7pv) m() int { _ = x7pv; return 0 }
+var x7pvar *T7pv
+var x7pv /* ERROR initialization cycle */ = x7pvar.m
+
+type T8pv int
+func (*T8pv) m() int { _ = x8pv; return 0 }
+var x8pvar *T8pv
+var x8pv /* ERROR initialization cycle */ = x8pvar.m()
+
+// cycles through method values of embedded methods
+
+type T9 struct { E9 }
+type E9 int
+func (E9) m() int { _ = x9; return 0 }
+var x9 /* ERROR initialization cycle */ = T9{0}.m
+
+type T10 struct { E10 }
+type E10 int
+func (E10) m() int { _ = x10; return 0 }
+var x10 /* ERROR initialization cycle */ = T10{0}.m()
+
+type T9p struct { E9p }
+type E9p int
+func (*E9p) m() int { _ = x9p; return 0 }
+var x9p /* ERROR initialization cycle */ = new(T9p).m
+
+type T10p struct { E10p }
+type E10p int
+func (*E10p) m() int { _ = x10p; return 0 }
+var x10p /* ERROR initialization cycle */ = new(T10p).m()
+
+type T9v struct { E9v }
+type E9v int
+func (E9v) m() int { _ = x9v; return 0 }
+var x9var T9v
+var x9v /* ERROR initialization cycle */ = x9var.m
+
+type T10v struct { E10v }
+type E10v int
+func (E10v) m() int { _ = x10v; return 0 }
+var x10var T10v
+var x10v /* ERROR initialization cycle */ = x10var.m()
+
+type T9pv struct { E9pv }
+type E9pv int
+func (*E9pv) m() int { _ = x9pv; return 0 }
+var x9pvar *T9pv
+var x9pv /* ERROR initialization cycle */ = x9pvar.m
+
+type T10pv struct { E10pv }
+type E10pv int
+func (*E10pv) m() int { _ = x10pv; return 0 }
+var x10pvar *T10pv
+var x10pv /* ERROR initialization cycle */ = x10pvar.m()
diff --git a/go/types/testdata/issues.src b/go/types/testdata/issues.src
new file mode 100644
index 0000000..595a634
--- /dev/null
+++ b/go/types/testdata/issues.src
@@ -0,0 +1,97 @@
+// 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 issues
+
+import "fmt"
+
+func issue7035() {
+ type T struct{ X int }
+ _ = func() {
+ fmt.Println() // must refer to imported fmt rather than the fmt below
+ }
+ fmt := new(T)
+ _ = fmt.X
+}
+
+func issue8066() {
+ const (
+ // TODO(gri) Enable test below for releases 1.4 and higher
+ // _ = float32(340282356779733661637539395458142568447)
+ _ = float32(340282356779733661637539395458142568448 /* ERROR cannot convert */ )
+ )
+}
+
+// Check that a missing identifier doesn't lead to a spurious error cascade.
+func issue8799a() {
+ x, ok := missing /* ERROR undeclared */ ()
+ _ = !ok
+ _ = x
+}
+
+func issue8799b(x int, ok bool) {
+ x, ok = missing /* ERROR undeclared */ ()
+ _ = !ok
+ _ = x
+}
+
+func issue9182() {
+ type Point C /* ERROR undeclared */ .Point
+ // no error for composite literal based on unknown type
+ _ = Point{x: 1, y: 2}
+}
+
+func f0() (a []int) { return }
+func f1() (a []int, b int) { return }
+func f2() (a, b []int) { return }
+
+func append_([]int, ...int) {}
+
+func issue9473(a []int, b ...int) {
+ // variadic builtin function
+ _ = append(f0())
+ _ = append(f0(), f0()...)
+ _ = append(f1())
+ _ = append(f2 /* ERROR cannot pass argument */ ())
+ _ = append(f2()... /* ERROR cannot use ... */ )
+ _ = append(f0(), f1 /* ERROR 2-valued expression */ ())
+ _ = append(f0(), f2 /* ERROR 2-valued expression */ ())
+ _ = append(f0(), f1()... /* ERROR cannot use ... */ )
+ _ = append(f0(), f2()... /* ERROR cannot use ... */ )
+
+ // variadic user-defined function
+ append_(f0())
+ append_(f0(), f0()...)
+ append_(f1())
+ append_(f2 /* ERROR cannot pass argument */ ())
+ append_(f2()... /* ERROR cannot use ... */ )
+ append_(f0(), f1 /* ERROR 2-valued expression */ ())
+ append_(f0(), f2 /* ERROR 2-valued expression */ ())
+ append_(f0(), f1()... /* ERROR cannot use */ )
+ append_(f0(), f2()... /* ERROR cannot use */ )
+}
+
+// Check that embedding a non-interface type in an interface results in a good error message.
+func issue10979() {
+ type _ interface {
+ int /* ERROR int is not an interface */
+ }
+ type T struct{}
+ type _ interface {
+ T /* ERROR T is not an interface */
+ }
+ type _ interface {
+ nosuchtype /* ERROR undeclared name: nosuchtype */
+ }
+ type _ interface {
+ fmt /* ERROR Nosuchtype not declared by package fmt */ .Nosuchtype
+ }
+ type _ interface {
+ nosuchpkg /* ERROR undeclared name: nosuchpkg */ .Nosuchtype
+ }
+ type I interface {
+ I /* ERROR I\.m \(value of type func\(I\)\) is not a type */ .m
+ m()
+ }
+}
diff --git a/go/types/testdata/labels.src b/go/types/testdata/labels.src
new file mode 100644
index 0000000..102ffc7
--- /dev/null
+++ b/go/types/testdata/labels.src
@@ -0,0 +1,207 @@
+// 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 file is a modified concatenation of the files
+// $GOROOT/test/label.go and $GOROOT/test/label1.go.
+
+package labels
+
+var x int
+
+func f0() {
+L1 /* ERROR "label L1 declared but not used" */ :
+ for {
+ }
+L2 /* ERROR "label L2 declared but not used" */ :
+ select {
+ }
+L3 /* ERROR "label L3 declared but not used" */ :
+ switch {
+ }
+L4 /* ERROR "label L4 declared but not used" */ :
+ if true {
+ }
+L5 /* ERROR "label L5 declared but not used" */ :
+ f0()
+L6:
+ f0()
+L6 /* ERROR "label L6 already declared" */ :
+ f0()
+ if x == 20 {
+ goto L6
+ }
+
+L7:
+ for {
+ break L7
+ break L8 /* ERROR "invalid break label L8" */
+ }
+
+// A label must be directly associated with a switch, select, or
+// for statement; it cannot be the label of a labeled statement.
+
+L7a /* ERROR "declared but not used" */ : L7b:
+ for {
+ break L7a /* ERROR "invalid break label L7a" */
+ continue L7a /* ERROR "invalid continue label L7a" */
+ continue L7b
+ }
+
+L8:
+ for {
+ if x == 21 {
+ continue L8
+ continue L7 /* ERROR "invalid continue label L7" */
+ }
+ }
+
+L9:
+ switch {
+ case true:
+ break L9
+ defalt /* ERROR "label defalt declared but not used" */ :
+ }
+
+L10:
+ select {
+ default:
+ break L10
+ break L9 /* ERROR "invalid break label L9" */
+ }
+
+ goto L10a
+L10a: L10b:
+ select {
+ default:
+ break L10a /* ERROR "invalid break label L10a" */
+ break L10b
+ continue L10b /* ERROR "invalid continue label L10b" */
+ }
+}
+
+func f1() {
+L1:
+ for {
+ if x == 0 {
+ break L1
+ }
+ if x == 1 {
+ continue L1
+ }
+ goto L1
+ }
+
+L2:
+ select {
+ default:
+ if x == 0 {
+ break L2
+ }
+ if x == 1 {
+ continue L2 /* ERROR "invalid continue label L2" */
+ }
+ goto L2
+ }
+
+L3:
+ switch {
+ case x > 10:
+ if x == 11 {
+ break L3
+ }
+ if x == 12 {
+ continue L3 /* ERROR "invalid continue label L3" */
+ }
+ goto L3
+ }
+
+L4:
+ if true {
+ if x == 13 {
+ break L4 /* ERROR "invalid break label L4" */
+ }
+ if x == 14 {
+ continue L4 /* ERROR "invalid continue label L4" */
+ }
+ if x == 15 {
+ goto L4
+ }
+ }
+
+L5:
+ f1()
+ if x == 16 {
+ break L5 /* ERROR "invalid break label L5" */
+ }
+ if x == 17 {
+ continue L5 /* ERROR "invalid continue label L5" */
+ }
+ if x == 18 {
+ goto L5
+ }
+
+ for {
+ if x == 19 {
+ break L1 /* ERROR "invalid break label L1" */
+ }
+ if x == 20 {
+ continue L1 /* ERROR "invalid continue label L1" */
+ }
+ if x == 21 {
+ goto L1
+ }
+ }
+}
+
+// Additional tests not in the original files.
+
+func f2() {
+L1 /* ERROR "label L1 declared but not used" */ :
+ if x == 0 {
+ for {
+ continue L1 /* ERROR "invalid continue label L1" */
+ }
+ }
+}
+
+func f3() {
+L1:
+L2:
+L3:
+ for {
+ break L1 /* ERROR "invalid break label L1" */
+ break L2 /* ERROR "invalid break label L2" */
+ break L3
+ continue L1 /* ERROR "invalid continue label L1" */
+ continue L2 /* ERROR "invalid continue label L2" */
+ continue L3
+ goto L1
+ goto L2
+ goto L3
+ }
+}
+
+// Blank labels are never declared.
+
+func f4() {
+_:
+_: // multiple blank labels are ok
+ goto _ /* ERROR "label _ not declared" */
+}
+
+func f5() {
+_:
+ for {
+ break _ /* ERROR "invalid break label _" */
+ continue _ /* ERROR "invalid continue label _" */
+ }
+}
+
+func f6() {
+_:
+ switch {
+ default:
+ break _ /* ERROR "invalid break label _" */
+ }
+}
diff --git a/go/types/testdata/methodsets.src b/go/types/testdata/methodsets.src
new file mode 100644
index 0000000..8921146
--- /dev/null
+++ b/go/types/testdata/methodsets.src
@@ -0,0 +1,214 @@
+// 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 methodsets
+
+type T0 struct {}
+
+func (T0) v0() {}
+func (*T0) p0() {}
+
+type T1 struct {} // like T0 with different method names
+
+func (T1) v1() {}
+func (*T1) p1() {}
+
+type T2 interface {
+ v2()
+ p2()
+}
+
+type T3 struct {
+ T0
+ *T1
+ T2
+}
+
+// Method expressions
+func _() {
+ var (
+ _ func(T0) = T0.v0
+ _ = T0 /* ERROR "not in method set" */ .p0
+
+ _ func (*T0) = (*T0).v0
+ _ func (*T0) = (*T0).p0
+
+ // T1 is like T0
+
+ _ func(T2) = T2.v2
+ _ func(T2) = T2.p2
+
+ _ func(T3) = T3.v0
+ _ func(T3) = T3 /* ERROR "not in method set" */ .p0
+ _ func(T3) = T3.v1
+ _ func(T3) = T3.p1
+ _ func(T3) = T3.v2
+ _ func(T3) = T3.p2
+
+ _ func(*T3) = (*T3).v0
+ _ func(*T3) = (*T3).p0
+ _ func(*T3) = (*T3).v1
+ _ func(*T3) = (*T3).p1
+ _ func(*T3) = (*T3).v2
+ _ func(*T3) = (*T3).p2
+ )
+}
+
+// Method values with addressable receivers
+func _() {
+ var (
+ v0 T0
+ _ func() = v0.v0
+ _ func() = v0.p0
+ )
+
+ var (
+ p0 *T0
+ _ func() = p0.v0
+ _ func() = p0.p0
+ )
+
+ // T1 is like T0
+
+ var (
+ v2 T2
+ _ func() = v2.v2
+ _ func() = v2.p2
+ )
+
+ var (
+ v4 T3
+ _ func() = v4.v0
+ _ func() = v4.p0
+ _ func() = v4.v1
+ _ func() = v4.p1
+ _ func() = v4.v2
+ _ func() = v4.p2
+ )
+
+ var (
+ p4 *T3
+ _ func() = p4.v0
+ _ func() = p4.p0
+ _ func() = p4.v1
+ _ func() = p4.p1
+ _ func() = p4.v2
+ _ func() = p4.p2
+ )
+}
+
+// Method calls with addressable receivers
+func _() {
+ var v0 T0
+ v0.v0()
+ v0.p0()
+
+ var p0 *T0
+ p0.v0()
+ p0.p0()
+
+ // T1 is like T0
+
+ var v2 T2
+ v2.v2()
+ v2.p2()
+
+ var v4 T3
+ v4.v0()
+ v4.p0()
+ v4.v1()
+ v4.p1()
+ v4.v2()
+ v4.p2()
+
+ var p4 *T3
+ p4.v0()
+ p4.p0()
+ p4.v1()
+ p4.p1()
+ p4.v2()
+ p4.p2()
+}
+
+// Method values with value receivers
+func _() {
+ var (
+ _ func() = T0{}.v0
+ _ func() = T0 /* ERROR "not in method set" */ {}.p0
+
+ _ func() = (&T0{}).v0
+ _ func() = (&T0{}).p0
+
+ // T1 is like T0
+
+ // no values for T2
+
+ _ func() = T3{}.v0
+ _ func() = T3 /* ERROR "not in method set" */ {}.p0
+ _ func() = T3{}.v1
+ _ func() = T3{}.p1
+ _ func() = T3{}.v2
+ _ func() = T3{}.p2
+
+ _ func() = (&T3{}).v0
+ _ func() = (&T3{}).p0
+ _ func() = (&T3{}).v1
+ _ func() = (&T3{}).p1
+ _ func() = (&T3{}).v2
+ _ func() = (&T3{}).p2
+ )
+}
+
+// Method calls with value receivers
+func _() {
+ T0{}.v0()
+ T0 /* ERROR "not in method set" */ {}.p0()
+
+ (&T0{}).v0()
+ (&T0{}).p0()
+
+ // T1 is like T0
+
+ // no values for T2
+
+ T3{}.v0()
+ T3 /* ERROR "not in method set" */ {}.p0()
+ T3{}.v1()
+ T3{}.p1()
+ T3{}.v2()
+ T3{}.p2()
+
+ (&T3{}).v0()
+ (&T3{}).p0()
+ (&T3{}).v1()
+ (&T3{}).p1()
+ (&T3{}).v2()
+ (&T3{}).p2()
+}
+
+// *T has no methods if T is an interface type
+func issue5918() {
+ var (
+ err error
+ _ = err.Error()
+ _ func() string = err.Error
+ _ func(error) string = error.Error
+
+ perr = &err
+ _ = perr /* ERROR "no field or method" */ .Error()
+ _ func() string = perr /* ERROR "no field or method" */ .Error
+ _ func(*error) string = ( /* ERROR "no field or method" */ *error).Error
+ )
+
+ type T *interface{ m() int }
+ var (
+ x T
+ _ = (*x).m()
+ _ = (*x).m
+
+ _ = x /* ERROR "no field or method" */ .m()
+ _ = x /* ERROR "no field or method" */ .m
+ _ = T /* ERROR "no field or method" */ .m
+ )
+}
diff --git a/go/types/testdata/shifts.src b/go/types/testdata/shifts.src
new file mode 100644
index 0000000..fa4de9e
--- /dev/null
+++ b/go/types/testdata/shifts.src
@@ -0,0 +1,341 @@
+// 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 shifts
+
+func shifts0() {
+ // basic constant shifts
+ const (
+ s = 10
+ _ = 0<<0
+ _ = 1<<s
+ _ = 1<<- /* ERROR "stupid shift" */ 1
+ _ = 1<<1075 /* ERROR "stupid shift" */
+ _ = 2.0<<1
+
+ _ int = 2<<s
+ _ float32 = 2<<s
+ _ complex64 = 2<<s
+
+ _ int = 2.0<<s
+ _ float32 = 2.0<<s
+ _ complex64 = 2.0<<s
+
+ _ int = 'a'<<s
+ _ float32 = 'a'<<s
+ _ complex64 = 'a'<<s
+ )
+}
+
+func shifts1() {
+ // basic non-constant shifts
+ var (
+ i int
+ u uint
+
+ _ = 1<<0
+ _ = 1<<i /* ERROR "must be unsigned" */
+ _ = 1<<u
+ _ = 1<<"foo" /* ERROR "cannot convert" */
+ _ = i<<0
+ _ = i<<- /* ERROR "must not be negative" */ 1
+ _ = 1 /* ERROR "overflows" */ <<100
+
+ _ uint = 1 << 0
+ _ uint = 1 << u
+ _ float32 = 1 /* ERROR "must be integer" */ << u
+ )
+}
+
+func shifts2() {
+ // from the spec
+ var (
+ s uint = 33
+ i = 1<<s // 1 has type int
+ j int32 = 1<<s // 1 has type int32; j == 0
+ k = uint64(1<<s) // 1 has type uint64; k == 1<<33
+ m int = 1.0<<s // 1.0 has type int
+ n = 1.0<<s != i // 1.0 has type int; n == false if ints are 32bits in size
+ o = 1<<s == 2<<s // 1 and 2 have type int; o == true if ints are 32bits in size
+ p = 1<<s == 1<<33 // illegal if ints are 32bits in size: 1 has type int, but 1<<33 overflows int
+ u = 1.0 /* ERROR "must be integer" */ <<s // illegal: 1.0 has type float64, cannot shift
+ u1 = 1.0 /* ERROR "must be integer" */ <<s != 0 // illegal: 1.0 has type float64, cannot shift
+ u2 = 1 /* ERROR "must be integer" */ <<s != 1.0 // illegal: 1 has type float64, cannot shift
+ v float32 = 1 /* ERROR "must be integer" */ <<s // illegal: 1 has type float32, cannot shift
+ w int64 = 1.0<<33 // 1.0<<33 is a constant shift expression
+ )
+ _, _, _, _, _, _, _, _, _, _, _, _ = i, j, k, m, n, o, p, u, u1, u2, v, w
+}
+
+func shifts3(a int16, b float32) {
+ // random tests
+ var (
+ s uint = 11
+ u = 1 /* ERROR "must be integer" */ <<s + 1.0
+ v complex128 = 1 /* ERROR "must be integer" */ << s + 1.0 /* ERROR "must be integer" */ << s + 1
+ )
+ x := 1.0 /* ERROR "must be integer" */ <<s + 1
+ shifts3(1.0 << s, 1 /* ERROR "must be integer" */ >> s)
+ _, _, _ = u, v, x
+}
+
+func shifts4() {
+ // shifts in comparisons w/ untyped operands
+ var s uint
+
+ _ = 1<<s == 1
+ _ = 1 /* ERROR "integer" */ <<s == 1.
+ _ = 1. /* ERROR "integer" */ <<s == 1
+ _ = 1. /* ERROR "integer" */ <<s == 1.
+
+ _ = 1<<s + 1 == 1
+ _ = 1 /* ERROR "integer" */ <<s + 1 == 1.
+ _ = 1 /* ERROR "integer" */ <<s + 1. == 1
+ _ = 1 /* ERROR "integer" */ <<s + 1. == 1.
+ _ = 1. /* ERROR "integer" */ <<s + 1 == 1
+ _ = 1. /* ERROR "integer" */ <<s + 1 == 1.
+ _ = 1. /* ERROR "integer" */ <<s + 1. == 1
+ _ = 1. /* ERROR "integer" */ <<s + 1. == 1.
+
+ _ = 1<<s == 1<<s
+ _ = 1 /* ERROR "integer" */ <<s == 1. /* ERROR "integer" */ <<s
+ _ = 1. /* ERROR "integer" */ <<s == 1 /* ERROR "integer" */ <<s
+ _ = 1. /* ERROR "integer" */ <<s == 1. /* ERROR "integer" */ <<s
+
+ _ = 1<<s + 1<<s == 1
+ _ = 1 /* ERROR "integer" */ <<s + 1 /* ERROR "integer" */ <<s == 1.
+ _ = 1 /* ERROR "integer" */ <<s + 1. /* ERROR "integer" */ <<s == 1
+ _ = 1 /* ERROR "integer" */ <<s + 1. /* ERROR "integer" */ <<s == 1.
+ _ = 1. /* ERROR "integer" */ <<s + 1 /* ERROR "integer" */ <<s == 1
+ _ = 1. /* ERROR "integer" */ <<s + 1 /* ERROR "integer" */ <<s == 1.
+ _ = 1. /* ERROR "integer" */ <<s + 1. /* ERROR "integer" */ <<s == 1
+ _ = 1. /* ERROR "integer" */ <<s + 1. /* ERROR "integer" */ <<s == 1.
+
+ _ = 1<<s + 1<<s == 1<<s + 1<<s
+ _ = 1 /* ERROR "integer" */ <<s + 1 /* ERROR "integer" */ <<s == 1 /* ERROR "integer" */ <<s + 1. /* ERROR "integer" */ <<s
+ _ = 1 /* ERROR "integer" */ <<s + 1 /* ERROR "integer" */ <<s == 1. /* ERROR "integer" */ <<s + 1 /* ERROR "integer" */ <<s
+ _ = 1 /* ERROR "integer" */ <<s + 1 /* ERROR "integer" */ <<s == 1. /* ERROR "integer" */ <<s + 1. /* ERROR "integer" */ <<s
+ _ = 1 /* ERROR "integer" */ <<s + 1. /* ERROR "integer" */ <<s == 1 /* ERROR "integer" */ <<s + 1 /* ERROR "integer" */ <<s
+ _ = 1 /* ERROR "integer" */ <<s + 1. /* ERROR "integer" */ <<s == 1 /* ERROR "integer" */ <<s + 1. /* ERROR "integer" */ <<s
+ _ = 1 /* ERROR "integer" */ <<s + 1. /* ERROR "integer" */ <<s == 1. /* ERROR "integer" */ <<s + 1 /* ERROR "integer" */ <<s
+ _ = 1 /* ERROR "integer" */ <<s + 1. /* ERROR "integer" */ <<s == 1. /* ERROR "integer" */ <<s + 1. /* ERROR "integer" */ <<s
+ _ = 1. /* ERROR "integer" */ <<s + 1 /* ERROR "integer" */ <<s == 1 /* ERROR "integer" */ <<s + 1 /* ERROR "integer" */ <<s
+ _ = 1. /* ERROR "integer" */ <<s + 1 /* ERROR "integer" */ <<s == 1 /* ERROR "integer" */ <<s + 1. /* ERROR "integer" */ <<s
+ _ = 1. /* ERROR "integer" */ <<s + 1 /* ERROR "integer" */ <<s == 1. /* ERROR "integer" */ <<s + 1 /* ERROR "integer" */ <<s
+ _ = 1. /* ERROR "integer" */ <<s + 1 /* ERROR "integer" */ <<s == 1. /* ERROR "integer" */ <<s + 1. /* ERROR "integer" */ <<s
+ _ = 1. /* ERROR "integer" */ <<s + 1. /* ERROR "integer" */ <<s == 1 /* ERROR "integer" */ <<s + 1 /* ERROR "integer" */ <<s
+ _ = 1. /* ERROR "integer" */ <<s + 1. /* ERROR "integer" */ <<s == 1 /* ERROR "integer" */ <<s + 1. /* ERROR "integer" */ <<s
+ _ = 1. /* ERROR "integer" */ <<s + 1. /* ERROR "integer" */ <<s == 1. /* ERROR "integer" */ <<s + 1 /* ERROR "integer" */ <<s
+ _ = 1. /* ERROR "integer" */ <<s + 1. /* ERROR "integer" */ <<s == 1. /* ERROR "integer" */ <<s + 1. /* ERROR "integer" */ <<s
+}
+
+func shifts5() {
+ // shifts in comparisons w/ typed operands
+ var s uint
+ var x int
+
+ _ = 1<<s == x
+ _ = 1.<<s == x
+ _ = 1.1 /* ERROR "int" */ <<s == x
+
+ _ = 1<<s + x == 1
+ _ = 1<<s + x == 1.
+ _ = 1<<s + x == 1.1 /* ERROR "int" */
+ _ = 1.<<s + x == 1
+ _ = 1.<<s + x == 1.
+ _ = 1.<<s + x == 1.1 /* ERROR "int" */
+ _ = 1.1 /* ERROR "int" */ <<s + x == 1
+ _ = 1.1 /* ERROR "int" */ <<s + x == 1.
+ _ = 1.1 /* ERROR "int" */ <<s + x == 1.1
+
+ _ = 1<<s == x<<s
+ _ = 1.<<s == x<<s
+ _ = 1.1 /* ERROR "int" */ <<s == x<<s
+}
+
+func shifts6() {
+ // shifts as operands in non-arithmetic operations and as arguments
+ var a [10]int
+ var s uint
+
+ _ = a[1<<s]
+ _ = a[1.0]
+ _ = a[1.0<<s]
+
+ _ = make([]int, 1.0)
+ _ = make([]int, 1.0<<s)
+ _ = make([]int, 1.1 /* ERROR "must be integer" */ <<s)
+
+ _ = float32(1)
+ _ = float32(1 /* ERROR "must be integer" */ <<s)
+ _ = float32(1.0)
+ _ = float32(1.0 /* ERROR "must be integer" */ <<s)
+ _ = float32(1.1 /* ERROR "must be integer" */ <<s)
+
+ var b []int
+ _ = append(b, 1<<s)
+ _ = append(b, 1.0<<s)
+ _ = append(b, 1.1 /* ERROR "must be integer" */ <<s)
+
+ _ = append(b, 1<<s)
+ _ = append(b, 1.0<<s) // should fail - see TODO in append code
+ _ = append(b, 1.1 /* ERROR "must be integer" */ <<s)
+
+ _ = complex(1.0 /* ERROR "must be integer" */ <<s, 0)
+ _ = complex(1.1 /* ERROR "must be integer" */ <<s, 0)
+ _ = complex(0, 1.0 /* ERROR "must be integer" */ <<s)
+ _ = complex(0, 1.1 /* ERROR "must be integer" */ <<s)
+
+ // TODO(gri) The delete below is not type-checked correctly yet.
+ // var m1 map[int]string
+ // delete(m1, 1<<s)
+}
+
+func shifts7() {
+ // shifts of shifts
+ var s uint
+ var x int
+ _ = x
+
+ _ = 1<<(1<<s)
+ _ = 1<<(1.<<s)
+ _ = 1. /* ERROR "integer" */ <<(1<<s)
+ _ = 1. /* ERROR "integer" */ <<(1.<<s)
+
+ x = 1<<(1<<s)
+ x = 1<<(1.<<s)
+ x = 1.<<(1<<s)
+ x = 1.<<(1.<<s)
+
+ _ = (1<<s)<<(1<<s)
+ _ = (1<<s)<<(1.<<s)
+ _ = ( /* ERROR "integer" */ 1.<<s)<<(1<<s)
+ _ = ( /* ERROR "integer" */ 1.<<s)<<(1.<<s)
+
+ x = (1<<s)<<(1<<s)
+ x = (1<<s)<<(1.<<s)
+ x = ( /* ERROR "integer" */ 1.<<s)<<(1<<s)
+ x = ( /* ERROR "integer" */ 1.<<s)<<(1.<<s)
+}
+
+func shifts8() {
+ // shift examples from shift discussion: better error messages
+ var s uint
+ _ = 1.0 /* ERROR "shifted operand 1.0 \(type float64\) must be integer" */ <<s == 1
+ _ = 1.0 /* ERROR "shifted operand 1.0 \(type float64\) must be integer" */ <<s == 1.0
+ _ = 1 /* ERROR "shifted operand 1 \(type float64\) must be integer" */ <<s == 1.0
+ _ = 1 /* ERROR "shifted operand 1 \(type float64\) must be integer" */ <<s + 1.0 == 1
+ _ = 1 /* ERROR "shifted operand 1 \(type float64\) must be integer" */ <<s + 1.1 == 1
+ _ = 1 /* ERROR "shifted operand 1 \(type float64\) must be integer" */ <<s + 1 == 1.0
+
+ // additional cases
+ _ = complex(1.0 /* ERROR "shifted operand 1.0 \(type float64\) must be integer" */ <<s, 1)
+ _ = complex(1.0, 1 /* ERROR "shifted operand 1 \(type float64\) must be integer" */ <<s)
+
+ _ = int(1.<<s)
+ _ = int(1.1 /* ERROR "shifted operand .* must be integer" */ <<s)
+ _ = float32(1 /* ERROR "shifted operand .* must be integer" */ <<s)
+ _ = float32(1. /* ERROR "shifted operand .* must be integer" */ <<s)
+ _ = float32(1.1 /* ERROR "shifted operand .* must be integer" */ <<s)
+ // TODO(gri) the error messages for these two are incorrect - disabled for now
+ // _ = complex64(1<<s)
+ // _ = complex64(1.<<s)
+ _ = complex64(1.1 /* ERROR "shifted operand .* must be integer" */ <<s)
+}
+
+func shifts9() {
+ // various originally failing snippets of code from the std library
+ // from src/compress/lzw/reader.go:90
+ {
+ var d struct {
+ bits uint32
+ width uint
+ }
+ _ = uint16(d.bits & (1<<d.width - 1))
+ }
+
+ // from src/debug/dwarf/buf.go:116
+ {
+ var ux uint64
+ var bits uint
+ x := int64(ux)
+ if x&(1<<(bits-1)) != 0 {}
+ }
+
+ // from src/encoding/asn1/asn1.go:160
+ {
+ var bytes []byte
+ if bytes[len(bytes)-1]&((1<<bytes[0])-1) != 0 {}
+ }
+
+ // from src/math/big/rat.go:140
+ {
+ var exp int
+ var mantissa uint64
+ shift := uint64(-1022 - (exp - 1)) // [1..53)
+ _ = mantissa & (1<<shift - 1)
+ }
+
+ // from src/net/interface.go:51
+ {
+ type Flags uint
+ var f Flags
+ var i int
+ if f&(1<<uint(i)) != 0 {}
+ }
+
+ // from src/runtime/softfloat64.go:234
+ {
+ var gm uint64
+ var shift uint
+ _ = gm & (1<<shift - 1)
+ }
+
+ // from src/strconv/atof.go:326
+ {
+ var mant uint64
+ var mantbits uint
+ if mant == 2<<mantbits {}
+ }
+
+ // from src/route_bsd.go:82
+ {
+ var Addrs int32
+ const rtaRtMask = 1
+ var i uint
+ if Addrs&rtaRtMask&(1<<i) == 0 {}
+ }
+
+ // from src/text/scanner/scanner.go:540
+ {
+ var s struct { Whitespace uint64 }
+ var ch rune
+ for s.Whitespace&(1<<uint(ch)) != 0 {}
+ }
+}
+
+func issue5895() {
+ var x = 'a' << 1 // type of x must be rune
+ var _ rune = x
+}
+
+func issue11325() {
+ var _ = 0 >> 1.1 /* ERROR "must be unsigned integer" */ // example from issue 11325
+ _ = 0 >> 1.1 /* ERROR "must be unsigned integer" */
+ _ = 0 << 1.1 /* ERROR "must be unsigned integer" */
+ _ = 0 >> 1.
+ _ = 1 >> 1.1 /* ERROR "must be unsigned integer" */
+ _ = 1 >> 1.
+ _ = 1. >> 1
+ _ = 1. >> 1.
+ _ = 1.1 /* ERROR "must be integer" */ >> 1
+}
+
+func issue11594() {
+ var _ = complex64 /* ERROR "must be integer" */ (1) << 2 // example from issue 11594
+ _ = float32 /* ERROR "must be integer" */ (0) << 1
+ _ = float64 /* ERROR "must be integer" */ (0) >> 2
+ _ = complex64 /* ERROR "must be integer" */ (0) << 3
+ _ = complex64 /* ERROR "must be integer" */ (0) >> 4
+}
diff --git a/go/types/testdata/stmt0.src b/go/types/testdata/stmt0.src
new file mode 100644
index 0000000..fd1ddba
--- /dev/null
+++ b/go/types/testdata/stmt0.src
@@ -0,0 +1,833 @@
+// 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.
+
+// statements
+
+package stmt0
+
+func assignments0() (int, int) {
+ var a, b, c int
+ var ch chan int
+ f0 := func() {}
+ f1 := func() int { return 1 }
+ f2 := func() (int, int) { return 1, 2 }
+ f3 := func() (int, int, int) { return 1, 2, 3 }
+
+ a, b, c = 1, 2, 3
+ a, b, c = 1 /* ERROR "assignment count mismatch" */ , 2
+ a, b, c = 1 /* ERROR "assignment count mismatch" */ , 2, 3, 4
+ _, _, _ = a, b, c
+
+ a = f0 /* ERROR "used as value" */ ()
+ a = f1()
+ a = f2 /* ERROR "assignment count mismatch" */ ()
+ a, b = f2()
+ a, b, c = f2 /* ERROR "assignment count mismatch" */ ()
+ a, b, c = f3()
+ a, b = f3 /* ERROR "assignment count mismatch" */ ()
+
+ a, b, c = <- /* ERROR "assignment count mismatch" */ ch
+
+ return /* ERROR "wrong number of return values" */
+ return /* ERROR "wrong number of return values" */ 1
+ return 1, 2
+ return /* ERROR "wrong number of return values" */ 1, 2, 3
+}
+
+func assignments1() {
+ b, i, f, c, s := false, 1, 1.0, 1i, "foo"
+ b = i /* ERROR "cannot assign" */
+ i = f /* ERROR "cannot assign" */
+ f = c /* ERROR "cannot assign" */
+ c = s /* ERROR "cannot assign" */
+ s = b /* ERROR "cannot assign" */
+
+ v0, v1, v2 := 1 /* ERROR "mismatch" */ , 2, 3, 4
+ _, _, _ = v0, v1, v2
+
+ b = true
+
+ i += 1
+ i += "foo" /* ERROR "cannot convert.*int" */
+
+ f -= 1
+ f /= 0
+ f = float32(0)/0 /* ERROR "division by zero" */
+ f -= "foo" /* ERROR "cannot convert.*float64" */
+
+ c *= 1
+ c /= 0
+
+ s += "bar"
+ s += 1 /* ERROR "cannot convert.*string" */
+
+ var u64 uint64
+ u64 += 1<<u64
+
+ undeclared /* ERROR "undeclared" */ = 991
+
+ // test cases for issue 5800
+ var (
+ _ int = nil /* ERROR "untyped nil value" */
+ _ [10]int = nil /* ERROR "untyped nil value" */
+ _ []byte = nil
+ _ struct{} = nil /* ERROR "untyped nil value" */
+ _ func() = nil
+ _ map[int]string = nil
+ _ chan int = nil
+ )
+
+ // test cases for issue 5500
+ _ = func() (int, bool) {
+ var m map[int]int
+ return /* ERROR "wrong number of return values" */ m[0]
+ }
+
+ g := func(int, bool){}
+ var m map[int]int
+ g(m[0]) /* ERROR "too few arguments" */
+
+ // assignments to _
+ _ = nil /* ERROR "use of untyped nil" */
+ _ = 1 /* ERROR overflow */ <<1000
+ (_) = 0
+}
+
+func assignments2() {
+ type mybool bool
+ var m map[string][]bool
+ var s []bool
+ var b bool
+ var d mybool
+ _ = s
+ _ = b
+ _ = d
+
+ // assignments to map index expressions are ok
+ s, b = m["foo"]
+ _, d = m["bar"]
+ m["foo"] = nil
+ m["foo"] = nil /* ERROR assignment count mismatch */ , false
+ _ = append(m["foo"])
+ _ = append(m["foo"], true)
+
+ var c chan int
+ _, b = <-c
+ _, d = <-c
+ <- /* ERROR cannot assign */ c = 0
+ <-c = 0 /* ERROR assignment count mismatch */ , false
+
+ var x interface{}
+ _, b = x.(int)
+ x /* ERROR cannot assign */ .(int) = 0
+ x.(int) = 0 /* ERROR assignment count mismatch */ , false
+
+ assignments2 /* ERROR used as value */ () = nil
+ int /* ERROR not an expression */ = 0
+}
+
+func issue6487() {
+ type S struct{x int}
+ _ = &S /* ERROR "cannot take address" */ {}.x
+ _ = &( /* ERROR "cannot take address" */ S{}.x)
+ _ = (&S{}).x
+ S /* ERROR "cannot assign" */ {}.x = 0
+ (&S{}).x = 0
+
+ type M map[string]S
+ var m M
+ m /* ERROR "cannot assign" */ ["foo"].x = 0
+ _ = &( /* ERROR "cannot take address" */ m["foo"].x)
+ _ = &m /* ERROR "cannot take address" */ ["foo"].x
+}
+
+func issue6766a() {
+ a, a /* ERROR redeclared */ := 1, 2
+ _ = a
+ a, b, b /* ERROR redeclared */ := 1, 2, 3
+ _ = b
+ c, c /* ERROR redeclared */, b := 1, 2, 3
+ _ = c
+ a, b := /* ERROR no new variables */ 1, 2
+}
+
+func shortVarDecls1() {
+ const c = 0
+ type d int
+ a, b, c /* ERROR "cannot assign" */ , d /* ERROR "cannot assign" */ := 1, "zwei", 3.0, 4
+ var _ int = a // a is of type int
+ var _ string = b // b is of type string
+}
+
+func incdecs() {
+ const c = 3.14
+ c /* ERROR "cannot assign" */ ++
+ s := "foo"
+ s /* ERROR "cannot convert" */ --
+ 3.14 /* ERROR "cannot assign" */ ++
+ var (
+ x int
+ y float32
+ z complex128
+ )
+ x++
+ y--
+ z++
+}
+
+func sends() {
+ var ch chan int
+ var rch <-chan int
+ var x int
+ x /* ERROR "cannot send" */ <- x
+ rch /* ERROR "cannot send" */ <- x
+ ch <- "foo" /* ERROR "cannot convert" */
+ ch <- x
+}
+
+func selects() {
+ select {}
+ var (
+ ch chan int
+ sc chan <- bool
+ )
+ select {
+ case <-ch:
+ case (<-ch):
+ case t := <-ch:
+ _ = t
+ case t := (<-ch):
+ _ = t
+ case t, ok := <-ch:
+ _, _ = t, ok
+ case t, ok := (<-ch):
+ _, _ = t, ok
+ case <-sc /* ERROR "cannot receive from send-only channel" */ :
+ }
+ select {
+ default:
+ default /* ERROR "multiple defaults" */ :
+ }
+ select {
+ case a, b := <-ch:
+ _, b = a, b
+ case x /* ERROR send or receive */ :
+ case a /* ERROR send or receive */ := ch:
+ }
+
+ // test for issue 9570: ch2 in second case falsely resolved to
+ // ch2 declared in body of first case
+ ch1 := make(chan int)
+ ch2 := make(chan int)
+ select {
+ case <-ch1:
+ var ch2 /* ERROR ch2 declared but not used */ chan bool
+ case i := <-ch2:
+ print(i + 1)
+ }
+}
+
+func gos() {
+ go 1 /* ERROR HERE "function must be invoked" */
+ go int /* ERROR "go requires function call, not conversion" */ (0)
+ go gos()
+ var c chan int
+ go close(c)
+ go len /* ERROR "go discards result" */ (c)
+}
+
+func defers() {
+ defer 1 /* ERROR HERE "function must be invoked" */
+ defer int /* ERROR "defer requires function call, not conversion" */ (0)
+ defer defers()
+ var c chan int
+ defer close(c)
+ defer len /* ERROR "defer discards result" */ (c)
+}
+
+func breaks() {
+ var x, y int
+
+ break /* ERROR "break" */
+ {
+ break /* ERROR "break" */
+ }
+ if x < y {
+ break /* ERROR "break" */
+ }
+
+ switch x {
+ case 0:
+ break
+ case 1:
+ if x == y {
+ break
+ }
+ default:
+ break
+ break
+ }
+
+ var z interface{}
+ switch z.(type) {
+ case int:
+ break
+ }
+
+ for {
+ break
+ }
+
+ var a []int
+ for _ = range a {
+ break
+ }
+
+ for {
+ if x == y {
+ break
+ }
+ }
+
+ var ch chan int
+ select {
+ case <-ch:
+ break
+ }
+
+ select {
+ case <-ch:
+ if x == y {
+ break
+ }
+ default:
+ break
+ }
+}
+
+func continues() {
+ var x, y int
+
+ continue /* ERROR "continue" */
+ {
+ continue /* ERROR "continue" */
+ }
+
+ if x < y {
+ continue /* ERROR "continue" */
+ }
+
+ switch x {
+ case 0:
+ continue /* ERROR "continue" */
+ }
+
+ var z interface{}
+ switch z.(type) {
+ case int:
+ continue /* ERROR "continue" */
+ }
+
+ var ch chan int
+ select {
+ case <-ch:
+ continue /* ERROR "continue" */
+ }
+
+ for i := 0; i < 10; i++ {
+ continue
+ if x < y {
+ continue
+ break
+ }
+ switch x {
+ case y:
+ continue
+ default:
+ break
+ }
+ select {
+ case <-ch:
+ continue
+ }
+ }
+
+ var a []int
+ for _ = range a {
+ continue
+ if x < y {
+ continue
+ break
+ }
+ switch x {
+ case y:
+ continue
+ default:
+ break
+ }
+ select {
+ case <-ch:
+ continue
+ }
+ }
+}
+
+func returns0() {
+ return
+ return 0 /* ERROR no result values expected */
+}
+
+func returns1(x float64) (int, *float64) {
+ return 0, &x
+ return /* ERROR wrong number of return values */
+ return "foo" /* ERROR "cannot convert" */, x /* ERROR "cannot return" */
+ return /* ERROR wrong number of return values */ 0, &x, 1
+}
+
+func returns2() (a, b int) {
+ return
+ return 1, "foo" /* ERROR cannot convert */
+ return /* ERROR wrong number of return values */ 1, 2, 3
+ {
+ type a int
+ return 1, 2
+ return /* ERROR a not in scope at return */
+ }
+}
+
+func returns3() (_ int) {
+ return
+ {
+ var _ int // blank (_) identifiers never shadow since they are in no scope
+ return
+ }
+}
+
+func switches0() {
+ var x int
+
+ switch x {
+ }
+
+ switch x {
+ default:
+ default /* ERROR "multiple defaults" */ :
+ }
+
+ switch {
+ case 1 /* ERROR "cannot convert" */ :
+ }
+
+ true := "false"
+ _ = true
+ // A tagless switch is equivalent to the bool
+ // constant true, not the identifier 'true'.
+ switch {
+ case "false" /* ERROR "cannot convert" */:
+ }
+
+ switch int32(x) {
+ case 1, 2:
+ case x /* ERROR "cannot compare" */ :
+ }
+
+ switch x {
+ case 1 /* ERROR "overflows" */ << 100:
+ }
+
+ switch x {
+ case 1:
+ case 1 /* DISABLED "duplicate case" */ :
+ case 2, 3, 4:
+ case 1 /* DISABLED "duplicate case" */ :
+ }
+
+ switch uint64(x) {
+ case 1 /* DISABLED duplicate case */ <<64-1:
+ case 1 /* DISABLED duplicate case */ <<64-1:
+ }
+}
+
+func switches1() {
+ fallthrough /* ERROR "fallthrough statement out of place" */
+
+ var x int
+ switch x {
+ case 0:
+ fallthrough /* ERROR "fallthrough statement out of place" */
+ break
+ case 1:
+ fallthrough
+ case 2:
+ default:
+ fallthrough
+ case 3:
+ fallthrough /* ERROR "fallthrough statement out of place" */
+ }
+
+ var y interface{}
+ switch y.(type) {
+ case int:
+ fallthrough /* ERROR "fallthrough statement out of place" */
+ default:
+ }
+
+ switch x {
+ case 0:
+ if x == 0 {
+ fallthrough /* ERROR "fallthrough statement out of place" */
+ }
+ }
+
+ switch x {
+ case 0:
+ goto L1
+ L1: fallthrough
+ case 1:
+ goto L2
+ goto L3
+ goto L4
+ L2: L3: L4: fallthrough
+ default:
+ }
+
+ switch x {
+ case 0:
+ goto L5
+ L5: fallthrough
+ default:
+ goto L6
+ goto L7
+ goto L8
+ L6: L7: L8: fallthrough /* ERROR "fallthrough statement out of place" */
+ }
+
+ switch x {
+ case 0:
+ {
+ fallthrough /* ERROR "fallthrough statement out of place" */
+ }
+ default:
+ }
+}
+
+type I interface {
+ m()
+}
+
+type I2 interface {
+ m(int)
+}
+
+type T struct{}
+type T1 struct{}
+type T2 struct{}
+
+func (T) m() {}
+func (T2) m(int) {}
+
+func typeswitches() {
+ var i int
+ var x interface{}
+
+ switch x.(type) {}
+ switch (x /* ERROR "outside type switch" */ .(type)) {}
+
+ switch x.(type) {
+ default:
+ default /* ERROR "multiple defaults" */ :
+ }
+
+ switch x /* ERROR "declared but not used" */ := x.(type) {}
+ switch _ /* ERROR "no new variable on left side of :=" */ := x.(type) {}
+
+ switch x := x.(type) {
+ case int:
+ var y int = x
+ _ = y
+ }
+
+ switch x := i /* ERROR "not an interface" */ .(type) {}
+
+ switch t := x.(type) {
+ case nil:
+ var v bool = t /* ERROR "cannot initialize" */
+ _ = v
+ case int:
+ var v int = t
+ _ = v
+ case float32, complex64:
+ var v float32 = t /* ERROR "cannot initialize" */
+ _ = v
+ default:
+ var v float32 = t /* ERROR "cannot initialize" */
+ _ = v
+ }
+
+ var t I
+ switch t.(type) {
+ case T:
+ case T1 /* ERROR "missing method m" */ :
+ case T2 /* ERROR "wrong type for method m" */ :
+ case I2 /* STRICT "wrong type for method m" */ : // only an error in strict mode (issue 8561)
+ }
+}
+
+// Test that each case clause uses the correct type of the variable
+// declared by the type switch (issue 5504).
+func typeswitch0() {
+ switch y := interface{}(nil).(type) {
+ case int:
+ func() int { return y + 0 }()
+ case float32:
+ func() float32 { return y }()
+ }
+}
+
+// Test correct scope setup.
+// (no redeclaration errors expected in the type switch)
+func typeswitch1() {
+ var t I
+ switch t := t; t := t.(type) {
+ case nil:
+ var _ I = t
+ case T:
+ var _ T = t
+ default:
+ var _ I = t
+ }
+}
+
+// Test correct typeswitch against interface types.
+type A interface { a() }
+type B interface { b() }
+type C interface { a(int) }
+
+func typeswitch2() {
+ switch A(nil).(type) {
+ case A:
+ case B:
+ case C /* STRICT "cannot have dynamic type" */: // only an error in strict mode (issue 8561)
+ }
+}
+
+func typeswitch3(x interface{}) {
+ switch x.(type) {
+ case int:
+ case float64:
+ case int /* ERROR duplicate case */ :
+ }
+
+ switch x.(type) {
+ case nil:
+ case int:
+ case nil /* ERROR duplicate case */ , nil /* ERROR duplicate case */ :
+ }
+
+ type F func(int)
+ switch x.(type) {
+ case nil:
+ case int, func(int):
+ case float32, func /* ERROR duplicate case */ (x int):
+ case F:
+ }
+}
+
+func fors1() {
+ for {}
+ var i string
+ _ = i
+ for i := 0; i < 10; i++ {}
+ for i := 0; i < 10; j /* ERROR cannot declare */ := 0 {}
+}
+
+func rangeloops1() {
+ var (
+ x int
+ a [10]float32
+ b []string
+ p *[10]complex128
+ pp **[10]complex128
+ s string
+ m map[int]bool
+ c chan int
+ sc chan<- int
+ rc <-chan int
+ )
+
+ for range x /* ERROR "cannot range over" */ {}
+ for _ = range x /* ERROR "cannot range over" */ {}
+ for i := range x /* ERROR "cannot range over" */ {}
+
+ for range a {}
+ for i := range a {
+ var ii int
+ ii = i
+ _ = ii
+ }
+ for i, x := range a {
+ var ii int
+ ii = i
+ _ = ii
+ var xx float64
+ xx = x /* ERROR "cannot assign" */
+ _ = xx
+ }
+ var ii int
+ var xx float32
+ for ii, xx = range a {}
+ _, _ = ii, xx
+
+ for range b {}
+ for i := range b {
+ var ii int
+ ii = i
+ _ = ii
+ }
+ for i, x := range b {
+ var ii int
+ ii = i
+ _ = ii
+ var xx string
+ xx = x
+ _ = xx
+ }
+
+ for range s {}
+ for i := range s {
+ var ii int
+ ii = i
+ _ = ii
+ }
+ for i, x := range s {
+ var ii int
+ ii = i
+ _ = ii
+ var xx rune
+ xx = x
+ _ = xx
+ }
+
+ for range p {}
+ for _, x := range p {
+ var xx complex128
+ xx = x
+ _ = xx
+ }
+
+ for range pp /* ERROR "cannot range over" */ {}
+ for _, x := range pp /* ERROR "cannot range over" */ {}
+
+ for range m {}
+ for k := range m {
+ var kk int32
+ kk = k /* ERROR "cannot assign" */
+ _ = kk
+ }
+ for k, v := range m {
+ var kk int
+ kk = k
+ _ = kk
+ if v {}
+ }
+
+ for range c {}
+ for _, _ /* ERROR "only one iteration variable" */ = range c {}
+ for e := range c {
+ var ee int
+ ee = e
+ _ = ee
+ }
+ for _ = range sc /* ERROR "cannot range over send-only channel" */ {}
+ for _ = range rc {}
+
+ // constant strings
+ const cs = "foo"
+ for range cs {}
+ for range "" {}
+ for i, x := range cs { _, _ = i, x }
+ for i, x := range "" {
+ var ii int
+ ii = i
+ _ = ii
+ var xx rune
+ xx = x
+ _ = xx
+ }
+}
+
+func rangeloops2() {
+ type I int
+ type R rune
+
+ var a [10]int
+ var i I
+ _ = i
+ for i /* ERROR cannot assign */ = range a {}
+ for i /* ERROR cannot assign */ = range &a {}
+ for i /* ERROR cannot assign */ = range a[:] {}
+
+ var s string
+ var r R
+ _ = r
+ for i /* ERROR cannot assign */ = range s {}
+ for i /* ERROR cannot assign */ = range "foo" {}
+ for _, r /* ERROR cannot assign */ = range s {}
+ for _, r /* ERROR cannot assign */ = range "foo" {}
+}
+
+func issue6766b() {
+ for _ := /* ERROR no new variables */ range "" {}
+ for a, a /* ERROR redeclared */ := range "" { _ = a }
+ var a int
+ _ = a
+ for a, a /* ERROR redeclared */ := range []int{1, 2, 3} { _ = a }
+}
+
+// Test that despite errors in the range clause,
+// the loop body is still type-checked (and thus
+// errors reported).
+func issue10148() {
+ for y /* ERROR declared but not used */ := range "" {
+ _ = "" /* ERROR cannot convert */ + 1
+ }
+ for range 1 /* ERROR cannot range over 1 */ {
+ _ = "" /* ERROR cannot convert */ + 1
+ }
+ for y := range 1 /* ERROR cannot range over 1 */ {
+ _ = "" /* ERROR cannot convert */ + 1
+ }
+}
+
+func labels0() {
+ goto L0
+ goto L1
+ L0:
+ L1:
+ L1 /* ERROR "already declared" */ :
+ if true {
+ goto L2
+ L2:
+ L0 /* ERROR "already declared" */ :
+ }
+ _ = func() {
+ goto L0
+ goto L1
+ goto L2
+ L0:
+ L1:
+ L2:
+ }
+}
+
+func expression_statements(ch chan int) {
+ expression_statements(ch)
+ <-ch
+ println()
+
+ 0 /* ERROR "not used" */
+ 1 /* ERROR "not used" */ +2
+ cap /* ERROR "not used" */ (ch)
+ println /* ERROR "must be called" */
+}
diff --git a/go/types/testdata/stmt1.src b/go/types/testdata/stmt1.src
new file mode 100644
index 0000000..a2955e6
--- /dev/null
+++ b/go/types/testdata/stmt1.src
@@ -0,0 +1,165 @@
+// 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.
+
+// terminating statements
+
+package stmt1
+
+func _() {}
+
+func _() int {} /* ERROR "missing return" */
+
+func _() int { panic(0) }
+func _() int { (panic(0)) }
+
+// block statements
+func _(x, y int) (z int) {
+ {
+ return
+ }
+}
+
+func _(x, y int) (z int) {
+ {
+ }
+} /* ERROR "missing return" */
+
+// if statements
+func _(x, y int) (z int) {
+ if x < y { return }
+ return 1
+}
+
+func _(x, y int) (z int) {
+ if x < y { return }
+} /* ERROR "missing return" */
+
+func _(x, y int) (z int) {
+ if x < y {
+ } else { return 1
+ }
+} /* ERROR "missing return" */
+
+func _(x, y int) (z int) {
+ if x < y { return
+ } else { return
+ }
+}
+
+// for statements
+func _(x, y int) (z int) {
+ for x < y {
+ return
+ }
+} /* ERROR "missing return" */
+
+func _(x, y int) (z int) {
+ for {
+ return
+ }
+}
+
+func _(x, y int) (z int) {
+ for {
+ return
+ break
+ }
+} /* ERROR "missing return" */
+
+func _(x, y int) (z int) {
+ for {
+ for { break }
+ return
+ }
+}
+
+func _(x, y int) (z int) {
+L: for {
+ for { break L }
+ return
+ }
+} /* ERROR "missing return" */
+
+// switch statements
+func _(x, y int) (z int) {
+ switch x {
+ case 0: return
+ default: return
+ }
+}
+
+func _(x, y int) (z int) {
+ switch x {
+ case 0: return
+ }
+} /* ERROR "missing return" */
+
+func _(x, y int) (z int) {
+ switch x {
+ case 0: return
+ case 1: break
+ }
+} /* ERROR "missing return" */
+
+func _(x, y int) (z int) {
+ switch x {
+ case 0: return
+ default:
+ switch y {
+ case 0: break
+ }
+ panic(0)
+ }
+}
+
+func _(x, y int) (z int) {
+L: switch x {
+ case 0: return
+ default:
+ switch y {
+ case 0: break L
+ }
+ panic(0)
+ }
+} /* ERROR "missing return" */
+
+// select statements
+func _(ch chan int) (z int) {
+ select {}
+} // nice!
+
+func _(ch chan int) (z int) {
+ select {
+ default: break
+ }
+} /* ERROR "missing return" */
+
+func _(ch chan int) (z int) {
+ select {
+ case <-ch: return
+ default: break
+ }
+} /* ERROR "missing return" */
+
+func _(ch chan int) (z int) {
+ select {
+ case <-ch: return
+ default:
+ for i := 0; i < 10; i++ {
+ break
+ }
+ return
+ }
+}
+
+func _(ch chan int) (z int) {
+L: select {
+ case <-ch: return
+ default:
+ for i := 0; i < 10; i++ {
+ break L
+ }
+ return
+ }
+} /* ERROR "missing return" */
diff --git a/go/types/testdata/vardecl.src b/go/types/testdata/vardecl.src
new file mode 100644
index 0000000..fb6b5f7
--- /dev/null
+++ b/go/types/testdata/vardecl.src
@@ -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.
+
+package vardecl
+
+// Prerequisites.
+import "math"
+func f() {}
+func g() (x, y int) { return }
+var m map[string]int
+
+// Var decls must have a type or an initializer.
+var _ int
+var _, _ int
+
+// The first error message is produced by the parser.
+// In a real-world scenario, the type-checker would not be run
+// in this case and the 2nd error message would not appear.
+var _ /* ERROR "missing variable type" */ /* ERROR "missing type or init expr" */
+var _ /* ERROR "missing variable type" */ /* ERROR "missing type or init expr" */, _
+var _ /* ERROR "missing variable type" */ /* ERROR "missing type or init expr" */, _, _
+
+// The initializer must be an expression.
+var _ = int /* ERROR "not an expression" */
+var _ = f /* ERROR "used as value" */ ()
+
+// Identifier and expression arity must match.
+var _, _ = 1, 2
+var _ = 1, 2 /* ERROR "extra init expr 2" */
+var _, _ = 1 /* ERROR "assignment count mismatch" */
+var _, _, _ /* ERROR "missing init expr for _" */ = 1, 2
+
+var _ = g /* ERROR "2-valued expr" */ ()
+var _, _ = g()
+var _, _, _ = g /* ERROR "assignment count mismatch" */ ()
+
+var _ = m["foo"]
+var _, _ = m["foo"]
+var _, _, _ = m /* ERROR "assignment count mismatch" */ ["foo"]
+
+var _, _ int = 1, 2
+var _ int = 1, 2 /* ERROR "extra init expr 2" */
+var _, _ int = 1 /* ERROR "assignment count mismatch" */
+var _, _, _ /* ERROR "missing init expr for _" */ int = 1, 2
+
+var (
+ _, _ = 1, 2
+ _ = 1, 2 /* ERROR "extra init expr 2" */
+ _, _ = 1 /* ERROR "assignment count mismatch" */
+ _, _, _ /* ERROR "missing init expr for _" */ = 1, 2
+
+ _ = g /* ERROR "2-valued expr" */ ()
+ _, _ = g()
+ _, _, _ = g /* ERROR "assignment count mismatch" */ ()
+
+ _ = m["foo"]
+ _, _ = m["foo"]
+ _, _, _ = m /* ERROR "assignment count mismatch" */ ["foo"]
+
+ _, _ int = 1, 2
+ _ int = 1, 2 /* ERROR "extra init expr 2" */
+ _, _ int = 1 /* ERROR "assignment count mismatch" */
+ _, _, _ /* ERROR "missing init expr for _" */ int = 1, 2
+)
+
+// Variables declared in function bodies must be 'used'.
+type T struct{}
+func (r T) _(a, b, c int) (u, v, w int) {
+ var x1 /* ERROR "declared but not used" */ int
+ var x2 /* ERROR "declared but not used" */ int
+ x1 = 1
+ (x2) = 2
+
+ y1 /* ERROR "declared but not used" */ := 1
+ y2 /* ERROR "declared but not used" */ := 2
+ y1 = 1
+ (y1) = 2
+
+ {
+ var x1 /* ERROR "declared but not used" */ int
+ var x2 /* ERROR "declared but not used" */ int
+ x1 = 1
+ (x2) = 2
+
+ y1 /* ERROR "declared but not used" */ := 1
+ y2 /* ERROR "declared but not used" */ := 2
+ y1 = 1
+ (y1) = 2
+ }
+
+ if x /* ERROR "declared but not used" */ := 0; a < b {}
+
+ switch x /* ERROR "declared but not used" */, y := 0, 1; a {
+ case 0:
+ _ = y
+ case 1:
+ x /* ERROR "declared but not used" */ := 0
+ }
+
+ var t interface{}
+ switch t /* ERROR "declared but not used" */ := t.(type) {}
+
+ switch t /* ERROR "declared but not used" */ := t.(type) {
+ case int:
+ }
+
+ switch t /* ERROR "declared but not used" */ := t.(type) {
+ case int:
+ case float32, complex64:
+ t = nil
+ }
+
+ switch t := t.(type) {
+ case int:
+ case float32, complex64:
+ _ = t
+ }
+
+ switch t := t.(type) {
+ case int:
+ case float32:
+ case string:
+ _ = func() string {
+ return t
+ }
+ }
+
+ switch t := t; t /* ERROR "declared but not used" */ := t.(type) {}
+
+ var z1 /* ERROR "declared but not used" */ int
+ var z2 int
+ _ = func(a, b, c int) (u, v, w int) {
+ z1 = a
+ (z1) = b
+ a = z2
+ return
+ }
+
+ var s []int
+ var i /* ERROR "declared but not used" */ , j int
+ for i, j = range s {
+ _ = j
+ }
+
+ for i, j /* ERROR "declared but not used" */ := range s {
+ _ = func() int {
+ return i
+ }
+ }
+ return
+}
+
+// Invalid (unused) expressions must not lead to spurious "declared but not used errors"
+func _() {
+ var a, b, c int
+ var x, y int
+ x, y = a /* ERROR assignment count mismatch */ , b, c
+ _ = x
+ _ = y
+}
+
+func _() {
+ var x int
+ return x /* ERROR no result values expected */
+ return math /* ERROR no result values expected */ .Sin(0)
+}
+
+func _() int {
+ var x, y int
+ return /* ERROR wrong number of return values */ x, y
+}
+
+// Short variable declarations must declare at least one new non-blank variable.
+func _() {
+ _ := /* ERROR no new variables */ 0
+ _, a := 0, 1
+ _, a := /* ERROR no new variables */ 0, 1
+ _, a, b := 0, 1, 2
+ _, _, _ := /* ERROR no new variables */ 0, 1, 2
+
+ _ = a
+ _ = b
+}
+
+// TODO(gri) consolidate other var decl checks in this file
\ No newline at end of file
diff --git a/go/types/token_test.go b/go/types/token_test.go
new file mode 100644
index 0000000..705bb29
--- /dev/null
+++ b/go/types/token_test.go
@@ -0,0 +1,47 @@
+// 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 checks invariants of token.Token ordering that we rely on
+// since package go/token doesn't provide any guarantees at the moment.
+
+package types
+
+import (
+ "go/token"
+ "testing"
+)
+
+var assignOps = map[token.Token]token.Token{
+ token.ADD_ASSIGN: token.ADD,
+ token.SUB_ASSIGN: token.SUB,
+ token.MUL_ASSIGN: token.MUL,
+ token.QUO_ASSIGN: token.QUO,
+ token.REM_ASSIGN: token.REM,
+ token.AND_ASSIGN: token.AND,
+ token.OR_ASSIGN: token.OR,
+ token.XOR_ASSIGN: token.XOR,
+ token.SHL_ASSIGN: token.SHL,
+ token.SHR_ASSIGN: token.SHR,
+ token.AND_NOT_ASSIGN: token.AND_NOT,
+}
+
+func TestZeroTok(t *testing.T) {
+ // zero value for token.Token must be token.ILLEGAL
+ var zero token.Token
+ if token.ILLEGAL != zero {
+ t.Errorf("%s == %d; want 0", token.ILLEGAL, zero)
+ }
+}
+
+func TestAssignOp(t *testing.T) {
+ // there are fewer than 256 tokens
+ for i := 0; i < 256; i++ {
+ tok := token.Token(i)
+ got := assignOp(tok)
+ want := assignOps[tok]
+ if got != want {
+ t.Errorf("for assignOp(%s): got %s; want %s", tok, got, want)
+ }
+ }
+}
diff --git a/go/types/type.go b/go/types/type.go
new file mode 100644
index 0000000..1df8b45
--- /dev/null
+++ b/go/types/type.go
@@ -0,0 +1,454 @@
+// 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 types
+
+import "sort"
+
+// TODO(gri) Revisit factory functions - make sure they have all relevant parameters.
+
+// A Type represents a type of Go.
+// All types implement the Type interface.
+type Type interface {
+ // Underlying returns the underlying type of a type.
+ Underlying() Type
+
+ // String returns a string representation of a type.
+ String() string
+}
+
+// BasicKind describes the kind of basic type.
+type BasicKind int
+
+const (
+ Invalid BasicKind = iota // type is invalid
+
+ // predeclared types
+ Bool
+ Int
+ Int8
+ Int16
+ Int32
+ Int64
+ Uint
+ Uint8
+ Uint16
+ Uint32
+ Uint64
+ Uintptr
+ Float32
+ Float64
+ Complex64
+ Complex128
+ String
+ UnsafePointer
+
+ // types for untyped values
+ UntypedBool
+ UntypedInt
+ UntypedRune
+ UntypedFloat
+ UntypedComplex
+ UntypedString
+ UntypedNil
+
+ // aliases
+ Byte = Uint8
+ Rune = Int32
+)
+
+// BasicInfo is a set of flags describing properties of a basic type.
+type BasicInfo int
+
+// Properties of basic types.
+const (
+ IsBoolean BasicInfo = 1 << iota
+ IsInteger
+ IsUnsigned
+ IsFloat
+ IsComplex
+ IsString
+ IsUntyped
+
+ IsOrdered = IsInteger | IsFloat | IsString
+ IsNumeric = IsInteger | IsFloat | IsComplex
+ IsConstType = IsBoolean | IsNumeric | IsString
+)
+
+// A Basic represents a basic type.
+type Basic struct {
+ kind BasicKind
+ info BasicInfo
+ name string
+}
+
+// Kind returns the kind of basic type b.
+func (b *Basic) Kind() BasicKind { return b.kind }
+
+// Info returns information about properties of basic type b.
+func (b *Basic) Info() BasicInfo { return b.info }
+
+// Name returns the name of basic type b.
+func (b *Basic) Name() string { return b.name }
+
+// An Array represents an array type.
+type Array struct {
+ len int64
+ elem Type
+}
+
+// NewArray returns a new array type for the given element type and length.
+func NewArray(elem Type, len int64) *Array { return &Array{len, elem} }
+
+// Len returns the length of array a.
+func (a *Array) Len() int64 { return a.len }
+
+// Elem returns element type of array a.
+func (a *Array) Elem() Type { return a.elem }
+
+// A Slice represents a slice type.
+type Slice struct {
+ elem Type
+}
+
+// NewSlice returns a new slice type for the given element type.
+func NewSlice(elem Type) *Slice { return &Slice{elem} }
+
+// Elem returns the element type of slice s.
+func (s *Slice) Elem() Type { return s.elem }
+
+// A Struct represents a struct type.
+type Struct struct {
+ fields []*Var
+ tags []string // field tags; nil if there are no tags
+ // TODO(gri) access to offsets is not threadsafe - fix this
+ offsets []int64 // field offsets in bytes, lazily initialized
+}
+
+// NewStruct returns a new struct with the given fields and corresponding field tags.
+// If a field with index i has a tag, tags[i] must be that tag, but len(tags) may be
+// only as long as required to hold the tag with the largest index i. Consequently,
+// if no field has a tag, tags may be nil.
+func NewStruct(fields []*Var, tags []string) *Struct {
+ var fset objset
+ for _, f := range fields {
+ if f.name != "_" && fset.insert(f) != nil {
+ panic("multiple fields with the same name")
+ }
+ }
+ if len(tags) > len(fields) {
+ panic("more tags than fields")
+ }
+ return &Struct{fields: fields, tags: tags}
+}
+
+// NumFields returns the number of fields in the struct (including blank and anonymous fields).
+func (s *Struct) NumFields() int { return len(s.fields) }
+
+// Field returns the i'th field for 0 <= i < NumFields().
+func (s *Struct) Field(i int) *Var { return s.fields[i] }
+
+// Tag returns the i'th field tag for 0 <= i < NumFields().
+func (s *Struct) Tag(i int) string {
+ if i < len(s.tags) {
+ return s.tags[i]
+ }
+ return ""
+}
+
+// A Pointer represents a pointer type.
+type Pointer struct {
+ base Type // element type
+}
+
+// NewPointer returns a new pointer type for the given element (base) type.
+func NewPointer(elem Type) *Pointer { return &Pointer{base: elem} }
+
+// Elem returns the element type for the given pointer p.
+func (p *Pointer) Elem() Type { return p.base }
+
+// A Tuple represents an ordered list of variables; a nil *Tuple is a valid (empty) tuple.
+// Tuples are used as components of signatures and to represent the type of multiple
+// assignments; they are not first class types of Go.
+type Tuple struct {
+ vars []*Var
+}
+
+// NewTuple returns a new tuple for the given variables.
+func NewTuple(x ...*Var) *Tuple {
+ if len(x) > 0 {
+ return &Tuple{x}
+ }
+ return nil
+}
+
+// Len returns the number variables of tuple t.
+func (t *Tuple) Len() int {
+ if t != nil {
+ return len(t.vars)
+ }
+ return 0
+}
+
+// At returns the i'th variable of tuple t.
+func (t *Tuple) At(i int) *Var { return t.vars[i] }
+
+// A Signature represents a (non-builtin) function or method type.
+type Signature struct {
+ // We need to keep the scope in Signature (rather than passing it around
+ // and store it in the Func Object) because when type-checking a function
+ // literal we call the general type checker which returns a general Type.
+ // We then unpack the *Signature and use the scope for the literal body.
+ scope *Scope // function scope, present for package-local signatures
+ recv *Var // nil if not a method
+ params *Tuple // (incoming) parameters from left to right; or nil
+ results *Tuple // (outgoing) results from left to right; or nil
+ variadic bool // true if the last parameter's type is of the form ...T (or string, for append built-in only)
+}
+
+// NewSignature returns a new function type for the given receiver, parameters,
+// and results, either of which may be nil. If variadic is set, the function
+// is variadic, it must have at least one parameter, and the last parameter
+// must be of unnamed slice type.
+func NewSignature(recv *Var, params, results *Tuple, variadic bool) *Signature {
+ if variadic {
+ n := params.Len()
+ if n == 0 {
+ panic("types.NewSignature: variadic function must have at least one parameter")
+ }
+ if _, ok := params.At(n - 1).typ.(*Slice); !ok {
+ panic("types.NewSignature: variadic parameter must be of unnamed slice type")
+ }
+ }
+ return &Signature{nil, recv, params, results, variadic}
+}
+
+// Recv returns the receiver of signature s (if a method), or nil if a
+// function.
+//
+// For an abstract method, Recv returns the enclosing interface either
+// as a *Named or an *Interface. Due to embedding, an interface may
+// contain methods whose receiver type is a different interface.
+func (s *Signature) Recv() *Var { return s.recv }
+
+// Params returns the parameters of signature s, or nil.
+func (s *Signature) Params() *Tuple { return s.params }
+
+// Results returns the results of signature s, or nil.
+func (s *Signature) Results() *Tuple { return s.results }
+
+// Variadic reports whether the signature s is variadic.
+func (s *Signature) Variadic() bool { return s.variadic }
+
+// An Interface represents an interface type.
+type Interface struct {
+ methods []*Func // ordered list of explicitly declared methods
+ embeddeds []*Named // ordered list of explicitly embedded types
+
+ allMethods []*Func // ordered list of methods declared with or embedded in this interface (TODO(gri): replace with mset)
+}
+
+// NewInterface returns a new interface for the given methods and embedded types.
+func NewInterface(methods []*Func, embeddeds []*Named) *Interface {
+ typ := new(Interface)
+
+ var mset objset
+ for _, m := range methods {
+ if mset.insert(m) != nil {
+ panic("multiple methods with the same name")
+ }
+ // set receiver
+ // TODO(gri) Ideally, we should use a named type here instead of
+ // typ, for less verbose printing of interface method signatures.
+ m.typ.(*Signature).recv = NewVar(m.pos, m.pkg, "", typ)
+ }
+ sort.Sort(byUniqueMethodName(methods))
+
+ if embeddeds == nil {
+ sort.Sort(byUniqueTypeName(embeddeds))
+ }
+
+ typ.methods = methods
+ typ.embeddeds = embeddeds
+ return typ
+}
+
+// NumExplicitMethods returns the number of explicitly declared methods of interface t.
+func (t *Interface) NumExplicitMethods() int { return len(t.methods) }
+
+// ExplicitMethod returns the i'th explicitly declared method of interface t for 0 <= i < t.NumExplicitMethods().
+// The methods are ordered by their unique Id.
+func (t *Interface) ExplicitMethod(i int) *Func { return t.methods[i] }
+
+// NumEmbeddeds returns the number of embedded types in interface t.
+func (t *Interface) NumEmbeddeds() int { return len(t.embeddeds) }
+
+// Embedded returns the i'th embedded type of interface t for 0 <= i < t.NumEmbeddeds().
+// The types are ordered by the corresponding TypeName's unique Id.
+func (t *Interface) Embedded(i int) *Named { return t.embeddeds[i] }
+
+// NumMethods returns the total number of methods of interface t.
+func (t *Interface) NumMethods() int { return len(t.allMethods) }
+
+// Method returns the i'th method of interface t for 0 <= i < t.NumMethods().
+// The methods are ordered by their unique Id.
+func (t *Interface) Method(i int) *Func { return t.allMethods[i] }
+
+// Empty returns true if t is the empty interface.
+func (t *Interface) Empty() bool { return len(t.allMethods) == 0 }
+
+// Complete computes the interface's method set. It must be called by users of
+// NewInterface after the interface's embedded types are fully defined and
+// before using the interface type in any way other than to form other types.
+// Complete returns the receiver.
+func (t *Interface) Complete() *Interface {
+ if t.allMethods != nil {
+ return t
+ }
+
+ var allMethods []*Func
+ if t.embeddeds == nil {
+ if t.methods == nil {
+ allMethods = make([]*Func, 0, 1)
+ } else {
+ allMethods = t.methods
+ }
+ } else {
+ allMethods = append(allMethods, t.methods...)
+ for _, et := range t.embeddeds {
+ it := et.Underlying().(*Interface)
+ it.Complete()
+ for _, tm := range it.allMethods {
+ // Make a copy of the method and adjust its receiver type.
+ newm := *tm
+ newmtyp := *tm.typ.(*Signature)
+ newm.typ = &newmtyp
+ newmtyp.recv = NewVar(newm.pos, newm.pkg, "", t)
+ allMethods = append(allMethods, &newm)
+ }
+ }
+ sort.Sort(byUniqueMethodName(allMethods))
+ }
+ t.allMethods = allMethods
+
+ return t
+}
+
+// A Map represents a map type.
+type Map struct {
+ key, elem Type
+}
+
+// NewMap returns a new map for the given key and element types.
+func NewMap(key, elem Type) *Map {
+ return &Map{key, elem}
+}
+
+// Key returns the key type of map m.
+func (m *Map) Key() Type { return m.key }
+
+// Elem returns the element type of map m.
+func (m *Map) Elem() Type { return m.elem }
+
+// A Chan represents a channel type.
+type Chan struct {
+ dir ChanDir
+ elem Type
+}
+
+// A ChanDir value indicates a channel direction.
+type ChanDir int
+
+// The direction of a channel is indicated by one of the following constants.
+const (
+ SendRecv ChanDir = iota
+ SendOnly
+ RecvOnly
+)
+
+// NewChan returns a new channel type for the given direction and element type.
+func NewChan(dir ChanDir, elem Type) *Chan {
+ return &Chan{dir, elem}
+}
+
+// Dir returns the direction of channel c.
+func (c *Chan) Dir() ChanDir { return c.dir }
+
+// Elem returns the element type of channel c.
+func (c *Chan) Elem() Type { return c.elem }
+
+// A Named represents a named type.
+type Named struct {
+ obj *TypeName // corresponding declared object
+ underlying Type // possibly a *Named during setup; never a *Named once set up completely
+ methods []*Func // methods declared for this type (not the method set of this type)
+}
+
+// NewNamed returns a new named type for the given type name, underlying type, and associated methods.
+// The underlying type must not be a *Named.
+func NewNamed(obj *TypeName, underlying Type, methods []*Func) *Named {
+ if _, ok := underlying.(*Named); ok {
+ panic("types.NewNamed: underlying type must not be *Named")
+ }
+ typ := &Named{obj: obj, underlying: underlying, methods: methods}
+ if obj.typ == nil {
+ obj.typ = typ
+ }
+ return typ
+}
+
+// TypeName returns the type name for the named type t.
+func (t *Named) Obj() *TypeName { return t.obj }
+
+// NumMethods returns the number of explicit methods whose receiver is named type t.
+func (t *Named) NumMethods() int { return len(t.methods) }
+
+// Method returns the i'th method of named type t for 0 <= i < t.NumMethods().
+func (t *Named) Method(i int) *Func { return t.methods[i] }
+
+// SetUnderlying sets the underlying type and marks t as complete.
+// TODO(gri) determine if there's a better solution rather than providing this function
+func (t *Named) SetUnderlying(underlying Type) {
+ if underlying == nil {
+ panic("types.Named.SetUnderlying: underlying type must not be nil")
+ }
+ if _, ok := underlying.(*Named); ok {
+ panic("types.Named.SetUnderlying: underlying type must not be *Named")
+ }
+ t.underlying = underlying
+}
+
+// AddMethod adds method m unless it is already in the method list.
+// TODO(gri) find a better solution instead of providing this function
+func (t *Named) AddMethod(m *Func) {
+ if i, _ := lookupMethod(t.methods, m.pkg, m.name); i < 0 {
+ t.methods = append(t.methods, m)
+ }
+}
+
+// Implementations for Type methods.
+
+func (t *Basic) Underlying() Type { return t }
+func (t *Array) Underlying() Type { return t }
+func (t *Slice) Underlying() Type { return t }
+func (t *Struct) Underlying() Type { return t }
+func (t *Pointer) Underlying() Type { return t }
+func (t *Tuple) Underlying() Type { return t }
+func (t *Signature) Underlying() Type { return t }
+func (t *Interface) Underlying() Type { return t }
+func (t *Map) Underlying() Type { return t }
+func (t *Chan) Underlying() Type { return t }
+func (t *Named) Underlying() Type { return t.underlying }
+
+func (t *Basic) String() string { return TypeString(t, nil) }
+func (t *Array) String() string { return TypeString(t, nil) }
+func (t *Slice) String() string { return TypeString(t, nil) }
+func (t *Struct) String() string { return TypeString(t, nil) }
+func (t *Pointer) String() string { return TypeString(t, nil) }
+func (t *Tuple) String() string { return TypeString(t, nil) }
+func (t *Signature) String() string { return TypeString(t, nil) }
+func (t *Interface) String() string { return TypeString(t, nil) }
+func (t *Map) String() string { return TypeString(t, nil) }
+func (t *Chan) String() string { return TypeString(t, nil) }
+func (t *Named) String() string { return TypeString(t, nil) }
diff --git a/go/types/typestring.go b/go/types/typestring.go
new file mode 100644
index 0000000..abee8ab
--- /dev/null
+++ b/go/types/typestring.go
@@ -0,0 +1,292 @@
+// 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 printing of types.
+
+package types
+
+import (
+ "bytes"
+ "fmt"
+)
+
+// A Qualifier controls how named package-level objects are printed in
+// calls to TypeString, ObjectString, and SelectionString.
+//
+// These three formatting routines call the Qualifier for each
+// package-level object O, and if the Qualifier returns a non-empty
+// string p, the object is printed in the form p.O.
+// If it returns an empty string, only the object name O is printed.
+//
+// Using a nil Qualifier is equivalent to using (*Package).Path: the
+// object is qualified by the import path, e.g., "encoding/json.Marshal".
+//
+type Qualifier func(*Package) string
+
+// RelativeTo(pkg) returns a Qualifier that fully qualifies members of
+// all packages other than pkg.
+func RelativeTo(pkg *Package) Qualifier {
+ if pkg == nil {
+ return nil
+ }
+ return func(other *Package) string {
+ if pkg == other {
+ return "" // same package; unqualified
+ }
+ return other.Path()
+ }
+}
+
+// If GcCompatibilityMode is set, printing of types is modified
+// to match the representation of some types in the gc compiler:
+//
+// - byte and rune lose their alias name and simply stand for
+// uint8 and int32 respectively
+// - embedded interfaces get flattened (the embedding info is lost,
+// and certain recursive interface types cannot be printed anymore)
+//
+// This makes it easier to compare packages computed with the type-
+// checker vs packages imported from gc export data.
+//
+// Caution: This flag affects all uses of WriteType, globally.
+// It is only provided for testing in conjunction with
+// gc-generated data. It may be removed at any time.
+var GcCompatibilityMode bool
+
+// TypeString returns the string representation of typ.
+// The Qualifier controls the printing of
+// package-level objects, and may be nil.
+func TypeString(typ Type, qf Qualifier) string {
+ var buf bytes.Buffer
+ WriteType(&buf, typ, qf)
+ return buf.String()
+}
+
+// WriteType writes the string representation of typ to buf.
+// The Qualifier controls the printing of
+// package-level objects, and may be nil.
+func WriteType(buf *bytes.Buffer, typ Type, qf Qualifier) {
+ writeType(buf, typ, qf, make([]Type, 8))
+}
+
+func writeType(buf *bytes.Buffer, typ Type, qf Qualifier, visited []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 {
+ fmt.Fprintf(buf, "○%T", typ) // cycle to typ
+ return
+ }
+ }
+ visited = append(visited, typ)
+
+ switch t := typ.(type) {
+ case nil:
+ buf.WriteString("<nil>")
+
+ case *Basic:
+ if t.kind == UnsafePointer {
+ buf.WriteString("unsafe.")
+ }
+ if GcCompatibilityMode {
+ // forget the alias names
+ switch t.kind {
+ case Byte:
+ t = Typ[Uint8]
+ case Rune:
+ t = Typ[Int32]
+ }
+ }
+ buf.WriteString(t.name)
+
+ case *Array:
+ fmt.Fprintf(buf, "[%d]", t.len)
+ writeType(buf, t.elem, qf, visited)
+
+ case *Slice:
+ buf.WriteString("[]")
+ writeType(buf, t.elem, qf, visited)
+
+ case *Struct:
+ buf.WriteString("struct{")
+ for i, f := range t.fields {
+ if i > 0 {
+ buf.WriteString("; ")
+ }
+ if !f.anonymous {
+ buf.WriteString(f.name)
+ buf.WriteByte(' ')
+ }
+ writeType(buf, f.typ, qf, visited)
+ if tag := t.Tag(i); tag != "" {
+ fmt.Fprintf(buf, " %q", tag)
+ }
+ }
+ buf.WriteByte('}')
+
+ case *Pointer:
+ buf.WriteByte('*')
+ writeType(buf, t.base, qf, visited)
+
+ case *Tuple:
+ writeTuple(buf, t, false, qf, visited)
+
+ case *Signature:
+ buf.WriteString("func")
+ writeSignature(buf, t, qf, visited)
+
+ case *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 }
+ // }
+ //
+ buf.WriteString("interface{")
+ if GcCompatibilityMode {
+ // print flattened interface
+ // (useful to compare against gc-generated interfaces)
+ for i, m := range t.allMethods {
+ if i > 0 {
+ buf.WriteString("; ")
+ }
+ buf.WriteString(m.name)
+ writeSignature(buf, m.typ.(*Signature), qf, visited)
+ }
+ } else {
+ // print explicit interface methods and embedded types
+ for i, m := range t.methods {
+ if i > 0 {
+ buf.WriteString("; ")
+ }
+ buf.WriteString(m.name)
+ writeSignature(buf, m.typ.(*Signature), qf, visited)
+ }
+ for i, typ := range t.embeddeds {
+ if i > 0 || len(t.methods) > 0 {
+ buf.WriteString("; ")
+ }
+ writeType(buf, typ, qf, visited)
+ }
+ }
+ buf.WriteByte('}')
+
+ case *Map:
+ buf.WriteString("map[")
+ writeType(buf, t.key, qf, visited)
+ buf.WriteByte(']')
+ writeType(buf, t.elem, qf, visited)
+
+ case *Chan:
+ var s string
+ var parens bool
+ switch t.dir {
+ case SendRecv:
+ s = "chan "
+ // chan (<-chan T) requires parentheses
+ if c, _ := t.elem.(*Chan); c != nil && c.dir == RecvOnly {
+ parens = true
+ }
+ case SendOnly:
+ s = "chan<- "
+ case RecvOnly:
+ s = "<-chan "
+ default:
+ panic("unreachable")
+ }
+ buf.WriteString(s)
+ if parens {
+ buf.WriteByte('(')
+ }
+ writeType(buf, t.elem, qf, visited)
+ if parens {
+ buf.WriteByte(')')
+ }
+
+ case *Named:
+ s := "<Named w/o object>"
+ if obj := t.obj; obj != nil {
+ if obj.pkg != nil {
+ writePackage(buf, obj.pkg, qf)
+ }
+ // TODO(gri): function-local named types should be displayed
+ // differently from named types at package level to avoid
+ // ambiguity.
+ s = obj.name
+ }
+ buf.WriteString(s)
+
+ default:
+ // For externally defined implementations of Type.
+ buf.WriteString(t.String())
+ }
+}
+
+func writeTuple(buf *bytes.Buffer, tup *Tuple, variadic bool, qf Qualifier, visited []Type) {
+ buf.WriteByte('(')
+ if tup != nil {
+ for i, v := range tup.vars {
+ if i > 0 {
+ buf.WriteString(", ")
+ }
+ if v.name != "" {
+ buf.WriteString(v.name)
+ buf.WriteByte(' ')
+ }
+ typ := v.typ
+ if variadic && i == len(tup.vars)-1 {
+ if s, ok := typ.(*Slice); ok {
+ buf.WriteString("...")
+ typ = s.elem
+ } else {
+ // special case:
+ // append(s, "foo"...) leads to signature func([]byte, string...)
+ if t, ok := typ.Underlying().(*Basic); !ok || t.kind != String {
+ panic("internal error: string type expected")
+ }
+ writeType(buf, typ, qf, visited)
+ buf.WriteString("...")
+ continue
+ }
+ }
+ writeType(buf, typ, qf, visited)
+ }
+ }
+ buf.WriteByte(')')
+}
+
+// WriteSignature writes the representation of the signature sig to buf,
+// without a leading "func" keyword.
+// The Qualifier controls the printing of
+// package-level objects, and may be nil.
+func WriteSignature(buf *bytes.Buffer, sig *Signature, qf Qualifier) {
+ writeSignature(buf, sig, qf, make([]Type, 8))
+}
+
+func writeSignature(buf *bytes.Buffer, sig *Signature, qf Qualifier, visited []Type) {
+ writeTuple(buf, sig.params, sig.variadic, qf, visited)
+
+ n := sig.results.Len()
+ if n == 0 {
+ // no result
+ return
+ }
+
+ buf.WriteByte(' ')
+ if n == 1 && sig.results.vars[0].name == "" {
+ // single unnamed result
+ writeType(buf, sig.results.vars[0].typ, qf, visited)
+ return
+ }
+
+ // multiple or named result(s)
+ writeTuple(buf, sig.results, false, qf, visited)
+}
diff --git a/go/types/typestring_test.go b/go/types/typestring_test.go
new file mode 100644
index 0000000..975b623
--- /dev/null
+++ b/go/types/typestring_test.go
@@ -0,0 +1,166 @@
+// 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 types_test
+
+import (
+ "go/ast"
+ "go/parser"
+ "go/token"
+ "testing"
+
+ _ "golang.org/x/tools/go/gcimporter"
+ . "golang.org/x/tools/go/types"
+)
+
+const filename = "<src>"
+
+func makePkg(t *testing.T, src string) (*Package, error) {
+ fset := token.NewFileSet()
+ file, err := parser.ParseFile(fset, filename, src, parser.DeclarationErrors)
+ if err != nil {
+ return nil, err
+ }
+ // use the package name as package path
+ return Check(file.Name.Name, fset, []*ast.File{file})
+}
+
+type testEntry struct {
+ src, str string
+}
+
+// dup returns a testEntry where both src and str are the same.
+func dup(s string) testEntry {
+ return testEntry{s, s}
+}
+
+// types that don't depend on any other type declarations
+var independentTestTypes = []testEntry{
+ // basic types
+ dup("int"),
+ dup("float32"),
+ dup("string"),
+
+ // arrays
+ dup("[10]int"),
+
+ // slices
+ dup("[]int"),
+ dup("[][]int"),
+
+ // structs
+ dup("struct{}"),
+ dup("struct{x int}"),
+ {`struct {
+ x, y int
+ z float32 "foo"
+ }`, `struct{x int; y int; z float32 "foo"}`},
+ {`struct {
+ string
+ elems []complex128
+ }`, `struct{string; elems []complex128}`},
+
+ // pointers
+ dup("*int"),
+ dup("***struct{}"),
+ dup("*struct{a int; b float32}"),
+
+ // functions
+ dup("func()"),
+ dup("func(x int)"),
+ {"func(x, y int)", "func(x int, y int)"},
+ {"func(x, y int, z string)", "func(x int, y int, z string)"},
+ dup("func(int)"),
+ {"func(int, string, byte)", "func(int, string, byte)"},
+
+ dup("func() int"),
+ {"func() (string)", "func() string"},
+ dup("func() (u int)"),
+ {"func() (u, v int, w string)", "func() (u int, v int, w string)"},
+
+ dup("func(int) string"),
+ dup("func(x int) string"),
+ dup("func(x int) (u string)"),
+ {"func(x, y int) (u string)", "func(x int, y int) (u string)"},
+
+ dup("func(...int) string"),
+ dup("func(x ...int) string"),
+ dup("func(x ...int) (u string)"),
+ {"func(x, y ...int) (u string)", "func(x int, y ...int) (u string)"},
+
+ // interfaces
+ dup("interface{}"),
+ dup("interface{m()}"),
+ dup(`interface{String() string; m(int) float32}`),
+
+ // maps
+ dup("map[string]int"),
+ {"map[struct{x, y int}][]byte", "map[struct{x int; y int}][]byte"},
+
+ // channels
+ dup("chan<- chan int"),
+ dup("chan<- <-chan int"),
+ dup("<-chan <-chan int"),
+ dup("chan (<-chan int)"),
+ dup("chan<- func()"),
+ dup("<-chan []func() int"),
+}
+
+// types that depend on other type declarations (src in TestTypes)
+var dependentTestTypes = []testEntry{
+ // interfaces
+ dup(`interface{io.Reader; io.Writer}`),
+ dup(`interface{m() int; io.Writer}`),
+ {`interface{m() interface{T}}`, `interface{m() interface{p.T}}`},
+}
+
+func TestTypeString(t *testing.T) {
+ skipSpecialPlatforms(t)
+
+ var tests []testEntry
+ tests = append(tests, independentTestTypes...)
+ tests = append(tests, dependentTestTypes...)
+
+ for _, test := range tests {
+ src := `package p; import "io"; type _ io.Writer; type T ` + test.src
+ pkg, err := makePkg(t, src)
+ if err != nil {
+ t.Errorf("%s: %s", src, err)
+ continue
+ }
+ typ := pkg.Scope().Lookup("T").Type().Underlying()
+ if got := typ.String(); got != test.str {
+ t.Errorf("%s: got %s, want %s", test.src, got, test.str)
+ }
+ }
+}
+
+func TestQualifiedTypeString(t *testing.T) {
+ p, _ := pkgFor("p.go", "package p; type T int", nil)
+ q, _ := pkgFor("q.go", "package q", nil)
+
+ pT := p.Scope().Lookup("T").Type()
+ for _, test := range []struct {
+ typ Type
+ this *Package
+ want string
+ }{
+ {pT, nil, "p.T"},
+ {pT, p, "T"},
+ {pT, q, "p.T"},
+ {NewPointer(pT), p, "*T"},
+ {NewPointer(pT), q, "*p.T"},
+ } {
+ qualifier := func(pkg *Package) string {
+ if pkg != test.this {
+ return pkg.Name()
+ }
+ return ""
+ }
+ if got := TypeString(test.typ, qualifier); got != test.want {
+ t.Errorf("TypeString(%s, %s) = %s, want %s",
+ test.this, test.typ, got, test.want)
+ }
+ }
+}
diff --git a/go/types/typeutil/example_test.go b/go/types/typeutil/example_test.go
new file mode 100644
index 0000000..9e3ada7
--- /dev/null
+++ b/go/types/typeutil/example_test.go
@@ -0,0 +1,68 @@
+// 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 typeutil_test
+
+import (
+ "fmt"
+ "sort"
+
+ "go/ast"
+ "go/parser"
+ "go/token"
+
+ "golang.org/x/tools/go/types"
+ "golang.org/x/tools/go/types/typeutil"
+)
+
+func ExampleMap() {
+ const source = `package P
+
+var X []string
+var Y []string
+
+const p, q = 1.0, 2.0
+
+func f(offset int32) (value byte, ok bool)
+func g(rune) (uint8, bool)
+`
+
+ // Parse and type-check the package.
+ fset := token.NewFileSet()
+ f, err := parser.ParseFile(fset, "P.go", source, 0)
+ if err != nil {
+ panic(err)
+ }
+ pkg, err := new(types.Config).Check("P", fset, []*ast.File{f}, nil)
+ if err != nil {
+ panic(err)
+ }
+
+ scope := pkg.Scope()
+
+ // Group names of package-level objects by their type.
+ var namesByType typeutil.Map // value is []string
+ for _, name := range scope.Names() {
+ T := scope.Lookup(name).Type()
+
+ names, _ := namesByType.At(T).([]string)
+ names = append(names, name)
+ namesByType.Set(T, names)
+ }
+
+ // Format, sort, and print the map entries.
+ var lines []string
+ namesByType.Iterate(func(T types.Type, names interface{}) {
+ lines = append(lines, fmt.Sprintf("%s %s", names, T))
+ })
+ sort.Strings(lines)
+ for _, line := range lines {
+ fmt.Println(line)
+ }
+
+ // Output:
+ // [X Y] []string
+ // [f g] func(offset int32) (value byte, ok bool)
+ // [p q] untyped float
+}
diff --git a/go/types/typeutil/imports.go b/go/types/typeutil/imports.go
new file mode 100644
index 0000000..967fe1e
--- /dev/null
+++ b/go/types/typeutil/imports.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.
+
+package typeutil
+
+import "golang.org/x/tools/go/types"
+
+// Dependencies returns all dependencies of the specified packages.
+//
+// Dependent packages appear in topological order: if package P imports
+// package Q, Q appears earlier than P in the result.
+// The algorithm follows import statements in the order they
+// appear in the source code, so the result is a total order.
+//
+func Dependencies(pkgs ...*types.Package) []*types.Package {
+ var result []*types.Package
+ seen := make(map[*types.Package]bool)
+ var visit func(pkgs []*types.Package)
+ visit = func(pkgs []*types.Package) {
+ for _, p := range pkgs {
+ if !seen[p] {
+ seen[p] = true
+ visit(p.Imports())
+ result = append(result, p)
+ }
+ }
+ }
+ visit(pkgs)
+ return result
+}
diff --git a/go/types/typeutil/imports_test.go b/go/types/typeutil/imports_test.go
new file mode 100644
index 0000000..8071ae1
--- /dev/null
+++ b/go/types/typeutil/imports_test.go
@@ -0,0 +1,79 @@
+// 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 typeutil_test
+
+import (
+ "fmt"
+ "go/ast"
+ "go/parser"
+ "go/token"
+ "testing"
+
+ "golang.org/x/tools/go/types"
+ "golang.org/x/tools/go/types/typeutil"
+)
+
+func TestDependencies(t *testing.T) {
+ packages := make(map[string]*types.Package)
+ conf := types.Config{
+ Packages: packages,
+ Import: func(_ map[string]*types.Package, path string) (*types.Package, error) {
+ return packages[path], nil
+ },
+ }
+ fset := token.NewFileSet()
+
+ // All edges go to the right.
+ // /--D--B--A
+ // F \_C_/
+ // \__E_/
+ for i, content := range []string{
+ `package A`,
+ `package C; import (_ "A")`,
+ `package B; import (_ "A")`,
+ `package E; import (_ "C")`,
+ `package D; import (_ "B"; _ "C")`,
+ `package F; import (_ "D"; _ "E")`,
+ } {
+ f, err := parser.ParseFile(fset, fmt.Sprintf("%d.go", i), content, 0)
+ if err != nil {
+ t.Fatal(err)
+ }
+ pkg, err := conf.Check(f.Name.Name, fset, []*ast.File{f}, nil)
+ if err != nil {
+ t.Fatal(err)
+ }
+ packages[pkg.Path()] = pkg
+ }
+
+ for _, test := range []struct {
+ roots, want string
+ }{
+ {"A", "A"},
+ {"B", "AB"},
+ {"C", "AC"},
+ {"D", "ABCD"},
+ {"E", "ACE"},
+ {"F", "ABCDEF"},
+
+ {"BE", "ABCE"},
+ {"EB", "ACEB"},
+ {"DE", "ABCDE"},
+ {"ED", "ACEBD"},
+ {"EF", "ACEBDF"},
+ } {
+ var pkgs []*types.Package
+ for _, r := range test.roots {
+ pkgs = append(pkgs, conf.Packages[string(r)])
+ }
+ var got string
+ for _, p := range typeutil.Dependencies(pkgs...) {
+ got += p.Path()
+ }
+ if got != test.want {
+ t.Errorf("Dependencies(%q) = %q, want %q", test.roots, got, test.want)
+ }
+ }
+}
diff --git a/go/types/typeutil/map.go b/go/types/typeutil/map.go
new file mode 100644
index 0000000..b3a04cc
--- /dev/null
+++ b/go/types/typeutil/map.go
@@ -0,0 +1,314 @@
+// 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 typeutil defines various utilities for types, such as Map,
+// a mapping from types.Type to interface{} values.
+package typeutil // import "golang.org/x/tools/go/types/typeutil"
+
+import (
+ "bytes"
+ "fmt"
+ "reflect"
+
+ "golang.org/x/tools/go/types"
+)
+
+// Map is a hash-table-based mapping from types (types.Type) to
+// arbitrary interface{} values. The concrete types that implement
+// the Type interface are pointers. Since they are not canonicalized,
+// == cannot be used to check for equivalence, and thus we cannot
+// simply use a Go map.
+//
+// Just as with map[K]V, a nil *Map is a valid empty map.
+//
+// Not thread-safe.
+//
+type Map struct {
+ hasher Hasher // shared by many Maps
+ table map[uint32][]entry // maps hash to bucket; entry.key==nil means unused
+ length int // number of map entries
+}
+
+// entry is an entry (key/value association) in a hash bucket.
+type entry struct {
+ key types.Type
+ value interface{}
+}
+
+// SetHasher sets the hasher used by Map.
+//
+// All Hashers are functionally equivalent but contain internal state
+// used to cache the results of hashing previously seen types.
+//
+// A single Hasher created by MakeHasher() may be shared among many
+// Maps. This is recommended if the instances have many keys in
+// common, as it will amortize the cost of hash computation.
+//
+// A Hasher may grow without bound as new types are seen. Even when a
+// type is deleted from the map, the Hasher never shrinks, since other
+// types in the map may reference the deleted type indirectly.
+//
+// Hashers are not thread-safe, and read-only operations such as
+// Map.Lookup require updates to the hasher, so a full Mutex lock (not a
+// read-lock) is require around all Map operations if a shared
+// hasher is accessed from multiple threads.
+//
+// If SetHasher is not called, the Map will create a private hasher at
+// the first call to Insert.
+//
+func (m *Map) SetHasher(hasher Hasher) {
+ m.hasher = hasher
+}
+
+// Delete removes the entry with the given key, if any.
+// It returns true if the entry was found.
+//
+func (m *Map) Delete(key types.Type) bool {
+ if m != nil && m.table != nil {
+ hash := m.hasher.Hash(key)
+ bucket := m.table[hash]
+ for i, e := range bucket {
+ if e.key != nil && types.Identical(key, e.key) {
+ // We can't compact the bucket as it
+ // would disturb iterators.
+ bucket[i] = entry{}
+ m.length--
+ return true
+ }
+ }
+ }
+ return false
+}
+
+// At returns the map entry for the given key.
+// The result is nil if the entry is not present.
+//
+func (m *Map) At(key types.Type) interface{} {
+ if m != nil && m.table != nil {
+ for _, e := range m.table[m.hasher.Hash(key)] {
+ if e.key != nil && types.Identical(key, e.key) {
+ return e.value
+ }
+ }
+ }
+ return nil
+}
+
+// Set sets the map entry for key to val,
+// and returns the previous entry, if any.
+func (m *Map) Set(key types.Type, value interface{}) (prev interface{}) {
+ if m.table != nil {
+ hash := m.hasher.Hash(key)
+ bucket := m.table[hash]
+ var hole *entry
+ for i, e := range bucket {
+ if e.key == nil {
+ hole = &bucket[i]
+ } else if types.Identical(key, e.key) {
+ prev = e.value
+ bucket[i].value = value
+ return
+ }
+ }
+
+ if hole != nil {
+ *hole = entry{key, value} // overwrite deleted entry
+ } else {
+ m.table[hash] = append(bucket, entry{key, value})
+ }
+ } else {
+ if m.hasher.memo == nil {
+ m.hasher = MakeHasher()
+ }
+ hash := m.hasher.Hash(key)
+ m.table = map[uint32][]entry{hash: {entry{key, value}}}
+ }
+
+ m.length++
+ return
+}
+
+// Len returns the number of map entries.
+func (m *Map) Len() int {
+ if m != nil {
+ return m.length
+ }
+ return 0
+}
+
+// Iterate calls function f on each entry in the map in unspecified order.
+//
+// If f should mutate the map, Iterate provides the same guarantees as
+// Go maps: if f deletes a map entry that Iterate has not yet reached,
+// f will not be invoked for it, but if f inserts a map entry that
+// Iterate has not yet reached, whether or not f will be invoked for
+// it is unspecified.
+//
+func (m *Map) Iterate(f func(key types.Type, value interface{})) {
+ if m != nil {
+ for _, bucket := range m.table {
+ for _, e := range bucket {
+ if e.key != nil {
+ f(e.key, e.value)
+ }
+ }
+ }
+ }
+}
+
+// Keys returns a new slice containing the set of map keys.
+// The order is unspecified.
+func (m *Map) Keys() []types.Type {
+ keys := make([]types.Type, 0, m.Len())
+ m.Iterate(func(key types.Type, _ interface{}) {
+ keys = append(keys, key)
+ })
+ return keys
+}
+
+func (m *Map) toString(values bool) string {
+ if m == nil {
+ return "{}"
+ }
+ var buf bytes.Buffer
+ fmt.Fprint(&buf, "{")
+ sep := ""
+ m.Iterate(func(key types.Type, value interface{}) {
+ fmt.Fprint(&buf, sep)
+ sep = ", "
+ fmt.Fprint(&buf, key)
+ if values {
+ fmt.Fprintf(&buf, ": %q", value)
+ }
+ })
+ fmt.Fprint(&buf, "}")
+ return buf.String()
+}
+
+// String returns a string representation of the map's entries.
+// Values are printed using fmt.Sprintf("%v", v).
+// Order is unspecified.
+//
+func (m *Map) String() string {
+ return m.toString(true)
+}
+
+// KeysString returns a string representation of the map's key set.
+// Order is unspecified.
+//
+func (m *Map) KeysString() string {
+ return m.toString(false)
+}
+
+////////////////////////////////////////////////////////////////////////
+// Hasher
+
+// A Hasher maps each type to its hash value.
+// For efficiency, a hasher uses memoization; thus its memory
+// footprint grows monotonically over time.
+// Hashers are not thread-safe.
+// Hashers have reference semantics.
+// Call MakeHasher to create a Hasher.
+type Hasher struct {
+ memo map[types.Type]uint32
+}
+
+// MakeHasher returns a new Hasher instance.
+func MakeHasher() Hasher {
+ return Hasher{make(map[types.Type]uint32)}
+}
+
+// Hash computes a hash value for the given type t such that
+// Identical(t, t') => Hash(t) == Hash(t').
+func (h Hasher) Hash(t types.Type) uint32 {
+ hash, ok := h.memo[t]
+ if !ok {
+ hash = h.hashFor(t)
+ h.memo[t] = hash
+ }
+ return hash
+}
+
+// hashString computes the Fowler–Noll–Vo hash of s.
+func hashString(s string) uint32 {
+ var h uint32
+ for i := 0; i < len(s); i++ {
+ h ^= uint32(s[i])
+ h *= 16777619
+ }
+ return h
+}
+
+// hashFor computes the hash of t.
+func (h Hasher) hashFor(t types.Type) uint32 {
+ // See Identical for rationale.
+ switch t := t.(type) {
+ case *types.Basic:
+ return uint32(t.Kind())
+
+ case *types.Array:
+ return 9043 + 2*uint32(t.Len()) + 3*h.Hash(t.Elem())
+
+ case *types.Slice:
+ return 9049 + 2*h.Hash(t.Elem())
+
+ case *types.Struct:
+ var hash uint32 = 9059
+ for i, n := 0, t.NumFields(); i < n; i++ {
+ f := t.Field(i)
+ if f.Anonymous() {
+ hash += 8861
+ }
+ hash += hashString(t.Tag(i))
+ hash += hashString(f.Name()) // (ignore f.Pkg)
+ hash += h.Hash(f.Type())
+ }
+ return hash
+
+ case *types.Pointer:
+ return 9067 + 2*h.Hash(t.Elem())
+
+ case *types.Signature:
+ var hash uint32 = 9091
+ if t.Variadic() {
+ hash *= 8863
+ }
+ return hash + 3*h.hashTuple(t.Params()) + 5*h.hashTuple(t.Results())
+
+ case *types.Interface:
+ var hash uint32 = 9103
+ for i, n := 0, t.NumMethods(); i < n; i++ {
+ // See go/types.identicalMethods for rationale.
+ // Method order is not significant.
+ // Ignore m.Pkg().
+ m := t.Method(i)
+ hash += 3*hashString(m.Name()) + 5*h.Hash(m.Type())
+ }
+ return hash
+
+ case *types.Map:
+ return 9109 + 2*h.Hash(t.Key()) + 3*h.Hash(t.Elem())
+
+ case *types.Chan:
+ return 9127 + 2*uint32(t.Dir()) + 3*h.Hash(t.Elem())
+
+ case *types.Named:
+ // Not safe with a copying GC; objects may move.
+ return uint32(reflect.ValueOf(t.Obj()).Pointer())
+
+ case *types.Tuple:
+ return h.hashTuple(t)
+ }
+ panic(t)
+}
+
+func (h Hasher) hashTuple(tuple *types.Tuple) uint32 {
+ // See go/types.identicalTypes for rationale.
+ n := tuple.Len()
+ var hash uint32 = 9137 + 2*uint32(n)
+ for i := 0; i < n; i++ {
+ hash += 3 * h.Hash(tuple.At(i).Type())
+ }
+ return hash
+}
diff --git a/go/types/typeutil/map_test.go b/go/types/typeutil/map_test.go
new file mode 100644
index 0000000..776b5e2
--- /dev/null
+++ b/go/types/typeutil/map_test.go
@@ -0,0 +1,174 @@
+// 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 typeutil_test
+
+// TODO(adonovan):
+// - test use of explicit hasher across two maps.
+// - test hashcodes are consistent with equals for a range of types
+// (e.g. all types generated by type-checking some body of real code).
+
+import (
+ "testing"
+
+ "golang.org/x/tools/go/types"
+ "golang.org/x/tools/go/types/typeutil"
+)
+
+var (
+ tStr = types.Typ[types.String] // string
+ tPStr1 = types.NewPointer(tStr) // *string
+ tPStr2 = types.NewPointer(tStr) // *string, again
+ tInt = types.Typ[types.Int] // int
+ tChanInt1 = types.NewChan(types.RecvOnly, tInt) // <-chan int
+ tChanInt2 = types.NewChan(types.RecvOnly, tInt) // <-chan int, again
+)
+
+func checkEqualButNotIdentical(t *testing.T, x, y types.Type, comment string) {
+ if !types.Identical(x, y) {
+ t.Errorf("%s: not equal: %s, %s", comment, x, y)
+ }
+ if x == y {
+ t.Errorf("%s: identical: %v, %v", comment, x, y)
+ }
+}
+
+func TestAxioms(t *testing.T) {
+ checkEqualButNotIdentical(t, tPStr1, tPStr2, "tPstr{1,2}")
+ checkEqualButNotIdentical(t, tChanInt1, tChanInt2, "tChanInt{1,2}")
+}
+
+func TestMap(t *testing.T) {
+ var tmap *typeutil.Map
+
+ // All methods but Set are safe on on (*T)(nil).
+ tmap.Len()
+ tmap.At(tPStr1)
+ tmap.Delete(tPStr1)
+ tmap.KeysString()
+ tmap.String()
+
+ tmap = new(typeutil.Map)
+
+ // Length of empty map.
+ if l := tmap.Len(); l != 0 {
+ t.Errorf("Len() on empty Map: got %d, want 0", l)
+ }
+ // At of missing key.
+ if v := tmap.At(tPStr1); v != nil {
+ t.Errorf("At() on empty Map: got %v, want nil", v)
+ }
+ // Deletion of missing key.
+ if tmap.Delete(tPStr1) {
+ t.Errorf("Delete() on empty Map: got true, want false")
+ }
+ // Set of new key.
+ if prev := tmap.Set(tPStr1, "*string"); prev != nil {
+ t.Errorf("Set() on empty Map returned non-nil previous value %s", prev)
+ }
+
+ // Now: {*string: "*string"}
+
+ // Length of non-empty map.
+ if l := tmap.Len(); l != 1 {
+ t.Errorf("Len(): got %d, want 1", l)
+ }
+ // At via insertion key.
+ if v := tmap.At(tPStr1); v != "*string" {
+ t.Errorf("At(): got %q, want \"*string\"", v)
+ }
+ // At via equal key.
+ if v := tmap.At(tPStr2); v != "*string" {
+ t.Errorf("At(): got %q, want \"*string\"", v)
+ }
+ // Iteration over sole entry.
+ tmap.Iterate(func(key types.Type, value interface{}) {
+ if key != tPStr1 {
+ t.Errorf("Iterate: key: got %s, want %s", key, tPStr1)
+ }
+ if want := "*string"; value != want {
+ t.Errorf("Iterate: value: got %s, want %s", value, want)
+ }
+ })
+
+ // Setion with key equal to present one.
+ if prev := tmap.Set(tPStr2, "*string again"); prev != "*string" {
+ t.Errorf("Set() previous value: got %s, want \"*string\"", prev)
+ }
+
+ // Setion of another association.
+ if prev := tmap.Set(tChanInt1, "<-chan int"); prev != nil {
+ t.Errorf("Set() previous value: got %s, want nil", prev)
+ }
+
+ // Now: {*string: "*string again", <-chan int: "<-chan int"}
+
+ want1 := "{*string: \"*string again\", <-chan int: \"<-chan int\"}"
+ want2 := "{<-chan int: \"<-chan int\", *string: \"*string again\"}"
+ if s := tmap.String(); s != want1 && s != want2 {
+ t.Errorf("String(): got %s, want %s", s, want1)
+ }
+
+ want1 = "{*string, <-chan int}"
+ want2 = "{<-chan int, *string}"
+ if s := tmap.KeysString(); s != want1 && s != want2 {
+ t.Errorf("KeysString(): got %s, want %s", s, want1)
+ }
+
+ // Keys().
+ I := types.Identical
+ switch k := tmap.Keys(); {
+ case I(k[0], tChanInt1) && I(k[1], tPStr1): // ok
+ case I(k[1], tChanInt1) && I(k[0], tPStr1): // ok
+ default:
+ t.Errorf("Keys(): got %v, want %s", k, want2)
+ }
+
+ if l := tmap.Len(); l != 2 {
+ t.Errorf("Len(): got %d, want 1", l)
+ }
+ // At via original key.
+ if v := tmap.At(tPStr1); v != "*string again" {
+ t.Errorf("At(): got %q, want \"*string again\"", v)
+ }
+ hamming := 1
+ tmap.Iterate(func(key types.Type, value interface{}) {
+ switch {
+ case I(key, tChanInt1):
+ hamming *= 2 // ok
+ case I(key, tPStr1):
+ hamming *= 3 // ok
+ }
+ })
+ if hamming != 6 {
+ t.Errorf("Iterate: hamming: got %d, want %d", hamming, 6)
+ }
+
+ if v := tmap.At(tChanInt2); v != "<-chan int" {
+ t.Errorf("At(): got %q, want \"<-chan int\"", v)
+ }
+ // Deletion with key equal to present one.
+ if !tmap.Delete(tChanInt2) {
+ t.Errorf("Delete() of existing key: got false, want true")
+ }
+
+ // Now: {*string: "*string again"}
+
+ if l := tmap.Len(); l != 1 {
+ t.Errorf("Len(): got %d, want 1", l)
+ }
+ // Deletion again.
+ if !tmap.Delete(tPStr2) {
+ t.Errorf("Delete() of existing key: got false, want true")
+ }
+
+ // Now: {}
+
+ if l := tmap.Len(); l != 0 {
+ t.Errorf("Len(): got %d, want %d", l, 0)
+ }
+ if s := tmap.String(); s != "{}" {
+ t.Errorf("Len(): got %q, want %q", s, "")
+ }
+}
diff --git a/go/types/typeutil/methodsetcache.go b/go/types/typeutil/methodsetcache.go
new file mode 100644
index 0000000..daad644
--- /dev/null
+++ b/go/types/typeutil/methodsetcache.go
@@ -0,0 +1,73 @@
+// 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 a cache of method sets.
+
+package typeutil
+
+import (
+ "sync"
+
+ "golang.org/x/tools/go/types"
+)
+
+// A MethodSetCache records the method set of each type T for which
+// MethodSet(T) is called so that repeat queries are fast.
+// The zero value is a ready-to-use cache instance.
+type MethodSetCache struct {
+ mu sync.Mutex
+ named map[*types.Named]struct{ value, pointer *types.MethodSet } // method sets for named N and *N
+ others map[types.Type]*types.MethodSet // all other types
+}
+
+// MethodSet returns the method set of type T. It is thread-safe.
+//
+// If cache is nil, this function is equivalent to types.NewMethodSet(T).
+// Utility functions can thus expose an optional *MethodSetCache
+// parameter to clients that care about performance.
+//
+func (cache *MethodSetCache) MethodSet(T types.Type) *types.MethodSet {
+ if cache == nil {
+ return types.NewMethodSet(T)
+ }
+ cache.mu.Lock()
+ defer cache.mu.Unlock()
+
+ switch T := T.(type) {
+ case *types.Named:
+ return cache.lookupNamed(T).value
+
+ case *types.Pointer:
+ if N, ok := T.Elem().(*types.Named); ok {
+ return cache.lookupNamed(N).pointer
+ }
+ }
+
+ // all other types
+ // (The map uses pointer equivalence, not type identity.)
+ mset := cache.others[T]
+ if mset == nil {
+ mset = types.NewMethodSet(T)
+ if cache.others == nil {
+ cache.others = make(map[types.Type]*types.MethodSet)
+ }
+ cache.others[T] = mset
+ }
+ return mset
+}
+
+func (cache *MethodSetCache) lookupNamed(named *types.Named) struct{ value, pointer *types.MethodSet } {
+ if cache.named == nil {
+ cache.named = make(map[*types.Named]struct{ value, pointer *types.MethodSet })
+ }
+ // Avoid recomputing mset(*T) for each distinct Pointer
+ // instance whose underlying type is a named type.
+ msets, ok := cache.named[named]
+ if !ok {
+ msets.value = types.NewMethodSet(named)
+ msets.pointer = types.NewMethodSet(types.NewPointer(named))
+ cache.named[named] = msets
+ }
+ return msets
+}
diff --git a/go/types/typeutil/ui.go b/go/types/typeutil/ui.go
new file mode 100644
index 0000000..20c5249
--- /dev/null
+++ b/go/types/typeutil/ui.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.
+
+package typeutil
+
+// This file defines utilities for user interfaces that display types.
+
+import "golang.org/x/tools/go/types"
+
+// IntuitiveMethodSet returns the intuitive method set of a type, T.
+//
+// The result contains MethodSet(T) and additionally, if T is a
+// concrete type, methods belonging to *T if there is no identically
+// named method on T itself. This corresponds to user intuition about
+// method sets; this function is intended only for user interfaces.
+//
+// The order of the result is as for types.MethodSet(T).
+//
+func IntuitiveMethodSet(T types.Type, msets *MethodSetCache) []*types.Selection {
+ var result []*types.Selection
+ mset := msets.MethodSet(T)
+ if _, ok := T.Underlying().(*types.Interface); ok {
+ for i, n := 0, mset.Len(); i < n; i++ {
+ result = append(result, mset.At(i))
+ }
+ } else {
+ pmset := msets.MethodSet(types.NewPointer(T))
+ for i, n := 0, pmset.Len(); i < n; i++ {
+ meth := pmset.At(i)
+ if m := mset.Lookup(meth.Obj().Pkg(), meth.Obj().Name()); m != nil {
+ meth = m
+ }
+ result = append(result, meth)
+ }
+ }
+ return result
+}
diff --git a/go/types/typexpr.go b/go/types/typexpr.go
new file mode 100644
index 0000000..bd2d7ba
--- /dev/null
+++ b/go/types/typexpr.go
@@ -0,0 +1,713 @@
+// 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 type-checking of identifiers and type expressions.
+
+package types
+
+import (
+ "go/ast"
+ "go/token"
+ "sort"
+ "strconv"
+
+ "golang.org/x/tools/go/exact"
+)
+
+// ident type-checks identifier e and initializes x with the value or type of e.
+// If an error occurred, x.mode is set to invalid.
+// For the meaning of def and path, see check.typ, below.
+//
+func (check *Checker) ident(x *operand, e *ast.Ident, def *Named, path []*TypeName) {
+ x.mode = invalid
+ x.expr = e
+
+ scope, obj := check.scope.LookupParent(e.Name, check.pos)
+ if obj == nil {
+ if e.Name == "_" {
+ check.errorf(e.Pos(), "cannot use _ as value or type")
+ } else {
+ check.errorf(e.Pos(), "undeclared name: %s", e.Name)
+ }
+ return
+ }
+ check.recordUse(e, obj)
+
+ check.objDecl(obj, def, path)
+ typ := obj.Type()
+ assert(typ != nil)
+
+ // The object may be dot-imported: If so, remove its package from
+ // the map of unused dot imports for the respective file scope.
+ // (This code is only needed for dot-imports. Without them,
+ // we only have to mark variables, see *Var case below).
+ if pkg := obj.Pkg(); pkg != check.pkg && pkg != nil {
+ delete(check.unusedDotImports[scope], pkg)
+ }
+
+ switch obj := obj.(type) {
+ case *PkgName:
+ check.errorf(e.Pos(), "use of package %s not in selector", obj.name)
+ return
+
+ case *Const:
+ check.addDeclDep(obj)
+ if typ == Typ[Invalid] {
+ return
+ }
+ if obj == universeIota {
+ if check.iota == nil {
+ check.errorf(e.Pos(), "cannot use iota outside constant declaration")
+ return
+ }
+ x.val = check.iota
+ } else {
+ x.val = obj.val
+ }
+ assert(x.val != nil)
+ x.mode = constant
+
+ case *TypeName:
+ x.mode = typexpr
+ // check for cycle
+ // (it's ok to iterate forward because each named type appears at most once in path)
+ for i, prev := range path {
+ if prev == obj {
+ check.errorf(obj.pos, "illegal cycle in declaration of %s", obj.name)
+ // print cycle
+ for _, obj := range path[i:] {
+ check.errorf(obj.Pos(), "\t%s refers to", obj.Name()) // secondary error, \t indented
+ }
+ check.errorf(obj.Pos(), "\t%s", obj.Name())
+ // maintain x.mode == typexpr despite error
+ typ = Typ[Invalid]
+ break
+ }
+ }
+
+ case *Var:
+ if obj.pkg == check.pkg {
+ obj.used = true
+ }
+ check.addDeclDep(obj)
+ if typ == Typ[Invalid] {
+ return
+ }
+ x.mode = variable
+
+ case *Func:
+ check.addDeclDep(obj)
+ x.mode = value
+
+ case *Builtin:
+ x.id = obj.id
+ x.mode = builtin
+
+ case *Nil:
+ x.mode = value
+
+ default:
+ unreachable()
+ }
+
+ x.typ = typ
+}
+
+// typExpr type-checks the type expression e and returns its type, or Typ[Invalid].
+// If def != nil, e is the type specification for the named type def, declared
+// in a type declaration, and def.underlying will be set to the type of e before
+// any components of e are type-checked. Path contains the path of named types
+// referring to this type.
+//
+func (check *Checker) typExpr(e ast.Expr, def *Named, path []*TypeName) (T Type) {
+ if trace {
+ check.trace(e.Pos(), "%s", e)
+ check.indent++
+ defer func() {
+ check.indent--
+ check.trace(e.Pos(), "=> %s", T)
+ }()
+ }
+
+ T = check.typExprInternal(e, def, path)
+ assert(isTyped(T))
+ check.recordTypeAndValue(e, typexpr, T, nil)
+
+ return
+}
+
+func (check *Checker) typ(e ast.Expr) Type {
+ return check.typExpr(e, nil, nil)
+}
+
+// funcType type-checks a function or method type.
+func (check *Checker) funcType(sig *Signature, recvPar *ast.FieldList, ftyp *ast.FuncType) {
+ scope := NewScope(check.scope, token.NoPos, token.NoPos, "function")
+ check.recordScope(ftyp, scope)
+
+ recvList, _ := check.collectParams(scope, recvPar, false)
+ params, variadic := check.collectParams(scope, ftyp.Params, true)
+ results, _ := check.collectParams(scope, ftyp.Results, false)
+
+ if recvPar != nil {
+ // recv parameter list present (may be empty)
+ // spec: "The receiver is specified via an extra parameter section preceeding the
+ // method name. That parameter section must declare a single parameter, the receiver."
+ var recv *Var
+ switch len(recvList) {
+ case 0:
+ check.error(recvPar.Pos(), "method is missing receiver")
+ recv = NewParam(0, nil, "", Typ[Invalid]) // ignore recv below
+ default:
+ // more than one receiver
+ check.error(recvList[len(recvList)-1].Pos(), "method must have exactly one receiver")
+ fallthrough // continue with first receiver
+ case 1:
+ recv = recvList[0]
+ }
+ // spec: "The receiver type must be of the form T or *T where T is a type name."
+ // (ignore invalid types - error was reported before)
+ if t, _ := deref(recv.typ); t != Typ[Invalid] {
+ var err string
+ if T, _ := t.(*Named); T != nil {
+ // spec: "The type denoted by T is called the receiver base type; it must not
+ // be a pointer or interface type and it must be declared in the same package
+ // as the method."
+ if T.obj.pkg != check.pkg {
+ err = "type not defined in this package"
+ } else {
+ // TODO(gri) This is not correct if the underlying type is unknown yet.
+ switch u := T.underlying.(type) {
+ case *Basic:
+ // unsafe.Pointer is treated like a regular pointer
+ if u.kind == UnsafePointer {
+ err = "unsafe.Pointer"
+ }
+ case *Pointer, *Interface:
+ err = "pointer or interface type"
+ }
+ }
+ } else {
+ err = "basic or unnamed type"
+ }
+ if err != "" {
+ check.errorf(recv.pos, "invalid receiver %s (%s)", recv.typ, err)
+ // ok to continue
+ }
+ }
+ sig.recv = recv
+ }
+
+ sig.scope = scope
+ sig.params = NewTuple(params...)
+ sig.results = NewTuple(results...)
+ sig.variadic = variadic
+}
+
+// typExprInternal drives type checking of types.
+// Must only be called by typExpr.
+//
+func (check *Checker) typExprInternal(e ast.Expr, def *Named, path []*TypeName) Type {
+ switch e := e.(type) {
+ case *ast.BadExpr:
+ // ignore - error reported before
+
+ case *ast.Ident:
+ var x operand
+ check.ident(&x, e, def, path)
+
+ switch x.mode {
+ case typexpr:
+ typ := x.typ
+ def.setUnderlying(typ)
+ return typ
+ case invalid:
+ // ignore - error reported before
+ case novalue:
+ check.errorf(x.pos(), "%s used as type", &x)
+ default:
+ check.errorf(x.pos(), "%s is not a type", &x)
+ }
+
+ case *ast.SelectorExpr:
+ var x operand
+ check.selector(&x, e)
+
+ switch x.mode {
+ case typexpr:
+ typ := x.typ
+ def.setUnderlying(typ)
+ return typ
+ case invalid:
+ // ignore - error reported before
+ case novalue:
+ check.errorf(x.pos(), "%s used as type", &x)
+ default:
+ check.errorf(x.pos(), "%s is not a type", &x)
+ }
+
+ case *ast.ParenExpr:
+ return check.typExpr(e.X, def, path)
+
+ case *ast.ArrayType:
+ if e.Len != nil {
+ typ := new(Array)
+ def.setUnderlying(typ)
+ typ.len = check.arrayLength(e.Len)
+ typ.elem = check.typExpr(e.Elt, nil, path)
+ return typ
+
+ } else {
+ typ := new(Slice)
+ def.setUnderlying(typ)
+ typ.elem = check.typ(e.Elt)
+ return typ
+ }
+
+ case *ast.StructType:
+ typ := new(Struct)
+ def.setUnderlying(typ)
+ check.structType(typ, e, path)
+ return typ
+
+ case *ast.StarExpr:
+ typ := new(Pointer)
+ def.setUnderlying(typ)
+ typ.base = check.typ(e.X)
+ return typ
+
+ case *ast.FuncType:
+ typ := new(Signature)
+ def.setUnderlying(typ)
+ check.funcType(typ, nil, e)
+ return typ
+
+ case *ast.InterfaceType:
+ typ := new(Interface)
+ def.setUnderlying(typ)
+ check.interfaceType(typ, e, def, path)
+ return typ
+
+ case *ast.MapType:
+ typ := new(Map)
+ def.setUnderlying(typ)
+
+ typ.key = check.typ(e.Key)
+ typ.elem = check.typ(e.Value)
+
+ // spec: "The comparison operators == and != must be fully defined
+ // for operands of the key type; thus the key type must not be a
+ // function, map, or slice."
+ //
+ // Delay this check because it requires fully setup types;
+ // it is safe to continue in any case (was issue 6667).
+ check.delay(func() {
+ if !Comparable(typ.key) {
+ check.errorf(e.Key.Pos(), "invalid map key type %s", typ.key)
+ }
+ })
+
+ return typ
+
+ case *ast.ChanType:
+ typ := new(Chan)
+ def.setUnderlying(typ)
+
+ dir := SendRecv
+ switch e.Dir {
+ case ast.SEND | ast.RECV:
+ // nothing to do
+ case ast.SEND:
+ dir = SendOnly
+ case ast.RECV:
+ dir = RecvOnly
+ default:
+ check.invalidAST(e.Pos(), "unknown channel direction %d", e.Dir)
+ // ok to continue
+ }
+
+ typ.dir = dir
+ typ.elem = check.typ(e.Value)
+ return typ
+
+ default:
+ check.errorf(e.Pos(), "%s is not a type", e)
+ }
+
+ typ := Typ[Invalid]
+ def.setUnderlying(typ)
+ return typ
+}
+
+// typeOrNil type-checks the type expression (or nil value) e
+// and returns the typ of e, or nil.
+// If e is neither a type nor nil, typOrNil returns Typ[Invalid].
+//
+func (check *Checker) typOrNil(e ast.Expr) Type {
+ var x operand
+ check.rawExpr(&x, e, nil)
+ switch x.mode {
+ case invalid:
+ // ignore - error reported before
+ case novalue:
+ check.errorf(x.pos(), "%s used as type", &x)
+ case typexpr:
+ return x.typ
+ case value:
+ if x.isNil() {
+ return nil
+ }
+ fallthrough
+ default:
+ check.errorf(x.pos(), "%s is not a type", &x)
+ }
+ return Typ[Invalid]
+}
+
+func (check *Checker) arrayLength(e ast.Expr) int64 {
+ var x operand
+ check.expr(&x, e)
+ if x.mode != constant {
+ if x.mode != invalid {
+ check.errorf(x.pos(), "array length %s must be constant", &x)
+ }
+ return 0
+ }
+ if !x.isInteger() {
+ check.errorf(x.pos(), "array length %s must be integer", &x)
+ return 0
+ }
+ n, ok := exact.Int64Val(x.val)
+ if !ok || n < 0 {
+ check.errorf(x.pos(), "invalid array length %s", &x)
+ return 0
+ }
+ return n
+}
+
+func (check *Checker) collectParams(scope *Scope, list *ast.FieldList, variadicOk bool) (params []*Var, variadic bool) {
+ if list == nil {
+ return
+ }
+
+ var named, anonymous bool
+ for i, field := range list.List {
+ ftype := field.Type
+ if t, _ := ftype.(*ast.Ellipsis); t != nil {
+ ftype = t.Elt
+ if variadicOk && i == len(list.List)-1 {
+ variadic = true
+ } else {
+ check.invalidAST(field.Pos(), "... not permitted")
+ // ignore ... and continue
+ }
+ }
+ typ := check.typ(ftype)
+ // The parser ensures that f.Tag is nil and we don't
+ // care if a constructed AST contains a non-nil tag.
+ if len(field.Names) > 0 {
+ // named parameter
+ for _, name := range field.Names {
+ if name.Name == "" {
+ check.invalidAST(name.Pos(), "anonymous parameter")
+ // ok to continue
+ }
+ par := NewParam(name.Pos(), check.pkg, name.Name, typ)
+ check.declare(scope, name, par, scope.pos)
+ params = append(params, par)
+ }
+ named = true
+ } else {
+ // anonymous parameter
+ par := NewParam(ftype.Pos(), check.pkg, "", typ)
+ check.recordImplicit(field, par)
+ params = append(params, par)
+ anonymous = true
+ }
+ }
+
+ if named && anonymous {
+ check.invalidAST(list.Pos(), "list contains both named and anonymous parameters")
+ // ok to continue
+ }
+
+ // For a variadic function, change the last parameter's type from T to []T.
+ if variadic && len(params) > 0 {
+ last := params[len(params)-1]
+ last.typ = &Slice{elem: last.typ}
+ }
+
+ return
+}
+
+func (check *Checker) declareInSet(oset *objset, pos token.Pos, obj Object) bool {
+ if alt := oset.insert(obj); alt != nil {
+ check.errorf(pos, "%s redeclared", obj.Name())
+ check.reportAltDecl(alt)
+ return false
+ }
+ return true
+}
+
+func (check *Checker) interfaceType(iface *Interface, ityp *ast.InterfaceType, def *Named, path []*TypeName) {
+ // empty interface: common case
+ if ityp.Methods == nil {
+ return
+ }
+
+ // The parser ensures that field tags are nil and we don't
+ // care if a constructed AST contains non-nil tags.
+
+ // use named receiver type if available (for better error messages)
+ var recvTyp Type = iface
+ if def != nil {
+ recvTyp = def
+ }
+
+ // Phase 1: Collect explicitly declared methods, the corresponding
+ // signature (AST) expressions, and the list of embedded
+ // type (AST) expressions. Do not resolve signatures or
+ // embedded types yet to avoid cycles referring to this
+ // interface.
+
+ var (
+ mset objset
+ signatures []ast.Expr // list of corresponding method signatures
+ embedded []ast.Expr // list of embedded types
+ )
+ for _, f := range ityp.Methods.List {
+ if len(f.Names) > 0 {
+ // The parser ensures that there's only one method
+ // and we don't care if a constructed AST has more.
+ name := f.Names[0]
+ pos := name.Pos()
+ // spec: "As with all method sets, in an interface type,
+ // each method must have a unique non-blank name."
+ if name.Name == "_" {
+ check.errorf(pos, "invalid method name _")
+ continue
+ }
+ // Don't type-check signature yet - use an
+ // empty signature now and update it later.
+ // Since we know the receiver, set it up now
+ // (required to avoid crash in ptrRecv; see
+ // e.g. test case for issue 6638).
+ // TODO(gri) Consider marking methods signatures
+ // as incomplete, for better error messages. See
+ // also the T4 and T5 tests in testdata/cycles2.src.
+ sig := new(Signature)
+ sig.recv = NewVar(pos, check.pkg, "", recvTyp)
+ m := NewFunc(pos, check.pkg, name.Name, sig)
+ if check.declareInSet(&mset, pos, m) {
+ iface.methods = append(iface.methods, m)
+ iface.allMethods = append(iface.allMethods, m)
+ signatures = append(signatures, f.Type)
+ check.recordDef(name, m)
+ }
+ } else {
+ // embedded type
+ embedded = append(embedded, f.Type)
+ }
+ }
+
+ // Phase 2: Resolve embedded interfaces. Because an interface must not
+ // embed itself (directly or indirectly), each embedded interface
+ // can be fully resolved without depending on any method of this
+ // interface (if there is a cycle or another error, the embedded
+ // type resolves to an invalid type and is ignored).
+ // In particular, the list of methods for each embedded interface
+ // must be complete (it cannot depend on this interface), and so
+ // those methods can be added to the list of all methods of this
+ // interface.
+
+ for _, e := range embedded {
+ pos := e.Pos()
+ typ := check.typExpr(e, nil, path)
+ // Determine underlying embedded (possibly incomplete) type
+ // by following its forward chain.
+ named, _ := typ.(*Named)
+ under := underlying(named)
+ embed, _ := under.(*Interface)
+ if embed == nil {
+ if typ != Typ[Invalid] {
+ check.errorf(pos, "%s is not an interface", typ)
+ }
+ continue
+ }
+ iface.embeddeds = append(iface.embeddeds, named)
+ // collect embedded methods
+ for _, m := range embed.allMethods {
+ if check.declareInSet(&mset, pos, m) {
+ iface.allMethods = append(iface.allMethods, m)
+ }
+ }
+ }
+
+ // Phase 3: At this point all methods have been collected for this interface.
+ // It is now safe to type-check the signatures of all explicitly
+ // declared methods, even if they refer to this interface via a cycle
+ // and embed the methods of this interface in a parameter of interface
+ // type.
+
+ for i, m := range iface.methods {
+ expr := signatures[i]
+ typ := check.typ(expr)
+ sig, _ := typ.(*Signature)
+ if sig == nil {
+ if typ != Typ[Invalid] {
+ check.invalidAST(expr.Pos(), "%s is not a method signature", typ)
+ }
+ continue // keep method with empty method signature
+ }
+ // update signature, but keep recv that was set up before
+ old := m.typ.(*Signature)
+ sig.recv = old.recv
+ *old = *sig // update signature (don't replace it!)
+ }
+
+ // TODO(gri) The list of explicit methods is only sorted for now to
+ // produce the same Interface as NewInterface. We may be able to
+ // claim source order in the future. Revisit.
+ sort.Sort(byUniqueMethodName(iface.methods))
+
+ // TODO(gri) The list of embedded types is only sorted for now to
+ // produce the same Interface as NewInterface. We may be able to
+ // claim source order in the future. Revisit.
+ sort.Sort(byUniqueTypeName(iface.embeddeds))
+
+ sort.Sort(byUniqueMethodName(iface.allMethods))
+}
+
+// byUniqueTypeName named type lists can be sorted by their unique type names.
+type byUniqueTypeName []*Named
+
+func (a byUniqueTypeName) Len() int { return len(a) }
+func (a byUniqueTypeName) Less(i, j int) bool { return a[i].obj.Id() < a[j].obj.Id() }
+func (a byUniqueTypeName) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
+
+// byUniqueMethodName method lists can be sorted by their unique method names.
+type byUniqueMethodName []*Func
+
+func (a byUniqueMethodName) Len() int { return len(a) }
+func (a byUniqueMethodName) Less(i, j int) bool { return a[i].Id() < a[j].Id() }
+func (a byUniqueMethodName) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
+
+func (check *Checker) tag(t *ast.BasicLit) string {
+ if t != nil {
+ if t.Kind == token.STRING {
+ if val, err := strconv.Unquote(t.Value); err == nil {
+ return val
+ }
+ }
+ check.invalidAST(t.Pos(), "incorrect tag syntax: %q", t.Value)
+ }
+ return ""
+}
+
+func (check *Checker) structType(styp *Struct, e *ast.StructType, path []*TypeName) {
+ list := e.Fields
+ if list == nil {
+ return
+ }
+
+ // struct fields and tags
+ var fields []*Var
+ var tags []string
+
+ // for double-declaration checks
+ var fset objset
+
+ // current field typ and tag
+ var typ Type
+ var tag string
+ // anonymous != nil indicates an anonymous field.
+ add := func(field *ast.Field, ident *ast.Ident, anonymous *TypeName, pos token.Pos) {
+ if tag != "" && tags == nil {
+ tags = make([]string, len(fields))
+ }
+ if tags != nil {
+ tags = append(tags, tag)
+ }
+
+ name := ident.Name
+ fld := NewField(pos, check.pkg, name, typ, anonymous != nil)
+ // spec: "Within a struct, non-blank field names must be unique."
+ if name == "_" || check.declareInSet(&fset, pos, fld) {
+ fields = append(fields, fld)
+ check.recordDef(ident, fld)
+ }
+ if anonymous != nil {
+ check.recordUse(ident, anonymous)
+ }
+ }
+
+ for _, f := range list.List {
+ typ = check.typExpr(f.Type, nil, path)
+ tag = check.tag(f.Tag)
+ if len(f.Names) > 0 {
+ // named fields
+ for _, name := range f.Names {
+ add(f, name, nil, name.Pos())
+ }
+ } else {
+ // anonymous field
+ name := anonymousFieldIdent(f.Type)
+ pos := f.Type.Pos()
+ t, isPtr := deref(typ)
+ switch t := t.(type) {
+ case *Basic:
+ if t == Typ[Invalid] {
+ // error was reported before
+ continue
+ }
+ // unsafe.Pointer is treated like a regular pointer
+ if t.kind == UnsafePointer {
+ check.errorf(pos, "anonymous field type cannot be unsafe.Pointer")
+ continue
+ }
+ add(f, name, Universe.Lookup(t.name).(*TypeName), pos)
+
+ case *Named:
+ // spec: "An embedded type must be specified as a type name
+ // T or as a pointer to a non-interface type name *T, and T
+ // itself may not be a pointer type."
+ switch u := t.underlying.(type) {
+ case *Basic:
+ // unsafe.Pointer is treated like a regular pointer
+ if u.kind == UnsafePointer {
+ check.errorf(pos, "anonymous field type cannot be unsafe.Pointer")
+ continue
+ }
+ case *Pointer:
+ check.errorf(pos, "anonymous field type cannot be a pointer")
+ continue
+ case *Interface:
+ if isPtr {
+ check.errorf(pos, "anonymous field type cannot be a pointer to an interface")
+ continue
+ }
+ }
+ add(f, name, t.obj, pos)
+
+ default:
+ check.invalidAST(pos, "anonymous field type %s must be named", typ)
+ }
+ }
+ }
+
+ styp.fields = fields
+ styp.tags = tags
+}
+
+func anonymousFieldIdent(e ast.Expr) *ast.Ident {
+ switch e := e.(type) {
+ case *ast.Ident:
+ return e
+ case *ast.StarExpr:
+ return anonymousFieldIdent(e.X)
+ case *ast.SelectorExpr:
+ return e.Sel
+ }
+ return nil // invalid anonymous field
+}
diff --git a/go/types/universe.go b/go/types/universe.go
new file mode 100644
index 0000000..12a34ef
--- /dev/null
+++ b/go/types/universe.go
@@ -0,0 +1,224 @@
+// 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 file sets up the universe scope and the unsafe package.
+
+package types
+
+import (
+ "go/token"
+ "strings"
+
+ "golang.org/x/tools/go/exact"
+)
+
+var (
+ Universe *Scope
+ Unsafe *Package
+ universeIota *Const
+ universeByte *Basic // uint8 alias, but has name "byte"
+ universeRune *Basic // int32 alias, but has name "rune"
+)
+
+var Typ = []*Basic{
+ Invalid: {Invalid, 0, "invalid type"},
+
+ Bool: {Bool, IsBoolean, "bool"},
+ Int: {Int, IsInteger, "int"},
+ Int8: {Int8, IsInteger, "int8"},
+ Int16: {Int16, IsInteger, "int16"},
+ Int32: {Int32, IsInteger, "int32"},
+ Int64: {Int64, IsInteger, "int64"},
+ Uint: {Uint, IsInteger | IsUnsigned, "uint"},
+ Uint8: {Uint8, IsInteger | IsUnsigned, "uint8"},
+ Uint16: {Uint16, IsInteger | IsUnsigned, "uint16"},
+ Uint32: {Uint32, IsInteger | IsUnsigned, "uint32"},
+ Uint64: {Uint64, IsInteger | IsUnsigned, "uint64"},
+ Uintptr: {Uintptr, IsInteger | IsUnsigned, "uintptr"},
+ Float32: {Float32, IsFloat, "float32"},
+ Float64: {Float64, IsFloat, "float64"},
+ Complex64: {Complex64, IsComplex, "complex64"},
+ Complex128: {Complex128, IsComplex, "complex128"},
+ String: {String, IsString, "string"},
+ UnsafePointer: {UnsafePointer, 0, "Pointer"},
+
+ UntypedBool: {UntypedBool, IsBoolean | IsUntyped, "untyped bool"},
+ UntypedInt: {UntypedInt, IsInteger | IsUntyped, "untyped int"},
+ UntypedRune: {UntypedRune, IsInteger | IsUntyped, "untyped rune"},
+ UntypedFloat: {UntypedFloat, IsFloat | IsUntyped, "untyped float"},
+ UntypedComplex: {UntypedComplex, IsComplex | IsUntyped, "untyped complex"},
+ UntypedString: {UntypedString, IsString | IsUntyped, "untyped string"},
+ UntypedNil: {UntypedNil, IsUntyped, "untyped nil"},
+}
+
+var aliases = [...]*Basic{
+ {Byte, IsInteger | IsUnsigned, "byte"},
+ {Rune, IsInteger, "rune"},
+}
+
+func defPredeclaredTypes() {
+ for _, t := range Typ {
+ def(NewTypeName(token.NoPos, nil, t.name, t))
+ }
+ for _, t := range aliases {
+ def(NewTypeName(token.NoPos, nil, t.name, t))
+ }
+
+ // Error has a nil package in its qualified name since it is in no package
+ res := NewVar(token.NoPos, nil, "", Typ[String])
+ sig := &Signature{results: NewTuple(res)}
+ err := NewFunc(token.NoPos, nil, "Error", sig)
+ typ := &Named{underlying: NewInterface([]*Func{err}, nil).Complete()}
+ sig.recv = NewVar(token.NoPos, nil, "", typ)
+ def(NewTypeName(token.NoPos, nil, "error", typ))
+}
+
+var predeclaredConsts = [...]struct {
+ name string
+ kind BasicKind
+ val exact.Value
+}{
+ {"true", UntypedBool, exact.MakeBool(true)},
+ {"false", UntypedBool, exact.MakeBool(false)},
+ {"iota", UntypedInt, exact.MakeInt64(0)},
+}
+
+func defPredeclaredConsts() {
+ for _, c := range predeclaredConsts {
+ def(NewConst(token.NoPos, nil, c.name, Typ[c.kind], c.val))
+ }
+}
+
+func defPredeclaredNil() {
+ def(&Nil{object{name: "nil", typ: Typ[UntypedNil]}})
+}
+
+// A builtinId is the id of a builtin function.
+type builtinId int
+
+const (
+ // universe scope
+ _Append builtinId = iota
+ _Cap
+ _Close
+ _Complex
+ _Copy
+ _Delete
+ _Imag
+ _Len
+ _Make
+ _New
+ _Panic
+ _Print
+ _Println
+ _Real
+ _Recover
+
+ // package unsafe
+ _Alignof
+ _Offsetof
+ _Sizeof
+
+ // testing support
+ _Assert
+ _Trace
+)
+
+var predeclaredFuncs = [...]struct {
+ name string
+ nargs int
+ variadic bool
+ kind exprKind
+}{
+ _Append: {"append", 1, true, expression},
+ _Cap: {"cap", 1, false, expression},
+ _Close: {"close", 1, false, statement},
+ _Complex: {"complex", 2, false, expression},
+ _Copy: {"copy", 2, false, statement},
+ _Delete: {"delete", 2, false, statement},
+ _Imag: {"imag", 1, false, expression},
+ _Len: {"len", 1, false, expression},
+ _Make: {"make", 1, true, expression},
+ _New: {"new", 1, false, expression},
+ _Panic: {"panic", 1, false, statement},
+ _Print: {"print", 0, true, statement},
+ _Println: {"println", 0, true, statement},
+ _Real: {"real", 1, false, expression},
+ _Recover: {"recover", 0, false, statement},
+
+ _Alignof: {"Alignof", 1, false, expression},
+ _Offsetof: {"Offsetof", 1, false, expression},
+ _Sizeof: {"Sizeof", 1, false, expression},
+
+ _Assert: {"assert", 1, false, statement},
+ _Trace: {"trace", 0, true, statement},
+}
+
+func defPredeclaredFuncs() {
+ for i := range predeclaredFuncs {
+ id := builtinId(i)
+ if id == _Assert || id == _Trace {
+ continue // only define these in testing environment
+ }
+ def(newBuiltin(id))
+ }
+}
+
+// DefPredeclaredTestFuncs defines the assert and trace built-ins.
+// These built-ins are intended for debugging and testing of this
+// package only.
+func DefPredeclaredTestFuncs() {
+ if Universe.Lookup("assert") != nil {
+ return // already defined
+ }
+ def(newBuiltin(_Assert))
+ def(newBuiltin(_Trace))
+}
+
+func init() {
+ Universe = NewScope(nil, token.NoPos, token.NoPos, "universe")
+ Unsafe = NewPackage("unsafe", "unsafe")
+ Unsafe.complete = true
+
+ defPredeclaredTypes()
+ defPredeclaredConsts()
+ defPredeclaredNil()
+ defPredeclaredFuncs()
+
+ universeIota = Universe.Lookup("iota").(*Const)
+ universeByte = Universe.Lookup("byte").(*TypeName).typ.(*Basic)
+ universeRune = Universe.Lookup("rune").(*TypeName).typ.(*Basic)
+}
+
+// Objects with names containing blanks are internal and not entered into
+// a scope. Objects with exported names are inserted in the unsafe package
+// scope; other objects are inserted in the universe scope.
+//
+func def(obj Object) {
+ name := obj.Name()
+ if strings.Index(name, " ") >= 0 {
+ return // nothing to do
+ }
+ // fix Obj link for named types
+ if typ, ok := obj.Type().(*Named); ok {
+ typ.obj = obj.(*TypeName)
+ }
+ // exported identifiers go into package unsafe
+ scope := Universe
+ if obj.Exported() {
+ scope = Unsafe.scope
+ // set Pkg field
+ switch obj := obj.(type) {
+ case *TypeName:
+ obj.pkg = Unsafe
+ case *Builtin:
+ obj.pkg = Unsafe
+ default:
+ unreachable()
+ }
+ }
+ if scope.Insert(obj) != nil {
+ panic("internal error: double declaration")
+ }
+}
diff --git a/go/vcs/discovery.go b/go/vcs/discovery.go
new file mode 100644
index 0000000..c4b0e3d
--- /dev/null
+++ b/go/vcs/discovery.go
@@ -0,0 +1,76 @@
+// 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 vcs
+
+import (
+ "encoding/xml"
+ "fmt"
+ "io"
+ "strings"
+)
+
+// charsetReader returns a reader for the given charset. Currently
+// it only supports UTF-8 and ASCII. Otherwise, it returns a meaningful
+// error which is printed by go get, so the user can find why the package
+// wasn't downloaded if the encoding is not supported. Note that, in
+// order to reduce potential errors, ASCII is treated as UTF-8 (i.e. characters
+// greater than 0x7f are not rejected).
+func charsetReader(charset string, input io.Reader) (io.Reader, error) {
+ switch strings.ToLower(charset) {
+ case "ascii":
+ return input, nil
+ default:
+ return nil, fmt.Errorf("can't decode XML document using charset %q", charset)
+ }
+}
+
+// parseMetaGoImports returns meta imports from the HTML in r.
+// Parsing ends at the end of the <head> section or the beginning of the <body>.
+func parseMetaGoImports(r io.Reader) (imports []metaImport, err error) {
+ d := xml.NewDecoder(r)
+ d.CharsetReader = charsetReader
+ d.Strict = false
+ var t xml.Token
+ for {
+ t, err = d.Token()
+ if err != nil {
+ if err == io.EOF {
+ err = nil
+ }
+ return
+ }
+ if e, ok := t.(xml.StartElement); ok && strings.EqualFold(e.Name.Local, "body") {
+ return
+ }
+ if e, ok := t.(xml.EndElement); ok && strings.EqualFold(e.Name.Local, "head") {
+ return
+ }
+ e, ok := t.(xml.StartElement)
+ if !ok || !strings.EqualFold(e.Name.Local, "meta") {
+ continue
+ }
+ if attrValue(e.Attr, "name") != "go-import" {
+ continue
+ }
+ if f := strings.Fields(attrValue(e.Attr, "content")); len(f) == 3 {
+ imports = append(imports, metaImport{
+ Prefix: f[0],
+ VCS: f[1],
+ RepoRoot: f[2],
+ })
+ }
+ }
+}
+
+// attrValue returns the attribute value for the case-insensitive key
+// `name', or the empty string if nothing is found.
+func attrValue(attrs []xml.Attr, name string) string {
+ for _, a := range attrs {
+ if strings.EqualFold(a.Name.Local, name) {
+ return a.Value
+ }
+ }
+ return ""
+}
diff --git a/go/vcs/env.go b/go/vcs/env.go
new file mode 100644
index 0000000..e846f5b
--- /dev/null
+++ b/go/vcs/env.go
@@ -0,0 +1,39 @@
+// 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 vcs
+
+import (
+ "os"
+ "strings"
+)
+
+// envForDir returns a copy of the environment
+// suitable for running in the given directory.
+// The environment is the current process's environment
+// but with an updated $PWD, so that an os.Getwd in the
+// child will be faster.
+func envForDir(dir string) []string {
+ env := os.Environ()
+ // Internally we only use rooted paths, so dir is rooted.
+ // Even if dir is not rooted, no harm done.
+ return mergeEnvLists([]string{"PWD=" + dir}, env)
+}
+
+// mergeEnvLists merges the two environment lists such that
+// variables with the same name in "in" replace those in "out".
+func mergeEnvLists(in, out []string) []string {
+NextVar:
+ for _, inkv := range in {
+ k := strings.SplitAfterN(inkv, "=", 2)[0]
+ for i, outkv := range out {
+ if strings.HasPrefix(outkv, k) {
+ out[i] = inkv
+ continue NextVar
+ }
+ }
+ out = append(out, inkv)
+ }
+ return out
+}
diff --git a/go/vcs/http.go b/go/vcs/http.go
new file mode 100644
index 0000000..9618818
--- /dev/null
+++ b/go/vcs/http.go
@@ -0,0 +1,80 @@
+// 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 vcs
+
+import (
+ "fmt"
+ "io"
+ "io/ioutil"
+ "log"
+ "net/http"
+ "net/url"
+)
+
+// httpClient is the default HTTP client, but a variable so it can be
+// changed by tests, without modifying http.DefaultClient.
+var httpClient = http.DefaultClient
+
+// httpGET returns the data from an HTTP GET request for the given URL.
+func httpGET(url string) ([]byte, error) {
+ resp, err := httpClient.Get(url)
+ if err != nil {
+ return nil, err
+ }
+ defer resp.Body.Close()
+ if resp.StatusCode != 200 {
+ return nil, fmt.Errorf("%s: %s", url, resp.Status)
+ }
+ b, err := ioutil.ReadAll(resp.Body)
+ if err != nil {
+ return nil, fmt.Errorf("%s: %v", url, err)
+ }
+ return b, nil
+}
+
+// httpsOrHTTP returns the body of either the importPath's
+// https resource or, if unavailable, the http resource.
+func httpsOrHTTP(importPath string) (urlStr string, body io.ReadCloser, err error) {
+ fetch := func(scheme string) (urlStr string, res *http.Response, err error) {
+ u, err := url.Parse(scheme + "://" + importPath)
+ if err != nil {
+ return "", nil, err
+ }
+ u.RawQuery = "go-get=1"
+ urlStr = u.String()
+ if Verbose {
+ log.Printf("Fetching %s", urlStr)
+ }
+ res, err = httpClient.Get(urlStr)
+ return
+ }
+ closeBody := func(res *http.Response) {
+ if res != nil {
+ res.Body.Close()
+ }
+ }
+ urlStr, res, err := fetch("https")
+ if err != nil || res.StatusCode != 200 {
+ if Verbose {
+ if err != nil {
+ log.Printf("https fetch failed.")
+ } else {
+ log.Printf("ignoring https fetch with status code %d", res.StatusCode)
+ }
+ }
+ closeBody(res)
+ urlStr, res, err = fetch("http")
+ }
+ if err != nil {
+ closeBody(res)
+ return "", nil, err
+ }
+ // Note: accepting a non-200 OK here, so people can serve a
+ // meta import in their http 404 page.
+ if Verbose {
+ log.Printf("Parsing meta tags from %s (status code %d)", urlStr, res.StatusCode)
+ }
+ return urlStr, res.Body, nil
+}
diff --git a/go/vcs/vcs.go b/go/vcs/vcs.go
new file mode 100644
index 0000000..2d9b7de
--- /dev/null
+++ b/go/vcs/vcs.go
@@ -0,0 +1,754 @@
+// 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 vcs // import "golang.org/x/tools/go/vcs"
+
+import (
+ "bytes"
+ "encoding/json"
+ "errors"
+ "fmt"
+ "log"
+ "os"
+ "os/exec"
+ "path/filepath"
+ "regexp"
+ "strconv"
+ "strings"
+)
+
+// Verbose enables verbose operation logging.
+var Verbose bool
+
+// ShowCmd controls whether VCS commands are printed.
+var ShowCmd bool
+
+// A Cmd describes how to use a version control system
+// like Mercurial, Git, or Subversion.
+type Cmd struct {
+ Name string
+ Cmd string // name of binary to invoke command
+
+ CreateCmd string // command to download a fresh copy of a repository
+ DownloadCmd string // command to download updates into an existing repository
+
+ TagCmd []TagCmd // commands to list tags
+ TagLookupCmd []TagCmd // commands to lookup tags before running tagSyncCmd
+ TagSyncCmd string // command to sync to specific tag
+ TagSyncDefault string // command to sync to default tag
+
+ LogCmd string // command to list repository changelogs in an XML format
+
+ Scheme []string
+ PingCmd string
+}
+
+// A TagCmd describes a command to list available tags
+// that can be passed to Cmd.TagSyncCmd.
+type TagCmd struct {
+ Cmd string // command to list tags
+ Pattern string // regexp to extract tags from list
+}
+
+// vcsList lists the known version control systems
+var vcsList = []*Cmd{
+ vcsHg,
+ vcsGit,
+ vcsSvn,
+ vcsBzr,
+}
+
+// ByCmd returns the version control system for the given
+// command name (hg, git, svn, bzr).
+func ByCmd(cmd string) *Cmd {
+ for _, vcs := range vcsList {
+ if vcs.Cmd == cmd {
+ return vcs
+ }
+ }
+ return nil
+}
+
+// vcsHg describes how to use Mercurial.
+var vcsHg = &Cmd{
+ Name: "Mercurial",
+ Cmd: "hg",
+
+ CreateCmd: "clone -U {repo} {dir}",
+ DownloadCmd: "pull",
+
+ // We allow both tag and branch names as 'tags'
+ // for selecting a version. This lets people have
+ // a go.release.r60 branch and a go1 branch
+ // and make changes in both, without constantly
+ // editing .hgtags.
+ TagCmd: []TagCmd{
+ {"tags", `^(\S+)`},
+ {"branches", `^(\S+)`},
+ },
+ TagSyncCmd: "update -r {tag}",
+ TagSyncDefault: "update default",
+
+ LogCmd: "log --encoding=utf-8 --limit={limit} --template={template}",
+
+ Scheme: []string{"https", "http", "ssh"},
+ PingCmd: "identify {scheme}://{repo}",
+}
+
+// vcsGit describes how to use Git.
+var vcsGit = &Cmd{
+ Name: "Git",
+ Cmd: "git",
+
+ CreateCmd: "clone {repo} {dir}",
+ DownloadCmd: "pull --ff-only",
+
+ TagCmd: []TagCmd{
+ // tags/xxx matches a git tag named xxx
+ // origin/xxx matches a git branch named xxx on the default remote repository
+ {"show-ref", `(?:tags|origin)/(\S+)$`},
+ },
+ TagLookupCmd: []TagCmd{
+ {"show-ref tags/{tag} origin/{tag}", `((?:tags|origin)/\S+)$`},
+ },
+ TagSyncCmd: "checkout {tag}",
+ TagSyncDefault: "checkout master",
+
+ Scheme: []string{"git", "https", "http", "git+ssh"},
+ PingCmd: "ls-remote {scheme}://{repo}",
+}
+
+// vcsBzr describes how to use Bazaar.
+var vcsBzr = &Cmd{
+ Name: "Bazaar",
+ Cmd: "bzr",
+
+ CreateCmd: "branch {repo} {dir}",
+
+ // Without --overwrite bzr will not pull tags that changed.
+ // Replace by --overwrite-tags after http://pad.lv/681792 goes in.
+ DownloadCmd: "pull --overwrite",
+
+ TagCmd: []TagCmd{{"tags", `^(\S+)`}},
+ TagSyncCmd: "update -r {tag}",
+ TagSyncDefault: "update -r revno:-1",
+
+ Scheme: []string{"https", "http", "bzr", "bzr+ssh"},
+ PingCmd: "info {scheme}://{repo}",
+}
+
+// vcsSvn describes how to use Subversion.
+var vcsSvn = &Cmd{
+ Name: "Subversion",
+ Cmd: "svn",
+
+ CreateCmd: "checkout {repo} {dir}",
+ DownloadCmd: "update",
+
+ // There is no tag command in subversion.
+ // The branch information is all in the path names.
+
+ LogCmd: "log --xml --limit={limit}",
+
+ Scheme: []string{"https", "http", "svn", "svn+ssh"},
+ PingCmd: "info {scheme}://{repo}",
+}
+
+func (v *Cmd) String() string {
+ return v.Name
+}
+
+// run runs the command line cmd in the given directory.
+// keyval is a list of key, value pairs. run expands
+// instances of {key} in cmd into value, but only after
+// splitting cmd into individual arguments.
+// If an error occurs, run prints the command line and the
+// command's combined stdout+stderr to standard error.
+// Otherwise run discards the command's output.
+func (v *Cmd) run(dir string, cmd string, keyval ...string) error {
+ _, err := v.run1(dir, cmd, keyval, true)
+ return err
+}
+
+// runVerboseOnly is like run but only generates error output to standard error in verbose mode.
+func (v *Cmd) runVerboseOnly(dir string, cmd string, keyval ...string) error {
+ _, err := v.run1(dir, cmd, keyval, false)
+ return err
+}
+
+// runOutput is like run but returns the output of the command.
+func (v *Cmd) runOutput(dir string, cmd string, keyval ...string) ([]byte, error) {
+ return v.run1(dir, cmd, keyval, true)
+}
+
+// run1 is the generalized implementation of run and runOutput.
+func (v *Cmd) run1(dir string, cmdline string, keyval []string, verbose bool) ([]byte, error) {
+ m := make(map[string]string)
+ for i := 0; i < len(keyval); i += 2 {
+ m[keyval[i]] = keyval[i+1]
+ }
+ args := strings.Fields(cmdline)
+ for i, arg := range args {
+ args[i] = expand(m, arg)
+ }
+
+ _, err := exec.LookPath(v.Cmd)
+ if err != nil {
+ fmt.Fprintf(os.Stderr,
+ "go: missing %s command. See http://golang.org/s/gogetcmd\n",
+ v.Name)
+ return nil, err
+ }
+
+ cmd := exec.Command(v.Cmd, args...)
+ cmd.Dir = dir
+ cmd.Env = envForDir(cmd.Dir)
+ if ShowCmd {
+ fmt.Printf("cd %s\n", dir)
+ fmt.Printf("%s %s\n", v.Cmd, strings.Join(args, " "))
+ }
+ var buf bytes.Buffer
+ cmd.Stdout = &buf
+ cmd.Stderr = &buf
+ err = cmd.Run()
+ out := buf.Bytes()
+ if err != nil {
+ if verbose || Verbose {
+ fmt.Fprintf(os.Stderr, "# cd %s; %s %s\n", dir, v.Cmd, strings.Join(args, " "))
+ os.Stderr.Write(out)
+ }
+ return nil, err
+ }
+ return out, nil
+}
+
+// Ping pings the repo to determine if scheme used is valid.
+// This repo must be pingable with this scheme and VCS.
+func (v *Cmd) Ping(scheme, repo string) error {
+ return v.runVerboseOnly(".", v.PingCmd, "scheme", scheme, "repo", repo)
+}
+
+// Create creates a new copy of repo in dir.
+// The parent of dir must exist; dir must not.
+func (v *Cmd) Create(dir, repo string) error {
+ return v.run(".", v.CreateCmd, "dir", dir, "repo", repo)
+}
+
+// CreateAtRev creates a new copy of repo in dir at revision rev.
+// The parent of dir must exist; dir must not.
+// rev must be a valid revision in repo.
+func (v *Cmd) CreateAtRev(dir, repo, rev string) error {
+ if err := v.Create(dir, repo); err != nil {
+ return err
+ }
+ return v.run(dir, v.TagSyncCmd, "tag", rev)
+}
+
+// Download downloads any new changes for the repo in dir.
+// dir must be a valid VCS repo compatible with v.
+func (v *Cmd) Download(dir string) error {
+ return v.run(dir, v.DownloadCmd)
+}
+
+// Tags returns the list of available tags for the repo in dir.
+// dir must be a valid VCS repo compatible with v.
+func (v *Cmd) Tags(dir string) ([]string, error) {
+ var tags []string
+ for _, tc := range v.TagCmd {
+ out, err := v.runOutput(dir, tc.Cmd)
+ if err != nil {
+ return nil, err
+ }
+ re := regexp.MustCompile(`(?m-s)` + tc.Pattern)
+ for _, m := range re.FindAllStringSubmatch(string(out), -1) {
+ tags = append(tags, m[1])
+ }
+ }
+ return tags, nil
+}
+
+// TagSync syncs the repo in dir to the named tag,
+// which either is a tag returned by tags or is v.TagDefault.
+// dir must be a valid VCS repo compatible with v and the tag must exist.
+func (v *Cmd) TagSync(dir, tag string) error {
+ if v.TagSyncCmd == "" {
+ return nil
+ }
+ if tag != "" {
+ for _, tc := range v.TagLookupCmd {
+ out, err := v.runOutput(dir, tc.Cmd, "tag", tag)
+ if err != nil {
+ return err
+ }
+ re := regexp.MustCompile(`(?m-s)` + tc.Pattern)
+ m := re.FindStringSubmatch(string(out))
+ if len(m) > 1 {
+ tag = m[1]
+ break
+ }
+ }
+ }
+ if tag == "" && v.TagSyncDefault != "" {
+ return v.run(dir, v.TagSyncDefault)
+ }
+ return v.run(dir, v.TagSyncCmd, "tag", tag)
+}
+
+// Log logs the changes for the repo in dir.
+// dir must be a valid VCS repo compatible with v.
+func (v *Cmd) Log(dir, logTemplate string) ([]byte, error) {
+ if err := v.Download(dir); err != nil {
+ return []byte{}, err
+ }
+
+ const N = 50 // how many revisions to grab
+ return v.runOutput(dir, v.LogCmd, "limit", strconv.Itoa(N), "template", logTemplate)
+}
+
+// LogAtRev logs the change for repo in dir at the rev revision.
+// dir must be a valid VCS repo compatible with v.
+// rev must be a valid revision for the repo in dir.
+func (v *Cmd) LogAtRev(dir, rev, logTemplate string) ([]byte, error) {
+ if err := v.Download(dir); err != nil {
+ return []byte{}, err
+ }
+
+ // Append revision flag to LogCmd.
+ logAtRevCmd := v.LogCmd + " --rev=" + rev
+ return v.runOutput(dir, logAtRevCmd, "limit", strconv.Itoa(1), "template", logTemplate)
+}
+
+// A vcsPath describes how to convert an import path into a
+// version control system and repository name.
+type vcsPath struct {
+ prefix string // prefix this description applies to
+ re string // pattern for import path
+ repo string // repository to use (expand with match of re)
+ vcs string // version control system to use (expand with match of re)
+ check func(match map[string]string) error // additional checks
+ ping bool // ping for scheme to use to download repo
+
+ regexp *regexp.Regexp // cached compiled form of re
+}
+
+// FromDir inspects dir and its parents to determine the
+// version control system and code repository to use.
+// On return, root is the import path
+// corresponding to the root of the repository
+// (thus root is a prefix of importPath).
+func FromDir(dir, srcRoot string) (vcs *Cmd, root string, err error) {
+ // Clean and double-check that dir is in (a subdirectory of) srcRoot.
+ dir = filepath.Clean(dir)
+ srcRoot = filepath.Clean(srcRoot)
+ if len(dir) <= len(srcRoot) || dir[len(srcRoot)] != filepath.Separator {
+ return nil, "", fmt.Errorf("directory %q is outside source root %q", dir, srcRoot)
+ }
+
+ for len(dir) > len(srcRoot) {
+ for _, vcs := range vcsList {
+ if fi, err := os.Stat(filepath.Join(dir, "."+vcs.Cmd)); err == nil && fi.IsDir() {
+ return vcs, dir[len(srcRoot)+1:], nil
+ }
+ }
+
+ // Move to parent.
+ ndir := filepath.Dir(dir)
+ if len(ndir) >= len(dir) {
+ // Shouldn't happen, but just in case, stop.
+ break
+ }
+ dir = ndir
+ }
+
+ return nil, "", fmt.Errorf("directory %q is not using a known version control system", dir)
+}
+
+// RepoRoot represents a version control system, a repo, and a root of
+// where to put it on disk.
+type RepoRoot struct {
+ VCS *Cmd
+
+ // repo is the repository URL, including scheme
+ Repo string
+
+ // root is the import path corresponding to the root of the
+ // repository
+ Root string
+}
+
+// RepoRootForImportPath analyzes importPath to determine the
+// version control system, and code repository to use.
+func RepoRootForImportPath(importPath string, verbose bool) (*RepoRoot, error) {
+ rr, err := RepoRootForImportPathStatic(importPath, "")
+ if err == errUnknownSite {
+ rr, err = RepoRootForImportDynamic(importPath, verbose)
+
+ // RepoRootForImportDynamic returns error detail
+ // that is irrelevant if the user didn't intend to use a
+ // dynamic import in the first place.
+ // Squelch it.
+ if err != nil {
+ if Verbose {
+ log.Printf("import %q: %v", importPath, err)
+ }
+ err = fmt.Errorf("unrecognized import path %q", importPath)
+ }
+ }
+
+ if err == nil && strings.Contains(importPath, "...") && strings.Contains(rr.Root, "...") {
+ // Do not allow wildcards in the repo root.
+ rr = nil
+ err = fmt.Errorf("cannot expand ... in %q", importPath)
+ }
+ return rr, err
+}
+
+var errUnknownSite = errors.New("dynamic lookup required to find mapping")
+
+// RepoRootForImportPathStatic attempts to map importPath to a
+// RepoRoot using the commonly-used VCS hosting sites in vcsPaths
+// (github.com/user/dir), or from a fully-qualified importPath already
+// containing its VCS type (foo.com/repo.git/dir)
+//
+// If scheme is non-empty, that scheme is forced.
+func RepoRootForImportPathStatic(importPath, scheme string) (*RepoRoot, error) {
+ if strings.Contains(importPath, "://") {
+ return nil, fmt.Errorf("invalid import path %q", importPath)
+ }
+ for _, srv := range vcsPaths {
+ if !strings.HasPrefix(importPath, srv.prefix) {
+ continue
+ }
+ m := srv.regexp.FindStringSubmatch(importPath)
+ if m == nil {
+ if srv.prefix != "" {
+ return nil, fmt.Errorf("invalid %s import path %q", srv.prefix, importPath)
+ }
+ continue
+ }
+
+ // Build map of named subexpression matches for expand.
+ match := map[string]string{
+ "prefix": srv.prefix,
+ "import": importPath,
+ }
+ for i, name := range srv.regexp.SubexpNames() {
+ if name != "" && match[name] == "" {
+ match[name] = m[i]
+ }
+ }
+ if srv.vcs != "" {
+ match["vcs"] = expand(match, srv.vcs)
+ }
+ if srv.repo != "" {
+ match["repo"] = expand(match, srv.repo)
+ }
+ if srv.check != nil {
+ if err := srv.check(match); err != nil {
+ return nil, err
+ }
+ }
+ vcs := ByCmd(match["vcs"])
+ if vcs == nil {
+ return nil, fmt.Errorf("unknown version control system %q", match["vcs"])
+ }
+ if srv.ping {
+ if scheme != "" {
+ match["repo"] = scheme + "://" + match["repo"]
+ } else {
+ for _, scheme := range vcs.Scheme {
+ if vcs.Ping(scheme, match["repo"]) == nil {
+ match["repo"] = scheme + "://" + match["repo"]
+ break
+ }
+ }
+ }
+ }
+ rr := &RepoRoot{
+ VCS: vcs,
+ Repo: match["repo"],
+ Root: match["root"],
+ }
+ return rr, nil
+ }
+ return nil, errUnknownSite
+}
+
+// RepoRootForImportDynamic finds a *RepoRoot for a custom domain that's not
+// statically known by RepoRootForImportPathStatic.
+//
+// This handles "vanity import paths" like "name.tld/pkg/foo".
+func RepoRootForImportDynamic(importPath string, verbose bool) (*RepoRoot, error) {
+ slash := strings.Index(importPath, "/")
+ if slash < 0 {
+ return nil, errors.New("import path doesn't contain a slash")
+ }
+ host := importPath[:slash]
+ if !strings.Contains(host, ".") {
+ return nil, errors.New("import path doesn't contain a hostname")
+ }
+ urlStr, body, err := httpsOrHTTP(importPath)
+ if err != nil {
+ return nil, fmt.Errorf("http/https fetch: %v", err)
+ }
+ defer body.Close()
+ imports, err := parseMetaGoImports(body)
+ if err != nil {
+ return nil, fmt.Errorf("parsing %s: %v", importPath, err)
+ }
+ metaImport, err := matchGoImport(imports, importPath)
+ if err != nil {
+ if err != errNoMatch {
+ return nil, fmt.Errorf("parse %s: %v", urlStr, err)
+ }
+ return nil, fmt.Errorf("parse %s: no go-import meta tags", urlStr)
+ }
+ if verbose {
+ log.Printf("get %q: found meta tag %#v at %s", importPath, metaImport, urlStr)
+ }
+ // If the import was "uni.edu/bob/project", which said the
+ // prefix was "uni.edu" and the RepoRoot was "evilroot.com",
+ // make sure we don't trust Bob and check out evilroot.com to
+ // "uni.edu" yet (possibly overwriting/preempting another
+ // non-evil student). Instead, first verify the root and see
+ // if it matches Bob's claim.
+ if metaImport.Prefix != importPath {
+ if verbose {
+ log.Printf("get %q: verifying non-authoritative meta tag", importPath)
+ }
+ urlStr0 := urlStr
+ urlStr, body, err = httpsOrHTTP(metaImport.Prefix)
+ if err != nil {
+ return nil, fmt.Errorf("fetch %s: %v", urlStr, err)
+ }
+ imports, err := parseMetaGoImports(body)
+ if err != nil {
+ return nil, fmt.Errorf("parsing %s: %v", importPath, err)
+ }
+ if len(imports) == 0 {
+ return nil, fmt.Errorf("fetch %s: no go-import meta tag", urlStr)
+ }
+ metaImport2, err := matchGoImport(imports, importPath)
+ if err != nil || metaImport != metaImport2 {
+ return nil, fmt.Errorf("%s and %s disagree about go-import for %s", urlStr0, urlStr, metaImport.Prefix)
+ }
+ }
+
+ if !strings.Contains(metaImport.RepoRoot, "://") {
+ return nil, fmt.Errorf("%s: invalid repo root %q; no scheme", urlStr, metaImport.RepoRoot)
+ }
+ rr := &RepoRoot{
+ VCS: ByCmd(metaImport.VCS),
+ Repo: metaImport.RepoRoot,
+ Root: metaImport.Prefix,
+ }
+ if rr.VCS == nil {
+ return nil, fmt.Errorf("%s: unknown vcs %q", urlStr, metaImport.VCS)
+ }
+ return rr, nil
+}
+
+// metaImport represents the parsed <meta name="go-import"
+// content="prefix vcs reporoot" /> tags from HTML files.
+type metaImport struct {
+ Prefix, VCS, RepoRoot string
+}
+
+// errNoMatch is returned from matchGoImport when there's no applicable match.
+var errNoMatch = errors.New("no import match")
+
+// matchGoImport returns the metaImport from imports matching importPath.
+// An error is returned if there are multiple matches.
+// errNoMatch is returned if none match.
+func matchGoImport(imports []metaImport, importPath string) (_ metaImport, err error) {
+ match := -1
+ for i, im := range imports {
+ if !strings.HasPrefix(importPath, im.Prefix) {
+ continue
+ }
+ if match != -1 {
+ err = fmt.Errorf("multiple meta tags match import path %q", importPath)
+ return
+ }
+ match = i
+ }
+ if match == -1 {
+ err = errNoMatch
+ return
+ }
+ return imports[match], nil
+}
+
+// expand rewrites s to replace {k} with match[k] for each key k in match.
+func expand(match map[string]string, s string) string {
+ for k, v := range match {
+ s = strings.Replace(s, "{"+k+"}", v, -1)
+ }
+ return s
+}
+
+// vcsPaths lists the known vcs paths.
+var vcsPaths = []*vcsPath{
+ // go.googlesource.com
+ {
+ prefix: "go.googlesource.com",
+ re: `^(?P<root>go\.googlesource\.com/[A-Za-z0-9_.\-]+/?)$`,
+ vcs: "git",
+ repo: "https://{root}",
+ check: noVCSSuffix,
+ },
+
+ // Google Code - new syntax
+ {
+ prefix: "code.google.com/",
+ re: `^(?P<root>code\.google\.com/[pr]/(?P<project>[a-z0-9\-]+)(\.(?P<subrepo>[a-z0-9\-]+))?)(/[A-Za-z0-9_.\-]+)*$`,
+ repo: "https://{root}",
+ check: googleCodeVCS,
+ },
+
+ // Google Code - old syntax
+ {
+ re: `^(?P<project>[a-z0-9_\-.]+)\.googlecode\.com/(git|hg|svn)(?P<path>/.*)?$`,
+ check: oldGoogleCode,
+ },
+
+ // Github
+ {
+ prefix: "github.com/",
+ re: `^(?P<root>github\.com/[A-Za-z0-9_.\-]+/[A-Za-z0-9_.\-]+)(/[A-Za-z0-9_.\-]+)*$`,
+ vcs: "git",
+ repo: "https://{root}",
+ check: noVCSSuffix,
+ },
+
+ // Bitbucket
+ {
+ prefix: "bitbucket.org/",
+ re: `^(?P<root>bitbucket\.org/(?P<bitname>[A-Za-z0-9_.\-]+/[A-Za-z0-9_.\-]+))(/[A-Za-z0-9_.\-]+)*$`,
+ repo: "https://{root}",
+ check: bitbucketVCS,
+ },
+
+ // Launchpad
+ {
+ prefix: "launchpad.net/",
+ re: `^(?P<root>launchpad\.net/((?P<project>[A-Za-z0-9_.\-]+)(?P<series>/[A-Za-z0-9_.\-]+)?|~[A-Za-z0-9_.\-]+/(\+junk|[A-Za-z0-9_.\-]+)/[A-Za-z0-9_.\-]+))(/[A-Za-z0-9_.\-]+)*$`,
+ vcs: "bzr",
+ repo: "https://{root}",
+ check: launchpadVCS,
+ },
+
+ // General syntax for any server.
+ {
+ re: `^(?P<root>(?P<repo>([a-z0-9.\-]+\.)+[a-z0-9.\-]+(:[0-9]+)?/[A-Za-z0-9_.\-/]*?)\.(?P<vcs>bzr|git|hg|svn))(/[A-Za-z0-9_.\-]+)*$`,
+ ping: true,
+ },
+}
+
+func init() {
+ // fill in cached regexps.
+ // Doing this eagerly discovers invalid regexp syntax
+ // without having to run a command that needs that regexp.
+ for _, srv := range vcsPaths {
+ srv.regexp = regexp.MustCompile(srv.re)
+ }
+}
+
+// noVCSSuffix checks that the repository name does not
+// end in .foo for any version control system foo.
+// The usual culprit is ".git".
+func noVCSSuffix(match map[string]string) error {
+ repo := match["repo"]
+ for _, vcs := range vcsList {
+ if strings.HasSuffix(repo, "."+vcs.Cmd) {
+ return fmt.Errorf("invalid version control suffix in %s path", match["prefix"])
+ }
+ }
+ return nil
+}
+
+var googleCheckout = regexp.MustCompile(`id="checkoutcmd">(hg|git|svn)`)
+
+// googleCodeVCS determines the version control system for
+// a code.google.com repository, by scraping the project's
+// /source/checkout page.
+func googleCodeVCS(match map[string]string) error {
+ if err := noVCSSuffix(match); err != nil {
+ return err
+ }
+ data, err := httpGET(expand(match, "https://code.google.com/p/{project}/source/checkout?repo={subrepo}"))
+ if err != nil {
+ return err
+ }
+
+ if m := googleCheckout.FindSubmatch(data); m != nil {
+ if vcs := ByCmd(string(m[1])); vcs != nil {
+ // Subversion requires the old URLs.
+ // TODO: Test.
+ if vcs == vcsSvn {
+ if match["subrepo"] != "" {
+ return fmt.Errorf("sub-repositories not supported in Google Code Subversion projects")
+ }
+ match["repo"] = expand(match, "https://{project}.googlecode.com/svn")
+ }
+ match["vcs"] = vcs.Cmd
+ return nil
+ }
+ }
+
+ return fmt.Errorf("unable to detect version control system for code.google.com/ path")
+}
+
+// oldGoogleCode is invoked for old-style foo.googlecode.com paths.
+// It prints an error giving the equivalent new path.
+func oldGoogleCode(match map[string]string) error {
+ return fmt.Errorf("invalid Google Code import path: use %s instead",
+ expand(match, "code.google.com/p/{project}{path}"))
+}
+
+// bitbucketVCS determines the version control system for a
+// Bitbucket repository, by using the Bitbucket API.
+func bitbucketVCS(match map[string]string) error {
+ if err := noVCSSuffix(match); err != nil {
+ return err
+ }
+
+ var resp struct {
+ SCM string `json:"scm"`
+ }
+ url := expand(match, "https://api.bitbucket.org/1.0/repositories/{bitname}")
+ data, err := httpGET(url)
+ if err != nil {
+ return err
+ }
+ if err := json.Unmarshal(data, &resp); err != nil {
+ return fmt.Errorf("decoding %s: %v", url, err)
+ }
+
+ if ByCmd(resp.SCM) != nil {
+ match["vcs"] = resp.SCM
+ if resp.SCM == "git" {
+ match["repo"] += ".git"
+ }
+ return nil
+ }
+
+ return fmt.Errorf("unable to detect version control system for bitbucket.org/ path")
+}
+
+// launchpadVCS solves the ambiguity for "lp.net/project/foo". In this case,
+// "foo" could be a series name registered in Launchpad with its own branch,
+// and it could also be the name of a directory within the main project
+// branch one level up.
+func launchpadVCS(match map[string]string) error {
+ if match["project"] == "" || match["series"] == "" {
+ return nil
+ }
+ _, err := httpGET(expand(match, "https://code.launchpad.net/{project}{series}/.bzr/branch-format"))
+ if err != nil {
+ match["root"] = expand(match, "launchpad.net/{project}")
+ match["repo"] = expand(match, "https://{root}")
+ }
+ return nil
+}
diff --git a/go/vcs/vcs_test.go b/go/vcs/vcs_test.go
new file mode 100644
index 0000000..d77f20b
--- /dev/null
+++ b/go/vcs/vcs_test.go
@@ -0,0 +1,135 @@
+// 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 vcs
+
+import (
+ "io/ioutil"
+ "os"
+ "path/filepath"
+ "reflect"
+ "runtime"
+ "strings"
+ "testing"
+)
+
+// Test that RepoRootForImportPath creates the correct RepoRoot for a given importPath.
+// TODO(cmang): Add tests for SVN and BZR.
+func TestRepoRootForImportPath(t *testing.T) {
+ if runtime.GOOS == "android" {
+ t.Skipf("incomplete source tree on %s", runtime.GOOS)
+ }
+
+ tests := []struct {
+ path string
+ want *RepoRoot
+ }{
+ {
+ "code.google.com/p/go",
+ &RepoRoot{
+ VCS: vcsHg,
+ Repo: "https://code.google.com/p/go",
+ },
+ },
+ {
+ "code.google.com/r/go",
+ &RepoRoot{
+ VCS: vcsHg,
+ Repo: "https://code.google.com/r/go",
+ },
+ },
+ {
+ "github.com/golang/groupcache",
+ &RepoRoot{
+ VCS: vcsGit,
+ Repo: "https://github.com/golang/groupcache",
+ },
+ },
+ }
+
+ for _, test := range tests {
+ got, err := RepoRootForImportPath(test.path, false)
+ if err != nil {
+ t.Errorf("RepoRootForImport(%q): %v", test.path, err)
+ continue
+ }
+ want := test.want
+ if got.VCS.Name != want.VCS.Name || got.Repo != want.Repo {
+ t.Errorf("RepoRootForImport(%q) = VCS(%s) Repo(%s), want VCS(%s) Repo(%s)", test.path, got.VCS, got.Repo, want.VCS, want.Repo)
+ }
+ }
+}
+
+// Test that FromDir correctly inspects a given directory and returns the right VCS.
+func TestFromDir(t *testing.T) {
+ type testStruct struct {
+ path string
+ want *Cmd
+ }
+
+ tests := make([]testStruct, len(vcsList))
+ tempDir, err := ioutil.TempDir("", "vcstest")
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer os.RemoveAll(tempDir)
+
+ for i, vcs := range vcsList {
+ tests[i] = testStruct{
+ filepath.Join(tempDir, vcs.Name, "."+vcs.Cmd),
+ vcs,
+ }
+ }
+
+ for _, test := range tests {
+ os.MkdirAll(test.path, 0755)
+ got, _, _ := FromDir(test.path, tempDir)
+ if got.Name != test.want.Name {
+ t.Errorf("FromDir(%q, %q) = %s, want %s", test.path, tempDir, got, test.want)
+ }
+ os.RemoveAll(test.path)
+ }
+}
+
+var parseMetaGoImportsTests = []struct {
+ in string
+ out []metaImport
+}{
+ {
+ `<meta name="go-import" content="foo/bar git https://github.com/rsc/foo/bar">`,
+ []metaImport{{"foo/bar", "git", "https://github.com/rsc/foo/bar"}},
+ },
+ {
+ `<meta name="go-import" content="foo/bar git https://github.com/rsc/foo/bar">
+ <meta name="go-import" content="baz/quux git http://github.com/rsc/baz/quux">`,
+ []metaImport{
+ {"foo/bar", "git", "https://github.com/rsc/foo/bar"},
+ {"baz/quux", "git", "http://github.com/rsc/baz/quux"},
+ },
+ },
+ {
+ `<head>
+ <meta name="go-import" content="foo/bar git https://github.com/rsc/foo/bar">
+ </head>`,
+ []metaImport{{"foo/bar", "git", "https://github.com/rsc/foo/bar"}},
+ },
+ {
+ `<meta name="go-import" content="foo/bar git https://github.com/rsc/foo/bar">
+ <body>`,
+ []metaImport{{"foo/bar", "git", "https://github.com/rsc/foo/bar"}},
+ },
+}
+
+func TestParseMetaGoImports(t *testing.T) {
+ for i, tt := range parseMetaGoImportsTests {
+ out, err := parseMetaGoImports(strings.NewReader(tt.in))
+ if err != nil {
+ t.Errorf("test#%d: %v", i, err)
+ continue
+ }
+ if !reflect.DeepEqual(out, tt.out) {
+ t.Errorf("test#%d:\n\thave %q\n\twant %q", i, out, tt.out)
+ }
+ }
+}
diff --git a/godoc/analysis/README b/godoc/analysis/README
new file mode 100644
index 0000000..411af1c
--- /dev/null
+++ b/godoc/analysis/README
@@ -0,0 +1,111 @@
+
+Type and Pointer Analysis to-do list
+====================================
+
+Alan Donovan <adonovan@google.com>
+
+
+Overall design
+--------------
+
+We should re-run the type and pointer analyses periodically,
+as we do with the indexer.
+
+Version skew: how to mitigate the bad effects of stale URLs in old pages?
+We could record the file's length/CRC32/mtime in the go/loader, and
+refuse to decorate it with links unless they match at serving time.
+
+Use the VFS mechanism when (a) enumerating packages and (b) loading
+them. (Requires planned changes to go/loader.)
+
+Future work: shard this using map/reduce for larger corpora.
+
+Testing: how does one test that a web page "looks right"?
+
+
+Bugs
+----
+
+(*ssa.Program).Create requires transitively error-free packages. We
+can make this more robust by making the requirement transitively free
+of "hard" errors; soft errors are fine.
+
+Markup of compiler errors is slightly buggy because they overlap with
+other selections (e.g. Idents). Fix.
+
+
+User Interface
+--------------
+
+CALLGRAPH:
+- Add a search box: given a search node, expand path from each entry
+ point to it.
+- Cause hovering over a given node to highlight that node, and all
+ nodes that are logically identical to it.
+- Initially expand the callgraph trees (but not their toggle divs).
+
+CALLEES:
+- The '(' links are not very discoverable. Highlight them?
+
+Type info:
+- In the source viewer's lower pane, use a toggle div around the
+ IMPLEMENTS and METHODSETS lists, like we do in the pacakge view.
+ Only expand them initially if short.
+- Include IMPLEMENTS and METHOD SETS information in search index.
+- URLs in IMPLEMENTS/METHOD SETS always link to source, even from the
+ package docs view. This makes sense for links to non-exported
+ types, but links to exported types and funcs should probably go to
+ other package docs.
+- Suppress toggle divs for empty method sets.
+
+Misc:
+- The [X] button in the lower pane is subject to scrolling.
+- Should the lower pane be floating? An iframe?
+ When we change document.location by clicking on a link, it will go away.
+ How do we prevent that (a la Gmail's chat windows)?
+- Progress/status: for each file, display its analysis status, one of:
+ - not in analysis scope
+ - type analysis running...
+ - type analysis complete
+ (+ optionally: there were type errors in this file)
+ And if PTA requested:
+ - type analysis complete; PTA not attempted due to type errors
+ - PTA running...
+ - PTA complete
+- Scroll the selection into view, e.g. the vertical center, or better
+ still, under the pointer (assuming we have a mouse).
+
+
+More features
+-------------
+
+Display the REFERRERS relation? (Useful but potentially large.)
+
+Display the INSTANTIATIONS relation? i.e. given a type T, show the set of
+syntactic constructs that can instantiate it:
+ var x T
+ x := T{...}
+ x = new(T)
+ x = make([]T, n)
+ etc
+ + all INSTANTIATIONS of all S defined as struct{t T} or [n]T
+(Potentially a lot of information.)
+(Add this to oracle too.)
+
+
+Optimisations
+-------------
+
+Each call to addLink takes a (per-file) lock. The locking is
+fine-grained so server latency isn't terrible, but overall it makes
+the link computation quite slow. Batch update might be better.
+
+Memory usage is now about 1.5GB for GOROOT + go.tools. It used to be 700MB.
+
+Optimize for time and space. The main slowdown is the network I/O
+time caused by an increase in page size of about 3x: about 2x from
+HTML, and 0.7--2.1x from JSON (unindented vs indented). The JSON
+contains a lot of filenames (e.g. 820 copies of 16 distinct
+filenames). 20% of the HTML is L%d spans (now disabled). The HTML
+also contains lots of tooltips for long struct/interface types.
+De-dup or just abbreviate? The actual formatting is very fast.
diff --git a/godoc/analysis/analysis.go b/godoc/analysis/analysis.go
new file mode 100644
index 0000000..c11ecbd
--- /dev/null
+++ b/godoc/analysis/analysis.go
@@ -0,0 +1,620 @@
+// 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 analysis performs type and pointer analysis
+// and generates mark-up for the Go source view.
+//
+// The Run method populates a Result object by running type and
+// (optionally) pointer analysis. The Result object is thread-safe
+// and at all times may be accessed by a serving thread, even as it is
+// progressively populated as analysis facts are derived.
+//
+// The Result is a mapping from each godoc file URL
+// (e.g. /src/fmt/print.go) to information about that file. The
+// information is a list of HTML markup links and a JSON array of
+// structured data values. Some of the links call client-side
+// JavaScript functions that index this array.
+//
+// The analysis computes mark-up for the following relations:
+//
+// IMPORTS: for each ast.ImportSpec, the package that it denotes.
+//
+// RESOLUTION: for each ast.Ident, its kind and type, and the location
+// of its definition.
+//
+// METHOD SETS, IMPLEMENTS: for each ast.Ident defining a named type,
+// its method-set, the set of interfaces it implements or is
+// implemented by, and its size/align values.
+//
+// CALLERS, CALLEES: for each function declaration ('func' token), its
+// callers, and for each call-site ('(' token), its callees.
+//
+// CALLGRAPH: the package docs include an interactive viewer for the
+// intra-package call graph of "fmt".
+//
+// CHANNEL PEERS: for each channel operation make/<-/close, the set of
+// other channel ops that alias the same channel(s).
+//
+// ERRORS: for each locus of a frontend (scanner/parser/type) error, the
+// location is highlighted in red and hover text provides the compiler
+// error message.
+//
+package analysis // import "golang.org/x/tools/godoc/analysis"
+
+import (
+ "fmt"
+ "go/build"
+ "go/scanner"
+ "go/token"
+ "html"
+ "io"
+ "log"
+ "os"
+ "path/filepath"
+ "runtime"
+ "sort"
+ "strings"
+ "sync"
+
+ "golang.org/x/tools/go/exact"
+ "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"
+ "golang.org/x/tools/go/types"
+)
+
+// -- links ------------------------------------------------------------
+
+// A Link is an HTML decoration of the bytes [Start, End) of a file.
+// Write is called before/after those bytes to emit the mark-up.
+type Link interface {
+ Start() int
+ End() int
+ Write(w io.Writer, _ int, start bool) // the godoc.LinkWriter signature
+}
+
+// An <a> element.
+type aLink struct {
+ start, end int // =godoc.Segment
+ title string // hover text
+ onclick string // JS code (NB: trusted)
+ href string // URL (NB: trusted)
+}
+
+func (a aLink) Start() int { return a.start }
+func (a aLink) End() int { return a.end }
+func (a aLink) Write(w io.Writer, _ int, start bool) {
+ if start {
+ fmt.Fprintf(w, `<a title='%s'`, html.EscapeString(a.title))
+ if a.onclick != "" {
+ fmt.Fprintf(w, ` onclick='%s'`, html.EscapeString(a.onclick))
+ }
+ if a.href != "" {
+ // TODO(adonovan): I think that in principle, a.href must first be
+ // url.QueryEscape'd, but if I do that, a leading slash becomes "%2F",
+ // which causes the browser to treat the path as relative, not absolute.
+ // WTF?
+ fmt.Fprintf(w, ` href='%s'`, html.EscapeString(a.href))
+ }
+ fmt.Fprintf(w, ">")
+ } else {
+ fmt.Fprintf(w, "</a>")
+ }
+}
+
+// An <a class='error'> element.
+type errorLink struct {
+ start int
+ msg string
+}
+
+func (e errorLink) Start() int { return e.start }
+func (e errorLink) End() int { return e.start + 1 }
+
+func (e errorLink) Write(w io.Writer, _ int, start bool) {
+ // <span> causes havoc, not sure why, so use <a>.
+ if start {
+ fmt.Fprintf(w, `<a class='error' title='%s'>`, html.EscapeString(e.msg))
+ } else {
+ fmt.Fprintf(w, "</a>")
+ }
+}
+
+// -- fileInfo ---------------------------------------------------------
+
+// FileInfo holds analysis information for the source file view.
+// Clients must not mutate it.
+type FileInfo struct {
+ Data []interface{} // JSON serializable values
+ Links []Link // HTML link markup
+}
+
+// A fileInfo is the server's store of hyperlinks and JSON data for a
+// particular file.
+type fileInfo struct {
+ mu sync.Mutex
+ data []interface{} // JSON objects
+ links []Link
+ sorted bool
+ hasErrors bool // TODO(adonovan): surface this in the UI
+}
+
+// addLink adds a link to the Go source file fi.
+func (fi *fileInfo) addLink(link Link) {
+ fi.mu.Lock()
+ fi.links = append(fi.links, link)
+ fi.sorted = false
+ if _, ok := link.(errorLink); ok {
+ fi.hasErrors = true
+ }
+ fi.mu.Unlock()
+}
+
+// addData adds the structured value x to the JSON data for the Go
+// source file fi. Its index is returned.
+func (fi *fileInfo) addData(x interface{}) int {
+ fi.mu.Lock()
+ index := len(fi.data)
+ fi.data = append(fi.data, x)
+ fi.mu.Unlock()
+ return index
+}
+
+// get returns the file info in external form.
+// Callers must not mutate its fields.
+func (fi *fileInfo) get() FileInfo {
+ var r FileInfo
+ // Copy slices, to avoid races.
+ fi.mu.Lock()
+ r.Data = append(r.Data, fi.data...)
+ if !fi.sorted {
+ sort.Sort(linksByStart(fi.links))
+ fi.sorted = true
+ }
+ r.Links = append(r.Links, fi.links...)
+ fi.mu.Unlock()
+ return r
+}
+
+// PackageInfo holds analysis information for the package view.
+// Clients must not mutate it.
+type PackageInfo struct {
+ CallGraph []*PCGNodeJSON
+ CallGraphIndex map[string]int
+ Types []*TypeInfoJSON
+}
+
+type pkgInfo struct {
+ mu sync.Mutex
+ callGraph []*PCGNodeJSON
+ callGraphIndex map[string]int // keys are (*ssa.Function).RelString()
+ types []*TypeInfoJSON // type info for exported types
+}
+
+func (pi *pkgInfo) setCallGraph(callGraph []*PCGNodeJSON, callGraphIndex map[string]int) {
+ pi.mu.Lock()
+ pi.callGraph = callGraph
+ pi.callGraphIndex = callGraphIndex
+ pi.mu.Unlock()
+}
+
+func (pi *pkgInfo) addType(t *TypeInfoJSON) {
+ pi.mu.Lock()
+ pi.types = append(pi.types, t)
+ pi.mu.Unlock()
+}
+
+// get returns the package info in external form.
+// Callers must not mutate its fields.
+func (pi *pkgInfo) get() PackageInfo {
+ var r PackageInfo
+ // Copy slices, to avoid races.
+ pi.mu.Lock()
+ r.CallGraph = append(r.CallGraph, pi.callGraph...)
+ r.CallGraphIndex = pi.callGraphIndex
+ r.Types = append(r.Types, pi.types...)
+ pi.mu.Unlock()
+ return r
+}
+
+// -- Result -----------------------------------------------------------
+
+// Result contains the results of analysis.
+// The result contains a mapping from filenames to a set of HTML links
+// and JavaScript data referenced by the links.
+type Result struct {
+ mu sync.Mutex // guards maps (but not their contents)
+ status string // global analysis status
+ fileInfos map[string]*fileInfo // keys are godoc file URLs
+ pkgInfos map[string]*pkgInfo // keys are import paths
+}
+
+// fileInfo returns the fileInfo for the specified godoc file URL,
+// constructing it as needed. Thread-safe.
+func (res *Result) fileInfo(url string) *fileInfo {
+ res.mu.Lock()
+ fi, ok := res.fileInfos[url]
+ if !ok {
+ if res.fileInfos == nil {
+ res.fileInfos = make(map[string]*fileInfo)
+ }
+ fi = new(fileInfo)
+ res.fileInfos[url] = fi
+ }
+ res.mu.Unlock()
+ return fi
+}
+
+// Status returns a human-readable description of the current analysis status.
+func (res *Result) Status() string {
+ res.mu.Lock()
+ defer res.mu.Unlock()
+ return res.status
+}
+
+func (res *Result) setStatusf(format string, args ...interface{}) {
+ res.mu.Lock()
+ res.status = fmt.Sprintf(format, args...)
+ log.Printf(format, args...)
+ res.mu.Unlock()
+}
+
+// FileInfo returns new slices containing opaque JSON values and the
+// HTML link markup for the specified godoc file URL. Thread-safe.
+// Callers must not mutate the elements.
+// It returns "zero" if no data is available.
+//
+func (res *Result) FileInfo(url string) (fi FileInfo) {
+ return res.fileInfo(url).get()
+}
+
+// pkgInfo returns the pkgInfo for the specified import path,
+// constructing it as needed. Thread-safe.
+func (res *Result) pkgInfo(importPath string) *pkgInfo {
+ res.mu.Lock()
+ pi, ok := res.pkgInfos[importPath]
+ if !ok {
+ if res.pkgInfos == nil {
+ res.pkgInfos = make(map[string]*pkgInfo)
+ }
+ pi = new(pkgInfo)
+ res.pkgInfos[importPath] = pi
+ }
+ res.mu.Unlock()
+ return pi
+}
+
+// PackageInfo returns new slices of JSON values for the callgraph and
+// type info for the specified package. Thread-safe.
+// Callers must not mutate its fields.
+// PackageInfo returns "zero" if no data is available.
+//
+func (res *Result) PackageInfo(importPath string) PackageInfo {
+ return res.pkgInfo(importPath).get()
+}
+
+// -- analysis ---------------------------------------------------------
+
+type analysis struct {
+ result *Result
+ prog *ssa.Program
+ ops []chanOp // all channel ops in program
+ allNamed []*types.Named // all named types in the program
+ ptaConfig pointer.Config
+ path2url map[string]string // maps openable path to godoc file URL (/src/fmt/print.go)
+ pcgs map[*ssa.Package]*packageCallGraph
+}
+
+// fileAndOffset returns the file and offset for a given pos.
+func (a *analysis) fileAndOffset(pos token.Pos) (fi *fileInfo, offset int) {
+ return a.fileAndOffsetPosn(a.prog.Fset.Position(pos))
+}
+
+// fileAndOffsetPosn returns the file and offset for a given position.
+func (a *analysis) fileAndOffsetPosn(posn token.Position) (fi *fileInfo, offset int) {
+ url := a.path2url[posn.Filename]
+ return a.result.fileInfo(url), posn.Offset
+}
+
+// posURL returns the URL of the source extent [pos, pos+len).
+func (a *analysis) posURL(pos token.Pos, len int) string {
+ if pos == token.NoPos {
+ return ""
+ }
+ posn := a.prog.Fset.Position(pos)
+ url := a.path2url[posn.Filename]
+ return fmt.Sprintf("%s?s=%d:%d#L%d",
+ url, posn.Offset, posn.Offset+len, posn.Line)
+}
+
+// ----------------------------------------------------------------------
+
+// Run runs program analysis and computes the resulting markup,
+// populating *result in a thread-safe manner, first with type
+// information then later with pointer analysis information if
+// enabled by the pta flag.
+//
+func Run(pta bool, result *Result) {
+ conf := loader.Config{
+ AllowErrors: true,
+ }
+
+ // Silence the default error handler.
+ // Don't print all errors; we'll report just
+ // one per errant package later.
+ conf.TypeChecker.Error = func(e error) {}
+
+ var roots, args []string // roots[i] ends with os.PathSeparator
+
+ // Enumerate packages in $GOROOT.
+ root := filepath.Join(runtime.GOROOT(), "src") + string(os.PathSeparator)
+ roots = append(roots, root)
+ args = allPackages(root)
+ log.Printf("GOROOT=%s: %s\n", root, args)
+
+ // Enumerate packages in $GOPATH.
+ for i, dir := range filepath.SplitList(build.Default.GOPATH) {
+ root := filepath.Join(dir, "src") + string(os.PathSeparator)
+ roots = append(roots, root)
+ pkgs := allPackages(root)
+ log.Printf("GOPATH[%d]=%s: %s\n", i, root, pkgs)
+ args = append(args, pkgs...)
+ }
+
+ // Uncomment to make startup quicker during debugging.
+ //args = []string{"golang.org/x/tools/cmd/godoc"}
+ //args = []string{"fmt"}
+
+ if _, err := conf.FromArgs(args, true); err != nil {
+ // TODO(adonovan): degrade gracefully, not fail totally.
+ // (The crippling case is a parse error in an external test file.)
+ result.setStatusf("Analysis failed: %s.", err) // import error
+ return
+ }
+
+ result.setStatusf("Loading and type-checking packages...")
+ iprog, err := conf.Load()
+ if iprog != nil {
+ // Report only the first error of each package.
+ for _, info := range iprog.AllPackages {
+ for _, err := range info.Errors {
+ fmt.Fprintln(os.Stderr, err)
+ break
+ }
+ }
+ log.Printf("Loaded %d packages.", len(iprog.AllPackages))
+ }
+ if err != nil {
+ result.setStatusf("Loading failed: %s.\n", err)
+ return
+ }
+
+ // Create SSA-form program representation.
+ // Only the transitively error-free packages are used.
+ prog := ssautil.CreateProgram(iprog, ssa.GlobalDebug)
+
+ // Compute the set of main packages, including testmain.
+ allPackages := prog.AllPackages()
+ var mainPkgs []*ssa.Package
+ if testmain := prog.CreateTestMainPackage(allPackages...); testmain != nil {
+ mainPkgs = append(mainPkgs, testmain)
+ if p := testmain.Const("packages"); p != nil {
+ log.Printf("Tested packages: %v", exact.StringVal(p.Value.Value))
+ }
+ }
+ for _, pkg := range allPackages {
+ if pkg.Object.Name() == "main" && pkg.Func("main") != nil {
+ mainPkgs = append(mainPkgs, pkg)
+ }
+ }
+ log.Print("Transitively error-free main packages: ", mainPkgs)
+
+ // Build SSA code for bodies of all functions in the whole program.
+ result.setStatusf("Constructing SSA form...")
+ prog.BuildAll()
+ log.Print("SSA construction complete")
+
+ a := analysis{
+ result: result,
+ prog: prog,
+ pcgs: make(map[*ssa.Package]*packageCallGraph),
+ }
+
+ // Build a mapping from openable filenames to godoc file URLs,
+ // i.e. "/src/" plus path relative to GOROOT/src or GOPATH[i]/src.
+ a.path2url = make(map[string]string)
+ for _, info := range iprog.AllPackages {
+ nextfile:
+ for _, f := range info.Files {
+ if f.Pos() == 0 {
+ continue // e.g. files generated by cgo
+ }
+ abs := iprog.Fset.File(f.Pos()).Name()
+ // Find the root to which this file belongs.
+ for _, root := range roots {
+ rel := strings.TrimPrefix(abs, root)
+ if len(rel) < len(abs) {
+ a.path2url[abs] = "/src/" + filepath.ToSlash(rel)
+ continue nextfile
+ }
+ }
+
+ log.Printf("Can't locate file %s (package %q) beneath any root",
+ abs, info.Pkg.Path())
+ }
+ }
+
+ // Add links for scanner, parser, type-checker errors.
+ // TODO(adonovan): fix: these links can overlap with
+ // identifier markup, causing the renderer to emit some
+ // characters twice.
+ errors := make(map[token.Position][]string)
+ for _, info := range iprog.AllPackages {
+ for _, err := range info.Errors {
+ switch err := err.(type) {
+ case types.Error:
+ posn := a.prog.Fset.Position(err.Pos)
+ errors[posn] = append(errors[posn], err.Msg)
+ case scanner.ErrorList:
+ for _, e := range err {
+ errors[e.Pos] = append(errors[e.Pos], e.Msg)
+ }
+ default:
+ log.Printf("Package %q has error (%T) without position: %v\n",
+ info.Pkg.Path(), err, err)
+ }
+ }
+ }
+ for posn, errs := range errors {
+ fi, offset := a.fileAndOffsetPosn(posn)
+ fi.addLink(errorLink{
+ start: offset,
+ msg: strings.Join(errs, "\n"),
+ })
+ }
+
+ // ---------- type-based analyses ----------
+
+ // Compute the all-pairs IMPLEMENTS relation.
+ // Collect all named types, even local types
+ // (which can have methods via promotion)
+ // and the built-in "error".
+ errorType := types.Universe.Lookup("error").Type().(*types.Named)
+ a.allNamed = append(a.allNamed, errorType)
+ for _, info := range iprog.AllPackages {
+ for _, obj := range info.Defs {
+ if obj, ok := obj.(*types.TypeName); ok {
+ a.allNamed = append(a.allNamed, obj.Type().(*types.Named))
+ }
+ }
+ }
+ log.Print("Computing implements relation...")
+ facts := computeImplements(&a.prog.MethodSets, a.allNamed)
+
+ // Add the type-based analysis results.
+ log.Print("Extracting type info...")
+ for _, info := range iprog.AllPackages {
+ a.doTypeInfo(info, facts)
+ }
+
+ a.visitInstrs(pta)
+
+ result.setStatusf("Type analysis complete.")
+
+ if pta {
+ a.pointer(mainPkgs)
+ }
+}
+
+// visitInstrs visits all SSA instructions in the program.
+func (a *analysis) visitInstrs(pta bool) {
+ log.Print("Visit instructions...")
+ for fn := range ssautil.AllFunctions(a.prog) {
+ for _, b := range fn.Blocks {
+ for _, instr := range b.Instrs {
+ // CALLEES (static)
+ // (Dynamic calls require pointer analysis.)
+ //
+ // We use the SSA representation to find the static callee,
+ // since in many cases it does better than the
+ // types.Info.{Refs,Selection} information. For example:
+ //
+ // defer func(){}() // static call to anon function
+ // f := func(){}; f() // static call to anon function
+ // f := fmt.Println; f() // static call to named function
+ //
+ // The downside is that we get no static callee information
+ // for packages that (transitively) contain errors.
+ if site, ok := instr.(ssa.CallInstruction); ok {
+ if callee := site.Common().StaticCallee(); callee != nil {
+ // TODO(adonovan): callgraph: elide wrappers.
+ // (Do static calls ever go to wrappers?)
+ if site.Common().Pos() != token.NoPos {
+ a.addCallees(site, []*ssa.Function{callee})
+ }
+ }
+ }
+
+ if !pta {
+ continue
+ }
+
+ // CHANNEL PEERS
+ // Collect send/receive/close instructions in the whole ssa.Program.
+ for _, op := range chanOps(instr) {
+ a.ops = append(a.ops, op)
+ a.ptaConfig.AddQuery(op.ch) // add channel ssa.Value to PTA query
+ }
+ }
+ }
+ }
+ log.Print("Visit instructions complete")
+}
+
+// pointer runs the pointer analysis.
+func (a *analysis) pointer(mainPkgs []*ssa.Package) {
+ // Run the pointer analysis and build the complete callgraph.
+ a.ptaConfig.Mains = mainPkgs
+ a.ptaConfig.BuildCallGraph = true
+ a.ptaConfig.Reflection = false // (for now)
+
+ a.result.setStatusf("Pointer analysis running...")
+
+ ptares, err := pointer.Analyze(&a.ptaConfig)
+ if err != nil {
+ // If this happens, it indicates a bug.
+ a.result.setStatusf("Pointer analysis failed: %s.", err)
+ return
+ }
+ log.Print("Pointer analysis complete.")
+
+ // Add the results of pointer analysis.
+
+ a.result.setStatusf("Computing channel peers...")
+ a.doChannelPeers(ptares.Queries)
+ a.result.setStatusf("Computing dynamic call graph edges...")
+ a.doCallgraph(ptares.CallGraph)
+
+ a.result.setStatusf("Analysis complete.")
+}
+
+type linksByStart []Link
+
+func (a linksByStart) Less(i, j int) bool { return a[i].Start() < a[j].Start() }
+func (a linksByStart) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
+func (a linksByStart) Len() int { return len(a) }
+
+// allPackages returns a new sorted slice of all packages beneath the
+// specified package root directory, e.g. $GOROOT/src or $GOPATH/src.
+// Derived from from go/ssa/stdlib_test.go
+// root must end with os.PathSeparator.
+//
+// TODO(adonovan): use buildutil.AllPackages when the tree thaws.
+func allPackages(root string) []string {
+ var pkgs []string
+ filepath.Walk(root, func(path string, info os.FileInfo, err error) error {
+ if info == nil {
+ return nil // non-existent root directory?
+ }
+ if !info.IsDir() {
+ return nil // not a directory
+ }
+ // Prune the search if we encounter any of these names:
+ base := filepath.Base(path)
+ if base == "testdata" || strings.HasPrefix(base, ".") {
+ return filepath.SkipDir
+ }
+ pkg := filepath.ToSlash(strings.TrimPrefix(path, root))
+ switch pkg {
+ case "builtin":
+ return filepath.SkipDir
+ case "":
+ return nil // ignore root of tree
+ }
+ pkgs = append(pkgs, pkg)
+ return nil
+ })
+ return pkgs
+}
diff --git a/godoc/analysis/callgraph.go b/godoc/analysis/callgraph.go
new file mode 100644
index 0000000..a98d294
--- /dev/null
+++ b/godoc/analysis/callgraph.go
@@ -0,0 +1,351 @@
+// 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 analysis
+
+// This file computes the CALLERS and CALLEES relations from the call
+// graph. CALLERS/CALLEES information is displayed in the lower pane
+// when a "func" token or ast.CallExpr.Lparen is clicked, respectively.
+
+import (
+ "fmt"
+ "go/ast"
+ "go/token"
+ "log"
+ "math/big"
+ "sort"
+
+ "golang.org/x/tools/go/callgraph"
+ "golang.org/x/tools/go/ssa"
+ "golang.org/x/tools/go/types"
+)
+
+// doCallgraph computes the CALLEES and CALLERS relations.
+func (a *analysis) doCallgraph(cg *callgraph.Graph) {
+ log.Print("Deleting synthetic nodes...")
+ // TODO(adonovan): opt: DeleteSyntheticNodes is asymptotically
+ // inefficient and can be (unpredictably) slow.
+ cg.DeleteSyntheticNodes()
+ log.Print("Synthetic nodes deleted")
+
+ // Populate nodes of package call graphs (PCGs).
+ for _, n := range cg.Nodes {
+ a.pcgAddNode(n.Func)
+ }
+ // Within each PCG, sort funcs by name.
+ for _, pcg := range a.pcgs {
+ pcg.sortNodes()
+ }
+
+ calledFuncs := make(map[ssa.CallInstruction]map[*ssa.Function]bool)
+ callingSites := make(map[*ssa.Function]map[ssa.CallInstruction]bool)
+ for _, n := range cg.Nodes {
+ for _, e := range n.Out {
+ if e.Site == nil {
+ continue // a call from a synthetic node such as <root>
+ }
+
+ // Add (site pos, callee) to calledFuncs.
+ // (Dynamic calls only.)
+ callee := e.Callee.Func
+
+ a.pcgAddEdge(n.Func, callee)
+
+ if callee.Synthetic != "" {
+ continue // call of a package initializer
+ }
+
+ if e.Site.Common().StaticCallee() == nil {
+ // dynamic call
+ // (CALLEES information for static calls
+ // is computed using SSA information.)
+ lparen := e.Site.Common().Pos()
+ if lparen != token.NoPos {
+ fns := calledFuncs[e.Site]
+ if fns == nil {
+ fns = make(map[*ssa.Function]bool)
+ calledFuncs[e.Site] = fns
+ }
+ fns[callee] = true
+ }
+ }
+
+ // Add (callee, site) to callingSites.
+ fns := callingSites[callee]
+ if fns == nil {
+ fns = make(map[ssa.CallInstruction]bool)
+ callingSites[callee] = fns
+ }
+ fns[e.Site] = true
+ }
+ }
+
+ // CALLEES.
+ log.Print("Callees...")
+ for site, fns := range calledFuncs {
+ var funcs funcsByPos
+ for fn := range fns {
+ funcs = append(funcs, fn)
+ }
+ sort.Sort(funcs)
+
+ a.addCallees(site, funcs)
+ }
+
+ // CALLERS
+ log.Print("Callers...")
+ for callee, sites := range callingSites {
+ pos := funcToken(callee)
+ if pos == token.NoPos {
+ log.Printf("CALLERS: skipping %s: no pos", callee)
+ continue
+ }
+
+ var this *types.Package // for relativizing names
+ if callee.Pkg != nil {
+ this = callee.Pkg.Object
+ }
+
+ // Compute sites grouped by parent, with text and URLs.
+ sitesByParent := make(map[*ssa.Function]sitesByPos)
+ for site := range sites {
+ fn := site.Parent()
+ sitesByParent[fn] = append(sitesByParent[fn], site)
+ }
+ var funcs funcsByPos
+ for fn := range sitesByParent {
+ funcs = append(funcs, fn)
+ }
+ sort.Sort(funcs)
+
+ v := callersJSON{
+ Callee: callee.String(),
+ Callers: []callerJSON{}, // (JS wants non-nil)
+ }
+ for _, fn := range funcs {
+ caller := callerJSON{
+ Func: prettyFunc(this, fn),
+ Sites: []anchorJSON{}, // (JS wants non-nil)
+ }
+ sites := sitesByParent[fn]
+ sort.Sort(sites)
+ for _, site := range sites {
+ pos := site.Common().Pos()
+ if pos != token.NoPos {
+ caller.Sites = append(caller.Sites, anchorJSON{
+ Text: fmt.Sprintf("%d", a.prog.Fset.Position(pos).Line),
+ Href: a.posURL(pos, len("(")),
+ })
+ }
+ }
+ v.Callers = append(v.Callers, caller)
+ }
+
+ fi, offset := a.fileAndOffset(pos)
+ fi.addLink(aLink{
+ start: offset,
+ end: offset + len("func"),
+ title: fmt.Sprintf("%d callers", len(sites)),
+ onclick: fmt.Sprintf("onClickCallers(%d)", fi.addData(v)),
+ })
+ }
+
+ // PACKAGE CALLGRAPH
+ log.Print("Package call graph...")
+ for pkg, pcg := range a.pcgs {
+ // Maps (*ssa.Function).RelString() to index in JSON CALLGRAPH array.
+ index := make(map[string]int)
+
+ // Treat exported functions (and exported methods of
+ // exported named types) as roots even if they aren't
+ // actually called from outside the package.
+ for i, n := range pcg.nodes {
+ if i == 0 || n.fn.Object() == nil || !n.fn.Object().Exported() {
+ continue
+ }
+ recv := n.fn.Signature.Recv()
+ if recv == nil || deref(recv.Type()).(*types.Named).Obj().Exported() {
+ roots := &pcg.nodes[0].edges
+ roots.SetBit(roots, i, 1)
+ }
+ index[n.fn.RelString(pkg.Object)] = i
+ }
+
+ json := a.pcgJSON(pcg)
+
+ // TODO(adonovan): pkg.Path() is not unique!
+ // It is possible to declare a non-test package called x_test.
+ a.result.pkgInfo(pkg.Object.Path()).setCallGraph(json, index)
+ }
+}
+
+// addCallees adds client data and links for the facts that site calls fns.
+func (a *analysis) addCallees(site ssa.CallInstruction, fns []*ssa.Function) {
+ v := calleesJSON{
+ Descr: site.Common().Description(),
+ Callees: []anchorJSON{}, // (JS wants non-nil)
+ }
+ var this *types.Package // for relativizing names
+ if p := site.Parent().Package(); p != nil {
+ this = p.Object
+ }
+
+ for _, fn := range fns {
+ v.Callees = append(v.Callees, anchorJSON{
+ Text: prettyFunc(this, fn),
+ Href: a.posURL(funcToken(fn), len("func")),
+ })
+ }
+
+ fi, offset := a.fileAndOffset(site.Common().Pos())
+ fi.addLink(aLink{
+ start: offset,
+ end: offset + len("("),
+ title: fmt.Sprintf("%d callees", len(v.Callees)),
+ onclick: fmt.Sprintf("onClickCallees(%d)", fi.addData(v)),
+ })
+}
+
+// -- utilities --------------------------------------------------------
+
+// stable order within packages but undefined across packages.
+type funcsByPos []*ssa.Function
+
+func (a funcsByPos) Less(i, j int) bool { return a[i].Pos() < a[j].Pos() }
+func (a funcsByPos) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
+func (a funcsByPos) Len() int { return len(a) }
+
+type sitesByPos []ssa.CallInstruction
+
+func (a sitesByPos) Less(i, j int) bool { return a[i].Common().Pos() < a[j].Common().Pos() }
+func (a sitesByPos) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
+func (a sitesByPos) Len() int { return len(a) }
+
+func funcToken(fn *ssa.Function) token.Pos {
+ switch syntax := fn.Syntax().(type) {
+ case *ast.FuncLit:
+ return syntax.Type.Func
+ case *ast.FuncDecl:
+ return syntax.Type.Func
+ }
+ return token.NoPos
+}
+
+// prettyFunc pretty-prints fn for the user interface.
+// TODO(adonovan): return HTML so we have more markup freedom.
+func prettyFunc(this *types.Package, fn *ssa.Function) string {
+ if fn.Parent() != nil {
+ return fmt.Sprintf("%s in %s",
+ types.TypeString(fn.Signature, types.RelativeTo(this)),
+ prettyFunc(this, fn.Parent()))
+ }
+ if fn.Synthetic != "" && fn.Name() == "init" {
+ // (This is the actual initializer, not a declared 'func init').
+ if fn.Pkg.Object == this {
+ return "package initializer"
+ }
+ return fmt.Sprintf("%q package initializer", fn.Pkg.Object.Path())
+ }
+ return fn.RelString(this)
+}
+
+// -- intra-package callgraph ------------------------------------------
+
+// pcgNode represents a node in the package call graph (PCG).
+type pcgNode struct {
+ fn *ssa.Function
+ pretty string // cache of prettyFunc(fn)
+ edges big.Int // set of callee func indices
+}
+
+// A packageCallGraph represents the intra-package edges of the global call graph.
+// The zeroth node indicates "all external functions".
+type packageCallGraph struct {
+ nodeIndex map[*ssa.Function]int // maps func to node index (a small int)
+ nodes []*pcgNode // maps node index to node
+}
+
+// sortNodes populates pcg.nodes in name order and updates the nodeIndex.
+func (pcg *packageCallGraph) sortNodes() {
+ nodes := make([]*pcgNode, 0, len(pcg.nodeIndex))
+ nodes = append(nodes, &pcgNode{fn: nil, pretty: "<external>"})
+ for fn := range pcg.nodeIndex {
+ nodes = append(nodes, &pcgNode{
+ fn: fn,
+ pretty: prettyFunc(fn.Pkg.Object, fn),
+ })
+ }
+ sort.Sort(pcgNodesByPretty(nodes[1:]))
+ for i, n := range nodes {
+ pcg.nodeIndex[n.fn] = i
+ }
+ pcg.nodes = nodes
+}
+
+func (pcg *packageCallGraph) addEdge(caller, callee *ssa.Function) {
+ var callerIndex int
+ if caller.Pkg == callee.Pkg {
+ // intra-package edge
+ callerIndex = pcg.nodeIndex[caller]
+ if callerIndex < 1 {
+ panic(caller)
+ }
+ }
+ edges := &pcg.nodes[callerIndex].edges
+ edges.SetBit(edges, pcg.nodeIndex[callee], 1)
+}
+
+func (a *analysis) pcgAddNode(fn *ssa.Function) {
+ if fn.Pkg == nil {
+ return
+ }
+ pcg, ok := a.pcgs[fn.Pkg]
+ if !ok {
+ pcg = &packageCallGraph{nodeIndex: make(map[*ssa.Function]int)}
+ a.pcgs[fn.Pkg] = pcg
+ }
+ pcg.nodeIndex[fn] = -1
+}
+
+func (a *analysis) pcgAddEdge(caller, callee *ssa.Function) {
+ if callee.Pkg != nil {
+ a.pcgs[callee.Pkg].addEdge(caller, callee)
+ }
+}
+
+// pcgJSON returns a new slice of callgraph JSON values.
+func (a *analysis) pcgJSON(pcg *packageCallGraph) []*PCGNodeJSON {
+ var nodes []*PCGNodeJSON
+ for _, n := range pcg.nodes {
+
+ // TODO(adonovan): why is there no good way to iterate
+ // over the set bits of a big.Int?
+ var callees []int
+ nbits := n.edges.BitLen()
+ for j := 0; j < nbits; j++ {
+ if n.edges.Bit(j) == 1 {
+ callees = append(callees, j)
+ }
+ }
+
+ var pos token.Pos
+ if n.fn != nil {
+ pos = funcToken(n.fn)
+ }
+ nodes = append(nodes, &PCGNodeJSON{
+ Func: anchorJSON{
+ Text: n.pretty,
+ Href: a.posURL(pos, len("func")),
+ },
+ Callees: callees,
+ })
+ }
+ return nodes
+}
+
+type pcgNodesByPretty []*pcgNode
+
+func (a pcgNodesByPretty) Less(i, j int) bool { return a[i].pretty < a[j].pretty }
+func (a pcgNodesByPretty) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
+func (a pcgNodesByPretty) Len() int { return len(a) }
diff --git a/godoc/analysis/implements.go b/godoc/analysis/implements.go
new file mode 100644
index 0000000..bee04d0
--- /dev/null
+++ b/godoc/analysis/implements.go
@@ -0,0 +1,195 @@
+// 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 analysis
+
+// This file computes the "implements" relation over all pairs of
+// named types in the program. (The mark-up is done by typeinfo.go.)
+
+// TODO(adonovan): do we want to report implements(C, I) where C and I
+// belong to different packages and at least one is not exported?
+
+import (
+ "sort"
+
+ "golang.org/x/tools/go/types"
+ "golang.org/x/tools/go/types/typeutil"
+)
+
+// computeImplements computes the "implements" relation over all pairs
+// of named types in allNamed.
+func computeImplements(cache *typeutil.MethodSetCache, allNamed []*types.Named) map[*types.Named]implementsFacts {
+ // Information about a single type's method set.
+ type msetInfo struct {
+ typ types.Type
+ mset *types.MethodSet
+ mask1, mask2 uint64
+ }
+
+ initMsetInfo := func(info *msetInfo, typ types.Type) {
+ info.typ = typ
+ info.mset = cache.MethodSet(typ)
+ for i := 0; i < info.mset.Len(); i++ {
+ name := info.mset.At(i).Obj().Name()
+ info.mask1 |= 1 << methodBit(name[0])
+ info.mask2 |= 1 << methodBit(name[len(name)-1])
+ }
+ }
+
+ // satisfies(T, U) reports whether type T satisfies type U.
+ // U must be an interface.
+ //
+ // Since there are thousands of types (and thus millions of
+ // pairs of types) and types.Assignable(T, U) is relatively
+ // expensive, we compute assignability directly from the
+ // method sets. (At least one of T and U must be an
+ // interface.)
+ //
+ // We use a trick (thanks gri!) related to a Bloom filter to
+ // quickly reject most tests, which are false. For each
+ // method set, we precompute a mask, a set of bits, one per
+ // distinct initial byte of each method name. Thus the mask
+ // for io.ReadWriter would be {'R','W'}. AssignableTo(T, U)
+ // cannot be true unless mask(T)&mask(U)==mask(U).
+ //
+ // As with a Bloom filter, we can improve precision by testing
+ // additional hashes, e.g. using the last letter of each
+ // method name, so long as the subset mask property holds.
+ //
+ // When analyzing the standard library, there are about 1e6
+ // calls to satisfies(), of which 0.6% return true. With a
+ // 1-hash filter, 95% of calls avoid the expensive check; with
+ // a 2-hash filter, this grows to 98.2%.
+ satisfies := func(T, U *msetInfo) bool {
+ return T.mask1&U.mask1 == U.mask1 &&
+ T.mask2&U.mask2 == U.mask2 &&
+ containsAllIdsOf(T.mset, U.mset)
+ }
+
+ // Information about a named type N, and perhaps also *N.
+ type namedInfo struct {
+ isInterface bool
+ base msetInfo // N
+ ptr msetInfo // *N, iff N !isInterface
+ }
+
+ var infos []namedInfo
+
+ // Precompute the method sets and their masks.
+ for _, N := range allNamed {
+ var info namedInfo
+ initMsetInfo(&info.base, N)
+ _, info.isInterface = N.Underlying().(*types.Interface)
+ if !info.isInterface {
+ initMsetInfo(&info.ptr, types.NewPointer(N))
+ }
+
+ if info.base.mask1|info.ptr.mask1 == 0 {
+ continue // neither N nor *N has methods
+ }
+
+ infos = append(infos, info)
+ }
+
+ facts := make(map[*types.Named]implementsFacts)
+
+ // Test all pairs of distinct named types (T, U).
+ // TODO(adonovan): opt: compute (U, T) at the same time.
+ for t := range infos {
+ T := &infos[t]
+ var to, from, fromPtr []types.Type
+ for u := range infos {
+ if t == u {
+ continue
+ }
+ U := &infos[u]
+ switch {
+ case T.isInterface && U.isInterface:
+ if satisfies(&U.base, &T.base) {
+ to = append(to, U.base.typ)
+ }
+ if satisfies(&T.base, &U.base) {
+ from = append(from, U.base.typ)
+ }
+ case T.isInterface: // U concrete
+ if satisfies(&U.base, &T.base) {
+ to = append(to, U.base.typ)
+ } else if satisfies(&U.ptr, &T.base) {
+ to = append(to, U.ptr.typ)
+ }
+ case U.isInterface: // T concrete
+ if satisfies(&T.base, &U.base) {
+ from = append(from, U.base.typ)
+ } else if satisfies(&T.ptr, &U.base) {
+ fromPtr = append(fromPtr, U.base.typ)
+ }
+ }
+ }
+
+ // Sort types (arbitrarily) to avoid nondeterminism.
+ sort.Sort(typesByString(to))
+ sort.Sort(typesByString(from))
+ sort.Sort(typesByString(fromPtr))
+
+ facts[T.base.typ.(*types.Named)] = implementsFacts{to, from, fromPtr}
+ }
+
+ return facts
+}
+
+type implementsFacts struct {
+ to []types.Type // named or ptr-to-named types assignable to interface T
+ from []types.Type // named interfaces assignable from T
+ fromPtr []types.Type // named interfaces assignable only from *T
+}
+
+type typesByString []types.Type
+
+func (p typesByString) Len() int { return len(p) }
+func (p typesByString) Less(i, j int) bool { return p[i].String() < p[j].String() }
+func (p typesByString) Swap(i, j int) { p[i], p[j] = p[j], p[i] }
+
+// methodBit returns the index of x in [a-zA-Z], or 52 if not found.
+func methodBit(x byte) uint64 {
+ switch {
+ case 'a' <= x && x <= 'z':
+ return uint64(x - 'a')
+ case 'A' <= x && x <= 'Z':
+ return uint64(26 + x - 'A')
+ }
+ return 52 // all other bytes
+}
+
+// containsAllIdsOf reports whether the method identifiers of T are a
+// superset of those in U. If U belongs to an interface type, the
+// result is equal to types.Assignable(T, U), but is cheaper to compute.
+//
+// TODO(gri): make this a method of *types.MethodSet.
+//
+func containsAllIdsOf(T, U *types.MethodSet) bool {
+ t, tlen := 0, T.Len()
+ u, ulen := 0, U.Len()
+ for t < tlen && u < ulen {
+ tMeth := T.At(t).Obj()
+ uMeth := U.At(u).Obj()
+ tId := tMeth.Id()
+ uId := uMeth.Id()
+ if tId > uId {
+ // U has a method T lacks: fail.
+ return false
+ }
+ if tId < uId {
+ // T has a method U lacks: ignore it.
+ t++
+ continue
+ }
+ // U and T both have a method of this Id. Check types.
+ if !types.Identical(tMeth.Type(), uMeth.Type()) {
+ return false // type mismatch
+ }
+ u++
+ t++
+ }
+ return u == ulen
+}
diff --git a/godoc/analysis/json.go b/godoc/analysis/json.go
new file mode 100644
index 0000000..f897618
--- /dev/null
+++ b/godoc/analysis/json.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.
+
+package analysis
+
+// This file defines types used by client-side JavaScript.
+
+type anchorJSON struct {
+ Text string // HTML
+ Href string // URL
+}
+
+type commOpJSON struct {
+ Op anchorJSON
+ Fn string
+}
+
+// JavaScript's onClickComm() expects a commJSON.
+type commJSON struct {
+ Ops []commOpJSON
+}
+
+// Indicates one of these forms of fact about a type T:
+// T "is implemented by <ByKind> type <Other>" (ByKind != "", e.g. "array")
+// T "implements <Other>" (ByKind == "")
+type implFactJSON struct {
+ ByKind string `json:",omitempty"`
+ Other anchorJSON
+}
+
+// Implements facts are grouped by form, for ease of reading.
+type implGroupJSON struct {
+ Descr string
+ Facts []implFactJSON
+}
+
+// JavaScript's onClickIdent() expects a TypeInfoJSON.
+type TypeInfoJSON struct {
+ Name string // type name
+ Size, Align int64
+ Methods []anchorJSON
+ ImplGroups []implGroupJSON
+}
+
+// JavaScript's onClickCallees() expects a calleesJSON.
+type calleesJSON struct {
+ Descr string
+ Callees []anchorJSON // markup for called function
+}
+
+type callerJSON struct {
+ Func string
+ Sites []anchorJSON
+}
+
+// JavaScript's onClickCallers() expects a callersJSON.
+type callersJSON struct {
+ Callee string
+ Callers []callerJSON
+}
+
+// JavaScript's cgAddChild requires a global array of PCGNodeJSON
+// called CALLGRAPH, representing the intra-package call graph.
+// The first element is special and represents "all external callers".
+type PCGNodeJSON struct {
+ Func anchorJSON
+ Callees []int // indices within CALLGRAPH of nodes called by this one
+}
diff --git a/godoc/analysis/peers.go b/godoc/analysis/peers.go
new file mode 100644
index 0000000..e1696e2
--- /dev/null
+++ b/godoc/analysis/peers.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 analysis
+
+// This file computes the channel "peers" relation over all pairs of
+// channel operations in the program. The peers are displayed in the
+// lower pane when a channel operation (make, <-, close) is clicked.
+
+// TODO(adonovan): handle calls to reflect.{Select,Recv,Send,Close} too,
+// then enable reflection in PTA.
+
+import (
+ "fmt"
+ "go/token"
+
+ "golang.org/x/tools/go/pointer"
+ "golang.org/x/tools/go/ssa"
+ "golang.org/x/tools/go/types"
+)
+
+func (a *analysis) doChannelPeers(ptsets map[ssa.Value]pointer.Pointer) {
+ addSendRecv := func(j *commJSON, op chanOp) {
+ j.Ops = append(j.Ops, commOpJSON{
+ Op: anchorJSON{
+ Text: op.mode,
+ Href: a.posURL(op.pos, op.len),
+ },
+ Fn: prettyFunc(nil, op.fn),
+ })
+ }
+
+ // Build an undirected bipartite multigraph (binary relation)
+ // of MakeChan ops and send/recv/close ops.
+ //
+ // TODO(adonovan): opt: use channel element types to partition
+ // the O(n^2) problem into subproblems.
+ aliasedOps := make(map[*ssa.MakeChan][]chanOp)
+ opToMakes := make(map[chanOp][]*ssa.MakeChan)
+ for _, op := range a.ops {
+ // Combine the PT sets from all contexts.
+ var makes []*ssa.MakeChan // aliased ops
+ ptr, ok := ptsets[op.ch]
+ if !ok {
+ continue // e.g. channel op in dead code
+ }
+ for _, label := range ptr.PointsTo().Labels() {
+ makechan, ok := label.Value().(*ssa.MakeChan)
+ if !ok {
+ continue // skip intrinsically-created channels for now
+ }
+ if makechan.Pos() == token.NoPos {
+ continue // not possible?
+ }
+ makes = append(makes, makechan)
+ aliasedOps[makechan] = append(aliasedOps[makechan], op)
+ }
+ opToMakes[op] = makes
+ }
+
+ // Now that complete relation is built, build links for ops.
+ for _, op := range a.ops {
+ v := commJSON{
+ Ops: []commOpJSON{}, // (JS wants non-nil)
+ }
+ ops := make(map[chanOp]bool)
+ for _, makechan := range opToMakes[op] {
+ v.Ops = append(v.Ops, commOpJSON{
+ Op: anchorJSON{
+ Text: "made",
+ Href: a.posURL(makechan.Pos()-token.Pos(len("make")),
+ len("make")),
+ },
+ Fn: makechan.Parent().RelString(op.fn.Package().Object),
+ })
+ for _, op := range aliasedOps[makechan] {
+ ops[op] = true
+ }
+ }
+ for op := range ops {
+ addSendRecv(&v, op)
+ }
+
+ // Add links for each aliased op.
+ fi, offset := a.fileAndOffset(op.pos)
+ fi.addLink(aLink{
+ start: offset,
+ end: offset + op.len,
+ title: "show channel ops",
+ onclick: fmt.Sprintf("onClickComm(%d)", fi.addData(v)),
+ })
+ }
+ // Add links for makechan ops themselves.
+ for makechan, ops := range aliasedOps {
+ v := commJSON{
+ Ops: []commOpJSON{}, // (JS wants non-nil)
+ }
+ for _, op := range ops {
+ addSendRecv(&v, op)
+ }
+
+ fi, offset := a.fileAndOffset(makechan.Pos())
+ fi.addLink(aLink{
+ start: offset - len("make"),
+ end: offset,
+ title: "show channel ops",
+ onclick: fmt.Sprintf("onClickComm(%d)", fi.addData(v)),
+ })
+ }
+}
+
+// -- utilities --------------------------------------------------------
+
+// chanOp abstracts an ssa.Send, ssa.Unop(ARROW), close(), or a SelectState.
+// Derived from oracle/peers.go.
+type chanOp struct {
+ ch ssa.Value
+ mode string // sent|received|closed
+ pos token.Pos
+ len int
+ fn *ssa.Function
+}
+
+// chanOps returns a slice of all the channel operations in the instruction.
+// Derived from oracle/peers.go.
+func chanOps(instr ssa.Instruction) []chanOp {
+ fn := instr.Parent()
+ var ops []chanOp
+ switch instr := instr.(type) {
+ case *ssa.UnOp:
+ if instr.Op == token.ARROW {
+ // TODO(adonovan): don't assume <-ch; could be 'range ch'.
+ ops = append(ops, chanOp{instr.X, "received", instr.Pos(), len("<-"), fn})
+ }
+ case *ssa.Send:
+ ops = append(ops, chanOp{instr.Chan, "sent", instr.Pos(), len("<-"), fn})
+ case *ssa.Select:
+ for _, st := range instr.States {
+ mode := "received"
+ if st.Dir == types.SendOnly {
+ mode = "sent"
+ }
+ ops = append(ops, chanOp{st.Chan, mode, st.Pos, len("<-"), fn})
+ }
+ case ssa.CallInstruction:
+ call := instr.Common()
+ if blt, ok := call.Value.(*ssa.Builtin); ok && blt.Name() == "close" {
+ pos := instr.Common().Pos()
+ ops = append(ops, chanOp{call.Args[0], "closed", pos - token.Pos(len("close")), len("close("), fn})
+ }
+ }
+ return ops
+}
diff --git a/godoc/analysis/typeinfo.go b/godoc/analysis/typeinfo.go
new file mode 100644
index 0000000..83e19c1
--- /dev/null
+++ b/godoc/analysis/typeinfo.go
@@ -0,0 +1,232 @@
+// 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 analysis
+
+// This file computes the markup for information from go/types:
+// IMPORTS, identifier RESOLUTION, METHOD SETS, size/alignment, and
+// the IMPLEMENTS relation.
+//
+// IMPORTS links connect import specs to the documentation for the
+// imported package.
+//
+// RESOLUTION links referring identifiers to their defining
+// identifier, and adds tooltips for kind and type.
+//
+// METHOD SETS, size/alignment, and the IMPLEMENTS relation are
+// displayed in the lower pane when a type's defining identifier is
+// clicked.
+
+import (
+ "fmt"
+ "reflect"
+ "strconv"
+ "strings"
+
+ "golang.org/x/tools/go/loader"
+ "golang.org/x/tools/go/types"
+ "golang.org/x/tools/go/types/typeutil"
+)
+
+// TODO(adonovan): audit to make sure it's safe on ill-typed packages.
+
+// TODO(adonovan): use same Sizes as loader.Config.
+var sizes = types.StdSizes{8, 8}
+
+func (a *analysis) doTypeInfo(info *loader.PackageInfo, implements map[*types.Named]implementsFacts) {
+ // We must not assume the corresponding SSA packages were
+ // created (i.e. were transitively error-free).
+
+ // IMPORTS
+ for _, f := range info.Files {
+ // Package decl.
+ fi, offset := a.fileAndOffset(f.Name.Pos())
+ fi.addLink(aLink{
+ start: offset,
+ end: offset + len(f.Name.Name),
+ title: "Package docs for " + info.Pkg.Path(),
+ // TODO(adonovan): fix: we're putting the untrusted Path()
+ // into a trusted field. What's the appropriate sanitizer?
+ href: "/pkg/" + info.Pkg.Path(),
+ })
+
+ // Import specs.
+ for _, imp := range f.Imports {
+ // Remove quotes.
+ L := int(imp.End()-imp.Path.Pos()) - len(`""`)
+ path, _ := strconv.Unquote(imp.Path.Value)
+ fi, offset := a.fileAndOffset(imp.Path.Pos())
+ fi.addLink(aLink{
+ start: offset + 1,
+ end: offset + 1 + L,
+ title: "Package docs for " + path,
+ // TODO(adonovan): fix: we're putting the untrusted path
+ // into a trusted field. What's the appropriate sanitizer?
+ href: "/pkg/" + path,
+ })
+ }
+ }
+
+ // RESOLUTION
+ qualifier := types.RelativeTo(info.Pkg)
+ for id, obj := range info.Uses {
+ // Position of the object definition.
+ pos := obj.Pos()
+ Len := len(obj.Name())
+
+ // Correct the position for non-renaming import specs.
+ // import "sync/atomic"
+ // ^^^^^^^^^^^
+ if obj, ok := obj.(*types.PkgName); ok && id.Name == obj.Imported().Name() {
+ // Assume this is a non-renaming import.
+ // NB: not true for degenerate renamings: `import foo "foo"`.
+ pos++
+ Len = len(obj.Imported().Path())
+ }
+
+ if obj.Pkg() == nil {
+ continue // don't mark up built-ins.
+ }
+
+ fi, offset := a.fileAndOffset(id.NamePos)
+ fi.addLink(aLink{
+ start: offset,
+ end: offset + len(id.Name),
+ title: types.ObjectString(obj, qualifier),
+ href: a.posURL(pos, Len),
+ })
+ }
+
+ // IMPLEMENTS & METHOD SETS
+ for _, obj := range info.Defs {
+ if obj, ok := obj.(*types.TypeName); ok {
+ a.namedType(obj, implements)
+ }
+ }
+}
+
+func (a *analysis) namedType(obj *types.TypeName, implements map[*types.Named]implementsFacts) {
+ qualifier := types.RelativeTo(obj.Pkg())
+ T := obj.Type().(*types.Named)
+ v := &TypeInfoJSON{
+ Name: obj.Name(),
+ Size: sizes.Sizeof(T),
+ Align: sizes.Alignof(T),
+ Methods: []anchorJSON{}, // (JS wants non-nil)
+ }
+
+ // addFact adds the fact "is implemented by T" (by) or
+ // "implements T" (!by) to group.
+ addFact := func(group *implGroupJSON, T types.Type, by bool) {
+ Tobj := deref(T).(*types.Named).Obj()
+ var byKind string
+ if by {
+ // Show underlying kind of implementing type,
+ // e.g. "slice", "array", "struct".
+ s := reflect.TypeOf(T.Underlying()).String()
+ byKind = strings.ToLower(strings.TrimPrefix(s, "*types."))
+ }
+ group.Facts = append(group.Facts, implFactJSON{
+ ByKind: byKind,
+ Other: anchorJSON{
+ Href: a.posURL(Tobj.Pos(), len(Tobj.Name())),
+ Text: types.TypeString(T, qualifier),
+ },
+ })
+ }
+
+ // IMPLEMENTS
+ if r, ok := implements[T]; ok {
+ if isInterface(T) {
+ // "T is implemented by <conc>" ...
+ // "T is implemented by <iface>"...
+ // "T implements <iface>"...
+ group := implGroupJSON{
+ Descr: types.TypeString(T, qualifier),
+ }
+ // Show concrete types first; use two passes.
+ for _, sub := range r.to {
+ if !isInterface(sub) {
+ addFact(&group, sub, true)
+ }
+ }
+ for _, sub := range r.to {
+ if isInterface(sub) {
+ addFact(&group, sub, true)
+ }
+ }
+ for _, super := range r.from {
+ addFact(&group, super, false)
+ }
+ v.ImplGroups = append(v.ImplGroups, group)
+ } else {
+ // T is concrete.
+ if r.from != nil {
+ // "T implements <iface>"...
+ group := implGroupJSON{
+ Descr: types.TypeString(T, qualifier),
+ }
+ for _, super := range r.from {
+ addFact(&group, super, false)
+ }
+ v.ImplGroups = append(v.ImplGroups, group)
+ }
+ if r.fromPtr != nil {
+ // "*C implements <iface>"...
+ group := implGroupJSON{
+ Descr: "*" + types.TypeString(T, qualifier),
+ }
+ for _, psuper := range r.fromPtr {
+ addFact(&group, psuper, false)
+ }
+ v.ImplGroups = append(v.ImplGroups, group)
+ }
+ }
+ }
+
+ // METHOD SETS
+ for _, sel := range typeutil.IntuitiveMethodSet(T, &a.prog.MethodSets) {
+ meth := sel.Obj().(*types.Func)
+ pos := meth.Pos() // may be 0 for error.Error
+ v.Methods = append(v.Methods, anchorJSON{
+ Href: a.posURL(pos, len(meth.Name())),
+ Text: types.SelectionString(sel, qualifier),
+ })
+ }
+
+ // Since there can be many specs per decl, we
+ // can't attach the link to the keyword 'type'
+ // (as we do with 'func'); we use the Ident.
+ fi, offset := a.fileAndOffset(obj.Pos())
+ fi.addLink(aLink{
+ start: offset,
+ end: offset + len(obj.Name()),
+ title: fmt.Sprintf("type info for %s", obj.Name()),
+ onclick: fmt.Sprintf("onClickTypeInfo(%d)", fi.addData(v)),
+ })
+
+ // Add info for exported package-level types to the package info.
+ if obj.Exported() && isPackageLevel(obj) {
+ // TODO(adonovan): Path is not unique!
+ // It is possible to declare a non-test package called x_test.
+ a.result.pkgInfo(obj.Pkg().Path()).addType(v)
+ }
+}
+
+// -- utilities --------------------------------------------------------
+
+func isInterface(T types.Type) bool { return types.IsInterface(T) }
+
+// deref returns a pointer's element type; otherwise it returns typ.
+func deref(typ types.Type) types.Type {
+ if p, ok := typ.Underlying().(*types.Pointer); ok {
+ return p.Elem()
+ }
+ return typ
+}
+
+// isPackageLevel reports whether obj is a package-level object.
+func isPackageLevel(obj types.Object) bool {
+ return obj.Pkg().Scope().Lookup(obj.Name()) == obj
+}
diff --git a/godoc/cmdline.go b/godoc/cmdline.go
new file mode 100644
index 0000000..9502ebb
--- /dev/null
+++ b/godoc/cmdline.go
@@ -0,0 +1,207 @@
+// 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 godoc
+
+import (
+ "fmt"
+ "go/ast"
+ "go/build"
+ "io"
+ "log"
+ "os"
+ pathpkg "path"
+ "path/filepath"
+ "regexp"
+ "strings"
+
+ "golang.org/x/tools/godoc/vfs"
+)
+
+const (
+ target = "/target"
+ cmdPrefix = "cmd/"
+ srcPrefix = "src/"
+ toolsPath = "golang.org/x/tools/cmd/"
+)
+
+// CommandLine returns godoc results to w.
+// Note that it may add a /target path to fs.
+func CommandLine(w io.Writer, fs vfs.NameSpace, pres *Presentation, args []string) error {
+ path := args[0]
+ srcMode := pres.SrcMode
+ cmdMode := strings.HasPrefix(path, cmdPrefix)
+ if strings.HasPrefix(path, srcPrefix) {
+ path = strings.TrimPrefix(path, srcPrefix)
+ srcMode = true
+ }
+ var abspath, relpath string
+ if cmdMode {
+ path = strings.TrimPrefix(path, cmdPrefix)
+ } else {
+ abspath, relpath = paths(fs, pres, path)
+ }
+
+ var mode PageInfoMode
+ if relpath == builtinPkgPath {
+ // the fake built-in package contains unexported identifiers
+ mode = NoFiltering | NoTypeAssoc
+ }
+ if srcMode {
+ // only filter exports if we don't have explicit command-line filter arguments
+ if len(args) > 1 {
+ mode |= NoFiltering
+ }
+ mode |= ShowSource
+ }
+
+ // First, try as package unless forced as command.
+ var info *PageInfo
+ if !cmdMode {
+ info = pres.GetPkgPageInfo(abspath, relpath, mode)
+ }
+
+ // Second, try as command (if the path is not absolute).
+ var cinfo *PageInfo
+ if !filepath.IsAbs(path) {
+ // First try go.tools/cmd.
+ abspath = pathpkg.Join(pres.PkgFSRoot(), toolsPath+path)
+ cinfo = pres.GetCmdPageInfo(abspath, relpath, mode)
+ if cinfo.IsEmpty() {
+ // Then try $GOROOT/cmd.
+ abspath = pathpkg.Join(pres.CmdFSRoot(), path)
+ cinfo = pres.GetCmdPageInfo(abspath, relpath, mode)
+ }
+ }
+
+ // determine what to use
+ if info == nil || info.IsEmpty() {
+ if cinfo != nil && !cinfo.IsEmpty() {
+ // only cinfo exists - switch to cinfo
+ info = cinfo
+ }
+ } else if cinfo != nil && !cinfo.IsEmpty() {
+ // both info and cinfo exist - use cinfo if info
+ // contains only subdirectory information
+ if info.PAst == nil && info.PDoc == nil {
+ info = cinfo
+ } else if relpath != target {
+ // The above check handles the case where an operating system path
+ // is provided (see documentation for paths below). In that case,
+ // relpath is set to "/target" (in anticipation of accessing packages there),
+ // and is therefore not expected to match a command.
+ fmt.Fprintf(w, "use 'godoc %s%s' for documentation on the %s command \n\n", cmdPrefix, relpath, relpath)
+ }
+ }
+
+ if info == nil {
+ return fmt.Errorf("%s: no such directory or package", args[0])
+ }
+ if info.Err != nil {
+ return info.Err
+ }
+
+ if info.PDoc != nil && info.PDoc.ImportPath == target {
+ // Replace virtual /target with actual argument from command line.
+ info.PDoc.ImportPath = args[0]
+ }
+
+ // If we have more than one argument, use the remaining arguments for filtering.
+ if len(args) > 1 {
+ info.IsFiltered = true
+ filterInfo(args[1:], info)
+ }
+
+ packageText := pres.PackageText
+ if pres.HTMLMode {
+ packageText = pres.PackageHTML
+ }
+ if err := packageText.Execute(w, info); err != nil {
+ return err
+ }
+ return nil
+}
+
+// paths determines the paths to use.
+//
+// If we are passed an operating system path like . or ./foo or /foo/bar or c:\mysrc,
+// we need to map that path somewhere in the fs name space so that routines
+// like getPageInfo will see it. We use the arbitrarily-chosen virtual path "/target"
+// for this. That is, if we get passed a directory like the above, we map that
+// directory so that getPageInfo sees it as /target.
+// Returns the absolute and relative paths.
+func paths(fs vfs.NameSpace, pres *Presentation, path string) (string, string) {
+ if filepath.IsAbs(path) {
+ fs.Bind(target, vfs.OS(path), "/", vfs.BindReplace)
+ return target, target
+ }
+ if build.IsLocalImport(path) {
+ cwd, _ := os.Getwd() // ignore errors
+ path = filepath.Join(cwd, path)
+ fs.Bind(target, vfs.OS(path), "/", vfs.BindReplace)
+ return target, target
+ }
+ if bp, _ := build.Import(path, "", build.FindOnly); bp.Dir != "" && bp.ImportPath != "" {
+ fs.Bind(target, vfs.OS(bp.Dir), "/", vfs.BindReplace)
+ return target, bp.ImportPath
+ }
+ return pathpkg.Join(pres.PkgFSRoot(), path), path
+}
+
+// filterInfo updates info to include only the nodes that match the given
+// filter args.
+func filterInfo(args []string, info *PageInfo) {
+ rx, err := makeRx(args)
+ if err != nil {
+ log.Fatalf("illegal regular expression from %v: %v", args, err)
+ }
+
+ filter := func(s string) bool { return rx.MatchString(s) }
+ switch {
+ case info.PAst != nil:
+ newPAst := map[string]*ast.File{}
+ for name, a := range info.PAst {
+ cmap := ast.NewCommentMap(info.FSet, a, a.Comments)
+ a.Comments = []*ast.CommentGroup{} // remove all comments.
+ ast.FilterFile(a, filter)
+ if len(a.Decls) > 0 {
+ newPAst[name] = a
+ }
+ for _, d := range a.Decls {
+ // add back the comments associated with d only
+ comments := cmap.Filter(d).Comments()
+ a.Comments = append(a.Comments, comments...)
+ }
+ }
+ info.PAst = newPAst // add only matching files.
+ case info.PDoc != nil:
+ info.PDoc.Filter(filter)
+ }
+}
+
+// Does s look like a regular expression?
+func isRegexp(s string) bool {
+ return strings.IndexAny(s, ".(|)*+?^$[]") >= 0
+}
+
+// Make a regular expression of the form
+// names[0]|names[1]|...names[len(names)-1].
+// Returns an error if the regular expression is illegal.
+func makeRx(names []string) (*regexp.Regexp, error) {
+ if len(names) == 0 {
+ return nil, fmt.Errorf("no expression provided")
+ }
+ s := ""
+ for i, name := range names {
+ if i > 0 {
+ s += "|"
+ }
+ if isRegexp(name) {
+ s += name
+ } else {
+ s += "^" + name + "$" // must match exactly
+ }
+ }
+ return regexp.Compile(s)
+}
diff --git a/godoc/cmdline_test.go b/godoc/cmdline_test.go
new file mode 100644
index 0000000..602f2bb
--- /dev/null
+++ b/godoc/cmdline_test.go
@@ -0,0 +1,294 @@
+// 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 godoc
+
+import (
+ "bytes"
+ "go/build"
+ "io/ioutil"
+ "os"
+ "path/filepath"
+ "reflect"
+ "regexp"
+ "runtime"
+ "testing"
+ "text/template"
+
+ "golang.org/x/tools/godoc/vfs"
+ "golang.org/x/tools/godoc/vfs/mapfs"
+)
+
+// setupGoroot creates temporary directory to act as GOROOT when running tests
+// that depend upon the build package. It updates build.Default to point to the
+// new GOROOT.
+// It returns a function that can be called to reset build.Default and remove
+// the temporary directory.
+func setupGoroot(t *testing.T) (cleanup func()) {
+ var stdLib = map[string]string{
+ "src/fmt/fmt.go": `// Package fmt implements formatted I/O.
+package fmt
+
+type Stringer interface {
+ String() string
+}
+`,
+ }
+ goroot, err := ioutil.TempDir("", "cmdline_test")
+ if err != nil {
+ t.Fatal(err)
+ }
+ origContext := build.Default
+ build.Default = build.Context{
+ GOROOT: goroot,
+ Compiler: "gc",
+ }
+ for relname, contents := range stdLib {
+ name := filepath.Join(goroot, relname)
+ if err := os.MkdirAll(filepath.Dir(name), 0770); err != nil {
+ t.Fatal(err)
+ }
+ if err := ioutil.WriteFile(name, []byte(contents), 0770); err != nil {
+ t.Fatal(err)
+ }
+ }
+
+ return func() {
+ if err := os.RemoveAll(goroot); err != nil {
+ t.Log(err)
+ }
+ build.Default = origContext
+ }
+}
+
+func TestPaths(t *testing.T) {
+ cleanup := setupGoroot(t)
+ defer cleanup()
+
+ pres := &Presentation{
+ pkgHandler: handlerServer{
+ fsRoot: "/fsroot",
+ },
+ }
+ fs := make(vfs.NameSpace)
+
+ absPath := "/foo/fmt"
+ if runtime.GOOS == "windows" {
+ absPath = `c:\foo\fmt`
+ }
+
+ for _, tc := range []struct {
+ desc string
+ path string
+ expAbs string
+ expRel string
+ }{
+ {
+ "Absolute path",
+ absPath,
+ "/target",
+ "/target",
+ },
+ {
+ "Local import",
+ "../foo/fmt",
+ "/target",
+ "/target",
+ },
+ {
+ "Import",
+ "fmt",
+ "/target",
+ "fmt",
+ },
+ {
+ "Default",
+ "unknownpkg",
+ "/fsroot/unknownpkg",
+ "unknownpkg",
+ },
+ } {
+ abs, rel := paths(fs, pres, tc.path)
+ if abs != tc.expAbs || rel != tc.expRel {
+ t.Errorf("%s: paths(%q) = %s,%s; want %s,%s", tc.desc, tc.path, abs, rel, tc.expAbs, tc.expRel)
+ }
+ }
+}
+
+func TestMakeRx(t *testing.T) {
+ for _, tc := range []struct {
+ desc string
+ names []string
+ exp string
+ }{
+ {
+ desc: "empty string",
+ names: []string{""},
+ exp: `^$`,
+ },
+ {
+ desc: "simple text",
+ names: []string{"a"},
+ exp: `^a$`,
+ },
+ {
+ desc: "two words",
+ names: []string{"foo", "bar"},
+ exp: `^foo$|^bar$`,
+ },
+ {
+ desc: "word & non-trivial",
+ names: []string{"foo", `ab?c`},
+ exp: `^foo$|ab?c`,
+ },
+ {
+ desc: "bad regexp",
+ names: []string{`(."`},
+ exp: `(."`,
+ },
+ } {
+ expRE, expErr := regexp.Compile(tc.exp)
+ if re, err := makeRx(tc.names); !reflect.DeepEqual(err, expErr) && !reflect.DeepEqual(re, expRE) {
+ t.Errorf("%s: makeRx(%v) = %q,%q; want %q,%q", tc.desc, tc.names, re, err, expRE, expErr)
+ }
+ }
+}
+
+func TestCommandLine(t *testing.T) {
+ cleanup := setupGoroot(t)
+ defer cleanup()
+ mfs := mapfs.New(map[string]string{
+ "src/bar/bar.go": `// Package bar is an example.
+package bar
+`,
+ "src/foo/foo.go": `// Package foo.
+package foo
+
+// First function is first.
+func First() {
+}
+
+// Second function is second.
+func Second() {
+}
+`,
+ "src/gen/gen.go": `// Package gen
+package gen
+
+//line notgen.go:3
+// F doc //line 1 should appear
+// line 2 should appear
+func F()
+//line foo.go:100`, // no newline on end to check corner cases!
+ "src/vet/vet.go": `// Package vet
+package vet
+`,
+ "src/cmd/go/doc.go": `// The go command
+package main
+`,
+ "src/cmd/gofmt/doc.go": `// The gofmt command
+package main
+`,
+ "src/cmd/vet/vet.go": `// The vet command
+package main
+`,
+ })
+ fs := make(vfs.NameSpace)
+ fs.Bind("/", mfs, "/", vfs.BindReplace)
+ c := NewCorpus(fs)
+ p := &Presentation{Corpus: c}
+ p.cmdHandler = handlerServer{
+ p: p,
+ c: c,
+ pattern: "/cmd/",
+ fsRoot: "/src/cmd",
+ }
+ p.pkgHandler = handlerServer{
+ p: p,
+ c: c,
+ pattern: "/pkg/",
+ fsRoot: "/src",
+ exclude: []string{"/src/cmd"},
+ }
+ p.initFuncMap()
+ p.PackageText = template.Must(template.New("PackageText").Funcs(p.FuncMap()).Parse(`{{$info := .}}{{$filtered := .IsFiltered}}{{if $filtered}}{{range .PAst}}{{range .Decls}}{{node $info .}}{{end}}{{end}}{{else}}{{with .PAst}}{{range $filename, $ast := .}}{{$filename}}:
+{{node $ $ast}}{{end}}{{end}}{{end}}{{with .PDoc}}{{if $.IsMain}}COMMAND {{.Doc}}{{else}}PACKAGE {{.Doc}}{{end}}{{with .Funcs}}
+{{range .}}{{node $ .Decl}}
+{{comment_text .Doc " " "\t"}}{{end}}{{end}}{{end}}`))
+
+ for _, tc := range []struct {
+ desc string
+ args []string
+ exp string
+ err bool
+ }{
+ {
+ desc: "standard package",
+ args: []string{"fmt"},
+ exp: "PACKAGE Package fmt implements formatted I/O.\n",
+ },
+ {
+ desc: "package",
+ args: []string{"bar"},
+ exp: "PACKAGE Package bar is an example.\n",
+ },
+ {
+ desc: "package w. filter",
+ args: []string{"foo", "First"},
+ exp: "PACKAGE \nfunc First()\n First function is first.\n",
+ },
+ {
+ desc: "package w. bad filter",
+ args: []string{"foo", "DNE"},
+ exp: "PACKAGE ",
+ },
+ {
+ desc: "source mode",
+ args: []string{"src/bar"},
+ exp: "bar/bar.go:\n// Package bar is an example.\npackage bar\n",
+ },
+ {
+ desc: "source mode w. filter",
+ args: []string{"src/foo", "Second"},
+ exp: "// Second function is second.\nfunc Second() {\n}",
+ },
+ {
+ desc: "package w. //line comments",
+ args: []string{"gen", "F"},
+ exp: "PACKAGE \nfunc F()\n F doc //line 1 should appear line 2 should appear\n",
+ },
+ {
+ desc: "command",
+ args: []string{"go"},
+ exp: "COMMAND The go command\n",
+ },
+ {
+ desc: "forced command",
+ args: []string{"cmd/gofmt"},
+ exp: "COMMAND The gofmt command\n",
+ },
+ {
+ desc: "bad arg",
+ args: []string{"doesnotexist"},
+ err: true,
+ },
+ {
+ desc: "both command and package",
+ args: []string{"vet"},
+ exp: "use 'godoc cmd/vet' for documentation on the vet command \n\nPACKAGE Package vet\n",
+ },
+ {
+ desc: "root directory",
+ args: []string{"/"},
+ exp: "",
+ },
+ } {
+ w := new(bytes.Buffer)
+ err := CommandLine(w, fs, p, tc.args)
+ if got, want := w.String(), tc.exp; got != want || tc.err == (err == nil) {
+ t.Errorf("%s: CommandLine(%v) = %q (%v); want %q (%v)",
+ tc.desc, tc.args, got, err, want, tc.err)
+ }
+ }
+}
diff --git a/godoc/corpus.go b/godoc/corpus.go
new file mode 100644
index 0000000..f2c7ebb
--- /dev/null
+++ b/godoc/corpus.go
@@ -0,0 +1,157 @@
+// 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 godoc
+
+import (
+ "errors"
+ pathpkg "path"
+ "time"
+
+ "golang.org/x/tools/godoc/analysis"
+ "golang.org/x/tools/godoc/util"
+ "golang.org/x/tools/godoc/vfs"
+)
+
+// A Corpus holds all the state related to serving and indexing a
+// collection of Go code.
+//
+// Construct a new Corpus with NewCorpus, then modify options,
+// then call its Init method.
+type Corpus struct {
+ fs vfs.FileSystem
+
+ // Verbose logging.
+ Verbose bool
+
+ // IndexEnabled controls whether indexing is enabled.
+ IndexEnabled bool
+
+ // IndexFiles specifies a glob pattern specifying index files.
+ // If not empty, the index is read from these files in sorted
+ // order.
+ IndexFiles string
+
+ // IndexThrottle specifies the indexing throttle value
+ // between 0.0 and 1.0. At 0.0, the indexer always sleeps.
+ // At 1.0, the indexer never sleeps. Because 0.0 is useless
+ // and redundant with setting IndexEnabled to false, the
+ // zero value for IndexThrottle means 0.9.
+ IndexThrottle float64
+
+ // IndexInterval specifies the time to sleep between reindexing
+ // all the sources.
+ // If zero, a default is used. If negative, the index is only
+ // built once.
+ IndexInterval time.Duration
+
+ // IndexDocs enables indexing of Go documentation.
+ // This will produce search results for exported types, functions,
+ // methods, variables, and constants, and will link to the godoc
+ // documentation for those identifiers.
+ IndexDocs bool
+
+ // IndexGoCode enables indexing of Go source code.
+ // This will produce search results for internal and external identifiers
+ // and will link to both declarations and uses of those identifiers in
+ // source code.
+ IndexGoCode bool
+
+ // IndexFullText enables full-text indexing.
+ // This will provide search results for any matching text in any file that
+ // is indexed, including non-Go files (see whitelisted in index.go).
+ // Regexp searching is supported via full-text indexing.
+ IndexFullText bool
+
+ // MaxResults optionally specifies the maximum results for indexing.
+ MaxResults int
+
+ // SummarizePackage optionally specifies a function to
+ // summarize a package. It exists as an optimization to
+ // avoid reading files to parse package comments.
+ //
+ // If SummarizePackage returns false for ok, the caller
+ // ignores all return values and parses the files in the package
+ // as if SummarizePackage were nil.
+ //
+ // If showList is false, the package is hidden from the
+ // package listing.
+ SummarizePackage func(pkg string) (summary string, showList, ok bool)
+
+ // IndexDirectory optionally specifies a function to determine
+ // whether the provided directory should be indexed. The dir
+ // will be of the form "/src/cmd/6a", "/doc/play",
+ // "/src/io", etc.
+ // If nil, all directories are indexed if indexing is enabled.
+ IndexDirectory func(dir string) bool
+
+ testDir string // TODO(bradfitz,adg): migrate old godoc flag? looks unused.
+
+ // Send a value on this channel to trigger a metadata refresh.
+ // It is buffered so that if a signal is not lost if sent
+ // during a refresh.
+ refreshMetadataSignal chan bool
+
+ // file system information
+ fsTree util.RWValue // *Directory tree of packages, updated with each sync (but sync code is removed now)
+ fsModified util.RWValue // timestamp of last call to invalidateIndex
+ docMetadata util.RWValue // mapping from paths to *Metadata
+
+ // SearchIndex is the search index in use.
+ searchIndex util.RWValue
+
+ // Analysis is the result of type and pointer analysis.
+ Analysis analysis.Result
+}
+
+// NewCorpus returns a new Corpus from a filesystem.
+// The returned corpus has all indexing enabled and MaxResults set to 1000.
+// Change or set any options on Corpus before calling the Corpus.Init method.
+func NewCorpus(fs vfs.FileSystem) *Corpus {
+ c := &Corpus{
+ fs: fs,
+ refreshMetadataSignal: make(chan bool, 1),
+
+ MaxResults: 1000,
+ IndexEnabled: true,
+ IndexDocs: true,
+ IndexGoCode: true,
+ IndexFullText: true,
+ }
+ return c
+}
+
+func (c *Corpus) CurrentIndex() (*Index, time.Time) {
+ v, t := c.searchIndex.Get()
+ idx, _ := v.(*Index)
+ return idx, t
+}
+
+func (c *Corpus) FSModifiedTime() time.Time {
+ _, ts := c.fsModified.Get()
+ return ts
+}
+
+// Init initializes Corpus, once options on Corpus are set.
+// It must be called before any subsequent method calls.
+func (c *Corpus) Init() error {
+ // TODO(bradfitz): do this in a goroutine because newDirectory might block for a long time?
+ // It used to be sometimes done in a goroutine before, at least in HTTP server mode.
+ if err := c.initFSTree(); err != nil {
+ return err
+ }
+ c.updateMetadata()
+ go c.refreshMetadataLoop()
+ return nil
+}
+
+func (c *Corpus) initFSTree() error {
+ dir := c.newDirectory(pathpkg.Join("/", c.testDir), -1)
+ if dir == nil {
+ return errors.New("godoc: corpus fstree is nil")
+ }
+ c.fsTree.Set(dir)
+ c.invalidateIndex()
+ return nil
+}
diff --git a/godoc/dirtrees.go b/godoc/dirtrees.go
new file mode 100644
index 0000000..a55b324
--- /dev/null
+++ b/godoc/dirtrees.go
@@ -0,0 +1,336 @@
+// 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.
+
+// This file contains the code dealing with package directory trees.
+
+package godoc
+
+import (
+ "bytes"
+ "go/doc"
+ "go/parser"
+ "go/token"
+ "log"
+ "os"
+ pathpkg "path"
+ "strings"
+)
+
+// Conventional name for directories containing test data.
+// Excluded from directory trees.
+//
+const testdataDirName = "testdata"
+
+type Directory struct {
+ Depth int
+ Path string // directory path; includes Name
+ Name string // directory name
+ HasPkg bool // true if the directory contains at least one package
+ Synopsis string // package documentation, if any
+ Dirs []*Directory // subdirectories
+}
+
+func isGoFile(fi os.FileInfo) bool {
+ name := fi.Name()
+ return !fi.IsDir() &&
+ len(name) > 0 && name[0] != '.' && // ignore .files
+ pathpkg.Ext(name) == ".go"
+}
+
+func isPkgFile(fi os.FileInfo) bool {
+ return isGoFile(fi) &&
+ !strings.HasSuffix(fi.Name(), "_test.go") // ignore test files
+}
+
+func isPkgDir(fi os.FileInfo) bool {
+ name := fi.Name()
+ return fi.IsDir() && len(name) > 0 &&
+ name[0] != '_' && name[0] != '.' // ignore _files and .files
+}
+
+type treeBuilder struct {
+ c *Corpus
+ maxDepth int
+}
+
+func (b *treeBuilder) newDirTree(fset *token.FileSet, path, name string, depth int) *Directory {
+ if name == testdataDirName {
+ return nil
+ }
+
+ if depth >= b.maxDepth {
+ // return a dummy directory so that the parent directory
+ // doesn't get discarded just because we reached the max
+ // directory depth
+ return &Directory{
+ Depth: depth,
+ Path: path,
+ Name: name,
+ }
+ }
+
+ var synopses [3]string // prioritized package documentation (0 == highest priority)
+
+ show := true // show in package listing
+ hasPkgFiles := false
+ haveSummary := false
+
+ if hook := b.c.SummarizePackage; hook != nil {
+ if summary, show0, ok := hook(strings.TrimPrefix(path, "/src/")); ok {
+ hasPkgFiles = true
+ show = show0
+ synopses[0] = summary
+ haveSummary = true
+ }
+ }
+
+ list, _ := b.c.fs.ReadDir(path)
+
+ // determine number of subdirectories and if there are package files
+ var dirchs []chan *Directory
+
+ for _, d := range list {
+ switch {
+ case isPkgDir(d):
+ ch := make(chan *Directory, 1)
+ dirchs = append(dirchs, ch)
+ go func(d os.FileInfo) {
+ name := d.Name()
+ ch <- b.newDirTree(fset, pathpkg.Join(path, name), name, depth+1)
+ }(d)
+ case !haveSummary && isPkgFile(d):
+ // looks like a package file, but may just be a file ending in ".go";
+ // don't just count it yet (otherwise we may end up with hasPkgFiles even
+ // though the directory doesn't contain any real package files - was bug)
+ // no "optimal" package synopsis yet; continue to collect synopses
+ file, err := b.c.parseFile(fset, pathpkg.Join(path, d.Name()),
+ parser.ParseComments|parser.PackageClauseOnly)
+ if err == nil {
+ hasPkgFiles = true
+ if file.Doc != nil {
+ // prioritize documentation
+ i := -1
+ switch file.Name.Name {
+ case name:
+ i = 0 // normal case: directory name matches package name
+ case "main":
+ i = 1 // directory contains a main package
+ default:
+ i = 2 // none of the above
+ }
+ if 0 <= i && i < len(synopses) && synopses[i] == "" {
+ synopses[i] = doc.Synopsis(file.Doc.Text())
+ }
+ }
+ haveSummary = synopses[0] != ""
+ }
+ }
+ }
+
+ // create subdirectory tree
+ var dirs []*Directory
+ for _, ch := range dirchs {
+ if d := <-ch; d != nil {
+ dirs = append(dirs, d)
+ }
+ }
+
+ // if there are no package files and no subdirectories
+ // containing package files, ignore the directory
+ if !hasPkgFiles && len(dirs) == 0 {
+ return nil
+ }
+
+ // select the highest-priority synopsis for the directory entry, if any
+ synopsis := ""
+ for _, synopsis = range synopses {
+ if synopsis != "" {
+ break
+ }
+ }
+
+ return &Directory{
+ Depth: depth,
+ Path: path,
+ Name: name,
+ HasPkg: hasPkgFiles && show, // TODO(bradfitz): add proper Hide field?
+ Synopsis: synopsis,
+ Dirs: dirs,
+ }
+}
+
+// newDirectory creates a new package directory tree with at most maxDepth
+// levels, anchored at root. The result tree is pruned such that it only
+// contains directories that contain package files or that contain
+// subdirectories containing package files (transitively). If a non-nil
+// pathFilter is provided, directory paths additionally must be accepted
+// by the filter (i.e., pathFilter(path) must be true). If a value >= 0 is
+// provided for maxDepth, nodes at larger depths are pruned as well; they
+// are assumed to contain package files even if their contents are not known
+// (i.e., in this case the tree may contain directories w/o any package files).
+//
+func (c *Corpus) newDirectory(root string, maxDepth int) *Directory {
+ // The root could be a symbolic link so use Stat not Lstat.
+ d, err := c.fs.Stat(root)
+ // If we fail here, report detailed error messages; otherwise
+ // is is hard to see why a directory tree was not built.
+ switch {
+ case err != nil:
+ log.Printf("newDirectory(%s): %s", root, err)
+ return nil
+ case root != "/" && !isPkgDir(d):
+ log.Printf("newDirectory(%s): not a package directory", root)
+ return nil
+ case root == "/" && !d.IsDir():
+ log.Printf("newDirectory(%s): not a directory", root)
+ return nil
+ }
+ if maxDepth < 0 {
+ maxDepth = 1e6 // "infinity"
+ }
+ b := treeBuilder{c, maxDepth}
+ // the file set provided is only for local parsing, no position
+ // information escapes and thus we don't need to save the set
+ return b.newDirTree(token.NewFileSet(), root, d.Name(), 0)
+}
+
+func (dir *Directory) writeLeafs(buf *bytes.Buffer) {
+ if dir != nil {
+ if len(dir.Dirs) == 0 {
+ buf.WriteString(dir.Path)
+ buf.WriteByte('\n')
+ return
+ }
+
+ for _, d := range dir.Dirs {
+ d.writeLeafs(buf)
+ }
+ }
+}
+
+func (dir *Directory) walk(c chan<- *Directory, skipRoot bool) {
+ if dir != nil {
+ if !skipRoot {
+ c <- dir
+ }
+ for _, d := range dir.Dirs {
+ d.walk(c, false)
+ }
+ }
+}
+
+func (dir *Directory) iter(skipRoot bool) <-chan *Directory {
+ c := make(chan *Directory)
+ go func() {
+ dir.walk(c, skipRoot)
+ close(c)
+ }()
+ return c
+}
+
+func (dir *Directory) lookupLocal(name string) *Directory {
+ for _, d := range dir.Dirs {
+ if d.Name == name {
+ return d
+ }
+ }
+ return nil
+}
+
+func splitPath(p string) []string {
+ p = strings.TrimPrefix(p, "/")
+ if p == "" {
+ return nil
+ }
+ return strings.Split(p, "/")
+}
+
+// lookup looks for the *Directory for a given path, relative to dir.
+func (dir *Directory) lookup(path string) *Directory {
+ d := splitPath(dir.Path)
+ p := splitPath(path)
+ i := 0
+ for i < len(d) {
+ if i >= len(p) || d[i] != p[i] {
+ return nil
+ }
+ i++
+ }
+ for dir != nil && i < len(p) {
+ dir = dir.lookupLocal(p[i])
+ i++
+ }
+ return dir
+}
+
+// DirEntry describes a directory entry. The Depth and Height values
+// are useful for presenting an entry in an indented fashion.
+//
+type DirEntry struct {
+ Depth int // >= 0
+ Height int // = DirList.MaxHeight - Depth, > 0
+ Path string // directory path; includes Name, relative to DirList root
+ Name string // directory name
+ HasPkg bool // true if the directory contains at least one package
+ Synopsis string // package documentation, if any
+}
+
+type DirList struct {
+ MaxHeight int // directory tree height, > 0
+ List []DirEntry
+}
+
+// listing creates a (linear) directory listing from a directory tree.
+// If skipRoot is set, the root directory itself is excluded from the list.
+// If filter is set, only the directory entries whose paths match the filter
+// are included.
+//
+func (root *Directory) listing(skipRoot bool, filter func(string) bool) *DirList {
+ if root == nil {
+ return nil
+ }
+
+ // determine number of entries n and maximum height
+ n := 0
+ minDepth := 1 << 30 // infinity
+ maxDepth := 0
+ for d := range root.iter(skipRoot) {
+ n++
+ if minDepth > d.Depth {
+ minDepth = d.Depth
+ }
+ if maxDepth < d.Depth {
+ maxDepth = d.Depth
+ }
+ }
+ maxHeight := maxDepth - minDepth + 1
+
+ if n == 0 {
+ return nil
+ }
+
+ // create list
+ list := make([]DirEntry, 0, n)
+ for d := range root.iter(skipRoot) {
+ if filter != nil && !filter(d.Path) {
+ continue
+ }
+ var p DirEntry
+ p.Depth = d.Depth - minDepth
+ p.Height = maxHeight - p.Depth
+ // the path is relative to root.Path - remove the root.Path
+ // prefix (the prefix should always be present but avoid
+ // crashes and check)
+ path := strings.TrimPrefix(d.Path, root.Path)
+ // remove leading separator if any - path must be relative
+ path = strings.TrimPrefix(path, "/")
+ p.Path = path
+ p.Name = d.Name
+ p.HasPkg = d.HasPkg
+ p.Synopsis = d.Synopsis
+ list = append(list, p)
+ }
+
+ return &DirList{maxHeight, list}
+}
diff --git a/godoc/format.go b/godoc/format.go
new file mode 100644
index 0000000..6013238
--- /dev/null
+++ b/godoc/format.go
@@ -0,0 +1,371 @@
+// 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 file implements FormatSelections and FormatText.
+// FormatText is used to HTML-format Go and non-Go source
+// text with line numbers and highlighted sections. It is
+// built on top of FormatSelections, a generic formatter
+// for "selected" text.
+
+package godoc
+
+import (
+ "fmt"
+ "go/scanner"
+ "go/token"
+ "io"
+ "regexp"
+ "strconv"
+ "text/template"
+)
+
+// ----------------------------------------------------------------------------
+// Implementation of FormatSelections
+
+// A Segment describes a text segment [start, end).
+// The zero value of a Segment is a ready-to-use empty segment.
+//
+type Segment struct {
+ start, end int
+}
+
+func (seg *Segment) isEmpty() bool { return seg.start >= seg.end }
+
+// A Selection is an "iterator" function returning a text segment.
+// Repeated calls to a selection return consecutive, non-overlapping,
+// non-empty segments, followed by an infinite sequence of empty
+// segments. The first empty segment marks the end of the selection.
+//
+type Selection func() Segment
+
+// A LinkWriter writes some start or end "tag" to w for the text offset offs.
+// It is called by FormatSelections at the start or end of each link segment.
+//
+type LinkWriter func(w io.Writer, offs int, start bool)
+
+// A SegmentWriter formats a text according to selections and writes it to w.
+// The selections parameter is a bit set indicating which selections provided
+// to FormatSelections overlap with the text segment: If the n'th bit is set
+// in selections, the n'th selection provided to FormatSelections is overlapping
+// with the text.
+//
+type SegmentWriter func(w io.Writer, text []byte, selections int)
+
+// FormatSelections takes a text and writes it to w using link and segment
+// writers lw and sw as follows: lw is invoked for consecutive segment starts
+// and ends as specified through the links selection, and sw is invoked for
+// consecutive segments of text overlapped by the same selections as specified
+// by selections. The link writer lw may be nil, in which case the links
+// Selection is ignored.
+//
+func FormatSelections(w io.Writer, text []byte, lw LinkWriter, links Selection, sw SegmentWriter, selections ...Selection) {
+ // If we have a link writer, make the links
+ // selection the last entry in selections
+ if lw != nil {
+ selections = append(selections, links)
+ }
+
+ // compute the sequence of consecutive segment changes
+ changes := newMerger(selections)
+
+ // The i'th bit in bitset indicates that the text
+ // at the current offset is covered by selections[i].
+ bitset := 0
+ lastOffs := 0
+
+ // Text segments are written in a delayed fashion
+ // such that consecutive segments belonging to the
+ // same selection can be combined (peephole optimization).
+ // last describes the last segment which has not yet been written.
+ var last struct {
+ begin, end int // valid if begin < end
+ bitset int
+ }
+
+ // flush writes the last delayed text segment
+ flush := func() {
+ if last.begin < last.end {
+ sw(w, text[last.begin:last.end], last.bitset)
+ }
+ last.begin = last.end // invalidate last
+ }
+
+ // segment runs the segment [lastOffs, end) with the selection
+ // indicated by bitset through the segment peephole optimizer.
+ segment := func(end int) {
+ if lastOffs < end { // ignore empty segments
+ if last.end != lastOffs || last.bitset != bitset {
+ // the last segment is not adjacent to or
+ // differs from the new one
+ flush()
+ // start a new segment
+ last.begin = lastOffs
+ }
+ last.end = end
+ last.bitset = bitset
+ }
+ }
+
+ for {
+ // get the next segment change
+ index, offs, start := changes.next()
+ if index < 0 || offs > len(text) {
+ // no more segment changes or the next change
+ // is past the end of the text - we're done
+ break
+ }
+ // determine the kind of segment change
+ if lw != nil && index == len(selections)-1 {
+ // we have a link segment change (see start of this function):
+ // format the previous selection segment, write the
+ // link tag and start a new selection segment
+ segment(offs)
+ flush()
+ lastOffs = offs
+ lw(w, offs, start)
+ } else {
+ // we have a selection change:
+ // format the previous selection segment, determine
+ // the new selection bitset and start a new segment
+ segment(offs)
+ lastOffs = offs
+ mask := 1 << uint(index)
+ if start {
+ bitset |= mask
+ } else {
+ bitset &^= mask
+ }
+ }
+ }
+ segment(len(text))
+ flush()
+}
+
+// A merger merges a slice of Selections and produces a sequence of
+// consecutive segment change events through repeated next() calls.
+//
+type merger struct {
+ selections []Selection
+ segments []Segment // segments[i] is the next segment of selections[i]
+}
+
+const infinity int = 2e9
+
+func newMerger(selections []Selection) *merger {
+ segments := make([]Segment, len(selections))
+ for i, sel := range selections {
+ segments[i] = Segment{infinity, infinity}
+ if sel != nil {
+ if seg := sel(); !seg.isEmpty() {
+ segments[i] = seg
+ }
+ }
+ }
+ return &merger{selections, segments}
+}
+
+// next returns the next segment change: index specifies the Selection
+// to which the segment belongs, offs is the segment start or end offset
+// as determined by the start value. If there are no more segment changes,
+// next returns an index value < 0.
+//
+func (m *merger) next() (index, offs int, start bool) {
+ // find the next smallest offset where a segment starts or ends
+ offs = infinity
+ index = -1
+ for i, seg := range m.segments {
+ switch {
+ case seg.start < offs:
+ offs = seg.start
+ index = i
+ start = true
+ case seg.end < offs:
+ offs = seg.end
+ index = i
+ start = false
+ }
+ }
+ if index < 0 {
+ // no offset found => all selections merged
+ return
+ }
+ // offset found - it's either the start or end offset but
+ // either way it is ok to consume the start offset: set it
+ // to infinity so it won't be considered in the following
+ // next call
+ m.segments[index].start = infinity
+ if start {
+ return
+ }
+ // end offset found - consume it
+ m.segments[index].end = infinity
+ // advance to the next segment for that selection
+ seg := m.selections[index]()
+ if !seg.isEmpty() {
+ m.segments[index] = seg
+ }
+ return
+}
+
+// ----------------------------------------------------------------------------
+// Implementation of FormatText
+
+// lineSelection returns the line segments for text as a Selection.
+func lineSelection(text []byte) Selection {
+ i, j := 0, 0
+ return func() (seg Segment) {
+ // find next newline, if any
+ for j < len(text) {
+ j++
+ if text[j-1] == '\n' {
+ break
+ }
+ }
+ if i < j {
+ // text[i:j] constitutes a line
+ seg = Segment{i, j}
+ i = j
+ }
+ return
+ }
+}
+
+// tokenSelection returns, as a selection, the sequence of
+// consecutive occurrences of token sel in the Go src text.
+//
+func tokenSelection(src []byte, sel token.Token) Selection {
+ var s scanner.Scanner
+ fset := token.NewFileSet()
+ file := fset.AddFile("", fset.Base(), len(src))
+ s.Init(file, src, nil, scanner.ScanComments)
+ return func() (seg Segment) {
+ for {
+ pos, tok, lit := s.Scan()
+ if tok == token.EOF {
+ break
+ }
+ offs := file.Offset(pos)
+ if tok == sel {
+ seg = Segment{offs, offs + len(lit)}
+ break
+ }
+ }
+ return
+ }
+}
+
+// makeSelection is a helper function to make a Selection from a slice of pairs.
+// Pairs describing empty segments are ignored.
+//
+func makeSelection(matches [][]int) Selection {
+ i := 0
+ return func() Segment {
+ for i < len(matches) {
+ m := matches[i]
+ i++
+ if m[0] < m[1] {
+ // non-empty segment
+ return Segment{m[0], m[1]}
+ }
+ }
+ return Segment{}
+ }
+}
+
+// regexpSelection computes the Selection for the regular expression expr in text.
+func regexpSelection(text []byte, expr string) Selection {
+ var matches [][]int
+ if rx, err := regexp.Compile(expr); err == nil {
+ matches = rx.FindAllIndex(text, -1)
+ }
+ return makeSelection(matches)
+}
+
+var selRx = regexp.MustCompile(`^([0-9]+):([0-9]+)`)
+
+// RangeSelection computes the Selection for a text range described
+// by the argument str; the range description must match the selRx
+// regular expression.
+func RangeSelection(str string) Selection {
+ m := selRx.FindStringSubmatch(str)
+ if len(m) >= 2 {
+ from, _ := strconv.Atoi(m[1])
+ to, _ := strconv.Atoi(m[2])
+ if from < to {
+ return makeSelection([][]int{{from, to}})
+ }
+ }
+ return nil
+}
+
+// Span tags for all the possible selection combinations that may
+// be generated by FormatText. Selections are indicated by a bitset,
+// and the value of the bitset specifies the tag to be used.
+//
+// bit 0: comments
+// bit 1: highlights
+// bit 2: selections
+//
+var startTags = [][]byte{
+ /* 000 */ []byte(``),
+ /* 001 */ []byte(`<span class="comment">`),
+ /* 010 */ []byte(`<span class="highlight">`),
+ /* 011 */ []byte(`<span class="highlight-comment">`),
+ /* 100 */ []byte(`<span class="selection">`),
+ /* 101 */ []byte(`<span class="selection-comment">`),
+ /* 110 */ []byte(`<span class="selection-highlight">`),
+ /* 111 */ []byte(`<span class="selection-highlight-comment">`),
+}
+
+var endTag = []byte(`</span>`)
+
+func selectionTag(w io.Writer, text []byte, selections int) {
+ if selections < len(startTags) {
+ if tag := startTags[selections]; len(tag) > 0 {
+ w.Write(tag)
+ template.HTMLEscape(w, text)
+ w.Write(endTag)
+ return
+ }
+ }
+ template.HTMLEscape(w, text)
+}
+
+// FormatText HTML-escapes text and writes it to w.
+// Consecutive text segments are wrapped in HTML spans (with tags as
+// defined by startTags and endTag) as follows:
+//
+// - if line >= 0, line number (ln) spans are inserted before each line,
+// starting with the value of line
+// - if the text is Go source, comments get the "comment" span class
+// - each occurrence of the regular expression pattern gets the "highlight"
+// span class
+// - text segments covered by selection get the "selection" span class
+//
+// Comments, highlights, and selections may overlap arbitrarily; the respective
+// HTML span classes are specified in the startTags variable.
+//
+func FormatText(w io.Writer, text []byte, line int, goSource bool, pattern string, selection Selection) {
+ var comments, highlights Selection
+ if goSource {
+ comments = tokenSelection(text, token.COMMENT)
+ }
+ if pattern != "" {
+ highlights = regexpSelection(text, pattern)
+ }
+ if line >= 0 || comments != nil || highlights != nil || selection != nil {
+ var lineTag LinkWriter
+ if line >= 0 {
+ lineTag = func(w io.Writer, _ int, start bool) {
+ if start {
+ fmt.Fprintf(w, "<span id=\"L%d\" class=\"ln\">%6d</span>\t", line, line)
+ line++
+ }
+ }
+ }
+ FormatSelections(w, text, lineTag, lineSelection(text), selectionTag, comments, highlights, selection)
+ } else {
+ template.HTMLEscape(w, text)
+ }
+}
diff --git a/godoc/godoc.go b/godoc/godoc.go
new file mode 100644
index 0000000..6b176c6
--- /dev/null
+++ b/godoc/godoc.go
@@ -0,0 +1,633 @@
+// 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 godoc is a work-in-progress (2013-07-17) package to
+// begin splitting up the godoc binary into multiple pieces.
+//
+// This package comment will evolve over time as this package splits
+// into smaller pieces.
+package godoc // import "golang.org/x/tools/godoc"
+
+import (
+ "bytes"
+ "fmt"
+ "go/ast"
+ "go/doc"
+ "go/format"
+ "go/printer"
+ "go/token"
+ htmltemplate "html/template"
+ "io"
+ "log"
+ "os"
+ pathpkg "path"
+ "regexp"
+ "strconv"
+ "strings"
+ "text/template"
+ "time"
+ "unicode"
+ "unicode/utf8"
+)
+
+// Fake relative package path for built-ins. Documentation for all globals
+// (not just exported ones) will be shown for packages in this directory.
+const builtinPkgPath = "builtin"
+
+// FuncMap defines template functions used in godoc templates.
+//
+// Convention: template function names ending in "_html" or "_url" produce
+// HTML- or URL-escaped strings; all other function results may
+// require explicit escaping in the template.
+func (p *Presentation) FuncMap() template.FuncMap {
+ p.initFuncMapOnce.Do(p.initFuncMap)
+ return p.funcMap
+}
+
+func (p *Presentation) TemplateFuncs() template.FuncMap {
+ p.initFuncMapOnce.Do(p.initFuncMap)
+ return p.templateFuncs
+}
+
+func (p *Presentation) initFuncMap() {
+ if p.Corpus == nil {
+ panic("nil Presentation.Corpus")
+ }
+ p.templateFuncs = template.FuncMap{
+ "code": p.code,
+ }
+ p.funcMap = template.FuncMap{
+ // various helpers
+ "filename": filenameFunc,
+ "repeat": strings.Repeat,
+
+ // access to FileInfos (directory listings)
+ "fileInfoName": fileInfoNameFunc,
+ "fileInfoTime": fileInfoTimeFunc,
+
+ // access to search result information
+ "infoKind_html": infoKind_htmlFunc,
+ "infoLine": p.infoLineFunc,
+ "infoSnippet_html": p.infoSnippet_htmlFunc,
+
+ // formatting of AST nodes
+ "node": p.nodeFunc,
+ "node_html": p.node_htmlFunc,
+ "comment_html": comment_htmlFunc,
+ "comment_text": comment_textFunc,
+ "sanitize": sanitizeFunc,
+
+ // support for URL attributes
+ "pkgLink": pkgLinkFunc,
+ "srcLink": srcLinkFunc,
+ "posLink_url": newPosLink_urlFunc(srcPosLinkFunc),
+ "docLink": docLinkFunc,
+ "queryLink": queryLinkFunc,
+
+ // formatting of Examples
+ "example_html": p.example_htmlFunc,
+ "example_text": p.example_textFunc,
+ "example_name": p.example_nameFunc,
+ "example_suffix": p.example_suffixFunc,
+
+ // formatting of analysis information
+ "callgraph_html": p.callgraph_htmlFunc,
+ "implements_html": p.implements_htmlFunc,
+ "methodset_html": p.methodset_htmlFunc,
+
+ // formatting of Notes
+ "noteTitle": noteTitle,
+
+ // Number operation
+ "multiply": multiply,
+ }
+ if p.URLForSrc != nil {
+ p.funcMap["srcLink"] = p.URLForSrc
+ }
+ if p.URLForSrcPos != nil {
+ p.funcMap["posLink_url"] = newPosLink_urlFunc(p.URLForSrcPos)
+ }
+ if p.URLForSrcQuery != nil {
+ p.funcMap["queryLink"] = p.URLForSrcQuery
+ }
+}
+
+func multiply(a, b int) int { return a * b }
+
+func filenameFunc(path string) string {
+ _, localname := pathpkg.Split(path)
+ return localname
+}
+
+func fileInfoNameFunc(fi os.FileInfo) string {
+ name := fi.Name()
+ if fi.IsDir() {
+ name += "/"
+ }
+ return name
+}
+
+func fileInfoTimeFunc(fi os.FileInfo) string {
+ if t := fi.ModTime(); t.Unix() != 0 {
+ return t.Local().String()
+ }
+ return "" // don't return epoch if time is obviously not set
+}
+
+// The strings in infoKinds must be properly html-escaped.
+var infoKinds = [nKinds]string{
+ PackageClause: "package clause",
+ ImportDecl: "import decl",
+ ConstDecl: "const decl",
+ TypeDecl: "type decl",
+ VarDecl: "var decl",
+ FuncDecl: "func decl",
+ MethodDecl: "method decl",
+ Use: "use",
+}
+
+func infoKind_htmlFunc(info SpotInfo) string {
+ return infoKinds[info.Kind()] // infoKind entries are html-escaped
+}
+
+func (p *Presentation) infoLineFunc(info SpotInfo) int {
+ line := info.Lori()
+ if info.IsIndex() {
+ index, _ := p.Corpus.searchIndex.Get()
+ if index != nil {
+ line = index.(*Index).Snippet(line).Line
+ } else {
+ // no line information available because
+ // we don't have an index - this should
+ // never happen; be conservative and don't
+ // crash
+ line = 0
+ }
+ }
+ return line
+}
+
+func (p *Presentation) infoSnippet_htmlFunc(info SpotInfo) string {
+ if info.IsIndex() {
+ index, _ := p.Corpus.searchIndex.Get()
+ // Snippet.Text was HTML-escaped when it was generated
+ return index.(*Index).Snippet(info.Lori()).Text
+ }
+ return `<span class="alert">no snippet text available</span>`
+}
+
+func (p *Presentation) nodeFunc(info *PageInfo, node interface{}) string {
+ var buf bytes.Buffer
+ p.writeNode(&buf, info.FSet, node)
+ return buf.String()
+}
+
+func (p *Presentation) node_htmlFunc(info *PageInfo, node interface{}, linkify bool) string {
+ var buf1 bytes.Buffer
+ p.writeNode(&buf1, info.FSet, node)
+
+ var buf2 bytes.Buffer
+ if n, _ := node.(ast.Node); n != nil && linkify && p.DeclLinks {
+ LinkifyText(&buf2, buf1.Bytes(), n)
+ } else {
+ FormatText(&buf2, buf1.Bytes(), -1, true, "", nil)
+ }
+
+ return buf2.String()
+}
+
+func comment_htmlFunc(comment string) string {
+ var buf bytes.Buffer
+ // TODO(gri) Provide list of words (e.g. function parameters)
+ // to be emphasized by ToHTML.
+ doc.ToHTML(&buf, comment, nil) // does html-escaping
+ return buf.String()
+}
+
+// punchCardWidth is the number of columns of fixed-width
+// characters to assume when wrapping text. Very few people
+// use terminals or cards smaller than 80 characters, so 80 it is.
+// We do not try to sniff the environment or the tty to adapt to
+// the situation; instead, by using a constant we make sure that
+// godoc always produces the same output regardless of context,
+// a consistency that is lost otherwise. For example, if we sniffed
+// the environment or tty, then http://golang.org/pkg/math/?m=text
+// would depend on the width of the terminal where godoc started,
+// which is clearly bogus. More generally, the Unix tools that behave
+// differently when writing to a tty than when writing to a file have
+// a history of causing confusion (compare `ls` and `ls | cat`), and we
+// want to avoid that mistake here.
+const punchCardWidth = 80
+
+func containsOnlySpace(buf []byte) bool {
+ isNotSpace := func(r rune) bool { return !unicode.IsSpace(r) }
+ return bytes.IndexFunc(buf, isNotSpace) == -1
+}
+
+func comment_textFunc(comment, indent, preIndent string) string {
+ var buf bytes.Buffer
+ doc.ToText(&buf, comment, indent, preIndent, punchCardWidth-2*len(indent))
+ if containsOnlySpace(buf.Bytes()) {
+ return ""
+ }
+ return buf.String()
+}
+
+// sanitizeFunc sanitizes the argument src by replacing newlines with
+// blanks, removing extra blanks, and by removing trailing whitespace
+// and commas before closing parentheses.
+func sanitizeFunc(src string) string {
+ buf := make([]byte, len(src))
+ j := 0 // buf index
+ comma := -1 // comma index if >= 0
+ for i := 0; i < len(src); i++ {
+ ch := src[i]
+ switch ch {
+ case '\t', '\n', ' ':
+ // ignore whitespace at the beginning, after a blank, or after opening parentheses
+ if j == 0 {
+ continue
+ }
+ if p := buf[j-1]; p == ' ' || p == '(' || p == '{' || p == '[' {
+ continue
+ }
+ // replace all whitespace with blanks
+ ch = ' '
+ case ',':
+ comma = j
+ case ')', '}', ']':
+ // remove any trailing comma
+ if comma >= 0 {
+ j = comma
+ }
+ // remove any trailing whitespace
+ if j > 0 && buf[j-1] == ' ' {
+ j--
+ }
+ default:
+ comma = -1
+ }
+ buf[j] = ch
+ j++
+ }
+ // remove trailing blank, if any
+ if j > 0 && buf[j-1] == ' ' {
+ j--
+ }
+ return string(buf[:j])
+}
+
+type PageInfo struct {
+ Dirname string // directory containing the package
+ Err error // error or nil
+
+ // package info
+ FSet *token.FileSet // nil if no package documentation
+ PDoc *doc.Package // nil if no package documentation
+ Examples []*doc.Example // nil if no example code
+ Notes map[string][]*doc.Note // nil if no package Notes
+ PAst map[string]*ast.File // nil if no AST with package exports
+ IsMain bool // true for package main
+ IsFiltered bool // true if results were filtered
+
+ // analysis info
+ TypeInfoIndex map[string]int // index of JSON datum for type T (if -analysis=type)
+ AnalysisData htmltemplate.JS // array of TypeInfoJSON values
+ CallGraph htmltemplate.JS // array of PCGNodeJSON values (if -analysis=pointer)
+ CallGraphIndex map[string]int // maps func name to index in CallGraph
+
+ // directory info
+ Dirs *DirList // nil if no directory information
+ DirTime time.Time // directory time stamp
+ DirFlat bool // if set, show directory in a flat (non-indented) manner
+}
+
+func (info *PageInfo) IsEmpty() bool {
+ return info.Err != nil || info.PAst == nil && info.PDoc == nil && info.Dirs == nil
+}
+
+func pkgLinkFunc(path string) string {
+ // because of the irregular mapping under goroot
+ // we need to correct certain relative paths
+ path = strings.TrimPrefix(path, "/")
+ path = strings.TrimPrefix(path, "src/")
+ path = strings.TrimPrefix(path, "pkg/")
+ return "pkg/" + path
+}
+
+func newPosLink_urlFunc(srcPosLinkFunc func(s string, line, low, high int) string) func(info *PageInfo, n interface{}) string {
+ // n must be an ast.Node or a *doc.Note
+ return func(info *PageInfo, n interface{}) string {
+ var pos, end token.Pos
+
+ switch n := n.(type) {
+ case ast.Node:
+ pos = n.Pos()
+ end = n.End()
+ case *doc.Note:
+ pos = n.Pos
+ end = n.End
+ default:
+ panic(fmt.Sprintf("wrong type for posLink_url template formatter: %T", n))
+ }
+
+ var relpath string
+ var line int
+ var low, high int // selection offset range
+
+ if pos.IsValid() {
+ p := info.FSet.Position(pos)
+ relpath = p.Filename
+ line = p.Line
+ low = p.Offset
+ }
+ if end.IsValid() {
+ high = info.FSet.Position(end).Offset
+ }
+
+ return srcPosLinkFunc(relpath, line, low, high)
+ }
+}
+
+func srcPosLinkFunc(s string, line, low, high int) string {
+ s = srcLinkFunc(s)
+ var buf bytes.Buffer
+ template.HTMLEscape(&buf, []byte(s))
+ // selection ranges are of form "s=low:high"
+ if low < high {
+ fmt.Fprintf(&buf, "?s=%d:%d", low, high) // no need for URL escaping
+ // if we have a selection, position the page
+ // such that the selection is a bit below the top
+ line -= 10
+ if line < 1 {
+ line = 1
+ }
+ }
+ // line id's in html-printed source are of the
+ // form "L%d" where %d stands for the line number
+ if line > 0 {
+ fmt.Fprintf(&buf, "#L%d", line) // no need for URL escaping
+ }
+ return buf.String()
+}
+
+func srcLinkFunc(s string) string {
+ s = pathpkg.Clean("/" + s)
+ if !strings.HasPrefix(s, "/src/") {
+ s = "/src" + s
+ }
+ return s
+}
+
+// queryLinkFunc returns a URL for a line in a source file with a highlighted
+// query term.
+// s is expected to be a path to a source file.
+// query is expected to be a string that has already been appropriately escaped
+// for use in a URL query.
+func queryLinkFunc(s, query string, line int) string {
+ url := pathpkg.Clean("/"+s) + "?h=" + query
+ if line > 0 {
+ url += "#L" + strconv.Itoa(line)
+ }
+ return url
+}
+
+func docLinkFunc(s string, ident string) string {
+ return pathpkg.Clean("/pkg/"+s) + "/#" + ident
+}
+
+func (p *Presentation) example_textFunc(info *PageInfo, funcName, indent string) string {
+ if !p.ShowExamples {
+ return ""
+ }
+
+ var buf bytes.Buffer
+ first := true
+ for _, eg := range info.Examples {
+ name := stripExampleSuffix(eg.Name)
+ if name != funcName {
+ continue
+ }
+
+ if !first {
+ buf.WriteString("\n")
+ }
+ first = false
+
+ // print code
+ cnode := &printer.CommentedNode{Node: eg.Code, Comments: eg.Comments}
+ var buf1 bytes.Buffer
+ p.writeNode(&buf1, info.FSet, cnode)
+ code := buf1.String()
+ // Additional formatting if this is a function body.
+ if n := len(code); n >= 2 && code[0] == '{' && code[n-1] == '}' {
+ // remove surrounding braces
+ code = code[1 : n-1]
+ // unindent
+ code = strings.Replace(code, "\n ", "\n", -1)
+ }
+ code = strings.Trim(code, "\n")
+ code = strings.Replace(code, "\n", "\n\t", -1)
+
+ buf.WriteString(indent)
+ buf.WriteString("Example:\n\t")
+ buf.WriteString(code)
+ buf.WriteString("\n")
+ }
+ return buf.String()
+}
+
+func (p *Presentation) example_htmlFunc(info *PageInfo, funcName string) string {
+ var buf bytes.Buffer
+ for _, eg := range info.Examples {
+ name := stripExampleSuffix(eg.Name)
+
+ if name != funcName {
+ continue
+ }
+
+ // print code
+ cnode := &printer.CommentedNode{Node: eg.Code, Comments: eg.Comments}
+ code := p.node_htmlFunc(info, cnode, true)
+ out := eg.Output
+ wholeFile := true
+
+ // Additional formatting if this is a function body.
+ if n := len(code); n >= 2 && code[0] == '{' && code[n-1] == '}' {
+ wholeFile = false
+ // remove surrounding braces
+ code = code[1 : n-1]
+ // unindent
+ code = strings.Replace(code, "\n ", "\n", -1)
+ // remove output comment
+ if loc := exampleOutputRx.FindStringIndex(code); loc != nil {
+ code = strings.TrimSpace(code[:loc[0]])
+ }
+ }
+
+ // Write out the playground code in standard Go style
+ // (use tabs, no comment highlight, etc).
+ play := ""
+ if eg.Play != nil && p.ShowPlayground {
+ var buf bytes.Buffer
+ if err := format.Node(&buf, info.FSet, eg.Play); err != nil {
+ log.Print(err)
+ } else {
+ play = buf.String()
+ }
+ }
+
+ // Drop output, as the output comment will appear in the code.
+ if wholeFile && play == "" {
+ out = ""
+ }
+
+ if p.ExampleHTML == nil {
+ out = ""
+ return ""
+ }
+
+ err := p.ExampleHTML.Execute(&buf, struct {
+ Name, Doc, Code, Play, Output string
+ }{eg.Name, eg.Doc, code, play, out})
+ if err != nil {
+ log.Print(err)
+ }
+ }
+ return buf.String()
+}
+
+// example_nameFunc takes an example function name and returns its display
+// name. For example, "Foo_Bar_quux" becomes "Foo.Bar (Quux)".
+func (p *Presentation) example_nameFunc(s string) string {
+ name, suffix := splitExampleName(s)
+ // replace _ with . for method names
+ name = strings.Replace(name, "_", ".", 1)
+ // use "Package" if no name provided
+ if name == "" {
+ name = "Package"
+ }
+ return name + suffix
+}
+
+// example_suffixFunc takes an example function name and returns its suffix in
+// parenthesized form. For example, "Foo_Bar_quux" becomes " (Quux)".
+func (p *Presentation) example_suffixFunc(name string) string {
+ _, suffix := splitExampleName(name)
+ return suffix
+}
+
+// implements_html returns the "> Implements" toggle for a package-level named type.
+// Its contents are populated from JSON data by client-side JS at load time.
+func (p *Presentation) implements_htmlFunc(info *PageInfo, typeName string) string {
+ if p.ImplementsHTML == nil {
+ return ""
+ }
+ index, ok := info.TypeInfoIndex[typeName]
+ if !ok {
+ return ""
+ }
+ var buf bytes.Buffer
+ err := p.ImplementsHTML.Execute(&buf, struct{ Index int }{index})
+ if err != nil {
+ log.Print(err)
+ }
+ return buf.String()
+}
+
+// methodset_html returns the "> Method set" toggle for a package-level named type.
+// Its contents are populated from JSON data by client-side JS at load time.
+func (p *Presentation) methodset_htmlFunc(info *PageInfo, typeName string) string {
+ if p.MethodSetHTML == nil {
+ return ""
+ }
+ index, ok := info.TypeInfoIndex[typeName]
+ if !ok {
+ return ""
+ }
+ var buf bytes.Buffer
+ err := p.MethodSetHTML.Execute(&buf, struct{ Index int }{index})
+ if err != nil {
+ log.Print(err)
+ }
+ return buf.String()
+}
+
+// callgraph_html returns the "> Call graph" toggle for a package-level func.
+// Its contents are populated from JSON data by client-side JS at load time.
+func (p *Presentation) callgraph_htmlFunc(info *PageInfo, recv, name string) string {
+ if p.CallGraphHTML == nil {
+ return ""
+ }
+ if recv != "" {
+ // Format must match (*ssa.Function).RelString().
+ name = fmt.Sprintf("(%s).%s", recv, name)
+ }
+ index, ok := info.CallGraphIndex[name]
+ if !ok {
+ return ""
+ }
+ var buf bytes.Buffer
+ err := p.CallGraphHTML.Execute(&buf, struct{ Index int }{index})
+ if err != nil {
+ log.Print(err)
+ }
+ return buf.String()
+}
+
+func noteTitle(note string) string {
+ return strings.Title(strings.ToLower(note))
+}
+
+func startsWithUppercase(s string) bool {
+ r, _ := utf8.DecodeRuneInString(s)
+ return unicode.IsUpper(r)
+}
+
+var exampleOutputRx = regexp.MustCompile(`(?i)//[[:space:]]*output:`)
+
+// stripExampleSuffix strips lowercase braz in Foo_braz or Foo_Bar_braz from name
+// while keeping uppercase Braz in Foo_Braz.
+func stripExampleSuffix(name string) string {
+ if i := strings.LastIndex(name, "_"); i != -1 {
+ if i < len(name)-1 && !startsWithUppercase(name[i+1:]) {
+ name = name[:i]
+ }
+ }
+ return name
+}
+
+func splitExampleName(s string) (name, suffix string) {
+ i := strings.LastIndex(s, "_")
+ if 0 <= i && i < len(s)-1 && !startsWithUppercase(s[i+1:]) {
+ name = s[:i]
+ suffix = " (" + strings.Title(s[i+1:]) + ")"
+ return
+ }
+ name = s
+ return
+}
+
+// Write an AST node to w.
+func (p *Presentation) writeNode(w io.Writer, fset *token.FileSet, x interface{}) {
+ // convert trailing tabs into spaces using a tconv filter
+ // to ensure a good outcome in most browsers (there may still
+ // be tabs in comments and strings, but converting those into
+ // the right number of spaces is much harder)
+ //
+ // TODO(gri) rethink printer flags - perhaps tconv can be eliminated
+ // with an another printer mode (which is more efficiently
+ // implemented in the printer than here with another layer)
+ mode := printer.TabIndent | printer.UseSpaces
+ err := (&printer.Config{Mode: mode, Tabwidth: p.TabWidth}).Fprint(&tconv{p: p, output: w}, fset, x)
+ if err != nil {
+ log.Print(err)
+ }
+}
+
+// WriteNode writes x to w.
+// TODO(bgarcia) Is this method needed? It's just a wrapper for p.writeNode.
+func (p *Presentation) WriteNode(w io.Writer, fset *token.FileSet, x interface{}) {
+ p.writeNode(w, fset, x)
+}
diff --git a/godoc/godoc_test.go b/godoc/godoc_test.go
new file mode 100644
index 0000000..a10a1ab
--- /dev/null
+++ b/godoc/godoc_test.go
@@ -0,0 +1,118 @@
+// 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 godoc
+
+import (
+ "testing"
+)
+
+func TestPkgLinkFunc(t *testing.T) {
+ for _, tc := range []struct {
+ path string
+ want string
+ }{
+ {"/src/fmt", "pkg/fmt"},
+ {"src/fmt", "pkg/fmt"},
+ {"/fmt", "pkg/fmt"},
+ {"fmt", "pkg/fmt"},
+ } {
+ if got := pkgLinkFunc(tc.path); got != tc.want {
+ t.Errorf("pkgLinkFunc(%v) = %v; want %v", tc.path, got, tc.want)
+ }
+ }
+}
+
+func TestSrcPosLinkFunc(t *testing.T) {
+ for _, tc := range []struct {
+ src string
+ line int
+ low int
+ high int
+ want string
+ }{
+ {"/src/fmt/print.go", 42, 30, 50, "/src/fmt/print.go?s=30:50#L32"},
+ {"/src/fmt/print.go", 2, 1, 5, "/src/fmt/print.go?s=1:5#L1"},
+ {"/src/fmt/print.go", 2, 0, 0, "/src/fmt/print.go#L2"},
+ {"/src/fmt/print.go", 0, 0, 0, "/src/fmt/print.go"},
+ {"/src/fmt/print.go", 0, 1, 5, "/src/fmt/print.go?s=1:5#L1"},
+ {"fmt/print.go", 0, 0, 0, "/src/fmt/print.go"},
+ {"fmt/print.go", 0, 1, 5, "/src/fmt/print.go?s=1:5#L1"},
+ } {
+ if got := srcPosLinkFunc(tc.src, tc.line, tc.low, tc.high); got != tc.want {
+ t.Errorf("srcLinkFunc(%v, %v, %v, %v) = %v; want %v", tc.src, tc.line, tc.low, tc.high, got, tc.want)
+ }
+ }
+}
+
+func TestSrcLinkFunc(t *testing.T) {
+ for _, tc := range []struct {
+ src string
+ want string
+ }{
+ {"/src/fmt/print.go", "/src/fmt/print.go"},
+ {"src/fmt/print.go", "/src/fmt/print.go"},
+ {"/fmt/print.go", "/src/fmt/print.go"},
+ {"fmt/print.go", "/src/fmt/print.go"},
+ } {
+ if got := srcLinkFunc(tc.src); got != tc.want {
+ t.Errorf("srcLinkFunc(%v) = %v; want %v", tc.src, got, tc.want)
+ }
+ }
+}
+
+func TestQueryLinkFunc(t *testing.T) {
+ for _, tc := range []struct {
+ src string
+ query string
+ line int
+ want string
+ }{
+ {"/src/fmt/print.go", "Sprintf", 33, "/src/fmt/print.go?h=Sprintf#L33"},
+ {"/src/fmt/print.go", "Sprintf", 0, "/src/fmt/print.go?h=Sprintf"},
+ {"src/fmt/print.go", "EOF", 33, "/src/fmt/print.go?h=EOF#L33"},
+ {"src/fmt/print.go", "a%3f+%26b", 1, "/src/fmt/print.go?h=a%3f+%26b#L1"},
+ } {
+ if got := queryLinkFunc(tc.src, tc.query, tc.line); got != tc.want {
+ t.Errorf("queryLinkFunc(%v, %v, %v) = %v; want %v", tc.src, tc.query, tc.line, got, tc.want)
+ }
+ }
+}
+
+func TestDocLinkFunc(t *testing.T) {
+ for _, tc := range []struct {
+ src string
+ ident string
+ want string
+ }{
+ {"fmt", "Sprintf", "/pkg/fmt/#Sprintf"},
+ {"fmt", "EOF", "/pkg/fmt/#EOF"},
+ } {
+ if got := docLinkFunc(tc.src, tc.ident); got != tc.want {
+ t.Errorf("docLinkFunc(%v, %v) = %v; want %v", tc.src, tc.ident, got, tc.want)
+ }
+ }
+}
+
+func TestSanitizeFunc(t *testing.T) {
+ for _, tc := range []struct {
+ src string
+ want string
+ }{
+ {},
+ {"foo", "foo"},
+ {"func f()", "func f()"},
+ {"func f(a int,)", "func f(a int)"},
+ {"func f(a int,\n)", "func f(a int)"},
+ {"func f(\n\ta int,\n\tb int,\n\tc int,\n)", "func f(a int, b int, c int)"},
+ {" ( a, b, c ) ", "(a, b, c)"},
+ {"( a, b, c int, foo bar , )", "(a, b, c int, foo bar)"},
+ {"{ a, b}", "{a, b}"},
+ {"[ a, b]", "[a, b]"},
+ } {
+ if got := sanitizeFunc(tc.src); got != tc.want {
+ t.Errorf("sanitizeFunc(%v) = %v; want %v", tc.src, got, tc.want)
+ }
+ }
+}
diff --git a/godoc/index.go b/godoc/index.go
new file mode 100644
index 0000000..725121a
--- /dev/null
+++ b/godoc/index.go
@@ -0,0 +1,1590 @@
+// 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.
+
+// This file contains the infrastructure to create an
+// identifier and full-text index for a set of Go files.
+//
+// Algorithm for identifier index:
+// - traverse all .go files of the file tree specified by root
+// - for each identifier (word) encountered, collect all occurrences (spots)
+// into a list; this produces a list of spots for each word
+// - reduce the lists: from a list of spots to a list of FileRuns,
+// and from a list of FileRuns into a list of PakRuns
+// - make a HitList from the PakRuns
+//
+// Details:
+// - keep two lists per word: one containing package-level declarations
+// that have snippets, and one containing all other spots
+// - keep the snippets in a separate table indexed by snippet index
+// and store the snippet index in place of the line number in a SpotInfo
+// (the line number for spots with snippets is stored in the snippet)
+// - at the end, create lists of alternative spellings for a given
+// word
+//
+// Algorithm for full text index:
+// - concatenate all source code in a byte buffer (in memory)
+// - add the files to a file set in lockstep as they are added to the byte
+// buffer such that a byte buffer offset corresponds to the Pos value for
+// that file location
+// - create a suffix array from the concatenated sources
+//
+// String lookup in full text index:
+// - use the suffix array to lookup a string's offsets - the offsets
+// correspond to the Pos values relative to the file set
+// - translate the Pos values back into file and line information and
+// sort the result
+
+package godoc
+
+import (
+ "bufio"
+ "bytes"
+ "encoding/gob"
+ "errors"
+ "fmt"
+ "go/ast"
+ "go/doc"
+ "go/parser"
+ "go/token"
+ "index/suffixarray"
+ "io"
+ "log"
+ "os"
+ pathpkg "path"
+ "path/filepath"
+ "regexp"
+ "runtime"
+ "sort"
+ "strconv"
+ "strings"
+ "sync"
+ "time"
+ "unicode"
+
+ "golang.org/x/tools/godoc/util"
+ "golang.org/x/tools/godoc/vfs"
+)
+
+// ----------------------------------------------------------------------------
+// InterfaceSlice is a helper type for sorting interface
+// slices according to some slice-specific sort criteria.
+
+type comparer func(x, y interface{}) bool
+
+type interfaceSlice struct {
+ slice []interface{}
+ less comparer
+}
+
+// ----------------------------------------------------------------------------
+// RunList
+
+// A RunList is a list of entries that can be sorted according to some
+// criteria. A RunList may be compressed by grouping "runs" of entries
+// which are equal (according to the sort critera) into a new RunList of
+// runs. For instance, a RunList containing pairs (x, y) may be compressed
+// into a RunList containing pair runs (x, {y}) where each run consists of
+// a list of y's with the same x.
+type RunList []interface{}
+
+func (h RunList) sort(less comparer) {
+ sort.Sort(&interfaceSlice{h, less})
+}
+
+func (p *interfaceSlice) Len() int { return len(p.slice) }
+func (p *interfaceSlice) Less(i, j int) bool { return p.less(p.slice[i], p.slice[j]) }
+func (p *interfaceSlice) Swap(i, j int) { p.slice[i], p.slice[j] = p.slice[j], p.slice[i] }
+
+// Compress entries which are the same according to a sort criteria
+// (specified by less) into "runs".
+func (h RunList) reduce(less comparer, newRun func(h RunList) interface{}) RunList {
+ if len(h) == 0 {
+ return nil
+ }
+ // len(h) > 0
+
+ // create runs of entries with equal values
+ h.sort(less)
+
+ // for each run, make a new run object and collect them in a new RunList
+ var hh RunList
+ i, x := 0, h[0]
+ for j, y := range h {
+ if less(x, y) {
+ hh = append(hh, newRun(h[i:j]))
+ i, x = j, h[j] // start a new run
+ }
+ }
+ // add final run, if any
+ if i < len(h) {
+ hh = append(hh, newRun(h[i:]))
+ }
+
+ return hh
+}
+
+// ----------------------------------------------------------------------------
+// KindRun
+
+// Debugging support. Disable to see multiple entries per line.
+const removeDuplicates = true
+
+// A KindRun is a run of SpotInfos of the same kind in a given file.
+// The kind (3 bits) is stored in each SpotInfo element; to find the
+// kind of a KindRun, look at any of its elements.
+type KindRun []SpotInfo
+
+// KindRuns are sorted by line number or index. Since the isIndex bit
+// is always the same for all infos in one list we can compare lori's.
+func (k KindRun) Len() int { return len(k) }
+func (k KindRun) Less(i, j int) bool { return k[i].Lori() < k[j].Lori() }
+func (k KindRun) Swap(i, j int) { k[i], k[j] = k[j], k[i] }
+
+// FileRun contents are sorted by Kind for the reduction into KindRuns.
+func lessKind(x, y interface{}) bool { return x.(SpotInfo).Kind() < y.(SpotInfo).Kind() }
+
+// newKindRun allocates a new KindRun from the SpotInfo run h.
+func newKindRun(h RunList) interface{} {
+ run := make(KindRun, len(h))
+ for i, x := range h {
+ run[i] = x.(SpotInfo)
+ }
+
+ // Spots were sorted by file and kind to create this run.
+ // Within this run, sort them by line number or index.
+ sort.Sort(run)
+
+ if removeDuplicates {
+ // Since both the lori and kind field must be
+ // same for duplicates, and since the isIndex
+ // bit is always the same for all infos in one
+ // list we can simply compare the entire info.
+ k := 0
+ prev := SpotInfo(1<<32 - 1) // an unlikely value
+ for _, x := range run {
+ if x != prev {
+ run[k] = x
+ k++
+ prev = x
+ }
+ }
+ run = run[0:k]
+ }
+
+ return run
+}
+
+// ----------------------------------------------------------------------------
+// FileRun
+
+// A Pak describes a Go package.
+type Pak struct {
+ Path string // path of directory containing the package
+ Name string // package name as declared by package clause
+}
+
+// Paks are sorted by name (primary key) and by import path (secondary key).
+func (p *Pak) less(q *Pak) bool {
+ return p.Name < q.Name || p.Name == q.Name && p.Path < q.Path
+}
+
+// A File describes a Go file.
+type File struct {
+ Name string // directory-local file name
+ Pak *Pak // the package to which the file belongs
+}
+
+// Path returns the file path of f.
+func (f *File) Path() string {
+ return pathpkg.Join(f.Pak.Path, f.Name)
+}
+
+// A Spot describes a single occurrence of a word.
+type Spot struct {
+ File *File
+ Info SpotInfo
+}
+
+// A FileRun is a list of KindRuns belonging to the same file.
+type FileRun struct {
+ File *File
+ Groups []KindRun
+}
+
+// Spots are sorted by file path for the reduction into FileRuns.
+func lessSpot(x, y interface{}) bool {
+ fx := x.(Spot).File
+ fy := y.(Spot).File
+ // same as "return fx.Path() < fy.Path()" but w/o computing the file path first
+ px := fx.Pak.Path
+ py := fy.Pak.Path
+ return px < py || px == py && fx.Name < fy.Name
+}
+
+// newFileRun allocates a new FileRun from the Spot run h.
+func newFileRun(h RunList) interface{} {
+ file := h[0].(Spot).File
+
+ // reduce the list of Spots into a list of KindRuns
+ h1 := make(RunList, len(h))
+ for i, x := range h {
+ h1[i] = x.(Spot).Info
+ }
+ h2 := h1.reduce(lessKind, newKindRun)
+
+ // create the FileRun
+ groups := make([]KindRun, len(h2))
+ for i, x := range h2 {
+ groups[i] = x.(KindRun)
+ }
+ return &FileRun{file, groups}
+}
+
+// ----------------------------------------------------------------------------
+// PakRun
+
+// A PakRun describes a run of *FileRuns of a package.
+type PakRun struct {
+ Pak *Pak
+ Files []*FileRun
+}
+
+// Sorting support for files within a PakRun.
+func (p *PakRun) Len() int { return len(p.Files) }
+func (p *PakRun) Less(i, j int) bool { return p.Files[i].File.Name < p.Files[j].File.Name }
+func (p *PakRun) Swap(i, j int) { p.Files[i], p.Files[j] = p.Files[j], p.Files[i] }
+
+// FileRuns are sorted by package for the reduction into PakRuns.
+func lessFileRun(x, y interface{}) bool {
+ return x.(*FileRun).File.Pak.less(y.(*FileRun).File.Pak)
+}
+
+// newPakRun allocates a new PakRun from the *FileRun run h.
+func newPakRun(h RunList) interface{} {
+ pak := h[0].(*FileRun).File.Pak
+ files := make([]*FileRun, len(h))
+ for i, x := range h {
+ files[i] = x.(*FileRun)
+ }
+ run := &PakRun{pak, files}
+ sort.Sort(run) // files were sorted by package; sort them by file now
+ return run
+}
+
+// ----------------------------------------------------------------------------
+// HitList
+
+// A HitList describes a list of PakRuns.
+type HitList []*PakRun
+
+// PakRuns are sorted by package.
+func lessPakRun(x, y interface{}) bool { return x.(*PakRun).Pak.less(y.(*PakRun).Pak) }
+
+func reduce(h0 RunList) HitList {
+ // reduce a list of Spots into a list of FileRuns
+ h1 := h0.reduce(lessSpot, newFileRun)
+ // reduce a list of FileRuns into a list of PakRuns
+ h2 := h1.reduce(lessFileRun, newPakRun)
+ // sort the list of PakRuns by package
+ h2.sort(lessPakRun)
+ // create a HitList
+ h := make(HitList, len(h2))
+ for i, p := range h2 {
+ h[i] = p.(*PakRun)
+ }
+ return h
+}
+
+// filter returns a new HitList created by filtering
+// all PakRuns from h that have a matching pakname.
+func (h HitList) filter(pakname string) HitList {
+ var hh HitList
+ for _, p := range h {
+ if p.Pak.Name == pakname {
+ hh = append(hh, p)
+ }
+ }
+ return hh
+}
+
+// ----------------------------------------------------------------------------
+// AltWords
+
+type wordPair struct {
+ canon string // canonical word spelling (all lowercase)
+ alt string // alternative spelling
+}
+
+// An AltWords describes a list of alternative spellings for a
+// canonical (all lowercase) spelling of a word.
+type AltWords struct {
+ Canon string // canonical word spelling (all lowercase)
+ Alts []string // alternative spelling for the same word
+}
+
+// wordPairs are sorted by their canonical spelling.
+func lessWordPair(x, y interface{}) bool { return x.(*wordPair).canon < y.(*wordPair).canon }
+
+// newAltWords allocates a new AltWords from the *wordPair run h.
+func newAltWords(h RunList) interface{} {
+ canon := h[0].(*wordPair).canon
+ alts := make([]string, len(h))
+ for i, x := range h {
+ alts[i] = x.(*wordPair).alt
+ }
+ return &AltWords{canon, alts}
+}
+
+func (a *AltWords) filter(s string) *AltWords {
+ var alts []string
+ for _, w := range a.Alts {
+ if w != s {
+ alts = append(alts, w)
+ }
+ }
+ if len(alts) > 0 {
+ return &AltWords{a.Canon, alts}
+ }
+ return nil
+}
+
+// Ident stores information about external identifiers in order to create
+// links to package documentation.
+type Ident struct {
+ Path string // e.g. "net/http"
+ Package string // e.g. "http"
+ Name string // e.g. "NewRequest"
+ Doc string // e.g. "NewRequest returns a new Request..."
+}
+
+// byImportCount sorts the given slice of Idents by the import
+// counts of the packages to which they belong.
+type byImportCount struct {
+ Idents []Ident
+ ImportCount map[string]int
+}
+
+func (ic byImportCount) Len() int {
+ return len(ic.Idents)
+}
+
+func (ic byImportCount) Less(i, j int) bool {
+ ri := ic.ImportCount[ic.Idents[i].Path]
+ rj := ic.ImportCount[ic.Idents[j].Path]
+ if ri == rj {
+ return ic.Idents[i].Path < ic.Idents[j].Path
+ }
+ return ri > rj
+}
+
+func (ic byImportCount) Swap(i, j int) {
+ ic.Idents[i], ic.Idents[j] = ic.Idents[j], ic.Idents[i]
+}
+
+func (ic byImportCount) String() string {
+ buf := bytes.NewBuffer([]byte("["))
+ for _, v := range ic.Idents {
+ buf.WriteString(fmt.Sprintf("\n\t%s, %s (%d)", v.Path, v.Name, ic.ImportCount[v.Path]))
+ }
+ buf.WriteString("\n]")
+ return buf.String()
+}
+
+// filter creates a new Ident list where the results match the given
+// package name.
+func (ic byImportCount) filter(pakname string) []Ident {
+ if ic.Idents == nil {
+ return nil
+ }
+ var res []Ident
+ for _, i := range ic.Idents {
+ if i.Package == pakname {
+ res = append(res, i)
+ }
+ }
+ return res
+}
+
+// top returns the top n identifiers.
+func (ic byImportCount) top(n int) []Ident {
+ if len(ic.Idents) > n {
+ return ic.Idents[:n]
+ }
+ return ic.Idents
+}
+
+// ----------------------------------------------------------------------------
+// Indexer
+
+type IndexResult struct {
+ Decls RunList // package-level declarations (with snippets)
+ Others RunList // all other occurrences
+}
+
+// Statistics provides statistics information for an index.
+type Statistics struct {
+ Bytes int // total size of indexed source files
+ Files int // number of indexed source files
+ Lines int // number of lines (all files)
+ Words int // number of different identifiers
+ Spots int // number of identifier occurrences
+}
+
+// An Indexer maintains the data structures and provides the machinery
+// for indexing .go files under a file tree. It implements the path.Visitor
+// interface for walking file trees, and the ast.Visitor interface for
+// walking Go ASTs.
+type Indexer struct {
+ c *Corpus
+ fset *token.FileSet // file set for all indexed files
+ fsOpenGate chan bool // send pre fs.Open; receive on close
+
+ mu sync.Mutex // guards all the following
+ sources bytes.Buffer // concatenated sources
+ strings map[string]string // interned string
+ packages map[Pak]*Pak // interned *Paks
+ words map[string]*IndexResult // RunLists of Spots
+ snippets []*Snippet // indices are stored in SpotInfos
+ current *token.File // last file added to file set
+ file *File // AST for current file
+ decl ast.Decl // AST for current decl
+ stats Statistics
+ throttle *util.Throttle
+ importCount map[string]int // package path ("net/http") => count
+ packagePath map[string]map[string]bool // "template" => "text/template" => true
+ exports map[string]map[string]SpotKind // "net/http" => "ListenAndServe" => FuncDecl
+ curPkgExports map[string]SpotKind
+ idents map[SpotKind]map[string][]Ident // kind => name => list of Idents
+}
+
+func (x *Indexer) intern(s string) string {
+ if s, ok := x.strings[s]; ok {
+ return s
+ }
+ x.strings[s] = s
+ return s
+}
+
+func (x *Indexer) lookupPackage(path, name string) *Pak {
+ // In the source directory tree, more than one package may
+ // live in the same directory. For the packages map, construct
+ // a key that includes both the directory path and the package
+ // name.
+ key := Pak{Path: x.intern(path), Name: x.intern(name)}
+ pak := x.packages[key]
+ if pak == nil {
+ pak = &key
+ x.packages[key] = pak
+ }
+ return pak
+}
+
+func (x *Indexer) addSnippet(s *Snippet) int {
+ index := len(x.snippets)
+ x.snippets = append(x.snippets, s)
+ return index
+}
+
+func (x *Indexer) visitIdent(kind SpotKind, id *ast.Ident) {
+ if id == nil {
+ return
+ }
+ name := x.intern(id.Name)
+
+ switch kind {
+ case TypeDecl, FuncDecl, ConstDecl, VarDecl:
+ x.curPkgExports[name] = kind
+ }
+
+ lists, found := x.words[name]
+ if !found {
+ lists = new(IndexResult)
+ x.words[name] = lists
+ }
+
+ if kind == Use || x.decl == nil {
+ if x.c.IndexGoCode {
+ // not a declaration or no snippet required
+ info := makeSpotInfo(kind, x.current.Line(id.Pos()), false)
+ lists.Others = append(lists.Others, Spot{x.file, info})
+ }
+ } else {
+ // a declaration with snippet
+ index := x.addSnippet(NewSnippet(x.fset, x.decl, id))
+ info := makeSpotInfo(kind, index, true)
+ lists.Decls = append(lists.Decls, Spot{x.file, info})
+ }
+
+ x.stats.Spots++
+}
+
+func (x *Indexer) visitFieldList(kind SpotKind, flist *ast.FieldList) {
+ for _, f := range flist.List {
+ x.decl = nil // no snippets for fields
+ for _, name := range f.Names {
+ x.visitIdent(kind, name)
+ }
+ ast.Walk(x, f.Type)
+ // ignore tag - not indexed at the moment
+ }
+}
+
+func (x *Indexer) visitSpec(kind SpotKind, spec ast.Spec) {
+ switch n := spec.(type) {
+ case *ast.ImportSpec:
+ x.visitIdent(ImportDecl, n.Name)
+ if n.Path != nil {
+ if imp, err := strconv.Unquote(n.Path.Value); err == nil {
+ x.importCount[x.intern(imp)]++
+ }
+ }
+
+ case *ast.ValueSpec:
+ for _, n := range n.Names {
+ x.visitIdent(kind, n)
+ }
+ ast.Walk(x, n.Type)
+ for _, v := range n.Values {
+ ast.Walk(x, v)
+ }
+
+ case *ast.TypeSpec:
+ x.visitIdent(TypeDecl, n.Name)
+ ast.Walk(x, n.Type)
+ }
+}
+
+func (x *Indexer) visitGenDecl(decl *ast.GenDecl) {
+ kind := VarDecl
+ if decl.Tok == token.CONST {
+ kind = ConstDecl
+ }
+ x.decl = decl
+ for _, s := range decl.Specs {
+ x.visitSpec(kind, s)
+ }
+}
+
+func (x *Indexer) Visit(node ast.Node) ast.Visitor {
+ switch n := node.(type) {
+ case nil:
+ // nothing to do
+
+ case *ast.Ident:
+ x.visitIdent(Use, n)
+
+ case *ast.FieldList:
+ x.visitFieldList(VarDecl, n)
+
+ case *ast.InterfaceType:
+ x.visitFieldList(MethodDecl, n.Methods)
+
+ case *ast.DeclStmt:
+ // local declarations should only be *ast.GenDecls;
+ // ignore incorrect ASTs
+ if decl, ok := n.Decl.(*ast.GenDecl); ok {
+ x.decl = nil // no snippets for local declarations
+ x.visitGenDecl(decl)
+ }
+
+ case *ast.GenDecl:
+ x.decl = n
+ x.visitGenDecl(n)
+
+ case *ast.FuncDecl:
+ kind := FuncDecl
+ if n.Recv != nil {
+ kind = MethodDecl
+ ast.Walk(x, n.Recv)
+ }
+ x.decl = n
+ x.visitIdent(kind, n.Name)
+ ast.Walk(x, n.Type)
+ if n.Body != nil {
+ ast.Walk(x, n.Body)
+ }
+
+ case *ast.File:
+ x.decl = nil
+ x.visitIdent(PackageClause, n.Name)
+ for _, d := range n.Decls {
+ ast.Walk(x, d)
+ }
+
+ default:
+ return x
+ }
+
+ return nil
+}
+
+// addFile adds a file to the index if possible and returns the file set file
+// and the file's AST if it was successfully parsed as a Go file. If addFile
+// failed (that is, if the file was not added), it returns file == nil.
+func (x *Indexer) addFile(f vfs.ReadSeekCloser, filename string, goFile bool) (file *token.File, ast *ast.File) {
+ defer f.Close()
+
+ // The file set's base offset and x.sources size must be in lock-step;
+ // this permits the direct mapping of suffix array lookup results to
+ // to corresponding Pos values.
+ //
+ // When a file is added to the file set, its offset base increases by
+ // the size of the file + 1; and the initial base offset is 1. Add an
+ // extra byte to the sources here.
+ x.sources.WriteByte(0)
+
+ // If the sources length doesn't match the file set base at this point
+ // the file set implementation changed or we have another error.
+ base := x.fset.Base()
+ if x.sources.Len() != base {
+ panic("internal error: file base incorrect")
+ }
+
+ // append file contents (src) to x.sources
+ if _, err := x.sources.ReadFrom(f); err == nil {
+ src := x.sources.Bytes()[base:]
+
+ if goFile {
+ // parse the file and in the process add it to the file set
+ if ast, err = parser.ParseFile(x.fset, filename, src, parser.ParseComments); err == nil {
+ file = x.fset.File(ast.Pos()) // ast.Pos() is inside the file
+ return
+ }
+ // file has parse errors, and the AST may be incorrect -
+ // set lines information explicitly and index as ordinary
+ // text file (cannot fall through to the text case below
+ // because the file has already been added to the file set
+ // by the parser)
+ file = x.fset.File(token.Pos(base)) // token.Pos(base) is inside the file
+ file.SetLinesForContent(src)
+ ast = nil
+ return
+ }
+
+ if util.IsText(src) {
+ // only add the file to the file set (for the full text index)
+ file = x.fset.AddFile(filename, x.fset.Base(), len(src))
+ file.SetLinesForContent(src)
+ return
+ }
+ }
+
+ // discard possibly added data
+ x.sources.Truncate(base - 1) // -1 to remove added byte 0 since no file was added
+ return
+}
+
+// Design note: Using an explicit white list of permitted files for indexing
+// makes sure that the important files are included and massively reduces the
+// number of files to index. The advantage over a blacklist is that unexpected
+// (non-blacklisted) files won't suddenly explode the index.
+
+// Files are whitelisted if they have a file name or extension
+// present as key in whitelisted.
+var whitelisted = map[string]bool{
+ ".bash": true,
+ ".c": true,
+ ".cc": true,
+ ".cpp": true,
+ ".cxx": true,
+ ".css": true,
+ ".go": true,
+ ".goc": true,
+ ".h": true,
+ ".hh": true,
+ ".hpp": true,
+ ".hxx": true,
+ ".html": true,
+ ".js": true,
+ ".out": true,
+ ".py": true,
+ ".s": true,
+ ".sh": true,
+ ".txt": true,
+ ".xml": true,
+ "AUTHORS": true,
+ "CONTRIBUTORS": true,
+ "LICENSE": true,
+ "Makefile": true,
+ "PATENTS": true,
+ "README": true,
+}
+
+// isWhitelisted returns true if a file is on the list
+// of "permitted" files for indexing. The filename must
+// be the directory-local name of the file.
+func isWhitelisted(filename string) bool {
+ key := pathpkg.Ext(filename)
+ if key == "" {
+ // file has no extension - use entire filename
+ key = filename
+ }
+ return whitelisted[key]
+}
+
+func (x *Indexer) indexDocs(dirname string, filename string, astFile *ast.File) {
+ pkgName := x.intern(astFile.Name.Name)
+ if pkgName == "main" {
+ return
+ }
+ pkgPath := x.intern(strings.TrimPrefix(strings.TrimPrefix(dirname, "/src/"), "pkg/"))
+ astPkg := ast.Package{
+ Name: pkgName,
+ Files: map[string]*ast.File{
+ filename: astFile,
+ },
+ }
+ var m doc.Mode
+ docPkg := doc.New(&astPkg, dirname, m)
+ addIdent := func(sk SpotKind, name string, docstr string) {
+ if x.idents[sk] == nil {
+ x.idents[sk] = make(map[string][]Ident)
+ }
+ name = x.intern(name)
+ x.idents[sk][name] = append(x.idents[sk][name], Ident{
+ Path: pkgPath,
+ Package: pkgName,
+ Name: name,
+ Doc: doc.Synopsis(docstr),
+ })
+ }
+
+ if x.idents[PackageClause] == nil {
+ x.idents[PackageClause] = make(map[string][]Ident)
+ }
+ // List of words under which the package identifier will be stored.
+ // This includes the package name and the components of the directory
+ // in which it resides.
+ words := strings.Split(pathpkg.Dir(pkgPath), "/")
+ if words[0] == "." {
+ words = []string{}
+ }
+ name := x.intern(docPkg.Name)
+ synopsis := doc.Synopsis(docPkg.Doc)
+ words = append(words, name)
+ pkgIdent := Ident{
+ Path: pkgPath,
+ Package: pkgName,
+ Name: name,
+ Doc: synopsis,
+ }
+ for _, word := range words {
+ word = x.intern(word)
+ found := false
+ pkgs := x.idents[PackageClause][word]
+ for i, p := range pkgs {
+ if p.Path == pkgPath {
+ if docPkg.Doc != "" {
+ p.Doc = synopsis
+ pkgs[i] = p
+ }
+ found = true
+ break
+ }
+ }
+ if !found {
+ x.idents[PackageClause][word] = append(x.idents[PackageClause][word], pkgIdent)
+ }
+ }
+
+ for _, c := range docPkg.Consts {
+ for _, name := range c.Names {
+ addIdent(ConstDecl, name, c.Doc)
+ }
+ }
+ for _, t := range docPkg.Types {
+ addIdent(TypeDecl, t.Name, t.Doc)
+ for _, c := range t.Consts {
+ for _, name := range c.Names {
+ addIdent(ConstDecl, name, c.Doc)
+ }
+ }
+ for _, v := range t.Vars {
+ for _, name := range v.Names {
+ addIdent(VarDecl, name, v.Doc)
+ }
+ }
+ for _, f := range t.Funcs {
+ addIdent(FuncDecl, f.Name, f.Doc)
+ }
+ for _, f := range t.Methods {
+ addIdent(MethodDecl, f.Name, f.Doc)
+ // Change the name of methods to be "<typename>.<methodname>".
+ // They will still be indexed as <methodname>.
+ idents := x.idents[MethodDecl][f.Name]
+ idents[len(idents)-1].Name = x.intern(t.Name + "." + f.Name)
+ }
+ }
+ for _, v := range docPkg.Vars {
+ for _, name := range v.Names {
+ addIdent(VarDecl, name, v.Doc)
+ }
+ }
+ for _, f := range docPkg.Funcs {
+ addIdent(FuncDecl, f.Name, f.Doc)
+ }
+}
+
+func (x *Indexer) indexGoFile(dirname string, filename string, file *token.File, astFile *ast.File) {
+ pkgName := astFile.Name.Name
+
+ if x.c.IndexGoCode {
+ x.current = file
+ pak := x.lookupPackage(dirname, pkgName)
+ x.file = &File{filename, pak}
+ ast.Walk(x, astFile)
+ }
+
+ if x.c.IndexDocs {
+ // Test files are already filtered out in visitFile if IndexGoCode and
+ // IndexFullText are false. Otherwise, check here.
+ isTestFile := (x.c.IndexGoCode || x.c.IndexFullText) &&
+ (strings.HasSuffix(filename, "_test.go") || strings.HasPrefix(dirname, "/test/"))
+ if !isTestFile {
+ x.indexDocs(dirname, filename, astFile)
+ }
+ }
+
+ ppKey := x.intern(pkgName)
+ if _, ok := x.packagePath[ppKey]; !ok {
+ x.packagePath[ppKey] = make(map[string]bool)
+ }
+ pkgPath := x.intern(strings.TrimPrefix(strings.TrimPrefix(dirname, "/src/"), "pkg/"))
+ x.packagePath[ppKey][pkgPath] = true
+
+ // Merge in exported symbols found walking this file into
+ // the map for that package.
+ if len(x.curPkgExports) > 0 {
+ dest, ok := x.exports[pkgPath]
+ if !ok {
+ dest = make(map[string]SpotKind)
+ x.exports[pkgPath] = dest
+ }
+ for k, v := range x.curPkgExports {
+ dest[k] = v
+ }
+ }
+}
+
+func (x *Indexer) visitFile(dirname string, fi os.FileInfo) {
+ if fi.IsDir() || !x.c.IndexEnabled {
+ return
+ }
+
+ filename := pathpkg.Join(dirname, fi.Name())
+ goFile := isGoFile(fi)
+
+ switch {
+ case x.c.IndexFullText:
+ if !isWhitelisted(fi.Name()) {
+ return
+ }
+ case x.c.IndexGoCode:
+ if !goFile {
+ return
+ }
+ case x.c.IndexDocs:
+ if !goFile ||
+ strings.HasSuffix(fi.Name(), "_test.go") ||
+ strings.HasPrefix(dirname, "/test/") {
+ return
+ }
+ default:
+ // No indexing turned on.
+ return
+ }
+
+ x.fsOpenGate <- true
+ defer func() { <-x.fsOpenGate }()
+
+ // open file
+ f, err := x.c.fs.Open(filename)
+ if err != nil {
+ return
+ }
+
+ x.mu.Lock()
+ defer x.mu.Unlock()
+
+ x.throttle.Throttle()
+
+ x.curPkgExports = make(map[string]SpotKind)
+ file, fast := x.addFile(f, filename, goFile)
+ if file == nil {
+ return // addFile failed
+ }
+
+ if fast != nil {
+ x.indexGoFile(dirname, fi.Name(), file, fast)
+ }
+
+ // update statistics
+ x.stats.Bytes += file.Size()
+ x.stats.Files++
+ x.stats.Lines += file.LineCount()
+}
+
+// indexOptions contains information that affects the contents of an index.
+type indexOptions struct {
+ // Docs provides documentation search results.
+ // It is only consulted if IndexEnabled is true.
+ // The default values is true.
+ Docs bool
+
+ // GoCode provides Go source code search results.
+ // It is only consulted if IndexEnabled is true.
+ // The default values is true.
+ GoCode bool
+
+ // FullText provides search results from all files.
+ // It is only consulted if IndexEnabled is true.
+ // The default values is true.
+ FullText bool
+
+ // MaxResults optionally specifies the maximum results for indexing.
+ // The default is 1000.
+ MaxResults int
+}
+
+// ----------------------------------------------------------------------------
+// Index
+
+type LookupResult struct {
+ Decls HitList // package-level declarations (with snippets)
+ Others HitList // all other occurrences
+}
+
+type Index struct {
+ fset *token.FileSet // file set used during indexing; nil if no textindex
+ suffixes *suffixarray.Index // suffixes for concatenated sources; nil if no textindex
+ words map[string]*LookupResult // maps words to hit lists
+ alts map[string]*AltWords // maps canonical(words) to lists of alternative spellings
+ snippets []*Snippet // all snippets, indexed by snippet index
+ stats Statistics
+ importCount map[string]int // package path ("net/http") => count
+ packagePath map[string]map[string]bool // "template" => "text/template" => true
+ exports map[string]map[string]SpotKind // "net/http" => "ListenAndServe" => FuncDecl
+ idents map[SpotKind]map[string][]Ident
+ opts indexOptions
+}
+
+func canonical(w string) string { return strings.ToLower(w) }
+
+// Somewhat arbitrary, but I figure low enough to not hurt disk-based filesystems
+// consuming file descriptors, where some systems have low 256 or 512 limits.
+// Go should have a built-in way to cap fd usage under the ulimit.
+const (
+ maxOpenFiles = 200
+ maxOpenDirs = 50
+)
+
+func (c *Corpus) throttle() float64 {
+ if c.IndexThrottle <= 0 {
+ return 0.9
+ }
+ if c.IndexThrottle > 1.0 {
+ return 1.0
+ }
+ return c.IndexThrottle
+}
+
+// NewIndex creates a new index for the .go files provided by the corpus.
+func (c *Corpus) NewIndex() *Index {
+ // initialize Indexer
+ // (use some reasonably sized maps to start)
+ x := &Indexer{
+ c: c,
+ fset: token.NewFileSet(),
+ fsOpenGate: make(chan bool, maxOpenFiles),
+ strings: make(map[string]string),
+ packages: make(map[Pak]*Pak, 256),
+ words: make(map[string]*IndexResult, 8192),
+ throttle: util.NewThrottle(c.throttle(), 100*time.Millisecond), // run at least 0.1s at a time
+ importCount: make(map[string]int),
+ packagePath: make(map[string]map[string]bool),
+ exports: make(map[string]map[string]SpotKind),
+ idents: make(map[SpotKind]map[string][]Ident, 4),
+ }
+
+ // index all files in the directories given by dirnames
+ var wg sync.WaitGroup // outstanding ReadDir + visitFile
+ dirGate := make(chan bool, maxOpenDirs)
+ for dirname := range c.fsDirnames() {
+ if c.IndexDirectory != nil && !c.IndexDirectory(dirname) {
+ continue
+ }
+ dirGate <- true
+ wg.Add(1)
+ go func(dirname string) {
+ defer func() { <-dirGate }()
+ defer wg.Done()
+
+ list, err := c.fs.ReadDir(dirname)
+ if err != nil {
+ log.Printf("ReadDir(%q): %v; skipping directory", dirname, err)
+ return // ignore this directory
+ }
+ for _, fi := range list {
+ wg.Add(1)
+ go func(fi os.FileInfo) {
+ defer wg.Done()
+ x.visitFile(dirname, fi)
+ }(fi)
+ }
+ }(dirname)
+ }
+ wg.Wait()
+
+ if !c.IndexFullText {
+ // the file set, the current file, and the sources are
+ // not needed after indexing if no text index is built -
+ // help GC and clear them
+ x.fset = nil
+ x.sources.Reset()
+ x.current = nil // contains reference to fset!
+ }
+
+ // for each word, reduce the RunLists into a LookupResult;
+ // also collect the word with its canonical spelling in a
+ // word list for later computation of alternative spellings
+ words := make(map[string]*LookupResult)
+ var wlist RunList
+ for w, h := range x.words {
+ decls := reduce(h.Decls)
+ others := reduce(h.Others)
+ words[w] = &LookupResult{
+ Decls: decls,
+ Others: others,
+ }
+ wlist = append(wlist, &wordPair{canonical(w), w})
+ x.throttle.Throttle()
+ }
+ x.stats.Words = len(words)
+
+ // reduce the word list {canonical(w), w} into
+ // a list of AltWords runs {canonical(w), {w}}
+ alist := wlist.reduce(lessWordPair, newAltWords)
+
+ // convert alist into a map of alternative spellings
+ alts := make(map[string]*AltWords)
+ for i := 0; i < len(alist); i++ {
+ a := alist[i].(*AltWords)
+ alts[a.Canon] = a
+ }
+
+ // create text index
+ var suffixes *suffixarray.Index
+ if c.IndexFullText {
+ suffixes = suffixarray.New(x.sources.Bytes())
+ }
+
+ // sort idents by the number of imports of their respective packages
+ for _, idMap := range x.idents {
+ for _, ir := range idMap {
+ sort.Sort(byImportCount{ir, x.importCount})
+ }
+ }
+
+ return &Index{
+ fset: x.fset,
+ suffixes: suffixes,
+ words: words,
+ alts: alts,
+ snippets: x.snippets,
+ stats: x.stats,
+ importCount: x.importCount,
+ packagePath: x.packagePath,
+ exports: x.exports,
+ idents: x.idents,
+ opts: indexOptions{
+ Docs: x.c.IndexDocs,
+ GoCode: x.c.IndexGoCode,
+ FullText: x.c.IndexFullText,
+ MaxResults: x.c.MaxResults,
+ },
+ }
+}
+
+var ErrFileIndexVersion = errors.New("file index version out of date")
+
+const fileIndexVersion = 3
+
+// fileIndex is the subset of Index that's gob-encoded for use by
+// Index.Write and Index.Read.
+type fileIndex struct {
+ Version int
+ Words map[string]*LookupResult
+ Alts map[string]*AltWords
+ Snippets []*Snippet
+ Fulltext bool
+ Stats Statistics
+ ImportCount map[string]int
+ PackagePath map[string]map[string]bool
+ Exports map[string]map[string]SpotKind
+ Idents map[SpotKind]map[string][]Ident
+ Opts indexOptions
+}
+
+func (x *fileIndex) Write(w io.Writer) error {
+ return gob.NewEncoder(w).Encode(x)
+}
+
+func (x *fileIndex) Read(r io.Reader) error {
+ return gob.NewDecoder(r).Decode(x)
+}
+
+// WriteTo writes the index x to w.
+func (x *Index) WriteTo(w io.Writer) (n int64, err error) {
+ w = countingWriter{&n, w}
+ fulltext := false
+ if x.suffixes != nil {
+ fulltext = true
+ }
+ fx := fileIndex{
+ Version: fileIndexVersion,
+ Words: x.words,
+ Alts: x.alts,
+ Snippets: x.snippets,
+ Fulltext: fulltext,
+ Stats: x.stats,
+ ImportCount: x.importCount,
+ PackagePath: x.packagePath,
+ Exports: x.exports,
+ Idents: x.idents,
+ Opts: x.opts,
+ }
+ if err := fx.Write(w); err != nil {
+ return 0, err
+ }
+ if fulltext {
+ encode := func(x interface{}) error {
+ return gob.NewEncoder(w).Encode(x)
+ }
+ if err := x.fset.Write(encode); err != nil {
+ return 0, err
+ }
+ if err := x.suffixes.Write(w); err != nil {
+ return 0, err
+ }
+ }
+ return n, nil
+}
+
+// ReadFrom reads the index from r into x; x must not be nil.
+// If r does not also implement io.ByteReader, it will be wrapped in a bufio.Reader.
+// If the index is from an old version, the error is ErrFileIndexVersion.
+func (x *Index) ReadFrom(r io.Reader) (n int64, err error) {
+ // We use the ability to read bytes as a plausible surrogate for buffering.
+ if _, ok := r.(io.ByteReader); !ok {
+ r = bufio.NewReader(r)
+ }
+ r = countingReader{&n, r.(byteReader)}
+ var fx fileIndex
+ if err := fx.Read(r); err != nil {
+ return n, err
+ }
+ if fx.Version != fileIndexVersion {
+ return 0, ErrFileIndexVersion
+ }
+ x.words = fx.Words
+ x.alts = fx.Alts
+ x.snippets = fx.Snippets
+ x.stats = fx.Stats
+ x.importCount = fx.ImportCount
+ x.packagePath = fx.PackagePath
+ x.exports = fx.Exports
+ x.idents = fx.Idents
+ x.opts = fx.Opts
+ if fx.Fulltext {
+ x.fset = token.NewFileSet()
+ decode := func(x interface{}) error {
+ return gob.NewDecoder(r).Decode(x)
+ }
+ if err := x.fset.Read(decode); err != nil {
+ return n, err
+ }
+ x.suffixes = new(suffixarray.Index)
+ if err := x.suffixes.Read(r); err != nil {
+ return n, err
+ }
+ }
+ return n, nil
+}
+
+// Stats returns index statistics.
+func (x *Index) Stats() Statistics {
+ return x.stats
+}
+
+// ImportCount returns a map from import paths to how many times they were seen.
+func (x *Index) ImportCount() map[string]int {
+ return x.importCount
+}
+
+// PackagePath returns a map from short package name to a set
+// of full package path names that use that short package name.
+func (x *Index) PackagePath() map[string]map[string]bool {
+ return x.packagePath
+}
+
+// Exports returns a map from full package path to exported
+// symbol name to its type.
+func (x *Index) Exports() map[string]map[string]SpotKind {
+ return x.exports
+}
+
+// Idents returns a map from identifier type to exported
+// symbol name to the list of identifiers matching that name.
+func (x *Index) Idents() map[SpotKind]map[string][]Ident {
+ return x.idents
+}
+
+func (x *Index) lookupWord(w string) (match *LookupResult, alt *AltWords) {
+ match = x.words[w]
+ alt = x.alts[canonical(w)]
+ // remove current spelling from alternatives
+ // (if there is no match, the alternatives do
+ // not contain the current spelling)
+ if match != nil && alt != nil {
+ alt = alt.filter(w)
+ }
+ return
+}
+
+// isIdentifier reports whether s is a Go identifier.
+func isIdentifier(s string) bool {
+ for i, ch := range s {
+ if unicode.IsLetter(ch) || ch == '_' || i > 0 && unicode.IsDigit(ch) {
+ continue
+ }
+ return false
+ }
+ return len(s) > 0
+}
+
+// For a given query, which is either a single identifier or a qualified
+// identifier, Lookup returns a SearchResult containing packages, a LookupResult, a
+// list of alternative spellings, and identifiers, if any. Any and all results
+// may be nil. If the query syntax is wrong, an error is reported.
+func (x *Index) Lookup(query string) (*SearchResult, error) {
+ ss := strings.Split(query, ".")
+
+ // check query syntax
+ for _, s := range ss {
+ if !isIdentifier(s) {
+ return nil, errors.New("all query parts must be identifiers")
+ }
+ }
+ rslt := &SearchResult{
+ Query: query,
+ Idents: make(map[SpotKind][]Ident, 5),
+ }
+ // handle simple and qualified identifiers
+ switch len(ss) {
+ case 1:
+ ident := ss[0]
+ rslt.Hit, rslt.Alt = x.lookupWord(ident)
+ if rslt.Hit != nil {
+ // found a match - filter packages with same name
+ // for the list of packages called ident, if any
+ rslt.Pak = rslt.Hit.Others.filter(ident)
+ }
+ for k, v := range x.idents {
+ const rsltLimit = 50
+ ids := byImportCount{v[ident], x.importCount}
+ rslt.Idents[k] = ids.top(rsltLimit)
+ }
+
+ case 2:
+ pakname, ident := ss[0], ss[1]
+ rslt.Hit, rslt.Alt = x.lookupWord(ident)
+ if rslt.Hit != nil {
+ // found a match - filter by package name
+ // (no paks - package names are not qualified)
+ decls := rslt.Hit.Decls.filter(pakname)
+ others := rslt.Hit.Others.filter(pakname)
+ rslt.Hit = &LookupResult{decls, others}
+ }
+ for k, v := range x.idents {
+ ids := byImportCount{v[ident], x.importCount}
+ rslt.Idents[k] = ids.filter(pakname)
+ }
+
+ default:
+ return nil, errors.New("query is not a (qualified) identifier")
+ }
+
+ return rslt, nil
+}
+
+func (x *Index) Snippet(i int) *Snippet {
+ // handle illegal snippet indices gracefully
+ if 0 <= i && i < len(x.snippets) {
+ return x.snippets[i]
+ }
+ return nil
+}
+
+type positionList []struct {
+ filename string
+ line int
+}
+
+func (list positionList) Len() int { return len(list) }
+func (list positionList) Less(i, j int) bool { return list[i].filename < list[j].filename }
+func (list positionList) Swap(i, j int) { list[i], list[j] = list[j], list[i] }
+
+// unique returns the list sorted and with duplicate entries removed
+func unique(list []int) []int {
+ sort.Ints(list)
+ var last int
+ i := 0
+ for _, x := range list {
+ if i == 0 || x != last {
+ last = x
+ list[i] = x
+ i++
+ }
+ }
+ return list[0:i]
+}
+
+// A FileLines value specifies a file and line numbers within that file.
+type FileLines struct {
+ Filename string
+ Lines []int
+}
+
+// LookupRegexp returns the number of matches and the matches where a regular
+// expression r is found in the full text index. At most n matches are
+// returned (thus found <= n).
+//
+func (x *Index) LookupRegexp(r *regexp.Regexp, n int) (found int, result []FileLines) {
+ if x.suffixes == nil || n <= 0 {
+ return
+ }
+ // n > 0
+
+ var list positionList
+ // FindAllIndex may returns matches that span across file boundaries.
+ // Such matches are unlikely, buf after eliminating them we may end up
+ // with fewer than n matches. If we don't have enough at the end, redo
+ // the search with an increased value n1, but only if FindAllIndex
+ // returned all the requested matches in the first place (if it
+ // returned fewer than that there cannot be more).
+ for n1 := n; found < n; n1 += n - found {
+ found = 0
+ matches := x.suffixes.FindAllIndex(r, n1)
+ // compute files, exclude matches that span file boundaries,
+ // and map offsets to file-local offsets
+ list = make(positionList, len(matches))
+ for _, m := range matches {
+ // by construction, an offset corresponds to the Pos value
+ // for the file set - use it to get the file and line
+ p := token.Pos(m[0])
+ if file := x.fset.File(p); file != nil {
+ if base := file.Base(); base <= m[1] && m[1] <= base+file.Size() {
+ // match [m[0], m[1]) is within the file boundaries
+ list[found].filename = file.Name()
+ list[found].line = file.Line(p)
+ found++
+ }
+ }
+ }
+ if found == n || len(matches) < n1 {
+ // found all matches or there's no chance to find more
+ break
+ }
+ }
+ list = list[0:found]
+ sort.Sort(list) // sort by filename
+
+ // collect matches belonging to the same file
+ var last string
+ var lines []int
+ addLines := func() {
+ if len(lines) > 0 {
+ // remove duplicate lines
+ result = append(result, FileLines{last, unique(lines)})
+ lines = nil
+ }
+ }
+ for _, m := range list {
+ if m.filename != last {
+ addLines()
+ last = m.filename
+ }
+ lines = append(lines, m.line)
+ }
+ addLines()
+
+ return
+}
+
+// InvalidateIndex should be called whenever any of the file systems
+// under godoc's observation change so that the indexer is kicked on.
+func (c *Corpus) invalidateIndex() {
+ c.fsModified.Set(nil)
+ c.refreshMetadata()
+}
+
+// indexUpToDate() returns true if the search index is not older
+// than any of the file systems under godoc's observation.
+//
+func (c *Corpus) indexUpToDate() bool {
+ _, fsTime := c.fsModified.Get()
+ _, siTime := c.searchIndex.Get()
+ return !fsTime.After(siTime)
+}
+
+// feedDirnames feeds the directory names of all directories
+// under the file system given by root to channel c.
+//
+func (c *Corpus) feedDirnames(ch chan<- string) {
+ if dir, _ := c.fsTree.Get(); dir != nil {
+ for d := range dir.(*Directory).iter(false) {
+ ch <- d.Path
+ }
+ }
+}
+
+// fsDirnames() returns a channel sending all directory names
+// of all the file systems under godoc's observation.
+//
+func (c *Corpus) fsDirnames() <-chan string {
+ ch := make(chan string, 256) // buffered for fewer context switches
+ go func() {
+ c.feedDirnames(ch)
+ close(ch)
+ }()
+ return ch
+}
+
+// CompatibleWith reports whether the Index x is compatible with the corpus
+// indexing options set in c.
+func (x *Index) CompatibleWith(c *Corpus) bool {
+ return x.opts.Docs == c.IndexDocs &&
+ x.opts.GoCode == c.IndexGoCode &&
+ x.opts.FullText == c.IndexFullText &&
+ x.opts.MaxResults == c.MaxResults
+}
+
+func (c *Corpus) readIndex(filenames string) error {
+ matches, err := filepath.Glob(filenames)
+ if err != nil {
+ return err
+ } else if matches == nil {
+ return fmt.Errorf("no index files match %q", filenames)
+ }
+ sort.Strings(matches) // make sure files are in the right order
+ files := make([]io.Reader, 0, len(matches))
+ for _, filename := range matches {
+ f, err := os.Open(filename)
+ if err != nil {
+ return err
+ }
+ defer f.Close()
+ files = append(files, f)
+ }
+ return c.ReadIndexFrom(io.MultiReader(files...))
+}
+
+// ReadIndexFrom sets the current index from the serialized version found in r.
+func (c *Corpus) ReadIndexFrom(r io.Reader) error {
+ x := new(Index)
+ if _, err := x.ReadFrom(r); err != nil {
+ return err
+ }
+ if !x.CompatibleWith(c) {
+ return fmt.Errorf("index file options are incompatible: %v", x.opts)
+ }
+ c.searchIndex.Set(x)
+ return nil
+}
+
+func (c *Corpus) UpdateIndex() {
+ if c.Verbose {
+ log.Printf("updating index...")
+ }
+ start := time.Now()
+ index := c.NewIndex()
+ stop := time.Now()
+ c.searchIndex.Set(index)
+ if c.Verbose {
+ secs := stop.Sub(start).Seconds()
+ stats := index.Stats()
+ log.Printf("index updated (%gs, %d bytes of source, %d files, %d lines, %d unique words, %d spots)",
+ secs, stats.Bytes, stats.Files, stats.Lines, stats.Words, stats.Spots)
+ }
+ memstats := new(runtime.MemStats)
+ runtime.ReadMemStats(memstats)
+ if c.Verbose {
+ log.Printf("before GC: bytes = %d footprint = %d", memstats.HeapAlloc, memstats.Sys)
+ }
+ runtime.GC()
+ runtime.ReadMemStats(memstats)
+ if c.Verbose {
+ log.Printf("after GC: bytes = %d footprint = %d", memstats.HeapAlloc, memstats.Sys)
+ }
+}
+
+// RunIndexer runs forever, indexing.
+func (c *Corpus) RunIndexer() {
+ // initialize the index from disk if possible
+ if c.IndexFiles != "" {
+ c.initFSTree()
+ if err := c.readIndex(c.IndexFiles); err != nil {
+ log.Printf("error reading index from file %s: %v", c.IndexFiles, err)
+ }
+ return
+ }
+
+ // Repeatedly update the package directory tree and index.
+ // TODO(bgarcia): Use fsnotify to only update when notified of a filesystem change.
+ for {
+ c.initFSTree()
+ c.UpdateIndex()
+ if c.IndexInterval < 0 {
+ return
+ }
+ delay := 5 * time.Minute // by default, reindex every 5 minutes
+ if c.IndexInterval > 0 {
+ delay = c.IndexInterval
+ }
+ time.Sleep(delay)
+ }
+}
+
+type countingWriter struct {
+ n *int64
+ w io.Writer
+}
+
+func (c countingWriter) Write(p []byte) (n int, err error) {
+ n, err = c.w.Write(p)
+ *c.n += int64(n)
+ return
+}
+
+type byteReader interface {
+ io.Reader
+ io.ByteReader
+}
+
+type countingReader struct {
+ n *int64
+ r byteReader
+}
+
+func (c countingReader) Read(p []byte) (n int, err error) {
+ n, err = c.r.Read(p)
+ *c.n += int64(n)
+ return
+}
+
+func (c countingReader) ReadByte() (b byte, err error) {
+ b, err = c.r.ReadByte()
+ *c.n += 1
+ return
+}
diff --git a/godoc/index_test.go b/godoc/index_test.go
new file mode 100644
index 0000000..a16bdcb
--- /dev/null
+++ b/godoc/index_test.go
@@ -0,0 +1,323 @@
+// 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 godoc
+
+import (
+ "bytes"
+ "reflect"
+ "sort"
+ "strings"
+ "testing"
+
+ "golang.org/x/tools/godoc/vfs/mapfs"
+)
+
+func newCorpus(t *testing.T) *Corpus {
+ c := NewCorpus(mapfs.New(map[string]string{
+ "src/foo/foo.go": `// Package foo is an example.
+package foo
+
+import "bar"
+
+const Pi = 3.1415
+
+var Foos []Foo
+
+// Foo is stuff.
+type Foo struct{}
+
+func New() *Foo {
+ return new(Foo)
+}
+`,
+ "src/bar/bar.go": `// Package bar is another example to test races.
+package bar
+`,
+ "src/other/bar/bar.go": `// Package bar is another bar package.
+package bar
+func X() {}
+`,
+ "src/skip/skip.go": `// Package skip should be skipped.
+package skip
+func Skip() {}
+`,
+ "src/bar/readme.txt": `Whitelisted text file.
+`,
+ "src/bar/baz.zzz": `Text file not whitelisted.
+`,
+ }))
+ c.IndexEnabled = true
+ c.IndexDirectory = func(dir string) bool {
+ return !strings.Contains(dir, "skip")
+ }
+
+ if err := c.Init(); err != nil {
+ t.Fatal(err)
+ }
+ return c
+}
+
+func TestIndex(t *testing.T) {
+ for _, docs := range []bool{true, false} {
+ for _, goCode := range []bool{true, false} {
+ for _, fullText := range []bool{true, false} {
+ c := newCorpus(t)
+ c.IndexDocs = docs
+ c.IndexGoCode = goCode
+ c.IndexFullText = fullText
+ c.UpdateIndex()
+ ix, _ := c.CurrentIndex()
+ if ix == nil {
+ t.Fatal("no index")
+ }
+ t.Logf("docs, goCode, fullText = %v,%v,%v", docs, goCode, fullText)
+ testIndex(t, c, ix)
+ }
+ }
+ }
+}
+
+func TestIndexWriteRead(t *testing.T) {
+ type key struct {
+ docs, goCode, fullText bool
+ }
+ type val struct {
+ buf *bytes.Buffer
+ c *Corpus
+ }
+ m := map[key]val{}
+
+ for _, docs := range []bool{true, false} {
+ for _, goCode := range []bool{true, false} {
+ for _, fullText := range []bool{true, false} {
+ k := key{docs, goCode, fullText}
+ c := newCorpus(t)
+ c.IndexDocs = docs
+ c.IndexGoCode = goCode
+ c.IndexFullText = fullText
+ c.UpdateIndex()
+ ix, _ := c.CurrentIndex()
+ if ix == nil {
+ t.Fatal("no index")
+ }
+ var buf bytes.Buffer
+ nw, err := ix.WriteTo(&buf)
+ if err != nil {
+ t.Fatalf("Index.WriteTo: %v", err)
+ }
+ m[k] = val{bytes.NewBuffer(buf.Bytes()), c}
+ ix2 := new(Index)
+ nr, err := ix2.ReadFrom(&buf)
+ if err != nil {
+ t.Fatalf("Index.ReadFrom: %v", err)
+ }
+ if nr != nw {
+ t.Errorf("Wrote %d bytes to index but read %d", nw, nr)
+ }
+ testIndex(t, c, ix)
+ }
+ }
+ }
+ // Test CompatibleWith
+ for k1, v1 := range m {
+ ix := new(Index)
+ if _, err := ix.ReadFrom(v1.buf); err != nil {
+ t.Fatalf("Index.ReadFrom: %v", err)
+ }
+ for k2, v2 := range m {
+ if got, want := ix.CompatibleWith(v2.c), k1 == k2; got != want {
+ t.Errorf("CompatibleWith = %v; want %v for %v, %v", got, want, k1, k2)
+ }
+ }
+ }
+}
+
+func testIndex(t *testing.T, c *Corpus, ix *Index) {
+ if _, ok := ix.words["Skip"]; ok {
+ t.Errorf("the word Skip was found; expected it to be skipped")
+ }
+ checkStats(t, c, ix)
+ checkImportCount(t, c, ix)
+ checkPackagePath(t, c, ix)
+ checkExports(t, c, ix)
+ checkIdents(t, c, ix)
+}
+
+// checkStats checks the Index's statistics.
+// Some statistics are only set when we're indexing Go code.
+func checkStats(t *testing.T, c *Corpus, ix *Index) {
+ want := Statistics{}
+ if c.IndexFullText {
+ want.Bytes = 314
+ want.Files = 4
+ want.Lines = 21
+ } else if c.IndexDocs || c.IndexGoCode {
+ want.Bytes = 291
+ want.Files = 3
+ want.Lines = 20
+ }
+ if c.IndexGoCode {
+ want.Words = 8
+ want.Spots = 12
+ }
+ if got := ix.Stats(); !reflect.DeepEqual(got, want) {
+ t.Errorf("Stats = %#v; want %#v", got, want)
+ }
+}
+
+// checkImportCount checks the Index's import count map.
+// It is only set when we're indexing Go code.
+func checkImportCount(t *testing.T, c *Corpus, ix *Index) {
+ want := map[string]int{}
+ if c.IndexGoCode {
+ want = map[string]int{
+ "bar": 1,
+ }
+ }
+ if got := ix.ImportCount(); !reflect.DeepEqual(got, want) {
+ t.Errorf("ImportCount = %v; want %v", got, want)
+ }
+}
+
+// checkPackagePath checks the Index's package path map.
+// It is set if at least one of the indexing options is enabled.
+func checkPackagePath(t *testing.T, c *Corpus, ix *Index) {
+ want := map[string]map[string]bool{}
+ if c.IndexDocs || c.IndexGoCode || c.IndexFullText {
+ want = map[string]map[string]bool{
+ "foo": map[string]bool{
+ "foo": true,
+ },
+ "bar": map[string]bool{
+ "bar": true,
+ "other/bar": true,
+ },
+ }
+ }
+ if got := ix.PackagePath(); !reflect.DeepEqual(got, want) {
+ t.Errorf("PackagePath = %v; want %v", got, want)
+ }
+}
+
+// checkExports checks the Index's exports map.
+// It is only set when we're indexing Go code.
+func checkExports(t *testing.T, c *Corpus, ix *Index) {
+ want := map[string]map[string]SpotKind{}
+ if c.IndexGoCode {
+ want = map[string]map[string]SpotKind{
+ "foo": map[string]SpotKind{
+ "Pi": ConstDecl,
+ "Foos": VarDecl,
+ "Foo": TypeDecl,
+ "New": FuncDecl,
+ },
+ "other/bar": map[string]SpotKind{
+ "X": FuncDecl,
+ },
+ }
+ }
+ if got := ix.Exports(); !reflect.DeepEqual(got, want) {
+ t.Errorf("Exports = %v; want %v", got, want)
+ }
+}
+
+// checkIdents checks the Index's indents map.
+// It is only set when we're indexing documentation.
+func checkIdents(t *testing.T, c *Corpus, ix *Index) {
+ want := map[SpotKind]map[string][]Ident{}
+ if c.IndexDocs {
+ want = map[SpotKind]map[string][]Ident{
+ PackageClause: map[string][]Ident{
+ "bar": []Ident{
+ {"bar", "bar", "bar", "Package bar is another example to test races."},
+ {"other/bar", "bar", "bar", "Package bar is another bar package."},
+ },
+ "foo": []Ident{{"foo", "foo", "foo", "Package foo is an example."}},
+ "other": []Ident{{"other/bar", "bar", "bar", "Package bar is another bar package."}},
+ },
+ ConstDecl: map[string][]Ident{
+ "Pi": []Ident{{"foo", "foo", "Pi", ""}},
+ },
+ VarDecl: map[string][]Ident{
+ "Foos": []Ident{{"foo", "foo", "Foos", ""}},
+ },
+ TypeDecl: map[string][]Ident{
+ "Foo": []Ident{{"foo", "foo", "Foo", "Foo is stuff."}},
+ },
+ FuncDecl: map[string][]Ident{
+ "New": []Ident{{"foo", "foo", "New", ""}},
+ "X": []Ident{{"other/bar", "bar", "X", ""}},
+ },
+ }
+ }
+ if got := ix.Idents(); !reflect.DeepEqual(got, want) {
+ t.Errorf("Idents = %v; want %v", got, want)
+ }
+}
+
+func TestIdentResultSort(t *testing.T) {
+ ic := map[string]int{
+ "/a/b/pkg1": 10,
+ "/a/b/pkg2": 2,
+ "/b/d/pkg3": 20,
+ }
+ for _, tc := range []struct {
+ ir []Ident
+ exp []Ident
+ }{
+ {
+ ir: []Ident{
+ {"/a/b/pkg2", "pkg2", "MyFunc2", ""},
+ {"/b/d/pkg3", "pkg3", "MyFunc3", ""},
+ {"/a/b/pkg1", "pkg1", "MyFunc1", ""},
+ },
+ exp: []Ident{
+ {"/b/d/pkg3", "pkg3", "MyFunc3", ""},
+ {"/a/b/pkg1", "pkg1", "MyFunc1", ""},
+ {"/a/b/pkg2", "pkg2", "MyFunc2", ""},
+ },
+ },
+ {
+ ir: []Ident{
+ {"/a/a/pkg1", "pkg1", "MyFunc1", ""},
+ {"/a/b/pkg1", "pkg1", "MyFunc1", ""},
+ },
+ exp: []Ident{
+ {"/a/b/pkg1", "pkg1", "MyFunc1", ""},
+ {"/a/a/pkg1", "pkg1", "MyFunc1", ""},
+ },
+ },
+ } {
+ if sort.Sort(byImportCount{tc.ir, ic}); !reflect.DeepEqual(tc.ir, tc.exp) {
+ t.Errorf("got: %v, want %v", tc.ir, tc.exp)
+ }
+ }
+}
+
+func TestIdentFilter(t *testing.T) {
+ ic := map[string]int{}
+ for _, tc := range []struct {
+ ir []Ident
+ pak string
+ exp []Ident
+ }{
+ {
+ ir: []Ident{
+ {"/a/b/pkg2", "pkg2", "MyFunc2", ""},
+ {"/b/d/pkg3", "pkg3", "MyFunc3", ""},
+ {"/a/b/pkg1", "pkg1", "MyFunc1", ""},
+ },
+ pak: "pkg2",
+ exp: []Ident{
+ {"/a/b/pkg2", "pkg2", "MyFunc2", ""},
+ },
+ },
+ } {
+ res := byImportCount{tc.ir, ic}.filter(tc.pak)
+ if !reflect.DeepEqual(res, tc.exp) {
+ t.Errorf("got: %v, want %v", res, tc.exp)
+ }
+ }
+}
diff --git a/godoc/linkify.go b/godoc/linkify.go
new file mode 100644
index 0000000..0a8fb47
--- /dev/null
+++ b/godoc/linkify.go
@@ -0,0 +1,234 @@
+// 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 LinkifyText which introduces
+// links for identifiers pointing to their declarations.
+// The approach does not cover all cases because godoc
+// doesn't have complete type information, but it's
+// reasonably good for browsing.
+
+package godoc
+
+import (
+ "fmt"
+ "go/ast"
+ "go/token"
+ "io"
+ "strconv"
+)
+
+// LinkifyText HTML-escapes source text and writes it to w.
+// Identifiers that are in a "use" position (i.e., that are
+// not being declared), are wrapped with HTML links pointing
+// to the respective declaration, if possible. Comments are
+// formatted the same way as with FormatText.
+//
+func LinkifyText(w io.Writer, text []byte, n ast.Node) {
+ links := linksFor(n)
+
+ i := 0 // links index
+ prev := "" // prev HTML tag
+ linkWriter := func(w io.Writer, _ int, start bool) {
+ // end tag
+ if !start {
+ if prev != "" {
+ fmt.Fprintf(w, `</%s>`, prev)
+ prev = ""
+ }
+ return
+ }
+
+ // start tag
+ prev = ""
+ if i < len(links) {
+ switch info := links[i]; {
+ case info.path != "" && info.name == "":
+ // package path
+ fmt.Fprintf(w, `<a href="/pkg/%s/">`, info.path)
+ prev = "a"
+ case info.path != "" && info.name != "":
+ // qualified identifier
+ fmt.Fprintf(w, `<a href="/pkg/%s/#%s">`, info.path, info.name)
+ prev = "a"
+ case info.path == "" && info.name != "":
+ // local identifier
+ if info.mode == identVal {
+ fmt.Fprintf(w, `<span id="%s">`, info.name)
+ prev = "span"
+ } else if ast.IsExported(info.name) {
+ fmt.Fprintf(w, `<a href="#%s">`, info.name)
+ prev = "a"
+ }
+ }
+ i++
+ }
+ }
+
+ idents := tokenSelection(text, token.IDENT)
+ comments := tokenSelection(text, token.COMMENT)
+ FormatSelections(w, text, linkWriter, idents, selectionTag, comments)
+}
+
+// A link describes the (HTML) link information for an identifier.
+// The zero value of a link represents "no link".
+//
+type link struct {
+ mode identMode
+ path, name string // package path, identifier name
+}
+
+// linksFor returns the list of links for the identifiers used
+// by node in the same order as they appear in the source.
+//
+func linksFor(node ast.Node) (list []link) {
+ modes := identModesFor(node)
+
+ // NOTE: We are expecting ast.Inspect to call the
+ // callback function in source text order.
+ ast.Inspect(node, func(node ast.Node) bool {
+ switch n := node.(type) {
+ case *ast.Ident:
+ m := modes[n]
+ info := link{mode: m}
+ switch m {
+ case identUse:
+ if n.Obj == nil && predeclared[n.Name] {
+ info.path = builtinPkgPath
+ }
+ info.name = n.Name
+ case identDef:
+ // any declaration expect const or var - empty link
+ case identVal:
+ // const or var declaration
+ info.name = n.Name
+ }
+ list = append(list, info)
+ return false
+ case *ast.SelectorExpr:
+ // Detect qualified identifiers of the form pkg.ident.
+ // If anything fails we return true and collect individual
+ // identifiers instead.
+ if x, _ := n.X.(*ast.Ident); x != nil {
+ // x must be a package for a qualified identifier
+ if obj := x.Obj; obj != nil && obj.Kind == ast.Pkg {
+ if spec, _ := obj.Decl.(*ast.ImportSpec); spec != nil {
+ // spec.Path.Value is the import path
+ if path, err := strconv.Unquote(spec.Path.Value); err == nil {
+ // Register two links, one for the package
+ // and one for the qualified identifier.
+ info := link{path: path}
+ list = append(list, info)
+ info.name = n.Sel.Name
+ list = append(list, info)
+ return false
+ }
+ }
+ }
+ }
+ }
+ return true
+ })
+
+ return
+}
+
+// The identMode describes how an identifier is "used" at its source location.
+type identMode int
+
+const (
+ identUse identMode = iota // identifier is used (must be zero value for identMode)
+ identDef // identifier is defined
+ identVal // identifier is defined in a const or var declaration
+)
+
+// identModesFor returns a map providing the identMode for each identifier used by node.
+func identModesFor(node ast.Node) map[*ast.Ident]identMode {
+ m := make(map[*ast.Ident]identMode)
+
+ ast.Inspect(node, func(node ast.Node) bool {
+ switch n := node.(type) {
+ case *ast.Field:
+ for _, n := range n.Names {
+ m[n] = identDef
+ }
+ case *ast.ImportSpec:
+ if name := n.Name; name != nil {
+ m[name] = identDef
+ }
+ case *ast.ValueSpec:
+ for _, n := range n.Names {
+ m[n] = identVal
+ }
+ case *ast.TypeSpec:
+ m[n.Name] = identDef
+ case *ast.FuncDecl:
+ m[n.Name] = identDef
+ case *ast.AssignStmt:
+ // Short variable declarations only show up if we apply
+ // this code to all source code (as opposed to exported
+ // declarations only).
+ if n.Tok == token.DEFINE {
+ // Some of the lhs variables may be re-declared,
+ // so technically they are not defs. We don't
+ // care for now.
+ for _, x := range n.Lhs {
+ // Each lhs expression should be an
+ // ident, but we are conservative and check.
+ if n, _ := x.(*ast.Ident); n != nil {
+ m[n] = identVal
+ }
+ }
+ }
+ }
+ return true
+ })
+
+ return m
+}
+
+// The predeclared map represents the set of all predeclared identifiers.
+// TODO(gri) This information is also encoded in similar maps in go/doc,
+// but not exported. Consider exporting an accessor and using
+// it instead.
+var predeclared = map[string]bool{
+ "bool": true,
+ "byte": true,
+ "complex64": true,
+ "complex128": true,
+ "error": true,
+ "float32": true,
+ "float64": true,
+ "int": true,
+ "int8": true,
+ "int16": true,
+ "int32": true,
+ "int64": true,
+ "rune": true,
+ "string": true,
+ "uint": true,
+ "uint8": true,
+ "uint16": true,
+ "uint32": true,
+ "uint64": true,
+ "uintptr": true,
+ "true": true,
+ "false": true,
+ "iota": true,
+ "nil": true,
+ "append": true,
+ "cap": true,
+ "close": true,
+ "complex": true,
+ "copy": true,
+ "delete": true,
+ "imag": true,
+ "len": true,
+ "make": true,
+ "new": true,
+ "panic": true,
+ "print": true,
+ "println": true,
+ "real": true,
+ "recover": true,
+}
diff --git a/godoc/meta.go b/godoc/meta.go
new file mode 100644
index 0000000..41ade39
--- /dev/null
+++ b/godoc/meta.go
@@ -0,0 +1,144 @@
+// 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.
+
+package godoc
+
+import (
+ "bytes"
+ "encoding/json"
+ "log"
+ pathpkg "path"
+ "strings"
+ "time"
+
+ "golang.org/x/tools/godoc/vfs"
+)
+
+var (
+ doctype = []byte("<!DOCTYPE ")
+ jsonStart = []byte("<!--{")
+ jsonEnd = []byte("}-->")
+)
+
+// ----------------------------------------------------------------------------
+// Documentation Metadata
+
+// TODO(adg): why are some exported and some aren't? -brad
+type Metadata struct {
+ Title string
+ Subtitle string
+ Template bool // execute as template
+ Path string // canonical path for this page
+ filePath string // filesystem path relative to goroot
+}
+
+func (m *Metadata) FilePath() string { return m.filePath }
+
+// extractMetadata extracts the Metadata from a byte slice.
+// It returns the Metadata value and the remaining data.
+// If no metadata is present the original byte slice is returned.
+//
+func extractMetadata(b []byte) (meta Metadata, tail []byte, err error) {
+ tail = b
+ if !bytes.HasPrefix(b, jsonStart) {
+ return
+ }
+ end := bytes.Index(b, jsonEnd)
+ if end < 0 {
+ return
+ }
+ b = b[len(jsonStart)-1 : end+1] // drop leading <!-- and include trailing }
+ if err = json.Unmarshal(b, &meta); err != nil {
+ return
+ }
+ tail = tail[end+len(jsonEnd):]
+ return
+}
+
+// UpdateMetadata scans $GOROOT/doc for HTML files, reads their metadata,
+// and updates the DocMetadata map.
+func (c *Corpus) updateMetadata() {
+ metadata := make(map[string]*Metadata)
+ var scan func(string) // scan is recursive
+ scan = func(dir string) {
+ fis, err := c.fs.ReadDir(dir)
+ if err != nil {
+ log.Println("updateMetadata:", err)
+ return
+ }
+ for _, fi := range fis {
+ name := pathpkg.Join(dir, fi.Name())
+ if fi.IsDir() {
+ scan(name) // recurse
+ continue
+ }
+ if !strings.HasSuffix(name, ".html") {
+ continue
+ }
+ // Extract metadata from the file.
+ b, err := vfs.ReadFile(c.fs, name)
+ if err != nil {
+ log.Printf("updateMetadata %s: %v", name, err)
+ continue
+ }
+ meta, _, err := extractMetadata(b)
+ if err != nil {
+ log.Printf("updateMetadata: %s: %v", name, err)
+ continue
+ }
+ // Store relative filesystem path in Metadata.
+ meta.filePath = name
+ if meta.Path == "" {
+ // If no Path, canonical path is actual path.
+ meta.Path = meta.filePath
+ }
+ // Store under both paths.
+ metadata[meta.Path] = &meta
+ metadata[meta.filePath] = &meta
+ }
+ }
+ scan("/doc")
+ c.docMetadata.Set(metadata)
+}
+
+// MetadataFor returns the *Metadata for a given relative path or nil if none
+// exists.
+//
+func (c *Corpus) MetadataFor(relpath string) *Metadata {
+ if m, _ := c.docMetadata.Get(); m != nil {
+ meta := m.(map[string]*Metadata)
+ // If metadata for this relpath exists, return it.
+ if p := meta[relpath]; p != nil {
+ return p
+ }
+ // Try with or without trailing slash.
+ if strings.HasSuffix(relpath, "/") {
+ relpath = relpath[:len(relpath)-1]
+ } else {
+ relpath = relpath + "/"
+ }
+ return meta[relpath]
+ }
+ return nil
+}
+
+// refreshMetadata sends a signal to update DocMetadata. If a refresh is in
+// progress the metadata will be refreshed again afterward.
+//
+func (c *Corpus) refreshMetadata() {
+ select {
+ case c.refreshMetadataSignal <- true:
+ default:
+ }
+}
+
+// RefreshMetadataLoop runs forever, updating DocMetadata when the underlying
+// file system changes. It should be launched in a goroutine.
+func (c *Corpus) refreshMetadataLoop() {
+ for {
+ <-c.refreshMetadataSignal
+ c.updateMetadata()
+ time.Sleep(10 * time.Second) // at most once every 10 seconds
+ }
+}
diff --git a/godoc/page.go b/godoc/page.go
new file mode 100644
index 0000000..b296b27
--- /dev/null
+++ b/godoc/page.go
@@ -0,0 +1,43 @@
+// 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.
+
+package godoc
+
+import (
+ "net/http"
+ "runtime"
+)
+
+// Page describes the contents of the top-level godoc webpage.
+type Page struct {
+ Title string
+ Tabtitle string
+ Subtitle string
+ Query string
+ Body []byte
+
+ // filled in by servePage
+ SearchBox bool
+ Playground bool
+ Version string
+}
+
+func (p *Presentation) ServePage(w http.ResponseWriter, page Page) {
+ if page.Tabtitle == "" {
+ page.Tabtitle = page.Title
+ }
+ page.SearchBox = p.Corpus.IndexEnabled
+ page.Playground = p.ShowPlayground
+ page.Version = runtime.Version()
+ applyTemplateToResponseWriter(w, p.GodocHTML, page)
+}
+
+func (p *Presentation) ServeError(w http.ResponseWriter, r *http.Request, relpath string, err error) {
+ w.WriteHeader(http.StatusNotFound)
+ p.ServePage(w, Page{
+ Title: "File " + relpath,
+ Subtitle: relpath,
+ Body: applyTemplate(p.ErrorHTML, "errorHTML", err), // err may contain an absolute path!
+ })
+}
diff --git a/godoc/parser.go b/godoc/parser.go
new file mode 100644
index 0000000..4e644d6
--- /dev/null
+++ b/godoc/parser.go
@@ -0,0 +1,74 @@
+// 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 file contains support functions for parsing .go files
+// accessed via godoc's file system fs.
+
+package godoc
+
+import (
+ "bytes"
+ "go/ast"
+ "go/parser"
+ "go/token"
+ pathpkg "path"
+
+ "golang.org/x/tools/godoc/vfs"
+)
+
+var linePrefix = []byte("//line ")
+
+// This function replaces source lines starting with "//line " with a blank line.
+// It does this irrespective of whether the line is truly a line comment or not;
+// e.g., the line may be inside a string, or a /*-style comment; however that is
+// rather unlikely (proper testing would require a full Go scan which we want to
+// avoid for performance).
+func replaceLinePrefixCommentsWithBlankLine(src []byte) {
+ for {
+ i := bytes.Index(src, linePrefix)
+ if i < 0 {
+ break // we're done
+ }
+ // 0 <= i && i+len(linePrefix) <= len(src)
+ if i == 0 || src[i-1] == '\n' {
+ // at beginning of line: blank out line
+ for i < len(src) && src[i] != '\n' {
+ src[i] = ' '
+ i++
+ }
+ } else {
+ // not at beginning of line: skip over prefix
+ i += len(linePrefix)
+ }
+ // i <= len(src)
+ src = src[i:]
+ }
+}
+
+func (c *Corpus) parseFile(fset *token.FileSet, filename string, mode parser.Mode) (*ast.File, error) {
+ src, err := vfs.ReadFile(c.fs, filename)
+ if err != nil {
+ return nil, err
+ }
+
+ // Temporary ad-hoc fix for issue 5247.
+ // TODO(gri) Remove this in favor of a better fix, eventually (see issue 7702).
+ replaceLinePrefixCommentsWithBlankLine(src)
+
+ return parser.ParseFile(fset, filename, src, mode)
+}
+
+func (c *Corpus) parseFiles(fset *token.FileSet, relpath string, abspath string, localnames []string) (map[string]*ast.File, error) {
+ files := make(map[string]*ast.File)
+ for _, f := range localnames {
+ absname := pathpkg.Join(abspath, f)
+ file, err := c.parseFile(fset, absname, parser.ParseComments)
+ if err != nil {
+ return nil, err
+ }
+ files[pathpkg.Join(relpath, f)] = file
+ }
+
+ return files, nil
+}
diff --git a/godoc/pres.go b/godoc/pres.go
new file mode 100644
index 0000000..a8f8b2b
--- /dev/null
+++ b/godoc/pres.go
@@ -0,0 +1,165 @@
+// 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 godoc
+
+import (
+ "net/http"
+ "regexp"
+ "sync"
+ "text/template"
+
+ "golang.org/x/tools/godoc/vfs/httpfs"
+)
+
+// SearchResultFunc functions return an HTML body for displaying search results.
+type SearchResultFunc func(p *Presentation, result SearchResult) []byte
+
+// Presentation generates output from a corpus.
+type Presentation struct {
+ Corpus *Corpus
+
+ mux *http.ServeMux
+ fileServer http.Handler
+ cmdHandler handlerServer
+ pkgHandler handlerServer
+
+ CallGraphHTML,
+ DirlistHTML,
+ ErrorHTML,
+ ExampleHTML,
+ GodocHTML,
+ ImplementsHTML,
+ MethodSetHTML,
+ PackageHTML,
+ PackageText,
+ SearchHTML,
+ SearchDocHTML,
+ SearchCodeHTML,
+ SearchTxtHTML,
+ SearchText,
+ SearchDescXML *template.Template
+
+ // TabWidth optionally specifies the tab width.
+ TabWidth int
+
+ ShowTimestamps bool
+ ShowPlayground bool
+ ShowExamples bool
+ DeclLinks bool
+
+ // SrcMode outputs source code instead of documentation in command-line mode.
+ SrcMode bool
+ // HTMLMode outputs HTML instead of plain text in command-line mode.
+ HTMLMode bool
+
+ // NotesRx optionally specifies a regexp to match
+ // notes to render in the output.
+ NotesRx *regexp.Regexp
+
+ // AdjustPageInfoMode optionally specifies a function to
+ // modify the PageInfoMode of a request. The default chosen
+ // value is provided.
+ AdjustPageInfoMode func(req *http.Request, mode PageInfoMode) PageInfoMode
+
+ // URLForSrc optionally specifies a function that takes a source file and
+ // returns a URL for it.
+ // The source file argument has the form /src/<path>/<filename>.
+ URLForSrc func(src string) string
+
+ // URLForSrcPos optionally specifies a function to create a URL given a
+ // source file, a line from the source file (1-based), and low & high offset
+ // positions (0-based, bytes from beginning of file). Ideally, the returned
+ // URL will be for the specified line of the file, while the high & low
+ // positions will be used to highlight a section of the file.
+ // The source file argument has the form /src/<path>/<filename>.
+ URLForSrcPos func(src string, line, low, high int) string
+
+ // URLForSrcQuery optionally specifies a function to create a URL given a
+ // source file, a query string, and a line from the source file (1-based).
+ // The source file argument has the form /src/<path>/<filename>.
+ // The query argument will be escaped for the purposes of embedding in a URL
+ // query parameter.
+ // Ideally, the returned URL will be for the specified line of the file with
+ // the query string highlighted.
+ URLForSrcQuery func(src, query string, line int) string
+
+ // SearchResults optionally specifies a list of functions returning an HTML
+ // body for displaying search results.
+ SearchResults []SearchResultFunc
+
+ initFuncMapOnce sync.Once
+ funcMap template.FuncMap
+ templateFuncs template.FuncMap
+}
+
+// NewPresentation returns a new Presentation from a corpus.
+// It sets SearchResults to:
+// [SearchResultDoc SearchResultCode SearchResultTxt].
+func NewPresentation(c *Corpus) *Presentation {
+ if c == nil {
+ panic("nil Corpus")
+ }
+ p := &Presentation{
+ Corpus: c,
+ mux: http.NewServeMux(),
+ fileServer: http.FileServer(httpfs.New(c.fs)),
+
+ TabWidth: 4,
+ ShowExamples: true,
+ DeclLinks: true,
+ SearchResults: []SearchResultFunc{
+ (*Presentation).SearchResultDoc,
+ (*Presentation).SearchResultCode,
+ (*Presentation).SearchResultTxt,
+ },
+ }
+ p.cmdHandler = handlerServer{
+ p: p,
+ c: c,
+ pattern: "/cmd/",
+ fsRoot: "/src/cmd",
+ }
+ p.pkgHandler = handlerServer{
+ p: p,
+ c: c,
+ pattern: "/pkg/",
+ fsRoot: "/src",
+ exclude: []string{"/src/cmd"},
+ }
+ p.cmdHandler.registerWithMux(p.mux)
+ p.pkgHandler.registerWithMux(p.mux)
+ p.mux.HandleFunc("/", p.ServeFile)
+ p.mux.HandleFunc("/search", p.HandleSearch)
+ p.mux.HandleFunc("/opensearch.xml", p.serveSearchDesc)
+ return p
+}
+
+func (p *Presentation) FileServer() http.Handler {
+ return p.fileServer
+}
+
+func (p *Presentation) ServeHTTP(w http.ResponseWriter, r *http.Request) {
+ p.mux.ServeHTTP(w, r)
+}
+
+func (p *Presentation) PkgFSRoot() string {
+ return p.pkgHandler.fsRoot
+}
+
+func (p *Presentation) CmdFSRoot() string {
+ return p.cmdHandler.fsRoot
+}
+
+// TODO(bradfitz): move this to be a method on Corpus. Just moving code around for now,
+// but this doesn't feel right.
+func (p *Presentation) GetPkgPageInfo(abspath, relpath string, mode PageInfoMode) *PageInfo {
+ return p.pkgHandler.GetPageInfo(abspath, relpath, mode)
+}
+
+// TODO(bradfitz): move this to be a method on Corpus. Just moving code around for now,
+// but this doesn't feel right.
+func (p *Presentation) GetCmdPageInfo(abspath, relpath string, mode PageInfoMode) *PageInfo {
+ return p.cmdHandler.GetPageInfo(abspath, relpath, mode)
+}
diff --git a/godoc/redirect/hash.go b/godoc/redirect/hash.go
new file mode 100644
index 0000000..d5a1e3e
--- /dev/null
+++ b/godoc/redirect/hash.go
@@ -0,0 +1,138 @@
+// 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 provides a compact encoding of
+// a map of Mercurial hashes to Git hashes.
+
+package redirect
+
+import (
+ "encoding/binary"
+ "fmt"
+ "io"
+ "os"
+ "sort"
+ "strconv"
+ "strings"
+)
+
+// hashMap is a map of Mercurial hashes to Git hashes.
+type hashMap struct {
+ file *os.File
+ entries int
+}
+
+// newHashMap takes a file handle that contains a map of Mercurial to Git
+// hashes. The file should be a sequence of pairs of little-endian encoded
+// uint32s, representing a hgHash and a gitHash respectively.
+// The sequence must be sorted by hgHash.
+// The file must remain open for as long as the returned hashMap is used.
+func newHashMap(f *os.File) (*hashMap, error) {
+ fi, err := f.Stat()
+ if err != nil {
+ return nil, err
+ }
+ return &hashMap{file: f, entries: int(fi.Size() / 8)}, nil
+}
+
+// Lookup finds an hgHash in the map that matches the given prefix, and returns
+// its corresponding gitHash. The prefix must be at least 8 characters long.
+func (m *hashMap) Lookup(s string) gitHash {
+ if m == nil {
+ return 0
+ }
+ hg, err := hgHashFromString(s)
+ if err != nil {
+ return 0
+ }
+ var git gitHash
+ b := make([]byte, 8)
+ sort.Search(m.entries, func(i int) bool {
+ n, err := m.file.ReadAt(b, int64(i*8))
+ if err != nil {
+ panic(err)
+ }
+ if n != 8 {
+ panic(io.ErrUnexpectedEOF)
+ }
+ v := hgHash(binary.LittleEndian.Uint32(b[:4]))
+ if v == hg {
+ git = gitHash(binary.LittleEndian.Uint32(b[4:]))
+ }
+ return v >= hg
+ })
+ return git
+}
+
+// hgHash represents the lower (leftmost) 32 bits of a Mercurial hash.
+type hgHash uint32
+
+func (h hgHash) String() string {
+ return intToHash(int64(h))
+}
+
+func hgHashFromString(s string) (hgHash, error) {
+ if len(s) < 8 {
+ return 0, fmt.Errorf("string too small: len(s) = %d", len(s))
+ }
+ hash := s[:8]
+ i, err := strconv.ParseInt(hash, 16, 64)
+ if err != nil {
+ return 0, err
+ }
+ return hgHash(i), nil
+}
+
+// gitHash represents the leftmost 28 bits of a Git hash in its upper 28 bits,
+// and it encodes hash's repository in the lower 4 bits.
+type gitHash uint32
+
+func (h gitHash) Hash() string {
+ return intToHash(int64(h))[:7]
+}
+
+func (h gitHash) Repo() string {
+ return repo(h & 0xF).String()
+}
+
+func intToHash(i int64) string {
+ s := strconv.FormatInt(i, 16)
+ if len(s) < 8 {
+ s = strings.Repeat("0", 8-len(s)) + s
+ }
+ return s
+}
+
+// repo represents a Go Git repository.
+type repo byte
+
+const (
+ repoGo repo = iota
+ repoBlog
+ repoCrypto
+ repoExp
+ repoImage
+ repoMobile
+ repoNet
+ repoSys
+ repoTalks
+ repoText
+ repoTools
+)
+
+func (r repo) String() string {
+ return map[repo]string{
+ repoGo: "go",
+ repoBlog: "blog",
+ repoCrypto: "crypto",
+ repoExp: "exp",
+ repoImage: "image",
+ repoMobile: "mobile",
+ repoNet: "net",
+ repoSys: "sys",
+ repoTalks: "talks",
+ repoText: "text",
+ repoTools: "tools",
+ }[r]
+}
diff --git a/godoc/redirect/redirect.go b/godoc/redirect/redirect.go
new file mode 100644
index 0000000..77d927d
--- /dev/null
+++ b/godoc/redirect/redirect.go
@@ -0,0 +1,232 @@
+// 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 redirect provides hooks to register HTTP handlers that redirect old
+// godoc paths to their new equivalents and assist in accessing the issue
+// tracker, wiki, code review system, etc.
+package redirect // import "golang.org/x/tools/godoc/redirect"
+
+import (
+ "fmt"
+ "net/http"
+ "os"
+ "regexp"
+ "strconv"
+ "strings"
+)
+
+// Register registers HTTP handlers that redirect old godoc paths to their new
+// equivalents and assist in accessing the issue tracker, wiki, code review
+// system, etc. If mux is nil it uses http.DefaultServeMux.
+func Register(mux *http.ServeMux) {
+ if mux == nil {
+ mux = http.DefaultServeMux
+ }
+ handlePathRedirects(mux, pkgRedirects, "/pkg/")
+ handlePathRedirects(mux, cmdRedirects, "/cmd/")
+ for prefix, redirect := range prefixHelpers {
+ p := "/" + prefix + "/"
+ mux.Handle(p, PrefixHandler(p, redirect))
+ }
+ for path, redirect := range redirects {
+ mux.Handle(path, Handler(redirect))
+ }
+ // NB: /src/pkg (sans trailing slash) is the index of packages.
+ mux.HandleFunc("/src/pkg/", srcPkgHandler)
+ mux.HandleFunc("/cl/", clHandler)
+ mux.HandleFunc("/change/", changeHandler)
+}
+
+func handlePathRedirects(mux *http.ServeMux, redirects map[string]string, prefix string) {
+ for source, target := range redirects {
+ h := Handler(prefix + target + "/")
+ p := prefix + source
+ mux.Handle(p, h)
+ mux.Handle(p+"/", h)
+ }
+}
+
+// Packages that were renamed between r60 and go1.
+var pkgRedirects = map[string]string{
+ "asn1": "encoding/asn1",
+ "big": "math/big",
+ "cmath": "math/cmplx",
+ "csv": "encoding/csv",
+ "exec": "os/exec",
+ "exp/template/html": "html/template",
+ "gob": "encoding/gob",
+ "http": "net/http",
+ "http/cgi": "net/http/cgi",
+ "http/fcgi": "net/http/fcgi",
+ "http/httptest": "net/http/httptest",
+ "http/pprof": "net/http/pprof",
+ "json": "encoding/json",
+ "mail": "net/mail",
+ "rand": "math/rand",
+ "rpc": "net/rpc",
+ "rpc/jsonrpc": "net/rpc/jsonrpc",
+ "scanner": "text/scanner",
+ "smtp": "net/smtp",
+ "tabwriter": "text/tabwriter",
+ "template": "text/template",
+ "template/parse": "text/template/parse",
+ "url": "net/url",
+ "utf16": "unicode/utf16",
+ "utf8": "unicode/utf8",
+ "xml": "encoding/xml",
+}
+
+// Commands that were renamed between r60 and go1.
+var cmdRedirects = map[string]string{
+ "gofix": "fix",
+ "goinstall": "go",
+ "gopack": "pack",
+ "gotest": "go",
+ "govet": "vet",
+ "goyacc": "yacc",
+}
+
+var redirects = map[string]string{
+ "/blog": "/blog/",
+ "/build": "http://build.golang.org",
+ "/change": "https://go.googlesource.com/go",
+ "/cl": "https://go-review.googlesource.com",
+ "/cmd/godoc/": "http://godoc.org/golang.org/x/tools/cmd/godoc/",
+ "/issue": "https://github.com/golang/go/issues",
+ "/issue/new": "https://github.com/golang/go/issues/new",
+ "/issues": "https://github.com/golang/go/issues",
+ "/issues/new": "https://github.com/golang/go/issues/new",
+ "/play": "http://play.golang.org",
+
+ // In Go 1.2 the references page is part of /doc/.
+ "/ref": "/doc/#references",
+ // This next rule clobbers /ref/spec and /ref/mem.
+ // TODO(adg): figure out what to do here, if anything.
+ // "/ref/": "/doc/#references",
+
+ // Be nice to people who are looking in the wrong place.
+ "/doc/mem": "/ref/mem",
+ "/doc/spec": "/ref/spec",
+
+ "/talks": "http://talks.golang.org",
+ "/tour": "http://tour.golang.org",
+ "/wiki": "https://github.com/golang/go/wiki",
+
+ "/doc/articles/c_go_cgo.html": "/blog/c-go-cgo",
+ "/doc/articles/concurrency_patterns.html": "/blog/go-concurrency-patterns-timing-out-and",
+ "/doc/articles/defer_panic_recover.html": "/blog/defer-panic-and-recover",
+ "/doc/articles/error_handling.html": "/blog/error-handling-and-go",
+ "/doc/articles/gobs_of_data.html": "/blog/gobs-of-data",
+ "/doc/articles/godoc_documenting_go_code.html": "/blog/godoc-documenting-go-code",
+ "/doc/articles/gos_declaration_syntax.html": "/blog/gos-declaration-syntax",
+ "/doc/articles/image_draw.html": "/blog/go-imagedraw-package",
+ "/doc/articles/image_package.html": "/blog/go-image-package",
+ "/doc/articles/json_and_go.html": "/blog/json-and-go",
+ "/doc/articles/json_rpc_tale_of_interfaces.html": "/blog/json-rpc-tale-of-interfaces",
+ "/doc/articles/laws_of_reflection.html": "/blog/laws-of-reflection",
+ "/doc/articles/slices_usage_and_internals.html": "/blog/go-slices-usage-and-internals",
+ "/doc/go_for_cpp_programmers.html": "/wiki/GoForCPPProgrammers",
+ "/doc/go_tutorial.html": "http://tour.golang.org/",
+}
+
+var prefixHelpers = map[string]string{
+ "issue": "https://github.com/golang/go/issues/",
+ "issues": "https://github.com/golang/go/issues/",
+ "play": "http://play.golang.org/",
+ "talks": "http://talks.golang.org/",
+ "wiki": "https://github.com/golang/go/wiki/",
+}
+
+func Handler(target string) http.Handler {
+ return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ http.Redirect(w, r, target, http.StatusMovedPermanently)
+ })
+}
+
+var validId = regexp.MustCompile(`^[A-Za-z0-9-]*$`)
+
+func PrefixHandler(prefix, baseURL string) http.Handler {
+ return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ if p := r.URL.Path; p == prefix {
+ // redirect /prefix/ to /prefix
+ http.Redirect(w, r, p[:len(p)-1], http.StatusFound)
+ return
+ }
+ id := r.URL.Path[len(prefix):]
+ if !validId.MatchString(id) {
+ http.Error(w, "Not found", http.StatusNotFound)
+ return
+ }
+ target := baseURL + id
+ http.Redirect(w, r, target, http.StatusFound)
+ })
+}
+
+// Redirect requests from the old "/src/pkg/foo" to the new "/src/foo".
+// See http://golang.org/s/go14nopkg
+func srcPkgHandler(w http.ResponseWriter, r *http.Request) {
+ r.URL.Path = "/src/" + r.URL.Path[len("/src/pkg/"):]
+ http.Redirect(w, r, r.URL.String(), http.StatusMovedPermanently)
+}
+
+func clHandler(w http.ResponseWriter, r *http.Request) {
+ const prefix = "/cl/"
+ if p := r.URL.Path; p == prefix {
+ // redirect /prefix/ to /prefix
+ http.Redirect(w, r, p[:len(p)-1], http.StatusFound)
+ return
+ }
+ id := r.URL.Path[len(prefix):]
+ // support /cl/152700045/, which is used in commit 0edafefc36.
+ id = strings.TrimSuffix(id, "/")
+ if !validId.MatchString(id) {
+ http.Error(w, "Not found", http.StatusNotFound)
+ return
+ }
+ target := ""
+ // the first CL in rietveld is about 152046, so only treat the id as
+ // a rietveld CL if it is larger than 150000.
+ if n, err := strconv.Atoi(id); err == nil && n > 150000 {
+ target = "https://codereview.appspot.com/" + id
+ } else {
+ target = "https://go-review.googlesource.com/r/" + id
+ }
+ http.Redirect(w, r, target, http.StatusFound)
+}
+
+var changeMap *hashMap
+
+// LoadChangeMap loads the specified map of Mercurial to Git revisions,
+// which is used by the /change/ handler to intelligently map old hg
+// revisions to their new git equivalents.
+// It should be called before calling Register.
+// The file should remain open as long as the process is running.
+// See the implementation of this package for details.
+func LoadChangeMap(filename string) error {
+ f, err := os.Open(filename)
+ if err != nil {
+ return err
+ }
+ m, err := newHashMap(f)
+ if err != nil {
+ return err
+ }
+ changeMap = m
+ return nil
+}
+
+func changeHandler(w http.ResponseWriter, r *http.Request) {
+ const prefix = "/change/"
+ if p := r.URL.Path; p == prefix {
+ // redirect /prefix/ to /prefix
+ http.Redirect(w, r, p[:len(p)-1], http.StatusFound)
+ return
+ }
+ hash := r.URL.Path[len(prefix):]
+ target := "https://go.googlesource.com/go/+/" + hash
+ if git := changeMap.Lookup(hash); git > 0 {
+ target = fmt.Sprintf("https://go.googlesource.com/%v/+/%v", git.Repo(), git.Hash())
+ }
+ http.Redirect(w, r, target, http.StatusFound)
+}
diff --git a/godoc/search.go b/godoc/search.go
new file mode 100644
index 0000000..e126330
--- /dev/null
+++ b/godoc/search.go
@@ -0,0 +1,138 @@
+// 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.
+
+package godoc
+
+import (
+ "bytes"
+ "fmt"
+ "net/http"
+ "regexp"
+ "strings"
+)
+
+type SearchResult struct {
+ Query string
+ Alert string // error or warning message
+
+ // identifier matches
+ Pak HitList // packages matching Query
+ Hit *LookupResult // identifier matches of Query
+ Alt *AltWords // alternative identifiers to look for
+
+ // textual matches
+ Found int // number of textual occurrences found
+ Textual []FileLines // textual matches of Query
+ Complete bool // true if all textual occurrences of Query are reported
+ Idents map[SpotKind][]Ident
+}
+
+func (c *Corpus) Lookup(query string) SearchResult {
+ result := &SearchResult{Query: query}
+
+ index, timestamp := c.CurrentIndex()
+ if index != nil {
+ // identifier search
+ if r, err := index.Lookup(query); err == nil {
+ result = r
+ } else if err != nil && !c.IndexFullText {
+ // ignore the error if full text search is enabled
+ // since the query may be a valid regular expression
+ result.Alert = "Error in query string: " + err.Error()
+ return *result
+ }
+
+ // full text search
+ if c.IndexFullText && query != "" {
+ rx, err := regexp.Compile(query)
+ if err != nil {
+ result.Alert = "Error in query regular expression: " + err.Error()
+ return *result
+ }
+ // If we get maxResults+1 results we know that there are more than
+ // maxResults results and thus the result may be incomplete (to be
+ // precise, we should remove one result from the result set, but
+ // nobody is going to count the results on the result page).
+ result.Found, result.Textual = index.LookupRegexp(rx, c.MaxResults+1)
+ result.Complete = result.Found <= c.MaxResults
+ if !result.Complete {
+ result.Found-- // since we looked for maxResults+1
+ }
+ }
+ }
+
+ // is the result accurate?
+ if c.IndexEnabled {
+ if ts := c.FSModifiedTime(); timestamp.Before(ts) {
+ // The index is older than the latest file system change under godoc's observation.
+ result.Alert = "Indexing in progress: result may be inaccurate"
+ }
+ } else {
+ result.Alert = "Search index disabled: no results available"
+ }
+
+ return *result
+}
+
+// SearchResultDoc optionally specifies a function returning an HTML body
+// displaying search results matching godoc documentation.
+func (p *Presentation) SearchResultDoc(result SearchResult) []byte {
+ return applyTemplate(p.SearchDocHTML, "searchDocHTML", result)
+}
+
+// SearchResultCode optionally specifies a function returning an HTML body
+// displaying search results matching source code.
+func (p *Presentation) SearchResultCode(result SearchResult) []byte {
+ return applyTemplate(p.SearchCodeHTML, "searchCodeHTML", result)
+}
+
+// SearchResultTxt optionally specifies a function returning an HTML body
+// displaying search results of textual matches.
+func (p *Presentation) SearchResultTxt(result SearchResult) []byte {
+ return applyTemplate(p.SearchTxtHTML, "searchTxtHTML", result)
+}
+
+// HandleSearch obtains results for the requested search and returns a page
+// to display them.
+func (p *Presentation) HandleSearch(w http.ResponseWriter, r *http.Request) {
+ query := strings.TrimSpace(r.FormValue("q"))
+ result := p.Corpus.Lookup(query)
+
+ if p.GetPageInfoMode(r)&NoHTML != 0 {
+ p.ServeText(w, applyTemplate(p.SearchText, "searchText", result))
+ return
+ }
+ contents := bytes.Buffer{}
+ for _, f := range p.SearchResults {
+ contents.Write(f(p, result))
+ }
+
+ var title string
+ if haveResults := contents.Len() > 0; haveResults {
+ title = fmt.Sprintf(`Results for query %q`, query)
+ if !p.Corpus.IndexEnabled {
+ result.Alert = ""
+ }
+ } else {
+ title = fmt.Sprintf(`No results found for query %q`, query)
+ }
+
+ body := bytes.NewBuffer(applyTemplate(p.SearchHTML, "searchHTML", result))
+ body.Write(contents.Bytes())
+
+ p.ServePage(w, Page{
+ Title: title,
+ Tabtitle: query,
+ Query: query,
+ Body: body.Bytes(),
+ })
+}
+
+func (p *Presentation) serveSearchDesc(w http.ResponseWriter, r *http.Request) {
+ w.Header().Set("Content-Type", "application/opensearchdescription+xml")
+ data := map[string]interface{}{
+ "BaseURL": fmt.Sprintf("http://%s", r.Host),
+ }
+ applyTemplateToResponseWriter(w, p.SearchDescXML, &data)
+}
diff --git a/godoc/server.go b/godoc/server.go
new file mode 100644
index 0000000..2c18efb
--- /dev/null
+++ b/godoc/server.go
@@ -0,0 +1,750 @@
+// 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 godoc
+
+import (
+ "bytes"
+ "encoding/json"
+ "fmt"
+ "go/ast"
+ "go/build"
+ "go/doc"
+ "go/token"
+ htmlpkg "html"
+ htmltemplate "html/template"
+ "io"
+ "io/ioutil"
+ "log"
+ "net/http"
+ "os"
+ pathpkg "path"
+ "path/filepath"
+ "sort"
+ "strings"
+ "text/template"
+ "time"
+
+ "golang.org/x/tools/godoc/analysis"
+ "golang.org/x/tools/godoc/util"
+ "golang.org/x/tools/godoc/vfs"
+)
+
+// handlerServer is a migration from an old godoc http Handler type.
+// This should probably merge into something else.
+type handlerServer struct {
+ p *Presentation
+ c *Corpus // copy of p.Corpus
+ pattern string // url pattern; e.g. "/pkg/"
+ fsRoot string // file system root to which the pattern is mapped; e.g. "/src"
+ exclude []string // file system paths to exclude; e.g. "/src/cmd"
+}
+
+func (s *handlerServer) registerWithMux(mux *http.ServeMux) {
+ mux.Handle(s.pattern, s)
+}
+
+// getPageInfo returns the PageInfo for a package directory abspath. If the
+// parameter genAST is set, an AST containing only the package exports is
+// computed (PageInfo.PAst), otherwise package documentation (PageInfo.Doc)
+// is extracted from the AST. If there is no corresponding package in the
+// directory, PageInfo.PAst and PageInfo.PDoc are nil. If there are no sub-
+// directories, PageInfo.Dirs is nil. If an error occurred, PageInfo.Err is
+// set to the respective error but the error is not logged.
+//
+func (h *handlerServer) GetPageInfo(abspath, relpath string, mode PageInfoMode) *PageInfo {
+ info := &PageInfo{Dirname: abspath}
+
+ // Restrict to the package files that would be used when building
+ // the package on this system. This makes sure that if there are
+ // separate implementations for, say, Windows vs Unix, we don't
+ // jumble them all together.
+ // Note: Uses current binary's GOOS/GOARCH.
+ // To use different pair, such as if we allowed the user to choose,
+ // set ctxt.GOOS and ctxt.GOARCH before calling ctxt.ImportDir.
+ ctxt := build.Default
+ ctxt.IsAbsPath = pathpkg.IsAbs
+ ctxt.ReadDir = func(dir string) ([]os.FileInfo, error) {
+ f, err := h.c.fs.ReadDir(filepath.ToSlash(dir))
+ filtered := make([]os.FileInfo, 0, len(f))
+ for _, i := range f {
+ if mode&NoFiltering != 0 || i.Name() != "internal" {
+ filtered = append(filtered, i)
+ }
+ }
+ return filtered, err
+ }
+ ctxt.OpenFile = func(name string) (r io.ReadCloser, err error) {
+ data, err := vfs.ReadFile(h.c.fs, filepath.ToSlash(name))
+ if err != nil {
+ return nil, err
+ }
+ return ioutil.NopCloser(bytes.NewReader(data)), nil
+ }
+
+ pkginfo, err := ctxt.ImportDir(abspath, 0)
+ // continue if there are no Go source files; we still want the directory info
+ if _, nogo := err.(*build.NoGoError); err != nil && !nogo {
+ info.Err = err
+ return info
+ }
+
+ // collect package files
+ pkgname := pkginfo.Name
+ pkgfiles := append(pkginfo.GoFiles, pkginfo.CgoFiles...)
+ if len(pkgfiles) == 0 {
+ // Commands written in C have no .go files in the build.
+ // Instead, documentation may be found in an ignored file.
+ // The file may be ignored via an explicit +build ignore
+ // constraint (recommended), or by defining the package
+ // documentation (historic).
+ pkgname = "main" // assume package main since pkginfo.Name == ""
+ pkgfiles = pkginfo.IgnoredGoFiles
+ }
+
+ // get package information, if any
+ if len(pkgfiles) > 0 {
+ // build package AST
+ fset := token.NewFileSet()
+ files, err := h.c.parseFiles(fset, relpath, abspath, pkgfiles)
+ if err != nil {
+ info.Err = err
+ return info
+ }
+
+ // ignore any errors - they are due to unresolved identifiers
+ pkg, _ := ast.NewPackage(fset, files, poorMansImporter, nil)
+
+ // extract package documentation
+ info.FSet = fset
+ if mode&ShowSource == 0 {
+ // show extracted documentation
+ var m doc.Mode
+ if mode&NoFiltering != 0 {
+ m |= doc.AllDecls
+ }
+ if mode&AllMethods != 0 {
+ m |= doc.AllMethods
+ }
+ info.PDoc = doc.New(pkg, pathpkg.Clean(relpath), m) // no trailing '/' in importpath
+ if mode&NoTypeAssoc != 0 {
+ for _, t := range info.PDoc.Types {
+ info.PDoc.Consts = append(info.PDoc.Consts, t.Consts...)
+ info.PDoc.Vars = append(info.PDoc.Vars, t.Vars...)
+ info.PDoc.Funcs = append(info.PDoc.Funcs, t.Funcs...)
+ t.Consts = nil
+ t.Vars = nil
+ t.Funcs = nil
+ }
+ // for now we cannot easily sort consts and vars since
+ // go/doc.Value doesn't export the order information
+ sort.Sort(funcsByName(info.PDoc.Funcs))
+ }
+
+ // collect examples
+ testfiles := append(pkginfo.TestGoFiles, pkginfo.XTestGoFiles...)
+ files, err = h.c.parseFiles(fset, relpath, abspath, testfiles)
+ if err != nil {
+ log.Println("parsing examples:", err)
+ }
+ info.Examples = collectExamples(h.c, pkg, files)
+
+ // collect any notes that we want to show
+ if info.PDoc.Notes != nil {
+ // could regexp.Compile only once per godoc, but probably not worth it
+ if rx := h.p.NotesRx; rx != nil {
+ for m, n := range info.PDoc.Notes {
+ if rx.MatchString(m) {
+ if info.Notes == nil {
+ info.Notes = make(map[string][]*doc.Note)
+ }
+ info.Notes[m] = n
+ }
+ }
+ }
+ }
+
+ } else {
+ // show source code
+ // TODO(gri) Consider eliminating export filtering in this mode,
+ // or perhaps eliminating the mode altogether.
+ if mode&NoFiltering == 0 {
+ packageExports(fset, pkg)
+ }
+ info.PAst = files
+ }
+ info.IsMain = pkgname == "main"
+ }
+
+ // get directory information, if any
+ var dir *Directory
+ var timestamp time.Time
+ if tree, ts := h.c.fsTree.Get(); tree != nil && tree.(*Directory) != nil {
+ // directory tree is present; lookup respective directory
+ // (may still fail if the file system was updated and the
+ // new directory tree has not yet been computed)
+ dir = tree.(*Directory).lookup(abspath)
+ timestamp = ts
+ }
+ if dir == nil {
+ // no directory tree present (too early after startup or
+ // command-line mode); compute one level for this page
+ // note: cannot use path filter here because in general
+ // it doesn't contain the FSTree path
+ dir = h.c.newDirectory(abspath, 1)
+ timestamp = time.Now()
+ }
+ info.Dirs = dir.listing(true, func(path string) bool { return h.includePath(path, mode) })
+ info.DirTime = timestamp
+ info.DirFlat = mode&FlatDir != 0
+
+ return info
+}
+
+func (h *handlerServer) includePath(path string, mode PageInfoMode) (r bool) {
+ // if the path is under one of the exclusion paths, don't list.
+ for _, e := range h.exclude {
+ if strings.HasPrefix(path, e) {
+ return false
+ }
+ }
+
+ // if the path includes 'internal', don't list unless we are in the NoFiltering mode.
+ if mode&NoFiltering != 0 {
+ return true
+ }
+ if strings.Contains(path, "internal") {
+ for _, c := range strings.Split(filepath.Clean(path), string(os.PathSeparator)) {
+ if c == "internal" {
+ return false
+ }
+ }
+ }
+ return true
+}
+
+type funcsByName []*doc.Func
+
+func (s funcsByName) Len() int { return len(s) }
+func (s funcsByName) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
+func (s funcsByName) Less(i, j int) bool { return s[i].Name < s[j].Name }
+
+func (h *handlerServer) ServeHTTP(w http.ResponseWriter, r *http.Request) {
+ if redirect(w, r) {
+ return
+ }
+
+ relpath := pathpkg.Clean(r.URL.Path[len(h.pattern):])
+ abspath := pathpkg.Join(h.fsRoot, relpath)
+ mode := h.p.GetPageInfoMode(r)
+ if relpath == builtinPkgPath {
+ mode = NoFiltering | NoTypeAssoc
+ }
+ info := h.GetPageInfo(abspath, relpath, mode)
+ if info.Err != nil {
+ log.Print(info.Err)
+ h.p.ServeError(w, r, relpath, info.Err)
+ return
+ }
+
+ if mode&NoHTML != 0 {
+ h.p.ServeText(w, applyTemplate(h.p.PackageText, "packageText", info))
+ return
+ }
+
+ var tabtitle, title, subtitle string
+ switch {
+ case info.PAst != nil:
+ for _, ast := range info.PAst {
+ tabtitle = ast.Name.Name
+ break
+ }
+ case info.PDoc != nil:
+ tabtitle = info.PDoc.Name
+ default:
+ tabtitle = info.Dirname
+ title = "Directory "
+ if h.p.ShowTimestamps {
+ subtitle = "Last update: " + info.DirTime.String()
+ }
+ }
+ if title == "" {
+ if info.IsMain {
+ // assume that the directory name is the command name
+ _, tabtitle = pathpkg.Split(relpath)
+ title = "Command "
+ } else {
+ title = "Package "
+ }
+ }
+ title += tabtitle
+
+ // special cases for top-level package/command directories
+ switch tabtitle {
+ case "/src":
+ title = "Packages"
+ tabtitle = "Packages"
+ case "/src/cmd":
+ title = "Commands"
+ tabtitle = "Commands"
+ }
+
+ // Emit JSON array for type information.
+ pi := h.c.Analysis.PackageInfo(relpath)
+ info.CallGraphIndex = pi.CallGraphIndex
+ info.CallGraph = htmltemplate.JS(marshalJSON(pi.CallGraph))
+ info.AnalysisData = htmltemplate.JS(marshalJSON(pi.Types))
+ info.TypeInfoIndex = make(map[string]int)
+ for i, ti := range pi.Types {
+ info.TypeInfoIndex[ti.Name] = i
+ }
+
+ h.p.ServePage(w, Page{
+ Title: title,
+ Tabtitle: tabtitle,
+ Subtitle: subtitle,
+ Body: applyTemplate(h.p.PackageHTML, "packageHTML", info),
+ })
+}
+
+type PageInfoMode uint
+
+const (
+ NoFiltering PageInfoMode = 1 << iota // do not filter exports
+ AllMethods // show all embedded methods
+ ShowSource // show source code, do not extract documentation
+ NoHTML // show result in textual form, do not generate HTML
+ FlatDir // show directory in a flat (non-indented) manner
+ NoTypeAssoc // don't associate consts, vars, and factory functions with types
+)
+
+// modeNames defines names for each PageInfoMode flag.
+var modeNames = map[string]PageInfoMode{
+ "all": NoFiltering,
+ "methods": AllMethods,
+ "src": ShowSource,
+ "text": NoHTML,
+ "flat": FlatDir,
+}
+
+// GetPageInfoMode computes the PageInfoMode flags by analyzing the request
+// URL form value "m". It is value is a comma-separated list of mode names
+// as defined by modeNames (e.g.: m=src,text).
+func (p *Presentation) GetPageInfoMode(r *http.Request) PageInfoMode {
+ var mode PageInfoMode
+ for _, k := range strings.Split(r.FormValue("m"), ",") {
+ if m, found := modeNames[strings.TrimSpace(k)]; found {
+ mode |= m
+ }
+ }
+ if p.AdjustPageInfoMode != nil {
+ mode = p.AdjustPageInfoMode(r, mode)
+ }
+ return mode
+}
+
+// poorMansImporter returns a (dummy) package object named
+// by the last path component of the provided package path
+// (as is the convention for packages). This is sufficient
+// to resolve package identifiers without doing an actual
+// import. It never returns an error.
+//
+func poorMansImporter(imports map[string]*ast.Object, path string) (*ast.Object, error) {
+ pkg := imports[path]
+ if pkg == nil {
+ // note that strings.LastIndex returns -1 if there is no "/"
+ pkg = ast.NewObj(ast.Pkg, path[strings.LastIndex(path, "/")+1:])
+ pkg.Data = ast.NewScope(nil) // required by ast.NewPackage for dot-import
+ imports[path] = pkg
+ }
+ return pkg, nil
+}
+
+// globalNames returns a set of the names declared by all package-level
+// declarations. Method names are returned in the form Receiver_Method.
+func globalNames(pkg *ast.Package) map[string]bool {
+ names := make(map[string]bool)
+ for _, file := range pkg.Files {
+ for _, decl := range file.Decls {
+ addNames(names, decl)
+ }
+ }
+ return names
+}
+
+// collectExamples collects examples for pkg from testfiles.
+func collectExamples(c *Corpus, pkg *ast.Package, testfiles map[string]*ast.File) []*doc.Example {
+ var files []*ast.File
+ for _, f := range testfiles {
+ files = append(files, f)
+ }
+
+ var examples []*doc.Example
+ globals := globalNames(pkg)
+ for _, e := range doc.Examples(files...) {
+ name := stripExampleSuffix(e.Name)
+ if name == "" || globals[name] {
+ examples = append(examples, e)
+ } else if c.Verbose {
+ log.Printf("skipping example 'Example%s' because '%s' is not a known function or type", e.Name, e.Name)
+ }
+ }
+
+ return examples
+}
+
+// addNames adds the names declared by decl to the names set.
+// Method names are added in the form ReceiverTypeName_Method.
+func addNames(names map[string]bool, decl ast.Decl) {
+ switch d := decl.(type) {
+ case *ast.FuncDecl:
+ name := d.Name.Name
+ if d.Recv != nil {
+ var typeName string
+ switch r := d.Recv.List[0].Type.(type) {
+ case *ast.StarExpr:
+ typeName = r.X.(*ast.Ident).Name
+ case *ast.Ident:
+ typeName = r.Name
+ }
+ name = typeName + "_" + name
+ }
+ names[name] = true
+ case *ast.GenDecl:
+ for _, spec := range d.Specs {
+ switch s := spec.(type) {
+ case *ast.TypeSpec:
+ names[s.Name.Name] = true
+ case *ast.ValueSpec:
+ for _, id := range s.Names {
+ names[id.Name] = true
+ }
+ }
+ }
+ }
+}
+
+// packageExports is a local implementation of ast.PackageExports
+// which correctly updates each package file's comment list.
+// (The ast.PackageExports signature is frozen, hence the local
+// implementation).
+//
+func packageExports(fset *token.FileSet, pkg *ast.Package) {
+ for _, src := range pkg.Files {
+ cmap := ast.NewCommentMap(fset, src, src.Comments)
+ ast.FileExports(src)
+ src.Comments = cmap.Filter(src).Comments()
+ }
+}
+
+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()
+}
+
+type writerCapturesErr struct {
+ w io.Writer
+ err error
+}
+
+func (w *writerCapturesErr) Write(p []byte) (int, error) {
+ n, err := w.w.Write(p)
+ if err != nil {
+ w.err = err
+ }
+ return n, err
+}
+
+// applyTemplateToResponseWriter uses an http.ResponseWriter as the io.Writer
+// for the call to template.Execute. It uses an io.Writer wrapper to capture
+// errors from the underlying http.ResponseWriter. Errors are logged only when
+// they come from the template processing and not the Writer; this avoid
+// polluting log files with error messages due to networking issues, such as
+// client disconnects and http HEAD protocol violations.
+func applyTemplateToResponseWriter(rw http.ResponseWriter, t *template.Template, data interface{}) {
+ w := &writerCapturesErr{w: rw}
+ err := t.Execute(w, data)
+ // There are some cases where template.Execute does not return an error when
+ // rw returns an error, and some where it does. So check w.err first.
+ if w.err == nil && err != nil {
+ // Log template errors.
+ log.Printf("%s.Execute: %s", t.Name(), err)
+ }
+}
+
+func redirect(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 redirectFile(w http.ResponseWriter, r *http.Request) (redirected bool) {
+ c := pathpkg.Clean(r.URL.Path)
+ c = strings.TrimRight(c, "/")
+ if r.URL.Path != c {
+ url := *r.URL
+ url.Path = c
+ http.Redirect(w, r, url.String(), http.StatusMovedPermanently)
+ redirected = true
+ }
+ return
+}
+
+func (p *Presentation) serveTextFile(w http.ResponseWriter, r *http.Request, abspath, relpath, title string) {
+ src, err := vfs.ReadFile(p.Corpus.fs, abspath)
+ if err != nil {
+ log.Printf("ReadFile: %s", err)
+ p.ServeError(w, r, relpath, err)
+ return
+ }
+
+ if r.FormValue("m") == "text" {
+ p.ServeText(w, src)
+ return
+ }
+
+ h := r.FormValue("h")
+ s := RangeSelection(r.FormValue("s"))
+
+ var buf bytes.Buffer
+ if pathpkg.Ext(abspath) == ".go" {
+ // Find markup links for this file (e.g. "/src/fmt/print.go").
+ fi := p.Corpus.Analysis.FileInfo(abspath)
+ buf.WriteString("<script type='text/javascript'>document.ANALYSIS_DATA = ")
+ buf.Write(marshalJSON(fi.Data))
+ buf.WriteString(";</script>\n")
+
+ if status := p.Corpus.Analysis.Status(); status != "" {
+ buf.WriteString("<a href='/lib/godoc/analysis/help.html'>Static analysis features</a> ")
+ // TODO(adonovan): show analysis status at per-file granularity.
+ fmt.Fprintf(&buf, "<span style='color: grey'>[%s]</span><br/>", htmlpkg.EscapeString(status))
+ }
+
+ buf.WriteString("<pre>")
+ formatGoSource(&buf, src, fi.Links, h, s)
+ buf.WriteString("</pre>")
+ } else {
+ buf.WriteString("<pre>")
+ FormatText(&buf, src, 1, false, h, s)
+ buf.WriteString("</pre>")
+ }
+ fmt.Fprintf(&buf, `<p><a href="/%s?m=text">View as plain text</a></p>`, htmlpkg.EscapeString(relpath))
+
+ p.ServePage(w, Page{
+ Title: title + " " + relpath,
+ Tabtitle: relpath,
+ Body: buf.Bytes(),
+ })
+}
+
+// formatGoSource HTML-escapes Go source text and writes it to w,
+// decorating it with the specified analysis links.
+//
+func formatGoSource(buf *bytes.Buffer, text []byte, links []analysis.Link, pattern string, selection Selection) {
+ // Emit to a temp buffer so that we can add line anchors at the end.
+ saved, buf := buf, new(bytes.Buffer)
+
+ var i int
+ var link analysis.Link // shared state of the two funcs below
+ segmentIter := func() (seg Segment) {
+ if i < len(links) {
+ link = links[i]
+ i++
+ seg = Segment{link.Start(), link.End()}
+ }
+ return
+ }
+ linkWriter := func(w io.Writer, offs int, start bool) {
+ link.Write(w, offs, start)
+ }
+
+ comments := tokenSelection(text, token.COMMENT)
+ var highlights Selection
+ if pattern != "" {
+ highlights = regexpSelection(text, pattern)
+ }
+
+ FormatSelections(buf, text, linkWriter, segmentIter, selectionTag, comments, highlights, selection)
+
+ // Now copy buf to saved, adding line anchors.
+
+ // The lineSelection mechanism can't be composed with our
+ // linkWriter, so we have to add line spans as another pass.
+ n := 1
+ for _, line := range bytes.Split(buf.Bytes(), []byte("\n")) {
+ fmt.Fprintf(saved, "<span id=\"L%d\" class=\"ln\">%6d</span>\t", n, n)
+ n++
+ saved.Write(line)
+ saved.WriteByte('\n')
+ }
+}
+
+func (p *Presentation) serveDirectory(w http.ResponseWriter, r *http.Request, abspath, relpath string) {
+ if redirect(w, r) {
+ return
+ }
+
+ list, err := p.Corpus.fs.ReadDir(abspath)
+ if err != nil {
+ p.ServeError(w, r, relpath, err)
+ return
+ }
+
+ p.ServePage(w, Page{
+ Title: "Directory " + relpath,
+ Tabtitle: relpath,
+ Body: applyTemplate(p.DirlistHTML, "dirlistHTML", list),
+ })
+}
+
+func (p *Presentation) ServeHTMLDoc(w http.ResponseWriter, r *http.Request, abspath, relpath string) {
+ // get HTML body contents
+ src, err := vfs.ReadFile(p.Corpus.fs, abspath)
+ if err != nil {
+ log.Printf("ReadFile: %s", err)
+ p.ServeError(w, r, relpath, err)
+ return
+ }
+
+ // if it begins with "<!DOCTYPE " assume it is standalone
+ // html that doesn't need the template wrapping.
+ if bytes.HasPrefix(src, doctype) {
+ w.Write(src)
+ return
+ }
+
+ // if it begins with a JSON blob, read in the metadata.
+ meta, src, err := extractMetadata(src)
+ if err != nil {
+ log.Printf("decoding metadata %s: %v", relpath, err)
+ }
+
+ // evaluate as template if indicated
+ if meta.Template {
+ tmpl, err := template.New("main").Funcs(p.TemplateFuncs()).Parse(string(src))
+ if err != nil {
+ log.Printf("parsing template %s: %v", relpath, err)
+ p.ServeError(w, r, relpath, err)
+ return
+ }
+ var buf bytes.Buffer
+ if err := tmpl.Execute(&buf, nil); err != nil {
+ log.Printf("executing template %s: %v", relpath, err)
+ p.ServeError(w, r, relpath, err)
+ return
+ }
+ src = buf.Bytes()
+ }
+
+ // if it's the language spec, add tags to EBNF productions
+ if strings.HasSuffix(abspath, "go_spec.html") {
+ var buf bytes.Buffer
+ Linkify(&buf, src)
+ src = buf.Bytes()
+ }
+
+ p.ServePage(w, Page{
+ Title: meta.Title,
+ Subtitle: meta.Subtitle,
+ Body: src,
+ })
+}
+
+func (p *Presentation) ServeFile(w http.ResponseWriter, r *http.Request) {
+ p.serveFile(w, r)
+}
+
+func (p *Presentation) serveFile(w http.ResponseWriter, r *http.Request) {
+ relpath := r.URL.Path
+
+ // Check to see if we need to redirect or serve another file.
+ if m := p.Corpus.MetadataFor(relpath); m != nil {
+ if m.Path != relpath {
+ // Redirect to canonical path.
+ http.Redirect(w, r, m.Path, http.StatusMovedPermanently)
+ return
+ }
+ // Serve from the actual filesystem path.
+ relpath = m.filePath
+ }
+
+ abspath := relpath
+ relpath = relpath[1:] // strip leading slash
+
+ switch pathpkg.Ext(relpath) {
+ case ".html":
+ if strings.HasSuffix(relpath, "/index.html") {
+ // We'll show index.html for the directory.
+ // Use the dir/ version as canonical instead of dir/index.html.
+ http.Redirect(w, r, r.URL.Path[0:len(r.URL.Path)-len("index.html")], http.StatusMovedPermanently)
+ return
+ }
+ p.ServeHTMLDoc(w, r, abspath, relpath)
+ return
+
+ case ".go":
+ p.serveTextFile(w, r, abspath, relpath, "Source file")
+ return
+ }
+
+ dir, err := p.Corpus.fs.Lstat(abspath)
+ if err != nil {
+ log.Print(err)
+ p.ServeError(w, r, relpath, err)
+ return
+ }
+
+ if dir != nil && dir.IsDir() {
+ if redirect(w, r) {
+ return
+ }
+ if index := pathpkg.Join(abspath, "index.html"); util.IsTextFile(p.Corpus.fs, index) {
+ p.ServeHTMLDoc(w, r, index, index)
+ return
+ }
+ p.serveDirectory(w, r, abspath, relpath)
+ return
+ }
+
+ if util.IsTextFile(p.Corpus.fs, abspath) {
+ if redirectFile(w, r) {
+ return
+ }
+ p.serveTextFile(w, r, abspath, relpath, "Text file")
+ return
+ }
+
+ p.fileServer.ServeHTTP(w, r)
+}
+
+func (p *Presentation) ServeText(w http.ResponseWriter, text []byte) {
+ w.Header().Set("Content-Type", "text/plain; charset=utf-8")
+ w.Write(text)
+}
+
+func marshalJSON(x interface{}) []byte {
+ var data []byte
+ var err error
+ const indentJSON = false // for easier debugging
+ if indentJSON {
+ data, err = json.MarshalIndent(x, "", " ")
+ } else {
+ data, err = json.Marshal(x)
+ }
+ if err != nil {
+ panic(fmt.Sprintf("json.Marshal failed: %s", err))
+ }
+ return data
+}
diff --git a/godoc/snippet.go b/godoc/snippet.go
new file mode 100644
index 0000000..dd9c822
--- /dev/null
+++ b/godoc/snippet.go
@@ -0,0 +1,123 @@
+// 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.
+
+// This file contains the infrastructure to create a code
+// snippet for search results.
+//
+// Note: At the moment, this only creates HTML snippets.
+
+package godoc
+
+import (
+ "bytes"
+ "fmt"
+ "go/ast"
+ "go/token"
+)
+
+type Snippet struct {
+ Line int
+ Text string // HTML-escaped
+}
+
+func (p *Presentation) newSnippet(fset *token.FileSet, decl ast.Decl, id *ast.Ident) *Snippet {
+ // TODO instead of pretty-printing the node, should use the original source instead
+ var buf1 bytes.Buffer
+ p.writeNode(&buf1, fset, decl)
+ // wrap text with <pre> tag
+ var buf2 bytes.Buffer
+ buf2.WriteString("<pre>")
+ FormatText(&buf2, buf1.Bytes(), -1, true, id.Name, nil)
+ buf2.WriteString("</pre>")
+ return &Snippet{fset.Position(id.Pos()).Line, buf2.String()}
+}
+
+func findSpec(list []ast.Spec, id *ast.Ident) ast.Spec {
+ for _, spec := range list {
+ switch s := spec.(type) {
+ case *ast.ImportSpec:
+ if s.Name == id {
+ return s
+ }
+ case *ast.ValueSpec:
+ for _, n := range s.Names {
+ if n == id {
+ return s
+ }
+ }
+ case *ast.TypeSpec:
+ if s.Name == id {
+ return s
+ }
+ }
+ }
+ return nil
+}
+
+func (p *Presentation) genSnippet(fset *token.FileSet, d *ast.GenDecl, id *ast.Ident) *Snippet {
+ s := findSpec(d.Specs, id)
+ if s == nil {
+ return nil // declaration doesn't contain id - exit gracefully
+ }
+
+ // only use the spec containing the id for the snippet
+ dd := &ast.GenDecl{
+ Doc: d.Doc,
+ TokPos: d.Pos(),
+ Tok: d.Tok,
+ Lparen: d.Lparen,
+ Specs: []ast.Spec{s},
+ Rparen: d.Rparen,
+ }
+
+ return p.newSnippet(fset, dd, id)
+}
+
+func (p *Presentation) funcSnippet(fset *token.FileSet, d *ast.FuncDecl, id *ast.Ident) *Snippet {
+ if d.Name != id {
+ return nil // declaration doesn't contain id - exit gracefully
+ }
+
+ // only use the function signature for the snippet
+ dd := &ast.FuncDecl{
+ Doc: d.Doc,
+ Recv: d.Recv,
+ Name: d.Name,
+ Type: d.Type,
+ }
+
+ return p.newSnippet(fset, dd, id)
+}
+
+// NewSnippet creates a text snippet from a declaration decl containing an
+// identifier id. Parts of the declaration not containing the identifier
+// may be removed for a more compact snippet.
+func NewSnippet(fset *token.FileSet, decl ast.Decl, id *ast.Ident) *Snippet {
+ // TODO(bradfitz, adg): remove this function. But it's used by indexer, which
+ // doesn't have a *Presentation, and NewSnippet needs a TabWidth.
+ var p Presentation
+ p.TabWidth = 4
+ return p.NewSnippet(fset, decl, id)
+}
+
+// NewSnippet creates a text snippet from a declaration decl containing an
+// identifier id. Parts of the declaration not containing the identifier
+// may be removed for a more compact snippet.
+func (p *Presentation) NewSnippet(fset *token.FileSet, decl ast.Decl, id *ast.Ident) *Snippet {
+ var s *Snippet
+ switch d := decl.(type) {
+ case *ast.GenDecl:
+ s = p.genSnippet(fset, d, id)
+ case *ast.FuncDecl:
+ s = p.funcSnippet(fset, d, id)
+ }
+
+ // handle failure gracefully
+ if s == nil {
+ var buf bytes.Buffer
+ fmt.Fprintf(&buf, `<span class="alert">could not generate a snippet for <span class="highlight">%s</span></span>`, id.Name)
+ s = &Snippet{fset.Position(id.Pos()).Line, buf.String()}
+ }
+ return s
+}
diff --git a/godoc/spec.go b/godoc/spec.go
new file mode 100644
index 0000000..6d6b9c2
--- /dev/null
+++ b/godoc/spec.go
@@ -0,0 +1,179 @@
+// 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.
+
+package godoc
+
+// This file contains the mechanism to "linkify" html source
+// text containing EBNF sections (as found in go_spec.html).
+// The result is the input source text with the EBNF sections
+// modified such that identifiers are linked to the respective
+// definitions.
+
+import (
+ "bytes"
+ "fmt"
+ "io"
+ "text/scanner"
+)
+
+type ebnfParser struct {
+ out io.Writer // parser output
+ src []byte // parser input
+ scanner scanner.Scanner
+ prev int // offset of previous token
+ pos int // offset of current token
+ tok rune // one token look-ahead
+ lit string // token literal
+}
+
+func (p *ebnfParser) flush() {
+ p.out.Write(p.src[p.prev:p.pos])
+ p.prev = p.pos
+}
+
+func (p *ebnfParser) next() {
+ p.tok = p.scanner.Scan()
+ p.pos = p.scanner.Position.Offset
+ p.lit = p.scanner.TokenText()
+}
+
+func (p *ebnfParser) printf(format string, args ...interface{}) {
+ p.flush()
+ fmt.Fprintf(p.out, format, args...)
+}
+
+func (p *ebnfParser) errorExpected(msg string) {
+ p.printf(`<span class="highlight">error: expected %s, found %s</span>`, msg, scanner.TokenString(p.tok))
+}
+
+func (p *ebnfParser) expect(tok rune) {
+ if p.tok != tok {
+ p.errorExpected(scanner.TokenString(tok))
+ }
+ p.next() // make progress in any case
+}
+
+func (p *ebnfParser) parseIdentifier(def bool) {
+ if p.tok == scanner.Ident {
+ name := p.lit
+ if def {
+ p.printf(`<a id="%s">%s</a>`, name, name)
+ } else {
+ p.printf(`<a href="#%s" class="noline">%s</a>`, name, name)
+ }
+ p.prev += len(name) // skip identifier when printing next time
+ p.next()
+ } else {
+ p.expect(scanner.Ident)
+ }
+}
+
+func (p *ebnfParser) parseTerm() bool {
+ switch p.tok {
+ case scanner.Ident:
+ p.parseIdentifier(false)
+
+ case scanner.String:
+ p.next()
+ const ellipsis = '…' // U+2026, the horizontal ellipsis character
+ if p.tok == ellipsis {
+ p.next()
+ p.expect(scanner.String)
+ }
+
+ case '(':
+ p.next()
+ p.parseExpression()
+ p.expect(')')
+
+ case '[':
+ p.next()
+ p.parseExpression()
+ p.expect(']')
+
+ case '{':
+ p.next()
+ p.parseExpression()
+ p.expect('}')
+
+ default:
+ return false // no term found
+ }
+
+ return true
+}
+
+func (p *ebnfParser) parseSequence() {
+ if !p.parseTerm() {
+ p.errorExpected("term")
+ }
+ for p.parseTerm() {
+ }
+}
+
+func (p *ebnfParser) parseExpression() {
+ for {
+ p.parseSequence()
+ if p.tok != '|' {
+ break
+ }
+ p.next()
+ }
+}
+
+func (p *ebnfParser) parseProduction() {
+ p.parseIdentifier(true)
+ p.expect('=')
+ if p.tok != '.' {
+ p.parseExpression()
+ }
+ p.expect('.')
+}
+
+func (p *ebnfParser) parse(out io.Writer, src []byte) {
+ // initialize ebnfParser
+ p.out = out
+ p.src = src
+ p.scanner.Init(bytes.NewBuffer(src))
+ p.next() // initializes pos, tok, lit
+
+ // process source
+ for p.tok != scanner.EOF {
+ p.parseProduction()
+ }
+ p.flush()
+}
+
+// Markers around EBNF sections
+var (
+ openTag = []byte(`<pre class="ebnf">`)
+ closeTag = []byte(`</pre>`)
+)
+
+func Linkify(out io.Writer, src []byte) {
+ for len(src) > 0 {
+ // i: beginning of EBNF text (or end of source)
+ i := bytes.Index(src, openTag)
+ if i < 0 {
+ i = len(src) - len(openTag)
+ }
+ i += len(openTag)
+
+ // j: end of EBNF text (or end of source)
+ j := bytes.Index(src[i:], closeTag) // close marker
+ if j < 0 {
+ j = len(src) - i
+ }
+ j += i
+
+ // write text before EBNF
+ out.Write(src[0:i])
+ // process EBNF
+ var p ebnfParser
+ p.parse(out, src[i:j])
+
+ // advance
+ src = src[j:]
+ }
+}
diff --git a/godoc/spot.go b/godoc/spot.go
new file mode 100644
index 0000000..95ffa4b
--- /dev/null
+++ b/godoc/spot.go
@@ -0,0 +1,83 @@
+// 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 godoc
+
+// ----------------------------------------------------------------------------
+// SpotInfo
+
+// A SpotInfo value describes a particular identifier spot in a given file;
+// It encodes three values: the SpotKind (declaration or use), a line or
+// snippet index "lori", and whether it's a line or index.
+//
+// The following encoding is used:
+//
+// bits 32 4 1 0
+// value [lori|kind|isIndex]
+//
+type SpotInfo uint32
+
+// SpotKind describes whether an identifier is declared (and what kind of
+// declaration) or used.
+type SpotKind uint32
+
+const (
+ PackageClause SpotKind = iota
+ ImportDecl
+ ConstDecl
+ TypeDecl
+ VarDecl
+ FuncDecl
+ MethodDecl
+ Use
+ nKinds
+)
+
+var (
+ // These must match the SpotKind values above.
+ name = []string{
+ "Packages",
+ "Imports",
+ "Constants",
+ "Types",
+ "Variables",
+ "Functions",
+ "Methods",
+ "Uses",
+ "Unknown",
+ }
+)
+
+func (x SpotKind) Name() string { return name[x] }
+
+func init() {
+ // sanity check: if nKinds is too large, the SpotInfo
+ // accessor functions may need to be updated
+ if nKinds > 8 {
+ panic("internal error: nKinds > 8")
+ }
+}
+
+// makeSpotInfo makes a SpotInfo.
+func makeSpotInfo(kind SpotKind, lori int, isIndex bool) SpotInfo {
+ // encode lori: bits [4..32)
+ x := SpotInfo(lori) << 4
+ if int(x>>4) != lori {
+ // lori value doesn't fit - since snippet indices are
+ // most certainly always smaller then 1<<28, this can
+ // only happen for line numbers; give it no line number (= 0)
+ x = 0
+ }
+ // encode kind: bits [1..4)
+ x |= SpotInfo(kind) << 1
+ // encode isIndex: bit 0
+ if isIndex {
+ x |= 1
+ }
+ return x
+}
+
+func (x SpotInfo) Kind() SpotKind { return SpotKind(x >> 1 & 7) }
+func (x SpotInfo) Lori() int { return int(x >> 4) }
+func (x SpotInfo) IsIndex() bool { return x&1 != 0 }
diff --git a/godoc/static/analysis/call-eg.png b/godoc/static/analysis/call-eg.png
new file mode 100644
index 0000000..c48bf4d
--- /dev/null
+++ b/godoc/static/analysis/call-eg.png
Binary files differ
diff --git a/godoc/static/analysis/call3.png b/godoc/static/analysis/call3.png
new file mode 100644
index 0000000..387a38c
--- /dev/null
+++ b/godoc/static/analysis/call3.png
Binary files differ
diff --git a/godoc/static/analysis/callers1.png b/godoc/static/analysis/callers1.png
new file mode 100644
index 0000000..80fbc62
--- /dev/null
+++ b/godoc/static/analysis/callers1.png
Binary files differ
diff --git a/godoc/static/analysis/callers2.png b/godoc/static/analysis/callers2.png
new file mode 100644
index 0000000..59a84ed
--- /dev/null
+++ b/godoc/static/analysis/callers2.png
Binary files differ
diff --git a/godoc/static/analysis/chan1.png b/godoc/static/analysis/chan1.png
new file mode 100644
index 0000000..5eb2811
--- /dev/null
+++ b/godoc/static/analysis/chan1.png
Binary files differ
diff --git a/godoc/static/analysis/chan2a.png b/godoc/static/analysis/chan2a.png
new file mode 100644
index 0000000..b757504
--- /dev/null
+++ b/godoc/static/analysis/chan2a.png
Binary files differ
diff --git a/godoc/static/analysis/chan2b.png b/godoc/static/analysis/chan2b.png
new file mode 100644
index 0000000..d197862
--- /dev/null
+++ b/godoc/static/analysis/chan2b.png
Binary files differ
diff --git a/godoc/static/analysis/error1.png b/godoc/static/analysis/error1.png
new file mode 100644
index 0000000..69550b9
--- /dev/null
+++ b/godoc/static/analysis/error1.png
Binary files differ
diff --git a/godoc/static/analysis/help.html b/godoc/static/analysis/help.html
new file mode 100644
index 0000000..023c07d
--- /dev/null
+++ b/godoc/static/analysis/help.html
@@ -0,0 +1,254 @@
+<!--{
+ "Title": "Static analysis features of godoc"
+}-->
+
+<style>
+ span.err { 'font-size:120%; color:darkred; background-color: yellow; }
+ img.ss { margin-left: 1in; } /* screenshot */
+ img.dotted { border: thin dotted; }
+</style>
+
+<!-- Images were grabbed from Chrome/Linux at 150% zoom, and are
+ displayed at 66% of natural size. This allows users to zoom a
+ little before seeing pixels. -->
+
+<p>
+ When invoked with the <code>-analysis</code> flag, godoc performs
+ static analysis on the Go packages it indexes and displays the
+ results in the source and package views. This document provides a
+ brief tour of these features.
+</p>
+
+<h2>Type analysis features</h2>
+<p>
+ <code>godoc -analysis=type</code> performs static checking similar
+ to that done by a compiler: it detects ill-formed programs, resolves
+ each identifier to the entity it denotes, computes the type of each
+ expression and the method set of each type, and determines which
+ types are assignable to each interface type.
+
+ <b>Type analysis</b> is relatively quick, requiring about 10 seconds for
+ the >200 packages of the standard library, for example.
+</p>
+
+<h3>Compiler errors</h3>
+<p>
+ If any source file contains a compilation error, the source view
+ will highlight the errant location in red. Hovering over it
+ displays the error message.
+</p>
+<img class="ss" width='811' src='error1.png'><br/>
+
+<h3>Identifier resolution</h3>
+<p>
+ In the source view, every referring identifier is annotated with
+ information about the language entity it refers to: a package,
+ constant, variable, type, function or statement label.
+
+ Hovering over the identifier reveals the entity's kind and type
+ (e.g. <code>var x int</code> or <code>func f
+ func(int) string</code>).
+</p>
+<img class="ss" width='652' src='ident-field.png'><br/>
+<br/>
+<img class="ss" width='652' src='ident-func.png'>
+<p>
+ Clicking the link takes you to the entity's definition.
+</p>
+<img class="ss" width='652' src='ident-def.png'><br/>
+
+<h3>Type information: size/alignment, method set, interfaces</h3>
+<p>
+ Clicking on the identifier that defines a named type causes a panel
+ to appear, displaying information about the named type, including
+ its size and alignment in bytes, its
+ <a href='http://golang.org/ref/spec#Method_sets'>method set</a>, and its
+ <i>implements</i> relation: the set of types T that are assignable to
+ or from this type U where at least one of T or U is an interface.
+
+ This example shows information about <code>net/rpc.methodType</code>.
+</p>
+<img class="ss" width='470' src='typeinfo-src.png'>
+<p>
+ The method set includes not only the declared methods of the type,
+ but also any methods "promoted" from anonymous fields of structs,
+ such as <code>sync.Mutex</code> in this example.
+
+ In addition, the receiver type is displayed as <code>*T</code> or
+ <code>T</code> depending on whether it requires the address or just
+ a copy of the receiver value.
+</p>
+<p>
+ The method set and <i>implements</i> relation are also available
+ via the package view.
+</p>
+<img class="ss dotted" width='716' src='typeinfo-pkg.png'>
+
+<h2>Pointer analysis features</h2>
+<p>
+ <code>godoc -analysis=pointer</code> additionally performs a precise
+ whole-program <b>pointer analysis</b>. In other words, it
+ approximates the set of memory locations to which each
+ reference—not just vars of kind <code>*T</code>, but also
+ <code>[]T</code>, <code>func</code>, <code>map</code>,
+ <code>chan</code>, and <code>interface</code>—may refer. This
+ information reveals the possible destinations of each dynamic call
+ (via a <code>func</code> variable or interface method), and the
+ relationship between send and receive operations on the same
+ channel.
+</p>
+<p>
+ Compared to type analysis, pointer analysis requires more time and
+ memory, and is impractical for code bases exceeding a million lines.
+</p>
+
+<h3>Call graph navigation</h3>
+<p>
+ When pointer analysis is complete, the source view annotates the
+ code with <b>callers</b> and <b>callees</b> information: callers
+ information is associated with the <code>func</code> keyword that
+ declares a function, and callees information is associated with the
+ open paren '<span style="color: dark-blue"><code>(</code></span>' of
+ a function call.
+</p>
+<p>
+ In this example, hovering over the declaration of the
+ <code>rot13</code> function (defined in strings/strings_test.go)
+ reveals that it is called in exactly one place.
+</p>
+<img class="ss" width='612' src='callers1.png'>
+<p>
+ Clicking the link navigates to the sole caller. (If there were
+ multiple callers, a list of choices would be displayed first.)
+</p>
+<img class="ss" width='680' src='callers2.png'>
+<p>
+ Notice that hovering over this call reveals that there are 19
+ possible callees at this site, of which our <code>rot13</code>
+ function was just one: this is a dynamic call through a variable of
+ type <code>func(rune) rune</code>.
+
+ Clicking on the call brings up the list of all 19 potential callees,
+ shown truncated. Many of them are anonymous functions.
+</p>
+<img class="ss" width='564' src='call3.png'>
+<p>
+ Pointer analysis gives a very precise approximation of the call
+ graph compared to type-based techniques.
+
+ As a case in point, the next example shows the dynamic call inside
+ the <code>testing</code> package responsible for calling all
+ user-defined functions named <code>Example<i>XYZ</i></code>.
+</p>
+<img class="ss" width='361' src='call-eg.png'>
+<p>
+ Recall that all such functions have type <code>func()</code>,
+ i.e. no arguments and no results. A type-based approximation could
+ only conclude that this call might dispatch to any function matching
+ that type—and these are very numerous in most
+ programs—but pointer analysis can track the flow of specific
+ <code>func</code> values through the testing package.
+
+ As an indication of its precision, the result contains only
+ functions whose name starts with <code>Example</code>.
+</p>
+
+<h3>Intra-package call graph</h3>
+<p>
+ The same call graph information is presented in a very different way
+ in the package view. For each package, an interactive tree view
+ allows exploration of the call graph as it relates to just that
+ package; all functions from other packages are elided.
+
+ The roots of the tree are the external entry points of the package:
+ not only its exported functions, but also any unexported or
+ anonymous functions that are called (dynamically) from outside the
+ package.
+</p>
+<p>
+ This example shows the entry points of the
+ <code>path/filepath</code> package, with the call graph for
+ <code>Glob</code> expanded several levels
+</p>
+<img class="ss dotted" width='501' src='ipcg-pkg.png'>
+<p>
+ Notice that the nodes for Glob and Join appear multiple times: the
+ tree is a partial unrolling of a cyclic graph; the full unrolling
+ is in general infinite.
+</p>
+<p>
+ For each function documented in the package view, another
+ interactive tree view allows exploration of the same graph starting
+ at that function.
+
+ This is a portion of the internal graph of
+ <code>net/http.ListenAndServe</code>.
+</p>
+<img class="ss dotted" width='455' src='ipcg-func.png'>
+
+<h3>Channel peers (send ↔ receive)</h3>
+<p>
+ Because concurrent Go programs use channels to pass not just values
+ but also control between different goroutines, it is natural when
+ reading Go code to want to navigate from a channel send to the
+ corresponding receive so as to understand the sequence of events.
+</p>
+<p>
+ Godoc annotates every channel operation—make, send, range,
+ receive, close—with a link to a panel displaying information
+ about other operations that might alias the same channel.
+</p>
+<p>
+ This example, from the tests of <code>net/http</code>, shows a send
+ operation on a <code>chan bool</code>.
+</p>
+<img class="ss" width='811' src='chan1.png'>
+<p>
+ Clicking on the <code><-</code> send operator reveals that this
+ channel is made at a unique location (line 332) and that there are
+ three receive operations that might read this value.
+
+ It hardly needs pointing out that some channel element types are
+ very widely used (e.g. struct{}, bool, int, interface{}) and that a
+ typical Go program might contain dozens of receive operations on a
+ value of type <code>chan bool</code>; yet the pointer analysis is
+ able to distinguish operations on channels at a much finer precision
+ than based on their type alone.
+</p>
+<p>
+ Notice also that the send occurs in a different (anonymous) function
+ from the outer one containing the <code>make</code> and the receive
+ operations.
+</p>
+<p>
+ Here's another example of send on a different <code>chan
+ bool</code>, also in package <code>net/http</code>:
+</p>
+<img class="ss" width='774' src='chan2a.png'>
+<p>
+ The analysis finds just one receive operation that might receive
+ from this channel, in the test for this feature.
+</p>
+<img class="ss" width='737' src='chan2b.png'>
+
+<h2>Known issues</h2>
+<p>
+ All analysis results pertain to exactly
+ one configuration (e.g. amd64 linux). Files that are conditionally
+ compiled based on different platforms or build tags are not visible
+ to the analysis.
+</p>
+<p>
+ Files that <code>import "C"</code> require
+ preprocessing by the cgo tool. The file offsets after preprocessing
+ do not align with the unpreprocessed file, so markup is misaligned.
+</p>
+<p>
+ Files are not periodically re-analyzed.
+ If the files change underneath the running server, the displayed
+ markup is misaligned.
+</p>
+<p>
+ Additional issues are listed at
+ <a href='https://go.googlesource.com/tools/+/master/godoc/analysis/README'>tools/godoc/analysis/README</a>.
+</p>
diff --git a/godoc/static/analysis/ident-def.png b/godoc/static/analysis/ident-def.png
new file mode 100644
index 0000000..b0d9e55
--- /dev/null
+++ b/godoc/static/analysis/ident-def.png
Binary files differ
diff --git a/godoc/static/analysis/ident-field.png b/godoc/static/analysis/ident-field.png
new file mode 100644
index 0000000..76cbe5a
--- /dev/null
+++ b/godoc/static/analysis/ident-field.png
Binary files differ
diff --git a/godoc/static/analysis/ident-func.png b/godoc/static/analysis/ident-func.png
new file mode 100644
index 0000000..69670fa
--- /dev/null
+++ b/godoc/static/analysis/ident-func.png
Binary files differ
diff --git a/godoc/static/analysis/ipcg-func.png b/godoc/static/analysis/ipcg-func.png
new file mode 100644
index 0000000..523318d
--- /dev/null
+++ b/godoc/static/analysis/ipcg-func.png
Binary files differ
diff --git a/godoc/static/analysis/ipcg-pkg.png b/godoc/static/analysis/ipcg-pkg.png
new file mode 100644
index 0000000..e029068
--- /dev/null
+++ b/godoc/static/analysis/ipcg-pkg.png
Binary files differ
diff --git a/godoc/static/analysis/typeinfo-pkg.png b/godoc/static/analysis/typeinfo-pkg.png
new file mode 100644
index 0000000..91bd5f7
--- /dev/null
+++ b/godoc/static/analysis/typeinfo-pkg.png
Binary files differ
diff --git a/godoc/static/analysis/typeinfo-src.png b/godoc/static/analysis/typeinfo-src.png
new file mode 100644
index 0000000..6e5b147
--- /dev/null
+++ b/godoc/static/analysis/typeinfo-src.png
Binary files differ
diff --git a/godoc/static/callgraph.html b/godoc/static/callgraph.html
new file mode 100644
index 0000000..c56b2ef
--- /dev/null
+++ b/godoc/static/callgraph.html
@@ -0,0 +1,15 @@
+<div class="toggle" style="display: none">
+ <div class="collapsed">
+ <p class="exampleHeading toggleButton">▹ <span class="text">Internal call graph</span></p>
+ </div>
+ <div class="expanded">
+ <p class="exampleHeading toggleButton">▾ <span class="text">Internal call graph</span></p>
+ <p>
+ This viewer shows the portion of the internal call
+ graph of this package that is reachable from this function.
+ See the <a href='#pkg-callgraph'>package's call
+ graph</a> for more information.
+ </p>
+ <ul style="margin-left: 0.5in" id="callgraph-{{.Index}}" class="treeview"></ul>
+ </div>
+</div>
diff --git a/godoc/static/codewalk.html b/godoc/static/codewalk.html
new file mode 100644
index 0000000..0f3d22a
--- /dev/null
+++ b/godoc/static/codewalk.html
@@ -0,0 +1,56 @@
+<!--
+ 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.
+-->
+
+<style type='text/css'>@import "/doc/codewalk/codewalk.css";</style>
+<script type="text/javascript" src="/doc/codewalk/codewalk.js"></script>
+
+<div id="codewalk-main">
+ <div class="left" id="code-column">
+ <div id='sizer'></div>
+ <div id="code-area">
+ <div id="code-header" align="center">
+ <a id="code-popout-link" href="" target="_blank">
+ <img title="View code in new window" alt="Pop Out Code" src="/doc/codewalk/popout.png" style="display: block; float: right;"/>
+ </a>
+ <select id="code-selector">
+ {{range .File}}
+ <option value="/doc/codewalk/?fileprint=/{{urlquery .}}">{{html .}}</option>
+ {{end}}
+ </select>
+ </div>
+ <div id="code">
+ <iframe class="code-display" name="code-display" id="code-display"></iframe>
+ </div>
+ </div>
+ <div id="code-options" class="setting">
+ <span>code on <a id="set-code-left" class="selected" href="#">left</a> • <a id="set-code-right" href="#">right</a></span>
+ <span>code width <span id="code-column-width">70%</span></span>
+ <span>filepaths <a id="show-filepaths" class="selected" href="#">shown</a> • <a id="hide-filepaths" href="#">hidden</a></span>
+ </div>
+ </div>
+ <div class="right" id="comment-column">
+ <div id="comment-area">
+ {{range .Step}}
+ <div class="comment first last">
+ <a class="comment-link" href="/doc/codewalk/?fileprint=/{{urlquery .File}}&lo={{urlquery .Lo}}&hi={{urlquery .Hi}}#mark" target="code-display"></a>
+ <div class="comment-title">{{html .Title}}</div>
+ <div class="comment-text">
+ {{with .Err}}
+ ERROR LOADING FILE: {{html .}}<br/><br/>
+ {{end}}
+ {{.XML}}
+ </div>
+ <div class="comment-text file-name"><span class="path-file">{{html .}}</span></div>
+ </div>
+ {{end}}
+ </div>
+ <div id="comment-options" class="setting">
+ <a id="prev-comment" href="#"><span class="hotkey">p</span>revious step</a>
+ •
+ <a id="next-comment" href="#"><span class="hotkey">n</span>ext step</a>
+ </div>
+ </div>
+</div>
diff --git a/godoc/static/codewalkdir.html b/godoc/static/codewalkdir.html
new file mode 100644
index 0000000..b7674c6
--- /dev/null
+++ b/godoc/static/codewalkdir.html
@@ -0,0 +1,16 @@
+<!--
+ 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.
+-->
+
+<table class="layout">
+{{range .}}
+<tr>
+ {{$name_html := html .Name}}
+ <td><a href="{{$name_html}}">{{$name_html}}</a></td>
+ <td width="25"> </td>
+ <td>{{html .Title}}</td>
+</tr>
+{{end}}
+</table>
diff --git a/godoc/static/dirlist.html b/godoc/static/dirlist.html
new file mode 100644
index 0000000..a3e1a2f
--- /dev/null
+++ b/godoc/static/dirlist.html
@@ -0,0 +1,31 @@
+<!--
+ 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.
+-->
+
+<p>
+<table class="layout">
+<tr>
+ <th align="left">File</th>
+ <td width="25"> </td>
+ <th align="right">Bytes</th>
+ <td width="25"> </td>
+ <th align="left">Modified</th>
+</tr>
+<tr>
+ <td><a href="..">..</a></td>
+</tr>
+{{range .}}
+<tr>
+ {{$name_html := fileInfoName . | html}}
+ <td align="left"><a href="{{$name_html}}">{{$name_html}}</a></td>
+ <td></td>
+ <td align="right">{{html .Size}}</td>
+ <td></td>
+ <td align="left">{{fileInfoTime . | html}}</td>
+</tr>
+{{end}}
+
+</table>
+</p>
diff --git a/godoc/static/doc.go b/godoc/static/doc.go
new file mode 100644
index 0000000..b3d8bcf
--- /dev/null
+++ b/godoc/static/doc.go
@@ -0,0 +1,8 @@
+// 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 static exports a map of static file content that supports the godoc
+// user interface. The map should be used with the mapfs package, see
+// golang.org/x/tools/godoc/vfs/mapfs.
+package static // import "golang.org/x/tools/godoc/static"
diff --git a/godoc/static/error.html b/godoc/static/error.html
new file mode 100644
index 0000000..7573aa2
--- /dev/null
+++ b/godoc/static/error.html
@@ -0,0 +1,9 @@
+<!--
+ 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.
+-->
+
+<p>
+<span class="alert" style="font-size:120%">{{html .}}</span>
+</p>
diff --git a/godoc/static/example.html b/godoc/static/example.html
new file mode 100644
index 0000000..cda2a84
--- /dev/null
+++ b/godoc/static/example.html
@@ -0,0 +1,28 @@
+<div id="example_{{.Name}}" class="toggle">
+ <div class="collapsed">
+ <p class="exampleHeading toggleButton">▹ <span class="text">Example{{example_suffix .Name}}</span></p>
+ </div>
+ <div class="expanded">
+ <p class="exampleHeading toggleButton">▾ <span class="text">Example{{example_suffix .Name}}</span></p>
+ {{with .Doc}}<p>{{html .}}</p>{{end}}
+ {{$output := .Output}}
+ {{with .Play}}
+ <div class="play">
+ <div class="input"><textarea class="code">{{html .}}</textarea></div>
+ <div class="output"><pre>{{html $output}}</pre></div>
+ <div class="buttons">
+ <a class="run" title="Run this code [shift-enter]">Run</a>
+ <a class="fmt" title="Format this code">Format</a>
+ <a class="share" title="Share this code">Share</a>
+ </div>
+ </div>
+ {{else}}
+ <p>Code:</p>
+ <pre class="code">{{.Code}}</pre>
+ {{with .Output}}
+ <p>Output:</p>
+ <pre class="output">{{html .}}</pre>
+ {{end}}
+ {{end}}
+ </div>
+</div>
diff --git a/godoc/static/gen.go b/godoc/static/gen.go
new file mode 100644
index 0000000..4226821
--- /dev/null
+++ b/godoc/static/gen.go
@@ -0,0 +1,7 @@
+// 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 static
+
+//go:generate go run makestatic.go
diff --git a/godoc/static/godoc.html b/godoc/static/godoc.html
new file mode 100644
index 0000000..6d6d1b6
--- /dev/null
+++ b/godoc/static/godoc.html
@@ -0,0 +1,105 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<meta name="viewport" content="width=device-width, initial-scale=1">
+<meta name="theme-color" content="#375EAB">
+{{with .Tabtitle}}
+ <title>{{html .}} - The Go Programming Language</title>
+{{else}}
+ <title>The Go Programming Language</title>
+{{end}}
+<link type="text/css" rel="stylesheet" href="/lib/godoc/style.css">
+{{if .SearchBox}}
+<link rel="search" type="application/opensearchdescription+xml" title="godoc" href="/opensearch.xml" />
+{{end}}
+<link rel="stylesheet" href="/lib/godoc/jquery.treeview.css">
+<script type="text/javascript">window.initFuncs = [];</script>
+</head>
+<body>
+
+<div id='lowframe' style="position: fixed; bottom: 0; left: 0; height: 0; width: 100%; border-top: thin solid grey; background-color: white; overflow: auto;">
+...
+</div><!-- #lowframe -->
+
+<div id="topbar"{{if .Title}} class="wide"{{end}}><div class="container">
+<div class="top-heading" id="heading-wide"><a href="/">The Go Programming Language</a></div>
+<div class="top-heading" id="heading-narrow"><a href="/">Go</a></div>
+<a href="#" id="menu-button"><span id="menu-button-arrow">▽</span></a>
+<form method="GET" action="/search">
+<div id="menu">
+<a href="/doc/">Documents</a>
+<a href="/pkg/">Packages</a>
+<a href="/project/">The Project</a>
+<a href="/help/">Help</a>
+<a href="/blog/">Blog</a>
+{{if .Playground}}
+<a id="playgroundButton" href="http://play.golang.org/" title="Show Go Playground">Play</a>
+{{end}}
+<input type="text" id="search" name="q" class="inactive" value="Search" placeholder="Search">
+</div>
+</form>
+
+</div></div>
+
+{{if .Playground}}
+<div id="playground" class="play">
+ <div class="input"><textarea class="code">package main
+
+import "fmt"
+
+func main() {
+ fmt.Println("Hello, 世界")
+}</textarea></div>
+ <div class="output"></div>
+ <div class="buttons">
+ <a class="run" title="Run this code [shift-enter]">Run</a>
+ <a class="fmt" title="Format this code">Format</a>
+ <a class="share" title="Share this code">Share</a>
+ </div>
+</div>
+{{end}}
+
+<div id="page"{{if .Title}} class="wide"{{end}}>
+<div class="container">
+
+{{with .Title}}
+ <h1>{{html .}}</h1>
+{{end}}
+{{with .Subtitle}}
+ <h2>{{html .}}</h2>
+{{end}}
+
+{{/* The Table of Contents is automatically inserted in this <div>.
+ Do not delete this <div>. */}}
+<div id="nav"></div>
+
+{{/* Body is HTML-escaped elsewhere */}}
+{{printf "%s" .Body}}
+
+<div id="footer">
+Build version {{html .Version}}.<br>
+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="/LICENSE">BSD license</a>.<br>
+<a href="/doc/tos.html">Terms of Service</a> |
+<a href="http://www.google.com/intl/en/policies/privacy/">Privacy Policy</a>
+</div>
+
+</div><!-- .container -->
+</div><!-- #page -->
+
+<!-- TODO(adonovan): load these from <head> using "defer" attribute? -->
+<script type="text/javascript" src="/lib/godoc/jquery.js"></script>
+<script type="text/javascript" src="/lib/godoc/jquery.treeview.js"></script>
+<script type="text/javascript" src="/lib/godoc/jquery.treeview.edit.js"></script>
+
+{{if .Playground}}
+<script type="text/javascript" src="/lib/godoc/playground.js"></script>
+{{end}}
+<script type="text/javascript" src="/lib/godoc/godocs.js"></script>
+
+</body>
+</html>
+
diff --git a/godoc/static/godocs.js b/godoc/static/godocs.js
new file mode 100644
index 0000000..47d1de9
--- /dev/null
+++ b/godoc/static/godocs.js
@@ -0,0 +1,567 @@
+// 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.
+
+/* A little code to ease navigation of these documents.
+ *
+ * On window load we:
+ * + Bind search box hint placeholder show/hide events (bindSearchEvents)
+ * + Generate a table of contents (generateTOC)
+ * + Bind foldable sections (bindToggles)
+ * + Bind links to foldable sections (bindToggleLinks)
+ */
+
+(function() {
+'use strict';
+
+// Mobile-friendly topbar menu
+$(function() {
+ var menu = $('#menu');
+ var menuButton = $('#menu-button');
+ var menuButtonArrow = $('#menu-button-arrow');
+ menuButton.click(function(event) {
+ menu.toggleClass('menu-visible');
+ menuButtonArrow.toggleClass('vertical-flip');
+ event.preventDefault();
+ return false;
+ });
+});
+
+function bindSearchEvents() {
+
+ var search = $('#search');
+ if (search.length === 0) {
+ return; // no search box
+ }
+
+ function clearInactive() {
+ if (search.is('.inactive')) {
+ search.val('');
+ search.removeClass('inactive');
+ }
+ }
+
+ function restoreInactive() {
+ if (search.val() !== '') {
+ return;
+ }
+ search.val(search.attr('placeholder'));
+ search.addClass('inactive');
+ }
+
+ search.on('focus', clearInactive);
+ search.on('blur', restoreInactive);
+
+ restoreInactive();
+}
+
+/* Generates a table of contents: looks for h2 and h3 elements and generates
+ * links. "Decorates" the element with id=="nav" with this table of contents.
+ */
+function generateTOC() {
+ if ($('#manual-nav').length > 0) {
+ return;
+ }
+
+ var nav = $('#nav');
+ if (nav.length === 0) {
+ return;
+ }
+
+ var toc_items = [];
+ $(nav).nextAll('h2, h3').each(function() {
+ var node = this;
+ if (node.id == '')
+ node.id = 'tmp_' + toc_items.length;
+ var link = $('<a/>').attr('href', '#' + node.id).text($(node).text());
+ var item;
+ if ($(node).is('h2')) {
+ item = $('<dt/>');
+ } else { // h3
+ item = $('<dd class="indent"/>');
+ }
+ item.append(link);
+ toc_items.push(item);
+ });
+ if (toc_items.length <= 1) {
+ return;
+ }
+
+ var dl1 = $('<dl/>');
+ var dl2 = $('<dl/>');
+
+ var split_index = (toc_items.length / 2) + 1;
+ if (split_index < 8) {
+ split_index = toc_items.length;
+ }
+ for (var i = 0; i < split_index; i++) {
+ dl1.append(toc_items[i]);
+ }
+ for (/* keep using i */; i < toc_items.length; i++) {
+ dl2.append(toc_items[i]);
+ }
+
+ var tocTable = $('<table class="unruled"/>').appendTo(nav);
+ var tocBody = $('<tbody/>').appendTo(tocTable);
+ var tocRow = $('<tr/>').appendTo(tocBody);
+
+ // 1st column
+ $('<td class="first"/>').appendTo(tocRow).append(dl1);
+ // 2nd column
+ $('<td/>').appendTo(tocRow).append(dl2);
+}
+
+function bindToggle(el) {
+ $('.toggleButton', el).click(function() {
+ if ($(el).is('.toggle')) {
+ $(el).addClass('toggleVisible').removeClass('toggle');
+ } else {
+ $(el).addClass('toggle').removeClass('toggleVisible');
+ }
+ });
+}
+function bindToggles(selector) {
+ $(selector).each(function(i, el) {
+ bindToggle(el);
+ });
+}
+
+function bindToggleLink(el, prefix) {
+ $(el).click(function() {
+ var href = $(el).attr('href');
+ var i = href.indexOf('#'+prefix);
+ if (i < 0) {
+ return;
+ }
+ var id = '#' + prefix + href.slice(i+1+prefix.length);
+ if ($(id).is('.toggle')) {
+ $(id).find('.toggleButton').first().click();
+ }
+ });
+}
+function bindToggleLinks(selector, prefix) {
+ $(selector).each(function(i, el) {
+ bindToggleLink(el, prefix);
+ });
+}
+
+function setupDropdownPlayground() {
+ if (!$('#page').is('.wide')) {
+ return; // don't show on front page
+ }
+ var button = $('#playgroundButton');
+ var div = $('#playground');
+ var setup = false;
+ button.toggle(function() {
+ button.addClass('active');
+ div.show();
+ if (setup) {
+ return;
+ }
+ setup = true;
+ playground({
+ 'codeEl': $('.code', div),
+ 'outputEl': $('.output', div),
+ 'runEl': $('.run', div),
+ 'fmtEl': $('.fmt', div),
+ 'shareEl': $('.share', div),
+ 'shareRedirect': '//play.golang.org/p/'
+ });
+ },
+ function() {
+ button.removeClass('active');
+ div.hide();
+ });
+ button.show();
+ $('#menu').css('min-width', '+=60');
+}
+
+function setupInlinePlayground() {
+ 'use strict';
+ // Set up playground when each element is toggled.
+ $('div.play').each(function (i, el) {
+ // Set up playground for this example.
+ var setup = function() {
+ var code = $('.code', el);
+ playground({
+ 'codeEl': code,
+ 'outputEl': $('.output', el),
+ 'runEl': $('.run', el),
+ 'fmtEl': $('.fmt', el),
+ 'shareEl': $('.share', el),
+ 'shareRedirect': '//play.golang.org/p/'
+ });
+
+ // Make the code textarea resize to fit content.
+ var resize = function() {
+ code.height(0);
+ var h = code[0].scrollHeight;
+ code.height(h+20); // minimize bouncing.
+ code.closest('.input').height(h);
+ };
+ code.on('keydown', resize);
+ code.on('keyup', resize);
+ code.keyup(); // resize now.
+ };
+
+ // If example already visible, set up playground now.
+ if ($(el).is(':visible')) {
+ setup();
+ return;
+ }
+
+ // Otherwise, set up playground when example is expanded.
+ var built = false;
+ $(el).closest('.toggle').click(function() {
+ // Only set up once.
+ if (!built) {
+ setup();
+ built = true;
+ }
+ });
+ });
+}
+
+// fixFocus tries to put focus to div#page so that keyboard navigation works.
+function fixFocus() {
+ var page = $('div#page');
+ var topbar = $('div#topbar');
+ page.css('outline', 0); // disable outline when focused
+ page.attr('tabindex', -1); // and set tabindex so that it is focusable
+ $(window).resize(function (evt) {
+ // only focus page when the topbar is at fixed position (that is, it's in
+ // front of page, and keyboard event will go to the former by default.)
+ // by focusing page, keyboard event will go to page so that up/down arrow,
+ // space, etc. will work as expected.
+ if (topbar.css('position') == "fixed")
+ page.focus();
+ }).resize();
+}
+
+function toggleHash() {
+ var hash = $(window.location.hash);
+ if (hash.is('.toggle')) {
+ hash.find('.toggleButton').first().click();
+ }
+}
+
+function personalizeInstallInstructions() {
+ var prefix = '?download=';
+ var s = window.location.search;
+ if (!s.startsWith(prefix)) {
+ // No 'download' query string; bail.
+ return;
+ }
+
+ var filename = s.substr(prefix.length);
+ var filenameRE = /^go1\.\d+(\.\d+)?([a-z0-9]+)?\.([a-z0-9]+)(-[a-z0-9]+)?(-osx10\.[68])?\.([a-z.]+)$/;
+ $('.downloadFilename').text(filename);
+ $('.hideFromDownload').hide();
+ var m = filenameRE.exec(filename);
+ if (!m) {
+ // Can't interpret file name; bail.
+ return;
+ }
+
+ var os = m[3];
+ var ext = m[6];
+ if (ext != 'tar.gz') {
+ $('#tarballInstructions').hide();
+ }
+ if (os != 'darwin' || ext != 'pkg') {
+ $('#darwinPackageInstructions').hide();
+ }
+ if (os != 'windows') {
+ $('#windowsInstructions').hide();
+ } else {
+ if (ext != 'msi') {
+ $('#windowsInstallerInstructions').hide();
+ }
+ if (ext != 'zip') {
+ $('#windowsZipInstructions').hide();
+ }
+ }
+
+ var download = "https://storage.googleapis.com/golang/" + filename;
+
+ var message = $('<p class="downloading">'+
+ 'Your download should begin shortly. '+
+ 'If it does not, click <a>this link</a>.</p>');
+ message.find('a').attr('href', download);
+ message.insertAfter('#nav');
+
+ window.location = download;
+}
+
+$(document).ready(function() {
+ bindSearchEvents();
+ generateTOC();
+ bindToggles(".toggle");
+ bindToggles(".toggleVisible");
+ bindToggleLinks(".exampleLink", "example_");
+ bindToggleLinks(".overviewLink", "");
+ bindToggleLinks(".examplesLink", "");
+ bindToggleLinks(".indexLink", "");
+ setupDropdownPlayground();
+ setupInlinePlayground();
+ fixFocus();
+ setupTypeInfo();
+ setupCallgraphs();
+ toggleHash();
+ personalizeInstallInstructions();
+
+ // godoc.html defines window.initFuncs in the <head> tag, and root.html and
+ // codewalk.js push their on-page-ready functions to the list.
+ // We execute those functions here, to avoid loading jQuery until the page
+ // content is loaded.
+ for (var i = 0; i < window.initFuncs.length; i++) window.initFuncs[i]();
+});
+
+// -- analysis ---------------------------------------------------------
+
+// escapeHTML returns HTML for s, with metacharacters quoted.
+// It is safe for use in both elements and attributes
+// (unlike the "set innerText, read innerHTML" trick).
+function escapeHTML(s) {
+ return s.replace(/&/g, '&').
+ replace(/\"/g, '"').
+ replace(/\'/g, ''').
+ replace(/</g, '<').
+ replace(/>/g, '>');
+}
+
+// makeAnchor returns HTML for an <a> element, given an anchorJSON object.
+function makeAnchor(json) {
+ var html = escapeHTML(json.Text);
+ if (json.Href != "") {
+ html = "<a href='" + escapeHTML(json.Href) + "'>" + html + "</a>";
+ }
+ return html;
+}
+
+function showLowFrame(html) {
+ var lowframe = document.getElementById('lowframe');
+ lowframe.style.height = "200px";
+ lowframe.innerHTML = "<p style='text-align: left;'>" + html + "</p>\n" +
+ "<div onclick='hideLowFrame()' style='position: absolute; top: 0; right: 0; cursor: pointer;'>✘</div>"
+};
+
+document.hideLowFrame = function() {
+ var lowframe = document.getElementById('lowframe');
+ lowframe.style.height = "0px";
+}
+
+// onClickCallers is the onclick action for the 'func' tokens of a
+// function declaration.
+document.onClickCallers = function(index) {
+ var data = document.ANALYSIS_DATA[index]
+ if (data.Callers.length == 1 && data.Callers[0].Sites.length == 1) {
+ document.location = data.Callers[0].Sites[0].Href; // jump to sole caller
+ return;
+ }
+
+ var html = "Callers of <code>" + escapeHTML(data.Callee) + "</code>:<br/>\n";
+ for (var i = 0; i < data.Callers.length; i++) {
+ var caller = data.Callers[i];
+ html += "<code>" + escapeHTML(caller.Func) + "</code>";
+ var sites = caller.Sites;
+ if (sites != null && sites.length > 0) {
+ html += " at line ";
+ for (var j = 0; j < sites.length; j++) {
+ if (j > 0) {
+ html += ", ";
+ }
+ html += "<code>" + makeAnchor(sites[j]) + "</code>";
+ }
+ }
+ html += "<br/>\n";
+ }
+ showLowFrame(html);
+};
+
+// onClickCallees is the onclick action for the '(' token of a function call.
+document.onClickCallees = function(index) {
+ var data = document.ANALYSIS_DATA[index]
+ if (data.Callees.length == 1) {
+ document.location = data.Callees[0].Href; // jump to sole callee
+ return;
+ }
+
+ var html = "Callees of this " + escapeHTML(data.Descr) + ":<br/>\n";
+ for (var i = 0; i < data.Callees.length; i++) {
+ html += "<code>" + makeAnchor(data.Callees[i]) + "</code><br/>\n";
+ }
+ showLowFrame(html);
+};
+
+// onClickTypeInfo is the onclick action for identifiers declaring a named type.
+document.onClickTypeInfo = function(index) {
+ var data = document.ANALYSIS_DATA[index];
+ var html = "Type <code>" + data.Name + "</code>: " +
+ " <small>(size=" + data.Size + ", align=" + data.Align + ")</small><br/>\n";
+ html += implementsHTML(data);
+ html += methodsetHTML(data);
+ showLowFrame(html);
+};
+
+// implementsHTML returns HTML for the implements relation of the
+// specified TypeInfoJSON value.
+function implementsHTML(info) {
+ var html = "";
+ if (info.ImplGroups != null) {
+ for (var i = 0; i < info.ImplGroups.length; i++) {
+ var group = info.ImplGroups[i];
+ var x = "<code>" + escapeHTML(group.Descr) + "</code> ";
+ for (var j = 0; j < group.Facts.length; j++) {
+ var fact = group.Facts[j];
+ var y = "<code>" + makeAnchor(fact.Other) + "</code>";
+ if (fact.ByKind != null) {
+ html += escapeHTML(fact.ByKind) + " type " + y + " implements " + x;
+ } else {
+ html += x + " implements " + y;
+ }
+ html += "<br/>\n";
+ }
+ }
+ }
+ return html;
+}
+
+
+// methodsetHTML returns HTML for the methodset of the specified
+// TypeInfoJSON value.
+function methodsetHTML(info) {
+ var html = "";
+ if (info.Methods != null) {
+ for (var i = 0; i < info.Methods.length; i++) {
+ html += "<code>" + makeAnchor(info.Methods[i]) + "</code><br/>\n";
+ }
+ }
+ return html;
+}
+
+// onClickComm is the onclick action for channel "make" and "<-"
+// send/receive tokens.
+document.onClickComm = function(index) {
+ var ops = document.ANALYSIS_DATA[index].Ops
+ if (ops.length == 1) {
+ document.location = ops[0].Op.Href; // jump to sole element
+ return;
+ }
+
+ var html = "Operations on this channel:<br/>\n";
+ for (var i = 0; i < ops.length; i++) {
+ html += makeAnchor(ops[i].Op) + " by <code>" + escapeHTML(ops[i].Fn) + "</code><br/>\n";
+ }
+ if (ops.length == 0) {
+ html += "(none)<br/>\n";
+ }
+ showLowFrame(html);
+};
+
+$(window).load(function() {
+ // Scroll window so that first selection is visible.
+ // (This means we don't need to emit id='L%d' spans for each line.)
+ // TODO(adonovan): ideally, scroll it so that it's under the pointer,
+ // but I don't know how to get the pointer y coordinate.
+ var elts = document.getElementsByClassName("selection");
+ if (elts.length > 0) {
+ elts[0].scrollIntoView()
+ }
+});
+
+// setupTypeInfo populates the "Implements" and "Method set" toggle for
+// each type in the package doc.
+function setupTypeInfo() {
+ for (var i in document.ANALYSIS_DATA) {
+ var data = document.ANALYSIS_DATA[i];
+
+ var el = document.getElementById("implements-" + i);
+ if (el != null) {
+ // el != null => data is TypeInfoJSON.
+ if (data.ImplGroups != null) {
+ el.innerHTML = implementsHTML(data);
+ el.parentNode.parentNode.style.display = "block";
+ }
+ }
+
+ var el = document.getElementById("methodset-" + i);
+ if (el != null) {
+ // el != null => data is TypeInfoJSON.
+ if (data.Methods != null) {
+ el.innerHTML = methodsetHTML(data);
+ el.parentNode.parentNode.style.display = "block";
+ }
+ }
+ }
+}
+
+function setupCallgraphs() {
+ if (document.CALLGRAPH == null) {
+ return
+ }
+ document.getElementById("pkg-callgraph").style.display = "block";
+
+ var treeviews = document.getElementsByClassName("treeview");
+ for (var i = 0; i < treeviews.length; i++) {
+ var tree = treeviews[i];
+ if (tree.id == null || tree.id.indexOf("callgraph-") != 0) {
+ continue;
+ }
+ var id = tree.id.substring("callgraph-".length);
+ $(tree).treeview({collapsed: true, animated: "fast"});
+ document.cgAddChildren(tree, tree, [id]);
+ tree.parentNode.parentNode.style.display = "block";
+ }
+}
+
+document.cgAddChildren = function(tree, ul, indices) {
+ if (indices != null) {
+ for (var i = 0; i < indices.length; i++) {
+ var li = cgAddChild(tree, ul, document.CALLGRAPH[indices[i]]);
+ if (i == indices.length - 1) {
+ $(li).addClass("last");
+ }
+ }
+ }
+ $(tree).treeview({animated: "fast", add: ul});
+}
+
+// cgAddChild adds an <li> element for document.CALLGRAPH node cgn to
+// the parent <ul> element ul. tree is the tree's root <ul> element.
+function cgAddChild(tree, ul, cgn) {
+ var li = document.createElement("li");
+ ul.appendChild(li);
+ li.className = "closed";
+
+ var code = document.createElement("code");
+
+ if (cgn.Callees != null) {
+ $(li).addClass("expandable");
+
+ // Event handlers and innerHTML updates don't play nicely together,
+ // hence all this explicit DOM manipulation.
+ var hitarea = document.createElement("div");
+ hitarea.className = "hitarea expandable-hitarea";
+ li.appendChild(hitarea);
+
+ li.appendChild(code);
+
+ var childUL = document.createElement("ul");
+ li.appendChild(childUL);
+ childUL.setAttribute('style', "display: none;");
+
+ var onClick = function() {
+ document.cgAddChildren(tree, childUL, cgn.Callees);
+ hitarea.removeEventListener('click', onClick)
+ };
+ hitarea.addEventListener('click', onClick);
+
+ } else {
+ li.appendChild(code);
+ }
+ code.innerHTML += " " + makeAnchor(cgn.Func);
+ return li
+}
+
+})();
diff --git a/godoc/static/images/minus.gif b/godoc/static/images/minus.gif
new file mode 100644
index 0000000..47fb7b7
--- /dev/null
+++ b/godoc/static/images/minus.gif
Binary files differ
diff --git a/godoc/static/images/plus.gif b/godoc/static/images/plus.gif
new file mode 100644
index 0000000..6906621
--- /dev/null
+++ b/godoc/static/images/plus.gif
Binary files differ
diff --git a/godoc/static/images/treeview-black-line.gif b/godoc/static/images/treeview-black-line.gif
new file mode 100644
index 0000000..e549687
--- /dev/null
+++ b/godoc/static/images/treeview-black-line.gif
Binary files differ
diff --git a/godoc/static/images/treeview-black.gif b/godoc/static/images/treeview-black.gif
new file mode 100644
index 0000000..b718d17
--- /dev/null
+++ b/godoc/static/images/treeview-black.gif
Binary files differ
diff --git a/godoc/static/images/treeview-default-line.gif b/godoc/static/images/treeview-default-line.gif
new file mode 100644
index 0000000..37114d3
--- /dev/null
+++ b/godoc/static/images/treeview-default-line.gif
Binary files differ
diff --git a/godoc/static/images/treeview-default.gif b/godoc/static/images/treeview-default.gif
new file mode 100644
index 0000000..76eee60
--- /dev/null
+++ b/godoc/static/images/treeview-default.gif
Binary files differ
diff --git a/godoc/static/images/treeview-gray-line.gif b/godoc/static/images/treeview-gray-line.gif
new file mode 100644
index 0000000..3760044
--- /dev/null
+++ b/godoc/static/images/treeview-gray-line.gif
Binary files differ
diff --git a/godoc/static/images/treeview-gray.gif b/godoc/static/images/treeview-gray.gif
new file mode 100644
index 0000000..cfdf1ab
--- /dev/null
+++ b/godoc/static/images/treeview-gray.gif
Binary files differ
diff --git a/godoc/static/implements.html b/godoc/static/implements.html
new file mode 100644
index 0000000..5f65b86
--- /dev/null
+++ b/godoc/static/implements.html
@@ -0,0 +1,9 @@
+<div class="toggle" style="display: none">
+ <div class="collapsed">
+ <p class="exampleHeading toggleButton">▹ <span class="text">Implements</span></p>
+ </div>
+ <div class="expanded">
+ <p class="exampleHeading toggleButton">▾ <span class="text">Implements</span></p>
+ <div style="margin-left: 1in" id='implements-{{.Index}}'>...</div>
+ </div>
+</div>
diff --git a/godoc/static/jquery.js b/godoc/static/jquery.js
new file mode 100644
index 0000000..bc3fbc8
--- /dev/null
+++ b/godoc/static/jquery.js
@@ -0,0 +1,2 @@
+/*! jQuery v1.8.2 jquery.com | jquery.org/license */
+(function(a,b){function G(a){var b=F[a]={};return p.each(a.split(s),function(a,c){b[c]=!0}),b}function J(a,c,d){if(d===b&&a.nodeType===1){var e="data-"+c.replace(I,"-$1").toLowerCase();d=a.getAttribute(e);if(typeof d=="string"){try{d=d==="true"?!0:d==="false"?!1:d==="null"?null:+d+""===d?+d:H.test(d)?p.parseJSON(d):d}catch(f){}p.data(a,c,d)}else d=b}return d}function K(a){var b;for(b in a){if(b==="data"&&p.isEmptyObject(a[b]))continue;if(b!=="toJSON")return!1}return!0}function ba(){return!1}function bb(){return!0}function bh(a){return!a||!a.parentNode||a.parentNode.nodeType===11}function bi(a,b){do a=a[b];while(a&&a.nodeType!==1);return a}function bj(a,b,c){b=b||0;if(p.isFunction(b))return p.grep(a,function(a,d){var e=!!b.call(a,d,a);return e===c});if(b.nodeType)return p.grep(a,function(a,d){return a===b===c});if(typeof b=="string"){var d=p.grep(a,function(a){return a.nodeType===1});if(be.test(b))return p.filter(b,d,!c);b=p.filter(b,d)}return p.grep(a,function(a,d){return p.inArray(a,b)>=0===c})}function bk(a){var b=bl.split("|"),c=a.createDocumentFragment();if(c.createElement)while(b.length)c.createElement(b.pop());return c}function bC(a,b){return a.getElementsByTagName(b)[0]||a.appendChild(a.ownerDocument.createElement(b))}function bD(a,b){if(b.nodeType!==1||!p.hasData(a))return;var c,d,e,f=p._data(a),g=p._data(b,f),h=f.events;if(h){delete g.handle,g.events={};for(c in h)for(d=0,e=h[c].length;d<e;d++)p.event.add(b,c,h[c][d])}g.data&&(g.data=p.extend({},g.data))}function bE(a,b){var c;if(b.nodeType!==1)return;b.clearAttributes&&b.clearAttributes(),b.mergeAttributes&&b.mergeAttributes(a),c=b.nodeName.toLowerCase(),c==="object"?(b.parentNode&&(b.outerHTML=a.outerHTML),p.support.html5Clone&&a.innerHTML&&!p.trim(b.innerHTML)&&(b.innerHTML=a.innerHTML)):c==="input"&&bv.test(a.type)?(b.defaultChecked=b.checked=a.checked,b.value!==a.value&&(b.value=a.value)):c==="option"?b.selected=a.defaultSelected:c==="input"||c==="textarea"?b.defaultValue=a.defaultValue:c==="script"&&b.text!==a.text&&(b.text=a.text),b.removeAttribute(p.expando)}function bF(a){return typeof a.getElementsByTagName!="undefined"?a.getElementsByTagName("*"):typeof a.querySelectorAll!="undefined"?a.querySelectorAll("*"):[]}function bG(a){bv.test(a.type)&&(a.defaultChecked=a.checked)}function bY(a,b){if(b in a)return b;var c=b.charAt(0).toUpperCase()+b.slice(1),d=b,e=bW.length;while(e--){b=bW[e]+c;if(b in a)return b}return d}function bZ(a,b){return a=b||a,p.css(a,"display")==="none"||!p.contains(a.ownerDocument,a)}function b$(a,b){var c,d,e=[],f=0,g=a.length;for(;f<g;f++){c=a[f];if(!c.style)continue;e[f]=p._data(c,"olddisplay"),b?(!e[f]&&c.style.display==="none"&&(c.style.display=""),c.style.display===""&&bZ(c)&&(e[f]=p._data(c,"olddisplay",cc(c.nodeName)))):(d=bH(c,"display"),!e[f]&&d!=="none"&&p._data(c,"olddisplay",d))}for(f=0;f<g;f++){c=a[f];if(!c.style)continue;if(!b||c.style.display==="none"||c.style.display==="")c.style.display=b?e[f]||"":"none"}return a}function b_(a,b,c){var d=bP.exec(b);return d?Math.max(0,d[1]-(c||0))+(d[2]||"px"):b}function ca(a,b,c,d){var e=c===(d?"border":"content")?4:b==="width"?1:0,f=0;for(;e<4;e+=2)c==="margin"&&(f+=p.css(a,c+bV[e],!0)),d?(c==="content"&&(f-=parseFloat(bH(a,"padding"+bV[e]))||0),c!=="margin"&&(f-=parseFloat(bH(a,"border"+bV[e]+"Width"))||0)):(f+=parseFloat(bH(a,"padding"+bV[e]))||0,c!=="padding"&&(f+=parseFloat(bH(a,"border"+bV[e]+"Width"))||0));return f}function cb(a,b,c){var d=b==="width"?a.offsetWidth:a.offsetHeight,e=!0,f=p.support.boxSizing&&p.css(a,"boxSizing")==="border-box";if(d<=0||d==null){d=bH(a,b);if(d<0||d==null)d=a.style[b];if(bQ.test(d))return d;e=f&&(p.support.boxSizingReliable||d===a.style[b]),d=parseFloat(d)||0}return d+ca(a,b,c||(f?"border":"content"),e)+"px"}function cc(a){if(bS[a])return bS[a];var b=p("<"+a+">").appendTo(e.body),c=b.css("display");b.remove();if(c==="none"||c===""){bI=e.body.appendChild(bI||p.extend(e.createElement("iframe"),{frameBorder:0,width:0,height:0}));if(!bJ||!bI.createElement)bJ=(bI.contentWindow||bI.contentDocument).document,bJ.write("<!doctype html><html><body>"),bJ.close();b=bJ.body.appendChild(bJ.createElement(a)),c=bH(b,"display"),e.body.removeChild(bI)}return bS[a]=c,c}function ci(a,b,c,d){var e;if(p.isArray(b))p.each(b,function(b,e){c||ce.test(a)?d(a,e):ci(a+"["+(typeof e=="object"?b:"")+"]",e,c,d)});else if(!c&&p.type(b)==="object")for(e in b)ci(a+"["+e+"]",b[e],c,d);else d(a,b)}function cz(a){return function(b,c){typeof b!="string"&&(c=b,b="*");var d,e,f,g=b.toLowerCase().split(s),h=0,i=g.length;if(p.isFunction(c))for(;h<i;h++)d=g[h],f=/^\+/.test(d),f&&(d=d.substr(1)||"*"),e=a[d]=a[d]||[],e[f?"unshift":"push"](c)}}function cA(a,c,d,e,f,g){f=f||c.dataTypes[0],g=g||{},g[f]=!0;var h,i=a[f],j=0,k=i?i.length:0,l=a===cv;for(;j<k&&(l||!h);j++)h=i[j](c,d,e),typeof h=="string"&&(!l||g[h]?h=b:(c.dataTypes.unshift(h),h=cA(a,c,d,e,h,g)));return(l||!h)&&!g["*"]&&(h=cA(a,c,d,e,"*",g)),h}function cB(a,c){var d,e,f=p.ajaxSettings.flatOptions||{};for(d in c)c[d]!==b&&((f[d]?a:e||(e={}))[d]=c[d]);e&&p.extend(!0,a,e)}function cC(a,c,d){var e,f,g,h,i=a.contents,j=a.dataTypes,k=a.responseFields;for(f in k)f in d&&(c[k[f]]=d[f]);while(j[0]==="*")j.shift(),e===b&&(e=a.mimeType||c.getResponseHeader("content-type"));if(e)for(f in i)if(i[f]&&i[f].test(e)){j.unshift(f);break}if(j[0]in d)g=j[0];else{for(f in d){if(!j[0]||a.converters[f+" "+j[0]]){g=f;break}h||(h=f)}g=g||h}if(g)return g!==j[0]&&j.unshift(g),d[g]}function cD(a,b){var c,d,e,f,g=a.dataTypes.slice(),h=g[0],i={},j=0;a.dataFilter&&(b=a.dataFilter(b,a.dataType));if(g[1])for(c in a.converters)i[c.toLowerCase()]=a.converters[c];for(;e=g[++j];)if(e!=="*"){if(h!=="*"&&h!==e){c=i[h+" "+e]||i["* "+e];if(!c)for(d in i){f=d.split(" ");if(f[1]===e){c=i[h+" "+f[0]]||i["* "+f[0]];if(c){c===!0?c=i[d]:i[d]!==!0&&(e=f[0],g.splice(j--,0,e));break}}}if(c!==!0)if(c&&a["throws"])b=c(b);else try{b=c(b)}catch(k){return{state:"parsererror",error:c?k:"No conversion from "+h+" to "+e}}}h=e}return{state:"success",data:b}}function cL(){try{return new a.XMLHttpRequest}catch(b){}}function cM(){try{return new a.ActiveXObject("Microsoft.XMLHTTP")}catch(b){}}function cU(){return setTimeout(function(){cN=b},0),cN=p.now()}function cV(a,b){p.each(b,function(b,c){var d=(cT[b]||[]).concat(cT["*"]),e=0,f=d.length;for(;e<f;e++)if(d[e].call(a,b,c))return})}function cW(a,b,c){var d,e=0,f=0,g=cS.length,h=p.Deferred().always(function(){delete i.elem}),i=function(){var b=cN||cU(),c=Math.max(0,j.startTime+j.duration-b),d=1-(c/j.duration||0),e=0,f=j.tweens.length;for(;e<f;e++)j.tweens[e].run(d);return h.notifyWith(a,[j,d,c]),d<1&&f?c:(h.resolveWith(a,[j]),!1)},j=h.promise({elem:a,props:p.extend({},b),opts:p.extend(!0,{specialEasing:{}},c),originalProperties:b,originalOptions:c,startTime:cN||cU(),duration:c.duration,tweens:[],createTween:function(b,c,d){var e=p.Tween(a,j.opts,b,c,j.opts.specialEasing[b]||j.opts.easing);return j.tweens.push(e),e},stop:function(b){var c=0,d=b?j.tweens.length:0;for(;c<d;c++)j.tweens[c].run(1);return b?h.resolveWith(a,[j,b]):h.rejectWith(a,[j,b]),this}}),k=j.props;cX(k,j.opts.specialEasing);for(;e<g;e++){d=cS[e].call(j,a,k,j.opts);if(d)return d}return cV(j,k),p.isFunction(j.opts.start)&&j.opts.start.call(a,j),p.fx.timer(p.extend(i,{anim:j,queue:j.opts.queue,elem:a})),j.progress(j.opts.progress).done(j.opts.done,j.opts.complete).fail(j.opts.fail).always(j.opts.always)}function cX(a,b){var c,d,e,f,g;for(c in a){d=p.camelCase(c),e=b[d],f=a[c],p.isArray(f)&&(e=f[1],f=a[c]=f[0]),c!==d&&(a[d]=f,delete a[c]),g=p.cssHooks[d];if(g&&"expand"in g){f=g.expand(f),delete a[d];for(c in f)c in a||(a[c]=f[c],b[c]=e)}else b[d]=e}}function cY(a,b,c){var d,e,f,g,h,i,j,k,l=this,m=a.style,n={},o=[],q=a.nodeType&&bZ(a);c.queue||(j=p._queueHooks(a,"fx"),j.unqueued==null&&(j.unqueued=0,k=j.empty.fire,j.empty.fire=function(){j.unqueued||k()}),j.unqueued++,l.always(function(){l.always(function(){j.unqueued--,p.queue(a,"fx").length||j.empty.fire()})})),a.nodeType===1&&("height"in b||"width"in b)&&(c.overflow=[m.overflow,m.overflowX,m.overflowY],p.css(a,"display")==="inline"&&p.css(a,"float")==="none"&&(!p.support.inlineBlockNeedsLayout||cc(a.nodeName)==="inline"?m.display="inline-block":m.zoom=1)),c.overflow&&(m.overflow="hidden",p.support.shrinkWrapBlocks||l.done(function(){m.overflow=c.overflow[0],m.overflowX=c.overflow[1],m.overflowY=c.overflow[2]}));for(d in b){f=b[d];if(cP.exec(f)){delete b[d];if(f===(q?"hide":"show"))continue;o.push(d)}}g=o.length;if(g){h=p._data(a,"fxshow")||p._data(a,"fxshow",{}),q?p(a).show():l.done(function(){p(a).hide()}),l.done(function(){var b;p.removeData(a,"fxshow",!0);for(b in n)p.style(a,b,n[b])});for(d=0;d<g;d++)e=o[d],i=l.createTween(e,q?h[e]:0),n[e]=h[e]||p.style(a,e),e in h||(h[e]=i.start,q&&(i.end=i.start,i.start=e==="width"||e==="height"?1:0))}}function cZ(a,b,c,d,e){return new cZ.prototype.init(a,b,c,d,e)}function c$(a,b){var c,d={height:a},e=0;b=b?1:0;for(;e<4;e+=2-b)c=bV[e],d["margin"+c]=d["padding"+c]=a;return b&&(d.opacity=d.width=a),d}function da(a){return p.isWindow(a)?a:a.nodeType===9?a.defaultView||a.parentWindow:!1}var c,d,e=a.document,f=a.location,g=a.navigator,h=a.jQuery,i=a.$,j=Array.prototype.push,k=Array.prototype.slice,l=Array.prototype.indexOf,m=Object.prototype.toString,n=Object.prototype.hasOwnProperty,o=String.prototype.trim,p=function(a,b){return new p.fn.init(a,b,c)},q=/[\-+]?(?:\d*\.|)\d+(?:[eE][\-+]?\d+|)/.source,r=/\S/,s=/\s+/,t=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,u=/^(?:[^#<]*(<[\w\W]+>)[^>]*$|#([\w\-]*)$)/,v=/^<(\w+)\s*\/?>(?:<\/\1>|)$/,w=/^[\],:{}\s]*$/,x=/(?:^|:|,)(?:\s*\[)+/g,y=/\\(?:["\\\/bfnrt]|u[\da-fA-F]{4})/g,z=/"[^"\\\r\n]*"|true|false|null|-?(?:\d\d*\.|)\d+(?:[eE][\-+]?\d+|)/g,A=/^-ms-/,B=/-([\da-z])/gi,C=function(a,b){return(b+"").toUpperCase()},D=function(){e.addEventListener?(e.removeEventListener("DOMContentLoaded",D,!1),p.ready()):e.readyState==="complete"&&(e.detachEvent("onreadystatechange",D),p.ready())},E={};p.fn=p.prototype={constructor:p,init:function(a,c,d){var f,g,h,i;if(!a)return this;if(a.nodeType)return this.context=this[0]=a,this.length=1,this;if(typeof a=="string"){a.charAt(0)==="<"&&a.charAt(a.length-1)===">"&&a.length>=3?f=[null,a,null]:f=u.exec(a);if(f&&(f[1]||!c)){if(f[1])return c=c instanceof p?c[0]:c,i=c&&c.nodeType?c.ownerDocument||c:e,a=p.parseHTML(f[1],i,!0),v.test(f[1])&&p.isPlainObject(c)&&this.attr.call(a,c,!0),p.merge(this,a);g=e.getElementById(f[2]);if(g&&g.parentNode){if(g.id!==f[2])return d.find(a);this.length=1,this[0]=g}return this.context=e,this.selector=a,this}return!c||c.jquery?(c||d).find(a):this.constructor(c).find(a)}return p.isFunction(a)?d.ready(a):(a.selector!==b&&(this.selector=a.selector,this.context=a.context),p.makeArray(a,this))},selector:"",jquery:"1.8.2",length:0,size:function(){return this.length},toArray:function(){return k.call(this)},get:function(a){return a==null?this.toArray():a<0?this[this.length+a]:this[a]},pushStack:function(a,b,c){var d=p.merge(this.constructor(),a);return d.prevObject=this,d.context=this.context,b==="find"?d.selector=this.selector+(this.selector?" ":"")+c:b&&(d.selector=this.selector+"."+b+"("+c+")"),d},each:function(a,b){return p.each(this,a,b)},ready:function(a){return p.ready.promise().done(a),this},eq:function(a){return a=+a,a===-1?this.slice(a):this.slice(a,a+1)},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},slice:function(){return this.pushStack(k.apply(this,arguments),"slice",k.call(arguments).join(","))},map:function(a){return this.pushStack(p.map(this,function(b,c){return a.call(b,c,b)}))},end:function(){return this.prevObject||this.constructor(null)},push:j,sort:[].sort,splice:[].splice},p.fn.init.prototype=p.fn,p.extend=p.fn.extend=function(){var a,c,d,e,f,g,h=arguments[0]||{},i=1,j=arguments.length,k=!1;typeof h=="boolean"&&(k=h,h=arguments[1]||{},i=2),typeof h!="object"&&!p.isFunction(h)&&(h={}),j===i&&(h=this,--i);for(;i<j;i++)if((a=arguments[i])!=null)for(c in a){d=h[c],e=a[c];if(h===e)continue;k&&e&&(p.isPlainObject(e)||(f=p.isArray(e)))?(f?(f=!1,g=d&&p.isArray(d)?d:[]):g=d&&p.isPlainObject(d)?d:{},h[c]=p.extend(k,g,e)):e!==b&&(h[c]=e)}return h},p.extend({noConflict:function(b){return a.$===p&&(a.$=i),b&&a.jQuery===p&&(a.jQuery=h),p},isReady:!1,readyWait:1,holdReady:function(a){a?p.readyWait++:p.ready(!0)},ready:function(a){if(a===!0?--p.readyWait:p.isReady)return;if(!e.body)return setTimeout(p.ready,1);p.isReady=!0;if(a!==!0&&--p.readyWait>0)return;d.resolveWith(e,[p]),p.fn.trigger&&p(e).trigger("ready").off("ready")},isFunction:function(a){return p.type(a)==="function"},isArray:Array.isArray||function(a){return p.type(a)==="array"},isWindow:function(a){return a!=null&&a==a.window},isNumeric:function(a){return!isNaN(parseFloat(a))&&isFinite(a)},type:function(a){return a==null?String(a):E[m.call(a)]||"object"},isPlainObject:function(a){if(!a||p.type(a)!=="object"||a.nodeType||p.isWindow(a))return!1;try{if(a.constructor&&!n.call(a,"constructor")&&!n.call(a.constructor.prototype,"isPrototypeOf"))return!1}catch(c){return!1}var d;for(d in a);return d===b||n.call(a,d)},isEmptyObject:function(a){var b;for(b in a)return!1;return!0},error:function(a){throw new Error(a)},parseHTML:function(a,b,c){var d;return!a||typeof a!="string"?null:(typeof b=="boolean"&&(c=b,b=0),b=b||e,(d=v.exec(a))?[b.createElement(d[1])]:(d=p.buildFragment([a],b,c?null:[]),p.merge([],(d.cacheable?p.clone(d.fragment):d.fragment).childNodes)))},parseJSON:function(b){if(!b||typeof b!="string")return null;b=p.trim(b);if(a.JSON&&a.JSON.parse)return a.JSON.parse(b);if(w.test(b.replace(y,"@").replace(z,"]").replace(x,"")))return(new Function("return "+b))();p.error("Invalid JSON: "+b)},parseXML:function(c){var d,e;if(!c||typeof c!="string")return null;try{a.DOMParser?(e=new DOMParser,d=e.parseFromString(c,"text/xml")):(d=new ActiveXObject("Microsoft.XMLDOM"),d.async="false",d.loadXML(c))}catch(f){d=b}return(!d||!d.documentElement||d.getElementsByTagName("parsererror").length)&&p.error("Invalid XML: "+c),d},noop:function(){},globalEval:function(b){b&&r.test(b)&&(a.execScript||function(b){a.eval.call(a,b)})(b)},camelCase:function(a){return a.replace(A,"ms-").replace(B,C)},nodeName:function(a,b){return a.nodeName&&a.nodeName.toLowerCase()===b.toLowerCase()},each:function(a,c,d){var e,f=0,g=a.length,h=g===b||p.isFunction(a);if(d){if(h){for(e in a)if(c.apply(a[e],d)===!1)break}else for(;f<g;)if(c.apply(a[f++],d)===!1)break}else if(h){for(e in a)if(c.call(a[e],e,a[e])===!1)break}else for(;f<g;)if(c.call(a[f],f,a[f++])===!1)break;return a},trim:o&&!o.call(" ")?function(a){return a==null?"":o.call(a)}:function(a){return a==null?"":(a+"").replace(t,"")},makeArray:function(a,b){var c,d=b||[];return a!=null&&(c=p.type(a),a.length==null||c==="string"||c==="function"||c==="regexp"||p.isWindow(a)?j.call(d,a):p.merge(d,a)),d},inArray:function(a,b,c){var d;if(b){if(l)return l.call(b,a,c);d=b.length,c=c?c<0?Math.max(0,d+c):c:0;for(;c<d;c++)if(c in b&&b[c]===a)return c}return-1},merge:function(a,c){var d=c.length,e=a.length,f=0;if(typeof d=="number")for(;f<d;f++)a[e++]=c[f];else while(c[f]!==b)a[e++]=c[f++];return a.length=e,a},grep:function(a,b,c){var d,e=[],f=0,g=a.length;c=!!c;for(;f<g;f++)d=!!b(a[f],f),c!==d&&e.push(a[f]);return e},map:function(a,c,d){var e,f,g=[],h=0,i=a.length,j=a instanceof p||i!==b&&typeof i=="number"&&(i>0&&a[0]&&a[i-1]||i===0||p.isArray(a));if(j)for(;h<i;h++)e=c(a[h],h,d),e!=null&&(g[g.length]=e);else for(f in a)e=c(a[f],f,d),e!=null&&(g[g.length]=e);return g.concat.apply([],g)},guid:1,proxy:function(a,c){var d,e,f;return typeof c=="string"&&(d=a[c],c=a,a=d),p.isFunction(a)?(e=k.call(arguments,2),f=function(){return a.apply(c,e.concat(k.call(arguments)))},f.guid=a.guid=a.guid||p.guid++,f):b},access:function(a,c,d,e,f,g,h){var i,j=d==null,k=0,l=a.length;if(d&&typeof d=="object"){for(k in d)p.access(a,c,k,d[k],1,g,e);f=1}else if(e!==b){i=h===b&&p.isFunction(e),j&&(i?(i=c,c=function(a,b,c){return i.call(p(a),c)}):(c.call(a,e),c=null));if(c)for(;k<l;k++)c(a[k],d,i?e.call(a[k],k,c(a[k],d)):e,h);f=1}return f?a:j?c.call(a):l?c(a[0],d):g},now:function(){return(new Date).getTime()}}),p.ready.promise=function(b){if(!d){d=p.Deferred();if(e.readyState==="complete")setTimeout(p.ready,1);else if(e.addEventListener)e.addEventListener("DOMContentLoaded",D,!1),a.addEventListener("load",p.ready,!1);else{e.attachEvent("onreadystatechange",D),a.attachEvent("onload",p.ready);var c=!1;try{c=a.frameElement==null&&e.documentElement}catch(f){}c&&c.doScroll&&function g(){if(!p.isReady){try{c.doScroll("left")}catch(a){return setTimeout(g,50)}p.ready()}}()}}return d.promise(b)},p.each("Boolean Number String Function Array Date RegExp Object".split(" "),function(a,b){E["[object "+b+"]"]=b.toLowerCase()}),c=p(e);var F={};p.Callbacks=function(a){a=typeof a=="string"?F[a]||G(a):p.extend({},a);var c,d,e,f,g,h,i=[],j=!a.once&&[],k=function(b){c=a.memory&&b,d=!0,h=f||0,f=0,g=i.length,e=!0;for(;i&&h<g;h++)if(i[h].apply(b[0],b[1])===!1&&a.stopOnFalse){c=!1;break}e=!1,i&&(j?j.length&&k(j.shift()):c?i=[]:l.disable())},l={add:function(){if(i){var b=i.length;(function d(b){p.each(b,function(b,c){var e=p.type(c);e==="function"&&(!a.unique||!l.has(c))?i.push(c):c&&c.length&&e!=="string"&&d(c)})})(arguments),e?g=i.length:c&&(f=b,k(c))}return this},remove:function(){return i&&p.each(arguments,function(a,b){var c;while((c=p.inArray(b,i,c))>-1)i.splice(c,1),e&&(c<=g&&g--,c<=h&&h--)}),this},has:function(a){return p.inArray(a,i)>-1},empty:function(){return i=[],this},disable:function(){return i=j=c=b,this},disabled:function(){return!i},lock:function(){return j=b,c||l.disable(),this},locked:function(){return!j},fireWith:function(a,b){return b=b||[],b=[a,b.slice?b.slice():b],i&&(!d||j)&&(e?j.push(b):k(b)),this},fire:function(){return l.fireWith(this,arguments),this},fired:function(){return!!d}};return l},p.extend({Deferred:function(a){var b=[["resolve","done",p.Callbacks("once memory"),"resolved"],["reject","fail",p.Callbacks("once memory"),"rejected"],["notify","progress",p.Callbacks("memory")]],c="pending",d={state:function(){return c},always:function(){return e.done(arguments).fail(arguments),this},then:function(){var a=arguments;return p.Deferred(function(c){p.each(b,function(b,d){var f=d[0],g=a[b];e[d[1]](p.isFunction(g)?function(){var a=g.apply(this,arguments);a&&p.isFunction(a.promise)?a.promise().done(c.resolve).fail(c.reject).progress(c.notify):c[f+"With"](this===e?c:this,[a])}:c[f])}),a=null}).promise()},promise:function(a){return a!=null?p.extend(a,d):d}},e={};return d.pipe=d.then,p.each(b,function(a,f){var g=f[2],h=f[3];d[f[1]]=g.add,h&&g.add(function(){c=h},b[a^1][2].disable,b[2][2].lock),e[f[0]]=g.fire,e[f[0]+"With"]=g.fireWith}),d.promise(e),a&&a.call(e,e),e},when:function(a){var b=0,c=k.call(arguments),d=c.length,e=d!==1||a&&p.isFunction(a.promise)?d:0,f=e===1?a:p.Deferred(),g=function(a,b,c){return function(d){b[a]=this,c[a]=arguments.length>1?k.call(arguments):d,c===h?f.notifyWith(b,c):--e||f.resolveWith(b,c)}},h,i,j;if(d>1){h=new Array(d),i=new Array(d),j=new Array(d);for(;b<d;b++)c[b]&&p.isFunction(c[b].promise)?c[b].promise().done(g(b,j,c)).fail(f.reject).progress(g(b,i,h)):--e}return e||f.resolveWith(j,c),f.promise()}}),p.support=function(){var b,c,d,f,g,h,i,j,k,l,m,n=e.createElement("div");n.setAttribute("className","t"),n.innerHTML=" <link/><table></table><a href='/a'>a</a><input type='checkbox'/>",c=n.getElementsByTagName("*"),d=n.getElementsByTagName("a")[0],d.style.cssText="top:1px;float:left;opacity:.5";if(!c||!c.length)return{};f=e.createElement("select"),g=f.appendChild(e.createElement("option")),h=n.getElementsByTagName("input")[0],b={leadingWhitespace:n.firstChild.nodeType===3,tbody:!n.getElementsByTagName("tbody").length,htmlSerialize:!!n.getElementsByTagName("link").length,style:/top/.test(d.getAttribute("style")),hrefNormalized:d.getAttribute("href")==="/a",opacity:/^0.5/.test(d.style.opacity),cssFloat:!!d.style.cssFloat,checkOn:h.value==="on",optSelected:g.selected,getSetAttribute:n.className!=="t",enctype:!!e.createElement("form").enctype,html5Clone:e.createElement("nav").cloneNode(!0).outerHTML!=="<:nav></:nav>",boxModel:e.compatMode==="CSS1Compat",submitBubbles:!0,changeBubbles:!0,focusinBubbles:!1,deleteExpando:!0,noCloneEvent:!0,inlineBlockNeedsLayout:!1,shrinkWrapBlocks:!1,reliableMarginRight:!0,boxSizingReliable:!0,pixelPosition:!1},h.checked=!0,b.noCloneChecked=h.cloneNode(!0).checked,f.disabled=!0,b.optDisabled=!g.disabled;try{delete n.test}catch(o){b.deleteExpando=!1}!n.addEventListener&&n.attachEvent&&n.fireEvent&&(n.attachEvent("onclick",m=function(){b.noCloneEvent=!1}),n.cloneNode(!0).fireEvent("onclick"),n.detachEvent("onclick",m)),h=e.createElement("input"),h.value="t",h.setAttribute("type","radio"),b.radioValue=h.value==="t",h.setAttribute("checked","checked"),h.setAttribute("name","t"),n.appendChild(h),i=e.createDocumentFragment(),i.appendChild(n.lastChild),b.checkClone=i.cloneNode(!0).cloneNode(!0).lastChild.checked,b.appendChecked=h.checked,i.removeChild(h),i.appendChild(n);if(n.attachEvent)for(k in{submit:!0,change:!0,focusin:!0})j="on"+k,l=j in n,l||(n.setAttribute(j,"return;"),l=typeof n[j]=="function"),b[k+"Bubbles"]=l;return p(function(){var c,d,f,g,h="padding:0;margin:0;border:0;display:block;overflow:hidden;",i=e.getElementsByTagName("body")[0];if(!i)return;c=e.createElement("div"),c.style.cssText="visibility:hidden;border:0;width:0;height:0;position:static;top:0;margin-top:1px",i.insertBefore(c,i.firstChild),d=e.createElement("div"),c.appendChild(d),d.innerHTML="<table><tr><td></td><td>t</td></tr></table>",f=d.getElementsByTagName("td"),f[0].style.cssText="padding:0;margin:0;border:0;display:none",l=f[0].offsetHeight===0,f[0].style.display="",f[1].style.display="none",b.reliableHiddenOffsets=l&&f[0].offsetHeight===0,d.innerHTML="",d.style.cssText="box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;padding:1px;border:1px;display:block;width:4px;margin-top:1%;position:absolute;top:1%;",b.boxSizing=d.offsetWidth===4,b.doesNotIncludeMarginInBodyOffset=i.offsetTop!==1,a.getComputedStyle&&(b.pixelPosition=(a.getComputedStyle(d,null)||{}).top!=="1%",b.boxSizingReliable=(a.getComputedStyle(d,null)||{width:"4px"}).width==="4px",g=e.createElement("div"),g.style.cssText=d.style.cssText=h,g.style.marginRight=g.style.width="0",d.style.width="1px",d.appendChild(g),b.reliableMarginRight=!parseFloat((a.getComputedStyle(g,null)||{}).marginRight)),typeof d.style.zoom!="undefined"&&(d.innerHTML="",d.style.cssText=h+"width:1px;padding:1px;display:inline;zoom:1",b.inlineBlockNeedsLayout=d.offsetWidth===3,d.style.display="block",d.style.overflow="visible",d.innerHTML="<div></div>",d.firstChild.style.width="5px",b.shrinkWrapBlocks=d.offsetWidth!==3,c.style.zoom=1),i.removeChild(c),c=d=f=g=null}),i.removeChild(n),c=d=f=g=h=i=n=null,b}();var H=/(?:\{[\s\S]*\}|\[[\s\S]*\])$/,I=/([A-Z])/g;p.extend({cache:{},deletedIds:[],uuid:0,expando:"jQuery"+(p.fn.jquery+Math.random()).replace(/\D/g,""),noData:{embed:!0,object:"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000",applet:!0},hasData:function(a){return a=a.nodeType?p.cache[a[p.expando]]:a[p.expando],!!a&&!K(a)},data:function(a,c,d,e){if(!p.acceptData(a))return;var f,g,h=p.expando,i=typeof c=="string",j=a.nodeType,k=j?p.cache:a,l=j?a[h]:a[h]&&h;if((!l||!k[l]||!e&&!k[l].data)&&i&&d===b)return;l||(j?a[h]=l=p.deletedIds.pop()||p.guid++:l=h),k[l]||(k[l]={},j||(k[l].toJSON=p.noop));if(typeof c=="object"||typeof c=="function")e?k[l]=p.extend(k[l],c):k[l].data=p.extend(k[l].data,c);return f=k[l],e||(f.data||(f.data={}),f=f.data),d!==b&&(f[p.camelCase(c)]=d),i?(g=f[c],g==null&&(g=f[p.camelCase(c)])):g=f,g},removeData:function(a,b,c){if(!p.acceptData(a))return;var d,e,f,g=a.nodeType,h=g?p.cache:a,i=g?a[p.expando]:p.expando;if(!h[i])return;if(b){d=c?h[i]:h[i].data;if(d){p.isArray(b)||(b in d?b=[b]:(b=p.camelCase(b),b in d?b=[b]:b=b.split(" ")));for(e=0,f=b.length;e<f;e++)delete d[b[e]];if(!(c?K:p.isEmptyObject)(d))return}}if(!c){delete h[i].data;if(!K(h[i]))return}g?p.cleanData([a],!0):p.support.deleteExpando||h!=h.window?delete h[i]:h[i]=null},_data:function(a,b,c){return p.data(a,b,c,!0)},acceptData:function(a){var b=a.nodeName&&p.noData[a.nodeName.toLowerCase()];return!b||b!==!0&&a.getAttribute("classid")===b}}),p.fn.extend({data:function(a,c){var d,e,f,g,h,i=this[0],j=0,k=null;if(a===b){if(this.length){k=p.data(i);if(i.nodeType===1&&!p._data(i,"parsedAttrs")){f=i.attributes;for(h=f.length;j<h;j++)g=f[j].name,g.indexOf("data-")||(g=p.camelCase(g.substring(5)),J(i,g,k[g]));p._data(i,"parsedAttrs",!0)}}return k}return typeof a=="object"?this.each(function(){p.data(this,a)}):(d=a.split(".",2),d[1]=d[1]?"."+d[1]:"",e=d[1]+"!",p.access(this,function(c){if(c===b)return k=this.triggerHandler("getData"+e,[d[0]]),k===b&&i&&(k=p.data(i,a),k=J(i,a,k)),k===b&&d[1]?this.data(d[0]):k;d[1]=c,this.each(function(){var b=p(this);b.triggerHandler("setData"+e,d),p.data(this,a,c),b.triggerHandler("changeData"+e,d)})},null,c,arguments.length>1,null,!1))},removeData:function(a){return this.each(function(){p.removeData(this,a)})}}),p.extend({queue:function(a,b,c){var d;if(a)return b=(b||"fx")+"queue",d=p._data(a,b),c&&(!d||p.isArray(c)?d=p._data(a,b,p.makeArray(c)):d.push(c)),d||[]},dequeue:function(a,b){b=b||"fx";var c=p.queue(a,b),d=c.length,e=c.shift(),f=p._queueHooks(a,b),g=function(){p.dequeue(a,b)};e==="inprogress"&&(e=c.shift(),d--),e&&(b==="fx"&&c.unshift("inprogress"),delete f.stop,e.call(a,g,f)),!d&&f&&f.empty.fire()},_queueHooks:function(a,b){var c=b+"queueHooks";return p._data(a,c)||p._data(a,c,{empty:p.Callbacks("once memory").add(function(){p.removeData(a,b+"queue",!0),p.removeData(a,c,!0)})})}}),p.fn.extend({queue:function(a,c){var d=2;return typeof a!="string"&&(c=a,a="fx",d--),arguments.length<d?p.queue(this[0],a):c===b?this:this.each(function(){var b=p.queue(this,a,c);p._queueHooks(this,a),a==="fx"&&b[0]!=="inprogress"&&p.dequeue(this,a)})},dequeue:function(a){return this.each(function(){p.dequeue(this,a)})},delay:function(a,b){return a=p.fx?p.fx.speeds[a]||a:a,b=b||"fx",this.queue(b,function(b,c){var d=setTimeout(b,a);c.stop=function(){clearTimeout(d)}})},clearQueue:function(a){return this.queue(a||"fx",[])},promise:function(a,c){var d,e=1,f=p.Deferred(),g=this,h=this.length,i=function(){--e||f.resolveWith(g,[g])};typeof a!="string"&&(c=a,a=b),a=a||"fx";while(h--)d=p._data(g[h],a+"queueHooks"),d&&d.empty&&(e++,d.empty.add(i));return i(),f.promise(c)}});var L,M,N,O=/[\t\r\n]/g,P=/\r/g,Q=/^(?:button|input)$/i,R=/^(?:button|input|object|select|textarea)$/i,S=/^a(?:rea|)$/i,T=/^(?:autofocus|autoplay|async|checked|controls|defer|disabled|hidden|loop|multiple|open|readonly|required|scoped|selected)$/i,U=p.support.getSetAttribute;p.fn.extend({attr:function(a,b){return p.access(this,p.attr,a,b,arguments.length>1)},removeAttr:function(a){return this.each(function(){p.removeAttr(this,a)})},prop:function(a,b){return p.access(this,p.prop,a,b,arguments.length>1)},removeProp:function(a){return a=p.propFix[a]||a,this.each(function(){try{this[a]=b,delete this[a]}catch(c){}})},addClass:function(a){var b,c,d,e,f,g,h;if(p.isFunction(a))return this.each(function(b){p(this).addClass(a.call(this,b,this.className))});if(a&&typeof a=="string"){b=a.split(s);for(c=0,d=this.length;c<d;c++){e=this[c];if(e.nodeType===1)if(!e.className&&b.length===1)e.className=a;else{f=" "+e.className+" ";for(g=0,h=b.length;g<h;g++)f.indexOf(" "+b[g]+" ")<0&&(f+=b[g]+" ");e.className=p.trim(f)}}}return this},removeClass:function(a){var c,d,e,f,g,h,i;if(p.isFunction(a))return this.each(function(b){p(this).removeClass(a.call(this,b,this.className))});if(a&&typeof a=="string"||a===b){c=(a||"").split(s);for(h=0,i=this.length;h<i;h++){e=this[h];if(e.nodeType===1&&e.className){d=(" "+e.className+" ").replace(O," ");for(f=0,g=c.length;f<g;f++)while(d.indexOf(" "+c[f]+" ")>=0)d=d.replace(" "+c[f]+" "," ");e.className=a?p.trim(d):""}}}return this},toggleClass:function(a,b){var c=typeof a,d=typeof b=="boolean";return p.isFunction(a)?this.each(function(c){p(this).toggleClass(a.call(this,c,this.className,b),b)}):this.each(function(){if(c==="string"){var e,f=0,g=p(this),h=b,i=a.split(s);while(e=i[f++])h=d?h:!g.hasClass(e),g[h?"addClass":"removeClass"](e)}else if(c==="undefined"||c==="boolean")this.className&&p._data(this,"__className__",this.className),this.className=this.className||a===!1?"":p._data(this,"__className__")||""})},hasClass:function(a){var b=" "+a+" ",c=0,d=this.length;for(;c<d;c++)if(this[c].nodeType===1&&(" "+this[c].className+" ").replace(O," ").indexOf(b)>=0)return!0;return!1},val:function(a){var c,d,e,f=this[0];if(!arguments.length){if(f)return c=p.valHooks[f.type]||p.valHooks[f.nodeName.toLowerCase()],c&&"get"in c&&(d=c.get(f,"value"))!==b?d:(d=f.value,typeof d=="string"?d.replace(P,""):d==null?"":d);return}return e=p.isFunction(a),this.each(function(d){var f,g=p(this);if(this.nodeType!==1)return;e?f=a.call(this,d,g.val()):f=a,f==null?f="":typeof f=="number"?f+="":p.isArray(f)&&(f=p.map(f,function(a){return a==null?"":a+""})),c=p.valHooks[this.type]||p.valHooks[this.nodeName.toLowerCase()];if(!c||!("set"in c)||c.set(this,f,"value")===b)this.value=f})}}),p.extend({valHooks:{option:{get:function(a){var b=a.attributes.value;return!b||b.specified?a.value:a.text}},select:{get:function(a){var b,c,d,e,f=a.selectedIndex,g=[],h=a.options,i=a.type==="select-one";if(f<0)return null;c=i?f:0,d=i?f+1:h.length;for(;c<d;c++){e=h[c];if(e.selected&&(p.support.optDisabled?!e.disabled:e.getAttribute("disabled")===null)&&(!e.parentNode.disabled||!p.nodeName(e.parentNode,"optgroup"))){b=p(e).val();if(i)return b;g.push(b)}}return i&&!g.length&&h.length?p(h[f]).val():g},set:function(a,b){var c=p.makeArray(b);return p(a).find("option").each(function(){this.selected=p.inArray(p(this).val(),c)>=0}),c.length||(a.selectedIndex=-1),c}}},attrFn:{},attr:function(a,c,d,e){var f,g,h,i=a.nodeType;if(!a||i===3||i===8||i===2)return;if(e&&p.isFunction(p.fn[c]))return p(a)[c](d);if(typeof a.getAttribute=="undefined")return p.prop(a,c,d);h=i!==1||!p.isXMLDoc(a),h&&(c=c.toLowerCase(),g=p.attrHooks[c]||(T.test(c)?M:L));if(d!==b){if(d===null){p.removeAttr(a,c);return}return g&&"set"in g&&h&&(f=g.set(a,d,c))!==b?f:(a.setAttribute(c,d+""),d)}return g&&"get"in g&&h&&(f=g.get(a,c))!==null?f:(f=a.getAttribute(c),f===null?b:f)},removeAttr:function(a,b){var c,d,e,f,g=0;if(b&&a.nodeType===1){d=b.split(s);for(;g<d.length;g++)e=d[g],e&&(c=p.propFix[e]||e,f=T.test(e),f||p.attr(a,e,""),a.removeAttribute(U?e:c),f&&c in a&&(a[c]=!1))}},attrHooks:{type:{set:function(a,b){if(Q.test(a.nodeName)&&a.parentNode)p.error("type property can't be changed");else if(!p.support.radioValue&&b==="radio"&&p.nodeName(a,"input")){var c=a.value;return a.setAttribute("type",b),c&&(a.value=c),b}}},value:{get:function(a,b){return L&&p.nodeName(a,"button")?L.get(a,b):b in a?a.value:null},set:function(a,b,c){if(L&&p.nodeName(a,"button"))return L.set(a,b,c);a.value=b}}},propFix:{tabindex:"tabIndex",readonly:"readOnly","for":"htmlFor","class":"className",maxlength:"maxLength",cellspacing:"cellSpacing",cellpadding:"cellPadding",rowspan:"rowSpan",colspan:"colSpan",usemap:"useMap",frameborder:"frameBorder",contenteditable:"contentEditable"},prop:function(a,c,d){var e,f,g,h=a.nodeType;if(!a||h===3||h===8||h===2)return;return g=h!==1||!p.isXMLDoc(a),g&&(c=p.propFix[c]||c,f=p.propHooks[c]),d!==b?f&&"set"in f&&(e=f.set(a,d,c))!==b?e:a[c]=d:f&&"get"in f&&(e=f.get(a,c))!==null?e:a[c]},propHooks:{tabIndex:{get:function(a){var c=a.getAttributeNode("tabindex");return c&&c.specified?parseInt(c.value,10):R.test(a.nodeName)||S.test(a.nodeName)&&a.href?0:b}}}}),M={get:function(a,c){var d,e=p.prop(a,c);return e===!0||typeof e!="boolean"&&(d=a.getAttributeNode(c))&&d.nodeValue!==!1?c.toLowerCase():b},set:function(a,b,c){var d;return b===!1?p.removeAttr(a,c):(d=p.propFix[c]||c,d in a&&(a[d]=!0),a.setAttribute(c,c.toLowerCase())),c}},U||(N={name:!0,id:!0,coords:!0},L=p.valHooks.button={get:function(a,c){var d;return d=a.getAttributeNode(c),d&&(N[c]?d.value!=="":d.specified)?d.value:b},set:function(a,b,c){var d=a.getAttributeNode(c);return d||(d=e.createAttribute(c),a.setAttributeNode(d)),d.value=b+""}},p.each(["width","height"],function(a,b){p.attrHooks[b]=p.extend(p.attrHooks[b],{set:function(a,c){if(c==="")return a.setAttribute(b,"auto"),c}})}),p.attrHooks.contenteditable={get:L.get,set:function(a,b,c){b===""&&(b="false"),L.set(a,b,c)}}),p.support.hrefNormalized||p.each(["href","src","width","height"],function(a,c){p.attrHooks[c]=p.extend(p.attrHooks[c],{get:function(a){var d=a.getAttribute(c,2);return d===null?b:d}})}),p.support.style||(p.attrHooks.style={get:function(a){return a.style.cssText.toLowerCase()||b},set:function(a,b){return a.style.cssText=b+""}}),p.support.optSelected||(p.propHooks.selected=p.extend(p.propHooks.selected,{get:function(a){var b=a.parentNode;return b&&(b.selectedIndex,b.parentNode&&b.parentNode.selectedIndex),null}})),p.support.enctype||(p.propFix.enctype="encoding"),p.support.checkOn||p.each(["radio","checkbox"],function(){p.valHooks[this]={get:function(a){return a.getAttribute("value")===null?"on":a.value}}}),p.each(["radio","checkbox"],function(){p.valHooks[this]=p.extend(p.valHooks[this],{set:function(a,b){if(p.isArray(b))return a.checked=p.inArray(p(a).val(),b)>=0}})});var V=/^(?:textarea|input|select)$/i,W=/^([^\.]*|)(?:\.(.+)|)$/,X=/(?:^|\s)hover(\.\S+|)\b/,Y=/^key/,Z=/^(?:mouse|contextmenu)|click/,$=/^(?:focusinfocus|focusoutblur)$/,_=function(a){return p.event.special.hover?a:a.replace(X,"mouseenter$1 mouseleave$1")};p.event={add:function(a,c,d,e,f){var g,h,i,j,k,l,m,n,o,q,r;if(a.nodeType===3||a.nodeType===8||!c||!d||!(g=p._data(a)))return;d.handler&&(o=d,d=o.handler,f=o.selector),d.guid||(d.guid=p.guid++),i=g.events,i||(g.events=i={}),h=g.handle,h||(g.handle=h=function(a){return typeof p!="undefined"&&(!a||p.event.triggered!==a.type)?p.event.dispatch.apply(h.elem,arguments):b},h.elem=a),c=p.trim(_(c)).split(" ");for(j=0;j<c.length;j++){k=W.exec(c[j])||[],l=k[1],m=(k[2]||"").split(".").sort(),r=p.event.special[l]||{},l=(f?r.delegateType:r.bindType)||l,r=p.event.special[l]||{},n=p.extend({type:l,origType:k[1],data:e,handler:d,guid:d.guid,selector:f,needsContext:f&&p.expr.match.needsContext.test(f),namespace:m.join(".")},o),q=i[l];if(!q){q=i[l]=[],q.delegateCount=0;if(!r.setup||r.setup.call(a,e,m,h)===!1)a.addEventListener?a.addEventListener(l,h,!1):a.attachEvent&&a.attachEvent("on"+l,h)}r.add&&(r.add.call(a,n),n.handler.guid||(n.handler.guid=d.guid)),f?q.splice(q.delegateCount++,0,n):q.push(n),p.event.global[l]=!0}a=null},global:{},remove:function(a,b,c,d,e){var f,g,h,i,j,k,l,m,n,o,q,r=p.hasData(a)&&p._data(a);if(!r||!(m=r.events))return;b=p.trim(_(b||"")).split(" ");for(f=0;f<b.length;f++){g=W.exec(b[f])||[],h=i=g[1],j=g[2];if(!h){for(h in m)p.event.remove(a,h+b[f],c,d,!0);continue}n=p.event.special[h]||{},h=(d?n.delegateType:n.bindType)||h,o=m[h]||[],k=o.length,j=j?new RegExp("(^|\\.)"+j.split(".").sort().join("\\.(?:.*\\.|)")+"(\\.|$)"):null;for(l=0;l<o.length;l++)q=o[l],(e||i===q.origType)&&(!c||c.guid===q.guid)&&(!j||j.test(q.namespace))&&(!d||d===q.selector||d==="**"&&q.selector)&&(o.splice(l--,1),q.selector&&o.delegateCount--,n.remove&&n.remove.call(a,q));o.length===0&&k!==o.length&&((!n.teardown||n.teardown.call(a,j,r.handle)===!1)&&p.removeEvent(a,h,r.handle),delete m[h])}p.isEmptyObject(m)&&(delete r.handle,p.removeData(a,"events",!0))},customEvent:{getData:!0,setData:!0,changeData:!0},trigger:function(c,d,f,g){if(!f||f.nodeType!==3&&f.nodeType!==8){var h,i,j,k,l,m,n,o,q,r,s=c.type||c,t=[];if($.test(s+p.event.triggered))return;s.indexOf("!")>=0&&(s=s.slice(0,-1),i=!0),s.indexOf(".")>=0&&(t=s.split("."),s=t.shift(),t.sort());if((!f||p.event.customEvent[s])&&!p.event.global[s])return;c=typeof c=="object"?c[p.expando]?c:new p.Event(s,c):new p.Event(s),c.type=s,c.isTrigger=!0,c.exclusive=i,c.namespace=t.join("."),c.namespace_re=c.namespace?new RegExp("(^|\\.)"+t.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,m=s.indexOf(":")<0?"on"+s:"";if(!f){h=p.cache;for(j in h)h[j].events&&h[j].events[s]&&p.event.trigger(c,d,h[j].handle.elem,!0);return}c.result=b,c.target||(c.target=f),d=d!=null?p.makeArray(d):[],d.unshift(c),n=p.event.special[s]||{};if(n.trigger&&n.trigger.apply(f,d)===!1)return;q=[[f,n.bindType||s]];if(!g&&!n.noBubble&&!p.isWindow(f)){r=n.delegateType||s,k=$.test(r+s)?f:f.parentNode;for(l=f;k;k=k.parentNode)q.push([k,r]),l=k;l===(f.ownerDocument||e)&&q.push([l.defaultView||l.parentWindow||a,r])}for(j=0;j<q.length&&!c.isPropagationStopped();j++)k=q[j][0],c.type=q[j][1],o=(p._data(k,"events")||{})[c.type]&&p._data(k,"handle"),o&&o.apply(k,d),o=m&&k[m],o&&p.acceptData(k)&&o.apply&&o.apply(k,d)===!1&&c.preventDefault();return c.type=s,!g&&!c.isDefaultPrevented()&&(!n._default||n._default.apply(f.ownerDocument,d)===!1)&&(s!=="click"||!p.nodeName(f,"a"))&&p.acceptData(f)&&m&&f[s]&&(s!=="focus"&&s!=="blur"||c.target.offsetWidth!==0)&&!p.isWindow(f)&&(l=f[m],l&&(f[m]=null),p.event.triggered=s,f[s](),p.event.triggered=b,l&&(f[m]=l)),c.result}return},dispatch:function(c){c=p.event.fix(c||a.event);var d,e,f,g,h,i,j,l,m,n,o=(p._data(this,"events")||{})[c.type]||[],q=o.delegateCount,r=k.call(arguments),s=!c.exclusive&&!c.namespace,t=p.event.special[c.type]||{},u=[];r[0]=c,c.delegateTarget=this;if(t.preDispatch&&t.preDispatch.call(this,c)===!1)return;if(q&&(!c.button||c.type!=="click"))for(f=c.target;f!=this;f=f.parentNode||this)if(f.disabled!==!0||c.type!=="click"){h={},j=[];for(d=0;d<q;d++)l=o[d],m=l.selector,h[m]===b&&(h[m]=l.needsContext?p(m,this).index(f)>=0:p.find(m,this,null,[f]).length),h[m]&&j.push(l);j.length&&u.push({elem:f,matches:j})}o.length>q&&u.push({elem:this,matches:o.slice(q)});for(d=0;d<u.length&&!c.isPropagationStopped();d++){i=u[d],c.currentTarget=i.elem;for(e=0;e<i.matches.length&&!c.isImmediatePropagationStopped();e++){l=i.matches[e];if(s||!c.namespace&&!l.namespace||c.namespace_re&&c.namespace_re.test(l.namespace))c.data=l.data,c.handleObj=l,g=((p.event.special[l.origType]||{}).handle||l.handler).apply(i.elem,r),g!==b&&(c.result=g,g===!1&&(c.preventDefault(),c.stopPropagation()))}}return t.postDispatch&&t.postDispatch.call(this,c),c.result},props:"attrChange attrName relatedNode srcElement altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "),fixHooks:{},keyHooks:{props:"char charCode key keyCode".split(" "),filter:function(a,b){return a.which==null&&(a.which=b.charCode!=null?b.charCode:b.keyCode),a}},mouseHooks:{props:"button buttons clientX clientY fromElement offsetX offsetY pageX pageY screenX screenY toElement".split(" "),filter:function(a,c){var d,f,g,h=c.button,i=c.fromElement;return a.pageX==null&&c.clientX!=null&&(d=a.target.ownerDocument||e,f=d.documentElement,g=d.body,a.pageX=c.clientX+(f&&f.scrollLeft||g&&g.scrollLeft||0)-(f&&f.clientLeft||g&&g.clientLeft||0),a.pageY=c.clientY+(f&&f.scrollTop||g&&g.scrollTop||0)-(f&&f.clientTop||g&&g.clientTop||0)),!a.relatedTarget&&i&&(a.relatedTarget=i===a.target?c.toElement:i),!a.which&&h!==b&&(a.which=h&1?1:h&2?3:h&4?2:0),a}},fix:function(a){if(a[p.expando])return a;var b,c,d=a,f=p.event.fixHooks[a.type]||{},g=f.props?this.props.concat(f.props):this.props;a=p.Event(d);for(b=g.length;b;)c=g[--b],a[c]=d[c];return a.target||(a.target=d.srcElement||e),a.target.nodeType===3&&(a.target=a.target.parentNode),a.metaKey=!!a.metaKey,f.filter?f.filter(a,d):a},special:{load:{noBubble:!0},focus:{delegateType:"focusin"},blur:{delegateType:"focusout"},beforeunload:{setup:function(a,b,c){p.isWindow(this)&&(this.onbeforeunload=c)},teardown:function(a,b){this.onbeforeunload===b&&(this.onbeforeunload=null)}}},simulate:function(a,b,c,d){var e=p.extend(new p.Event,c,{type:a,isSimulated:!0,originalEvent:{}});d?p.event.trigger(e,null,b):p.event.dispatch.call(b,e),e.isDefaultPrevented()&&c.preventDefault()}},p.event.handle=p.event.dispatch,p.removeEvent=e.removeEventListener?function(a,b,c){a.removeEventListener&&a.removeEventListener(b,c,!1)}:function(a,b,c){var d="on"+b;a.detachEvent&&(typeof a[d]=="undefined"&&(a[d]=null),a.detachEvent(d,c))},p.Event=function(a,b){if(this instanceof p.Event)a&&a.type?(this.originalEvent=a,this.type=a.type,this.isDefaultPrevented=a.defaultPrevented||a.returnValue===!1||a.getPreventDefault&&a.getPreventDefault()?bb:ba):this.type=a,b&&p.extend(this,b),this.timeStamp=a&&a.timeStamp||p.now(),this[p.expando]=!0;else return new p.Event(a,b)},p.Event.prototype={preventDefault:function(){this.isDefaultPrevented=bb;var a=this.originalEvent;if(!a)return;a.preventDefault?a.preventDefault():a.returnValue=!1},stopPropagation:function(){this.isPropagationStopped=bb;var a=this.originalEvent;if(!a)return;a.stopPropagation&&a.stopPropagation(),a.cancelBubble=!0},stopImmediatePropagation:function(){this.isImmediatePropagationStopped=bb,this.stopPropagation()},isDefaultPrevented:ba,isPropagationStopped:ba,isImmediatePropagationStopped:ba},p.each({mouseenter:"mouseover",mouseleave:"mouseout"},function(a,b){p.event.special[a]={delegateType:b,bindType:b,handle:function(a){var c,d=this,e=a.relatedTarget,f=a.handleObj,g=f.selector;if(!e||e!==d&&!p.contains(d,e))a.type=f.origType,c=f.handler.apply(this,arguments),a.type=b;return c}}}),p.support.submitBubbles||(p.event.special.submit={setup:function(){if(p.nodeName(this,"form"))return!1;p.event.add(this,"click._submit keypress._submit",function(a){var c=a.target,d=p.nodeName(c,"input")||p.nodeName(c,"button")?c.form:b;d&&!p._data(d,"_submit_attached")&&(p.event.add(d,"submit._submit",function(a){a._submit_bubble=!0}),p._data(d,"_submit_attached",!0))})},postDispatch:function(a){a._submit_bubble&&(delete a._submit_bubble,this.parentNode&&!a.isTrigger&&p.event.simulate("submit",this.parentNode,a,!0))},teardown:function(){if(p.nodeName(this,"form"))return!1;p.event.remove(this,"._submit")}}),p.support.changeBubbles||(p.event.special.change={setup:function(){if(V.test(this.nodeName)){if(this.type==="checkbox"||this.type==="radio")p.event.add(this,"propertychange._change",function(a){a.originalEvent.propertyName==="checked"&&(this._just_changed=!0)}),p.event.add(this,"click._change",function(a){this._just_changed&&!a.isTrigger&&(this._just_changed=!1),p.event.simulate("change",this,a,!0)});return!1}p.event.add(this,"beforeactivate._change",function(a){var b=a.target;V.test(b.nodeName)&&!p._data(b,"_change_attached")&&(p.event.add(b,"change._change",function(a){this.parentNode&&!a.isSimulated&&!a.isTrigger&&p.event.simulate("change",this.parentNode,a,!0)}),p._data(b,"_change_attached",!0))})},handle:function(a){var b=a.target;if(this!==b||a.isSimulated||a.isTrigger||b.type!=="radio"&&b.type!=="checkbox")return a.handleObj.handler.apply(this,arguments)},teardown:function(){return p.event.remove(this,"._change"),!V.test(this.nodeName)}}),p.support.focusinBubbles||p.each({focus:"focusin",blur:"focusout"},function(a,b){var c=0,d=function(a){p.event.simulate(b,a.target,p.event.fix(a),!0)};p.event.special[b]={setup:function(){c++===0&&e.addEventListener(a,d,!0)},teardown:function(){--c===0&&e.removeEventListener(a,d,!0)}}}),p.fn.extend({on:function(a,c,d,e,f){var g,h;if(typeof a=="object"){typeof c!="string"&&(d=d||c,c=b);for(h in a)this.on(h,c,d,a[h],f);return this}d==null&&e==null?(e=c,d=c=b):e==null&&(typeof c=="string"?(e=d,d=b):(e=d,d=c,c=b));if(e===!1)e=ba;else if(!e)return this;return f===1&&(g=e,e=function(a){return p().off(a),g.apply(this,arguments)},e.guid=g.guid||(g.guid=p.guid++)),this.each(function(){p.event.add(this,a,e,d,c)})},one:function(a,b,c,d){return this.on(a,b,c,d,1)},off:function(a,c,d){var e,f;if(a&&a.preventDefault&&a.handleObj)return e=a.handleObj,p(a.delegateTarget).off(e.namespace?e.origType+"."+e.namespace:e.origType,e.selector,e.handler),this;if(typeof a=="object"){for(f in a)this.off(f,c,a[f]);return this}if(c===!1||typeof c=="function")d=c,c=b;return d===!1&&(d=ba),this.each(function(){p.event.remove(this,a,d,c)})},bind:function(a,b,c){return this.on(a,null,b,c)},unbind:function(a,b){return this.off(a,null,b)},live:function(a,b,c){return p(this.context).on(a,this.selector,b,c),this},die:function(a,b){return p(this.context).off(a,this.selector||"**",b),this},delegate:function(a,b,c,d){return this.on(b,a,c,d)},undelegate:function(a,b,c){return arguments.length===1?this.off(a,"**"):this.off(b,a||"**",c)},trigger:function(a,b){return this.each(function(){p.event.trigger(a,b,this)})},triggerHandler:function(a,b){if(this[0])return p.event.trigger(a,b,this[0],!0)},toggle:function(a){var b=arguments,c=a.guid||p.guid++,d=0,e=function(c){var e=(p._data(this,"lastToggle"+a.guid)||0)%d;return p._data(this,"lastToggle"+a.guid,e+1),c.preventDefault(),b[e].apply(this,arguments)||!1};e.guid=c;while(d<b.length)b[d++].guid=c;return this.click(e)},hover:function(a,b){return this.mouseenter(a).mouseleave(b||a)}}),p.each("blur focus focusin focusout load resize scroll unload click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup error contextmenu".split(" "),function(a,b){p.fn[b]=function(a,c){return c==null&&(c=a,a=null),arguments.length>0?this.on(b,null,a,c):this.trigger(b)},Y.test(b)&&(p.event.fixHooks[b]=p.event.keyHooks),Z.test(b)&&(p.event.fixHooks[b]=p.event.mouseHooks)}),function(a,b){function bc(a,b,c,d){c=c||[],b=b||r;var e,f,i,j,k=b.nodeType;if(!a||typeof a!="string")return c;if(k!==1&&k!==9)return[];i=g(b);if(!i&&!d)if(e=P.exec(a))if(j=e[1]){if(k===9){f=b.getElementById(j);if(!f||!f.parentNode)return c;if(f.id===j)return c.push(f),c}else if(b.ownerDocument&&(f=b.ownerDocument.getElementById(j))&&h(b,f)&&f.id===j)return c.push(f),c}else{if(e[2])return w.apply(c,x.call(b.getElementsByTagName(a),0)),c;if((j=e[3])&&_&&b.getElementsByClassName)return w.apply(c,x.call(b.getElementsByClassName(j),0)),c}return bp(a.replace(L,"$1"),b,c,d,i)}function bd(a){return function(b){var c=b.nodeName.toLowerCase();return c==="input"&&b.type===a}}function be(a){return function(b){var c=b.nodeName.toLowerCase();return(c==="input"||c==="button")&&b.type===a}}function bf(a){return z(function(b){return b=+b,z(function(c,d){var e,f=a([],c.length,b),g=f.length;while(g--)c[e=f[g]]&&(c[e]=!(d[e]=c[e]))})})}function bg(a,b,c){if(a===b)return c;var d=a.nextSibling;while(d){if(d===b)return-1;d=d.nextSibling}return 1}function bh(a,b){var c,d,f,g,h,i,j,k=C[o][a];if(k)return b?0:k.slice(0);h=a,i=[],j=e.preFilter;while(h){if(!c||(d=M.exec(h)))d&&(h=h.slice(d[0].length)),i.push(f=[]);c=!1;if(d=N.exec(h))f.push(c=new q(d.shift())),h=h.slice(c.length),c.type=d[0].replace(L," ");for(g in e.filter)(d=W[g].exec(h))&&(!j[g]||(d=j[g](d,r,!0)))&&(f.push(c=new q(d.shift())),h=h.slice(c.length),c.type=g,c.matches=d);if(!c)break}return b?h.length:h?bc.error(a):C(a,i).slice(0)}function bi(a,b,d){var e=b.dir,f=d&&b.dir==="parentNode",g=u++;return b.first?function(b,c,d){while(b=b[e])if(f||b.nodeType===1)return a(b,c,d)}:function(b,d,h){if(!h){var i,j=t+" "+g+" ",k=j+c;while(b=b[e])if(f||b.nodeType===1){if((i=b[o])===k)return b.sizset;if(typeof i=="string"&&i.indexOf(j)===0){if(b.sizset)return b}else{b[o]=k;if(a(b,d,h))return b.sizset=!0,b;b.sizset=!1}}}else while(b=b[e])if(f||b.nodeType===1)if(a(b,d,h))return b}}function bj(a){return a.length>1?function(b,c,d){var e=a.length;while(e--)if(!a[e](b,c,d))return!1;return!0}:a[0]}function bk(a,b,c,d,e){var f,g=[],h=0,i=a.length,j=b!=null;for(;h<i;h++)if(f=a[h])if(!c||c(f,d,e))g.push(f),j&&b.push(h);return g}function bl(a,b,c,d,e,f){return d&&!d[o]&&(d=bl(d)),e&&!e[o]&&(e=bl(e,f)),z(function(f,g,h,i){if(f&&e)return;var j,k,l,m=[],n=[],o=g.length,p=f||bo(b||"*",h.nodeType?[h]:h,[],f),q=a&&(f||!b)?bk(p,m,a,h,i):p,r=c?e||(f?a:o||d)?[]:g:q;c&&c(q,r,h,i);if(d){l=bk(r,n),d(l,[],h,i),j=l.length;while(j--)if(k=l[j])r[n[j]]=!(q[n[j]]=k)}if(f){j=a&&r.length;while(j--)if(k=r[j])f[m[j]]=!(g[m[j]]=k)}else r=bk(r===g?r.splice(o,r.length):r),e?e(null,g,r,i):w.apply(g,r)})}function bm(a){var b,c,d,f=a.length,g=e.relative[a[0].type],h=g||e.relative[" "],i=g?1:0,j=bi(function(a){return a===b},h,!0),k=bi(function(a){return y.call(b,a)>-1},h,!0),m=[function(a,c,d){return!g&&(d||c!==l)||((b=c).nodeType?j(a,c,d):k(a,c,d))}];for(;i<f;i++)if(c=e.relative[a[i].type])m=[bi(bj(m),c)];else{c=e.filter[a[i].type].apply(null,a[i].matches);if(c[o]){d=++i;for(;d<f;d++)if(e.relative[a[d].type])break;return bl(i>1&&bj(m),i>1&&a.slice(0,i-1).join("").replace(L,"$1"),c,i<d&&bm(a.slice(i,d)),d<f&&bm(a=a.slice(d)),d<f&&a.join(""))}m.push(c)}return bj(m)}function bn(a,b){var d=b.length>0,f=a.length>0,g=function(h,i,j,k,m){var n,o,p,q=[],s=0,u="0",x=h&&[],y=m!=null,z=l,A=h||f&&e.find.TAG("*",m&&i.parentNode||i),B=t+=z==null?1:Math.E;y&&(l=i!==r&&i,c=g.el);for(;(n=A[u])!=null;u++){if(f&&n){for(o=0;p=a[o];o++)if(p(n,i,j)){k.push(n);break}y&&(t=B,c=++g.el)}d&&((n=!p&&n)&&s--,h&&x.push(n))}s+=u;if(d&&u!==s){for(o=0;p=b[o];o++)p(x,q,i,j);if(h){if(s>0)while(u--)!x[u]&&!q[u]&&(q[u]=v.call(k));q=bk(q)}w.apply(k,q),y&&!h&&q.length>0&&s+b.length>1&&bc.uniqueSort(k)}return y&&(t=B,l=z),x};return g.el=0,d?z(g):g}function bo(a,b,c,d){var e=0,f=b.length;for(;e<f;e++)bc(a,b[e],c,d);return c}function bp(a,b,c,d,f){var g,h,j,k,l,m=bh(a),n=m.length;if(!d&&m.length===1){h=m[0]=m[0].slice(0);if(h.length>2&&(j=h[0]).type==="ID"&&b.nodeType===9&&!f&&e.relative[h[1].type]){b=e.find.ID(j.matches[0].replace(V,""),b,f)[0];if(!b)return c;a=a.slice(h.shift().length)}for(g=W.POS.test(a)?-1:h.length-1;g>=0;g--){j=h[g];if(e.relative[k=j.type])break;if(l=e.find[k])if(d=l(j.matches[0].replace(V,""),R.test(h[0].type)&&b.parentNode||b,f)){h.splice(g,1),a=d.length&&h.join("");if(!a)return w.apply(c,x.call(d,0)),c;break}}}return i(a,m)(d,b,f,c,R.test(a)),c}function bq(){}var c,d,e,f,g,h,i,j,k,l,m=!0,n="undefined",o=("sizcache"+Math.random()).replace(".",""),q=String,r=a.document,s=r.documentElement,t=0,u=0,v=[].pop,w=[].push,x=[].slice,y=[].indexOf||function(a){var b=0,c=this.length;for(;b<c;b++)if(this[b]===a)return b;return-1},z=function(a,b){return a[o]=b==null||b,a},A=function(){var a={},b=[];return z(function(c,d){return b.push(c)>e.cacheLength&&delete a[b.shift()],a[c]=d},a)},B=A(),C=A(),D=A(),E="[\\x20\\t\\r\\n\\f]",F="(?:\\\\.|[-\\w]|[^\\x00-\\xa0])+",G=F.replace("w","w#"),H="([*^$|!~]?=)",I="\\["+E+"*("+F+")"+E+"*(?:"+H+E+"*(?:(['\"])((?:\\\\.|[^\\\\])*?)\\3|("+G+")|)|)"+E+"*\\]",J=":("+F+")(?:\\((?:(['\"])((?:\\\\.|[^\\\\])*?)\\2|([^()[\\]]*|(?:(?:"+I+")|[^:]|\\\\.)*|.*))\\)|)",K=":(even|odd|eq|gt|lt|nth|first|last)(?:\\("+E+"*((?:-\\d)?\\d*)"+E+"*\\)|)(?=[^-]|$)",L=new RegExp("^"+E+"+|((?:^|[^\\\\])(?:\\\\.)*)"+E+"+$","g"),M=new RegExp("^"+E+"*,"+E+"*"),N=new RegExp("^"+E+"*([\\x20\\t\\r\\n\\f>+~])"+E+"*"),O=new RegExp(J),P=/^(?:#([\w\-]+)|(\w+)|\.([\w\-]+))$/,Q=/^:not/,R=/[\x20\t\r\n\f]*[+~]/,S=/:not\($/,T=/h\d/i,U=/input|select|textarea|button/i,V=/\\(?!\\)/g,W={ID:new RegExp("^#("+F+")"),CLASS:new RegExp("^\\.("+F+")"),NAME:new RegExp("^\\[name=['\"]?("+F+")['\"]?\\]"),TAG:new RegExp("^("+F.replace("w","w*")+")"),ATTR:new RegExp("^"+I),PSEUDO:new RegExp("^"+J),POS:new RegExp(K,"i"),CHILD:new RegExp("^:(only|nth|first|last)-child(?:\\("+E+"*(even|odd|(([+-]|)(\\d*)n|)"+E+"*(?:([+-]|)"+E+"*(\\d+)|))"+E+"*\\)|)","i"),needsContext:new RegExp("^"+E+"*[>+~]|"+K,"i")},X=function(a){var b=r.createElement("div");try{return a(b)}catch(c){return!1}finally{b=null}},Y=X(function(a){return a.appendChild(r.createComment("")),!a.getElementsByTagName("*").length}),Z=X(function(a){return a.innerHTML="<a href='#'></a>",a.firstChild&&typeof a.firstChild.getAttribute!==n&&a.firstChild.getAttribute("href")==="#"}),$=X(function(a){a.innerHTML="<select></select>";var b=typeof a.lastChild.getAttribute("multiple");return b!=="boolean"&&b!=="string"}),_=X(function(a){return a.innerHTML="<div class='hidden e'></div><div class='hidden'></div>",!a.getElementsByClassName||!a.getElementsByClassName("e").length?!1:(a.lastChild.className="e",a.getElementsByClassName("e").length===2)}),ba=X(function(a){a.id=o+0,a.innerHTML="<a name='"+o+"'></a><div name='"+o+"'></div>",s.insertBefore(a,s.firstChild);var b=r.getElementsByName&&r.getElementsByName(o).length===2+r.getElementsByName(o+0).length;return d=!r.getElementById(o),s.removeChild(a),b});try{x.call(s.childNodes,0)[0].nodeType}catch(bb){x=function(a){var b,c=[];for(;b=this[a];a++)c.push(b);return c}}bc.matches=function(a,b){return bc(a,null,null,b)},bc.matchesSelector=function(a,b){return bc(b,null,null,[a]).length>0},f=bc.getText=function(a){var b,c="",d=0,e=a.nodeType;if(e){if(e===1||e===9||e===11){if(typeof a.textContent=="string")return a.textContent;for(a=a.firstChild;a;a=a.nextSibling)c+=f(a)}else if(e===3||e===4)return a.nodeValue}else for(;b=a[d];d++)c+=f(b);return c},g=bc.isXML=function(a){var b=a&&(a.ownerDocument||a).documentElement;return b?b.nodeName!=="HTML":!1},h=bc.contains=s.contains?function(a,b){var c=a.nodeType===9?a.documentElement:a,d=b&&b.parentNode;return a===d||!!(d&&d.nodeType===1&&c.contains&&c.contains(d))}:s.compareDocumentPosition?function(a,b){return b&&!!(a.compareDocumentPosition(b)&16)}:function(a,b){while(b=b.parentNode)if(b===a)return!0;return!1},bc.attr=function(a,b){var c,d=g(a);return d||(b=b.toLowerCase()),(c=e.attrHandle[b])?c(a):d||$?a.getAttribute(b):(c=a.getAttributeNode(b),c?typeof a[b]=="boolean"?a[b]?b:null:c.specified?c.value:null:null)},e=bc.selectors={cacheLength:50,createPseudo:z,match:W,attrHandle:Z?{}:{href:function(a){return a.getAttribute("href",2)},type:function(a){return a.getAttribute("type")}},find:{ID:d?function(a,b,c){if(typeof b.getElementById!==n&&!c){var d=b.getElementById(a);return d&&d.parentNode?[d]:[]}}:function(a,c,d){if(typeof c.getElementById!==n&&!d){var e=c.getElementById(a);return e?e.id===a||typeof e.getAttributeNode!==n&&e.getAttributeNode("id").value===a?[e]:b:[]}},TAG:Y?function(a,b){if(typeof b.getElementsByTagName!==n)return b.getElementsByTagName(a)}:function(a,b){var c=b.getElementsByTagName(a);if(a==="*"){var d,e=[],f=0;for(;d=c[f];f++)d.nodeType===1&&e.push(d);return e}return c},NAME:ba&&function(a,b){if(typeof b.getElementsByName!==n)return b.getElementsByName(name)},CLASS:_&&function(a,b,c){if(typeof b.getElementsByClassName!==n&&!c)return b.getElementsByClassName(a)}},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(a){return a[1]=a[1].replace(V,""),a[3]=(a[4]||a[5]||"").replace(V,""),a[2]==="~="&&(a[3]=" "+a[3]+" "),a.slice(0,4)},CHILD:function(a){return a[1]=a[1].toLowerCase(),a[1]==="nth"?(a[2]||bc.error(a[0]),a[3]=+(a[3]?a[4]+(a[5]||1):2*(a[2]==="even"||a[2]==="odd")),a[4]=+(a[6]+a[7]||a[2]==="odd")):a[2]&&bc.error(a[0]),a},PSEUDO:function(a){var b,c;if(W.CHILD.test(a[0]))return null;if(a[3])a[2]=a[3];else if(b=a[4])O.test(b)&&(c=bh(b,!0))&&(c=b.indexOf(")",b.length-c)-b.length)&&(b=b.slice(0,c),a[0]=a[0].slice(0,c)),a[2]=b;return a.slice(0,3)}},filter:{ID:d?function(a){return a=a.replace(V,""),function(b){return b.getAttribute("id")===a}}:function(a){return a=a.replace(V,""),function(b){var c=typeof b.getAttributeNode!==n&&b.getAttributeNode("id");return c&&c.value===a}},TAG:function(a){return a==="*"?function(){return!0}:(a=a.replace(V,"").toLowerCase(),function(b){return b.nodeName&&b.nodeName.toLowerCase()===a})},CLASS:function(a){var b=B[o][a];return b||(b=B(a,new RegExp("(^|"+E+")"+a+"("+E+"|$)"))),function(a){return b.test(a.className||typeof a.getAttribute!==n&&a.getAttribute("class")||"")}},ATTR:function(a,b,c){return function(d,e){var f=bc.attr(d,a);return f==null?b==="!=":b?(f+="",b==="="?f===c:b==="!="?f!==c:b==="^="?c&&f.indexOf(c)===0:b==="*="?c&&f.indexOf(c)>-1:b==="$="?c&&f.substr(f.length-c.length)===c:b==="~="?(" "+f+" ").indexOf(c)>-1:b==="|="?f===c||f.substr(0,c.length+1)===c+"-":!1):!0}},CHILD:function(a,b,c,d){return a==="nth"?function(a){var b,e,f=a.parentNode;if(c===1&&d===0)return!0;if(f){e=0;for(b=f.firstChild;b;b=b.nextSibling)if(b.nodeType===1){e++;if(a===b)break}}return e-=d,e===c||e%c===0&&e/c>=0}:function(b){var c=b;switch(a){case"only":case"first":while(c=c.previousSibling)if(c.nodeType===1)return!1;if(a==="first")return!0;c=b;case"last":while(c=c.nextSibling)if(c.nodeType===1)return!1;return!0}}},PSEUDO:function(a,b){var c,d=e.pseudos[a]||e.setFilters[a.toLowerCase()]||bc.error("unsupported pseudo: "+a);return d[o]?d(b):d.length>1?(c=[a,a,"",b],e.setFilters.hasOwnProperty(a.toLowerCase())?z(function(a,c){var e,f=d(a,b),g=f.length;while(g--)e=y.call(a,f[g]),a[e]=!(c[e]=f[g])}):function(a){return d(a,0,c)}):d}},pseudos:{not:z(function(a){var b=[],c=[],d=i(a.replace(L,"$1"));return d[o]?z(function(a,b,c,e){var f,g=d(a,null,e,[]),h=a.length;while(h--)if(f=g[h])a[h]=!(b[h]=f)}):function(a,e,f){return b[0]=a,d(b,null,f,c),!c.pop()}}),has:z(function(a){return function(b){return bc(a,b).length>0}}),contains:z(function(a){return function(b){return(b.textContent||b.innerText||f(b)).indexOf(a)>-1}}),enabled:function(a){return a.disabled===!1},disabled:function(a){return a.disabled===!0},checked:function(a){var b=a.nodeName.toLowerCase();return b==="input"&&!!a.checked||b==="option"&&!!a.selected},selected:function(a){return a.parentNode&&a.parentNode.selectedIndex,a.selected===!0},parent:function(a){return!e.pseudos.empty(a)},empty:function(a){var b;a=a.firstChild;while(a){if(a.nodeName>"@"||(b=a.nodeType)===3||b===4)return!1;a=a.nextSibling}return!0},header:function(a){return T.test(a.nodeName)},text:function(a){var b,c;return a.nodeName.toLowerCase()==="input"&&(b=a.type)==="text"&&((c=a.getAttribute("type"))==null||c.toLowerCase()===b)},radio:bd("radio"),checkbox:bd("checkbox"),file:bd("file"),password:bd("password"),image:bd("image"),submit:be("submit"),reset:be("reset"),button:function(a){var b=a.nodeName.toLowerCase();return b==="input"&&a.type==="button"||b==="button"},input:function(a){return U.test(a.nodeName)},focus:function(a){var b=a.ownerDocument;return a===b.activeElement&&(!b.hasFocus||b.hasFocus())&&(!!a.type||!!a.href)},active:function(a){return a===a.ownerDocument.activeElement},first:bf(function(a,b,c){return[0]}),last:bf(function(a,b,c){return[b-1]}),eq:bf(function(a,b,c){return[c<0?c+b:c]}),even:bf(function(a,b,c){for(var d=0;d<b;d+=2)a.push(d);return a}),odd:bf(function(a,b,c){for(var d=1;d<b;d+=2)a.push(d);return a}),lt:bf(function(a,b,c){for(var d=c<0?c+b:c;--d>=0;)a.push(d);return a}),gt:bf(function(a,b,c){for(var d=c<0?c+b:c;++d<b;)a.push(d);return a})}},j=s.compareDocumentPosition?function(a,b){return a===b?(k=!0,0):(!a.compareDocumentPosition||!b.compareDocumentPosition?a.compareDocumentPosition:a.compareDocumentPosition(b)&4)?-1:1}:function(a,b){if(a===b)return k=!0,0;if(a.sourceIndex&&b.sourceIndex)return a.sourceIndex-b.sourceIndex;var c,d,e=[],f=[],g=a.parentNode,h=b.parentNode,i=g;if(g===h)return bg(a,b);if(!g)return-1;if(!h)return 1;while(i)e.unshift(i),i=i.parentNode;i=h;while(i)f.unshift(i),i=i.parentNode;c=e.length,d=f.length;for(var j=0;j<c&&j<d;j++)if(e[j]!==f[j])return bg(e[j],f[j]);return j===c?bg(a,f[j],-1):bg(e[j],b,1)},[0,0].sort(j),m=!k,bc.uniqueSort=function(a){var b,c=1;k=m,a.sort(j);if(k)for(;b=a[c];c++)b===a[c-1]&&a.splice(c--,1);return a},bc.error=function(a){throw new Error("Syntax error, unrecognized expression: "+a)},i=bc.compile=function(a,b){var c,d=[],e=[],f=D[o][a];if(!f){b||(b=bh(a)),c=b.length;while(c--)f=bm(b[c]),f[o]?d.push(f):e.push(f);f=D(a,bn(e,d))}return f},r.querySelectorAll&&function(){var a,b=bp,c=/'|\\/g,d=/\=[\x20\t\r\n\f]*([^'"\]]*)[\x20\t\r\n\f]*\]/g,e=[":focus"],f=[":active",":focus"],h=s.matchesSelector||s.mozMatchesSelector||s.webkitMatchesSelector||s.oMatchesSelector||s.msMatchesSelector;X(function(a){a.innerHTML="<select><option selected=''></option></select>",a.querySelectorAll("[selected]").length||e.push("\\["+E+"*(?:checked|disabled|ismap|multiple|readonly|selected|value)"),a.querySelectorAll(":checked").length||e.push(":checked")}),X(function(a){a.innerHTML="<p test=''></p>",a.querySelectorAll("[test^='']").length&&e.push("[*^$]="+E+"*(?:\"\"|'')"),a.innerHTML="<input type='hidden'/>",a.querySelectorAll(":enabled").length||e.push(":enabled",":disabled")}),e=new RegExp(e.join("|")),bp=function(a,d,f,g,h){if(!g&&!h&&(!e||!e.test(a))){var i,j,k=!0,l=o,m=d,n=d.nodeType===9&&a;if(d.nodeType===1&&d.nodeName.toLowerCase()!=="object"){i=bh(a),(k=d.getAttribute("id"))?l=k.replace(c,"\\$&"):d.setAttribute("id",l),l="[id='"+l+"'] ",j=i.length;while(j--)i[j]=l+i[j].join("");m=R.test(a)&&d.parentNode||d,n=i.join(",")}if(n)try{return w.apply(f,x.call(m.querySelectorAll(n),0)),f}catch(p){}finally{k||d.removeAttribute("id")}}return b(a,d,f,g,h)},h&&(X(function(b){a=h.call(b,"div");try{h.call(b,"[test!='']:sizzle"),f.push("!=",J)}catch(c){}}),f=new RegExp(f.join("|")),bc.matchesSelector=function(b,c){c=c.replace(d,"='$1']");if(!g(b)&&!f.test(c)&&(!e||!e.test(c)))try{var i=h.call(b,c);if(i||a||b.document&&b.document.nodeType!==11)return i}catch(j){}return bc(c,null,null,[b]).length>0})}(),e.pseudos.nth=e.pseudos.eq,e.filters=bq.prototype=e.pseudos,e.setFilters=new bq,bc.attr=p.attr,p.find=bc,p.expr=bc.selectors,p.expr[":"]=p.expr.pseudos,p.unique=bc.uniqueSort,p.text=bc.getText,p.isXMLDoc=bc.isXML,p.contains=bc.contains}(a);var bc=/Until$/,bd=/^(?:parents|prev(?:Until|All))/,be=/^.[^:#\[\.,]*$/,bf=p.expr.match.needsContext,bg={children:!0,contents:!0,next:!0,prev:!0};p.fn.extend({find:function(a){var b,c,d,e,f,g,h=this;if(typeof a!="string")return p(a).filter(function(){for(b=0,c=h.length;b<c;b++)if(p.contains(h[b],this))return!0});g=this.pushStack("","find",a);for(b=0,c=this.length;b<c;b++){d=g.length,p.find(a,this[b],g);if(b>0)for(e=d;e<g.length;e++)for(f=0;f<d;f++)if(g[f]===g[e]){g.splice(e--,1);break}}return g},has:function(a){var b,c=p(a,this),d=c.length;return this.filter(function(){for(b=0;b<d;b++)if(p.contains(this,c[b]))return!0})},not:function(a){return this.pushStack(bj(this,a,!1),"not",a)},filter:function(a){return this.pushStack(bj(this,a,!0),"filter",a)},is:function(a){return!!a&&(typeof a=="string"?bf.test(a)?p(a,this.context).index(this[0])>=0:p.filter(a,this).length>0:this.filter(a).length>0)},closest:function(a,b){var c,d=0,e=this.length,f=[],g=bf.test(a)||typeof a!="string"?p(a,b||this.context):0;for(;d<e;d++){c=this[d];while(c&&c.ownerDocument&&c!==b&&c.nodeType!==11){if(g?g.index(c)>-1:p.find.matchesSelector(c,a)){f.push(c);break}c=c.parentNode}}return f=f.length>1?p.unique(f):f,this.pushStack(f,"closest",a)},index:function(a){return a?typeof a=="string"?p.inArray(this[0],p(a)):p.inArray(a.jquery?a[0]:a,this):this[0]&&this[0].parentNode?this.prevAll().length:-1},add:function(a,b){var c=typeof a=="string"?p(a,b):p.makeArray(a&&a.nodeType?[a]:a),d=p.merge(this.get(),c);return this.pushStack(bh(c[0])||bh(d[0])?d:p.unique(d))},addBack:function(a){return this.add(a==null?this.prevObject:this.prevObject.filter(a))}}),p.fn.andSelf=p.fn.addBack,p.each({parent:function(a){var b=a.parentNode;return b&&b.nodeType!==11?b:null},parents:function(a){return p.dir(a,"parentNode")},parentsUntil:function(a,b,c){return p.dir(a,"parentNode",c)},next:function(a){return bi(a,"nextSibling")},prev:function(a){return bi(a,"previousSibling")},nextAll:function(a){return p.dir(a,"nextSibling")},prevAll:function(a){return p.dir(a,"previousSibling")},nextUntil:function(a,b,c){return p.dir(a,"nextSibling",c)},prevUntil:function(a,b,c){return p.dir(a,"previousSibling",c)},siblings:function(a){return p.sibling((a.parentNode||{}).firstChild,a)},children:function(a){return p.sibling(a.firstChild)},contents:function(a){return p.nodeName(a,"iframe")?a.contentDocument||a.contentWindow.document:p.merge([],a.childNodes)}},function(a,b){p.fn[a]=function(c,d){var e=p.map(this,b,c);return bc.test(a)||(d=c),d&&typeof d=="string"&&(e=p.filter(d,e)),e=this.length>1&&!bg[a]?p.unique(e):e,this.length>1&&bd.test(a)&&(e=e.reverse()),this.pushStack(e,a,k.call(arguments).join(","))}}),p.extend({filter:function(a,b,c){return c&&(a=":not("+a+")"),b.length===1?p.find.matchesSelector(b[0],a)?[b[0]]:[]:p.find.matches(a,b)},dir:function(a,c,d){var e=[],f=a[c];while(f&&f.nodeType!==9&&(d===b||f.nodeType!==1||!p(f).is(d)))f.nodeType===1&&e.push(f),f=f[c];return e},sibling:function(a,b){var c=[];for(;a;a=a.nextSibling)a.nodeType===1&&a!==b&&c.push(a);return c}});var bl="abbr|article|aside|audio|bdi|canvas|data|datalist|details|figcaption|figure|footer|header|hgroup|mark|meter|nav|output|progress|section|summary|time|video",bm=/ jQuery\d+="(?:null|\d+)"/g,bn=/^\s+/,bo=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,bp=/<([\w:]+)/,bq=/<tbody/i,br=/<|&#?\w+;/,bs=/<(?:script|style|link)/i,bt=/<(?:script|object|embed|option|style)/i,bu=new RegExp("<(?:"+bl+")[\\s/>]","i"),bv=/^(?:checkbox|radio)$/,bw=/checked\s*(?:[^=]|=\s*.checked.)/i,bx=/\/(java|ecma)script/i,by=/^\s*<!(?:\[CDATA\[|\-\-)|[\]\-]{2}>\s*$/g,bz={option:[1,"<select multiple='multiple'>","</select>"],legend:[1,"<fieldset>","</fieldset>"],thead:[1,"<table>","</table>"],tr:[2,"<table><tbody>","</tbody></table>"],td:[3,"<table><tbody><tr>","</tr></tbody></table>"],col:[2,"<table><tbody></tbody><colgroup>","</colgroup></table>"],area:[1,"<map>","</map>"],_default:[0,"",""]},bA=bk(e),bB=bA.appendChild(e.createElement("div"));bz.optgroup=bz.option,bz.tbody=bz.tfoot=bz.colgroup=bz.caption=bz.thead,bz.th=bz.td,p.support.htmlSerialize||(bz._default=[1,"X<div>","</div>"]),p.fn.extend({text:function(a){return p.access(this,function(a){return a===b?p.text(this):this.empty().append((this[0]&&this[0].ownerDocument||e).createTextNode(a))},null,a,arguments.length)},wrapAll:function(a){if(p.isFunction(a))return this.each(function(b){p(this).wrapAll(a.call(this,b))});if(this[0]){var b=p(a,this[0].ownerDocument).eq(0).clone(!0);this[0].parentNode&&b.insertBefore(this[0]),b.map(function(){var a=this;while(a.firstChild&&a.firstChild.nodeType===1)a=a.firstChild;return a}).append(this)}return this},wrapInner:function(a){return p.isFunction(a)?this.each(function(b){p(this).wrapInner(a.call(this,b))}):this.each(function(){var b=p(this),c=b.contents();c.length?c.wrapAll(a):b.append(a)})},wrap:function(a){var b=p.isFunction(a);return this.each(function(c){p(this).wrapAll(b?a.call(this,c):a)})},unwrap:function(){return this.parent().each(function(){p.nodeName(this,"body")||p(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,!0,function(a){(this.nodeType===1||this.nodeType===11)&&this.appendChild(a)})},prepend:function(){return this.domManip(arguments,!0,function(a){(this.nodeType===1||this.nodeType===11)&&this.insertBefore(a,this.firstChild)})},before:function(){if(!bh(this[0]))return this.domManip(arguments,!1,function(a){this.parentNode.insertBefore(a,this)});if(arguments.length){var a=p.clean(arguments);return this.pushStack(p.merge(a,this),"before",this.selector)}},after:function(){if(!bh(this[0]))return this.domManip(arguments,!1,function(a){this.parentNode.insertBefore(a,this.nextSibling)});if(arguments.length){var a=p.clean(arguments);return this.pushStack(p.merge(this,a),"after",this.selector)}},remove:function(a,b){var c,d=0;for(;(c=this[d])!=null;d++)if(!a||p.filter(a,[c]).length)!b&&c.nodeType===1&&(p.cleanData(c.getElementsByTagName("*")),p.cleanData([c])),c.parentNode&&c.parentNode.removeChild(c);return this},empty:function(){var a,b=0;for(;(a=this[b])!=null;b++){a.nodeType===1&&p.cleanData(a.getElementsByTagName("*"));while(a.firstChild)a.removeChild(a.firstChild)}return this},clone:function(a,b){return a=a==null?!1:a,b=b==null?a:b,this.map(function(){return p.clone(this,a,b)})},html:function(a){return p.access(this,function(a){var c=this[0]||{},d=0,e=this.length;if(a===b)return c.nodeType===1?c.innerHTML.replace(bm,""):b;if(typeof a=="string"&&!bs.test(a)&&(p.support.htmlSerialize||!bu.test(a))&&(p.support.leadingWhitespace||!bn.test(a))&&!bz[(bp.exec(a)||["",""])[1].toLowerCase()]){a=a.replace(bo,"<$1></$2>");try{for(;d<e;d++)c=this[d]||{},c.nodeType===1&&(p.cleanData(c.getElementsByTagName("*")),c.innerHTML=a);c=0}catch(f){}}c&&this.empty().append(a)},null,a,arguments.length)},replaceWith:function(a){return bh(this[0])?this.length?this.pushStack(p(p.isFunction(a)?a():a),"replaceWith",a):this:p.isFunction(a)?this.each(function(b){var c=p(this),d=c.html();c.replaceWith(a.call(this,b,d))}):(typeof a!="string"&&(a=p(a).detach()),this.each(function(){var b=this.nextSibling,c=this.parentNode;p(this).remove(),b?p(b).before(a):p(c).append(a)}))},detach:function(a){return this.remove(a,!0)},domManip:function(a,c,d){a=[].concat.apply([],a);var e,f,g,h,i=0,j=a[0],k=[],l=this.length;if(!p.support.checkClone&&l>1&&typeof j=="string"&&bw.test(j))return this.each(function(){p(this).domManip(a,c,d)});if(p.isFunction(j))return this.each(function(e){var f=p(this);a[0]=j.call(this,e,c?f.html():b),f.domManip(a,c,d)});if(this[0]){e=p.buildFragment(a,this,k),g=e.fragment,f=g.firstChild,g.childNodes.length===1&&(g=f);if(f){c=c&&p.nodeName(f,"tr");for(h=e.cacheable||l-1;i<l;i++)d.call(c&&p.nodeName(this[i],"table")?bC(this[i],"tbody"):this[i],i===h?g:p.clone(g,!0,!0))}g=f=null,k.length&&p.each(k,function(a,b){b.src?p.ajax?p.ajax({url:b.src,type:"GET",dataType:"script",async:!1,global:!1,"throws":!0}):p.error("no ajax"):p.globalEval((b.text||b.textContent||b.innerHTML||"").replace(by,"")),b.parentNode&&b.parentNode.removeChild(b)})}return this}}),p.buildFragment=function(a,c,d){var f,g,h,i=a[0];return c=c||e,c=!c.nodeType&&c[0]||c,c=c.ownerDocument||c,a.length===1&&typeof i=="string"&&i.length<512&&c===e&&i.charAt(0)==="<"&&!bt.test(i)&&(p.support.checkClone||!bw.test(i))&&(p.support.html5Clone||!bu.test(i))&&(g=!0,f=p.fragments[i],h=f!==b),f||(f=c.createDocumentFragment(),p.clean(a,c,f,d),g&&(p.fragments[i]=h&&f)),{fragment:f,cacheable:g}},p.fragments={},p.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){p.fn[a]=function(c){var d,e=0,f=[],g=p(c),h=g.length,i=this.length===1&&this[0].parentNode;if((i==null||i&&i.nodeType===11&&i.childNodes.length===1)&&h===1)return g[b](this[0]),this;for(;e<h;e++)d=(e>0?this.clone(!0):this).get(),p(g[e])[b](d),f=f.concat(d);return this.pushStack(f,a,g.selector)}}),p.extend({clone:function(a,b,c){var d,e,f,g;p.support.html5Clone||p.isXMLDoc(a)||!bu.test("<"+a.nodeName+">")?g=a.cloneNode(!0):(bB.innerHTML=a.outerHTML,bB.removeChild(g=bB.firstChild));if((!p.support.noCloneEvent||!p.support.noCloneChecked)&&(a.nodeType===1||a.nodeType===11)&&!p.isXMLDoc(a)){bE(a,g),d=bF(a),e=bF(g);for(f=0;d[f];++f)e[f]&&bE(d[f],e[f])}if(b){bD(a,g);if(c){d=bF(a),e=bF(g);for(f=0;d[f];++f)bD(d[f],e[f])}}return d=e=null,g},clean:function(a,b,c,d){var f,g,h,i,j,k,l,m,n,o,q,r,s=b===e&&bA,t=[];if(!b||typeof b.createDocumentFragment=="undefined")b=e;for(f=0;(h=a[f])!=null;f++){typeof h=="number"&&(h+="");if(!h)continue;if(typeof h=="string")if(!br.test(h))h=b.createTextNode(h);else{s=s||bk(b),l=b.createElement("div"),s.appendChild(l),h=h.replace(bo,"<$1></$2>"),i=(bp.exec(h)||["",""])[1].toLowerCase(),j=bz[i]||bz._default,k=j[0],l.innerHTML=j[1]+h+j[2];while(k--)l=l.lastChild;if(!p.support.tbody){m=bq.test(h),n=i==="table"&&!m?l.firstChild&&l.firstChild.childNodes:j[1]==="<table>"&&!m?l.childNodes:[];for(g=n.length-1;g>=0;--g)p.nodeName(n[g],"tbody")&&!n[g].childNodes.length&&n[g].parentNode.removeChild(n[g])}!p.support.leadingWhitespace&&bn.test(h)&&l.insertBefore(b.createTextNode(bn.exec(h)[0]),l.firstChild),h=l.childNodes,l.parentNode.removeChild(l)}h.nodeType?t.push(h):p.merge(t,h)}l&&(h=l=s=null);if(!p.support.appendChecked)for(f=0;(h=t[f])!=null;f++)p.nodeName(h,"input")?bG(h):typeof h.getElementsByTagName!="undefined"&&p.grep(h.getElementsByTagName("input"),bG);if(c){q=function(a){if(!a.type||bx.test(a.type))return d?d.push(a.parentNode?a.parentNode.removeChild(a):a):c.appendChild(a)};for(f=0;(h=t[f])!=null;f++)if(!p.nodeName(h,"script")||!q(h))c.appendChild(h),typeof h.getElementsByTagName!="undefined"&&(r=p.grep(p.merge([],h.getElementsByTagName("script")),q),t.splice.apply(t,[f+1,0].concat(r)),f+=r.length)}return t},cleanData:function(a,b){var c,d,e,f,g=0,h=p.expando,i=p.cache,j=p.support.deleteExpando,k=p.event.special;for(;(e=a[g])!=null;g++)if(b||p.acceptData(e)){d=e[h],c=d&&i[d];if(c){if(c.events)for(f in c.events)k[f]?p.event.remove(e,f):p.removeEvent(e,f,c.handle);i[d]&&(delete i[d],j?delete e[h]:e.removeAttribute?e.removeAttribute(h):e[h]=null,p.deletedIds.push(d))}}}}),function(){var a,b;p.uaMatch=function(a){a=a.toLowerCase();var b=/(chrome)[ \/]([\w.]+)/.exec(a)||/(webkit)[ \/]([\w.]+)/.exec(a)||/(opera)(?:.*version|)[ \/]([\w.]+)/.exec(a)||/(msie) ([\w.]+)/.exec(a)||a.indexOf("compatible")<0&&/(mozilla)(?:.*? rv:([\w.]+)|)/.exec(a)||[];return{browser:b[1]||"",version:b[2]||"0"}},a=p.uaMatch(g.userAgent),b={},a.browser&&(b[a.browser]=!0,b.version=a.version),b.chrome?b.webkit=!0:b.webkit&&(b.safari=!0),p.browser=b,p.sub=function(){function a(b,c){return new a.fn.init(b,c)}p.extend(!0,a,this),a.superclass=this,a.fn=a.prototype=this(),a.fn.constructor=a,a.sub=this.sub,a.fn.init=function c(c,d){return d&&d instanceof p&&!(d instanceof a)&&(d=a(d)),p.fn.init.call(this,c,d,b)},a.fn.init.prototype=a.fn;var b=a(e);return a}}();var bH,bI,bJ,bK=/alpha\([^)]*\)/i,bL=/opacity=([^)]*)/,bM=/^(top|right|bottom|left)$/,bN=/^(none|table(?!-c[ea]).+)/,bO=/^margin/,bP=new RegExp("^("+q+")(.*)$","i"),bQ=new RegExp("^("+q+")(?!px)[a-z%]+$","i"),bR=new RegExp("^([-+])=("+q+")","i"),bS={},bT={position:"absolute",visibility:"hidden",display:"block"},bU={letterSpacing:0,fontWeight:400},bV=["Top","Right","Bottom","Left"],bW=["Webkit","O","Moz","ms"],bX=p.fn.toggle;p.fn.extend({css:function(a,c){return p.access(this,function(a,c,d){return d!==b?p.style(a,c,d):p.css(a,c)},a,c,arguments.length>1)},show:function(){return b$(this,!0)},hide:function(){return b$(this)},toggle:function(a,b){var c=typeof a=="boolean";return p.isFunction(a)&&p.isFunction(b)?bX.apply(this,arguments):this.each(function(){(c?a:bZ(this))?p(this).show():p(this).hide()})}}),p.extend({cssHooks:{opacity:{get:function(a,b){if(b){var c=bH(a,"opacity");return c===""?"1":c}}}},cssNumber:{fillOpacity:!0,fontWeight:!0,lineHeight:!0,opacity:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{"float":p.support.cssFloat?"cssFloat":"styleFloat"},style:function(a,c,d,e){if(!a||a.nodeType===3||a.nodeType===8||!a.style)return;var f,g,h,i=p.camelCase(c),j=a.style;c=p.cssProps[i]||(p.cssProps[i]=bY(j,i)),h=p.cssHooks[c]||p.cssHooks[i];if(d===b)return h&&"get"in h&&(f=h.get(a,!1,e))!==b?f:j[c];g=typeof d,g==="string"&&(f=bR.exec(d))&&(d=(f[1]+1)*f[2]+parseFloat(p.css(a,c)),g="number");if(d==null||g==="number"&&isNaN(d))return;g==="number"&&!p.cssNumber[i]&&(d+="px");if(!h||!("set"in h)||(d=h.set(a,d,e))!==b)try{j[c]=d}catch(k){}},css:function(a,c,d,e){var f,g,h,i=p.camelCase(c);return c=p.cssProps[i]||(p.cssProps[i]=bY(a.style,i)),h=p.cssHooks[c]||p.cssHooks[i],h&&"get"in h&&(f=h.get(a,!0,e)),f===b&&(f=bH(a,c)),f==="normal"&&c in bU&&(f=bU[c]),d||e!==b?(g=parseFloat(f),d||p.isNumeric(g)?g||0:f):f},swap:function(a,b,c){var d,e,f={};for(e in b)f[e]=a.style[e],a.style[e]=b[e];d=c.call(a);for(e in b)a.style[e]=f[e];return d}}),a.getComputedStyle?bH=function(b,c){var d,e,f,g,h=a.getComputedStyle(b,null),i=b.style;return h&&(d=h[c],d===""&&!p.contains(b.ownerDocument,b)&&(d=p.style(b,c)),bQ.test(d)&&bO.test(c)&&(e=i.width,f=i.minWidth,g=i.maxWidth,i.minWidth=i.maxWidth=i.width=d,d=h.width,i.width=e,i.minWidth=f,i.maxWidth=g)),d}:e.documentElement.currentStyle&&(bH=function(a,b){var c,d,e=a.currentStyle&&a.currentStyle[b],f=a.style;return e==null&&f&&f[b]&&(e=f[b]),bQ.test(e)&&!bM.test(b)&&(c=f.left,d=a.runtimeStyle&&a.runtimeStyle.left,d&&(a.runtimeStyle.left=a.currentStyle.left),f.left=b==="fontSize"?"1em":e,e=f.pixelLeft+"px",f.left=c,d&&(a.runtimeStyle.left=d)),e===""?"auto":e}),p.each(["height","width"],function(a,b){p.cssHooks[b]={get:function(a,c,d){if(c)return a.offsetWidth===0&&bN.test(bH(a,"display"))?p.swap(a,bT,function(){return cb(a,b,d)}):cb(a,b,d)},set:function(a,c,d){return b_(a,c,d?ca(a,b,d,p.support.boxSizing&&p.css(a,"boxSizing")==="border-box"):0)}}}),p.support.opacity||(p.cssHooks.opacity={get:function(a,b){return bL.test((b&&a.currentStyle?a.currentStyle.filter:a.style.filter)||"")?.01*parseFloat(RegExp.$1)+"":b?"1":""},set:function(a,b){var c=a.style,d=a.currentStyle,e=p.isNumeric(b)?"alpha(opacity="+b*100+")":"",f=d&&d.filter||c.filter||"";c.zoom=1;if(b>=1&&p.trim(f.replace(bK,""))===""&&c.removeAttribute){c.removeAttribute("filter");if(d&&!d.filter)return}c.filter=bK.test(f)?f.replace(bK,e):f+" "+e}}),p(function(){p.support.reliableMarginRight||(p.cssHooks.marginRight={get:function(a,b){return p.swap(a,{display:"inline-block"},function(){if(b)return bH(a,"marginRight")})}}),!p.support.pixelPosition&&p.fn.position&&p.each(["top","left"],function(a,b){p.cssHooks[b]={get:function(a,c){if(c){var d=bH(a,b);return bQ.test(d)?p(a).position()[b]+"px":d}}}})}),p.expr&&p.expr.filters&&(p.expr.filters.hidden=function(a){return a.offsetWidth===0&&a.offsetHeight===0||!p.support.reliableHiddenOffsets&&(a.style&&a.style.display||bH(a,"display"))==="none"},p.expr.filters.visible=function(a){return!p.expr.filters.hidden(a)}),p.each({margin:"",padding:"",border:"Width"},function(a,b){p.cssHooks[a+b]={expand:function(c){var d,e=typeof c=="string"?c.split(" "):[c],f={};for(d=0;d<4;d++)f[a+bV[d]+b]=e[d]||e[d-2]||e[0];return f}},bO.test(a)||(p.cssHooks[a+b].set=b_)});var cd=/%20/g,ce=/\[\]$/,cf=/\r?\n/g,cg=/^(?:color|date|datetime|datetime-local|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i,ch=/^(?:select|textarea)/i;p.fn.extend({serialize:function(){return p.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?p.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&&(this.checked||ch.test(this.nodeName)||cg.test(this.type))}).map(function(a,b){var c=p(this).val();return c==null?null:p.isArray(c)?p.map(c,function(a,c){return{name:b.name,value:a.replace(cf,"\r\n")}}):{name:b.name,value:c.replace(cf,"\r\n")}}).get()}}),p.param=function(a,c){var d,e=[],f=function(a,b){b=p.isFunction(b)?b():b==null?"":b,e[e.length]=encodeURIComponent(a)+"="+encodeURIComponent(b)};c===b&&(c=p.ajaxSettings&&p.ajaxSettings.traditional);if(p.isArray(a)||a.jquery&&!p.isPlainObject(a))p.each(a,function(){f(this.name,this.value)});else for(d in a)ci(d,a[d],c,f);return e.join("&").replace(cd,"+")};var cj,ck,cl=/#.*$/,cm=/^(.*?):[ \t]*([^\r\n]*)\r?$/mg,cn=/^(?:about|app|app\-storage|.+\-extension|file|res|widget):$/,co=/^(?:GET|HEAD)$/,cp=/^\/\//,cq=/\?/,cr=/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi,cs=/([?&])_=[^&]*/,ct=/^([\w\+\.\-]+:)(?:\/\/([^\/?#:]*)(?::(\d+)|)|)/,cu=p.fn.load,cv={},cw={},cx=["*/"]+["*"];try{ck=f.href}catch(cy){ck=e.createElement("a"),ck.href="",ck=ck.href}cj=ct.exec(ck.toLowerCase())||[],p.fn.load=function(a,c,d){if(typeof a!="string"&&cu)return cu.apply(this,arguments);if(!this.length)return this;var e,f,g,h=this,i=a.indexOf(" ");return i>=0&&(e=a.slice(i,a.length),a=a.slice(0,i)),p.isFunction(c)?(d=c,c=b):c&&typeof c=="object"&&(f="POST"),p.ajax({url:a,type:f,dataType:"html",data:c,complete:function(a,b){d&&h.each(d,g||[a.responseText,b,a])}}).done(function(a){g=arguments,h.html(e?p("<div>").append(a.replace(cr,"")).find(e):a)}),this},p.each("ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split(" "),function(a,b){p.fn[b]=function(a){return this.on(b,a)}}),p.each(["get","post"],function(a,c){p[c]=function(a,d,e,f){return p.isFunction(d)&&(f=f||e,e=d,d=b),p.ajax({type:c,url:a,data:d,success:e,dataType:f})}}),p.extend({getScript:function(a,c){return p.get(a,b,c,"script")},getJSON:function(a,b,c){return p.get(a,b,c,"json")},ajaxSetup:function(a,b){return b?cB(a,p.ajaxSettings):(b=a,a=p.ajaxSettings),cB(a,b),a},ajaxSettings:{url:ck,isLocal:cn.test(cj[1]),global:!0,type:"GET",contentType:"application/x-www-form-urlencoded; charset=UTF-8",processData:!0,async:!0,accepts:{xml:"application/xml, text/xml",html:"text/html",text:"text/plain",json:"application/json, text/javascript","*":cx},contents:{xml:/xml/,html:/html/,json:/json/},responseFields:{xml:"responseXML",text:"responseText"},converters:{"* text":a.String,"text html":!0,"text json":p.parseJSON,"text xml":p.parseXML},flatOptions:{context:!0,url:!0}},ajaxPrefilter:cz(cv),ajaxTransport:cz(cw),ajax:function(a,c){function y(a,c,f,i){var k,s,t,u,w,y=c;if(v===2)return;v=2,h&&clearTimeout(h),g=b,e=i||"",x.readyState=a>0?4:0,f&&(u=cC(l,x,f));if(a>=200&&a<300||a===304)l.ifModified&&(w=x.getResponseHeader("Last-Modified"),w&&(p.lastModified[d]=w),w=x.getResponseHeader("Etag"),w&&(p.etag[d]=w)),a===304?(y="notmodified",k=!0):(k=cD(l,u),y=k.state,s=k.data,t=k.error,k=!t);else{t=y;if(!y||a)y="error",a<0&&(a=0)}x.status=a,x.statusText=(c||y)+"",k?o.resolveWith(m,[s,y,x]):o.rejectWith(m,[x,y,t]),x.statusCode(r),r=b,j&&n.trigger("ajax"+(k?"Success":"Error"),[x,l,k?s:t]),q.fireWith(m,[x,y]),j&&(n.trigger("ajaxComplete",[x,l]),--p.active||p.event.trigger("ajaxStop"))}typeof a=="object"&&(c=a,a=b),c=c||{};var d,e,f,g,h,i,j,k,l=p.ajaxSetup({},c),m=l.context||l,n=m!==l&&(m.nodeType||m instanceof p)?p(m):p.event,o=p.Deferred(),q=p.Callbacks("once memory"),r=l.statusCode||{},t={},u={},v=0,w="canceled",x={readyState:0,setRequestHeader:function(a,b){if(!v){var c=a.toLowerCase();a=u[c]=u[c]||a,t[a]=b}return this},getAllResponseHeaders:function(){return v===2?e:null},getResponseHeader:function(a){var c;if(v===2){if(!f){f={};while(c=cm.exec(e))f[c[1].toLowerCase()]=c[2]}c=f[a.toLowerCase()]}return c===b?null:c},overrideMimeType:function(a){return v||(l.mimeType=a),this},abort:function(a){return a=a||w,g&&g.abort(a),y(0,a),this}};o.promise(x),x.success=x.done,x.error=x.fail,x.complete=q.add,x.statusCode=function(a){if(a){var b;if(v<2)for(b in a)r[b]=[r[b],a[b]];else b=a[x.status],x.always(b)}return this},l.url=((a||l.url)+"").replace(cl,"").replace(cp,cj[1]+"//"),l.dataTypes=p.trim(l.dataType||"*").toLowerCase().split(s),l.crossDomain==null&&(i=ct.exec(l.url.toLowerCase())||!1,l.crossDomain=i&&i.join(":")+(i[3]?"":i[1]==="http:"?80:443)!==cj.join(":")+(cj[3]?"":cj[1]==="http:"?80:443)),l.data&&l.processData&&typeof l.data!="string"&&(l.data=p.param(l.data,l.traditional)),cA(cv,l,c,x);if(v===2)return x;j=l.global,l.type=l.type.toUpperCase(),l.hasContent=!co.test(l.type),j&&p.active++===0&&p.event.trigger("ajaxStart");if(!l.hasContent){l.data&&(l.url+=(cq.test(l.url)?"&":"?")+l.data,delete l.data),d=l.url;if(l.cache===!1){var z=p.now(),A=l.url.replace(cs,"$1_="+z);l.url=A+(A===l.url?(cq.test(l.url)?"&":"?")+"_="+z:"")}}(l.data&&l.hasContent&&l.contentType!==!1||c.contentType)&&x.setRequestHeader("Content-Type",l.contentType),l.ifModified&&(d=d||l.url,p.lastModified[d]&&x.setRequestHeader("If-Modified-Since",p.lastModified[d]),p.etag[d]&&x.setRequestHeader("If-None-Match",p.etag[d])),x.setRequestHeader("Accept",l.dataTypes[0]&&l.accepts[l.dataTypes[0]]?l.accepts[l.dataTypes[0]]+(l.dataTypes[0]!=="*"?", "+cx+"; q=0.01":""):l.accepts["*"]);for(k in l.headers)x.setRequestHeader(k,l.headers[k]);if(!l.beforeSend||l.beforeSend.call(m,x,l)!==!1&&v!==2){w="abort";for(k in{success:1,error:1,complete:1})x[k](l[k]);g=cA(cw,l,c,x);if(!g)y(-1,"No Transport");else{x.readyState=1,j&&n.trigger("ajaxSend",[x,l]),l.async&&l.timeout>0&&(h=setTimeout(function(){x.abort("timeout")},l.timeout));try{v=1,g.send(t,y)}catch(B){if(v<2)y(-1,B);else throw B}}return x}return x.abort()},active:0,lastModified:{},etag:{}});var cE=[],cF=/\?/,cG=/(=)\?(?=&|$)|\?\?/,cH=p.now();p.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var a=cE.pop()||p.expando+"_"+cH++;return this[a]=!0,a}}),p.ajaxPrefilter("json jsonp",function(c,d,e){var f,g,h,i=c.data,j=c.url,k=c.jsonp!==!1,l=k&&cG.test(j),m=k&&!l&&typeof i=="string"&&!(c.contentType||"").indexOf("application/x-www-form-urlencoded")&&cG.test(i);if(c.dataTypes[0]==="jsonp"||l||m)return f=c.jsonpCallback=p.isFunction(c.jsonpCallback)?c.jsonpCallback():c.jsonpCallback,g=a[f],l?c.url=j.replace(cG,"$1"+f):m?c.data=i.replace(cG,"$1"+f):k&&(c.url+=(cF.test(j)?"&":"?")+c.jsonp+"="+f),c.converters["script json"]=function(){return h||p.error(f+" was not called"),h[0]},c.dataTypes[0]="json",a[f]=function(){h=arguments},e.always(function(){a[f]=g,c[f]&&(c.jsonpCallback=d.jsonpCallback,cE.push(f)),h&&p.isFunction(g)&&g(h[0]),h=g=b}),"script"}),p.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/javascript|ecmascript/},converters:{"text script":function(a){return p.globalEval(a),a}}}),p.ajaxPrefilter("script",function(a){a.cache===b&&(a.cache=!1),a.crossDomain&&(a.type="GET",a.global=!1)}),p.ajaxTransport("script",function(a){if(a.crossDomain){var c,d=e.head||e.getElementsByTagName("head")[0]||e.documentElement;return{send:function(f,g){c=e.createElement("script"),c.async="async",a.scriptCharset&&(c.charset=a.scriptCharset),c.src=a.url,c.onload=c.onreadystatechange=function(a,e){if(e||!c.readyState||/loaded|complete/.test(c.readyState))c.onload=c.onreadystatechange=null,d&&c.parentNode&&d.removeChild(c),c=b,e||g(200,"success")},d.insertBefore(c,d.firstChild)},abort:function(){c&&c.onload(0,1)}}}});var cI,cJ=a.ActiveXObject?function(){for(var a in cI)cI[a](0,1)}:!1,cK=0;p.ajaxSettings.xhr=a.ActiveXObject?function(){return!this.isLocal&&cL()||cM()}:cL,function(a){p.extend(p.support,{ajax:!!a,cors:!!a&&"withCredentials"in a})}(p.ajaxSettings.xhr()),p.support.ajax&&p.ajaxTransport(function(c){if(!c.crossDomain||p.support.cors){var d;return{send:function(e,f){var g,h,i=c.xhr();c.username?i.open(c.type,c.url,c.async,c.username,c.password):i.open(c.type,c.url,c.async);if(c.xhrFields)for(h in c.xhrFields)i[h]=c.xhrFields[h];c.mimeType&&i.overrideMimeType&&i.overrideMimeType(c.mimeType),!c.crossDomain&&!e["X-Requested-With"]&&(e["X-Requested-With"]="XMLHttpRequest");try{for(h in e)i.setRequestHeader(h,e[h])}catch(j){}i.send(c.hasContent&&c.data||null),d=function(a,e){var h,j,k,l,m;try{if(d&&(e||i.readyState===4)){d=b,g&&(i.onreadystatechange=p.noop,cJ&&delete cI[g]);if(e)i.readyState!==4&&i.abort();else{h=i.status,k=i.getAllResponseHeaders(),l={},m=i.responseXML,m&&m.documentElement&&(l.xml=m);try{l.text=i.responseText}catch(a){}try{j=i.statusText}catch(n){j=""}!h&&c.isLocal&&!c.crossDomain?h=l.text?200:404:h===1223&&(h=204)}}}catch(o){e||f(-1,o)}l&&f(h,j,l,k)},c.async?i.readyState===4?setTimeout(d,0):(g=++cK,cJ&&(cI||(cI={},p(a).unload(cJ)),cI[g]=d),i.onreadystatechange=d):d()},abort:function(){d&&d(0,1)}}}});var cN,cO,cP=/^(?:toggle|show|hide)$/,cQ=new RegExp("^(?:([-+])=|)("+q+")([a-z%]*)$","i"),cR=/queueHooks$/,cS=[cY],cT={"*":[function(a,b){var c,d,e=this.createTween(a,b),f=cQ.exec(b),g=e.cur(),h=+g||0,i=1,j=20;if(f){c=+f[2],d=f[3]||(p.cssNumber[a]?"":"px");if(d!=="px"&&h){h=p.css(e.elem,a,!0)||c||1;do i=i||".5",h=h/i,p.style(e.elem,a,h+d);while(i!==(i=e.cur()/g)&&i!==1&&--j)}e.unit=d,e.start=h,e.end=f[1]?h+(f[1]+1)*c:c}return e}]};p.Animation=p.extend(cW,{tweener:function(a,b){p.isFunction(a)?(b=a,a=["*"]):a=a.split(" ");var c,d=0,e=a.length;for(;d<e;d++)c=a[d],cT[c]=cT[c]||[],cT[c].unshift(b)},prefilter:function(a,b){b?cS.unshift(a):cS.push(a)}}),p.Tween=cZ,cZ.prototype={constructor:cZ,init:function(a,b,c,d,e,f){this.elem=a,this.prop=c,this.easing=e||"swing",this.options=b,this.start=this.now=this.cur(),this.end=d,this.unit=f||(p.cssNumber[c]?"":"px")},cur:function(){var a=cZ.propHooks[this.prop];return a&&a.get?a.get(this):cZ.propHooks._default.get(this)},run:function(a){var b,c=cZ.propHooks[this.prop];return this.options.duration?this.pos=b=p.easing[this.easing](a,this.options.duration*a,0,1,this.options.duration):this.pos=b=a,this.now=(this.end-this.start)*b+this.start,this.options.step&&this.options.step.call(this.elem,this.now,this),c&&c.set?c.set(this):cZ.propHooks._default.set(this),this}},cZ.prototype.init.prototype=cZ.prototype,cZ.propHooks={_default:{get:function(a){var b;return a.elem[a.prop]==null||!!a.elem.style&&a.elem.style[a.prop]!=null?(b=p.css(a.elem,a.prop,!1,""),!b||b==="auto"?0:b):a.elem[a.prop]},set:function(a){p.fx.step[a.prop]?p.fx.step[a.prop](a):a.elem.style&&(a.elem.style[p.cssProps[a.prop]]!=null||p.cssHooks[a.prop])?p.style(a.elem,a.prop,a.now+a.unit):a.elem[a.prop]=a.now}}},cZ.propHooks.scrollTop=cZ.propHooks.scrollLeft={set:function(a){a.elem.nodeType&&a.elem.parentNode&&(a.elem[a.prop]=a.now)}},p.each(["toggle","show","hide"],function(a,b){var c=p.fn[b];p.fn[b]=function(d,e,f){return d==null||typeof d=="boolean"||!a&&p.isFunction(d)&&p.isFunction(e)?c.apply(this,arguments):this.animate(c$(b,!0),d,e,f)}}),p.fn.extend({fadeTo:function(a,b,c,d){return this.filter(bZ).css("opacity",0).show().end().animate({opacity:b},a,c,d)},animate:function(a,b,c,d){var e=p.isEmptyObject(a),f=p.speed(b,c,d),g=function(){var b=cW(this,p.extend({},a),f);e&&b.stop(!0)};return e||f.queue===!1?this.each(g):this.queue(f.queue,g)},stop:function(a,c,d){var e=function(a){var b=a.stop;delete a.stop,b(d)};return typeof a!="string"&&(d=c,c=a,a=b),c&&a!==!1&&this.queue(a||"fx",[]),this.each(function(){var b=!0,c=a!=null&&a+"queueHooks",f=p.timers,g=p._data(this);if(c)g[c]&&g[c].stop&&e(g[c]);else for(c in g)g[c]&&g[c].stop&&cR.test(c)&&e(g[c]);for(c=f.length;c--;)f[c].elem===this&&(a==null||f[c].queue===a)&&(f[c].anim.stop(d),b=!1,f.splice(c,1));(b||!d)&&p.dequeue(this,a)})}}),p.each({slideDown:c$("show"),slideUp:c$("hide"),slideToggle:c$("toggle"),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"},fadeToggle:{opacity:"toggle"}},function(a,b){p.fn[a]=function(a,c,d){return this.animate(b,a,c,d)}}),p.speed=function(a,b,c){var d=a&&typeof a=="object"?p.extend({},a):{complete:c||!c&&b||p.isFunction(a)&&a,duration:a,easing:c&&b||b&&!p.isFunction(b)&&b};d.duration=p.fx.off?0:typeof d.duration=="number"?d.duration:d.duration in p.fx.speeds?p.fx.speeds[d.duration]:p.fx.speeds._default;if(d.queue==null||d.queue===!0)d.queue="fx";return d.old=d.complete,d.complete=function(){p.isFunction(d.old)&&d.old.call(this),d.queue&&p.dequeue(this,d.queue)},d},p.easing={linear:function(a){return a},swing:function(a){return.5-Math.cos(a*Math.PI)/2}},p.timers=[],p.fx=cZ.prototype.init,p.fx.tick=function(){var a,b=p.timers,c=0;for(;c<b.length;c++)a=b[c],!a()&&b[c]===a&&b.splice(c--,1);b.length||p.fx.stop()},p.fx.timer=function(a){a()&&p.timers.push(a)&&!cO&&(cO=setInterval(p.fx.tick,p.fx.interval))},p.fx.interval=13,p.fx.stop=function(){clearInterval(cO),cO=null},p.fx.speeds={slow:600,fast:200,_default:400},p.fx.step={},p.expr&&p.expr.filters&&(p.expr.filters.animated=function(a){return p.grep(p.timers,function(b){return a===b.elem}).length});var c_=/^(?:body|html)$/i;p.fn.offset=function(a){if(arguments.length)return a===b?this:this.each(function(b){p.offset.setOffset(this,a,b)});var c,d,e,f,g,h,i,j={top:0,left:0},k=this[0],l=k&&k.ownerDocument;if(!l)return;return(d=l.body)===k?p.offset.bodyOffset(k):(c=l.documentElement,p.contains(c,k)?(typeof k.getBoundingClientRect!="undefined"&&(j=k.getBoundingClientRect()),e=da(l),f=c.clientTop||d.clientTop||0,g=c.clientLeft||d.clientLeft||0,h=e.pageYOffset||c.scrollTop,i=e.pageXOffset||c.scrollLeft,{top:j.top+h-f,left:j.left+i-g}):j)},p.offset={bodyOffset:function(a){var b=a.offsetTop,c=a.offsetLeft;return p.support.doesNotIncludeMarginInBodyOffset&&(b+=parseFloat(p.css(a,"marginTop"))||0,c+=parseFloat(p.css(a,"marginLeft"))||0),{top:b,left:c}},setOffset:function(a,b,c){var d=p.css(a,"position");d==="static"&&(a.style.position="relative");var e=p(a),f=e.offset(),g=p.css(a,"top"),h=p.css(a,"left"),i=(d==="absolute"||d==="fixed")&&p.inArray("auto",[g,h])>-1,j={},k={},l,m;i?(k=e.position(),l=k.top,m=k.left):(l=parseFloat(g)||0,m=parseFloat(h)||0),p.isFunction(b)&&(b=b.call(a,c,f)),b.top!=null&&(j.top=b.top-f.top+l),b.left!=null&&(j.left=b.left-f.left+m),"using"in b?b.using.call(a,j):e.css(j)}},p.fn.extend({position:function(){if(!this[0])return;var a=this[0],b=this.offsetParent(),c=this.offset(),d=c_.test(b[0].nodeName)?{top:0,left:0}:b.offset();return c.top-=parseFloat(p.css(a,"marginTop"))||0,c.left-=parseFloat(p.css(a,"marginLeft"))||0,d.top+=parseFloat(p.css(b[0],"borderTopWidth"))||0,d.left+=parseFloat(p.css(b[0],"borderLeftWidth"))||0,{top:c.top-d.top,left:c.left-d.left}},offsetParent:function(){return this.map(function(){var a=this.offsetParent||e.body;while(a&&!c_.test(a.nodeName)&&p.css(a,"position")==="static")a=a.offsetParent;return a||e.body})}}),p.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(a,c){var d=/Y/.test(c);p.fn[a]=function(e){return p.access(this,function(a,e,f){var g=da(a);if(f===b)return g?c in g?g[c]:g.document.documentElement[e]:a[e];g?g.scrollTo(d?p(g).scrollLeft():f,d?f:p(g).scrollTop()):a[e]=f},a,e,arguments.length,null)}}),p.each({Height:"height",Width:"width"},function(a,c){p.each({padding:"inner"+a,content:c,"":"outer"+a},function(d,e){p.fn[e]=function(e,f){var g=arguments.length&&(d||typeof e!="boolean"),h=d||(e===!0||f===!0?"margin":"border");return p.access(this,function(c,d,e){var f;return p.isWindow(c)?c.document.documentElement["client"+a]:c.nodeType===9?(f=c.documentElement,Math.max(c.body["scroll"+a],f["scroll"+a],c.body["offset"+a],f["offset"+a],f["client"+a])):e===b?p.css(c,d,e,h):p.style(c,d,e,h)},c,g?e:b,g,null)}})}),a.jQuery=a.$=p,typeof define=="function"&&define.amd&&define.amd.jQuery&&define("jquery",[],function(){return p})})(window);
\ No newline at end of file
diff --git a/godoc/static/jquery.treeview.css b/godoc/static/jquery.treeview.css
new file mode 100644
index 0000000..ac33361
--- /dev/null
+++ b/godoc/static/jquery.treeview.css
@@ -0,0 +1,76 @@
+/* https://github.com/jzaefferer/jquery-treeview/blob/master/jquery.treeview.css */
+/* License: MIT. */
+.treeview, .treeview ul {
+ padding: 0;
+ margin: 0;
+ list-style: none;
+}
+
+.treeview ul {
+ background-color: white;
+ margin-top: 4px;
+}
+
+.treeview .hitarea {
+ background: url(images/treeview-default.gif) -64px -25px no-repeat;
+ height: 16px;
+ width: 16px;
+ margin-left: -16px;
+ float: left;
+ cursor: pointer;
+}
+/* fix for IE6 */
+* html .hitarea {
+ display: inline;
+ float:none;
+}
+
+.treeview li {
+ margin: 0;
+ padding: 3px 0pt 3px 16px;
+}
+
+.treeview a.selected {
+ background-color: #eee;
+}
+
+#treecontrol { margin: 1em 0; display: none; }
+
+.treeview .hover { color: red; cursor: pointer; }
+
+.treeview li { background: url(images/treeview-default-line.gif) 0 0 no-repeat; }
+.treeview li.collapsable, .treeview li.expandable { background-position: 0 -176px; }
+
+.treeview .expandable-hitarea { background-position: -80px -3px; }
+
+.treeview li.last { background-position: 0 -1766px }
+.treeview li.lastCollapsable, .treeview li.lastExpandable { background-image: url(images/treeview-default.gif); }
+.treeview li.lastCollapsable { background-position: 0 -111px }
+.treeview li.lastExpandable { background-position: -32px -67px }
+
+.treeview div.lastCollapsable-hitarea, .treeview div.lastExpandable-hitarea { background-position: 0; }
+
+.treeview-red li { background-image: url(images/treeview-red-line.gif); }
+.treeview-red .hitarea, .treeview-red li.lastCollapsable, .treeview-red li.lastExpandable { background-image: url(images/treeview-red.gif); }
+
+.treeview-black li { background-image: url(images/treeview-black-line.gif); }
+.treeview-black .hitarea, .treeview-black li.lastCollapsable, .treeview-black li.lastExpandable { background-image: url(images/treeview-black.gif); }
+
+.treeview-gray li { background-image: url(images/treeview-gray-line.gif); }
+.treeview-gray .hitarea, .treeview-gray li.lastCollapsable, .treeview-gray li.lastExpandable { background-image: url(images/treeview-gray.gif); }
+
+.treeview-famfamfam li { background-image: url(images/treeview-famfamfam-line.gif); }
+.treeview-famfamfam .hitarea, .treeview-famfamfam li.lastCollapsable, .treeview-famfamfam li.lastExpandable { background-image: url(images/treeview-famfamfam.gif); }
+
+.treeview .placeholder {
+ background: url(images/ajax-loader.gif) 0 0 no-repeat;
+ height: 16px;
+ width: 16px;
+ display: block;
+}
+
+.filetree li { padding: 3px 0 2px 16px; }
+.filetree span.folder, .filetree span.file { padding: 1px 0 1px 16px; display: block; }
+.filetree span.folder { background: url(images/folder.gif) 0 0 no-repeat; }
+.filetree li.expandable span.folder { background: url(images/folder-closed.gif) 0 0 no-repeat; }
+.filetree span.file { background: url(images/file.gif) 0 0 no-repeat; }
diff --git a/godoc/static/jquery.treeview.edit.js b/godoc/static/jquery.treeview.edit.js
new file mode 100644
index 0000000..9895b02
--- /dev/null
+++ b/godoc/static/jquery.treeview.edit.js
@@ -0,0 +1,39 @@
+/* https://github.com/jzaefferer/jquery-treeview/blob/master/jquery.treeview.edit.js */
+/* License: MIT. */
+(function($) {
+ var CLASSES = $.treeview.classes;
+ var proxied = $.fn.treeview;
+ $.fn.treeview = function(settings) {
+ settings = $.extend({}, settings);
+ if (settings.add) {
+ return this.trigger("add", [settings.add]);
+ }
+ if (settings.remove) {
+ return this.trigger("remove", [settings.remove]);
+ }
+ return proxied.apply(this, arguments).bind("add", function(event, branches) {
+ $(branches).prev()
+ .removeClass(CLASSES.last)
+ .removeClass(CLASSES.lastCollapsable)
+ .removeClass(CLASSES.lastExpandable)
+ .find(">.hitarea")
+ .removeClass(CLASSES.lastCollapsableHitarea)
+ .removeClass(CLASSES.lastExpandableHitarea);
+ $(branches).find("li").andSelf().prepareBranches(settings).applyClasses(settings, $(this).data("toggler"));
+ }).bind("remove", function(event, branches) {
+ var prev = $(branches).prev();
+ var parent = $(branches).parent();
+ $(branches).remove();
+ prev.filter(":last-child").addClass(CLASSES.last)
+ .filter("." + CLASSES.expandable).replaceClass(CLASSES.last, CLASSES.lastExpandable).end()
+ .find(">.hitarea").replaceClass(CLASSES.expandableHitarea, CLASSES.lastExpandableHitarea).end()
+ .filter("." + CLASSES.collapsable).replaceClass(CLASSES.last, CLASSES.lastCollapsable).end()
+ .find(">.hitarea").replaceClass(CLASSES.collapsableHitarea, CLASSES.lastCollapsableHitarea);
+ if (parent.is(":not(:has(>))") && parent[0] != this) {
+ parent.parent().removeClass(CLASSES.collapsable).removeClass(CLASSES.expandable)
+ parent.siblings(".hitarea").andSelf().remove();
+ }
+ });
+ };
+
+})(jQuery);
diff --git a/godoc/static/jquery.treeview.js b/godoc/static/jquery.treeview.js
new file mode 100644
index 0000000..356af23
--- /dev/null
+++ b/godoc/static/jquery.treeview.js
@@ -0,0 +1,256 @@
+/*
+ * Treeview 1.4.1 - jQuery plugin to hide and show branches of a tree
+ *
+ * http://bassistance.de/jquery-plugins/jquery-plugin-treeview/
+ * http://docs.jquery.com/Plugins/Treeview
+ *
+ * Copyright (c) 2007 Jörn Zaefferer
+ *
+ * Dual licensed under the MIT and GPL licenses:
+ * http://www.opensource.org/licenses/mit-license.php
+ * http://www.gnu.org/licenses/gpl.html
+ *
+ * Revision: $Id: jquery.treeview.js 5759 2008-07-01 07:50:28Z joern.zaefferer $
+ *
+ */
+
+;(function($) {
+
+ // TODO rewrite as a widget, removing all the extra plugins
+ $.extend($.fn, {
+ swapClass: function(c1, c2) {
+ var c1Elements = this.filter('.' + c1);
+ this.filter('.' + c2).removeClass(c2).addClass(c1);
+ c1Elements.removeClass(c1).addClass(c2);
+ return this;
+ },
+ replaceClass: function(c1, c2) {
+ return this.filter('.' + c1).removeClass(c1).addClass(c2).end();
+ },
+ hoverClass: function(className) {
+ className = className || "hover";
+ return this.hover(function() {
+ $(this).addClass(className);
+ }, function() {
+ $(this).removeClass(className);
+ });
+ },
+ heightToggle: function(animated, callback) {
+ animated ?
+ this.animate({ height: "toggle" }, animated, callback) :
+ this.each(function(){
+ jQuery(this)[ jQuery(this).is(":hidden") ? "show" : "hide" ]();
+ if(callback)
+ callback.apply(this, arguments);
+ });
+ },
+ heightHide: function(animated, callback) {
+ if (animated) {
+ this.animate({ height: "hide" }, animated, callback);
+ } else {
+ this.hide();
+ if (callback)
+ this.each(callback);
+ }
+ },
+ prepareBranches: function(settings) {
+ if (!settings.prerendered) {
+ // mark last tree items
+ this.filter(":last-child:not(ul)").addClass(CLASSES.last);
+ // collapse whole tree, or only those marked as closed, anyway except those marked as open
+ this.filter((settings.collapsed ? "" : "." + CLASSES.closed) + ":not(." + CLASSES.open + ")").find(">ul").hide();
+ }
+ // return all items with sublists
+ return this.filter(":has(>ul)");
+ },
+ applyClasses: function(settings, toggler) {
+ // TODO use event delegation
+ this.filter(":has(>ul):not(:has(>a))").find(">span").unbind("click.treeview").bind("click.treeview", function(event) {
+ // don't handle click events on children, eg. checkboxes
+ if ( this == event.target )
+ toggler.apply($(this).next());
+ }).add( $("a", this) ).hoverClass();
+
+ if (!settings.prerendered) {
+ // handle closed ones first
+ this.filter(":has(>ul:hidden)")
+ .addClass(CLASSES.expandable)
+ .replaceClass(CLASSES.last, CLASSES.lastExpandable);
+
+ // handle open ones
+ this.not(":has(>ul:hidden)")
+ .addClass(CLASSES.collapsable)
+ .replaceClass(CLASSES.last, CLASSES.lastCollapsable);
+
+ // create hitarea if not present
+ var hitarea = this.find("div." + CLASSES.hitarea);
+ if (!hitarea.length)
+ hitarea = this.prepend("<div class=\"" + CLASSES.hitarea + "\"/>").find("div." + CLASSES.hitarea);
+ hitarea.removeClass().addClass(CLASSES.hitarea).each(function() {
+ var classes = "";
+ $.each($(this).parent().attr("class").split(" "), function() {
+ classes += this + "-hitarea ";
+ });
+ $(this).addClass( classes );
+ })
+ }
+
+ // apply event to hitarea
+ this.find("div." + CLASSES.hitarea).click( toggler );
+ },
+ treeview: function(settings) {
+
+ settings = $.extend({
+ cookieId: "treeview"
+ }, settings);
+
+ if ( settings.toggle ) {
+ var callback = settings.toggle;
+ settings.toggle = function() {
+ return callback.apply($(this).parent()[0], arguments);
+ };
+ }
+
+ // factory for treecontroller
+ function treeController(tree, control) {
+ // factory for click handlers
+ function handler(filter) {
+ return function() {
+ // reuse toggle event handler, applying the elements to toggle
+ // start searching for all hitareas
+ toggler.apply( $("div." + CLASSES.hitarea, tree).filter(function() {
+ // for plain toggle, no filter is provided, otherwise we need to check the parent element
+ return filter ? $(this).parent("." + filter).length : true;
+ }) );
+ return false;
+ };
+ }
+ // click on first element to collapse tree
+ $("a:eq(0)", control).click( handler(CLASSES.collapsable) );
+ // click on second to expand tree
+ $("a:eq(1)", control).click( handler(CLASSES.expandable) );
+ // click on third to toggle tree
+ $("a:eq(2)", control).click( handler() );
+ }
+
+ // handle toggle event
+ function toggler() {
+ $(this)
+ .parent()
+ // swap classes for hitarea
+ .find(">.hitarea")
+ .swapClass( CLASSES.collapsableHitarea, CLASSES.expandableHitarea )
+ .swapClass( CLASSES.lastCollapsableHitarea, CLASSES.lastExpandableHitarea )
+ .end()
+ // swap classes for parent li
+ .swapClass( CLASSES.collapsable, CLASSES.expandable )
+ .swapClass( CLASSES.lastCollapsable, CLASSES.lastExpandable )
+ // find child lists
+ .find( ">ul" )
+ // toggle them
+ .heightToggle( settings.animated, settings.toggle );
+ if ( settings.unique ) {
+ $(this).parent()
+ .siblings()
+ // swap classes for hitarea
+ .find(">.hitarea")
+ .replaceClass( CLASSES.collapsableHitarea, CLASSES.expandableHitarea )
+ .replaceClass( CLASSES.lastCollapsableHitarea, CLASSES.lastExpandableHitarea )
+ .end()
+ .replaceClass( CLASSES.collapsable, CLASSES.expandable )
+ .replaceClass( CLASSES.lastCollapsable, CLASSES.lastExpandable )
+ .find( ">ul" )
+ .heightHide( settings.animated, settings.toggle );
+ }
+ }
+ this.data("toggler", toggler);
+
+ function serialize() {
+ function binary(arg) {
+ return arg ? 1 : 0;
+ }
+ var data = [];
+ branches.each(function(i, e) {
+ data[i] = $(e).is(":has(>ul:visible)") ? 1 : 0;
+ });
+ $.cookie(settings.cookieId, data.join(""), settings.cookieOptions );
+ }
+
+ function deserialize() {
+ var stored = $.cookie(settings.cookieId);
+ if ( stored ) {
+ var data = stored.split("");
+ branches.each(function(i, e) {
+ $(e).find(">ul")[ parseInt(data[i]) ? "show" : "hide" ]();
+ });
+ }
+ }
+
+ // add treeview class to activate styles
+ this.addClass("treeview");
+
+ // prepare branches and find all tree items with child lists
+ var branches = this.find("li").prepareBranches(settings);
+
+ switch(settings.persist) {
+ case "cookie":
+ var toggleCallback = settings.toggle;
+ settings.toggle = function() {
+ serialize();
+ if (toggleCallback) {
+ toggleCallback.apply(this, arguments);
+ }
+ };
+ deserialize();
+ break;
+ case "location":
+ var current = this.find("a").filter(function() {
+ return this.href.toLowerCase() == location.href.toLowerCase();
+ });
+ if ( current.length ) {
+ // TODO update the open/closed classes
+ var items = current.addClass("selected").parents("ul, li").add( current.next() ).show();
+ if (settings.prerendered) {
+ // if prerendered is on, replicate the basic class swapping
+ items.filter("li")
+ .swapClass( CLASSES.collapsable, CLASSES.expandable )
+ .swapClass( CLASSES.lastCollapsable, CLASSES.lastExpandable )
+ .find(">.hitarea")
+ .swapClass( CLASSES.collapsableHitarea, CLASSES.expandableHitarea )
+ .swapClass( CLASSES.lastCollapsableHitarea, CLASSES.lastExpandableHitarea );
+ }
+ }
+ break;
+ }
+
+ branches.applyClasses(settings, toggler);
+
+ // if control option is set, create the treecontroller and show it
+ if ( settings.control ) {
+ treeController(this, settings.control);
+ $(settings.control).show();
+ }
+
+ return this;
+ }
+ });
+
+ // classes used by the plugin
+ // need to be styled via external stylesheet, see first example
+ $.treeview = {};
+ var CLASSES = ($.treeview.classes = {
+ open: "open",
+ closed: "closed",
+ expandable: "expandable",
+ expandableHitarea: "expandable-hitarea",
+ lastExpandableHitarea: "lastExpandable-hitarea",
+ collapsable: "collapsable",
+ collapsableHitarea: "collapsable-hitarea",
+ lastCollapsableHitarea: "lastCollapsable-hitarea",
+ lastCollapsable: "lastCollapsable",
+ lastExpandable: "lastExpandable",
+ last: "last",
+ hitarea: "hitarea"
+ });
+
+})(jQuery);
diff --git a/godoc/static/makestatic.go b/godoc/static/makestatic.go
new file mode 100644
index 0000000..f5e3272
--- /dev/null
+++ b/godoc/static/makestatic.go
@@ -0,0 +1,121 @@
+// 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 ignore
+
+// Command makestatic reads a set of files and writes a Go source file to "static.go"
+// that declares a map of string constants containing contents of the input files.
+// It is intended to be invoked via "go generate" (directive in "gen.go").
+package main
+
+import (
+ "bufio"
+ "bytes"
+ "fmt"
+ "io/ioutil"
+ "os"
+ "unicode/utf8"
+)
+
+var files = []string{
+ "analysis/call3.png",
+ "analysis/call-eg.png",
+ "analysis/callers1.png",
+ "analysis/callers2.png",
+ "analysis/chan1.png",
+ "analysis/chan2a.png",
+ "analysis/chan2b.png",
+ "analysis/error1.png",
+ "analysis/help.html",
+ "analysis/ident-def.png",
+ "analysis/ident-field.png",
+ "analysis/ident-func.png",
+ "analysis/ipcg-func.png",
+ "analysis/ipcg-pkg.png",
+ "analysis/typeinfo-pkg.png",
+ "analysis/typeinfo-src.png",
+ "callgraph.html",
+ "codewalk.html",
+ "codewalkdir.html",
+ "dirlist.html",
+ "error.html",
+ "example.html",
+ "godoc.html",
+ "godocs.js",
+ "images/minus.gif",
+ "images/plus.gif",
+ "images/treeview-black-line.gif",
+ "images/treeview-black.gif",
+ "images/treeview-default-line.gif",
+ "images/treeview-default.gif",
+ "images/treeview-gray-line.gif",
+ "images/treeview-gray.gif",
+ "implements.html",
+ "jquery.js",
+ "jquery.treeview.css",
+ "jquery.treeview.edit.js",
+ "jquery.treeview.js",
+ "methodset.html",
+ "opensearch.xml",
+ "package.html",
+ "package.txt",
+ "play.js",
+ "playground.js",
+ "search.html",
+ "search.txt",
+ "searchcode.html",
+ "searchdoc.html",
+ "searchtxt.html",
+ "style.css",
+}
+
+func main() {
+ if err := makestatic(); err != nil {
+ fmt.Fprintln(os.Stderr, err)
+ os.Exit(1)
+ }
+}
+
+func makestatic() error {
+ f, err := os.Create("static.go")
+ if err != nil {
+ return err
+ }
+ defer f.Close()
+ w := bufio.NewWriter(f)
+ fmt.Fprintf(w, "%v\n\npackage static\n\n", warning)
+ fmt.Fprintf(w, "var Files = map[string]string{\n")
+ for _, fn := range files {
+ b, err := ioutil.ReadFile(fn)
+ if err != nil {
+ return err
+ }
+ fmt.Fprintf(w, "\t%q: ", fn)
+ if utf8.Valid(b) {
+ fmt.Fprintf(w, "`%s`", sanitize(b))
+ } else {
+ fmt.Fprintf(w, "%q", b)
+ }
+ fmt.Fprintln(w, ",\n")
+ }
+ fmt.Fprintln(w, "}")
+ if err := w.Flush(); err != nil {
+ return err
+ }
+ return f.Close()
+}
+
+// sanitize prepares a valid UTF-8 string as a raw string constant.
+func sanitize(b []byte) []byte {
+ // Replace ` with `+"`"+`
+ b = bytes.Replace(b, []byte("`"), []byte("`+\"`\"+`"), -1)
+
+ // Replace BOM with `+"\xEF\xBB\xBF"+`
+ // (A BOM is valid UTF-8 but not permitted in Go source files.
+ // I wouldn't bother handling this, but for some insane reason
+ // jquery.js has a BOM somewhere in the middle.)
+ return bytes.Replace(b, []byte("\xEF\xBB\xBF"), []byte("`+\"\\xEF\\xBB\\xBF\"+`"), -1)
+}
+
+const warning = "// DO NOT EDIT ** This file was generated by \"go generate\" ** DO NOT EDIT //"
diff --git a/godoc/static/methodset.html b/godoc/static/methodset.html
new file mode 100644
index 0000000..1b339e3
--- /dev/null
+++ b/godoc/static/methodset.html
@@ -0,0 +1,9 @@
+<div class="toggle" style="display: none">
+ <div class="collapsed">
+ <p class="exampleHeading toggleButton">▹ <span class="text">Method set</span></p>
+ </div>
+ <div class="expanded">
+ <p class="exampleHeading toggleButton">▾ <span class="text">Method set</span></p>
+ <div style="margin-left: 1in" id='methodset-{{.Index}}'>...</div>
+ </div>
+</div>
diff --git a/godoc/static/opensearch.xml b/godoc/static/opensearch.xml
new file mode 100644
index 0000000..1b652db
--- /dev/null
+++ b/godoc/static/opensearch.xml
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<OpenSearchDescription xmlns="http://a9.com/-/spec/opensearch/1.1/">
+ <ShortName>godoc</ShortName>
+ <Description>The Go Programming Language</Description>
+ <Tags>go golang</Tags>
+ <Contact />
+ <Url type="text/html" template="{{.BaseURL}}/search?q={searchTerms}" />
+ <Image height="15" width="16" type="image/x-icon">/favicon.ico</Image>
+ <OutputEncoding>UTF-8</OutputEncoding>
+ <InputEncoding>UTF-8</InputEncoding>
+</OpenSearchDescription>
diff --git a/godoc/static/package.html b/godoc/static/package.html
new file mode 100644
index 0000000..964ed91
--- /dev/null
+++ b/godoc/static/package.html
@@ -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.
+-->
+<!--
+ Note: Static (i.e., not template-generated) href and id
+ attributes start with "pkg-" to make it impossible for
+ them to conflict with generated attributes (some of which
+ correspond to Go identifiers).
+-->
+{{with .PDoc}}
+ <script type='text/javascript'>
+ document.ANALYSIS_DATA = {{$.AnalysisData}};
+ document.CALLGRAPH = {{$.CallGraph}};
+ </script>
+
+ {{if $.IsMain}}
+ {{/* command documentation */}}
+ {{comment_html .Doc}}
+ {{else}}
+ {{/* package documentation */}}
+ <div id="short-nav">
+ <dl>
+ <dd><code>import "{{html .ImportPath}}"</code></dd>
+ </dl>
+ <dl>
+ <dd><a href="#pkg-overview" class="overviewLink">Overview</a></dd>
+ <dd><a href="#pkg-index" class="indexLink">Index</a></dd>
+ {{if $.Examples}}
+ <dd><a href="#pkg-examples" class="examplesLink">Examples</a></dd>
+ {{end}}
+ {{if $.Dirs}}
+ <dd><a href="#pkg-subdirectories">Subdirectories</a></dd>
+ {{end}}
+ </dl>
+ </div>
+ <!-- The package's Name is printed as title by the top-level template -->
+ <div id="pkg-overview" class="toggleVisible">
+ <div class="collapsed">
+ <h2 class="toggleButton" title="Click to show Overview section">Overview ▹</h2>
+ </div>
+ <div class="expanded">
+ <h2 class="toggleButton" title="Click to hide Overview section">Overview ▾</h2>
+ {{comment_html .Doc}}
+ </div>
+ </div>
+ {{example_html $ ""}}
+
+ <div id="pkg-index" class="toggleVisible">
+ <div class="collapsed">
+ <h2 class="toggleButton" title="Click to show Index section">Index ▹</h2>
+ </div>
+ <div class="expanded">
+ <h2 class="toggleButton" title="Click to hide Index section">Index ▾</h2>
+
+ <!-- Table of contents for API; must be named manual-nav to turn off auto nav. -->
+ <div id="manual-nav">
+ <dl>
+ {{if .Consts}}
+ <dd><a href="#pkg-constants">Constants</a></dd>
+ {{end}}
+ {{if .Vars}}
+ <dd><a href="#pkg-variables">Variables</a></dd>
+ {{end}}
+ {{range .Funcs}}
+ {{$name_html := html .Name}}
+ <dd><a href="#{{$name_html}}">{{node_html $ .Decl false | sanitize}}</a></dd>
+ {{end}}
+ {{range .Types}}
+ {{$tname_html := html .Name}}
+ <dd><a href="#{{$tname_html}}">type {{$tname_html}}</a></dd>
+ {{range .Funcs}}
+ {{$name_html := html .Name}}
+ <dd> <a href="#{{$name_html}}">{{node_html $ .Decl false | sanitize}}</a></dd>
+ {{end}}
+ {{range .Methods}}
+ {{$name_html := html .Name}}
+ <dd> <a href="#{{$tname_html}}.{{$name_html}}">{{node_html $ .Decl false | sanitize}}</a></dd>
+ {{end}}
+ {{end}}
+ {{if $.Notes}}
+ {{range $marker, $item := $.Notes}}
+ <dd><a href="#pkg-note-{{$marker}}">{{noteTitle $marker | html}}s</a></dd>
+ {{end}}
+ {{end}}
+ </dl>
+ </div><!-- #manual-nav -->
+
+ {{if $.Examples}}
+ <div id="pkg-examples">
+ <h4>Examples</h4>
+ <dl>
+ {{range $.Examples}}
+ <dd><a class="exampleLink" href="#example_{{.Name}}">{{example_name .Name}}</a></dd>
+ {{end}}
+ </dl>
+ </div>
+ {{end}}
+
+ {{with .Filenames}}
+ <h4>Package files</h4>
+ <p>
+ <span style="font-size:90%">
+ {{range .}}
+ <a href="{{.|srcLink|html}}">{{.|filename|html}}</a>
+ {{end}}
+ </span>
+ </p>
+ {{end}}
+ </div><!-- .expanded -->
+ </div><!-- #pkg-index -->
+
+ <div id="pkg-callgraph" class="toggle" style="display: none">
+ <div class="collapsed">
+ <h2 class="toggleButton" title="Click to show Internal Call Graph section">Internal call graph ▹</h2>
+ </div> <!-- .expanded -->
+ <div class="expanded">
+ <h2 class="toggleButton" title="Click to hide Internal Call Graph section">Internal call graph ▾</h2>
+ <p>
+ In the call graph viewer below, each node
+ is a function belonging to this package
+ and its children are the functions it
+ calls—perhaps dynamically.
+ </p>
+ <p>
+ The root nodes are the entry points of the
+ package: functions that may be called from
+ outside the package.
+ There may be non-exported or anonymous
+ functions among them if they are called
+ dynamically from another package.
+ </p>
+ <p>
+ Click a node to visit that function's source code.
+ From there you can visit its callers by
+ clicking its declaring <code>func</code>
+ token.
+ </p>
+ <p>
+ Functions may be omitted if they were
+ determined to be unreachable in the
+ particular programs or tests that were
+ analyzed.
+ </p>
+ <!-- Zero means show all package entry points. -->
+ <ul style="margin-left: 0.5in" id="callgraph-0" class="treeview"></ul>
+ </div>
+ </div> <!-- #pkg-callgraph -->
+
+ {{with .Consts}}
+ <h2 id="pkg-constants">Constants</h2>
+ {{range .}}
+ <pre>{{node_html $ .Decl true}}</pre>
+ {{comment_html .Doc}}
+ {{end}}
+ {{end}}
+ {{with .Vars}}
+ <h2 id="pkg-variables">Variables</h2>
+ {{range .}}
+ <pre>{{node_html $ .Decl true}}</pre>
+ {{comment_html .Doc}}
+ {{end}}
+ {{end}}
+ {{range .Funcs}}
+ {{/* Name is a string - no need for FSet */}}
+ {{$name_html := html .Name}}
+ <h2 id="{{$name_html}}">func <a href="{{posLink_url $ .Decl}}">{{$name_html}}</a></h2>
+ <pre>{{node_html $ .Decl true}}</pre>
+ {{comment_html .Doc}}
+ {{example_html $ .Name}}
+ {{callgraph_html $ "" .Name}}
+
+ {{end}}
+ {{range .Types}}
+ {{$tname := .Name}}
+ {{$tname_html := html .Name}}
+ <h2 id="{{$tname_html}}">type <a href="{{posLink_url $ .Decl}}">{{$tname_html}}</a></h2>
+ <pre>{{node_html $ .Decl true}}</pre>
+ {{comment_html .Doc}}
+
+ {{range .Consts}}
+ <pre>{{node_html $ .Decl true}}</pre>
+ {{comment_html .Doc}}
+ {{end}}
+
+ {{range .Vars}}
+ <pre>{{node_html $ .Decl true}}</pre>
+ {{comment_html .Doc}}
+ {{end}}
+
+ {{example_html $ $tname}}
+ {{implements_html $ $tname}}
+ {{methodset_html $ $tname}}
+
+ {{range .Funcs}}
+ {{$name_html := html .Name}}
+ <h3 id="{{$name_html}}">func <a href="{{posLink_url $ .Decl}}">{{$name_html}}</a></h3>
+ <pre>{{node_html $ .Decl true}}</pre>
+ {{comment_html .Doc}}
+ {{example_html $ .Name}}
+ {{callgraph_html $ "" .Name}}
+ {{end}}
+
+ {{range .Methods}}
+ {{$name_html := html .Name}}
+ <h3 id="{{$tname_html}}.{{$name_html}}">func ({{html .Recv}}) <a href="{{posLink_url $ .Decl}}">{{$name_html}}</a></h3>
+ <pre>{{node_html $ .Decl true}}</pre>
+ {{comment_html .Doc}}
+ {{$name := printf "%s_%s" $tname .Name}}
+ {{example_html $ $name}}
+ {{callgraph_html $ .Recv .Name}}
+ {{end}}
+ {{end}}
+ {{end}}
+
+ {{with $.Notes}}
+ {{range $marker, $content := .}}
+ <h2 id="pkg-note-{{$marker}}">{{noteTitle $marker | html}}s</h2>
+ <ul style="list-style: none; padding: 0;">
+ {{range .}}
+ <li><a href="{{posLink_url $ .}}">☞</a> {{html .Body}}</li>
+ {{end}}
+ </ul>
+ {{end}}
+ {{end}}
+{{end}}
+
+{{with .PAst}}
+ {{range $filename, $ast := .}}
+ <a href="{{$filename|srcLink|html}}">{{$filename|filename|html}}</a>:<pre>{{node_html $ $ast false}}</pre>
+ {{end}}
+{{end}}
+
+{{with .Dirs}}
+ {{/* DirList entries are numbers and strings - no need for FSet */}}
+ {{if $.PDoc}}
+ <h2 id="pkg-subdirectories">Subdirectories</h2>
+ {{end}}
+ {{if eq $.Dirname "/src"}}
+ <div id="manual-nav">
+ <dl>
+ <dt><a href="#stdlib">Standard library</a></dt>
+ <dt><a href="#other">Other packages</a></dt>
+ <dd><a href="#subrepo">Sub-repositories</a></dd>
+ <dd><a href="#community">Community</a></dd>
+ </dl>
+ </div>
+ <h2 id="stdlib">Standard library</h2>
+ <img class="gopher" src="/doc/gopher/pkg.png"/>
+ {{end}}
+
+
+ <div class="pkg-dir">
+ <table>
+ <tr>
+ <th class="pkg-name">Name</th>
+ <th class="pkg-synopsis">Synopsis</th>
+ </tr>
+
+ {{if not (or (eq $.Dirname "/src") (eq $.Dirname "/src/cmd") $.DirFlat)}}
+ <tr>
+ <td colspan="2"><a href="..">..</a></td>
+ </tr>
+ {{end}}
+
+ {{range .List}}
+ {{if $.DirFlat}}
+ {{if .HasPkg}}
+ <tr>
+ <td class="pkg-name">
+ <a href="{{html .Path}}/">{{html .Path}}</a>
+ </td>
+ <td class="pkg-synopsis">
+ {{html .Synopsis}}
+ </td>
+ </tr>
+ {{end}}
+ {{else}}
+ <tr>
+ <td class="pkg-name" style="padding-left: {{multiply .Depth 20}}px;">
+ <a href="{{html .Path}}/">{{html .Name}}</a>
+ </td>
+ <td class="pkg-synopsis">
+ {{html .Synopsis}}
+ </td>
+ </tr>
+ {{end}}
+ {{end}}
+ </table>
+ </div>
+
+
+ {{if eq $.Dirname "/src"}}
+ <h2 id="other">Other packages</h2>
+
+ <h3 id="subrepo">Sub-repositories</h3>
+ <p>
+ These packages are part of the Go Project but outside the main Go tree.
+ They are developed under looser <a href="/doc/go1compat">compatibility requirements</a> than the Go core.
+ Install them with "<a href="/cmd/go/#hdr-Download_and_install_packages_and_dependencies">go get</a>".
+ </p>
+ <ul>
+ <li><a href="//godoc.org/golang.org/x/benchmarks">benchmarks</a> — benchmarks to measure Go as it is developed.</li>
+ <li><a href="//godoc.org/golang.org/x/blog">blog</a> — <a href="//blog.golang.org">blog.golang.org</a>'s implementation.</li>
+ <li><a href="//godoc.org/golang.org/x/build">build</a> — <a href="//build.golang.org">build.golang.org</a>'s implementation.</li>
+ <li><a href="//godoc.org/golang.org/x/crypto">crypto</a> — additional cryptography packages.</li>
+ <li><a href="//godoc.org/golang.org/x/debug">debug</a> — an experimental debugger for Go.</li>
+ <li><a href="//godoc.org/golang.org/x/image">image</a> — additional imaging packages.</li>
+ <li><a href="//godoc.org/golang.org/x/mobile">mobile</a> — experimental support for Go on mobile platforms.</li>
+ <li><a href="//godoc.org/golang.org/x/net">net</a> — additional networking packages.</li>
+ <li><a href="//godoc.org/golang.org/x/sys">sys</a> — packages for making system calls.</li>
+ <li><a href="//godoc.org/golang.org/x/text">text</a> — packages for working with text.</li>
+ <li><a href="//godoc.org/golang.org/x/tools">tools</a> — godoc, goimports, gorename, and other tools.</li>
+ <li><a href="//godoc.org/golang.org/x/tour">tour</a> — <a href="//tour.golang.org">tour.golang.org</a>'s implementation.</li>
+ <li><a href="//godoc.org/golang.org/x/exp">exp</a> — experimental and deprecated packages (handle with care; may change without warning).</li>
+ </ul>
+
+ <h3 id="community">Community</h3>
+ <p>
+ These services can help you find Open Source packages provided by the community.
+ </p>
+ <ul>
+ <li><a href="//godoc.org">GoDoc</a> - a package index and search engine.</li>
+ <li><a href="http://go-search.org">Go Search</a> - a code search engine.</li>
+ <li><a href="/wiki/Projects">Projects at the Go Wiki</a> - a curated list of Go projects.</li>
+ </ul>
+ {{end}}
+{{end}}
diff --git a/godoc/static/package.txt b/godoc/static/package.txt
new file mode 100644
index 0000000..e53fa6e
--- /dev/null
+++ b/godoc/static/package.txt
@@ -0,0 +1,116 @@
+{{$info := .}}{{$filtered := .IsFiltered}}{{/*
+
+---------------------------------------
+
+*/}}{{if $filtered}}{{range .PAst}}{{range .Decls}}{{node $info .}}
+
+{{end}}{{end}}{{else}}{{with .PAst}}{{range $filename, $ast := .}}{{$filename}}:
+{{node $ $ast}}{{end}}{{end}}{{end}}{{/*
+
+---------------------------------------
+
+*/}}{{if and $filtered (not (or .PDoc .PAst))}}No match found.
+{{end}}{{with .PDoc}}{{if $.IsMain}}COMMAND DOCUMENTATION
+
+{{comment_text .Doc " " "\t"}}
+{{else}}{{if not $filtered}}PACKAGE DOCUMENTATION
+
+package {{.Name}}
+ import "{{.ImportPath}}"
+
+{{comment_text .Doc " " "\t"}}
+{{example_text $ "" " "}}{{end}}{{/*
+
+---------------------------------------
+
+*/}}{{with .Consts}}{{if not $filtered}}CONSTANTS
+
+{{end}}{{range .}}{{node $ .Decl}}
+{{comment_text .Doc " " "\t"}}
+{{end}}{{end}}{{/*
+
+---------------------------------------
+
+*/}}{{with .Vars}}{{if not $filtered}}VARIABLES
+
+{{end}}{{range .}}{{node $ .Decl}}
+{{comment_text .Doc " " "\t"}}
+{{end}}{{end}}{{/*
+
+---------------------------------------
+
+*/}}{{with .Funcs}}{{if not $filtered}}FUNCTIONS
+
+{{end}}{{range .}}{{node $ .Decl}}
+{{comment_text .Doc " " "\t"}}
+{{example_text $ .Name " "}}{{end}}{{end}}{{/*
+
+---------------------------------------
+
+*/}}{{with .Types}}{{if not $filtered}}TYPES
+
+{{end}}{{range .}}{{$tname := .Name}}{{node $ .Decl}}
+{{comment_text .Doc " " "\t"}}
+{{/*
+
+---------------------------------------
+
+*/}}{{if .Consts}}{{range .Consts}}{{node $ .Decl}}
+{{comment_text .Doc " " "\t"}}
+{{end}}{{end}}{{/*
+
+---------------------------------------
+
+*/}}{{if .Vars}}{{range .Vars}}{{node $ .Decl}}
+{{comment_text .Doc " " "\t"}}
+{{range $name := .Names}}{{example_text $ $name " "}}{{end}}{{end}}{{end}}{{/*
+
+---------------------------------------
+
+*/}}{{if .Funcs}}{{range .Funcs}}{{node $ .Decl}}
+{{comment_text .Doc " " "\t"}}
+{{example_text $ .Name " "}}{{end}}{{end}}{{/*
+
+---------------------------------------
+
+*/}}{{if .Methods}}{{range .Methods}}{{node $ .Decl}}
+{{comment_text .Doc " " "\t"}}
+{{$name := printf "%s_%s" $tname .Name}}{{example_text $ $name " "}}{{end}}{{end}}{{/*
+
+---------------------------------------
+
+*/}}{{end}}{{end}}{{/*
+
+---------------------------------------
+
+*/}}{{if and $filtered (not (or .Consts (or .Vars (or .Funcs .Types))))}}No match found.
+{{end}}{{/*
+
+---------------------------------------
+
+*/}}{{end}}{{/*
+
+---------------------------------------
+
+*/}}{{with $.Notes}}
+{{range $marker, $content := .}}
+{{$marker}}S
+
+{{range $content}}{{comment_text .Body " " "\t"}}
+{{end}}{{end}}{{end}}{{end}}{{/*
+
+---------------------------------------
+
+*/}}{{if not $filtered}}{{with .Dirs}}SUBDIRECTORIES
+{{if $.DirFlat}}{{range .List}}{{if .HasPkg}}
+ {{.Path}}{{end}}{{end}}
+{{else}}{{range .List}}
+ {{repeat `. ` .Depth}}{{.Name}}{{end}}
+{{end}}{{end}}{{/*
+
+---------------------------------------
+
+*/}}{{end}}{{/*
+Make sure there is no newline at the end of this file.
+perl -i -pe 'chomp if eof' package.txt
+*/}}
diff --git a/godoc/static/play.js b/godoc/static/play.js
new file mode 100644
index 0000000..7e87460
--- /dev/null
+++ b/godoc/static/play.js
@@ -0,0 +1,103 @@
+// 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.
+
+function initPlayground(transport) {
+ "use strict";
+
+ function text(node) {
+ var s = "";
+ for (var i = 0; i < node.childNodes.length; i++) {
+ var n = node.childNodes[i];
+ if (n.nodeType === 1) {
+ if (n.tagName === "BUTTON") continue
+ if (n.tagName === "SPAN" && n.className === "number") continue;
+ if (n.tagName === "DIV" || n.tagName == "BR") {
+ s += "\n";
+ }
+ s += text(n);
+ continue;
+ }
+ if (n.nodeType === 3) {
+ s += n.nodeValue;
+ }
+ }
+ return s.replace("\xA0", " "); // replace non-breaking spaces
+ }
+
+ function init(code) {
+ var output = document.createElement('div');
+ var outpre = document.createElement('pre');
+ var running;
+
+ if ($ && $(output).resizable) {
+ $(output).resizable({
+ handles: "n,w,nw",
+ minHeight: 27,
+ minWidth: 135,
+ maxHeight: 608,
+ maxWidth: 990
+ });
+ }
+
+ function onKill() {
+ if (running) running.Kill();
+ }
+
+ function onRun(e) {
+ onKill();
+ output.style.display = "block";
+ outpre.innerHTML = "";
+ run1.style.display = "none";
+ var options = {Race: e.shiftKey};
+ running = transport.Run(text(code), PlaygroundOutput(outpre), options);
+ }
+
+ function onClose() {
+ onKill();
+ output.style.display = "none";
+ run1.style.display = "inline-block";
+ }
+
+ var run1 = document.createElement('button');
+ run1.innerHTML = 'Run';
+ run1.className = 'run';
+ run1.addEventListener("click", onRun, false);
+ var run2 = document.createElement('button');
+ run2.className = 'run';
+ run2.innerHTML = 'Run';
+ run2.addEventListener("click", onRun, false);
+ var kill = document.createElement('button');
+ kill.className = 'kill';
+ kill.innerHTML = 'Kill';
+ kill.addEventListener("click", onKill, false);
+ var close = document.createElement('button');
+ close.className = 'close';
+ close.innerHTML = 'Close';
+ close.addEventListener("click", onClose, false);
+
+ var button = document.createElement('div');
+ button.classList.add('buttons');
+ button.appendChild(run1);
+ // Hack to simulate insertAfter
+ code.parentNode.insertBefore(button, code.nextSibling);
+
+ var buttons = document.createElement('div');
+ buttons.classList.add('buttons');
+ buttons.appendChild(run2);
+ buttons.appendChild(kill);
+ buttons.appendChild(close);
+
+ output.classList.add('output');
+ output.appendChild(buttons);
+ output.appendChild(outpre);
+ output.style.display = "none";
+ code.parentNode.insertBefore(output, button.nextSibling);
+ }
+
+ var play = document.querySelectorAll('div.playground');
+ for (var i = 0; i < play.length; i++) {
+ init(play[i]);
+ }
+}
+
diff --git a/godoc/static/playground.js b/godoc/static/playground.js
new file mode 100644
index 0000000..93dea15
--- /dev/null
+++ b/godoc/static/playground.js
@@ -0,0 +1,433 @@
+// 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.
+
+/*
+In the absence of any formal way to specify interfaces in JavaScript,
+here's a skeleton implementation of a playground transport.
+
+ function Transport() {
+ // Set up any transport state (eg, make a websocket connection).
+ return {
+ Run: function(body, output, options) {
+ // Compile and run the program 'body' with 'options'.
+ // Call the 'output' callback to display program output.
+ return {
+ Kill: function() {
+ // Kill the running program.
+ }
+ };
+ }
+ };
+ }
+
+ // The output callback is called multiple times, and each time it is
+ // passed an object of this form.
+ var write = {
+ Kind: 'string', // 'start', 'stdout', 'stderr', 'end'
+ Body: 'string' // content of write or end status message
+ }
+
+ // The first call must be of Kind 'start' with no body.
+ // Subsequent calls may be of Kind 'stdout' or 'stderr'
+ // and must have a non-null Body string.
+ // The final call should be of Kind 'end' with an optional
+ // Body string, signifying a failure ("killed", for example).
+
+ // The output callback must be of this form.
+ // See PlaygroundOutput (below) for an implementation.
+ function outputCallback(write) {
+ }
+*/
+
+function HTTPTransport() {
+ 'use strict';
+
+ // TODO(adg): support stderr
+
+ function playback(output, events) {
+ var timeout;
+ output({Kind: 'start'});
+ function next() {
+ if (!events || events.length === 0) {
+ output({Kind: 'end'});
+ return;
+ }
+ var e = events.shift();
+ if (e.Delay === 0) {
+ output({Kind: 'stdout', Body: e.Message});
+ next();
+ return;
+ }
+ timeout = setTimeout(function() {
+ output({Kind: 'stdout', Body: e.Message});
+ next();
+ }, e.Delay / 1000000);
+ }
+ next();
+ return {
+ Stop: function() {
+ clearTimeout(timeout);
+ }
+ }
+ }
+
+ function error(output, msg) {
+ output({Kind: 'start'});
+ output({Kind: 'stderr', Body: msg});
+ output({Kind: 'end'});
+ }
+
+ var seq = 0;
+ return {
+ Run: function(body, output, options) {
+ seq++;
+ var cur = seq;
+ var playing;
+ $.ajax('/compile', {
+ type: 'POST',
+ data: {'version': 2, 'body': body},
+ dataType: 'json',
+ success: function(data) {
+ if (seq != cur) return;
+ if (!data) return;
+ if (playing != null) playing.Stop();
+ if (data.Errors) {
+ error(output, data.Errors);
+ return;
+ }
+ playing = playback(output, data.Events);
+ },
+ error: function() {
+ error(output, 'Error communicating with remote server.');
+ }
+ });
+ return {
+ Kill: function() {
+ if (playing != null) playing.Stop();
+ output({Kind: 'end', Body: 'killed'});
+ }
+ };
+ }
+ };
+}
+
+function SocketTransport() {
+ 'use strict';
+
+ var id = 0;
+ var outputs = {};
+ var started = {};
+ var websocket = new WebSocket('ws://' + window.location.host + '/socket');
+
+ websocket.onclose = function() {
+ console.log('websocket connection closed');
+ }
+
+ websocket.onmessage = function(e) {
+ var m = JSON.parse(e.data);
+ var output = outputs[m.Id];
+ if (output === null)
+ return;
+ if (!started[m.Id]) {
+ output({Kind: 'start'});
+ started[m.Id] = true;
+ }
+ output({Kind: m.Kind, Body: m.Body});
+ }
+
+ function send(m) {
+ websocket.send(JSON.stringify(m));
+ }
+
+ return {
+ Run: function(body, output, options) {
+ var thisID = id+'';
+ id++;
+ outputs[thisID] = output;
+ send({Id: thisID, Kind: 'run', Body: body, Options: options});
+ return {
+ Kill: function() {
+ send({Id: thisID, Kind: 'kill'});
+ }
+ };
+ }
+ };
+}
+
+function PlaygroundOutput(el) {
+ 'use strict';
+
+ return function(write) {
+ if (write.Kind == 'start') {
+ el.innerHTML = '';
+ return;
+ }
+
+ var cl = 'system';
+ if (write.Kind == 'stdout' || write.Kind == 'stderr')
+ cl = write.Kind;
+
+ var m = write.Body;
+ if (write.Kind == 'end')
+ m = '\nProgram exited' + (m?(': '+m):'.');
+
+ if (m.indexOf('IMAGE:') === 0) {
+ // TODO(adg): buffer all writes before creating image
+ var url = 'data:image/png;base64,' + m.substr(6);
+ var img = document.createElement('img');
+ img.src = url;
+ el.appendChild(img);
+ return;
+ }
+
+ // ^L clears the screen.
+ var s = m.split('\x0c');
+ if (s.length > 1) {
+ el.innerHTML = '';
+ m = s.pop();
+ }
+
+ m = m.replace(/&/g, '&');
+ m = m.replace(/</g, '<');
+ m = m.replace(/>/g, '>');
+
+ var needScroll = (el.scrollTop + el.offsetHeight) == el.scrollHeight;
+
+ var span = document.createElement('span');
+ span.className = cl;
+ span.innerHTML = m;
+ el.appendChild(span);
+
+ if (needScroll)
+ el.scrollTop = el.scrollHeight - el.offsetHeight;
+ }
+}
+
+(function() {
+ function lineHighlight(error) {
+ var regex = /prog.go:([0-9]+)/g;
+ var r = regex.exec(error);
+ while (r) {
+ $(".lines div").eq(r[1]-1).addClass("lineerror");
+ r = regex.exec(error);
+ }
+ }
+ function highlightOutput(wrappedOutput) {
+ return function(write) {
+ if (write.Body) lineHighlight(write.Body);
+ wrappedOutput(write);
+ }
+ }
+ function lineClear() {
+ $(".lineerror").removeClass("lineerror");
+ }
+
+ // opts is an object with these keys
+ // codeEl - code editor element
+ // outputEl - program output element
+ // runEl - run button element
+ // fmtEl - fmt button element (optional)
+ // fmtImportEl - fmt "imports" checkbox element (optional)
+ // shareEl - share button element (optional)
+ // shareURLEl - share URL text input element (optional)
+ // shareRedirect - base URL to redirect to on share (optional)
+ // toysEl - toys select element (optional)
+ // enableHistory - enable using HTML5 history API (optional)
+ // transport - playground transport to use (default is HTTPTransport)
+ function playground(opts) {
+ var code = $(opts.codeEl);
+ var transport = opts['transport'] || new HTTPTransport();
+ var running;
+
+ // autoindent helpers.
+ function insertTabs(n) {
+ // find the selection start and end
+ var start = code[0].selectionStart;
+ var end = code[0].selectionEnd;
+ // split the textarea content into two, and insert n tabs
+ var v = code[0].value;
+ var u = v.substr(0, start);
+ for (var i=0; i<n; i++) {
+ u += "\t";
+ }
+ u += v.substr(end);
+ // set revised content
+ code[0].value = u;
+ // reset caret position after inserted tabs
+ code[0].selectionStart = start+n;
+ code[0].selectionEnd = start+n;
+ }
+ function autoindent(el) {
+ var curpos = el.selectionStart;
+ var tabs = 0;
+ while (curpos > 0) {
+ curpos--;
+ if (el.value[curpos] == "\t") {
+ tabs++;
+ } else if (tabs > 0 || el.value[curpos] == "\n") {
+ break;
+ }
+ }
+ setTimeout(function() {
+ insertTabs(tabs);
+ }, 1);
+ }
+
+ function keyHandler(e) {
+ if (e.keyCode == 9 && !e.ctrlKey) { // tab (but not ctrl-tab)
+ insertTabs(1);
+ e.preventDefault();
+ return false;
+ }
+ if (e.keyCode == 13) { // enter
+ if (e.shiftKey) { // +shift
+ run();
+ e.preventDefault();
+ return false;
+ } if (e.ctrlKey) { // +control
+ fmt();
+ e.preventDefault();
+ } else {
+ autoindent(e.target);
+ }
+ }
+ return true;
+ }
+ code.unbind('keydown').bind('keydown', keyHandler);
+ var outdiv = $(opts.outputEl).empty();
+ var output = $('<pre/>').appendTo(outdiv);
+
+ function body() {
+ return $(opts.codeEl).val();
+ }
+ function setBody(text) {
+ $(opts.codeEl).val(text);
+ }
+ function origin(href) {
+ return (""+href).split("/").slice(0, 3).join("/");
+ }
+
+ var pushedEmpty = (window.location.pathname == "/");
+ function inputChanged() {
+ if (pushedEmpty) {
+ return;
+ }
+ pushedEmpty = true;
+ $(opts.shareURLEl).hide();
+ window.history.pushState(null, "", "/");
+ }
+ function popState(e) {
+ if (e === null) {
+ return;
+ }
+ if (e && e.state && e.state.code) {
+ setBody(e.state.code);
+ }
+ }
+ var rewriteHistory = false;
+ if (window.history && window.history.pushState && window.addEventListener && opts.enableHistory) {
+ rewriteHistory = true;
+ code[0].addEventListener('input', inputChanged);
+ window.addEventListener('popstate', popState);
+ }
+
+ function setError(error) {
+ if (running) running.Kill();
+ lineClear();
+ lineHighlight(error);
+ output.empty().addClass("error").text(error);
+ }
+ function loading() {
+ lineClear();
+ if (running) running.Kill();
+ output.removeClass("error").text('Waiting for remote server...');
+ }
+ function run() {
+ loading();
+ running = transport.Run(body(), highlightOutput(PlaygroundOutput(output[0])));
+ }
+
+ function fmt() {
+ loading();
+ var data = {"body": body()};
+ if ($(opts.fmtImportEl).is(":checked")) {
+ data["imports"] = "true";
+ }
+ $.ajax("/fmt", {
+ data: data,
+ type: "POST",
+ dataType: "json",
+ success: function(data) {
+ if (data.Error) {
+ setError(data.Error);
+ } else {
+ setBody(data.Body);
+ setError("");
+ }
+ }
+ });
+ }
+
+ $(opts.runEl).click(run);
+ $(opts.fmtEl).click(fmt);
+
+ if (opts.shareEl !== null && (opts.shareURLEl !== null || opts.shareRedirect !== null)) {
+ var shareURL;
+ if (opts.shareURLEl) {
+ shareURL = $(opts.shareURLEl).hide();
+ }
+ var sharing = false;
+ $(opts.shareEl).click(function() {
+ if (sharing) return;
+ sharing = true;
+ var sharingData = body();
+ $.ajax("/share", {
+ processData: false,
+ data: sharingData,
+ type: "POST",
+ complete: function(xhr) {
+ sharing = false;
+ if (xhr.status != 200) {
+ alert("Server error; try again.");
+ return;
+ }
+ if (opts.shareRedirect) {
+ window.location = opts.shareRedirect + xhr.responseText;
+ }
+ if (shareURL) {
+ var path = "/p/" + xhr.responseText;
+ var url = origin(window.location) + path;
+ shareURL.show().val(url).focus().select();
+
+ if (rewriteHistory) {
+ var historyData = {"code": sharingData};
+ window.history.pushState(historyData, "", path);
+ pushedEmpty = false;
+ }
+ }
+ }
+ });
+ });
+ }
+
+ if (opts.toysEl !== null) {
+ $(opts.toysEl).bind('change', function() {
+ var toy = $(this).val();
+ $.ajax("/doc/play/"+toy, {
+ processData: false,
+ type: "GET",
+ complete: function(xhr) {
+ if (xhr.status != 200) {
+ alert("Server error; try again.");
+ return;
+ }
+ setBody(xhr.responseText);
+ }
+ });
+ });
+ }
+ }
+
+ window.playground = playground;
+})();
diff --git a/godoc/static/search.html b/godoc/static/search.html
new file mode 100644
index 0000000..e0d13b9
--- /dev/null
+++ b/godoc/static/search.html
@@ -0,0 +1,18 @@
+<!--
+ 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.
+-->
+{{with .Alert}}
+ <p>
+ <span class="alert" style="font-size:120%">{{html .}}</span>
+ </p>
+{{end}}
+{{with .Alt}}
+ <p>
+ <span class="alert" style="font-size:120%">Did you mean: </span>
+ {{range .Alts}}
+ <a href="search?q={{urlquery .}}" style="font-size:120%">{{html .}}</a>
+ {{end}}
+ </p>
+{{end}}
diff --git a/godoc/static/search.txt b/godoc/static/search.txt
new file mode 100644
index 0000000..0ae0c08
--- /dev/null
+++ b/godoc/static/search.txt
@@ -0,0 +1,54 @@
+QUERY
+ {{.Query}}
+
+{{with .Alert}}{{.}}
+{{end}}{{/* .Alert */}}{{/*
+
+---------------------------------------
+
+*/}}{{with .Alt}}DID YOU MEAN
+
+{{range .Alts}} {{.}}
+{{end}}
+{{end}}{{/* .Alt */}}{{/*
+
+---------------------------------------
+
+*/}}{{with .Pak}}PACKAGE {{$.Query}}
+
+{{range .}} {{pkgLink .Pak.Path}}
+{{end}}
+{{end}}{{/* .Pak */}}{{/*
+
+---------------------------------------
+
+*/}}{{range $key, $val := .Idents}}{{if $val}}{{$key.Name}}
+{{range $val}} {{.Path}}.{{.Name}}
+{{end}}
+{{end}}{{end}}{{/* .Idents */}}{{/*
+
+---------------------------------------
+
+*/}}{{with .Hit}}{{with .Decls}}PACKAGE-LEVEL DECLARATIONS
+
+{{range .}}package {{.Pak.Name}}
+{{range $file := .Files}}{{range .Groups}}{{range .}} {{srcLink $file.File.Path}}:{{infoLine .}}{{end}}
+{{end}}{{end}}{{/* .Files */}}
+{{end}}{{end}}{{/* .Decls */}}{{/*
+
+---------------------------------------
+
+*/}}{{with .Others}}LOCAL DECLARATIONS AND USES
+
+{{range .}}package {{.Pak.Name}}
+{{range $file := .Files}}{{range .Groups}}{{range .}} {{srcLink $file.File.Path}}:{{infoLine .}}
+{{end}}{{end}}{{end}}{{/* .Files */}}
+{{end}}{{end}}{{/* .Others */}}{{end}}{{/* .Hit */}}{{/*
+
+---------------------------------------
+
+*/}}{{if .Textual}}{{if .Complete}}{{.Found}} TEXTUAL OCCURRENCES{{else}}MORE THAN {{.Found}} TEXTUAL OCCURRENCES{{end}}
+
+{{range .Textual}}{{len .Lines}} {{srcLink .Filename}}
+{{end}}{{if not .Complete}}... ...
+{{end}}{{end}}
diff --git a/godoc/static/searchcode.html b/godoc/static/searchcode.html
new file mode 100644
index 0000000..a032e64
--- /dev/null
+++ b/godoc/static/searchcode.html
@@ -0,0 +1,64 @@
+<!--
+ 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.
+-->
+{{$query_url := urlquery .Query}}
+{{if not .Idents}}
+ {{with .Pak}}
+ <h2 id="Packages">Package {{html $.Query}}</h2>
+ <p>
+ <table class="layout">
+ {{range .}}
+ {{$pkg_html := pkgLink .Pak.Path | html}}
+ <tr><td><a href="/{{$pkg_html}}">{{$pkg_html}}</a></td></tr>
+ {{end}}
+ </table>
+ </p>
+ {{end}}
+{{end}}
+{{with .Hit}}
+ {{with .Decls}}
+ <h2 id="Global">Package-level declarations</h2>
+ {{range .}}
+ {{$pkg_html := pkgLink .Pak.Path | html}}
+ <h3 id="Global_{{$pkg_html}}">package <a href="/{{$pkg_html}}">{{html .Pak.Name}}</a></h3>
+ {{range .Files}}
+ {{$file := .File.Path}}
+ {{range .Groups}}
+ {{range .}}
+ {{$line := infoLine .}}
+ <a href="{{queryLink $file $query_url $line | html}}">{{$file}}:{{$line}}</a>
+ {{infoSnippet_html .}}
+ {{end}}
+ {{end}}
+ {{end}}
+ {{end}}
+ {{end}}
+ {{with .Others}}
+ <h2 id="Local">Local declarations and uses</h2>
+ {{range .}}
+ {{$pkg_html := pkgLink .Pak.Path | html}}
+ <h3 id="Local_{{$pkg_html}}">package <a href="/{{$pkg_html}}">{{html .Pak.Name}}</a></h3>
+ {{range .Files}}
+ {{$file := .File.Path}}
+ <a href="{{queryLink $file $query_url 0 | html}}">{{$file}}</a>
+ <table class="layout">
+ {{range .Groups}}
+ <tr>
+ <td width="25"></td>
+ <th align="left" valign="top">{{index . 0 | infoKind_html}}</th>
+ <td align="left" width="4"></td>
+ <td>
+ {{range .}}
+ {{$line := infoLine .}}
+ <a href="{{queryLink $file $query_url $line | html}}">{{$line}}</a>
+ {{end}}
+ </td>
+ </tr>
+ {{end}}
+ </table>
+ {{end}}
+ {{end}}
+ {{end}}
+{{end}}
diff --git a/godoc/static/searchdoc.html b/godoc/static/searchdoc.html
new file mode 100644
index 0000000..679c02c
--- /dev/null
+++ b/godoc/static/searchdoc.html
@@ -0,0 +1,24 @@
+<!--
+ 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.
+-->
+{{range $key, $val := .Idents}}
+ {{if $val}}
+ <h2 id="{{$key.Name}}">{{$key.Name}}</h2>
+ {{range $val}}
+ {{$pkg_html := pkgLink .Path | html}}
+ {{if eq "Packages" $key.Name}}
+ <a href="/{{$pkg_html}}">{{html .Path}}</a>
+ {{else}}
+ {{$doc_html := docLink .Path .Name| html}}
+ <a href="/{{$pkg_html}}">{{html .Package}}</a>.<a href="{{$doc_html}}">{{.Name}}</a>
+ {{end}}
+ {{if .Doc}}
+ <p>{{comment_html .Doc}}</p>
+ {{else}}
+ <p><em>No documentation available</em></p>
+ {{end}}
+ {{end}}
+ {{end}}
+{{end}}
diff --git a/godoc/static/searchtxt.html b/godoc/static/searchtxt.html
new file mode 100644
index 0000000..7e4a978
--- /dev/null
+++ b/godoc/static/searchtxt.html
@@ -0,0 +1,42 @@
+<!--
+ 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.
+-->
+{{$query_url := urlquery .Query}}
+{{with .Textual}}
+ {{if $.Complete}}
+ <h2 id="Textual">{{html $.Found}} textual occurrences</h2>
+ {{else}}
+ <h2 id="Textual">More than {{html $.Found}} textual occurrences</h2>
+ <p>
+ <span class="alert" style="font-size:120%">Not all files or lines containing "{{html $.Query}}" are shown.</span>
+ </p>
+ {{end}}
+ <p>
+ <table class="layout">
+ {{range .}}
+ {{$file := .Filename}}
+ <tr>
+ <td align="left" valign="top">
+ <a href="{{queryLink $file $query_url 0}}">{{$file}}</a>:
+ </td>
+ <td align="left" width="4"></td>
+ <th align="left" valign="top">{{len .Lines}}</th>
+ <td align="left" width="4"></td>
+ <td align="left">
+ {{range .Lines}}
+ <a href="{{queryLink $file $query_url .}}">{{html .}}</a>
+ {{end}}
+ {{if not $.Complete}}
+ ...
+ {{end}}
+ </td>
+ </tr>
+ {{end}}
+ {{if not $.Complete}}
+ <tr><td align="left">...</td></tr>
+ {{end}}
+ </table>
+ </p>
+{{end}}
diff --git a/godoc/static/static.go b/godoc/static/static.go
new file mode 100644
index 0000000..3009e24
--- /dev/null
+++ b/godoc/static/static.go
@@ -0,0 +1,3544 @@
+// DO NOT EDIT ** This file was generated by "go generate" ** DO NOT EDIT //
+
+package static
+
+var Files = map[string]string{
+ "analysis/call3.png": "\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x03N\x00\x00\x01\xea\b\x03\x00\x00\x00\x04l\xeeb\x00\x00\x00\x01sRGB\x00\xae\xce\x1c\xe9\x00\x00\x02\xfdPLTE\x00\x01\x00\x04\x06\x03\x06\t\x05\x0e\x10\r\x16\x17\x15$\x18\x0f\x1e\x1d\x17!# #$\"$%#&(%)(\"()'-+\x1f*+),-+-/,41&J-\x1202/241S/\x0e564,7M796<:.:<9!?p=?<B@4@B?DECLH9?JVHIGvD\x13JLIMOLVQ@QRPUWT_ZHY[X,`\xae7]\xaduWG8`\xaa\\^[A`\xa5:b\xab;b\xac<c\xad_a^=d\xae@f\xb0bdaRe\x99lfP\x90^8Ci\xb4egdMj\xafhjgFm\xb1Ol\xb2fj\x90Ip\xb4\xa7c\"}iflnkKr\xb7oqnNu\xba\xb3h\"{s[Xv\xb6tvs\u007fr\u007fZx\xb8ry\x81]{\xbb\\}\xb6y{x_}\xbeX\x80\xbf`\x80\xba\x96xpb\x80\xc0}\u007f|\x89\x80eb\x83\xbd\u007f\x81~\x9a{oe\x85\xc0\x82\x83\x81k\x85\xbb\xa7}fh\x88\xc3m\x88\xbdj\x8aľ~G\x87\x89\x86q\x8c\xc1\x8a\x8c\x89\xbe\x82Y\x96\x8cnt\x8e\xc4z\x8f\xc0\x8f\x91\x8ex\x92\xc8~\x93\xc3x\x95\xc4z\x94ʒ\x94\x91\x80\x95\xc5ӊJz\x98ǂ\x96Ǡ\x96w|\x99ȕ\x97\x94\x83\x98ɂ\x9aė\x99\x96\x86\x9a\xcc\xe4\x8dA\x80\x9d̅\x9dǚ\x9c\x98\x83\xa0Ϝ\x9e\x9b\xa8\x9e\u007f\x88\xa0\xcb\xf3\x915\x8a\xa2̙\xa0\xb5\x9f\xa1\x9e\x8e\xa2Nj\xa3Ρ\xa3\xa0\xfa\x95/\xa2\xa4\xa1\x8e\xa6\xd0\xff\x952\x92\xa6˳\xa6\x82\xa5\xa7\xa4\x91\xa9ԧ\xa9\xa6\x94\xac֙\xacҪ\xac\xa8\xb9\xac\x88\x9e\xaeΛ\xafԭ\xaf\xac\x9d\xb1֢\xb1ѯ\xb1\xae\xa1\xb5ڥ\xb5ճ\xb5\xb2µ\x90\xa3\xb7ݵ\xb7\xb4\xac\xb7Ҫ\xb9ٷ\xb9\xb6\xac\xbcܺ\xbc\xb9\xb1\xbd\u05ef\xbe\xdf˾\x98\xbd\xbf\xbc\xb1\xc0\xe0\xba\xc1\xd6\xc0¾\xb7\xc2\xdd\xc2\xc4\xc1\xb9\xc5\xe0\xbd\xc5\xda\xc4\xc6û\xc7\xe2\xd6ǝ\xbc\xc8\xe3\xbb\xca\xde\xc7\xc9ƿ\xca\xe5\xc6\xca\xda\xc0\xcc\xda\xca\xcc\xc8\xc1\xcc\xe7\xbf\xcf\xe2\xc2\xce\xe9\xcd\xcf\xcc\xc4\xd0\xde\xcb\xcf\xdf\xc8\xd0\xe5\xcf\xd1\xce\xdfѥ\xca\xd1\xe7\xcc\xd3\xe9\xd2\xd4\xd1\xcc\xd5\xdd\xd3\xd3\xde\xce\xd6\xeb\xd6\xd8\xd5\xd0\xd8\xed\xe7ج\xd2\xda\xe2\xcb\xdb\xee\xd5\xd9\xe9\xd9\xd9\xe4\xd7\xdb\xeb\xda\xdc\xd9\xd8\xdc\xec\xd2\xde\xec\xd9\xdd\xed\xdc\xdd\xe7\xdd\xdf\xdc\xd4\xe0\xef\xdb\xdf\xef\xf0\xe0\xb3\xdc\xe1\xe4\xdd\xe1\xf1\xe0\xe2\xdf\xd9\xe5\xf4\xe0\xe5\xe8\xe0\xe4\xf4\xe3\xe5\xe2\xde\xe6\xef\xe7\xe5\xe9\xe5\xe7\xe4\xe6\xe7\xf1\xe0\xe9\xf1\xe4\xe9\xeb\xe7\xe9\xe6\xe3\xec\xf4\xeb\xed\xea\xe6\xee\xf7\xec\xed\xf7\xe8\xf0\xf9\xf0\xf0\xfb\xf0\xf3\xef\xf4\xf2\xf6\xee\xf4\xf6\xf0\xf6\xf8\xf4\xf7\xf3\xf2\xf7\xfa\xf5\xfa\xfd\xf8\xfa\xf7\xfd\xfb\xff\xf7\xfd\xff\xf9\xff\xff\xfe\xff\xfc\x9cx\xeb\xab\x00\x00 \x00IDATx^\xed\x9d\x0fp\x14ׁ\xa7C\x9c\xf3\x83\x89-\x94\x95V\xa7\xb0\x04r\xac8\x14\xd37l\tF\\N\xa0\xd1\xe9N\xb27\xd2q\x0e\x845\xc1+\xbc\xb6N\xb0\x11\xb2\x1d\xd8(K!\x8e\x15\n\xa9S \"\x18\bZ\x82\x10QJ\x12\b,\x84A\x90\n\x10\xe1\"\xe0\x80b\xc9v\xe2\x12Nd\x1bk\x89\xd6\xc4j;\x80\x8d\x8d\xf0\xd4Խ\xd7\xdd3\xf3\xba\xa7{zz\xd4j\x8dF\xbf\xaf\xa8\xa1\xe7\xe9\xbd\xd7\u007f\xa6\xbf\xe9\xee7=\xbf\xf9\x8c?fD\x00\x80\x8aϘIc\x8cY\xd7\x00L4\xa0\x13\x00\xb6\x01\x9d\x00\xb0\r\xe8\x04\x80m@'\x00l\x03:%27\xcc*\x00{\x81N\tKwA\x1aYhV\t\xd8\ntJXfάj|ɬ\x12\xb0\x15Gu\xea\xde_[]w\xa8\x9fM\xde8\xb1\xa7z\xd7\x19m\xa9\xd3\xf4\x15\xa7%͋\xf2\x8c\xa81\xb5ެJ\\q\x82\xec7\xab\x02\xec\xc6I\x9dz\xab\xea\xcft\x9f\xd9U;@\xa7\xebk\x8e_h\xafnה:Mfچ\x82\xa4>\xb3Z2\xf5Sw\x99U\x89+\xdaI\xb3Y\x15`7N\xea\xd4U\xd5M\x1f\a\xaa\xe8A\xe9x5ۉ\xbb\xaa\xfbU\xa5N\xd3G։\xe2\x98\x1c\x16\x1d\xa0\x8d\xb4\x99U\x01v\xe3\xa4N\xa2t\x00\xeae\xfa\xd4\xcb'\"\xb5\xed\xaaR\xa7\xe9\"\xe3\xeb\xfc\xcd\x12\xd0i\fpT'\xca@w\x1dۅw\xc9'\"{\xeaU\xa5\x8e2\x98J$\x96J\xcf6d$el\xa0\xff\x9f\x98BȪ\xae\xdc\xe9I\xf3\x06\xf9\xca}I\x84L\xae\xd5\xeb&H\xd7\xc2TWڼ\xb07\x85\x9a\xb4*\xf6_w\xb2<7\x92\xcc\xd7\xe0\xe7ֿ(\xdd5m\xc1\tZZL\\UKg$=$\xd5\xec\xcdMM_\xba4uj\x1d\x9d\xae\x9d3u\xc6R\xedѴ\xf3\x89|\xf7\xe2\xa7\xf2\x874\xc5b\x13tr\x1egu\uab6a\xaa\xaaa\xfbáZ\xb6\xb7\x0e\xd4\xecR\x95:\xcb\xf1\xe6\xed\xa4\xac\xb9Y\xdai\v\\\xab\xeaW\xb9r\xe9\"\xd5\xd5N\x9b\x91<mi.Q\x0f\x8a\xb577\xbb\xcat\xbbQh\x9a\x9aQ\xd1XF*\xb4\xe5\v\xc9<\xf6\xdf`\xcd:\x99\x1a^S~n\xf5\xe4ᦺ\x05\x93\xa9\x03gj\xa7\x90Բ\x8ad6\xca=83}C\x99+\xa9\xfa!\xdaq\xc1\xe4\xe2\xfau\xa9\x19ꡓ_\xce}\xa6\xa5\xe3\xc0b\xe1]U\xe9`o\xd3\xec\x14\xe77\xe9\x84\xc7Y\x9d\xc4\xde\xeeSu\xb5\xf4e\uebe9\xef\x1d\xe8\xdeSU\xa7*u\x9a\xe0\xc9\xde~i\x14L~\x143Hf\xbf\xde%UR$\x9d\x06\xa6ͣ'\xad\x83ua\xe3\x1a\x17\xd6\\\x90\xfe\xef\xbd ӫ\xf9{pn\x03ul\x96\xb3\xa4O\x8a\\)T\xf2\xdcT:\xb5\x9d\xd0\xe3\xd5\x06r\x8aN֓\x1a\x91\x9d\xc3mW\xb5?\xe0e\"\xed\xcbQ\x1f\x9d\x16\xd2\xe3\xa0\xe3\xc7{\xe0\xb4N\"\xdb\xe5\x1a\xe9c_==$\xb5\xd5\xefQ\x97:LP\xa7\x82Y\xd2\u007f3\v\xd8c\x86K\xffӚ\x88:Փ\xe3\x11\xfeJ\xad\"\x01.\xa8\xff\x10\x9a[\xef\x86yӓ\x89\xb4$.\xb6 e.\xfa\xb0\"Ed\xcbɶӢ郌\xf4\x02U\xfb\u05fc\x85\x1b\x0f\xfcjHs\xae\xf7\xd2\xfe\xaa\x998:9\x8f\x93:)C\xe1'\xaa\xe4g}7\xc4\xdaC\xdaRG\t\xea4g\x81\xf4\u07fc\xd9\xec1c\xb6~\xed\x88:\xad#&\x03\xfd\xcd\xf52\xda\xd1\xeb\xe0\xdc\xdaҦ\xad\xd8՜)\xeb\xc4f%\xe9TAz\xd9a\x93\x1d\x9d2\x14\x1f5w:\\;P^$\xe4\xed\r\xbbvjƵ\x93\xf38\xa9Sm\x93\xf4\xdf\xf1j\xfa ]AHc\xe4|\xa9Ä\x8eNӥ\xff\xa6\xcbG'\x83;s\"\xea\xd4hrt2$8\xb7\x99s\x98\x90\v5:\xbd4y\xdeK'f\xcca\x85\xb9\xd3\xdb%ԧ\x8b\xe7\xb6R\x91\xae\xb5\xcc? j\xc0\xc8\xde\x18\xe0\xa8Nҥ\x89tZw\xa6\x8a\xee\x14\xfd\x92I\\\xa9\xd3\x04u\xaa\x97.H\xb6\xcbO3\x16\xe9\xd7\x0e\xe9t\xa1,̝\xfe\xf4L\xf6\x0eQ\xbcT\xfb\x87\xc0\xb5\x93\x11\xc1\xb9Mc^\xdd\xc8\xd0\xe8\xd4N\xd2\bɔ\x86K\xf6\x13\xe9J\xf3\xf15\xaa\xf6;\x85\x0e\xf6\xdf\xcagE\r\xd0i\fpR\xa7\xae\xaa\xc63\xddg\xea\xd8\xfd\x0f]U\xed\xdd\xc7k\xeb\aԥ\xce\"\x8f\xec\xc9\xfb\\\xee\xe4\x15\xf5+&\xe7R\xadۚgd67k\x15\xa0\xc5ͮ\x82\xe6f\xf9rd\x01\x99\x1a6\xe4\xd0\xf4\xc0\xcc\r\xf5\xc5$\xec\x18\xbb@\x1e\xd9Ӈ\x9f[\x19Y\xb4aM\x06I\xadh릳j\x13\xdb\v\\\xcd\xdd\xe2qWc}\xb32\xb6\xbe\x82,\xaa\xdbS@\xd4\xe3\xf5;\x05\xcf\x0f\x8e\x1cyF\x96\x8a\xa7\x9d\x1c\xd2\x16\x81\xd1\xc6I\x9d\xc4\ue9ba\xea]m\x927\xc7\xebjꏇ\x95:\xc9@\x8at%2E\xbe\x1bcݬ\xa4Y\xd2\xe7N\x93\xa5R\xad\x02\xedr1\x91/\xf0\xaa\xa7\xea\xbc\xf3w-JO\x9e\x1d~\x1fRMj\x84\x8bB~n7*f\xb8R\x17\xd5Lwe\x16\xd3\"ש\xa9\xf4\xb1X<\xe4b\x15\\\x99\xec\xe2Iܟ\x99\x9a2Gs'\xdeO\x97\xef\xccw{W\x86\xd9$\xf6NYt\xa27\xca\xfb\x11\x81M8\xaaS°\x8784j\xd6;\xb5\xb8wp\xb0\xaf}a\f\xc3t{f\x86\r[\x80Q\x06:\xc5@M\xca\xc3fUlbO\x8a2\x11\xd3\xed\xec\xbd'\xc6\xe0έ\t\rt\xb2Nw\xeaR\xa7NM\xdb'Kgy\xe2\xa9\xc91\x0e\x1c\x02G\x81N\xf1MA\xd2\xc3ۛ\xb6?\x9c\xe4\xd4\xe1\x10\x8c\b\xe8\x14\xe7\xd4?\x94\xeeJ\x9f\x17˩\x1ep\x1e\xe8\x04\x80m@\xa7D\xe4G!̪\x02;\x81N\x89\bt\x1a#\xa0S\"\x02\x9d\xc6\b蔈@\xa71\x02:%\"\xd0i\x8c\x80N\x89\bt\x1a#\xa0S\"\x02\x9d\xc6\b蔈(*\xfd\xe3\u007f\xff\xbeJ\xa7\xbe9{D0\x9a8\xaa\x93~\xa82\xe5T\x15>\xf6\xb7H\x87\xf7\x88\xf1\x1fe\x9b\xfeA\xf8{\xcdѩb\xb2\xfa\xbb\x87\xc0f\x9c\xd4I?T\x99\xd2W}(r\x86\x1d\b㈧\xc5\xf8\x8f\xb2M\xee\u007f\f;٫\x9f\xb2N\xbf\x05\xb0\x05'u\xd2\x0fU\xa6\xd47vC'\xab\x84e\xadp0\x9b\xfe\xaf\xfb\xeft\xae\x9dV\xb9\xf0\x9d\x8dQ\xc4I\x9d\fB\x95\xc5S5\x03\xd0\xc9V\x98G\xff\xeb\xbf~\xffG?\xfcяn\f\xaa\xbe\x91ۯ\xc9\x15\x03\xb6\xe2\xa8N\xa2n\xa8r\u007fu\x97\x98@:\x19\xc42\x8b\x91\xf3\x95\xdf\xcdso\xf5z;6欼&\x8a\xd7ʽ\xee\xfc\xa7.\xd2\xe2\u007f\x16\xdc\xfb\xd6{s\x9e\xfa\x8djR\xbc\xe6\x11\x04A:٣\xa5\a6\x16y\x9ex\x9d=\xb9\xb6v\xb1\xf7_\xfee\xb1\xa7\x85\xda\xf4ÿ\xf9\x9f\u007f\xf9\x17\u007f\xf1\xd7\u007f9s\xe6\xd2߬^\xec\xf6>\xf5\xba<\xa3UIN}Wk\"\xe2\xacN\xba\xa1\xca\xf5\x8db\"\xe9d\x14\xcbl\x92\xafܑ-l,\x11\x16\xef\xcc\xdbG\xaf\x8b\x84\xf5\x1d-O\t\xe7D\xf1b\x8b[\xc8߹3\xdfs\x91\x9f\x14\xc5s\x9d\x9d\xf3w\xb2f\xacԻso\xf6j:=T\xe4\xdd\xf7\x83\xf9\x9e\x03O\xec\xa3:\xfd\x93\xfb?L\xce̜\x94\x949{\xd2_}}o\xc7Na\x9f<\x9fC\b8\x1aE\x9c\xd5I/T\xf9\f\xf3+\x81t\x12\rc\x99#\xe7+{\u05ca\x1d\xc2\x11\xf1\x99\xf5\xa2x\xbd\x85\x1e\xa2\x86\x960EĬBv\xb8\xca_\xae\x9e\xa4\xc8:\xd1\xd2\x1cz\xdcY\xeb\xa5S-\x025m\x1f{`\x83\xe4\xee\xfb\xd6\xf8\xfdg>\xf4\u07fb\xef?\xd2\x19\r\xb1.\x19\xddd|\xfdL\xd5\xf8\xc2a\x9dİP\xe5\xfe\xea37n\xdcx\xa96\x912w\x8cb\x99e\f\xf2\x95\xbd-\xe29ᚸu\xadȒ]\x9f(\xcc\x16\x96\xb0⬭\xecq\x1f\xfd\v?)r:=C\x1fvfч\xad9\xf4\xe1e\xaa\xa4\xac\xd3_L\x9a4I\\4i\xd2g\xfe7\x9fb֭\xc98\av\xe2\xa4N\xba\xa1\xca\x17\xaa\x02$ΐ\x93Q,\xb3\x82~\xbe\xb2\xb7C<\xe7\x16%\x9d\xcey\xf3\xb7\x1e\xe9,\x91u\x92\xac\xe9dg~ܤ\xc8\xe9\xc4\xfe\x97t\xda7\x97\x8a֡\x1c\x9d\xfeI\xf8?\u007f\xfd\x97T\xa7\xcf\xfd\xa7\xbf:şT\xb6!~o\x14qR'\xfdP\xe5^Ʃ\x9a^\xedOK\x8cc\x8cb\x99#\xc2tʒu*Z~\x9d\x16\x94\xcb:md\x8f\a\xa4\xa3ShR\xd4\xd3\xe95\xe1\x89\xd7.\x16-\x1f\x92t\xfa\xbe\xfb\xef\xbf\xff?\xa8NS\xfe\x9f\xfb\x1c?\x9b2\x97\xf5\x881\x10-\x8e\xea\xa4\x1b\xaa,\x91`\xd7N\xfa\xb1̑\xf3\x959\x9d\xf2\xcb\xe9\xf3\xa1Ge\x9d\xf2\xd8\x05S\xe1J\xf5\xa4\xa8\xa7\xd39!O\x10J\xd8\b\x9e<P\xfeÿe:\x9d\xf2\xaed\x1fQm\x94\\\x14ǒ\x10J\vF\x8a\x93:\xe9\x87*Snt\x9f\xaa\xe9\x8e\xf2\x17\x9f\xe3\x1e\x83Xf\xd1$_\xf9bξ\xeb-\xee\x8b\xd7\xd7R\x1fv\n\xe5\av>*,\xde\xdbIm\x11\xbe\xder\xa0(\xe7e\x91\x9f\x1c\xea\xec\xec\x9c\xfflg\xe75\xf1\xb5N\xf7\xb3\x9dC\xbf|\xd6\xdd\xf9\x9axn~GG\xe7\xeb\xcc\x1d\xf9c\xdc\u007f\x90t\xea\xea\x98_t\xa0c\xa3 \xff&@\x05i7^\x060R\x9c\xd4\xc9 T\x99\x96\xb3K\xa7D9>\x19\xc42\x8b\x91\xf3\x95\x87聥%[\xf0\xb4\b\xc2jqh_Q\x96w\xed\x81\"\xf7Jv\x86\xf7L\xb6w\xedk\xacNh\xf2\x97\x82\xcc\x01\xf1;\xf4\xd1\xfd+\xf61\xd4w\xc4N7+s/\xbf(\xdfd\xf4\xf7\u007f\xf3\xdf$\x9d\x06_.\xf7f/\x97\xef\xf0kN\n\xfbM\x02`#\x8e\xea\x04\xac\x93\xb5SoR\x8f?x\x9e\xfdû\xef^\xfb\xe5\xea\x9ck\xf2-\xb0\u007f\xf7W\xb2N\xa1*\xdb]\x05\xdaϖ\x81\x9d@\xa78'z\x9d\x8e(?\xe89\xb4\xb8C\xd6\xe9G\xffE\xa3S_:n(\x1f]\xa0S\x9c\x13\xbdN\xe7\xd8\x109\xe5\xa2\xf0+\xe5\\0\xec\xe8\x04F\x19\xe8\x14\u05fc.\x8d4h'\xf5\x19z\xc6\xf3lKG˳\x9e\xf5C\xd0i\x8c\x80Nq\x8d4\xd2\xf0\x9avҀ\xa1#Ox\xdd\xde'\x8e\f\x05\xbe\x8d\xfb\xb7\xd0\xc9a\xa0S\"\x02\x9d\xc6\b蔈@\xa71\x02:%0u\xd0\xc9a\xa0S\xc22\xb8a!\xbb\x05v\xc5!\xf8\xe4\x18\xd0)a\x99\xa3|A㳻\xe0\x93S@\xa7De\x80}}\xf0C\xbf\xff\xde}\v\x13\xe5v\xc8\xf8\a:%*\x03\x84dfޗ\x969{\xd2\xc3\xd0\xc9)\xa0S\xa22\xb8\xe7s\x9f\x9dt\u007fJJJf;\xc2V\x9c\x02:%,3\xa6\x97U\x1f\xba\xd0\xd5\xf5\x12\xbe/\xe8\x18\x8e\xea\xa4\x1b\xaa<P#}\xb5\xbd&\x91\xae\x97\x1bS\x83!\xd1}\xc5iI\xf3TA\x18\xdfQ2\xbdFF`\x16\x05\x84\x90\xa4.\x9d\n'\xc8~\x96\xb1\xa7\xc9\xd9\x03\xa3\x8a\x93:\xe9\x87*\xf7U\x1d\xef\xa6$\xd0w\xdb\xe9\xdaM\r\xc6\x05e\xa6m(HR]\xbc\xbc\xde\xe9\x8e|/kT\x04f\xd1\xddܼA7뫝\xa8\xb3(\x80\x038\xa9\x93~\xa8r_U\xa4؟\xf1N\x1fY\x17\x1e\x11frk\xb8U\xdatu\xd2/\x05\xa3\x8a\x93:\xe9\x87*'\xb6N]D\xe7\xb7A\xa0S\xa2\xe2\xa8N\xa2^\xa8r\xc2\xe9ԗD\xc8d\xe9\xab\xfa\x83\xa9r\x9e\x9e\xf6\v\xe5Y\x1b\x9fQґCpQ˺\xa9\xcbb1qU-\x9d\x91\xf4\x10+\v͂\xa1/N\x13tr\x1egu\xd2\vU\xee\xabj\xdcUUۜ@\x83\xb9\xed\xcdͮ2i\xeax\xf3vR\xd6ܬM\x10d\x19*-K<\x17\xf92.jY?u\xf9L\xed\x14\x92ZV\x91,\x85\x8e\x85f!\xea\xea4\xd8\xdb4;EgDo\x92m\x84\xf7\r\x9c\xd6I/T\xb9\xbf\xaa\xf6D\xf7\x99\xba\xed\t\xe4\x93(&\x05\xf6u\xfd\x93\xbd\xa2\xeb\xa2x\xbdh\xb9\xaa\x90\x8bZ\xd6O]\x16])\xd4\xcb\xdcT\xe5YR$\x9d\x16\xd2c\x9b\xde/\xd0Mz\xdb&\xa0\x93.\x0e\xeb$\x86\x85*\x8b\xe2)&\xd2@MB\x9d\x9a\x98\xe8$\xa5#\a\xf2'e\xb8\xa8e\x83\xd4e\xd1\xc5~K\xa6̥<\x8b\xa8\xd3K\xfb\xabf\xea\x1e\x9d\xcc4\x89\x16褋\x93:\xe9\x86*\ahN\xa8$z\x13\x9dT\xe9\xc8\n\\Բ~\xea\xb2(\x9d\xdeE\xa7\x13\xa5Y\xaf\x14:\x8d.N\xea\xa4\x1f\xaa\xdc(\xefoM\t\xf5\xeb\xb8&:\xa9ґ\xa3ƚN\xba\xa5\xd0itqT'\xddP\xe5z\xe9\xb0\xd4W\x13\f\xb1L\x04Lt\xf2^g\xbfƴ2\xfc/\x11qR\xa7Iҿ\b\u007f\x0f\xef\x1b8\xab\x93~\xa8rw\xd5\xfe\xae\x97ګ\x13\xe7\xe04\xd8\xd6\xdc\xec*hn\xee\x0f\x8c\xec\x85\xed\xd6Y\xc2\x13\xbf\xe8X.\x05%GO7\xed\xb4Ml/p5w\xf3\xb3\x90\xee\x8aX\xd7\xdc\x1c\xf6iC\xbb\xdeOe0E\x9e\xfb\x82,ʫ_\xbb\u007f҃\xdf3\xd2\x05:ł\x93:\x19\x84*\xf76\xd6\xd6ԟ\x8a\xd4n|\xd1.\xa7*\x93*q E\x9a\x98rFS\xa3hgy (9z\x8aiO\xaeSS\xe9c17\v\xe9\x9e=Fد\f\xf4NYt\xa2W{\xbf\x1eS\xe4\x8b\xcfɢ|\xf5\x8bϿ\xfa\xfc\x97~f\xa0\vt\x8a\x05Gu\x02N\xb2g&!\xda_ƙ\x14p\x85\xf2\xb9\x9fӇ\x9f\xffgŏ\xef=8\xe9\xfeo\xbd\xfd\xf6\xf3_\xbe\xef\xbe/\xff:\xa8\xd3\xf7>?\xe9\xfe\xaf\xbd\xcdM<\xff\xe5\xcfMz\xf0\xbb\xd0\xc9\x00\xe8\x94\xc0\xf4\x9e\xd0~\x80\x1c\xae\xd3\xfd\x8aM\x9f\xfbޫ\xcfS\xb5\x1e|\xee\xd5_\u007f\xe5+\x01\x9d\xfe\xf5\xc1\u007f\xa5\a\xb0\xafq\x13\x0f~\xf3\u05ef\xfe\xec\xcb\xd0\xc9\x00\xe84\xa1\xe0u\x92O\xf6\x94S\xba/|\xf7\xed \xbf\xbe?\xa0\xd3\x17\u007f\xa6\x18\x17\x9c\xf8\xec\xcf\xe5:\xd0I\x17\xe84\xa1\xe0ubC\x11\xf7\u007fK\xd1iү\xe5\xff\u007fNO\xe6&M\n\xe8t\x9f|C\x117\xf1\xd5\xfb\xbe\xf2\xad\x9fC'#\xa0ӄ\x82\xd7I\xe2\xb9\xcf\xcb\xffߧ\xe8\xf4ů\xfe\xfc\xedW\x83:MR\x8eE\xa1\x89\xb7\u007f\xf6\xb5/\xdf\xf7M\xe8d\x00t\x9aP\x84\xe9\xf4\xe5\xaf)\x1a)'{\x9f}\x95^(\x05u\xfa\xc27\x95j\xc1\t\xc6\xf3\xf7A'\x03\xa0ӄ\x82\xd7\xe9K?{\xf5\xf9\xaf|\xe1UY\x91\xe7\xeeW\x86\"\xbe\xf9\xea\xcf>\x1f\xd4\xe9\xb9\xfb\xbe\xf5\xebW\x9f\xfb\x127\xf1\xa5\xef\xbd\xfa\xea7\x1f\x84N\x06@\xa7\t\x05\x13I\xb9\nz\xfb\xbb\x9f\xff\xcc\xfd_}5p\xc8\xf9\xee祁\xf2\x9f=8\xe9\xfeo\x06uz\xfb\xb9/~v\xd2\x17\x9f\xe3&\xbe\xf7\xc5I\xf7}\xf9y\xe8d\x00t\x9aPp\xa7y#\x03:\xe9\x02\x9d&\x14\xd0it\x81N\x13\n\xe84\xba@\xa7\t\x05t\x1a]\xa0ӄ\x02:\x8d.\xd0iB\xa1\x1f\xa3\x12\vfs\x9a\x988\xaa\x93n\xa82\xe5\xcc\xfe\x9a\xba\xf6\b\xed\x80Bİf\xdb9A\xf6\x9bU\x01j\x9c\xd4I?TY\x1cl\xacj\xbb\xd0^\xa5\x97\xb3\r\xd4D\fk\xb6\x1d\xc42[\xc6I\x9d\xf4C\x95\xc5\xc6\xean\xa6\x9a\xf6;v \x12\xbaa\xcd6\x83\x1cY\xcb8\xa9\x93~\xa8rw\x95\xf4\xad\xdcQ\xde5\x12\r\xdd\f\n\x9b\x81N\x96qT'Q/T\xb9\xad:\x91~\x8af\x141\vk\xbe\xe8\x16\x84\xad\xbfY[8\xff\x89w\xb9RӰf\xcao\xca\x17\xbb\xbdO\xbd.j@,\xb3e\x9c\xd5I/TyO\xfd\x99]U\xb5\x87\x12*\x04vt0\tk\xbe\xdeҒ_\x94\xedݸv.\x9fBa\x1a\xd6,\x8a\x1d\x9e\xaf\xef\xed\xd8)\xecS\x15\x1a\xc52\x83H8\xab\x93^\xa8r\x9d\x14\xaa\\[\x87cT\x14D\x0e\x1c\x13\x1f\x15J\xae\x89C\xea\xf8>Ӱ\xe6\xeb\xf9O\xb0\x9c\xb2\x16u3\xa3Xf\x10\t\x87u\x12\xc3C\x95\xeb\xa5\xf1\x88\xfe\xc4\nU\x1e-\xcct\xca\n\x8bG2\x0fk\xee\x10~\xa5m$\x1a\xc72\x83H8\xa9\x93~\xa8r\x93<\xf6۴Ǩ\x19\ba\xa6\xd3\xd7\xc3\xcbLÚ\xf7\t\xd7\xc3[I-q\xedd\x15'u\xd2\x0fUn\xaf\x91>\x8clęE\x14\x98\xe9T\xaeShF\x87:+=\x04F\xf6,\xe3\xa8N\xba\xa1\xca}\xd2@y\u007f5n\x8b\x88\x82\xd1\xd0\xe9\x9aw\xe5\x10\xfdo\xe3F\xed\x1f\xa0\x93e\x9c\xd4I?TYl\xafn\xef>U\xbb\vC\x11&\x98\x855\xbf\xfb\x8b\u03a2\x95\x9d\x9d\x16\xc3e)\x1d\xf3\x8b\x0etl\x14\x0eh\xcbuc\x99A$\x9c\xd4\xc9 TY\xec\xdaS\xb3\xab\x1d6\x99a\x16\xd6|Q\x90xʠy\x04^.\xf7f/?\x12V\xac\x1b\xcb\f\"\xe1\xa8N`|\xa1\x17\xcb\f\"\x01\x9d@\x04\xc2c\x99A$\xa0\x13\x00\xb6\x01\x9d\x00\xb0\r\xe8\x04\x80m@'\x00l\x03:\x01`\x1b\xd0\t\x00ۀN\x00\xd8\x06t\x02\xc06\xa0\x13\x00\xb6\x01\x9d\x00\xb0\r\xe8\x04\x80m@'\x00l\xc3Q\x9d\xf4B\x95\ak\xabdjM\x1a\x83\xf8\x80\vv\x06Z\x9c\xd4I7Ty\xa0\xaa\xbd\x9b\xd2^u¬9\x183\x9a\xb8\xafJs\xc1\xce@\x8b\x93:\xe9\x87*\x9fbv\r\xd4⋟q\xcc\xecEf5\x80\x84\x93:\xe9\x87*K\xd4\xe3\xbb\xed\xf1L\x06t\x8a\x0eGu\x12\xf5B\x95\x19R\x12\v\x18+\xba\x16\xa6\xba\xd2\xe6I_\x14ܐ\x91\x94\xb1\x81\xfe_L\\UKg$=\xc4\xde\xfa\x94p\xbe\f\x91\x0fv\xe6*\x14\xb3\xa2\v.2S\xea\xacv\xce\xd4\x19K'j@\x9f\xb3:\xe9\x85*3\xa4$K0F4Mͨh,#\x15t\xb2\xc0\xb5\xaa~\x95+\x97\xbe\xc1\xd5N!\xa9e\x15\xc9\vE\xb1\xffP\xf3\x8c\xcc\xe6\xe6f)\x99\"\x18\xec\xccU薊\xda\n\\\xac\xbc`rq\xfd\xbaԌ\t\x1a1\xe1\xacNz\xa1ʔ\vU\xf8\n\xf5\xd810m\xde\x00\xcbk\xa3W\xb3\xfb\xa5\x1fH\x93\x1f])\xf4E\xc9M\x95\xaa\xa8N\xf6\x02\xe1d\\\x05ɰ2\xa6S=\xa9\x11Y\xa4\xd8vqB\xe2\xb0Nbx\xa82\xa5\xb1.r\x130\x9aԓ@\xa4\x94X0K\xfaof\x01}p\xb1\aI\x11#\x9dB\x15B:-\x9a>\xc8H/\x10'$N\xea\xa4\x1f\xaaL\xa9Ad\xe5\x18\xb2\x8e\x04\u007f\xbdd\xce\x02\xe9\xbfy\xb3E^\x11#\x9dB\x15B\x93\x19ʅ\xd6\x04\r@rR'\xfdPe\x96\x03\xab\x8a\xa0\a\xce\xd2\xc8\x1d\x9d\xa6K\xffM\x97\x8eNZ\x9d\xaa_\x92+\x19鴊M\xe6No\x97\x98\xa0CK\x8e\xea\xa4\x1b\xaa\xcc.\x9dF\xf77^AD\xfa\xd33ٛ[\xf1Rv\xdeǮy\xb6K\x81ͼN\x99\x99\xf4\xb2\x97(\xa7\xe4::%\xad\x10\xc5\x1b\xb3\xd9\xe4~\xb9\xd6\xe3k\xc4\t\x89\x93:\x19\x84*S\xb7\xf0[icI\xd3\x0337\xd4\x17\x13vҐ;yE\xfd\x8aɹ\xd2h]A\x9b\xd8^\xe0\x92~\x93\xad\xccU\xb1'sj7\x1f쬪0'u͚9dJ\xcd\x19Q\\A\x16\xd5\xed) \x13\xf4\x961'u2\nU\xbe\x80\xbbVƖ\xaeE\xe9ɳ\xe5\x17aݬ\xa4Y\xf2\xe7N\x84\xb8NM\xa5\x8f\xc5\xf4\xd9@qJR&\x8bD\x0f\x05;\xab*te&%?\xf4\xb8\\w\u007ffjʜ\xfdF\xb3Jp\x1c\xd5\t\x80\xc4\x06:\x01`\x1b\xd0\t\x00ۀN\x00\xd8\x06t\x02\xc06\xa0\x13\x00\xb6\x01\x9d\x00\xb0\r\xe8\x04\x80m@'\x00l\x03:\x01`\x1b\xd0\t\x00ۀN\x00\xd8\x06t\x1a7,\"\xa9\xb9g\xcc*\x811\x05:\x8d\x1b\xba\x9bjf\xa6NԈ\xa0q\x82\xa3:\xe9\x85*\xb3\xa4\x9c]ջ\x0ea?\x89\x82&\x82\xacܸ\xc6I\x9dtC\x95ž\xda]R)\xbe\x91kN\x1bi3\xab\x02\xc6\x12'u\xd2\x0fUn\xaec_\xad\x1e\xack6i\r\xa0S\xdc\xe3\xa4N\xfa\xa1ʍr8\xd8\x1e$W\x9a\x03\x9d\xe2\x1cGu\x12\xf5B\x95\xfbj\x9b\xfa\x06\xfb\x9aq\xb2\x17\x05'H\x93Y\x150\x968\xab\x93n\xa8\xf2@#-ݏ\xf4\x95(\x18L\x9d}\xa8{\x82\xe6\x15\x8f\v\x9c\xd5I/Ty\xb0\xb1\x8e\xe5\x1b5\xe2'4\xa2`?!d\x81Y%0f8\xac\x93\x18\x1e\xaa\xdc\\7 \x95\xe2\a\x9e\xcc\xe9O\x9d\xbe\xae\t\x19\x9f\xf1\x8b\x93:\xe9\x87*W\xcb\xf9`R6,\x88L\x1b\xc1\x80M\\\xe3\xa4N\xfa\xa1\xca\xd0)z0\xb2\x17\xe78\xaa\x93n\xa8r\x93t\xb27P\x871+s\xa0S\x9c\xe3\xa4N\xfa\xa1\xca\x03\xdb\xebNu\x9f\xaaێ\xa1=s\xa0S\x9c\xe3\xa4N\x06\xa1ʃm\xbbjv\xb5a`ό\xc1\xee\xf6E.\xfc\xae\\\\\xe3\xa8N`$,$d\xda\x1e\xb3J`L\x81N\xe3\x86\xee\xe384\xc5;\xd0\t\x00ۀN\x00\xd8\x06t\x02\xc06\xa0\x13\x00\xb6\x01\x9d\x00\xb0\r\xe8\x04\x80m@'\x00l\x03:\x01`\x1b\xd0\t\x00ۀN@\xcd\xe0\xc0\xc0\xc0`\xf0?`\t\xe8\x04T\x1c\x9aL\bI\xea\xefO\xa2\xffMFX\x9bE\xa0\x13\x90\xd83\xa7W\xfa\xbf\x8eԷ\xb5\x9d\x12\xc5Smm\xf5\xa4Τ\xd1X\xd37'\xce\xee\tvT'\xfdPen\x12\x18\xf3\x1dAh1\xab\x13\x99\rd\xf2v\xa3\xbfU\x902y\xa2\x8e\x04o\xb4\xed\x96u*&\x93G[\xab\x98\u05edb\xf2\x1a\xb3*\x8e\xe2\xa4N\xfa\xa1\xca\xfc$0\xe6\xf5N\xf7N\xb3:\x91\xe9k\x9e]f\xf0\xa7u\x93k\x94\xa9p\x9d\xba\x9b]\xfa͚l{\xcd\f\u05ed\xe3\x9cnq\x88\xfa)\xebLj8\x8a\x93:\xe9\x87*s\x93 \"Y#\xd4I\x14\x17\x18\xe8t\xc1\xb5\"0\x19\xae\x93(\x1a\xe84{\x91nqL\x18\xac\xdb\xf2r\xddb\x8eUq\xf5\x8dJ'u\xd2\x0fU\xe6&ADFO\xa7\x82\xf4\xe0\x9b\x99\x05\x9d2F_\xa7GMu\xeaO/0\xab\xe2 \x8e\xea$\xea\x85*s\x93 \"Y\x1b\x9f\xf1\xe6<\xf5\x1bUYw2\x91I\xe6ޤ\a\xd3\\\x8f\xa7\xa77\x15\xa7d\xb2\x84\xd0E\xe9\xaei\v\xe4\x1f\xb2\xa1:\x15Ӻ\x0f\xb0Q\x87\xda9Sg,\x95-\x1aL\x0e\x1e\x9c\xf4u*~8=eA\x17}룍\x1f\x17\xcb\xe8c]\xbd2\xdf\f\xa9\x06\xd7Y8\xef湷z\xbd\x1d\x1bsV^\x13\xc5k\xe5^w\xfeS\x17i\xf1E\xb7 <5\xe4\x15\x84\x9c\xebܺ\x1d\x11\x04a\xab\xb8\x93>\xb6\xb0I\xc6\xd7Y'C?]\xee)\xdax\x9dMv>\x91\xef^\xfcT\xfe\x90\xdc\xfb\xaa\xa48J\x19qV'\xbdPe>_\x19D\"K\xf8zK\xcb\x12\xcfE\xbel\xb0f\x9dL\r\xff!QS2Y\x9aIRפU0\x05\x1en\xaa[0Y\xcal\xa1:u\xe7N^Ǧ\v&\x17\u05efK͐\x12\x9a۹\xe8s]\x9dH\xc6\xf6\xed\x19I\xa7\xc4\xfeCӊ{\xc5\u07b2\xe4\xe6\xfe\xfeC\xcd32\x9b\x9b\x9b\xa51$\xbe3\x1d:\xb2\x85\x8d%\xc2\xe2\x9dy\xfb\x98.\xeb;Z\x9e\x12\xe85\xd1\xd0/v\n\xbf\x10\u007f:\xf7\xa7\xbf\x12\xb9u\xbbޙ\xff\xec\x1f\xc4?\xfc \xbb\xf3ڵ\xce\u03a2\x95\x9d\x9d\x9d/\xb3>\x9e\x116v\xec\xf3>J\x1d\xfa\xe5\xdcgZ:\x0e,\x16ޕ;?\x14Oq4\xce\xea\xa4\x17\xaa\xccM\x82\x88d\x15\xd17\xe7\xebE\xcbU\x85\xbd\x17dzU\xa5\xe9\xb9T\xa3z\xb1\xe0a\x16\xb9\xc6\u07bff-d\xc5T\xa7\n\x97t\x1aPO\xd8\xd8C\x1b\xd9.?\t%\xcb\xea\xea4\x93\x1e\x00\x06f̡\x93e\xechT \x9f_\x05O\xf6T\x9d\xe9\xe1]+v\bG\xc4g\xd6\xd3\xe5o\xa1\x87\xa8\xa1%\xabY\xf1\xd03˯y\xe5\xb3<n\xddv\xb2\xa3\xd13\xcfH\xc5\xc1\x93\xbd#\xc2\x01\xfax\x8e\r\x00\x1e\xf02\x91\xf6\xe5(G\xa7n\x12Go\xc4\x0e\xeb$\x86\x87*\xf3\x93 \x12Y[\xd9\xe3\x01\xe1\x1aWv\x81\x04Pe-\xa7o\xa7{w\xbf\xb8\x82\xed\xf0\xbd\x1b\xe6MO&\xb3X\xf1\x82\xb2UD>\xa9^4}\x90!_x\xec1\xd3\xe9q\xf6\xb8\x81\xf4\xb1\xb2S\xe2@\xb2\x9cE\x1b\xd4Iՙ\x1e\xde\x16j\xc25q\xebZ:}\xed\xc0\x13\x85\xd9\xc2\x12\xa9\xfc\xfa\xa3yO\xc9Vp\xeb\xf6\xfa\xdc_\x89׳;\xa4\xe2\xa0Nk\v\x87ޥx\xa9e\xafy\v7\x1e\xf8Րb\x13]\"C\x8b\x9d\xc7I\x9d\xf4C\x95Փ\xc0\x18\xf9r\xbdSP\r\x1e7\xd7˨o`H\xdf/\xb6\xb9DI\xa7\xb6\xb4i+v5g\xca:\xa5%ϔ\x0eSb\x86\"\xa1\xf4\x8c\x8f\xef3\x1e\x8ah&l\xb4h\xdeRq\u007f\x8a|b\x19\xd4Iՙ\x1e\xde\x0e\xf1\x9c[\x94t:\xe7\xcd\xdfz\xa4\xb3D\xd6Il\x11:\xe5\t~ݞ\xf8\x17\xb1C9\xf6\x04uZ\xa2\\G=%2!ˋ\x84\xbc\xbd\x8aOm$\x8e\xf6\x1c'u\xd2\x0fU\xe6'A$\xb26\xb2G\xf5\xd1\xc9\x00N\xa7\x99s\xd8\xdb\xd8BY\xa7\xd4S\x17\x92+\xd8T\xee\xf4v\t\xe9\x1c\xb1\x9f\x1b\xba\xd3\xd5i){\xac&쬱>uP9דu\xaa~Iә\x1eL\xa7,Y\xa7\xa2\xe5l8\xa1\\\xd6\xe9u\xef\xd6|\xf9\x12\x88_\xb7#9Cʹ\x9e\xacӁ\xd7\xd8\xd1\xe9\x9c\x04\xfd\xfb\xb9\xadT\xa4k-\xf3\x0f\xc8U\xca\\q\xf4\x11\x8b\xa3:\xe9\x86*s\x93 \"Y^\xba'\x0e\x15\xad4\xab'\xaat\x9aƎ\x1972\x94\x93=Q\xdc\xefb\x87\xa2\xfd\xb2*\x8f\xcb7\x15,\x9a\x1e\x1cE\xd0\xd5)\x9d\x1a983\x93M\x0f\xa6֧(\xafU&-\xe8euԝ](;.j\xe0t\xcag\x82\f=*\xe94\xb4\xfc\a\xe2\xb3%\xd2Q\x86_\xb7\xa1\xc5Gr\xe4s=q%-\xf8\x03\xbb`\xea\x90o\x9b\xd8J\x0fb;\x05\xe9\x8f+\x9f\x95jܘ9O;\xb71\xc4I\x9d\xf4C\x95\xb9I\x10\x91,\xe1\x89_t,\xcfy٬\x1e}\x8bJ\xa9\xe8\xdf\xee:џ\x9b\xd9-\x96\x91E\x1b\xd6d\x90Ԋ\xb6\xfe\xe6\xd9\x05m\x83\xfd\xf3қ\xe8\x1b\xd8\n\xb2\xa8nO\x01\xa9\x95\xeawM\xae\b4\xd5\x1fٛ\xd7\xd64'E\xbe\xc0Z1]9ףDž\x8a=\x99SYuUg\v\xc8T\xcd/I^\xcc\xd9w\xbd\xc5}\xf1\xfaڒש\f\xe5\av>*,\xde\xdby\xbd\xf3;\xde\xd7\xc5\xdfdo켮Y\xb7\xad\x859ʰ\xddά}GJ<\xaf\xb1\xb2\xb9k[\x8e<ä\xda)x~p\x84N\xca\xc6U\x90x\xfa\xc0\xd2I\x9d\fB\x95\xb9I\x10\x89\xa2\x9d\xe5\xd9\u07b5\xaf\x99U\xa3\xef\xd8i\x84\xd4&\x93\xa9u\xecr\xe6F\xc5\fWꢚ\xe9\xae\xcc\r\xec&\xf1\xf6Z\xfa\xb8\x8aVڟ\x99\x9a2g\xbf\xd2b\xd5\x03\x81\v\x90:\xd2\x15\xf8\x82FW@\xa7\x99e\x8b\x92\xd3s\x15ͺ\xc8\xc3JՁ┤L\xf9\xaa\x8b\xef\xacz\xaaf\xe8z(O\x10Z\xb2\x05O\x8b \xac\x16\x87\xf6\x15ey\xd7\x1e(r\xaf젗B\x1bō\x820\xb7C\xb3n/\v땦\xd77\xe6\xcc_)_+v\x94,\xceY\xce\x14\xfa\xe9\xf2\x9d\xf9n\xefJ٦椥b\x1c\xe1\xa8N nY\xeaRԑ>\x9eU\xbe\xa0A\xf4>Z\xefw\x99\x9d\x97\xef!#\xbc\x9a\xb9\x96\xd5aVEa\xbb\xab \xae\xbe\x94\x05\x9d\x80DE\xba<\x900x\xa2-\xf0\x05\x8d\xb6\x13z\xbbj]\xaa\xc9\x0e\\\x93\xf2\xb082Z\x16\xbfkVE\xa6/=\xben(\x87N\xc0\neMb\xa6\xd1]\xe9\nݩKGt\x1d\xbc\xb3c\xa8\xe4\af\x95\xe2\x15\xe8\x04\xa2g\x80d\x14\xa7k\xc6\x19l\xe6\xba\xf0\xf5\u007f\xf6F\xf1Q@|\x02\x9d\x80\x05ʦf\x8e\xf6\x17=\u007f\xe0)y٬N\xdc\x02\x9d\x00\xb0\r\xe8\x04\x80m@'\x00l\x03:\x01`\x1b\xd0\t\x00ۀN\x00\xd8\x06t\x02\x8e\x131\xb0y\\\xa79C'\xe04Jn\xb3\xfe\x1f\xc7w\x9a3t\x02#!\x90\xc5l\x85@n\xb3>\\\x9as\xdce&\x9b\xe2\xb4N\xa7\xaa\x94\xbb\x94\xbb\xf7\xd4\xec\xef\x0e\x9b\x04\xd1\x10s\x06\xb1\xedHY\xccV\x17\x87\xfbJ\x15G\x87\xf7H`2\xf8E\xabx\xcbL6\xc5a\x9d\xfa\xaa\x0f\xc9\xdf1\xeb\xaen\xeej\xae\xee\xd6L\x82\xa8\x88=\x83\xd8f\xe4,f\xabq\xcf\xfa:\x1d\xf1\x04\x9d\f\xea\x14o\x99ɦ8\xacS}c\xb7\xa4\xd3\r)i\xe5P\xed\r\xd5$\x88\x96\x983\x88m%\x98\xc5l-\x9fV_'q(8\x15\xd2)\xce2\x93MqV\xa7S5\x03\xb2Ng\xaa\xd9M\xfc\x03\xd5gT\x93 Zb\xce \xb6\x95`\x16\xb3-:\x85\xe0t\x8a\xaf\xccdS\x1cթ\xbf\xbaK\x94uj\x94\xbf\b]ߤ\x9a\x04\x11\xf8g\xc1}`c\x91\xe7\x89\xd7ٓ\xd83\x88et\xb3\x98\x19]\vS]i\xf3\xa4\xc2\r\x19I\x19\x1bD\xf6\x834Sօ\x87*\x8b|\x16\xb3^ܳ\n\xd52p:դ\xc9)q\xd7<\x02w\x01\xc6\xe9\x14_\x99ɦ8\xaaS}\xa3\xa8\xe8\xb4K\x8e&8\xb4G5\t\"p\xb1\xc5-xw\xee͖\xf2Sc\xcf \x96\xd1\xcfb\x16Ŧ\xa9\x19\x15\x8de\xa4\x82N\x16\xb8Vկr\xe5\xd2Ӈ\xda)dښ\xb2i\xeaPe\x91\xcfb\u058b{\xe6Q/\x03\xa7\xd3B\xa2\xe4\x10\x9d\xeb\xec\x9c\x1f<\xc4\xf1:\xc5Uf\xb2)\x9fy\x1c\x00`\x13#8:\x01\x00\xd4@'\x00l\x03:\x01`\x1b\xd0\t\x00ۀN\x00\xd8\x06t\x02\xc06\xa0\x13\x00\xb6\x01\x9d\x00\xb0\r\xe8\x04\x80m@'\x00l\x03:\x01`\x1b\xd0\t\x00ۀN\x00\xd8\x06t\x02\xc06\xa0\x13\x00\xb6\x01\x9d\x00\xb0\r\xe8\x04\x80m@'\x00l\x03:\x01`\x1b\xd0\t\x00ۀN\x00\xd8\x06t\x02\xc06\xa0\x13\x00\xb6\x01\x9d\x00\xb0\r\xe8\x04\x80m@'\x00l\x03:\x01`\x1b\xd0\t\x00ۀN\x00\xd8\x06t\x02\xc06\xa0\x13\x00\xb6\x01\x9d\x00\xb0\r\xe8\x04\x80m\x98\xeb4\xb0f\xf6TW\xfa\xc2C\xe1\u007f\xd9@\x1eV\x1eF\xc0\xbd\x8ai\xae\xf4\xc6\xe0Ӂ{\xf4\xa1\x96,\nU\xa8#\v\xc3\x1a\xf1\xac#\xc5\x11\xffn\x82a\xf7\x9a\x053AZn\xb3E5\xc1\x96\xed\t\xc6\x12S\x9dj\\ʏ\x12\xcf\xfbP\xfb'[^\xfe\n\xd6w{\xe0ن$6\x97\xb8\xd0I\xbd`&\xc8\xcbm\xb6\xa8&ز=\xc1Xb\xa6\xd3RB\x16\x9e\x10?\xe9]\xe5\"\x99\xf74\u007f\xb3\xe5\xe5\x9fE\x96~r/\xd0\xf3=B\xc2t\xea\xdeЬ\xd7.\xc8\bu2\xec^\xb5`&(\xcbm\xb6\xa8&ز=\xc1Xb\xa2S\x13!\xdb\xe5\xa9\xe3\x84\xd4h\xfeh\xcb˟N\xbaBO\xf4t2c\x84:\x19\xa2Z0\x13\x94\xe5\x1e!\xb6lO0\x96D\xd6\xe9^Zh_-&\xd35\u007f\xb5\xe5\xe5O#ݡ'\xf1\xa4\x93j\xc1L\x80N@\"\xb2Nm\x84\f\x04\xa6\xfb6tIE\x8b\xd2]I3W\x89~\xf5\xcb?\xb0t\xba+e\xe1q\xb9*\xff\xa4\xbfx\x9a+yN\x8dꬩ\x97\x96\xa5,d\xd7%s\xa4˲\x80\x0f+\xa4g\xddL'qi\xbakzY\xe8\x82D\xaf\x9bS\vR\xa7λ\xc0t\xaa%\xb3\xe4\xa2\n\xe9ɺ\x0fX\xebU\x1fHE\xdc\x02ג\r\x83\xc5i\x0fd4\xd2\xc9Y\xae\xb4\x9b\xacD(\x00\x00\x1e\xe5IDAT\xa5\xdc\xf5N\xff\n\xb6\xc8g\x82}\a\x16,\xb0wK\xd2jz\x0e\xb6\t,\xb7\xd2Wh\xf5\xb4-\x14\xf8\x99\xe9o\xcfYd\x85\x1f\x8c?\"봊\xccД\x14\x13\x92\x9e\x91F\x1f>P\xbd\xfcǧ\x12\u05ec鄬\xf1k\x9e\xf4&\x93\x94\xd93\by\x88\xeb\xa3\xdeE\xa6\xb2>\xe8\x1e\xb3&\xd7E\xe6\xe5\xd6)\u007fس\x88^\xa9\xe5\x0e0;\xd2HZ\n!\xb3\xee)\xfb\xbb^7U\x84\xa4\xcdrMɤ;\xfa\a.\xd2+\x95\xcd gh\xeb\xa5\xe9$\x99\xb6\x9e\xf9\x89f\x81kIq*Is\x11\xd2XL\x1e\xa0e\x99\xfe\x80N\x87\x92\xc8\xd4ٴ$x\xed\x13X0\x8dN|ϡ6\x81\xe5\x96\xfb\xe2VO\xd3B\x81\x9f\x99\xc1\xf6\x84N\xe3\x93\xc8:- \x05\xea\x826\x92\xc4\x0e:\xa7\xa6\x92\r\xfc\xcb?\x90LV\xd0\xfd\xe5T\ni\xd4<YHVQ%^J&\x87\x82}\xbc4\x99\xac\xa1e\xfb]\xa4\xd6ot\xb2G\xa6wљ\xb9\xc8\x1ee\u007f\xd7\xeb\x86\x10\xaa\xe1\a\xf3\xa4\x83\xdbBY\xe4\x97\xc84\xa9\xf5\f\xfa\xce\xdf\xec\"\xbb4\vL\xff2\xb3\xd7\u007f/\x97\xb8\x1e\xa8\xbfǮ\v/(\xdd\x0fNe\xfd߫ \x0f\x84\x8e\"\xf2\x82it\xe2z\xe6\xdb(\xcb-\xf5\xa5Z=U\v\x05\xbe\xa1\xc1\xf6\xf4\xd7W\x9d\xf2\x83\xf1Gd\x9d\xe6h\xdf$W\x902\xe5\xffb\xfe\xe5_A\x16H\xc5\xfb\xd9\xd1L\xf5d\x9alKun[\xb0\x8f\x85\xca\x1eZGR\xef\x19\xea$\x1dl\x8a\xd9\\\xa4}T\xa7\x9b\\y\xd9>Le\x95\x9a\xe5\v\xbbǙU\xb4u_\xb0\xb5j\x81\x95~{\t\xa9`e\xb3\xd9>.u_F\xe6I\xb52I\xe0@i\xa4S\xa8g\xbe\r\xaf\x93j\xf5T-\x14\xf8\x86\x06\xdb\x13\x8cS\"\xeb\xf4\x10Y\xaa)Q\x86\x8e+\xd8a+\xf4\xf2O#MR\xf1'\x93I\xbf\xfa\xc9Cd\xce\x19\xf5h\xf3\xbd$e\xc8\xec\xdeTzff\xa0\x93|)T͆$\xa4}4\xbc\x1b\u007f2;\xb6\xf8\x95=\xf1^\n\xeb\xf4^\x1a\xdbyk\xc9\xccPk\xd5\x02\xd7\xca箟\x10y\x9e\xb9\xa4Z\xe9~\xa6\xb2ȃ\x83\xa1\xfeuu\xe2z\xe6\xdbp:\xa9WO\xbd,2\xaa\x99\xe9oO0N\x89\xac\xd3\xc3$W[t\xef̮\xb2Eӈ\xea\xe5\xff\x90^\xe5̑p\x91v\xd5\x13\xff\x19z\xa5\x92\x9c\xbb\x87\xbb\x12\x1f D\xb9\x8e\x98\xc3\xce\xe5\xf4u\x92\x8fo{\xd8\xff\xd2\xfe\x1e\xde\xcd\a\x81n\xf6Ho\xfcKٱ\xaa\x9d\xcc\xe6Z+\x03\x03\xdc\x02\xd7\xca\xc7\x05:\x17v\xe5\xef/ UJ\xad\xc0\xa5\x17\x8f\xaeN\\\xcf|\x1bN'\xf5\xeai\x96EB=3\xbd\xed\t\xc6+\x91u\xaa\xe0\x87\"\x8e\xb3=\xa6:\x8d\rbe\xccQ\xbd\xfc\"\tѨzBϬ\n\x92\xe8Ĕ\xe2\xe0\xa5x7\x99\xa2L-`\x9fdE\x1a(\x0f\xe9\x14\xdeM?!\xf2D\xb3\xa4S\x17I\xbbG\xed\xaf\xe5Z\xcb\r\xf9\x05V\xfe\x12\xa6\x13=\\q\x87%\x05]\x9dB=\xab\xdap:\xa9WO\xbd,\x12\xea\x99\xe9nO0^\x89\xacS7\xf7\xd2\xf7\x93\xc9]\xecΛ\xe2\xfa\v\x1fjNN>T\xae\x10$TO\x18\xf7N\xad\x99EB;I\u007f4G\xa70\x9dº\xf9 \xf0Q\xcf~\xf9\xb2d\x069q/i\xca\a~\x8dN\xaa\x056\xd2ɯ]d\x86Z\xa75Z\x9dTm8\x9d\xfa5G\xa70\x9dT\r\xf5\xb7'\x18\xaf\x98\xdc\x151-t\xf1\xb4\x82^Z\xd3\xeb\x01\xf9Z}\xa9\xfa\xe5Oe\xc7!Ʃ\xfe{\xea'\x03\xf2\xa7+\xb5dJ\xf0F\xa2\a\xa2\xb8v\xd2\xea\x14ލ?E\xe9f\x8d\xacS\x05Y\xd1.\xef\xb3\xfc.\xac^`C\x9df(#\xe4M\x0fU\a\xbaW\x16\xacJ\xe9\xec\xe10\x9d\xf86\xfc\xb5\x93j\xf5\xf4t\xe2\x1a\x1amO0N1\xd1i\x17!\xf5\xf2\xd4!B6\xb0\xb3:\xe9\xbc\xff\xc3tvQ\x15z\xf9\x8b\xc9li7o#\xae\x0fTODe\xcf\xed#\x93\x83\x1e\x04\x86\xbev\x91\xe4O\xa2\xd4I\xaf\x9bb\xb9\x9b{\xd3e\x9d\x06ȴ\x15\xf25>\xbf\v\xab\x17\xd8P\xa7\x15\xca\u07be@\x1e\xf2\x93\x90\x17\xac^>\xdd\xfd0-L'\xbe\x8d\xdeȞ\xb4zz:q\r\x8d\xb6'\x18\xa7\x98\xdd\x02\xbb\x90^$\x9f\xf9\xf0^\xef\xe3\x84̹翗,\x8dNߘG؎\x1ez\xf9\xfb\\\xa4\x98\xeeO])\xec`\xa6z\xf2\x10y\x88\xee\xba\x1f.R\x06\x87\x19\x17\xa6\x90\n*ES\x12\x1bX\xd3\xdc\xcb\xe3\"\x8d\x9f\xdc\xd39:\xe9t\xd3\xef\"\x1b\xee\xf9?\xcc\r\xdcT\x91I\x92\x92\xa5\xd3,\xd5\xd1I\xb5\xc0\x86:\xf5'\xb1E\xba\xb7\x8eL\x15\x83\xfd\xcb\vF\xcf\xdd\xe8_\xfa3I\x98N\xaa6\xf2rK\xe5\xaa\xd5\xd3Ӊkh\xb4=\xf1\xb9\xd38\xc5L\xa7O\n\x02\xc3\n\v\xa4\x91\bB\xa6-\x98=9\xa5\x8c\res/\u007f\x93\x8b<0{:\x91\xef:\xe7\x9f\f\xa4\x10\xd7\xccYI$\xad?\xd4g\xfd\x14\x92<;\x9d\xc8\xe7\x91j\x9df\x13\xf6\xa5\b\x9d\x93=\x9dn\x1a]$mv\x12Y\xa8\xe8\xb4'\xe0\x95j\x17V-\xb0\xa1N\xecs֔\xd9t\x1e\xdc\x1d\xe1ʂ\x15\x13\x92\x9cN\x92*\xc2tR\xb5\x91\x97[.\xe7WOO'\xbe\xa1\xd1\xf6\xc4]\x11\xe3\x133\x9d\xfc\xfe3\xc53\x1ep\xa5/R>?m\xcbLu\xcd,\xfb\xe0C\x17\x19T\x9d\x9c\xf4/\x9d\xeeJ\x9a]-\x9f\x8a\xf1O\x06\x96\xcep=@[\xf0]v?\x9c\xeeJ\x97oj\xd3\xe8ԗ\xf9@\xf2~\xbd\xa1\b\xddnrӒ\xe6\xb45*\x16\xd1E\n\\`\xf1\xbb0\xbf\xc0\xc6:\xf9\xfb\x8aӧ\xa4\xe6\xf2\x8b\xa2,ؽ\xdaY\xae\x94ܾ\x13\xe1:\xf1m\xe4\xe5Vʹ\xd5\xd3Չoh\xb0=\xa1\xd3\xf8\xc4\\\xa7\xf1\xc2\x00\xbb\xc1\b\x80\xb1$qt\xaa\xe0\x86\x11\x00\x18\x13\x12D\xa7\xbe\xc1\xc6\a\\\xa1a\x04\x00Ƅ\x04\xd1)\x97\x10\x1c\x9c\xc0\x98\x93 :U'\xa5\xc1&0\xe6$\x88N\x00\xc4\x03\xd0\t\x00ۀN\x00\xd8\x06t\x02\xc06\xa0\x13\x00\xb6\x01\x9d\x00\xb0\r\xe8\x04\x80m@'\x00l\x03:\x01`\x1bv\xebt\xb6\xe4\xb6Y\x95h\xb8Sr֬\n\x00q\x87\xa9N\x1fm\xc9\xf3\x94\xfb\xccj\x058(4D]7\x12\xbe\x83\xc2A\xb3:V\xb8\xec=oVń\x91\xf7\x10-\x97\xe6\n2^k\x9br3m\xe2yOS\xd8 \xb8\xd9\x1bӋ\x1e\xa1A\xaf\r\xb0\x17S\x9dJ\xbdG7y>6\xab\xa5\xd0*\xbc`V%Z^t\xb7\x9aU\xb1\xc0\xf9쨏vW~\xaf[l\xa1\a\x0e\x83\xce\"V\x18~Ž\xb9\x87\xb2[\xb0v\xa0\xbf\xd9\xd3sX\xf8\x9d\xa6\xf0N\xa5\xa7\x94\xfeWꩼ\xa3\xd7\x06؋\x99Nw\x84V\xbf\xef\xaeI\xa5\x00\xef\xbbw\x9bU\x89\x9e\xbdY7ͪX \xfa7\xfa\x95\xeb\xf5ˣ\xef\x81è\xb3\xc8\x15\xb2\xa4#\xc9\v\x82e\x03\xae\x86\xe9\xe4\xdf]N\xdf\f\xefx\xcam|e\x80!f:\xbd'X8\xc7\xd9\xec\x1d6\xab\x12=\xc3\xde\xcdfUF\x85\xc7\xcc\f\xb0\x82ig\xba\x15d\x9d\xde\xdba\xd9`=\x9d*KO\xfb_X]\t\x9d\x9c \xa2N\xbe\xc5\xf2I\xfc\x0e\xbf\u007f\xab@\xcf\xe3\xdew\vKؤ\xfb؎%\x9e\xd5\xf2\xc1\xe3\xbdo繽\xe5Ҵ/[~\xcd\xder\v\xc2\xde\xf7*\v=\xab?\xe5:\xe3J\x8d:\xf3\xbdP\x92\xbddG@ɽ\x1e\x8d\x9c\x96{P\xf8\xd8C\xd7\xe1$\x9bR/z\x88\x9eՅ\xee\xbc\xf2B\x9f\xff\xbcrٲ\\\xbd\x16\x06=ܩ\\\\\xb8c\xc7\xe2\xec\xd3\\\x0f\x1c\\g\xaa%ӛ\x9b\x8a\xac\xc0u\xce\x1f\xe92\x94\xfb\n\x05!\xc7翻>\xdf]X\xfe\x96\xdf\xffi\x9e\xfbDž\xf9W\xb6\xe5\x94\xdee\x8bӺ%?\xa7\\\xb9d\n\xea\x14\x9a\xdb\xee\xca\xc3O\xfbˏ2\x9d\x82=h\x9b\x01\xbb\x88|tz\xb3\xe7\xa4\xd0\xd0\xd3s\x8b\x9d\x98\xbb\x1b\xfc\xbe\xab\x9b\xb3\xe8k|\xd2-x\x1b\x0e\xe6<\xcdj\\\xc9^~\xf0r\x83 ]\xe7\xbc)\xf4H\xad\x86O\x9f,,\xca.\xdcQ9\xf7\xcf\\_\\\xa9Qg\x9b\x85m/\xb6z\x1fS\xf6\xc9W\x84\xdf\xfaUX\xee!\xc0՞\x9e\xf9\xd2\x1e\xaa\xaa\x1b⍹\x9b\xce^>\x96'|J\xaf[z\x8a\x9e\xa4\xd7-\xff\xaeY\v\xdd\x1e|\x8fz\x0f7\xcc\xf7\x1c[\xdd\xca\xf5\xc0\xc1u\xc6/\x99\xee\xdcTd\xed\x1d\x1e^\xbf\x83\xcd\xe1\xb7\rt#\xbc0\xf7\x857\x99\x9c[\xae\x9c.\x17\xae\xd2m\x9e#\xec(\x15\x16\x1f\xcck\x95\x16\xa7\xb0\xa1\xa1\xd0\xf3\x8e\xd40\xa8Shn\xbb+of\u007f4\xff\x16\xd3)ԃ\xa6\x19\xb0\x8b\xe8O\xf6\xa4\xb7̆,i2\x87\xbe9Wz\xe9\xd4p\xe1j\xfa\x92\xf9NKg\xf9/\n\u007f\n4{L\xa0o\x9da\xd7\\\xa1R\xdd\xce\xceK\x03\x19W\xe5\xc3\x005X\b\xbf\xf8\xb7\xd6\x03\x87Gy\xc3\x0f\xd5\xe58\xece\x1a\x1cΑ,\xe4N\xbfTk\x11\xde\xc3i\x81\xbe\xd3\x1f\x16\xde\xd1\xf6\xc0\x11\xec\x8c[2\xa3\xb9\x85\xc8b\x87\xacriҷ\xa9\xe4N\xa14\xc89|\x92.\x88o\x19\xf3\xd8[I\xb7\xf5y\xff\xa6-\xacn!-\xfe\xb8\xb0D\xaa\x1dЉ\x9b\xdb\xeeJ\xff\xb2-+\xfdL'\xae\au3`\x17\xb1\xe9\xb4)0yIx3T\xf7\xac\xf0~`\xf2\xb1,\xfe\xc0\x14^\xaa\xdb\xd9\xfaG|\x9fR\n7\xcbun\n\xa7G\xd8\x03GP\x86`]\x8e?\xe7\x17n;\xf6\xa6Ov\x81\u05c9_\x8b\xf0\x1ev\xe7Ї?Iҫz\xe0\bv\xc6-\x99\xd1\xdcBdm\xb9zu\x99\xac\x93\u007f\xf8\x1by\xca\xe7\x14w\x0e\xaf~$GXF\xa7\xbc'\xa9*\xc3\xcc\x14ZW:\xc1>,\x0f[\x04t\xe2\xe6F+\xb1\x0f\x1d\xa4k\xa7P\x0f\xeaf\xc0.b\xd3)8\xd9*p\xd7)܅\xf0c\xda\xcb\x01M\xa9ng˔K\t\xe5T\xec\xaa\xf0\xca\b{\xe0\b\xca\x10j\xc6\xf1\xf1\xd1\xf5K\x84\xbc\x83aG'~-\xc2{h\x9d{\x87\xbd\xa1\xbc\xa3\xed\x81#\xd8\x19\xbfd\x06s\v\xc1fq\xe9\xb2\xf2䬲\x19\xaez\vw\x9f\xed)\x95t\xba\xe4\xbf\xea\xf6+:I\x8b\xd5#H\x03\xee\x81W\x80\x9b\x1b\xadtg\xc7mI'\xae\au3`\x17\x16uګ\xd9\u007f/\xf3\xaf\xc7p\xf0\x12\xda\xffط\xfd:\x84Ju;\xab|\xe4\xf7\x12\xca;f\x83;|\x80\xdeZ\x0f\x1c\x11u\xba\xba\x9b\xee\xda\x1f\x9f\xf4\x1cfO\xa4\x1d\xfc\x98tXR\xadEx\x0f\u007f\x16\xca\xff\xfcVQ\x89O\xdb\x03G\xb03nɌ\xe6\x16Bَo\xb1ո\xe9\xdd[\xf8\x11{\xb6\xa4\x84\xbds};\xa0SV@\xa7m\xec\x8f\xc7\x04i[\x05t\xe2\xe6&U\xf2K:q=\xa8\x9b\x01\xbb\x88^'\x0f}A|+5\xfb\xef]o)ۛ\xb6I/\x8e\xff\xdbE\x81wg\xfd\x01\xe2P\xa9ng\x97\xe4k\x9e\xbd\xf2\xfd\x10\xbe%\xe5#\xec\x81'\xa2N\r\xc2%\xf6_\xe9\x16\xe9\xb1\xd4\xef\xbf-\xf7\xa3Z\x8b\xf0\x1e~/\xe4\tB\xe9Ͱ\x1e8\x82\x9dqKf47\xff\xfb\a\xdf\xe7fA\xada\xabX\xb2\u05ffE\xdaƅ\xccm\xdf7\xc2tʣF\f?R*\xb5\b\xe8\xc4͍Ӊ\xebA\xdd\f\xd8E4#{W%IJ\xbc\a\x1bJ\x04\xf7\v\u007f\xbc\xd5\xe3\xde|\xd5\xf7\xe6f7\x1b\xf1\xbb2\xffѣ\x97\xb6\tǤ\xea\xef\xc9w\x06}\xfa[i\xc0*x!%\xa3*\xd5\xefl\xf7\xdcʳg7+wV\xb4\x86\x9d\x88X\xed!\x80\xefw==\xf37\xf7\xf4\xdc\xf5\xab\xea\x86h\x10\xb2\u007fr\x9e6\xbb\"=\xc9j=[\x9a\xfdg\xd5\xdc\xf4{\xf8\xfd\xfc\xcb/\xf6\xdc\xf4\x85\xf5\xc0\xf7\xact\xc6/\x99\xee\xdc\x18O\xcb\xc3\x0f\x81\xbb\"zrv\f\xbf\xb2\xd5{\xd3\xff~ζW|\xb4\xd9\xfa\xc3\r\x8fѓī\u007f\xcci\x1d>\xe9~k\xb8\x92\xa9\x9c%,?y\xac(\xe7O\xf4`\xc9\xee\x8ah\xed\xe9Q\xcd\xed\xa3\xcaR\xb6\xaa\xb7J+?\xe2z\xe0\x9b\x01\x1b\x89\xfc\xb9S\x8et\x06\xee\x96\x06r\xdf+\xf5d\xaf\xfe\xb1 l\xddʊ\xfe-\x9b>n\xa5\xc5\u007fZ_\x98\x1d\xbc_u\xef|v\x9e\xff\x96|\xe2\xae9\xb8\xa8J\r:\xbbT\xba8\xe7I\xe9\xbd\xdb\xdf\xe3\xd9\xe1\xd7`\xb1\x87 o(W\x12G\xfd\xea\xbaA^x\xb2\xa1\xd0\xed-\x95]\xf0m\xcb\xf1<yU=7\xfd\x1e^q\xb32\xf7\x93\xefhz\xe0\bt\xe6\xe7\x96Lwn\x8ccޣRE!@+\x9b\xdc\xe6\xdf&\bs\xaf\xf8}\xadEY\xde\xf5NJ\xdcO\xd2c\xe2\xc9l!\xfb\xa4tm\x94\xb5csN~%Sf\x93\xd2j=?\xb7\x06A\xd8D\x9fn\x11\x84\x86P\x0f\xa5|3`#f'{\xd6\xf0ms\x9f4\xab\x13\x1d\xa7ݛU\x9f\xe1\xc4!\xb7\xb3\xb7\xdc\xfe\xf4ӏ\xdfx:'\xda[\x1aG\x83\xd0\xf5\xaa%bl\x06\"c\xafN\xf4\r\xb0Ж\xa1\xd7;ްA\xb2\xb8\xe3\xac\xf2)\x93/Ou4\x1c~_\xc6\xc6\xfb\xad\"\x11\xa3\x1716\x03\x91\xb1Y\xa7\x89\xc4\xef\xe5!r\xff;\xfcgo~\xff\x93\xca9ד\xba\x8dl'F/bl\x06\"\x03\x9dbƷٳ\xe5\xf4\x95\xd3[<[T\a\xd2?\x9d\x97q\xe4*\xff\xa642bV+\x8c\x18\x9b\x013\xa0S\xec\xf8ί\xcew\xe7\xaf>?\x86\xfb\xa542\xa2\x19B\x8d\x82\x18\x9b\x013\xa0\x13\x00\xb6\x01\x9d\x00\xb0\r\xe8\x04\x80m@'\x00l\x03:\x01`\x1b\xd0\t\x00ۀN\x00\xd8\x06t\x02\xc06\xa0\x13\x00\xb6a\xb7N\xc8(\a\x13\x18S\x9d\x90Q.3\xf2\x1e\xa2\xe5\xa4t\a\xed⧣\xb9\th\xab\xa0\x93\xdad\xc0\xd1P]+\xb3\xb0Rw\xc2'\xa2\x9bꄌr\x19\v=pĒQ~\xf7\xbc\xf0㞞\x17\x96\xe5}\xa4S_\x83\x947\x18%\x1f\xf7\x94\x04\xea\x1a\xce\xc2\xca\xe2\xe8ԝ\xf0\x89\xe8f:!\xa3<@\xf4=pĔQ~K:\x8a\xdc\xf1D%\x8a\x95oZ\x94\a\xeb\x1a\xcd\xc2\xca\xe2\xe8՝\xe8\x89\xe8f:!\xa3|D\x98v\xa6WA\xde\u007f\xfd\xcb\xcc\xdaJ\x8cD\xa7\xf0YXY\x1c\xbd\xba\x13=\x11=rV\x042\xca\xc7\"\xa3\\\xde\u007foK)\xce\xc1fF[=k\x87\\\xca'\x97si\xe4\xaaׂ괍\xcen\xfe\x1dn\x16l\x19~\xcc\"%\x84\xd3\x06\xcbk\xa5\xeeDOD\x8f&\xc9\b\x19\xe5\xcef\x94\xdf\x12\x8e\r\xdf\xfdݲ%w\xf9fF[=KXr\xf2l\xdeӪ\xe4r.\x8d\\\xb5\x16T\xa7\x9b\x95B\xebU~\x16ï\x14n\xb9\xed\xbf\xfd\x93\x9c\x9e\xbb\x06\xcbk\xa5\xeeDOD\x8f\xfed\x8f\x8f]EF\xf9hf\x94ߒ\xde\xf7\x8bn\xaa\x9b\x19l\xf5,\xefG\xec,ۯJ.\xe7\xd3ȹ\xb5\xa0:\xb5f\x9d\xd7\xcc\xc2\xdf\xc0\x8e0\x9b6\xcbuu\x96\xd7J݉\x9e\x88\x1e\x9bN\x9b\x02\x93\xc8(\x1f\x85\x8c\xf2[\xc2O\xae^\xbd\xb4i\xf1\x1b\xea\x15\xd2\xdf\xeaY[\x02\xa5|r9\x97FέEy\xc3^\xe5\xe5\xe4f\xe1\xbf9\xf7\xdf\xfc\xbe\x1c9\xc3Yoy\xadԝ\xe8\x89\xe8\xb1\xe9\x14\x9cDF\xf9(d\x94+\xd7\xfe\xeb\x8b|\xaaf\xfa[=T\xca%\x97\xf3i\xe4\xdcZ\x94{s\x96<\xed\xd3̂\x16\xef\xf0_\xca\xd1\xd8\xcd\xcd\xd8J݉\x9e\x88nQ'd\x94s=\x8cVF\xb9\xb2\xff\x1e\xa3o\xe6\xfc\n\xe9ou\xb5NY\xb2N|\x1a9\xb7\x16\xe5\xdew\xde\xcfi\xd5̂\x9e\xac\xe5\xf9\x94\xf37\xdd\xe5\xb5Rw\xa2'\xa2G\xaf\x132ʵ=\x8cVF\xb9\xb2\xffn\xca\xf6\xa9VH\u007f\xab\xeb\xeaħ\x91sk\xc1\x06\xca/\xb9\xaf\xaag\xc1\x82\x02\xcf+\xe7o\xba\xcbk\xa5\xeeDOD\x8ffd\x0f\x19\xe5\x8ef\x94˷!\x9c\xad\x946f\xb0\x99\xfeV\xe7J\xf9\xe4\xf2P\x1a9\xb7\x16\x1f\xf7\x94l\xfe\x9d\xefn\xb9\xf7\xcam\xd5,\xe8L\x1e\xc9\xf9\xd4py\xadԝ\xf0\x89\xe8\x91?wBF\xf9\x18d\x94\xcb7ɹ\x97\x1d\xf3\xf1\xcd\xf4\xb7z\xa8t\v\x9f\\\x1eJ#\xe7\xd6\xe2(\x9bx\x83\xf5\xbeW=\v\xff\x9f\x84\xc0QUgy\xadԝ\xf0\x89\xe8f'{\xd6@F\xf9\xb8\xe4nV\xd8\xfb\x80!V\xea\x06\t]T'8\xf6ꄌr\xc73\xca\xed\xe0\xf4\xe2\xe8ߺ\xac\xd4\r\x02\x9d\x80\x19\xf1\x91Q>b\x1a\xae\xf8J\u007fbVI\xc1J]\x1e\xe8\x04̈\x87\x8c\xf2\x913,,\xdf\xea\x8d\xf2l\xd5J]\x8e\t\x94\x88\x0e\x9db'\x0e2\xcam\xa0!\xbbTsϠ1Vꆘ@\x89\xe8\xd0\t\x00ۀN\x00\xd8\x06t\x02\xc06\xa0\x13\x00\xb6\x01\x9d\x00\xb0\r\xe8\x04\x80m@'\x00l\x03:\x01`\x1b\xd0\t\x00ۀN\x00\xd8\xc6\xc8ur.\xbc;:\xd6\x1f\x95\xff\xbf\xb2:\xcf]\xb8yb\xdc\xdb\x02\xe2\x04\v:\x8dyx\xb7!|\xdd7\x84\xdd\xd2\xffW\xe7\x96\x1c\xbb|\xb4(o\x02|g\r\xc4\r\x16t\x1a\xfb\xf0n#Bu}=\xf9\x8aNg\x05\x16ipS\xf9\xda=\x00N`A'Ӽm+\x98vfZ\x81#Tw\xbd\xb0\xde#\xeb\xe4\x93\x0eKz\xe1b\x00\x8c\x16&:\xc5Ux\xb7*o\xdbwt\xb9\xe7\x1b\x87}\x9a\xcen\xdf\xf2\xe7\xec\x0e\xd4\xf7ݹT\xf8\x8d\x98\x8e\x9d\x00\xc4Dd\x9d\xe2+\xbc[5\xe3MY{_ܛ\xb5\xd9\x1fV7\xa8ӛԱl\fE\x00\a\x89\xacS\x9c\x85ws3\xbe$\x85\xd5ɏ\xea\xbaA\x9d|W\xaf\xb4\x16z\xe1\x13p\x8e\xc8:\xc5Yx77\xe3\xcdr$㣛\xc3\xea\x86N\xf6(\x1f\xe7\xebd_\x020J\x98\\;\xc5Wx77\xe3\x12Y\x93\U00092c3a\x8aNw\xe496\xb8q\xf1\x04\x1c#\xb2Nq\x16\xde\xcd\xcdx\xf3#\xacw_ᦰ\xba\xb2N\xbe\x1c\xb9f\x83'\x86\x1c+\x00b#\xb2Nq\x16\xde\xcd\xcd\xf8E\xe9O'\x85\x17\xb5u\x03:屟@\xf2\u007f\\\x18\xfec\x1a\x00\x8c\x16f:\xc5Sx\xb7*\xa3\xbcR\xd8}~\xb7P\xa9\xe9\xecNOO\xf6z)T\xfd\x05\xa1\xfc\xe8\xe5\xd6\xc2<;\u007f\xaf\x1a\x80\xc8D\xd6)\xbe»U\x19\xe5\xbe\xd6e\x9ee\x87}\x9a\xba{\xa5\x1an\xf6+\xac\xbf}\xbap\xfe\x92m\xb6d\xd2\x02\x10\x1d\x16\ue288\x9a\xc4\t\xef\x06\xc0\x12\xa3\xa1S\xe2\x84w\x03`\x89\xd1\xd0)A»\x01\xb0\xcah\xe8\x94\x18\xe1\xdd\x00Xf4tJ\x90\xf0n\x00\xac2*:\x0101\x81N\x00\xd8\x06t\x02\xc06\xa0\x13\x00\xb6\x01\x9d\x00\xb0\r\xe8\x04\x80m@'\x00l\x03:\x01`\x1b\xd0\t\x00۰[\xa7\xb3%\xb7ͪ\xa8\xb9S\x12K\x88,\x00\xf1\x88\xa9N\x1fm\xc9\xf3\x94G}\xb7\xd0A\xa1!\xea\xba2\xbe\x83\xc2A\xb3:V\x18yd\xfa\xc8{\x88\x96\xb3n\xe5\xae`\xb7\xf9[J\x83\\\xe9E\x8f\xd0`V\x15\x8c\x19\xa6:\x95z\x8fn\xf2D\xfb\xbd\xa5V)\xe5\xcb\"/\xba[ͪX\xc0Bd\xfa\x98\x87\xae\x1f\x14zz\x0e\v\xad==s\x8d\xdfQ\x02\xcd\xeeTzJ\xe9\u007f\xa5\x9eJ|#2~1\xd3\xe9\x8e\xd0\x1a\f\xd43\xe5}7\x1f\xca\x155{\xb3\xec\xfc\x06z\xf4G\xc71\x0f]ou\xb3\x84\xc1\xdf\xf9\xfd\x1e\xe37\x94`\xb3\xdd\xe5\xf4]펧<\xa6M\f\x9c\xc1L\xa7\xf7\x04\vg>\x9b\xbd1}5pػ٬ʨ`%\x06\xdd\x14\xd3\xcet*\xf8\xdeStz\xcf\xd8\xe0`\xb3ݕ\xa5\xa7\xfd/\xac\xae\x84NqLD\x9d|\x8b\xe5S\xfb\x1d,\x82\x9c\x9eǽ\xef\x16\x96h\xd2\xc8\xfd\xef};\xcf\xed-\x97\xa6}\xd9\xf2K\xcde\x89\x1b5\xe3\x82\xc9){=\x1a\r-\xf7\xa0`\x10\x99\xce\x11W\xa1\xeb\fI\xa7h\x9a\xed\xae<\xfc\xb4\xbf\xfc(\xd3\xe9\xee\xfa|wa\xf9[~i![\xb7\xe4甿\x17\xd6/\x18\v\"\x1f\x9d\xde\xec9)4\xf4\xf4\xdc\xf2\xfbo\xf6\xb8\x1b\xfc\xbe\xab\x9b\xb3\xd4i\xe4\xfe+\xd9\xcb\x0f^n\x10\xa4\x93\x957\x85\x1e\xa9\x15\x97%n\xd4,\x14L\xcexE\xf8\xadz\xbe\x96{\b\xa0\x1b\x99\xce\x11_\xa1댠Nf\xcdvW\xde\xcc\xfeh\xfe-\xa6\xd3ya˕\xd3\xe5\xc2Uy!\v\x1b\x1a\n=\xef\x84u\fƀ\xe8O\xf6B1z\\\x1a\xf9p!\x8b\xb3\xf3\x9d\x96.\x8f_\x14\x82_\xb4\r\x85\x98\xeb6\xe3\x82\xc9\x197\x85\xf0\x8b\u007fk=p\x84G\xa6s\xc4]\xe8zP'\xd3f\xbb+\xfd˶\xac\xf43\x9d\x86O\xd2%\xf5-\x93\xde*\xb2\n\xef\xb28\xc1\x12\xbd\xbe\x81\xd3ĦӦ\xc0\xe4%>\x0e\xe2\xac\x10\xcc\xd7\x0f\x85\x98\xeb6\xe3\x82\xc9\x197\x85\xd3~-\xd6z\xe0\b\x8fL爻\xd0\xf5\xa0N\xa6ͨN\xec3\x05\xe9\xda\xe9\xce\xe1Տ\xe4\bRL{\x96t\x82}X\xc0x_<\x10\x9bN\xc1\xc9V\x81\xbbz\t\x9e\xb7\xf0!\xe6\xba\xcd\xf8`r\xbf\xfe\x8f\x9aY\xeb\x81#<\x94\x96'\xdeB׃\x1bʹ\x19\xd5\xe9ΎےNW\xbd\x85\xbb\xcf\xf6\x94\xca:I\v\xdb#\x98\x8d\xd3\x03'\xb0\xa8\xd3^\xcd^}\x99\u007f\x19\x87\xb3\x1a\x02\x93\xa1\x10s\xddf\\09\xa3\xc1\x1d>\x14o\xad\a\x8e\x88:\xc5]\xe8zP'\xd3f\xbb\xe5\xc4[\xa6Ӓ\x12\xf6&\xf6mY\xa7m\xec\xf1\x98\x10\xed\x87\x19`4\x89^'\xf6#\x99\xbe\x95\x9a\xbd\xfa\xae\xb7\x94\xedcۤ\xd7\xd4\xff\xed\xa2\xc0{v\xe8\xadX\xb7\x19\x17LN\xf1-\xd1\xf9\xd5\x18K=\xf0D\xd4)\xeeB׃:\x996\xe3t*d\xf2\xfb\xbe!\xeb\x94GE\x1a~\xa4\xd4\x0f\xe2\x80hF\xf6\xaeJ\x92\x94x\x0f6\x94\b\xee\x17\xfeȧ\x91\xfb\xaf\xcc\u007f\xf4\xe8\xa5m\xca\x0f:\xbf'\xdf/\xa4\xca\x12\xd7o\x16\n&\xf7\xb33F홊\xd5\x1e\x02\xe8G\xa6s\xc4W\xe8:\xe5\xcd\xc3B\xab\x1c\x1dm\xd2\xec\xa3\xcaR\xb6&\xb7J+?\xa2\x15\xd6\x1fnx\x8c\x9e\x0eҖY\xc2\xf2\x93NJr\x90\xb6\x16\x17D\xfe\xdc)G:\x9dwKû\xef\x95z\xb2W\xffX\x10\xb6\xf2i\xe4\xf4\x02}}av\xf0.ֽ\xf3\xd9E\x90*KܠY0\x98\x9c\x9e\xf7{vhgl\xb1\x87 \xfa\x91\xe9\x1c\xf1\x15\xbaN\x0f+\xac\u007f\xcf\xdd(\x9a5\b\xc2&\xfat\x8b 4\xf8}\xadEY\xde\xf5NJ\xdc\xf4\x98\x94\xb5csN~\xa5\xea=\x03\x8c\x19f'{\xd6\xf0ms\x87\x8f\\\x9bpڽ9\xde\u007f\x82)\x9eC\xd7C\u05eb`\xec\xb1W'\xfa\xbeYhq\xc4\xf6\x8e7l\x90,\xee\x88\xe7\xd0u\xe8\x14OجSb\x12ϡ\xeb\xd0)\x9e\x80NQ\x10\xbf\xa1\xeb7\xa5\xf1\x12\xb3Z\xc0)\xa0S4\xc4m\xe8\xba4^\xf2\xbe\x1f\xc4\t\xd0\t\x00ۀN\x00\xd8\x06t\x02\xc06\xa0\x13\x00\xb6\x01\x9d\x00\xb0\r\xe8\x04\x80m@'\x00l\x03:\x01`\x1b\xd0\t\x00۰['d\x94\x83\t\x8c\xa9N\xc8(\x1f=\x90Q\x9eh\x98ꄌ\xf2\xe8@F90\xd7\t\x19\xe5Q\x82\x8cr`\xae\x132ʣĴ3d\x94O\x00\"gE \xa3\x1c\x19\xe5\xc0\x02\xd1$\x19!\xa3\x1c\x19\xe5 *\xa2?\xd9CF92ʁ\t\xb1\xe9\xb4)0\x89\x8c\xf2`\x0f\x81\xceL\xc3\xc6\xd5 \xa3<\x91\x88M\xa7\xe0$2ʃ=\x04:3\r\x1bW\x83\x8c\xf2D¢N\xc8(GF90&z\x9d\x90Q\x8e\x8cr`B4#{\xc8(GF9\x88\x8aȟ;!\xa3\x1c\x19\xe5\xc0\x02f'{\xd6@F\xb9\xe3 \x056\x9e\xb0W'd\x94;\x0et\x8a'l\xd6)1AF9\x88\x0e\xe8\x14\x05\xc8(\a\xd1\x01\x9d\xa2\x01\x19\xe5 *\xa0\x13\x00\xb6\x01\x9d\x00\xb0\r\xe8\x04\x80m@'\x00l\x03:\x01`\x1b\xd0\t\x00ۀN\x00\xd8\x06t\x02\xc06\xa0\x13\x00\xb6a\xb7N\x963\xca\xf5Ar9\x18\x8f\x98\xea4\xda\x19\xe5\xfa \xb9\\@r\xf98\xc4T\xa7\xd1\xcf(\xd7\a\xc9\xe5H.\x1f\u007f\x98\xe9\xe4DF\xb9>H.Gr\xf9\xb8\xc3L''2\xca\xf5Ar9\x92\xcb\xc7\x1d\x91\xb3\"F\x9cQ\xceuf9w\x1c\xc9\xe5Q4Cry\\\x11M\x92\xd1\b2ʹ\xbe,\xe7\x8e#\xb9<\x8afH.\x8f+\xa2?ً1\xa3\x9c\xc7Z\xee8\x92ˣh\x86\xe4\xf2\xb8\"6\x9d6\x05&\xcd3\xcay\xac\xe5\x8e#\xb9<\x8afH.\x8f+b\xd3)8i\x9eQ\xcec-w\x1c\xc9\xe5Q4Cry\\aQ'\xeb\x19\xe5<\xd6rǑ\\\x1eE3$\x97\xc7\x15\xd1\xeb\x14cF9\x8f\xa5\xdcq$\x97\xfb\xa3h\x86\xe4\xf2\xb8\"\x9a\x91\xbd\x11e\x94\a\xb1\x9a;\x8e\xe4r\xbfy3$\x97\xc7\x17\x91?w\xb2!\xa3<\x88\xc5\xdcq$\x97#\xb9|\xfcav\xb2g\x8dX2\xca\xf5Ar\xf9\x88@6\xec\xd8`\xafN1d\x94\xeb\x83\xe4\xf2\x91\x01\x9d\xc6\x06\x9bu\x9aH \xb9\x1ch\x81N1\x83\xe4r\xa0\x05:\xc5\x0e\x92ˁ\x06\xe8\x04\x80m@'\x00l\x03:\x01`\x1b\xd0\t\x00ۀN\x00\xd8\x06t\x02\xc06\xa0\x13\x00\xb6\x01\x9d\x00\xb0\r\xe8\x04\x80mح\x132\xca\xc1\x04\xc6T'd\x94ˌ\xbc\x87hAF\xf9\xf8\xc5T'd\x94\xcbX\xe8\x81\x03\x19\xe5\x13\v3\x9d\x90Q\x1e \xfa\x1e8\x90Q>\xb10\xd3\t\x19\xe5#´3d\x94'\x14\x91\xb3\"\x90Q\x8e\x8cr`\x81h\x92\x8c\x90Q\x8e\x8cr\x10\x15џ\xec!\xa3\\\xdb\x032ʁ\x86\xd8t\xda\x14\x98DF92\xcaA\x88\xd8t\nN\"\xa3\x1c\x19\xe5 \x84E\x9d\x90Q\x8e\x8cr`L\xf4:!\xa3\\\xdb\x032ʁ\x86hF\xf6\x90Q\x8e\x8cr\x10\x15\x91?wBF92ʁ\x05\xccN\xf6\xac\x81\x8c\xf28\x01)\xb0c\x83\xbd:!\xa3\x1c\x19\xe5\x13\x1a\x9bu\x9aH \xa3\x1ch\x81N1\x83\x8cr\xa0\x05:\xc5\x0e2ʁ\x06\xe8\x04\x80m@'\x00l\x03:\x01`\x1b\xd0\t\x00ۀN\x00\xd8\x06t\x02\xc06\xa0\x13\x00\xb6\x01\x9d\x00\xb0\r\xe8\x04\x80mح\x132\xca\xc1\x04\xc6T'd\x94ˌ\xbc\x87h9)\xddA\xbb\xf8\xe9h\xee\x12\xda*\xe8\xa46\x19p4T\xd74ڼg\xaeP\xe2\xf3\x9f\x15\x84\xb9\x97\xd5\u007fxgu\xb6\xb7\xf2\x8a\xf7\xb6\x95\x19O LuBF\xb9\x8c\x85\x1e8b\xc9(\xbf{^\xf8qO\xcf\v\xcb\xf2>ҩ\xafA\xca\x1b\x8c\x92\x8f{J\x02uM\xa3͇/\v\x9e\x1e\xffݳ\xc2e\xf5\xf7L.e\xaf<vr\x99 \xfc\xbb\x95\x19O \xcctBFy\x80\xe8{\xe0\x88%\xa3\xdc\u007fKz\xe3\xbf\xe3\x89j\u007f\xb5\xf2U\x8c\xf2`]\xd3h\xf3\xbbB\xe5f\xfa\x82j\xb2[\xee\xe4<M7\xc3p\x91\xf0\xef\xd6f<a0\xd3\t\x19\xe5#´3\xbd\n\xb2N\xfeefm%\xac\xec՜Nf\xd1\xe6w\x85\xcb\xd9\xc3a:\xed\xf6Hߗo\x15\u07b36\xe3\tC\xe4\xac\bd\x94\x8fEF\xb9\xac\xd3m)\xc59\xd8\xcch\xabg\xed\x90K?\xcds\xff\xb80\xffʶ\x9cһ|\\\xb9굠:m\xa3\xb3\x9b\u007f\xc7<\xda\xfc\xae\xf0\xfecg\x15\x9d|G\x97{\xbeq\x98\xadZ\xd1&i\xeewZ}\xa1\x19kz\xd0\xdd:z+\x9f\x90D\x93d\x84\x8crg3\xcao\tdž\xef\xfenْ\xbb|3\xa3\xad\x9e%,9y6\x8f\x96^\xc9\x11v\x94\n\x8b\x0f\xe6\xb5\xf2q媵\xa0:ݬ\x942\x92L\xa3ͩN\xad\xe5\x8aN\x9b\xb2\xf6\xbe\xb87k3]a\x81\xbb\x9e\r\xceXӃ\xce\xd6\xd1]\xf9\x84$\xfa\x93=>v\x15\x19壙Q~K:d\x15\xddT73\xd8\xeaYޏ\xd8Y6\x9d\xf2V\xd2W\xe0\xbc\u007f\xd3\x16u\\9\xb7\x16T\xa7\xd6,\xe9\xf54\x8d6\xa7:ݙ\u007fG\xd2\xe9\x92\x14\xf0\xc7\x1e\xdf\xe7_\x91ЌU=\xe8m\x1d\xa3\x95O<b\xd3iS`\x12\x19壐Q~K\xf8\xc9ի\x976-~C\xbdB\xfa[=kK\xa0\xd4{\x92\xee\xb1\xc3r\x90%\x17WέEy\xc3^\xe5\xe54\x8d6\xa7:\xf9\xcb[%\x9d6\xcb\xdd<\xba\xd9\xef\xe3G[C3V\xf5\xa0\xb7u\x8cV>\xf1\x88M\xa7\xe0$2\xcaG!\xa3\\\x19\x8aX_\xe4S5\xd3\xdf\xea\xa1R\xef%\xffU\xb7\x9c\v\xcbǕskQ\xee\xcdY\xf2\xb44[\xd3hs\xa6\xd3\xd9oH:\x95\xc8\xc1\x86\xe5%\xc1k'\xdf%Ռ\xc3z\xd0n\x1d\xa3\x95O<,ꄌr\xae\x87\xd1\xca(Wt:F\x0f\x12\xfc\n\xe9ou\xb5NY\xb2N|\\9\xb7\x16\xe5\xdew\xdeϑ\x0e0\xa6\xd1\xe6L\xa7\xe1\xec\xcb\xd2\xd1\xe9\x11\xb6\x86\xbe\xc2MldOڲ'\x85\xdb\xfc\x8cU=\xe8m\x1d\xa3\x95O<\xa2\xd7\t\x19\xe5\xda\x1eF+\xa3\\\xd1iS\xb6O\xb5B\xfa[]W'>\xae\x9c[\v6P~\xc9\xcd2gM\xa3͙N\xfeM\x95L\xa7\x17\xa5e8)\xbc\x18\xf8\xdc\xc9WZ\xa8\x9a\xb1\xaa\a\xbd\xadc\xb4\xf2\x89G4#{\xc8(w4\xa3\\\xbe+\xe2l\xa5\xb41\x83\xcd\xf4\xb7:W\xfaǜ\xd6\xe1\x93\uedc6+\xe9.\x1c\x8a+\xe7\xd6\xe2㞒Ϳ\xf3\xdd-\xf7^\xb9m\x1am>|Y8{\xd7\xdf\xe3\x91F\xf6*\x85\xdd\xe7w\v\x92\x80\x97<%/\x9c]\xed~E\xb58\xa1\x1e\f\xb6\x8e\xd1\xca'\x1e\x91?wBF\xf9\x18d\x94\xcb\xf7칗\x1d\xf3\xf1\xcd\xf4\xb7z\xa8t\v=\x16\x9c\xcc\x16\xb2O\xb2K\x94P\\9\xb7\x16G\xd9\xc4\x1b\xac\xf7\xbd\xa6\xd1\xe6W\xe6\n\xc2i\xbf\xaf\xc4+\x9d\xe7\xb5.\xf3,;,\x8b\xf1\xcejO\xde\xd3\xff\xa6^\x9cP\x0f\x06[\xc7h\xe5\x13\x0f\xb3\x93=k \xa3||\x13\xba\xf8\x1d1\t\xb8u\xa2\xc0^\x9d\x90Q\x1e'\x19\xe51b\xa3N\x06['\xc1\xb1Y\xa7\x89D<g\x94Lj\x8d:\x19l\x9d\x04\a:\xc5L\xfcf\x94Lj\xad\xd1\xe6\x06['\xc1\x81N\xb1\x13\xb7\x19\xe51bo\xb4y\xa2m\x9d\xa8\x80N\x00\xd8\x06t\x02\xc06\xa0\x13\x00\xb6\x01\x9d\x00\xb0\r\xe8\x04\x80m\xfc\u007f\xe7\xbd\xe7\x84\xdaB\xea\xf4\x00\x00\x00\x00IEND\xaeB`\x82",
+
+ "analysis/call-eg.png": "\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x02\x1e\x00\x00\x01\xc8\b\x03\x00\x00\x006\x92\x13\xd7\x00\x00\x00\x01sRGB\x00\xae\xce\x1c\xe9\x00\x00\x02\xfdPLTE\x00\x01\x00\x05\a\x03\n\r\t\r\x12\x14\x0e\x12\x1d\x11\x13\x10\x1b\x1a\x14 \x19\x15\"6\x1f#%!# $%#&(&+)\x1e++$*,*0.\"-/,\x1c0Z120463/6B;8-8:7<>;C@4#Cx@B?AFHDFDKH<MH7\x00f\x00IJH\x00i\x01\x00j\x02LNK8P|0R\x95\am\x06PROYTC\x0fp\vTVS/Z\xa3\x0es\x18,`\xae7]\xad\x15v\x1c[]Zb]K9a\xab\x19y\x1e;b\xac_a^=d\xae@f\xb0*{!bdaBh\xb3efdDi\xb4fheMj\xaf.\x81.Fm\xb1qjROl\xb2Ho\xb3kmj0\x859Jq\xb5Kr\xb7npmMs\xb8;\x86:cr\x8fNu\xba|t]Xv\xb6sur?\x8a>Zx\xb8vxu]{\xbb_}\xbez|y\x84|dX\x80\xbfL\x91K`\x81\xbbb\x80\xc0}\u007f|\u007f\x81~c\x83\xbdN\x95Ue\x85\xbf\u007f\x83\x92W\x95V\x82\x84\x81\x8d\x84fg\x88\xc2m\x87\xbci\x89\xc3j\x8a\xc4[\x9aZ\x87\x89\x86q\x8c\xc1\x8a\x8b\x88\\\x9dc\x96\x8cnt\x8e\xc4v\x90\xc6g\xa0g}\x91\u008f\x91\x8ey\x93ɒ\x94\x91\x80\x95\xc6z\x97Ƃ\x96\xc7s\xa4l\xa1\x96x\x95\x97\x94\x83\x98ɂ\x9aė\x99\x96\u007f\x9d\xcct\xa9v\x86\x9b́\x9eΚ\x9c\x99\x82\xa0Ϩ\x9d\u007f\x9c\x9e\x9b\x88\xa0\xca\u007f\xabz\x8a\xa2̟\xa1\x9e\x9e\xa3\xa5\xa1\xa3\xa0\x8d\xa6Ђ\xb1\x85\xa3\xa5\xa2\xb3\xa7\x83\x91\xa9ԧ\xa9\xa6\x8d\xb5\x8a\x94\xac֙\xacѪ\xac\xa9\xa4\xac\xc0\x9e\xad͍\xb8\x93\x9b\xafԻ\xae\x89\x9d\xb1֯\xb1\xae\x97\xbb\x97\x9f\xb3ء\xb5\xdaµ\x90\xb4\xb6\xb3\xa3\xbf\x9d\xac\xb7Ң\xc0\xa4\xa9\xb9ٷ\xb9\xb6\xac\xbcܺ\xbc\xb9\xa6Ũ\xb1\xbd\u05ef\xbe\u07fd\xbf\xbc̿\x9a\xb1\xc0\xe1\xb8\xc0ձȭ\xc0¿\xb7\xc2ݹ\xc5\xe0\xbd\xc5ڲͷ\xc2\xc6ֻ\xc7\xe2\xd6ǝ\xc6\xc8ż\xc8\xe3\xbf\xca\xe5\xbdм\xc6\xcb\xdb\xca\xcc\xc8\xc1\xcc\xe7\xc2\xcd\xe9\xbf\xcf\xe2\xc7\xce\xe4\xca\xcf\xdf\xce\xd0\xcd\xc8\xd3\xc1\xc8\xd0\xe6\xdfѥ\xca\xd1\xe7\xcb\xd3\xe9\xca\xd8\xcc\xd3\xd5\xd1\xce\xd6\xeb\xd3\xd7\xe0\xd6\xd8\xd4\xd0\xd8\xed\xe7ج\xd5\xdb\xd0\xcb\xdb\xee\xd5\xd9\xe9\xd9\xdb\xd8\xd7\xdb\xeb\xd8\xdc\xec\xd2\xde\xec\xd5\xdf\xda\xd9\xdd\xed\xdc\xdd\xe7\xdd\xdf\xdc\xd7\xe1\xdb\xdb\xdf\xef\xd5\xe1\xef\xf0\xe0\xb3\xdd\xe1\xf1\xe0\xe2\xdf\xde\xe3\xe6\xd9\xe5\xf4\xe0\xe4\xf4\xe3\xe5\xe2\xde\xe6\xef\xe8\xe5\xea\xe5\xe7\xe4\xe6\xe7\xf1\xe0\xe9\xf1\xe3\xe9\xeb\xe7\xe9\xe6\xe3\xec\xf4\xeb\xed\xea\xe6\xee\xf7\xec\xed\xf7\xe8\xf0\xf9\xef\xf0\xfb\xf0\xf3\xef\xf4\xf2\xf6\xef\xf4\xf7\xf4\xf7\xf3\xf2\xf7\xfa\xf5\xfa\xfd\xf8\xfa\xf7\xfd\xfb\xff\xf7\xfd\xff\xf9\xfe\xff\xfe\xff\xfcA\x10\x8d\xd1\x00\x00 \x00IDATx^\xed\x9d\x0ft\x14U\xbe\xe7\awqv+\xfd^\xcc&O\x98\xe51\xd3@vaȆ\x82\x89M\"\x98`^\xc0\x13a} \b\x0e\x88\x99l\x1c=A\x98\xe1\xafg2\xcf3YI\x8eA\xf2@$\x98\xacsL\x00\xb3J\x88\x12\x91\x80\xae\xe6\x80ᨼ#\x90LD\x87\x93\x991\x83о\xc9L\xc4RQD\x12\xfb\xd4\xd9{oUu\xdd[\xa9\xbe71\xe9\xaa\xea\xee\xdf\xe7p\x92ە[\xb7nU}\xba\xeaVu\u007f\xa9\xef\xa9#@\x01\xe2\x9c\xef\x89\x14\xe0!j\x1c\x88u@\x0f\x80\x03\xe8\x01p\x00=\x00\x0e\xa0\a\xc0\x01\xf4\x008\xb8\xa7G_kMeM\x9b\xfe\xa2\xad\xaejG\v\xaf6\xe0\n\xee\xe9QW\xd5z\xaa\xa5\xb2\x05\x17{\x1bʛO\xb5\x94\xb7\v\xe6\x00\x1c\xc75=Z+\xbb\xd0\xcf\xf6\xca\x1e\xf4\xb3\xa1\xb2CQ\xbaʍC\t\xe0\x19\\ӣ\xae\x81\xfc\xaanQ\x94\x8e\xf2V\\\xec\xe1U\a\\\xc15=j\x1a\xb5_u\x8a\xd2\\\xd9+\xa8\f\xb8\x84kz4Uc'\x82U\xbb\xb0\"m5\xe5\xd5MA\xd1,\x80㸦GOU]W\xb0\xa3\xa6|\x87\xa2\xec(\xafn\xedh\xab\xde\x01\xc7\x10\xcf\xe1\x9a\x1e\xca\xf9\xba\xf2\xf2\xf2\xe6\xba\x1a4\f!\xe3Ӟ\xaaf\xd1,\x80Ӹ\xa7\a:\xb3\x9c\xefS\xaa\x9b\x14\xa5\xb1\x86\xbc\xd4\u007f\x01\x1e\xc2==ȩ\xa4\xbd\x1c]ҶT\xf5\xe1rC\x1d\u007f\x06\xc0y\\ӣ\xad\xbc\v\x9dP\xaa\xf1\xf5\xcbyraۣ\xdd\"\x03\xbc\x84kz\xb4\x97\xb7t\xb4Vב˕\x96\xca\x1644\xad\x81\xa1\xa9\xe7pM\x0f\xa5uWU]\xab^n\xaf\xa9\xda\xd5\x02vx\x0f\xf7\xf4\x00b\x00\xd0\x03\xe0\x00z\x00\x1c@\x0f\x80\x03\xe8\x01p\x00=\x00\x0e\xa0\a\xc0\x01\xf4\x008\x80\x1e\x00\a\xd0\x03\xe0\x00z\x00\x1c@\x0f\x80\x03\xe8\x01p\x00=\x14e\xcd\x1a\xbb\"\xa0\xb8\xa9G8D\xd9[]\xaeQ-\x9a%:\xfc\x9b\u007f\xa3M\x11\xb3Ǐȼ\xfb\xc4\xe0yF\x8f\x12\xb4\x88\xa9gE\xb5\xdc\xc2==\xc2!\xca`yK\a\xa2\xa5\xbcUq\x85\x92)\xef\xdb\x141=\xbf\xf5?qd\xcf\"\xff\x8b\x83g\x1a5\xce\x1e9\xb2\xc7\u007fDT\xcb-\\Ӄ\nQ\xb6ᯌ\x05\xf1\x97\x92\xdd\xe0\xacy\xc48\xcb\x1e<\x14\xe5\x041cѭJTy\r\xf4\x18\x04\x15\xa2\xd4^\xefr\xe9\xdbb\x91\x0f\x1e\x86\x1eO\xfa\xa3\x9b\xd0\x02=\x06C\x85(1\xe4\x9b\xc9npv\xf2F\x9b\xa2\x8e\xa6G\xc9LE\xf9\x85\u07ff\x17U\xf0ߎ\x8b\x93\xf7l\xbcu\xea݃\x06\f{\x17M\xbdu#2\xe9\xc4d\xbf\u007f\xa52\xd3\xef\x9fޫ\xf4\xac\x9c9y\xe6J4z\xe9˜\xfc\xeb\x993_\xdc8}Q\x10\xb7\xf0䚙\xd3W\xea-\x98z\x18-x\x06\xd7\xf4\xa0B\x94\x98]\r\xdc\xda\xd1c\xcd\xe4\xb36E\x9d\x13\xfe\x17\x82g7\xfa\x9fP\x94\xf7\x8fL~\f\xedȒ)h\xfc\xbaw\xb2?\xf3\xb1'\xa7\xae\xb4T.\xf1o|\xe1\xc9\xcc\xdb\xfb\x94\xbe\xd7\x1e\xf3\xbf\xa6\xfcֿ\x17Y\xf1\x82\u007f͋{W\xa2\x97ʋ\xd3\xfd\x1b\xef\xf6g>\x91\xf9$ia\xe6\x13\x8f͜\xaa\rz\xc3z\x84[\xf0\f\xae\xe9A\x85(\x11\xa7p\xde\xc5\r\xceN^cS48\x81/]\xfc%\xa4<\x05\xe9\xa1<6\x85\x14\xa7#\x8fJ2ٺ/\xf8\u007f\xab\xe0]\xbd\x17\xbf(\xb9\xe3\x8f3\x9f\xc0\x85\xe0^|0\xb8\x1d\xab\x94Y\x82\xea\xfc_\xa5\x04/e\xca-h\xcc\xf5\xe7\x99w\x909\r=\x98\x16\xbc\x81kzP!JD\xc3.A\xedh\xf1\v\xf3\x88\xf1\x8bA\a\x0f\xa4Ǔ\xaf\xbd\xb0h\n\x99N\xebQ\x12.\x9a\xac\xbc\xa5\xb7\x0f1\x93\xc8\x14\xbc=S?\xb8\xfcq\xcfݷL\xc7\xe7$%s/\xda\xf5Ae\xe3\xcfp\v\xe44\xb6\xc7\xffg\xfc\xcbЃi\xc1\x1b\xb8\xa7\x87\x19\xa2DT\xb5\xf0\xabF\x8b\xf7\xa7\xac\xb1)\x86!c\x8f?\xfb\xf7\xe02\xad\x87Y4\xb9ݯ\xa1i\xb1W\xdf\xe5\xafe\xceܸ\xf7\xc8\xddD\x8f\x17\x95\xd7&+\xba\x1e\xb8\x05刟\x9c]\f=\xd8\x16<\x81{z\x98!J\xfc?\x03\x9d\xe2W\x8e\x16\x1b\xfdgm\x8aa\xb4\xa1\xe9t\xb2/Ez\x94\xdcr\x82\xf0G\xfc\xe2\xfd\xcc\xc7f\x92\xc2\xedw\xe0\x93\xcbJC\x8f)\n{\xf4 \xff卡\aӂ7pM\x0f*D\x89\x87\x1e\xe7\x05գ\xc3\xfbSJl\x8a&\x9a\x1e\x99\x1bO\xa0q\xc4T\xb4G\xfb\ue22cNjژ\xe11<\xe4\xe8\xbd\xe31e\xcd\xddx\x889\x13\x1f\n\xfan\x1f\xa4G&\xb2&x\xcb\"2\xa7\xa1\a\xdd\x02\x1a\n=\xe1\x81{\xa9\xae\xe9A\x87(\x91+\xee\\\xcd\t\x0e\x1e\xf8\xca\x05\xfd\xbc{e\tڽ\x8b2\x9fx\xe2\x0e\xff\xe4ߞ@\x171%\xaf)'J&\x1fa\xef\x92l\xf4\xffl\xef\xde\x12\xb4\x8b\x83G\xd6d\x9eU\xceN\xdfx\xa4Wy̿r\xcf\x13\xb7\xa3\v\x96\xd7NL\u007f2\xb8w\xf2\x89\xe0\xcf\xf0\x15\xf1\x14\xff\xed{\xf7܊G\xb8\xe4\xae\xe9\x93G\x8e\x9c\xa5[\xc0\xac\xf4\xc2I\xc65=\x98\x10\xe5)wF\xa6\xefO-\xb1)\x9a\xecE\x03\x01\xf4V>qk&\xb2\xe4\xec\xa2)S\xef\xfe\xb5\u07fff\r\x9a:\xf9\xc4T\xf4\xd32Xy\xf1\xee\xcc\xe9\x8b^\xc0G\x01\xbf\u007f#\xda\xd7~t\xec\xe9{\xf2\xd6)\x99+\xf7\xdc:yQ\xa6\u07ffw\xaa\u007f\xea^2\xb6\x98\xb2\xb1d\xfa\xcc\x12\xacW\t=\xe00Z\xc0\xec\xc9ܣ\xb8\x8e{zx\x80_\xfb\xffͦ\xe8\x04\xda\xd0\xd4\xfb$\xb4\x1e\xee}\x92\x0fz\x00\x1c@\x0f \"\xda\xe06\x16\x00=\\\x80\fn=p\xd9*\x06\xf4\x008\x80\x1e\x00\a\xd0\x03\xe0\x00z\x00\x1c@\x0f\x80\x03\xe8\x01p\x00=\x00\x0e\xa0\a\xc0\x01\xf4\x18\x16/\xad\xfaPQ\xceOK\x98\x87\x03\xb8\xa7\a\xf5$ʞ\xa6]\x95\xbb\x9a\xbc\xf7\xb0\xb0Wg\xc8\x1a\x81w\xb4\t\xb5r\xed\xa7\xe8\xd7\xe6\xa4u\xdc\xf9\xe2\a\xf7\xf40\x9fDy\xbe\xba\xa6\xad\xa3mW\xb5;\xdf\x18\xe3\xf0\xf1\xab\xf9\x0f\xbd\x8a8 \xbfB^?#\x1f\xd0\xfeP\x97\xf4\bg\xb68\xc25=\xa8\x10e#y\x0eT\xef\x0e\x97R\x94<\n\u007f\x85\u007f\xfeN\xd3\xe3wY\xbf\xe9\xeb\xeb\xeb\xc5\xdf\x11|\xc0\xe7R\xf0\xc2a\\Ӄ\nQ6h\xa7\xf2\x1a\xb7\x92P\x1c4=>}\xe6c\xf4\xb3\xfd\x1f\xfe\xd3?Κ4q\xe2\ndtϸ;\x05s\xc6\a\xae\xe9A\x85(\xcfW7v\xf5v5V;\x1f\xa3\xfc\xf4\xc0\xaa\xecſ\xc1\xfb^\xf9xӼ\xf9\xbf\xf9ͼ\xec\xe7\x99\n\x9a\x1e\x84^\xdf\u007f\xce\xc8\x18\x93\x9c\x91>\xe6\x81 :|$\xbb\xf3\xedX\x87qM\x0f:D\x19l(//opa{o\x92\u007f\xf3\xca3\xf9\xf7\xa0\xe1構\xf3\x9f\xa9\rd?\xf3\xd03L\x85\xc2M\x1f\u007f\xfc\xcc*R\f\xfe\x87u\xaa\xdavU\x1d\xb8a6\xf2\xb8IJ\x88'߹\xa6\a\x15\xa2\xecm\u0601\x86\xa6;\x1a\x1c\x8f\xe8\xbfD\x86\x9ao\xca\xe8\x88\xf1\xbc\xfc\x0e\x1ez\xbec\xa9Q\x88\xaf[\xf2I1\xf8\x0fcƌQ\xf2ƌ\xb9a\x1d\x1aCwH\xee|{\xdaa\\Ӄ\nQ6\xed\xc0\a\x0e\x17\x86\xa6\x9b\n?\xfd\x1bb\xfe&E\xd96W\xc1CЗ,5\n\x1fz\xf3\xcdM\x9a\x1e\xca\xff\xf9/\xff\x88\xf4\x18;g]{/\xd6c\x87\xb5\xb5x\xc4==\xcc\x10e\xa5\x96gh\xad\x14\xd4\x1fu\x96\xea\xb75\x1eB\a\x8e\x19h\x04\xf2\xca\xe0\xa3\a\x1a{\xbc\xa3\x9fo\xfe\xdf\xff\xf8_H\x8f\xa4\xd6.|\x94k\x96\x1c\x97\xd9\r\xdc\xd3\xc3\fQ\xba\xa6Ǧ\xc27\t\x1f\xe3\x03\xc7C\xbf{g\xf1\xaaO-5\xa8\xa1\xa9\xf2q\xe0\u007fb=\xdaI\xc7\xd7\xf9\xbcw\x17/\n\xb8\xa6\a\x15\xa2l '\x97\xe0\x0e\xc7/l_\x91\xc9uʶZ<\x00)\x90\xe5\xa2\x0f\xf5?\x9cZ\u05ee\x15h=\x94\xf5\xff-\xacG\xdf\xc4YJ\"\xe0\x9a\x1eT\x882\xb8\x83\fMw8\u007f\xe9\xb2mƦ\xe7_ڄ%y3\xf0\xca+\xaf~h\x1c<fKd\uf4fb\xa6\x1f\x87k\xff\uefc6\xf5\xd8,\xb5\fn-\x0eqM\x0f:D\xd9ۼ\xab\xaa\xa6\xd9\xf1\v\x17\xc4+E\xf3\xe6\x16\xe1[\xa2\xaff\xe1AHV\x916\xf8\xa8J+ǿ\xc8g.ԍ\x90\xf0ɥ)y\x85]k\xf1\x87{zx\x8a\x0f\xb3\u007f\xf5\xe1\xdf\xfe\xf6\xf1\x9bks̓\xc5`\xfeU\xd7c\x87\xefN7\\v\x01Ѓ\xf0\xd2\\\xed\xbc\xf2\xe9\xbcW8\xb5vhz\x9c\x1f\x97(\x1f\u0602\x1e\x1aoꗴ\xef\f\xba\xb4\xd5!\x17\xc0x\xec\xf1\x1f\xff{\x82\x1c8\b\xa0\a\xe1\xd3Mٿz\xfe\xd5\xe7\u007f\x95]f\xbd\xb4\xd5\x01=\x86\x8f\xa8\xf1\x18\xe2ӗ\x1e\xca\xcf\xca\u007f\xe8\xa5\bvh\xec0\xef{$\b\xa0\xc70\x00=\x86\x85\xa8\xf1x\x03\xf4\x18\x16\xa2\xc6\xe3\x8b\xdeGoCzܸ\xba)\x81\xfc\x00=\x86\xcc4\xe3\x03}\xb7\x1e\x0e\xe0\x02\xa0\xc7P\t\x8e]\xa7\xaaWUu`\xec\x1c\xcf}g:j\x80\x1eC%(I\x19\x19c\xd32\xd2\xc7\xdc\xe9\xfc\xb7\x1e\xdd\x02\xf4\x18*\xbdM\xe3RS'\xa4\xa6\xa6f\xb48\xff١[\x80\x1eC\xa6\xb7\xa3\xbd\xbd\xfd\x14\xfa\x97\x10\xdf\xf4\xd0\x00=\x86\x01θh9\x97D\xc1==\xa8\x10%U\x04<\x85{z\x98!J\xba\xe8\t\x1a[D5\x12\x05\xd7\xf4\xa0B\x94T\xd1\x1b\xa4\xe7\x89j\xe8\x8c\x19}D\x8bt\x16\xd7\xf4\xa0B\x94ևR\xbaN\xfam\xa2\x1a:c.\x8e6\xa0\x87\x06\x15\xa2\xb4<\x94\xd21Z\x93$\xe9\x81\xf6\x05\xe3\x93g\xe1۠\xd5Ӓ'\xe0\xf8l\x9d\xa4\x91\xae(K\xa4\xa4j\xe5\x94O\x9a\xc8\xd4ES˗MH\x9e\xd5\x01z\xf0\x115\u0383\nQZ\x1eJ\xe9\x18\xc1\x1d\xd5\xe3'\xa4\x8c[\x96'\x9dR\x94;\x93\x96\xd5=\x92\x96ާ\xf445N\xc8hllDC\xe5\x8eƤ\x87\x15\xa5y\x81\x8f\xa9\xdbV\x9d$\xa5=\xbc9e\x0e\xe8\xc1G\xd48\x0f*D\xc9>\x94\xd2Qҥ\f\x9c\xb7\xc7nj*\x05\x87\x9bH\x1f̓\x8b\x0f\xe9\xa1<\xecc\xeb*\xbeTt\xe4X\x90\x06z\xf0\x115΅z\x12%\xf3PJGI\xf7\xe9\x0f\xb1\xcb\x1bߋ\xd1\xfe_\x86\bz\x18u\x15\xdf\x02}\xea\xf0\xf5\x18C\xfeq\xfe\xaex\n\xf7\xf4`\x9eDI\x15\x1d%=]/L\xd2G\x1cs\xc8T{=\x8c\xba\xe6T\xbc\xa7\x9f\xbaI\xdb\xdfڅ\xc7X\xaa`\xbb\xfbA\x8f\xa1A=\x89\x92~(\xa5\xb3\x84E\xc8\x1b\xdfB\xe8\nO\xad\xc4\xc7\n\"\xc2\x03>\xb6.\xab\xc7\xcdOQ\xfb\xfb'\xf7Z\v\x16@\x8f\xa1A\x85(\x99\x87R:Kx\x977h\xa3\x8e\xfbID!#CQ\xbaȄ\xe4Պҗ\xceՃ\xde\xdf/\xdfx\xceR\xb8\xf8\xf8Mcn\xfc%\x9a\xf0\xa3\xb17\xfc\xe8ݰ\x1e\x8f\xff\xfd\x98\xef\xff\xf3E\xaa\x80\xfe>\xe6\xa6\u007f\x01=\f\xa8\x10%\xf3PJ\a\xe9m&\xd7(ڈb\xb5\x94\xb7\xab\xe6N\xa9\x1a\x97\x1f\xf6m\xae\xc9H\xc6\a\xb3ii\xeb\xd6M\x93\x92\xaaڨ\xba\xe8zfA\xb3Ҳ \xa9\xb1êǏ\xef\xb5\x16\x1e\x1f\xfb\xf8\xb9\x97\u007f|\xf1\xe2\xdf=u\xeeݟ\xfc\xd8\xd0\xe3ٿ{\xf6\xdc\xcb?\xf8g\xaapӽ\xef\x9e{\xf6\x87\xa0G\x18*DI?\x94\xd2A\xf0\xbd\f\x84\x1e\xa6n\xc8HM\xcd\xd0n\xbd\x04\x97\xa5&g\x90\xff\xfd\xa7=#9e\xd6\xfd\x92\xb4\x84\xaa\xbb\x04\xfdNjKF?\x97X\xf4\xb09x\xe0#\x82\xc1\xbb7\x1az\xdc\xfc\x1cz\xf9\xc6\xf7\xa9\xc2\rohu@\x8f8¢Ǐ~n-\\\x1c\xf3\xae\xf6\xfb\x8d\x1f\x8eE\xe3UC\x8f\xb1\xda\xf0\x95*\xfc\xd3؟\xfc\xf2\r\xd0#\xbe`\xf5x\xce8f\x84\vh\xff\xebz\xdc\xfcOo\\<\x17\xd6c\xcc\x1b\x86=F\xe1\xe2s\xf7\xfe\xe8\x86{A\x8f\xb8\x82\xd5\xe3\a\xbf\xb4\x16\x90\x16\xfa\xc9\xe5\x06$̳a=n6\x8e.\xe1\x02\xe6\xe5\x1b@\x8f\xb8\x82\xd1\xe3\xd9\xef_\xb4\x14\x10Oݨ\rMo\xba\xf7\xdcs\xdf\x0f\xeb\xf1\xd4\xd8_\xbe{\xee\xa9\x1fP\x85\x1f<~\xee\xdc\xcfo\x02=\xe2\n,\x86>x@G\x02\xe3\x98q\xb3y\xf0\xb8x\xf1_\xfe\x9e\\\xd8>\x87\xaeo\u007f\x1e\xd6\xe3\xe2S7\xdf0\xe6槨\xc2\xe37\x8f\x19\xfb×A\x8f\xb8\"<(\x1d5@\x8f8\x02\xf4\xe0!j<\xee\x01=x\x88\x1a\x8f{@\x0f\x1e\xa2\xc6\xe3\x1eЃ\x87\xa8\xf1\xb8g\xcc\xe8#Z\xa4\xb3\x80\x1e\x00\x87\x98\xd0#OJ]\x00))7\x88\t=:\x1a\xab&\xa6z&\x05\x93H8\xafG\xa3q\x1c訩j\xe8\x18T\x8c@\xa3\xe4\xc2'\xfe\x80\xe3zt\x95\xb7h\x85\x8e\xca\xc6\xf6\xc6\xca\x0eK1\x12͉\xf1\xf4%\xaf\xe1\xb4\x1e\x1d;t=\xfa\xc87\x8f\x9b\xaa\xfb\x98bD@\x0fWpX\x8f\xc6\xf2F=j\xddVI\x1e\xc6P\xd9\xc6\x14#\x02z\xb8\x82\xc3z\x04\x83F\x94\xb6A\xfb\xde^]#S\x8cH\xab\xe4\xc67\x95\x13\x1e\x87\xf5P\xc2I\xeb\x1a-\xd5\xd2T\xc3\x14#қ:\xad\xa9#\x91\xfe\xe3\x15o\xe0\x9a\x1e\xfa\xaf\x96j\xa6\x18\x19\x9c\x8c\x9eͫ\x00D\x01\xd7\xf4\xd0c\xf9\x8d5L1\"=i\xe3\x1fi8\xa5\x00\xce\xe2\x9a\x1e\xfa\x80\x03?\x19\x9d*F\xa4Yr\xfcIs\x80\x8bz\xb4\x95\xe3۠=\xe5mL1\"p\xe5\xe2\n\xae\xe9\xd1GB\x93\x8d\xda}\x8fp1\"\xa0\x87+8\xacG\xb0\xa3\xa3\xaa\xb1\x83\xe4\x9c\xe1\xaei\f\xe0\xb0\x1e-\xe5\x04\xf2\xf1ZGCe\x8d\xf1\x99\x8bY\xb4\xa3\xb7\xa3%\xcf\xe7B~\x1fpX\x8f\xef\xc6\x1cI\x1a\xef\xc2\xff\r\x03Ć\x1e\x1d\xadp\xe8p\x87\x98\xd0\x03p\v\xd0\x03\xe0\x00z\x00\x1c@\x0f\x80\x03\xe8\x01p\x00=\x00\x0e\xa0\a\xc0\x01\xf4\x008\x80\x1e\x00\a\xd0\x03\xe0\x00z\x00\x1c@\x0f\x80\x83\xf3z\u0605(\xa9\xa9\x80\x97p\\\x0f\xbb\x10%5\x15\xf0\x14N\xeba\x17\xa2\xa4\xa6\x02\xde\xc2a=lC\x94\xd4T\xc0[8\xac\x87m\x88\x92\x9a\nx\v\x87\xf5P\xecB\x94\xd4T\xc0[\xb8\xa6\x87%9\tzx\x12\xd7\xf4\xb0$'A\x0fO\xe2\x9a\x1e\x96\xe4$\xe8\xe1I\\\xd3Ò\x9c\x04=<\x89kzX\x92\x93\xa0\x87'qX\x0f\xfb\x10%5\x15\xf0\x14\x0e\xeba\x1f\xa2\xa4\xa7\x02^\xc2a=\x80\xd8\x02\xf4\x008\x80\x1e\x00\a\xd0\x03\xe0\x00z\x00\x1c@\x0f\x80\x03\xe8\x01p\x00=\x00\x0e\xa0\a\xc0\x01\xf4\x008\x80\x1e\x00\a\xd0\x03\xe0\x00z\x00\x1c@\x0f\x80\xc3\xf7\xee\a\x80\x88\x8c\xe8\xe8\x01\xc4;\xa0\a\xc0\x01\xf4\x008\x80\x1e\x00\a\xd0\x03\xe0\x00z\x00\x1c@\x0f\x80\x03\xe8\x01p\x00=\x00\x0e\xa0\a\xc0\x01\xf4\x008\x80\x1e\x00\a\xd0\x03\xe0\x00z\x00\x1c@\x0f\x80\x03\xe8\x01p\x00=\x00\x0e\xa0\a\xc0\x01\xf4\x008\x80\x1e\x00\a\xd0\x03\xe0\x00z\x00\x1c@\x0f\x80\x03\xe8\x01p\x00=\x00\x0e\xa0\a\xc0\x01\xf4\x008\x80\x1e\x00\a\xd0\x03\xe0\x00z\x00\x1c@\x0f\x80\x03\xe8\x01p\x00=\x00\x0eC\xd1#\xb8.=%)\xed\xb6\xa6\xc1\u007fyT\xbaS\xff1\x02\x066\x8f\xf7\x8dk\b\xbf\f\x0e\xa0\x1f\xd5\xd2mf\x85]Ҝ\xc1sQ<\"-\xe3\xfe]@\xc4\xe6-\x1d\x13@\xfa-ꪀQٞ\xa3\xc9\x10\xf4\xa8J\x924f]\xb5\xfeiTVg3n\xbb\xc5x\xf5h2^\x8a'\xf4`;&@뷨\xab\x02Fe{\x8e&b=VHҜV囮\a|Rƀ\xe5o\xa3\xb2:\x93\xa4\x15\xdf\f\x18-\x0fH\xd2 =:\x1em\xb4\x9b/\xcc\b\xf5\x88\xd8<\xd31\x01z\xbfE]\x150*\xdbs4\x11\xea\xd1(I;\xb4R\xab$UY\xfe8*\xab3Nj7_\xd8\xe9!b\x84zD\x84\xe9\x98\x00\xbd\xdf#dT\xb6\xe7h\"\xd2c \xcd\xdc\xf6ˤ\U00056fce\xca\xea\xa4I\x1d\xe6\v/\xe9\xc1tL@\x82\xea\xd1,IA\xa3|\xfeQ\xf2nj\xce\x1b\xe7K\x9e\xf8\x80\xa2\xb2\xab\x13\\1ޗ:\xa7U\xabJ\xbf\xe8Y2>)eZ\x15s\x94\xeeZ2.)u\x0e>\xafO#\xc3\x1ac\xff\xae&\xaf:\xb0\x1eʊq\xbe\xf1\x0f\x98't\xbbf\xdaf\xa7\xa6\xccj\xc7zTK\x13\xb5I\x9bɋG>'s\u007fN&Q\x1d\xae\x96\x1e\xed]\x92曄\x06\x9c\xd5\x13}i+\xa8\xf1B\xcfj\xdc\xe5\xb6p\xdbFnj\xbd\xf5\x88\xb4D\xb5\xb6\x1c\x9e\xc7\xe8\xb7ޖ\xb9z\xd69t\xe8\x85\xd9oω\xd2j\xd5}Dz< M\xb0LY&I\xe3&\xa5\xa1\x1f\x9f3\xabӚ,\xf9&\x8d\x97\xa4u\xaa\xe5EW\x8a\x94\x9a>\x01\rl\xa96꒤\x94t\xd4\x06\xda\x02\xeb\xf2|Ҭ\xbc]\xfa\x1fj\xf2$鶼 ڨh\x11i\xa9\x924q@\xdf\u007fv͔KR\xda$_R\x06ډ\x9f'I]d\xda\x04\xa9\rͽb\x9c\x94\x82\xe7\xfe\xc6\xd2\xe1jiY\xaa\x94擤\x86%\x92\x0fM\xcbP\r=\x9a\x92\xb5.\x85\xafό\x8eY\xf4\xa0[6\xe71\xfa\xad\xb5E\xad\x9ee\x0e\x1dza\x11\xb6gl\xe81[Z\xc0Nh\x96\x92\xf1A\xa1-Ez\x94^\x9d`\x8a\xb4\x1a\xad\u007f[\xaa\xd4`y1Gz\x00\xed\xe2S)\xe6\x86WO%I\xebд\x06\x9fT\xadF:\xb9H\xe3ѡ\xaa9I\xaa\xd1\xf7\x9f]3\x92\x84\xb4\xfa|\x169\xf8ܦ\x89y\n\x9f\x00\xd1\xdc\x13\xd0;\xb3ɇ\xff\xcet\x18\xfdeb\x97:\x90'\xf9|u\x03j\x83$\x9dқ\xefM\xc1\xed\x0fl\x96|\xe6\xbb\\\xeb\x98E\x0f\xaaez\x1e\xbdߤ-f\xf5\x989t\xe8\x19#lO\xb5\xae\xdc<\x90\xb9\x87H\x8fiV\x89WK\x0f뿗ѫ\xb3Z\x9aM&\xd7\xe1\xa3\r\xf3b\xbc\xb6\xf7+\xf3\x9a\xc3mܦo\xf1]R\xea@D=\xc8\xc1`\t^\n\xd9\xe66\xcd,\xd0\xfav\x95\f\x8f\x9a\xb4\x81\xd1\xfd\xd8\x124\xf7ym\xee%\x96\x0e\xeb\xedvI\xd2f<m\x1a\xdeg\xa4\xf9\x87\xf5\xc3R\x06\xb5\x17\xed\xf50[\xa6\xe7\xa1\xf5`V\x8f\x99C\x87\x9e1\xc2\xf6\xf4\b\"=fI+,S\xf4K\xbd\xcd\xe15!?\xc6I\xda\x15\xdd7IR\x0f\xfbb\x964\xad\x8d\xbd:\x1cH\xd6/\t\x06RЙ \x82\x1e\xdaP\xa2\x12\x0fQ\xc96\x1f܌\x9a\x82\xdf\xfb\xaa\xbeeQ[\xedd$}\x9e\x9e;Oe;\\\xad\x9d+\xbf\x91\xb4e\xe6I\x95z\xf3\x13%\xed\xfeWo\xafپ\xad\x1eT\xcb\xf4<\x94\x1e\xec\xea\xb1}\xd1`\x16f\xbf==\x82H\x8f;\xa9\xb5\xd2\x19h۵.\x0f\r,\x16P\xabsU\x92&M#$I-\xcc\v\xb5\r\x9d\xe9S\xf2j\xa8\x91YP\x92\xf4\xf3p\x06>w\xd8\xeb\xa1\x1d\u007fj\xf0o\xb2\xff\x067\xf3\xb9\xd1L\r\x19ٮ\xc0ǒ\x16)\x9d\x9a[\x1f(R\x1d\xae\xd6\u07b7h)x$\x88\x8e?\xe5z-\x9f>t\xa1\xb1Ճj\x99\x9e\x87҃]=K_\b\xec\xc2춧W\x10鱙\x1e\x9a\xb6\xe2-P\x99\x86\a铦1\xab\xa3H&\r\xcc\vt$_\x90\x8c\nI\xcb\xc2C\xb3\x0e)I/\xcd\xc6wRx\x17\xb6\xa6\x1e\x83\x9b\xe9\x91$\xad\xd0H\xf4h\x97\xd2\x06\x90\xcd\xd5\xd4\xdcڌt\x87\xf5\xbf\f\xd2\x03\x1dN\xa8Æ\x8e\xad\x1ef\xcb\xcc<\x94\x1e\xec\xea\xb1}!\xb0\v\xb3ݞ^A\xa4G\a\xb5*=RR;\xbeӼ\xa4\xee\xd4U\xf4\xdbr\xf48\x1f\x9e\x87y\x81\x19h[7I2W\xba'\xfc\xf6\x9a\x16\xf9\xe81H\x8fA\xcd|n\xdcj\xa8Ӯ\x8b'H\xad\x03\xc9I\x9f\xab\x16=\x98\x0eG\xd2C\x95\x84G\x8fuV=\x98y(=\xd8ճу\x99\xd1~{z\x05\x91\x1ehH\x18\xbe\xe7\xb4\x1a\r\xb5\xd0\xf9T\x1b\xbb\xad`W'M?\x9d\xaam=\x03신6\x02\xaf\x96\x92\x8c\xa1Ào\bc\x0f\xab\x1e\x83\x9bQS\xf5f\xd6i]\xdc,\xadn\xd1\xf6\x01\xbdK\xd8\x0eG\xd4c\x82>\\j\x98Ui4\xafw\xac\\?\xbd.\x19\xa4\a=\x0f\xa5\a\xbbzvzP3Fڞ\x1eA\xa8G\x8d$\xd5i\xa5&\t]{)\xba\xf9W\xc7\xe1\xadf\xae\xce\x12)\x9d\xec\xb6f|\xb1F\xbfP\xf4=\xd1E\xedWch_#\xa5|3D=\xec\x9a\xd1/\x06\x06t\x83\x83\xd2\xf8՚\x97\xf4.a;\x1cQ\x8f\xd5\xfaޛ\xad]\xd2\x10\xb4\x8e\xd5i\xa7Wt}dՃ\x9e\x87҃]=;=\xa8\x19#mO\x8f \xd4C\x9d\x83\x06MmW\a\xba\xee\x97\xf0Gr\xc8v|5\xd97K\xc2;\xce\\\x9d.\x9f\xb4\fm\x9f\xf6T|\xa5ü\x98%\xcdB\xbb\xe2j\x1euC\xebT\x92\xb4\x19\xed\xe4\xc6d|\xe1`\xb9w\x9d$5|3`s\xf4\xb0i\xa6\xc7'=:\x80'\xe9\a\xb8\f)9\x85\x1c\xd6-G\x0f\xaa\xc3\x11\xf5\xe8I\xc6]\x1axDJV\xc2\xedk\x1dC\xe7\n\xf4\x97\x9e\fi\x90\x1e\xcc<Z\xbf\xc9tf\xf5\xec\xf4\xa0f\x8c\xb4=c\xe4\xbe\a\x1aH-0\x86\x99\xb3\xc9\xc8T\x92\xc6\xcfNOJyX\x9aĬN\xa3O\xf2Ớ\xe4S]\xfaE0U\xf2M\x9c\x94,\xa5\xf5\x98m\x92ۊ\xe3$\xed\xa2\x99\xd5#]\xc2\x1f\xa2ۜ\\l\x9aiH\x92\xd2ғ\xa5\xdbt=j\fO\x98]\xc2t8\xa2\x1e\xf8\xbeUJz\xaa\x94D}\xabE\xef\xd8\x12t\xc94NJ\xde<H\x0ff\x1e\xad\xdf\xdatz\xf5\xec\xf4\xa0g\x8c\xb4=c\xe3\xae)\xa6m\xc9\x04_\xd28\xe3~TsF\x9ao\xe2ß_\xf5\xa11+}0\xecY6ޗ\x9c^\xa9\x1d\xfa\xe9\x17\xc1\x15\x13|x\x0e\xbaɎ;\xc7\xf9\xd2nӾK\xc1\xeaѕ\xe1K\xa9\xb3\xd1þ\x99\xbc\xb4\xe4i\xcd\r\xba\x15\xa8K\xda;\x8e\xdd%t\x87#\xebA>'I[@wE\xef\xd8@\xf5$_j\xde\xf9\xd6\xc1z\xd0\xf3h\xfd֧S\xabg\xab\a=c\x84\xed\x19;z\xc4\n\xc1A\x9f(\x03#$\x9e\xf4\xd8L\r+\x81Q!n\xf48\xdf\xdb\xe0\xf3\x99\xc3J`T\x88\x1b=\xf0\x00\x1a\x0e\x1e\xa3M\xdc\xe8Q\x99\x9c\x06v\x8c:q\xa3\a\x10\r@\x0f\x80\x03\xe8\x01p\x00=\x00\x0e\xa0\a\xc0\x01\xf4\x008\x80\x1e\x00\a\xd0\x03\xe0\x00z\x00\x1c\xdcУ\xa2BT\x03\xf0\b#\xd5c\x9b,\x1f\xa3^\x9e\xce?\x19\xb1\xaa\xc1_\xe5ݢ*\xa3\xc1\xdb3d\x8d\xfc\x90\xa8*C\x05\x9a%\xfb\xb2\xa8V\x820R=\xaetf\xd5S/O\xe6\x1c\x8fX\u0560,p\x05\xff:\xf3'QE\x13a]\x9b\n\xfd\xefeUt\"v\xcb_\xd9\xcc\x10\x99+\x9d\x9d\a\xe5ߋj%\b#\xd5CU\x03\xb4\x1e\xaa\xf8\x9dzy\xc6N\xf2\xbb\xa8LP\x91BX\u05f6\x82ֳ\xa3\xf25\x9b\xbfq\xe9\x06=tF[\x0f1[\x03_\x92\xdf\xf7\x89v9\x85\xb0\xaem\x05\xadg\x97w\x8a\x95\xb5\x00z\x18\x88\xf4\xb8^V\x98U\xb8\xe1\x02*]Ȓ\xe5\xda\xcbe\v\xb3\xd7~\x8b^]\xdeR\x90\x95\xbf\x1e\x9f%\x02\xbbw.\xcd^\x8bKײe}$\xf2:*ԫ\xf5\xe8\xe7\xeb\xe8\x80r\xb48g\xe9\xce~\xbd\xc1ϲ\xb6\xa3\x9f'\xf5q\xc1*\xce\"\f\xe8\xbatc\x9dk\v\xb3\n\xd6/\f\xb1\x15(\xc2\xe2\xfe\x05\xb5\xbb!T(˹!si\xdf\x16d=]Xxf{n\xe9u4\x82\xca:XQ\x98\xbbA\x1fr\x84\xf5`\xbb\x9e\x80\x88\xf48)W\x9cy}\x83܍\xce\xe5\xaf\x1f[\xb88\xa7pgٌ/й>g\xd5\xfe\xd3\xf5\xf2\x01T# /=v\xbc`\v\xae\xdc\xdd٩\xed\x92\xeb\x9dsk\xbfR\xbf\xaa\xcd\xed\xbc\x8e\xc7z\xdb\xdf:\x98\u007f\x9f\xfe\x1e\xae\xc8\xc2&\xf5\xbf\u05f9\xf8A40\xf8k\xe4E\x84\xa1\xebR\x8d\xfda\xc6\xd6\xe3\xa7\x0f\x15\xc8߲\x15(\x02\xb5\xfd\xfde\xf8L\x16\xfa\xa0^\xfe@=:\xe3\xe8G\xf4\xd2\xce̕w\x96\xca\xf3\xf6\x15\x1cP\xffr,K^\xb8\xaf~a\xf6%2cX\x0f\xb6\xeb\t\x88H\x8f\xfech\a\x87\x96o /\xee\x93\xd1;-\x84&\xf4\x17\xaeE\x9b,\xf4:>\xab\a\xf2\xbfF\xdb1_\xaf\x9f\xad\xbfc+\xf0Ѿl\xab\x8a\xf7\xc7Q\x15oq\xed\x02糬mz\xcd\xf0\xf9\xc0~\x11\f\xe1\xbaTc\a\xf3\xf1!\xe6`n\x88\xa9@\x13\xc0\x87\x94\xf5\xa4\x18\xdaZt\xadp\x1f.QK\x9b_\xa6\xbe%\x9fT\xb7\xe2\xeb\xec\xc0B4\xf9Za\x11\xa9m\xe8\xc1v=\x11\x11\xe9\xa1^;\xb8\xf6\xae\xb9\xf2rR\xbe/\xa0\xbf\xabߖ?\nW\b\xe0\xad[\x1f\xd0_\x19z\x9c\xc9\xeeW\xfb\xb3;Q\xa9\xec\xaeз\x88B\xedfǶ\xac\xcf\xf4\x9a\xe6\x1e\xb5]\x04C\xb8.\xd5\xd8\x17\x85\v\xb7\x1f\xfa(\x14b+\xd0\x04*\xba\xbbu\xeb\xd4\xfe\x9f\x16\xacת\x9aK\x9b\u007f\f\xed\xfa~u7\x9e7@.\xb6\x0fj\xc3XC\x0f\xb6뉈H\x8f\xee\xfc\xc2\xdd\xc7;K\xf5}W\xa4O= \x9b\xe7cr:\x19\xa4Ƿ\x05\xc7\xd5\xe3\x05x\x87,\xd7G\x06d?]\tl5\xe6\v\xefQ\xfbE0\x84\xebҍ];T\xb6T.\xd8\xcf9z\xa0\xbe\xbc}Z\u007fq\\~\x8f\xfc\xa6\x966\xff\xb4ڝ\xa5\xeaz\x90~w\xca\xe4\x02\xd9Ѓ\xe9zB\"\xd2ci\x11\x16a\x8b\xbe\xef\xb6\xe8SO\xcb\xe6}\x06{=\xd4\xed\x1b\xd4-x\x10\x8aނ\u007f\"\x90\xf7\xe5N\xd98xh{\xf4\xf0\x17\x91\x16\xc1\x10\xaeK5ֽ\x1b\x89q\xedX\xf6A\xa6\x02\x8d>4\xbd\x80\x97|e~\xed¯\xf1+jiX\x8f\x80\xa1\a\xb9\xda>$\x93Ӛy\xf4\xa0\xba\x9e\x90\x88\xf4(Ļ+\xf4S}\xdf\x19\xef\xd1\xeb\xf3K\xf1\x9bv;ަ\x11\xf4\xf8 \xf0e\xe0\x03\\8\xad\x9d\xbak\xf1\x99\xffK\xf3ࡖ\x96\xa2\x9d\x86\xfff\xbf\b\x86p]\xaa\xb1z\x99\x1c\x18J+\x98\n\x88\xcf\xf6\xe9\n\xeaz\xccG\xe7\x8dPQ\xadZA\xfaL-\x8dѣ\x00\x0f\xa9\xee*%s\x18z\xd0]OLDz\xd4\xcbe\a\xf7݇\x8e\xe1\xdd\xdf~@\xae\x0f\xb4M\u007f&pϡ\xb7\xb7ˇ\xd5/;\xb3*\xbaC\x1fUdu~\xa9\x86~\x8f\xae\\*:;\xc9;0T\xb8\xb6P;\xd9\xef\x9eQv\xfcx\x05\x19\xe5\xed\x9caޭ\xae\x0f\x1c8^\x9a\xf3E\xc4E0\xbd0\xeaR\x8d\xd5\xcb9\xb5'Q\xf1\f[AU7h\xc3Q\xe3\xaei\xe7ܝ\xfd\xefm˿\xa2~6w\xfb{!ji\u007f\xc9=\xd0\u007f,\xebB\u007fY\xe9\x15<\x8c]u\xec\xf0\xe2\xdcOИ\x06\xdf5=\xd0\xd9\xc9.-A\x11\xe9\x11:\xb08\x90_vxqV\xe9\x05\xed<\xac]\t\xa8\x9f\x94\x15\xe6\x14\x1d'\x9f\xb9\xc8Y\xff\x9e\x83~nS\xff\xa0\x9f\xaa\x0f\x91\x1a\a\x02\a\xf46N\x97\xce\xcb-~[\xc57F\xa8cCh{n\xf6\x83ݜEP\x84\xebR\x8d\x1d}\xb0\xbe0k~\xe9\x19k\x05\xf5p>\xe9\xc0۲\xc1\x81\xd3\xe8\xc7Nu\xbb,\xcf8c.\xad\xb8@\x96\x8f\xe5\xc89\xc7\xc8\xd8\"\xb0\xb3bna\x19\xbea\xb7U\x9f\xab\x8cYZ\x82\"\xd2cTyZ\xb6ޚ\xf0\fý\xf7\x9b 8\xaa\xc7\xd6a\\!\xf6\u007f\xa6\xe1\xd0-K\xd0\xc3\x16G\xf5\x18\x0e\x0f\xea\xc7\xf8\aE\x15G\a\xd0\xc3\x16\xcf\xea\xf1\xc9I\x8dOD\x15G\x83+d\x80-\xaa\x95\x80xV\x0fG!\x03\xec\xc1\x17L\x00\xe8\x01p\x00=\x00\x0e\xa0\a\xc0\x01\xf4\x008\x80\x1e\x00\a\xd0\x03\xe0\x00z\x00\x1c@\x0f\x80\x03\xe8\x01ppC\x0f\xc8\xd8\xc6\f#\xd5ct2\xb6C\x99m\xb8\x8cj\xc6\x16M\xc4\xdf^9 \xcbV\xb5\xa3\xd1u\xef0R=\xbe{ƖF4\x9b\xeb\x19\xdb/r\xf6\xe3/\x9c^۟c\xfd\"\xbd\xd9ua'c\x90\x91\xea\xf1\xdd3\xb6\f\x82\xd9\xdc\xcf\xd8.?L~\x1d^>\xa8r\xb8\xeb\xc2N\xc6 \xa3\xad\x87\x18#c;\x1c\xdc\xcf\xd8n\xa9%\xbfjm\xbfH\xaf!\xecd\f\"\xd2#J\x19[u\xa9>0(\xa6g\xb3D]u<\x91\xb1ݭ\xed\xfb\xb2\xdd\xccv0\xbbn\xdfI\xfb\xd0p\f!\xd2#J\x19[5@\xc6\x05E\xf2~z6K\xd4U\xc7\x13\x19\xdb\xc3Ejw\xe1\xef\xd5\xfb\x0e\xb1\xdb!\xdcu\xfbNڇ\x86c\b\x91\x1e\xd1\xca\xd8֣q\\\xa8B>h\x99\x8d\x89\xba\x9a\xb8\x9f\xb1\xed,Pwg\xedV\vp,\x94\r\x02\x87\x93=v\x9d\x8c\x14\x1a\x8e\x15DzD/c\xab\x86\xcaf\x84\x03$a=訫\x89\xfb\x19\xdb/\xe4\xfe\a\xb7\x16_\xd7B~L\x10x\xb0\x1e\xcc\x1aۇ\x86c\x05\x91\x1e\xd1\xcb\xd8\xf6\xaf\xcf2\xaff\xc3z\x90ߝ\xb2\xe5\x1a\xd1\xfd\x8cm(p)\xe7O9\x97\xb2\xb4\xa5\x15QK\x19\xac\a\xb3\xc6LݘC\xa4G\xd42\xb6\xd7\x1f\fP\xf1\xa2\xb0\x1et\xd4\xd5\xc4\x03\x19\xdb\xc5\xfb\v\xd5\xc2\x03\x8b\xc9t&\b\xcc\xeaa\xe9d\xa4\xd0p\xac \xd2#Z\x19\xdbkE\xe4\xccs\xb2\x94\x9d\x8d\x89\xba\x9ax c\xbb\xbex\x8b\xba\xa5x-\x99\xce\x1c\xab\xc2kl\xd7\xc9X\xbf\xdc\x15\xe9\x11\xa5\x8c\xed\xb5\xe5\xf2>|\xe9\xb2\x15\xed\x1ez63\xea\xca\xf6\xc2\xfd\x8c\xed\xce\x19\xfb\xd5\xfd3\xd0\xf1\x90\xde\x0e\xcc\x1a\xdbt2bh8V\x10\xe9\x11\xa5\x8c\xedGYz݅*3\x9b\x19ue\xf0@\xc6\xf6\xad\xec\v\xea%|\x03\x9d\xde\x0e\xcc\x1a\xdbt2bh8V\x10\xe91\xaa\x883\xb6ý\x05;j\xb8\xb6`o\xe3\xa8\x1e⌭\xb9\x97 c\xeb\x05\x1c\xd5C\x8c\xb9\x97 c\xeb\x05<\xa5\a\x1du\x85\x8c\xad\x17\xf0\x94\x1e\xaeE]][\xb0\xd7\xf1\x94\x1e\x80\xd7\x00=\x00\x0e\xa0\a\xc0\x01\xf4\x008\x80\x1e\x00\a\xd0\x03\xe0\x00z\x00\x1c@\x0f\x80\x03\xe8\x01ppC\x0f\xc8\xd8\xc6\f#\xd5#A2\xb6\x87qC\x05k\xcd/`\xdb\xf2Y\x96\xbc\x94_#\xd6\x18\xa9\x1e\t\x92\xb1\xbd~T\xde\xd7y\xb8x\xc6\x19\xdbY\fB\xdd\x15\x015\xae\x18\xa9\x1e֏\xc2\xc5\xef\xd4\xd8\xcc\xd8^\xc2\xdfl\r\x15/\xb6\xabNQ\x0fzX\x18\xee7%b3cK\xf4P\x0fʂo'%\x9a\x1e\x90\xb1Ֆ\xa6\xe9QV\xc8N5\xb7\x0e:)\x95\x15\xe6n\xd1N.\x90\xb1M\xb4\x8c\xed%\xf9\xad\xfe\xbf\xee\x96\xf7\xb1S\xcd\xc6\xd4\xcbs\x97\x1e>\xbeV\x0e0\x15 c\x9b \x19\xdbK\xe4\xf8T\x16b\xa7R\x8d\x15/\xee\xc7ŀjYc\xc8ت\t\x90\xb1\xbd$\xef\xef>Y\x9c\xfd\x19;\xd5l\xec\x9a\x16f\xa8\rX*@\xc6\x16\xefٸ\xcfؒ\xb1\x87\xe6\x005\xd5l\xac[&\xd9}\xb2\x1d c\x9bp\x19[mh:\xb7\x96\x9dj6\xf6\xb5v\x9e\xdc\x1aP-k\f\x19[5\x012\xb6\x9a\x1e\xf9;/죧R\x8d\x15\x15\"\x1b>\t\x04\xd8نpM\xeeiDz@\xc6V[\xda\x05\x19\x1f\xebJ\xd7W,g\xfb`4\xa6^\xca.\xac\xaf͕\xb3\x8e\xfe\x052\xb6\t\x97\xb1E\x95\xf05\xf8\x85\xc5\x05'\xe9>\x98[\a]\xd9n\xc8]\xb8\xfbh\x96\xbc\x8d\xaa\x00\x19\xdb\xe1\x00\x19\xdbX\xc3Q= c\x1bk8\xaa>o5\x06\x00\x00\t\x1cIDAT\x87\x18\xc8\xd8z\vO\xe9\x01\x19[\xaf\xe1)=\\\x8b\xba\xba\xb6`\xaf\xe3)=\x00\xaf\x01z\x00\x1c@\x0f\x80\x03\xe8\x01p\x00=\x00\x0e\xa0\a\xc0\x01\xf4\x008\x80\x1e\x00\a\xd0\x03\xe0\x00z\x00\x1c\x04zX\"\xb4\x14_W\x14d\xeb_\xee\xf5|B6Q\x9fB;r\x04zX\"\xb4\x14\xa5\xf9\x87\xb6fk_(\xf7|B6Q\x9fB;r\x84'\x97\b\x9ft_\x93\x0f\x9a\xe9\r\xc1\x1b\xdc\xfd\x84l\x82>\x85v\xe4|W=.\xcbC?*\v\xbf\x8d\x1b\xf5\x84l\x82>\x85v\xe4\x88\xf5ؾU\v\x9f\xa2a\xc8Q\xfd\u007f\xb0\b\xcd\xd3\xc6\x05\xf8\x8b\xeafB\x16M?\xb4*\xfb\xa7\a\xd9\xfd鉄l\x82>\x85v\xe4\x88\xf5\x90W\xbd~ly\xf6%m\x18\xa2\xff\x0f\x16\x1fu\x1e\x93\xeb;;\xc9W\x86\xc3\tY\x9c\xf2\xa8}\xab6\xf0\xbf\x99\xf9=\x91\x90MЧЎ\x1c\xb1\x1eK\xd1\xfb\xa8\u007fq\x91\xca&Z\x98\x93\x8b\x9eR9M\xb2 \xa7e*\xdeDp?!\x9b\xa0O\xa1\x1d9b=\x9e\xc6?\x0f\xe1\x11\xa2H\x8f\nm\xe4w\x8f\xf5\xea\xd1\xfd\x84l\x82>\x85v\xe4\x88\xf5 ۏ\x84OEz\x14k\xef\xf5\xf5E*\x8b\xfb\t\xd9\x04}\n\xed\xc8\x11\xebA§\x87q\xf8\x94\xec\x84Z\xce\xd1\xe3.\xbc\xf9C\v\xc3)k\x1d\xf7\x13\xb2\t\xfa\x14ڑ#\xd6\x03G!C\xf7\xe0\xf0i6\t\xabF\xd6\xe3-r\xbe>&\xbfei\xc2\xfd\x84l\x82>\x85v\xe4\x88\xf5\x90\xd7~p\xba\x98\xa4^\x8b\xf3\xf7\xef+\")R\xedʅ|\xf5\x9fNȖɻO\xee\x96\amQ\xf7\x13\xb2\t\xfa\x14ڑ#\xd4\xe3\x9e\xfa\xb2\x1c=\xf5z\xb94;g\xedӲ\xbc-\x94K\xce\xceY\xf8:\x90NȆ\x0e.\xcf^n\xb9\xef\xa1z !\x9b\xa8O\xa1\x1d9B=b\x02ȸE\x89(\xe9\x01\t\xd9\xf8 Jz@B6>\x88\x92\x1e\x90\x90\x8d\x0f\xa2\xa4\x87\xa3@B6jă\x1e@\xd4\x00=\x00\x0e\xa0\a\xc0\x01\xf4\x008\x80\x1e\x00\a\xd0\x03\xe0\x00z\x00\x1c@\x0f\x80\x03\xe8\x01p\x00=\x00\x0e\x02=\xe2#c\xab\xaa\x17\xd6\x17\xcc}\xf0\xcc\xf2\xf7l\xe6\x18\t\xecҢ\xb1\x1d\\F\xa0G|dl\xd5?e\xad?~t\vy\xf0\xe1\xa8\xc2.M\xb4\x1db\x10\xe1\xc9%.2\xb6k\xf1\x17UC\x15\xa3\xae\x87\xca.mx\a\xbaX\xe0\xbb\xea\x11[\x19ۅ$c{A\x8e»\xdbfiq\x84X\x8fx\xc8ؖ\xcd\xc7\xf9\xca\xd0[\xe4p\x17~\x04\xaf\xf9\x14Z\xd4\xc2!\xfdi\xbcTqHq[ci\xcc\xd3xmZ\xa0\xd68\x86\x10\xeb\x11\x0f\x19\xdb\xcf\n\xe5\xb5\xf5\x1fh;\xc6|\x04\xaf\xd9\x18n!\xbf~\xff\xdc-LqHq\xdb\xf0Ҙ\xa7\xf1\x0en\x81Z\xe3\x18B\xacG<dl\xd5k\xfb\x8a\xb2\xe4\\\\\xa2\x1e\xc1K?\xa37\x90\x8b\xde\xece\xf9lq(q[\xfa\xe4\x12~\"\x9e]\v\xcc\x1a\xc7\nb=\x9e\xc6?c<c\x8b\t\x9d^\x8f\x03Z\xf4#x\xa9g\xf4\x92g j\xebf\x16\x87\x12\xb7\xb5\xd5î\x05f\x8dc\x05\xb1\x1ed\x95c<cۭ\x8d\x03\x8a70\x8fय़\xd1K\xad\x9bY\x1cJ\xdc\xd6V\x0f\xdb\x16\xe85\x8e\x15\xc4z\xc4C\xc6v>y\xa2\xaeZ\xbb\x98y\x04/\xfd\x8c^[=\x86\x12\xb7\xe5\xeb\x11i\x8dc\x05\xb1\x1e\xf1\x90\xb1-\xc0\x0f\x99UCx\x0fS\x8fय़\xd1k\xab\xc7P\xe2\xb6|=\"\xadq\xac \xd6#\x1e2\xb6\x05\xf2\xfc\xfa\xd3\xc7K\xb3\xf1Z\x84\x1f\xc1K5F=\x8d\x97~0\xaf0nK-\xcd\xdc\x0e\xf6-\xb0k\x1c+\b\xf5\x88\x8b\x8cm\xd1\xe1ڥ9\xf9\x1b\xb4ԍ\xf1\b^\xea)\xb4\xd4\xd3x\xe9\a\xf3\n\xe3\xb6\xd4\xd2\xcc\xed`\xdf\x02\xbbƱ\x82P\x8f\x98\x00RrQ\"Jz\xc4s\xc6\xd6\xe1us\x95(\xe9\x11\xcf\x19[\x87\xd7\xcdU\xa2\xa4G<gl\x1d]7\x97\x89\x92\x1e\x8e\x02\x19ۨ\x11\x0fz\x00Q\x03\xf4\x008\x80\x1e\x00\a\xd0\x03\xe0\x00z\x00\x1c@\x0f\x80\x03\xe8\x01p\x00=\x00\x0e\xa0\a\xc0\x01\xf4\x008\b\xf4\x80\x8c\xed\xc8ѲA\xb1\x89@\x0f\xc8؎\x1c=\x1b\x14\x93\bO.\x90\xb1\x1d9\xf5\t\xa7\adl\x87A<\xeb\x01\x19ۈ\x19\xdbZ\xb2\xea\xc7\xd0\xcfZj噺W\xca\ns\xb7h'\x17\xc8\xd8&X\xc6\xf6\xab\xb2\xe2\xce\xeb\xea\xf5\xf7\x8aˮQ+O\u05fd<w\xe9\xe1\xe3ke\xbc\xcd c\x9bp\x19ۣ\xda%\xc9\U000a3595\x0f\xd7-^\u070f\x17\x81\xb7\x19dlI\xa0(\x912\xb6\x17\xe4P\xff\xd1k\xdf\x06.XVި{M{\x10\x19I\x16B\xc66\xe12\xb6\xa1\xac\v\a\xe4ڿ\xca!\xcb\xca\x1bu\xbbe\xf2\xdcm\xad]\xc8\xd8\xe2UO\xa8\x8c\xed\xd2c\xa5\xc5K\x8f\xe3S\f\xb3\xf2Fݯe\xb2~[qc\x90\xb1M\xbc\x8cm\xd9\xf6\xac\xd3\xf26\xfc\x17f\xe5\xc3u\x8b\xf0\x82?\t\xe0\xc6 c\x9bp\x19[u_\xf6\xdc\xd0\xe2l\xa2Ox\xe5麗\xb2\v\xebks\xc96\x83\x8cm\xc2el\xd5\xee\xdcZu\u007f\x0e\xe9zx噺\x977\xe4.\xdc}4\v5\x06\x19[\xd7p4%\x97HDI\x0f\x87s\xa8\x8e\xea\xe1\xf0\xba\xb9J\x94\xf4p8\x87\xea\xa8\x1e\x0e\xaf\x9b\xabDI\x0fGs\xa8\x90\xb1\x8d\x1aQ\xd2\xc3Q c\x1b5\xe2A\x0f j\x80\x1e\x00\a\xd0\x03\xe0\x00z\x00\x1c@\x0f\x80\x03\xe8\x01p\x00=\x00\x0e\xa0\a\xc0\x01\xf4\x008\x80\x1e\x00\a\x81\x1e\x90\xb1Ml\x04z@\xc6v\xa4\bW\xde\xd3\bO.\x90\xb1\x1d\x19\u0095\xf74\xdfU\x0f\xc8\xd8\x0e\x11\xe1\xca{\x1a\xb1\x1e\x90\xb1\xe5=\xc7\xd6h\x8c\xda:\x91\xd6\xcd\xd8:t\u05fd\x8eX\x0f\xc8\xd8r\x9ec\x1bn\x8c\xde:\x11\xd6-\xbcu\xa8\xae{\x1d\xb1\x1e\x90\xb1\x8d\x9c\xb1\xa5\x1a\xa3\xb6\x8e\xfd\xbaQ[\x87\ueeb7\x11\xeb\x01\x19\xdb\xc8\x19[\xba1s\xebد\x1b\xb5u\xe8\xae{\x1b\xb1\x1ed\xd7C\xc6\xd66cK5F\xb7`\xbbn\xd4֡\xbb\xeem\xc4z@\xc66rƖj\x8c\xda:\xf6\xebFm\x1d\xba\xeb\xdeF\xac\adl#gl\xa9ƨ\xadc\xbfn\xd4։'= c\xcb\xc9ؚ\x8dQ['º\x85\xb7\x0e\xd3uo#\xd4\x032\xb6\xbc\x8c\xad٘\xb9u\"\xad\x9b\xb1uBL\u05fd\x8dP\x8f\x98\xc0є\\\"\x11%=\x1cΡ:\xaa\x87\xc3\xeb\xe6*Q\xd2\xc3\xe1\x1c\xaa\xa3z8\xbcn\xae\x12%=\x1c͡B\xc66jDI\x0fG\x81\x8cmԈ\a=\x80\xa8\x01z\x00\x1c@\x0f\x80\x03\xe8\x01p\x00=\x00\x0e\xa0\a\xc0\x01\xf4\x008\x80\x1e\x00\a\xd0\x03\xe0\x00z\x00\x1c\x04zD\xce\xd8F\x99Q\xcd\xd8\x1e#-\xcd\xdb0\xf8\xc6;\x95\x14\xa6\x8a\x80\x81@\x8f\x88\x19\xdb\xe1DG\x85u\xa3\x9d\xb1\xbd~R~\xba\xb3\xf3\xe8\U00082bedթ\xa40U\x04\f\x84'\x97\b\x9f\x95\x0f':*\xac\x1b\xf5\x8c\xed\x97Z\xd8%ۺ.TR\x98\t\r\x03:\xdfU\x8f\xe1DG\x85u\xa3\x9e\xb1\xd5\xf4P\x97[\x97C}\xa1z8\xa1\xe1\xc4A\xac\x87\x91\xb1\xc5yѧ\xd5z\xf4\xf3uan\x96BX\u05c9\x8c\xad\xa6Ǖ\xc0\xbe\bIa:4<\x84`m\xe2 \xd6\xc3\xc8\xd8\xf6\xbfWXqE\xfd\xaavn\xe7uan\x96BX\u05c9\x8c\xed\x97\xf2\xe1\xfe\xeb\xbf_\xbe\xf4z\xa4\xa40\x1d\x1a\x16\x06k\x13\b\xb1\x1efƶ\x1e\xbf\xc1\xf5`\xa807K!\xac\x1b\xf5\x8c\xed\x97\xe4ذ\x98\xe4\x06\"d\xfd\xc2Ea\xb06\x91\x10\xebafl\xaf\xcc\xf8w54W\xcb5\ns\xb3\x14ºQ\xcf\xd8~)\xd7vw\x9f\xde:\xef\x0f\xaaX\x0fa\xb06\x91\x10\xebA\x86\x00Z|u\xfdN\xf5t\xaee\x8fF\xca\xcdR\b\xebF=c\xab\x0fM\xcb\x16\x87\xc4z\b\x83\xb5\x89\x84X\x0f3c\xab\x9e,\b\x19\xff\xe9\x8007K!\xac\x1b\xf5\x8c\xad\xae\xc7\xe1\xf0\xff308)L\x1d=D\x0f\xafM \xc4z\x98\x19[5Tp2W\u007f?\vs\xb3\x14ºQ\xcf\xd8\xeazl\xcd\tEL\n\x87\x8b\xc2`m\"!\xd6\xc3\xccآ}qW\xae~Y\"\xcc\xcdR\b\xebF;c\xab\xdd5=^&\xefW#$\x85\xa9\xa28X\x9b@\b\xf5\xa02\xb6\xaa\xfa\x89l\x1c\x19\x84\xb9Y\na\xddhgl\xb5\xcf\\\xb2\x96\x1f»\xdf.)L\x87\x86\x87\x10\xacM\x1c\x84z0\\\x0fx\xf3)\xbd\x8e\xa6\xe4\x12\x89\xe1\xe9\xf1\xfa\xbc!\xde?t8\x87\nzD\x89a\xe8Q\u007f&TZ+\xaa\xa4\xe3p\x0e\x15\xf4\x88\x12Cף_^\xb5m\xfeP?>u4\x87\xeap\xc66\x91\x18\xba\x1ej}N\xa9\xf5s\x11o\x00\x19ۨ1\f=\x80\xc4\x03\xf4\x008\x80\x1e\x00\a\xd0\x03\xe0\x00z\x00\x1c@\x0f\x80\xc3\xff\a'\xa7c\x12\x8d\x96\rF\x00\x00\x00\x00IEND\xaeB`\x82",
+
+ "analysis/callers1.png": "\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x03\xa2\x00\x00\x01.\b\x03\x00\x00\x00\xa3\xcb_?\x00\x00\x00\x01sRGB\x00\xae\xce\x1c\xe9\x00\x00\x02\xfdPLTE\x00\x01\x00\x04\a\x03\x06\f\x0f\n\r\t\x10\x12\x0f\x17\x17\x13\x1a\x1a\x14 \x1f\x19!# #$\"%$\x1d$%#&'%'(&+)\x1e()'++$*+)+-*/-!,-+-.,02/52'241574796<9-9;8:;C;=:=?<B@4?@>#CxAB@CDBDFCKH<MH7HIG\x00f\x00\x00h\x00\x00i\x01JLI\x00j\x02MOL\x05m\x05PRO\fo\t\x0fq\vTVSZVD\fr\x17WXV\x11t\x19,`\xae7]\xad\x15v\x1c[]Z\x19y\x1e]_\\d_M:b\xac_`^<c\xad>e\xafac`*{!Ag\xb2ceb)|*dfcfgeghfLi\xafDl\xb0hjgqjR\\k\x88/\x82/jkiHo\xb3/\x858Jq\xb5mol;\x86:pqoUt\xb4>\x89=|t]tvs@\x8b?swzB\x8c@vxu@\x8dG\\{\xbbxzw]~\xb7K\x8fJ{}z\x85}d}\u007f|O\x93N\u007f\x81~c\x83\xbdN\x95Uu\x84\x96\x81\x83\x80W\x95V\x8e\x85gm\x87\xbcZ\x98Y\x87\x89\x86]\x9c\\\x89\x8b\x88\x95\x8bm\\\x9dcs\x8d\xc3d\x9dd\x8c\x8e\x8bf\x9fg{\x90\xc0\x8e\x90\x8d\x90\x92\x8f\u007f\x93\xc4j\xa3jz\x97Ɠ\x95\x92s\xa4l\xa1\x96xq\xa5s\x81\x9a×\x99\x96\x84\x9cƙ\x9b\x98u\xaaw\x9b\x9d\x99~\xaay\x9c\x9e\x9b\xa8\x9e\u007f\x88\xa0˞\xa0\x9d\x80\xad|\xa0\xa2\x9f\xa1\xa3\xa0\xa2\xa4\xa1\x92\xa5ʮ\xa4\x85\x82\xb1\x86\xa4\xa6\xa3\xa5\xa7\xa4\xb4\xa7\x82\xa6\xa8\xa5\x8b\xb3\x88\x95\xa9Ψ\xaa\xa7\x8d\xb5\x8a\x98\xabѩ\xab\xa8\x8e\xb6\x8c\x8d\xb8\x93\xab\xad\xaa\xb9\xad\x88\x9f\xaeέ\xaf\xac\x96\xba\x96\xaf\xb1\xae\xa3\xb2Ҙ\xbc\x98\xb1\xb3\xaf\xb2\xb4\xb1\x9b\xbe\x9bµ\x90\xb4\xb6\xb3\xb5\xb7\xb4\xa3\xbf\x9d\xac\xb7Ң\xc0\xa4\xb7\xb9\xb6\xb8\xba\xb7\xb9\xbb\xb8\xa5ħ\xb1\xbc\u05fb\xbd\xba\xbc\xbe\xbb\xbd\xbf\xbc\xafƫ\xa9ȫ\xb8\xc0տ\xc1\xbe\xce\xc1\x9b\xc1ÿ\xb2ʮ\xc2\xc4\xc1\xbc\xc4ٲ̷\xc4\xc6ú\u0379\xd7Ȝ\xc1\xc8\u07bb\xca\xde\xc7\xc9Ƽϻ\xc9\xcb\xc8\xc0\xcc\xda\xc7\xcb\xdb\xca\xccɿҾ\xcc\xce\xcb\xc4\xcf\xdd\xca\xce\xde\xce\xd0\xcc\xc8\xd3\xc1\xe0Ф\xcf\xd2\xce\xc8\xd6\xc9\xd1\xd3\xd0\xd1\xd2\xdc\xd2\xd4\xd1\xdeէ\xca\xd8\xcc\xd3\xd5\xd2\xcd\xd6\xde\xcc\xda\xce\xd5\xd7\xd4\xe7\u05eb\xd6\xd8\xd5\xd1\xd9\xe1\xd5\xdb\xd1\xd8\xda\xd6\xd8\xd9\xe3\xd3\xdc\xe4\xda\xdc\xd9\xe6ݯ\xd5\xdf\xda\xdc\xdf\xdb\xd7\xe1\xdc\xde\xe0\xdd\xf0\xe0\xb3\xdc\xe1\xe4\xdf\xe1\xde\xe1\xe3\xe0\xe3\xe5\xe1\xe1\xe6\xe8\xe4\xe6\xe3\xe8\xe5\xea\xe5\xe7\xe4\xe6\xe8\xe5\xe4\xe9\xec\xe7\xe9\xe6\xef\xf2\xee\xf7\xf9\xf6\xfe\xff\xfc\xbd\bi5\x00\x00 \x00IDATx^\xed\x9d\x0fp\x13\u05fd\xef\xe1%\xb7\xf7\xf8Y\xba\xbdvjW&\xbevs=n\xb1\xc7\xf6\x98\xa8@\x84\xc3s\x80\x90\xe0\x10\xee\x03'J\xe19\xaf\xb9\x81\xa4\x80\xfb\x9cb\x87ۄ\xbf\xc1m\xd0\x00Uq\xc1<BL\x9d\xa7)\xc5@\xf0\xad\x15p\x9c8&\xb8Ԏi\xeb\xe4\xc6!\xb85\x93\xb9Q\xe2LP:\xb7ʄ\x99e2\xe2ܛy{ή\xa4]\xedY\xadd죕\xfc\xfb\f#\xfdt\xf6\xecٳF\xdf=\u007fvu\xbe3\xbe\x9a8\x18\x00\x80\xa9f\x86\x91\x0ec`T6\x00\x007\rH\x14\x00L\rH\x14\x00L\rH\x14\x00L\rH\x14\x00L\rH\x14\x00L\rH\x14\x00L\rH\x14\x00L\rH\x14\x00LM\nI\xb4\xb1\x91\x15\x02@z\xc3]\xa2C.\x8f\x14\xf8\xda\xdd\x1d\xbePjװ^\xfe0\u007f*y\x8e\x11\x12\x1e)))9\x81O\x88\xaf\x8fhw3\xe0\xc3Ғ\xfb5\x89\u007f}zn\xf9?\ai\xf8\xda\xdcW4\x9b\xd50K`\xd0(֯\xfcJ\xe8\x93\xe2\x10\n\x8c\x8f6\xf5$R\a\xf6Y\x18\x92\xc8!\x00\xde\x12\r\xecy\xb5\x85\x06c\xfb\xbc\x97\xbc\xfbƤ\xd4q\xd7\x1b1\xf6\x91x\xaa\xfc*#$\\\xd9Z\U000a6005s%[\xaf\xe0\x84y\xab\xb1\\\x93\xb6f\xee\xd1\xc6\xf2\xcfix\xb6\xfce\xcd\xe6(X%0\xf8\xf8ܹ\xa3%\xbf\v}R\x1cBA\x1cG\x9br\x12\xa9\x03\xfb,\x98\xbcy1\x12'r\b\x80\xb7D=\xa7ǨD\x83\a^\x15__=@/\xc1\xbeVc\x89^)\xdd\xca\b%\x0e\x97\b\xe2k\xb0\xe40\x9e\x00{5\x02\xfb\\,((\xc8\x1f\xe2h#\xb4%\xe8\xf0VX\xa2\xaaC(\x88\xe3hSN\xfcu\xd0;\v\x16+7(>\xc4\u007f\b\x80\xb7D\x87\xdc\x01\x1f\x95\xe8\xf0\x1e\xf2_\x1b\xd8C:\xb8]\xae\xae}\x86\x12m\x8c\xb4\x9c\x8d\xeaFt\xd2%z\xa5$\xb1~\xd8\x04$\x9a\xe8!\xccI\"g\xa1\x92(\x90\x00|%\x1a\xd87\x82%\x89\x9e>F\x13\x8eu\x8a/B\x00\xb7\x18I\xf4\xc3\xd2g\x19\xa1\x8cR\xa2\xe7\x1e]P:\xf7\x9f\x17\xd0\xf4\x13\x8f\x94\u07fbU\xdc\xf4viI\xc9\xf3W\x9e\xba\xbb\xfc\xfb\xea\xcb\xf7է\xe6\xcf\xd9 wSCy\x85\xb9%\x14\xd2P\u007f^^RRz\x82l\xfdqI\xe9K[\xef-\u007f\xf4cU^u\t\x11Xu \xc8\x12U\x1eB\x01\xf3hd\x84\xbd\x17北m\x9d\x13\xd2;\x9aDpn\xe9O\x16\xcc\u007f\xf3\xd99k\x02\xe2\xdf\u007f\xc3\xfc\xd2\x05O\xbc-\x1d\xe2p\xe3\x82;\x9f\xb8\xa2\n\xf5\xce\xf8\xafO\xcd]\xb0u\xeb\xdc9'\x14\x05+\xce\xe2\xc7d\x1fiL\xae\xfeC]\xd90W\xac\xdaU\xfc\x8a\x94\xb5d\xa5\xea\x10\"GW\x96\xaf<\x1a}4@\x05_\x89zNbY\xa2m\xaf҄\xee6i\x83\xa1D\x1bK?f\x842\n\x89^,}\xea\xe5\xd7^\x9a[\x12\xa4\x19\x9f={x\xee\xca \x16N\x9cXp\xef\x9c\x05[\x9f*\xfd\x10\v\x1fJ\x88{\\\x99s\xefK\xaf<ZR\x8e\x95y\xf1\xdb\xe7N\x94\xec=w\x8e6\xd4\x17ϝ+\xdfK\x82?\x9d(-\x99\xbb\xf7\xf0\x9c\r\xea\xbc\xca\x12\"0\xeb@\b\xb5\xa2\x8aC(\xaa\xc3<\x9apn\xce\xf3W\xf1\xd5\xe7\xe7\x9c\x13tNH\xf7h2o\xce)ٺ\xa6d\xee\xcf\xe6\x8a\u007f\x9d\xb3%\x8do\x9ex\xa2\xf4-\xe9\x10\v~\xb6wA\xf9{\xcaP猅\xfb\xe7\x1f}\xbe\xbc\xfc\xa5GUݔ\xc8Y\\=W\xbaW\x1e\x93\xab\xfePo\xceY\xf9\x8b\xd7\xf6\x8a\xff-\x81ߝ\xbbw\u0379s\xe7\xe8\\A\xf8\x10\xa4?\xf4\xfc\xd9\xe7˟\x8a\xda\rP\xc1U\xa2\xc3\xee@H\xa2\xb2&ߐ\xe6\x8e\f%\xfaa\xe9ӌ0\x84B\xa2G\xe7\x92\xef\xe7\xd19A\xf2}\xfc\x15&\xb2\xa0W\xec\x95%\xb4\x15\xc1x\x8d|A\u007f\x04\xe3G\xee\x15w\v\xae$\x02S\xe5U\xf5\xdfBߦ\xf29\xe2\x85᩹꼊\x12\x14\xe8Ձ\xd5\xd1UT\x87\x1eEs4\xdcH\xbe\xb6?$w\x99\xd8'\xa4{\xb4\x10\xf3\x9f\x127\xbcBoT\t'\xc8\x1fj\xe5\x13\xf4\x10w\x8b;\u007f\xbe\xe0!uȬÉ\x12\xb1\xe1=Z\xf2\x1e\x8e\"\xf2\x87\xa2\xfbH\x1d\xfe\xc8n\u0082\xef\x93n\xc9\t:\x9f\xa4\xea\xe8ʇx\xad\xe45\xfazV\xb5\x1b\xa0\x86\xa7D\x03\xfb\x86\x83\xc1\xe0XKP\xfc6\xb5yiRW\x9c\xad\xe8\x8f\xc5\xe6B\x1b\x86PH\xf4\xe3\xf9w\xff\xf8\xa5\xb7\xe9\x1cƆ\xbb\x05\xf1p\xc1\x05\xf4\x1e\xea\xcary\xaf+\xafH\\\xc1\x9f\x97\xbcD\x12\x9e/\x8f\xce˖(ٴW\x9dWY\x82\x02\xbd:\xb0$\x1a\xa9\x0eE{4\xfcf\xb9\x80\x85\xf2sх\x85OH\xf7h!\xe6\x9f\x10\x0f\x1c\xc0\xcf\xfdP\x8c\xffz\xf4\xfbwϡ\xfdM\\No\\\x1d-\xf9\\\x15bV\x1d\x9e\x9b\x83I\x95\xff\x15G\xc1\x96hx\xb7\xb3D\xd9!X\x12m\x94\xeeV\xddߨ\xda\rP\xc3S\xa2\xa3\xae\x10>|Z\xba;\xda\xde)m2\x90\xe8\xd5\xf2FF\x18F\xfar\t%G\xc5\xd7\xcf_\xdap\u007f\xc9\xdc_`\xd2\xceH\xd06c\xe5J\xcd^\x17K\xc8\xf7^\xfaZ\xa8\xf2\xb2%\x1a\xfe\x12F\xf2*KP\xa2S\x878\xa6\x8b\xb4G\x13\a\x93/\xe3\x97iK\xa9sBzG\v1\xff5\xfcV)\xa6\x12}k\xee\x82\xe7^>\xb7fe\xe4P\xe7J.\xaaB̪\xc3\xe1ҿ\x92\xc6.\xceV4\xb2[\x89bT̒\xe8#RE\x9fxH]\x02\xa0\x82\xa7D\x83~\u0090\xdb\xef\x0f\xe2a\x97ط\xc2\x01\x97\xfcȂ\x81D\x9f-\xbd\xc2\b\xc3H_.*\x98\x8b\xa4A\xf8\xfcD\xf9Q\xb1\xd7t\xf7E\xca_I\x16Ƅ\xe2_\xa9\xa41\x9d\xecQ\xe55\x90h$\xaf\xb2\x04\x05zu\x98\x98D\xf1\xb3O\xe0'\xe8\x04\x19\xfb\x84t\x8f\x16\x82H\xb4\\\x92\xe8\xfd\x0f\xd1\xc6V\x92(-\xf3%\xb1}U\x86\x98U\x87\x0fK\xbf\xff\xe1\xdb\xf7>\xa2\xb9U\x12%\xd1\xe7\xa3$\xfa\x9a\xa6\x15}\xe9CEv\xf1\x0fw7}\xbb\xbb\x11\xab\xcf\x18P\xc2S\xa2\x12>\xf9\xbeh\x97\xf8\xday@\xfeo\x8f-Q\x83F\x14\a\xee$\x89\x8dw\x8a_\xb1\xbdtx\x83\xd7<M\xbe!tL\xf6\xfc\xcf\xc8+k\xce\xff\xa1\x05b\xe3{\xa5\\\xfa6)\xf2\x1aHT\x91WQ\x82\x02\xbd:LP\xa2o\x95_-\u007f\x8b\x04\xec\x13\xd2=Z\b\x85D\x17\x90\x9d\x82R\x03\\>W\x94k\xe0\xee5\xea\x10\xb3\xeap\xb1dnIɚ\xa8;]X%Q\xf1:\x11|(J\xa2\xc2\xfc5\xe4\x8a\xf0,\xbd\x00\xac\x11K\xbf\x1a\x1a%ˇ8+MSKcQ\x90\xa8\x0e\xbc%\x1a\xf4\r\xb9}~1\x18\xdb\xd3y\xa9Kz\xbaH\xf0\xf9ܝ\xbeq\xfd\x9d\xb6FZέ\x8cF\x94\xfc/?}\xf6i\xfa\xff\xbd\xb7d\xce\xf3g_n,yS\x8c\x9f+\xfd\xe1\xcb\xff\xda(&\aߢ\x13\x8a\xd1c\xd8\xf7\xca\x17\xec}\xfe\xce\xd2\xd2_\xbd\xa7\xc8+OT\xbeE\xae\x1d\xc2\xefΝ+o<w.@\xe6,\x1b\xdf\xc2\x17\x1bK\xc9\x04f$\xaf\xb2\x84\b\xcc:HO\x17\x1d\xa6\xb5P\x1cB\x81\xce\xd1pp\xfe\xa3\xf3\xa5\xac\xcc\x13b\x1f-\xc2{w\x1e\x16N\x94\xbe'\xfcp\xcd\xc7b\xde\rG\u007f\xb6R\xec\x15\x8b\x92//Yy\xe2\xa5{\xe7\x90?g$d\xd7\xe1\xed\xf2\xd7Ξ\xbb\x1a݈*\xcf⑹\xbf\xf8\xd9C%\xe2\xdfAU\xf57\xcb\xef?z\xf6Yi\xc0\xbe\xb7\xfc\xf0\xcbk\xca?V\x1eBl\xf6K\x9f;\xfb\\\xe9S8\xea\x8c\x01%\xbc%\xea#C\xd1\x034\xea\xd8\xd7.=\xa3\xdb'\rP\x03z\xfb\\%\xd3\xf2\x9aP\xc5ٕ\xe5+ɵ\x18\x9fxd\xef\x82\xd2\xf9kޤ\xa9\xaf\xad\x99;瑳\xd2mD\xcd\x10M\xe4\xca\x13w\u07bd\xf5W\xa5%O+\xf2\nsh^z%\xb8(\xed'~Ǟ&I\uf54b\xafʼ\xea\x12\xc20\xeb@\x9f\xd1%lP\x1dB\x81\xde\xd1\xf0\xe1\xf2\xd0\xcd\x0e\xd6\t\xb1\x8f\x16&(6\x80'攔\x9f ك\x87\xef-\x9f\xbb\xe1\xa5{K\xc5&\xad|k\xe3\x9c\xf9OQEDBv\x1d~GSK\x1fQ]\x88TgqeM\xf9\x9cG\u007f\"\xe6UW\xfdʆ\x05s\x1e\x92\x1e\xf6\x13\x9e\xbd\xb3|\xcd[\xaaC\x88\x95;L\ue2ca\"\x8f:c@\x01o\x89N\x84\x9f\x94\xfc\x89\x11\x027G\xa8?\xab\x0eY\\\x9d\xf3\xf4\xd5`\xf0\xf3\x8b\x1b\xee\x8c\xefq\\`RI\x05\x89¯Ц\x82\xf8%\xfa\xf2\x1c\xa9\x8f\x1b\x9c\xabj\x9f\x01>\xa4\x82D\x81\xa9 ~\x89^,\x95z\xb8\xef\x95*fh\x01^\x80D\xa7'\xd2\xfcLt\xc8&\xd8X\xdex\xe2\xcd\x13\x8d\xac\xc9t`\xca\x01\x89NO\xe8\xfċѡ\x1e\xaf<:\xbft\xfe\xf7\xa1\x9b\x9b\x14@\xa2\x00`j@\xa2\x00`j@\xa2\x00`j@\xa2\x00`j@\xa2\x00`j@\xa2\x00`j@\xa2)\x87\xe67a@Z\x03\x12M-|\xce<\xb4\xc4(\x13\x90N\x80DٴW\xfa\x8d\xb2ă\xbf\xb2\xdd(KB\x04\x8b\x8b]\xa7njr\x01\xe9\x04w\x892\f#\x02\xde\xd6}\xed\x031\x97L\xfer\xd7\xf2E\x9bn\xc4\xca1A\x965K\xef\x9dUy\x96\x02\xe7h(y\vj\xd2\xdb#1\xb6dl1ʒ\b\x03\xa8\xc3(\v\x90f\xf0\x96(\xc30\"\xe0n\x1f\x1a\xeds\xb7\xc5\xd2h\xfd\x83\xc7w.\xba\x16#\x83H0H\x16\xd7\x12\f\x87j\x9d\xfd\x91\xf8\r\xb4\x9e\xbe\xf7\xa2J\xf7IWQ\x9el2Ӝ\xe1f\xec8!<\x99\xcdFY\x12\xe0\r\xe45\xca\x02\xa4\x19\xbc%\xca0\x8c\xe8l%\xaa\xf2\xef\xeb\xd3\xdf\xeb\x9a\xe38\xbea\xa0\xd0w*\x8a\x8b\x17\xce..^\xab\xfb\xd3p\x99\x8a\x9ap\xe8͗%\xfa\x02:)\xbe\xfa\x90\x8b~\xbadY\xcf\xdaqb4X'\xb1cڋz\x8c\xb2\x00i\x06g\x89\xb2\f#\xdaZ\xe9\xa6N\x8f\xfen\x1f9^\xd7\xdf(!X\x90\xdd>3\xdb^1\xa3\xc1\xc0e\xa4lY(Z\x86\x1eȖ\xc5H\x97e\xe9C\xdd\xf4\x83s\x96\x91\xcc\x13 0\xcbi\x94%~@\xa2\xd3\x0f\xbe\x12e\x1aF\xf8\xa4V\xa6\xfb\x05\x9d\x9d\xae/wPvc\xbc\xcb\xe18\x83?\xadv\xac&a\xf5\xa9ݫ\x17m\xfa\x8c\xe6\xf9\xf4\x99\xe5\xffm\xf3W_\r\xff\xe7W\xffu\xcb=\xd2D\xcf@&B\r#\xab\n\xb2\xaa\x88d\x9b˲\xcbH\x8fӃ$\xcaH\x96q\x1f\xce\r\xb7\x97A\u007fGA\x19U\xb7\x90\xf3$\xa3\x84\x10\x8a\xd4:\x94тG-\xa8\x18\xe3:dq\xad-ʮ\x92Υ\xa52\xbb(ܚ7dE]3\x12.!B\x17Ht\xda\xc1W\xa2\xba\x86\x11\xa4\xe7\xab;\xcaz\u007f\xf0\x8c\xe3\xd0\xe0\xe0_0\xfel\xb0\xfa\x10\xbe\xf1\x87]\xd5\x18_>S\xedx\xf0\xd0\xff[\xfa\f\xc91\xb8xݡ\u007f\x981cF\xb0fƌ[\x9a\xa4o\xb6\xd0z\xa0\xa0('\u007f\xed\n$~\xe9\x9d\xd6\x06O\x83u\x95x\x91\xe8\xf6\x16ٽ^o\xc8\xcf4,\xd1\v\xa2n\xbfq\x89\x86\xfd\xa8K[B\x18E\xaa\xcfki¸\xc7i\x15{\x05\a2\x91\xadi{\xce}$\x8b3\xa3\xce\xd3l+\x93G\xc5\xddѲJ\xb8\x84\xd0~\xe3]\x15\xb9\x93ؾ\x03)\x01W\x89\xea\x1bF\x88_dw\x8c\xbb\x1c\x91\x8e\xae(Q\x8c\x0fU\xd3p\xa9\u0602n{P\x8c\xae\xd7n\xba\x1e\xf4\xfd\xef\u007f\x10%\xfa7K\xb6\xbc\x13n\xb4\xcaм\x005U\xe8\xa0\x13\xa1\x1d\x886ݑ\x8e.VH4\xd8۵=?\x8fjԃ.iJP\x11I\xb5\x92\x89\xdf&+I\xb4\xe6\x8aB^e\xa3\xfb\x93ɦ^tP\xca=\x86\xb4\xfd\x83\xc4J\x90Y\"^Eb\x8c\x06\x80\xf4\x84\xa7Dc\x18F\xe0\x1eW\xf8\x86\a\x03\xb6Dw\x86\xc2\xf3\x8e\xf7E\x8d\x05\\\xa2D3\xfb\xfd\x91neYh\xa6\xc6YLߊ騐-QB \xbf\x8a\xbc\xb5\xa1p]ʘs=\x91T\xa5\xc0\x9c\xa1\xf0\x81B\x81\x90/\x8fAǢ\x94\x96x\t2c\x1d\xaebhE\xa7\x1d<%\xaao\x18!t\x86\x96\xa5gÖh8<\xee\xb8N\x12Z\x89DG\x14\x03\xbf\xb2\n9\xa8\xbc\x87\xbe-\xac\xa4\xa9\f\x89ʺn\xca$\xef=\x91\x9ei\xb8\x04\x15\x91T\xa5\xc0\xc2a\x99<ޕ\x9f\x02\xea\x95'\xa1&^B\x04/\xea\x8dN\x02\xd2\x1c\x9e\x12\xd55\x8c\bxZ|1\xf7\x8c\x92\xe8\xfe(\x89\x9ew\xbcK\x12\xb4\x12\r\x89\xd1YH\xdf\n#\xad\xe8>\xb9\x15\x93$*\xe4J9\x9b\xe8\xccN\xc0\x1a~nA%\xe70\x91T\x9a\xb3!J`+\n\xfb)rϽɢm\xf9\x12+!\x02\xcc\xe8N?xJTBk\x18\xe1?xD\xfc\x12\xc7rd\x8fHt\xd1~\x8co\xd4GI\xf4ڃ\xf5\xa4\x19\xfd\x9f\xba\x12\xf5о\xe6Ai$g\xb7c<\x8e\xa4;=\xa1V4\xaf\x8a\xbc\x06\xf2\xa5f\xab\xe6\x8e\xd0<\x8d\x91D\xb3\x9f\x14+^\x11%\xb0\x0e\xa9\xf0\x8d\x9bi\x96`\xf1\u009b,A\x01Ht\xfa\xc1[\xa2\fÈ\xb1}\aG}>_w\xab\xde>Ҍ\xee\x1f\xe8\xf3\u007f\xf5\x0f\xfe\xf2\xd0:G\xf5\xa9\xcb\u007f\x19\xac\xde\xf5\x87\x1b\xef\xef\xaa&3\xbd\x83\x8bV\x1f?\xbf\xfb\x1fU\x12\x15z\xe8ܭ4\xac\\\x91\xb1\u07b3>c\x05\x8d\x9b\xac\xdb\xdb\xe6e\x93#\x8f{\xbdߨ\xf1\xf6\x88zlAU\xae\x93\xcd\xf9\xf2\xd3E\xefdlה\x10F\x95Zi۲\xb9\x12e\xba\x87}^\x8b\xb3\a\xf7;-^\xb1\x88\xf5\xe8\x81\xd6v'\x92\xa6\xc2v \xc5\xd3L\x13*AA\x1f\xa3\xd3\f\xa47\xbc%\xca0\x8c8&\x0fP\xf5&+\xaf/\xa5\xb7E\xab? \x1f>\xaa_\xb4x\xd3~\x87c\xd7.\x92\xf4\xfeb\xf1u\x97\x98\xfc\xc13\xb5\x8b\xd7\xfd\x1f\x95D\a2\xe8pNj\u0082ͳ\xb3g7Km\xa3P\x97\x9be\xa7C\xba\x06\x9a#sD\f{\x96\xe4[\x8b\x1f\vu,\x1b\xbe\xde\x1d]B\x18U\xea\x88=+\xa7j#Buub\x92e([|\xad\x13\x93;\xec\xb6\\\xbbt\xe7כ\xf5$\x8e\"\xc1\x12\x94\x8cg.\x1b\x187|\xc4\x11H'xKt*ьE'\xcec\x16\xdd6=1\x0eZ\x9c\x93R\xa1\x10mŌI$ \x9d\x01\x89\xb2ّ\x1fé-~\xfc\xb3&\xf5\x87.\x84\xf1\x81\xd8Sk@\x9a\x91\x02\x12u\xc4\xcb?N\xa2D\x01\xc0$\x80D\x01\xc0Ԥ\x80D\xe3f2;\xba\x00`\x12@\xa2\x00`j\xd2G\xa2B\xf32\xf2\x18\xfd\xfan\xd0(\x90N\xa4\x8dD\x83\x95\xa1\x1f\xa3\x1d\x01\x8d\x02iD\xdaHT\xb8u\xf3W_\xfd\xe7W_\xfd\u05edK\xe0\xc7 @\x1a\x916\x12\r d\xb7ߚg\xaf\x98᜔\xe55\x01\xc0\x1c\xa4\x8dD\x05o~n\xee\x1d\xb9\xb9\xb9\xf3ހ\x8e.\x90F\xa4\x8dD\xb1\xe0\xbbt\xe9\xd2\xe8\xa5Kc\xd0\xcf\x05҉\xf4\x91h\xdc\xeb\xe8\x02@*\x91F\x12Mab\xd8SL\xb6\xe5\x04\x90jp\x97(\xc30\xc2\xd7q`Ok\xf74\xee\x9fF\xec)\x18\xfe\x15\x93l9\x01\xa4\x1a\xbc%\xca0\x8c\x18wy\x86dž\x8f\x1c\x98|\x8dθ\x19\x8c\n\x9f<\"\xf6\x14L\xff\x8aɵ\x9c\x00R\r\xde\x12e\x18F\\rQg\x97\xd8\v\x8cM\x88\x19_L\x1c~\x12\x8d\xd8S\xe8\xf8WL\xaa\xe5\x04\x90jp\x96(\xcb0BZ\xa6\xd6\xef\x9a\xfc\x9fA\xa6\x86D\xc3\xf6\x14z\xfe\x15\x93j9\x01\xa4\x1a|%\xca4\x8c \bc\xad\x9eɟ\x8a\xbdI\x89֡\xcc\xe6\xef\xe5\xe7\xde3\xa2)\u061dG۷\xb1\x1cy1\xcd\x1ce3\x97\xa0\x1fDȞB\u05ff\x82a9\x01L#\xf8JT\xc70\xc2\xefr\xb9ܓ?\x14\xbd9\x89\x06\xa9\x85C\xc1概\xec\xa1肗\xa0*\xf2&\xb8\x9b%\xdcJ\t%\xe8\a\x11\xb2\xa7\xa0\xb0\xfc+\x18\x96\x13\xc04\x82\xabDu\r#\xfc\xbe\xa1֩\x98.2\x92!\xfd\xa7\xb3\x8d,\xebi-\b\x90\xa5;+\xa3\v\x1e\xdd,\xa9g|T\"z\x11\x95D\xfc \x14\xf6\x14l\xff\n\xb6\xe5\x040]\xe0)\xd1X\x86\x11b\xdbsRwljB\xf4\xf7\xe27\xf5\x85\x1aS\xa2d\xfcg\xddH\x8aiF:w-GQ\x88\xa8\x85<\x13\xf1\x83hS\xee\xcc\xf2\xaf`[N\x00\xd3\x05\x9e\x12\xd51\x8c\x90\x9f\a\x1apM\xfa`\x94\xe8\xef\xf6\x17'(Q\xb2Ξ\xb4,}\x97f%\xdc\x10^\x8fD\xb4\xa9[\"~\x10=\xca^,˿\x82m9\x01L\x17xJ\x94m\x18\x11l\x91\xa6\x8c.\xec\x9b\x12\x89\xaaT\xf8\xf3\xdbf~\xed_\xbe\xf8\xe2\xb7߹\xf5\x96\xef\xfc9,џ\xff\xfd̿\xfd_$\xe3\x0f\xbe6\x93l\x9by\xdbO\xc5\x0f\xa4\xe5\xb4>F\x8aq\xa1D\xfb\xe0\x89\xf8A(\xec)\xd8\xfe\x15l\xcb\t`\xba\xc0S\xa2\x12\x1aÈ\x03\xc4XP\xec螎\xb9\xdbD\x88\x96\xe8\xcf\xff\xe6\xe7\x9f\xfc\xf6\xbb_|\xf1w/~\xf2\xef\xff\xe3\xbb!\x89\xfe\xfa\xef~\xfd\xc9o\xbf%jt\xc6\xed\xbf\xff\xe2\x8b\xdb~\xf0\xe7\xff\xf8\xf5\xb7\xc5\x0fĬ\xc1\x9aG\x86\x94\x85\xf6\xe8\x82G\xb7(Ə\f\x12\xf2\x83\x88\xd8S\xe8\xf8W0-'\x80\xe9\x02o\x892\f#\xdeq\x9d\x1c\x1e\x1b\x9e\xba颈D\xbf\xf9\xd3H\x83\xfa\xef_\vI\xf4\xf6߈\x1f\u007f\xff\xb7bL\x82[~/m\x9fA\xae$VTֺ\xe7\x8e\\\x8d\x1e\xe5\x19]6\x89\xfaA\xc8\xf6\x14\xfa\xfe\x15Z\xcb\t`\x1a\xc1[\xa2\f\xc3\b\xec\xebl\xdd\xd7\xd63\x05\xb7\xfe\xa2%:\xf3\xcf\xd2\xfb\xef\xbf}\xeb\x8c\x193C\x12\xbdu\xa6\b\xfd\xf8\x1f\xe2\xb6\u007f\xba\xf5\xbb\xffBTJ\x1f]\xb0\xaeu\xe6\xccZ\xa5}\xa6\xc2msi\xd2\xc2$\xec\a!\xd9S\xe8\xfaW0,'\x80i\x04o\x89r%Z\xa2\xb7\xca\x12\xbd\xfd\x9f~\xff\xc5'3B\x12\x9d)\xb7\x9br\xc6\xdf\xfc\xe0;\xb7\xfc $Q\xc50q\n\x89iO1ٖ\x13@\x8a1\xad$z\xbb\xdcѽ\xe5\x93/\xbex1,\xd1o\xfeH%Q\x91\xdf\xde\xc2W\xa2\xb1\xec)\xa6\xc0r\x02H)\xa6\x95D_\xfc\x9a4]t\xdb\x0f>\xf9\xcd\u007f\x0fK\xf4\xc5[\xff\xe5ϟ\xbc\xf8-9\xe3\xb7\xfe\xef'\x9f\xfc\xe86\xce\x12\x05\x00]\xd2^\xa2\xf4\x87e!\x8d\xfe\xf4\xef\xe9M\x97\xdf\xdc6\xf3k?\nK\xf4\x8b\x17o\xbfe\xe6\xed/\xca\x12\xfd\xf9\xed3o\xfd\xf6o\xa9D\xa5\x19\x1e\x00H*i/щB\x1f\xa3G\xc8\x12\xf5\xdc\x10\x00p\x06$\xaa\x03\xbf\x1f\xa3\x01@,@\xa2:\x80D\x01s\x00\x12\xd5\x01$\n\x98\x03\x90\xa8\x0e Q\xc0\x1c\xa4\xb7Do\x06\xa3\xc2\x01\x80\vi-Q\x00H}@\xa2\x80̤\xff\x16\x10\x98\x14@\xa2\x00\xc1\xe7̓~a\x0e\x98\r\x90(\x80\xc9OR\x8b]\xa7a\xb5^S\xc2]\xa2\f\xc3\be*gN\xda\xc2\xc7\xf5\xd7\xe5eUMVg\xefU[_\x9c\xa9\xfey\xb9[\xb4\xe1d\x10\u007f\x1d0\x1e@\x1d\x8cT\xc0\f\xf0\x96(\xc30B\x99\xca\x1bOvxm\xbdyy.gV<?+\xf7őɅX?(e\xa5>Y\xb8%ï\t\xe3$\x10ky\xf0\xf8\xeb@\x9c*\xa2\x97_\x02\xcc\x02o\x892\f#\x14\xa9\xfc\t7\x9b~Ԍ\x83q\x88O\xd4r\xae\xf1Bh/0\x97\xd5d\xa5Vl\xc6\xd9^M\x18\x17AW\xee\xbc\x18\x9b\xe3\xaf\x03Y\xc0\f~/`V8K\x94i\x18\x11IM\"#(ޮ\xf6\xd8\x12T1`\x90\xa7\x13uƙ:\xdb=\x86F4a<\fT\xa0{b\r\x1f\xe3\xaf\x03H\xd4\xcc\xf0\x95(\xdb0\"\x92ʗ@\x16B\x19t\x91\x16\xc1&\xad\x9a\xb9V\xb5\xfdr\xb5ñ\xff\xa3m\x0f/\xda\xf4\xa5z\xc7c\xf9\x19\xd4\xed\x81m\x18A\xe8C}\xf4=\xb0l\x96%\xff\x9e\x90\xa0C\xa9J\xaa\x1a\x96\xcc\x1e\xc8D\x99ê0\x8cn\x1d\x02k3\xf2\xc9EŸ\x0e\xc5r\x06\xbb*UM\x17HԴ\xf0\x95(\xdb0\"\x92ʙ>\xafW\xfe\xd1\xf6\x05\xefA\xd4\xe4\xf5\xaa\x87v\xd7Ϝ\xa9]\xbd\xb8v\xf7\xb6\xbb>\x8d\xda1\xb0>3\uf21ea\x04\xc1g\x93\x8a\xf2\xa0\xefu\xb5ޓѫNU\xb29\xc7\xda'T\xd9ɢb\x8a0\x8c^\x1d\xda\xf22\xd7\xd3n\xb9q\x1d\xacN\xaf\xd7\xdbU\x89\xb6\xa8R\x15\b\xe3]\x15\xb9q\xf5\xf1\x81$\xc0U\xa2l\xc3\bE*\u007f\xb2B\xeb*\xb0;\xba\x8f;\xea\xaf\xe1\x1b״\x1b\x86\xca\xd0c\xfa\x86\x11a\x02\xad\xe4\xab?;\xc6\x1d\xc7-ȅ\x03\xd9ǢB%\xac:ԡ\xb2\x90ьa\x1d\x9a\xfa\xc5a\xab\x13雔.\x11\x9b\xd8x{\xf9\x00wxJ\x94m\x18\xa1L发D\xab\xa3\x1bP\x19wn\x96K\xdf0\"\x82\xbf\xb9\xaa0\a\xcd\xd6ی[Q\xeeZ\xbcc\x96\xa0\x0eU\xb0\xea\xe0\xb6\xe6ʶ\xc1q\xd4Al'\x97!7\xd6e\xac\xc3U\f\xad\xa8i\xe1)Q\xb6a\x842\x95?F\x12]\xc7H\x14\xdb\xd0J\xb4\x90(B\xcf0\"Lo^\xfe\x93m^\xbb\xaeDdz\xd7v~}\xb4\xb0I\x1d\xaaa\xd6\xe1R\x15\xaa\x94\xdaQ\xc3:\x88\n\xad\xb2\x1c\xd1\xdfJ\xf0\xa2\xde\xd8\x19\x80\xa4\xc1S\xa2:\x86\x11\x8aT\xfe\x18I\xf4\x19F\xa28\x12͏\xb3cX\\INs\x99\xaeD\xdbŶツ\x9c\x80:Tì\x03\x1d\x8d>\x19_\xd3\x17\xb0[5\xbd\xe7(`F\u05fc\U00014a04\xc60B\x91ʟ\tH\xb43?^m`\x9cO\x9c#\x82e\xba\x12mC#\xf8\x02Z\x81\x83\x05\x97\x14\xa1:\x8f\x8eDɜ\xee\xacx\xdc\xe4\xfc\x15\xf4n\xabGc{\xa1\x00$j^xK\x94a\x18\xa1L\xe5\x8a\xd0\xe3\xf5\x92\xe9\xce@hF\xb7Gݎ\u007f\xf9\xc7\xc1\xd5\xf5\x83\x83\xd1#\xc1ev\x8d%\xb0.MhY\xf3\xe62dۢ\xa3\x80\xf1욶\x82\"K\xddf\x8b_\x11*2\xe8\xd4AbȾ\f\x1b\x12(F[\xbc\"Nk\x8cL}\xe0\xbdfZxK\x94e\x18\xa1L\xe5\xc9\x1b\x92\xb3\x03ra!\x97\x06\xaa;\x92\x18_vP6\xe9\xec\x1e\x0f\xc1\x1dEV\xdb\x03\xee;,zM\xd8\xe9;lu\x81\x93E\xb9ͪ0\xc2\xcd\xd7\xe1B\xa6<\x9dT\x10#\xd3x沁\xf1d\f4\x00CxK\x140'm\xc5\b~\x8cfN@\xa2\x80\xc4\xf8@2f\xd4\x01C@\xa2\x00`j@\xa2\x00`j@\xa2\x00`j@\xa2\x00`j@\xa2\x00`j@\xa2\x00`j@\xa2\x00`j@\xa2\x00`j@\xa2\x00`j@\xa2\x00`j@\xa2\x00\a\\\xd9\r\xe2kO.\xf7_3\xa5\x01 є\xa0\xbd\xd2\xcf\b͈\xbf\xb2]\x9b\x18\xc8^\x8b\xc60\xbeϦY\xf5\x85\x01\xb3\x84i\fw\x89j\r#\x047]\x16E\xb3\x82\x1d\x10f\vjb\x84\xf1\x93\x88w\xc4Ͳ%C\xebzџ)\xccj\xc7㖍Q\xe9\xa3+\xf2\xb3go\x96\u007f\x1f\xef\xb2\xe7\xe4o$?\x88c\x95\xa0\x0f\xcfsK\n\xbc%\xca0\x8c\b\xb8.\xf8DL\xdd6L\n\x9d\xfdF9th\xcep3\xc2\x04H\xc4;\x02\x1b\xac\xb6=\xf8n\xec\xedؓ\xa9Yl\xb0\xd7\x1a,h\x15\xaf.Q\xebI\x8c|c\xf6v\xcfƜ\xd9t\x8d\x9c\x85\x19u\xed\r\xa8U\xa7\x04)?+1\xa1sKExK\x94a\x18\x11pM\x13K\xae\x8a\x1a\xa3\x1cl.Y\xd63\xc2DH\xc4;b\b\xc5^Tb\x9d\xce:-\x11\x1a\xac\xd1\xff\xa1\xfe\xcc=h(X\x18mo\xb1\xa4\x80\xf4\x9c\x86\xb3I\xe3\xba\xc4\xdaM\xd6gi\xd6)\x81\xc0\xaeY\"疒p\x96(\xcb0b\xdaH\xb4,\x8eeLX8g\x05\x18a\"$\xe2\x1d\xd1c\xb0\x8c\x91\xdeRJ\x11\x02\xb3\x9c\xd1I\x8f\xa1\x85\xe2\xe1\xa2ǘ\xc5\xd2B\x10\xf7U\x90\xa3\xd2\xfe\xfb\x88\xb4\xf2\x03\xa3\x04\xacW\xb3D\xce-%\xe1+Q\xa6aD\xbaIt \x13\xa1\x86\x91U\x05YU\xe4*\xd4R\x99]D\xdc%<\xf2\xf2$ed\x9d\xea\x8c\x16<jAŪ\xbcu\xc8\xe2Z[\x94]\xa5\xf9c\b9OF\x87\xba6\x12:\xc4\xef_\xc1\x16\xc2\xe0\xa6\xda\xea\xe5\x9bjo\xe0ץuZ\x1ct\xdd\xd0\x1b\xa7\xd6-^\xbd\xfb:ƻ\x1c\xd5\xc7w\xd6.\xdd\xf4\x91\x9c\xbd!+z^!8,\xe0e\x9aɢnIF\xceB\xf1ob\t`\xc5fm\tXO\xa2\x89\x9c[J\xc2W\xa2LÈ\x80\xeb\xe4\v\xae\x03\u07b4\x99-\x12Z\x0f\x14\x14\xe5\xe4\xaf]A&1\x9d\x19u\x9ef[Y\x10\a\xba\xbdEv\xaf\xd7+v\x1b|^\x8b\xd8d\xf4\x90\xf5\xbe\x14y\x87\x0fd\"[\xd3\xf6\x9c\xfb\xa2\xcb\xebG]ѡ\x8e\x8d\x84 /L\xaf\xf9S\xc6\xed_\xe1\x1f\x1d=\x82\x8e\x8c\x8e\xaa'\x06\xfe\xed\xae\x9dgΟZ\xee\xf8\x12_\x1b\xa4\xab\x9d\r~@\x92w:v\x9f?\xfe\xe0\xe37\xf0\xe53Վ\xdaC\x87j\x17]\x96\xf2w\xb3\xb4\xa4\x9d,\x92\x11\xf2V\x89=\x8c\x8a=\xc5\x19y\xceВ\xfa\xda\x12\xd85\xc3\t\x9c[\xaa\xc2U\xa2lÈ\x80\xabe`l\xb8\xf5`\xdahT\xfc¡y\xe2\x99Ҷ\x93\xcc\xee\xf4\xa2\x8345\xdcѥN2MVu^l\xcd\x155\xbd\xca\x16]\x98'2ˢ\bY6\x12v\xb9\xa5\xd6]\x8e\xd3ȿBgi\xfb\xe3\x0f\x92\xc6\xfa\xf8\xd2\x1b\xe4C\xb8\xa3\xfb\xba\xe3\x94\xf8\xfa\xae\xe3\x8c\xf8Z\xfd\xb0X\x93k\xb5\xf2\xa2\xdcc\xac\x81\xa0f\xb2H&\xe8\xcc\x12/[\xf9\x19\xb6-\x1d\xcdy\xf9r?^S\x82\xf1\xa2\xfbF疲\xf0\x94(\xdb0\x02\a\x87\x888\x05w\x1a\xad\xe4Z\x16\x9a\xeex\xa0P \xe4ӡ\x95\x8eD\xc3S#Vg$UA[\xe4[\xa9\bY6\x12#\xf2\xc2\xf4\xfas\xb2\x06\xfe\x15\xc1N\x8f\xa7\t5y<\xea\x81ܧ\xb5\x0f\xef>\xf5\xfe\x8d\xeb\xf4CX\xa2\xdb\x1e\xbe\xfe\xa5H\xedN1\xae\xdeOR\x8e;\xa4KƘtIRS\xa8sᨣ\v\x18\x97Y\x89\x80Dz\xe5>\xbd\xa6\x04\x9d\x9a)1\xf2\xe6HUxJ\x94m\x18\x11\xc2ۦ\xb7_\xeaQV\x11\n\xe4K?\xbd\xb6\xebH4\x94W\x95\xaa@1\x04S\x84:V\x16\xb11\xf2\xaf \xb0F|\xd7N=\xb3ڱ\xfc\x97\xeaV\xf4qGd\x01\xd1\xeaC$e\xd0!ݐ\xe9e\xac\xca\xebEm\n\xc3\xe50\x81\x9aLz\x17\xa9\xa6\x98~\\V&%\xb3J0\x98Ȋ\xe7\xdcR\x12\x9e\x12e\x1bF\x84\xd4\xda\x19\xa7\aC*\x10\x16\xe3\x8a\xc2~\x8a?\x9cJo\x05S16X\xd5y\xf5$\x1a\xb061B\xe3\x89U\x06F\xfe\x15\x04\x86\x10\xde\xdd/\x8a\xf3ڙE\xc7\xc9\az\xe0S\x9f\x92V\xf4]\ni9\xabw\x93M\xa7\xe4V\xb4ɢ\x9dw\xae\xb1\t\xd8\x19\xa9\xbe\x8c\xaf,W\xeaN5\xe4\xd0q\xce\x12\xf9z\xc5*\xc1@\xa2\xf1\x9c[J\xc2S\xa2\x12\x1a\xc3\b\x0f\xb5\x04\xf2\xbb/\xc4\xdc-\xa5\bˮC\xba\x17\xbfq3y\xb5\x8b]\xbdq\x9a@\xfas\xc1\x8a8%\x8ak\xee\bj\xc3\tI\xd4ȿ\x82p)G3f<\xe48O\xde\xeaw\xd1\xd7z\x8c?#\x03\xd0\xf3t\x14\x8a\xf7\xffR|\xa9^NƢ\x0f\xd7\xd3\xec\xc1\xe2\x85\xd1%`\xbfe=\xeeGM\x19j\x8bŁYE\x97\x88\xbf)\xb9\xe7IN\xfe\x12}\x94\x97]\x02\xb3f\n\xe29\xb7\x94\x84\xb7D\x19\x86\x11c\xae\x8e\x91\xb1\xbe}\x9etY\f]\xe8\xa1s\xb7Ҩq=z\xa0\xb5݉\xe8e\xa9ɺ\xbdm^69\xe5J͕ۖ(\xd3=\xac\xc8\xeb\xf3Z\x9c=\xb8\xdfi\xf1F\xcfE\xbe\x93\xb1=*\x8ci#\x11\x03#\xff\n\x1d\x0e9\x16\x1fz\xfd\xf5\x9d\x8eA\xfa\xa1\xfa\xf8\xeb\xf5\x8bɡ\xf7ߵ팘J\xa7\x8b\x1c\xebΜZ\xbd\xf4\x03\x9a}\a\xd2>F\xb5\x1d\x8d\xe0\x03\x85A\xab\xea\xc0Dzfy\x88\x95E\xbe\x18o\xb44tl\xb7\x15\atK0b\x82\xe7f~xK\x94e\x181~\xf2\x80\xdb3\x94.\n\xc5\x03\x92\x0f\x85\xdc\x0et\xd8m\xb9v\xe9&\xb0P\x97\x9be\xa77\x05F\xecY9U\x1b\x11\xaaS\xe4\xad\x13\xdf-C\xd9\xe2k]t\x89\r_\xefV\x87\x13\xb5\x910\xf4\xaf`s\xaa\xfePm\xf5\x83\xf5T\xa1\xf8\xfa\ue94b\xea\xa51\xe7\xf9\xfa\xe5K\xebi\x03[\xbd{\xe7\xd2\xdam\u007f\xa1\xa9ެ\xf0}\xdc\bw\x88G\xf4Z<\xea\xf9\xd8\xd0\f4\xedݶ\xce\xce*j\b\xe8\x97`\xc4\x04\xcf\xcd\xfc\xf0\x96(0\x11\x1e\xb3\xb42B\x13!M\x17Q\x0eZ\x9c\xda\xdbg\xe3H\x1c\xcd\x04+\xd1\n\xcd\x16\x06\xcc\x12\xa6/ є`G\xfe8#4\x0f\x11\x89\xfag1\u007f\xa6Bo,\t\xef\xc4\xd3U\xd2)a\xda\x02\x12\x05&\x01E+\nL2 Q\xe0\xa6\xf9l\xb0z\xd7\x1fn\x18\xe5\x02&\x06H\x14\xb8iv9\x1c\x0e\xc6\xc3N\xc0\xa4\x00\x12\x05\x00S\x03\x12\x05\x00S\x03\x12\x05\x00S\x03\x12\x05\x00S\x03\x12\x05\x00S\x03\x12\x05\x00S\x03\x12\x05\x00S3\x9d%Z\x83l\xab\x86\x8d2\x01@r\x99\xce\x12\xf5u\xba\x8bm\x13Z\xf4\x12\x00\xb8\xc1]\xa2Z\xc3\b\x91\xe1c\xee\xd6>\xbd=\xa6\x92.4\x80\x01\xc0\xcc\xf0\x96(\xc30\x02\v']=\xa3\xfd\xaeX?\xa9\x9f*z\r\xd6u\x06\x80d\xc3[\xa2\f\xc3\b|z\x8fؚ\xfa]\xc9\x18\x16\x82D\x01\xb3\xc3Y\xa2,\xc3\b\x9f\x8b\xaeZ\x94\x94A!H\x140;|%\xca4\x8c\xe8\x11\xd5\x1a\xcfO}\xa7\x82\x81\xc8J\xef\x00`J\xf8J\x94i\x18\xd1\xee\x19ns\x1d\xe8N\xcaZ\x18\x82\xad\xb2{,Y\xd7\a\x00\x88\x03\xae\x12e\x1bF\xb4RÈ\x03\xadI\xd1\xe81\x84\xd0=F\x99\x00 y\U00014a0ea\x84g\x0f]\xf5\xda\xdd\x1b{\xef)!`+\xdcѩ\xe7\x12\x02\x00&\x80\xa7Du\f#\xba$\xa7\x88\xaeh\xf7I\x1e\xf4\xa2\x93FY\x00 \xa9\U00014a0eaD\xbf\x9b\x0e\x06O'\xc30\x02ft\x01\xb3\xc3S\xa2\x12\x1a\xc3\b?\xbd\xe9\x12\xd8\xd7\x17s\xb7\xa9\x01$\n\x98\x1d\xde\x12e\x18F\xe0\xbe=}cC-mɘ.2r\x8d\a\x80d\xc3[\xa2,\xc3\b|\xa9\xdd}\xa4\x8f\xbfB\x05_\u007f\x8d5m̜\x814\x85\xb7D\xcd\xc4\x12\x84\n\x921G\x05\x00\t0\x9d%\xea\xeb\x1f\xc3\x00`r\xa6\xb3D\x01 \x05\x00\x89\x02\x80\xa9\x01\x89\x02\x80\xa9\x01\x89\x02\x80\xa9\x01\x89\x02\x80\xa9\x01\x89\x02\x80\xa9\x01\x89\x02\x80\xa9\x01\x89\x02\x80\xa9\x01\x89\x02\x80\xa9\x01\x89\x022\xb0>\x8c9\x01\x89\x02\x04\x9f3\x0f-1\xca\x04$\x03\x90( \x12,.v\x9d\x86'\x96M\tw\x89j\f#\x84\x16y\xb5\x94\x031\xf7\x9b\x1aN\xda\xc2k=\xf8\xeb\xf2\xb2\xaa&\xab\xb3\xf7\xaa\xad/\x14n\xb7ng\xa4\x86\xf1\xcf\xcbݢ\r'\x83\xd0Ѿ\x87$\nU\xa9j\x06P\a#\x150\x03\xbc%\xaa5\x8c\x10\\\xfd>\x91>W2\xdcU<\xd9/\x84\xc2yy.gV<\xebm\xfb\xe2\xc8\xe4B\xaePXf\x99\xcdH\r\xf3d\xe1\x96\f\xbf&\x8c\x93@\xac_\xbb\x86\x8ef\xaf\xf0\x8a\x1c\x94\x17:d\xd5\x01\xe37\x90\x97\x91\n\x98\x01\xde\x12e\x18F\xd0\xe3\xf1\xd4\x00\x00\x0f\xb1IDAT\f\xd1U\x8cZ\xbac\xef8E\x84\x9bM?j\xc6\xc18\xc4'j9\xd7e\xd8ؾ\x80B\xd2\x0fd\xac\xc8\b\x15\x1bI\x8dP\xb1\x19g{5a\\\x04]\xb9\xf3bl\x0e\x1d\xad\x8a\x8e1\xabr\xc6T\xa9j`\x81\x18\xf3\xc2Y\xa2,\xc3\bʱ\x17\xf8\xaf\xba\xa0b\x04Ż\xbc\xd9\xd8\x12Ta\xd4\xe2w\xa2\xcep\xd4\x1f^\xf1>\x92\x1aa\xb6{\f\x8dh\xc2x\x18\xa8@\xf7\xc4\x1a>\x86\x8e6NZf7r\xabSՀD\xcd\v_\x892\r#\bîqݝ\xa6\x8c@\x16B\x19t\x04,ؤ\xe1\xdaZ\xd5\xf6\xcb\xd5\x0e\xc7\xfe\x8f\xb6=\xbchӗ\xea\x1d\x8f\xe5g\xac%-\xe3X\x8e<\xccˉ\x96J\x1fꓣ\xa6|\x9cߤI\x8dPհd\xf6@&\xca\x1cV\x85at\xeb\x10X\x9b\x91O.*\xf1ԁ\xe4\xaab\xa4F\xe8\x02\x89\x9a\x16\xbe\x12e\x1aF\x10ZO\xeb\xee3\x85\xf4y\xbdVI>\x17ıZ\x93\u05eb\x1e\xda]?s\xa6v\xf5\xe2\xda\xdd\xdb\xee\xfa4j\xc7\xc0\xfa̼#\xa2\xb2\xdd\xcd\x12\xee\xe8.\x80\xcf\x16*j^\r^fפF\u061cc\xed\x13\xaa\xec=AU\x18F\xaf\x0emy\x99\xebi\xff9\x9e:D\xba\xb9\xcc:\b\xe3]\x15\xb9q\xf5\xf1\x81$\xc0U\xa2l\xc3\bL\x16\xc1Nք\u007fV\xa8\x85cwt\x1fw\xd4_\xc37\xaei7\f\x95\xa1\xc7\xc4>䨄~\x17 \x98\xbd\x1d\xefȎ1v݂\\8\x90},*TªC\x1d*\x1b\x92C\xe3:(\xba\xb9L\x96\x88mp\xbc\xbd|\x80;<%\xaac\x18!r\xb25\xd6~S\x89\x91D\xab\xa3\x1bP\x19wn\x96\v\x8f\xa2\x10\xba\x9e\x13\x03\xa8[\xe8\x8ea\x05ފr\xd7\xe2\x1d\xb3\x04u\xa8\x82U\a\xb75W\x16]\x1cuPtsٛ;\\\xc5Њ\x9a\x16\x9e\x12\xd51\x8c\x10q\xf7\xc5\xd8mJ1\x92\xe8:F\xa2؆V\xa2\x85D\x11^\x8f\x84\xfe<l3UO\xb3\xde\xe6\xf1쵝_\x1f-lR\x87j\x98u\xb8T\x85*\xa5vԸ\x0e\x8an\xae\x1e^\x94\fG\x1d \x1exJT\xc70\x82\xacG\x9f4\xe7##\x89>\xc3H\x14G\xa2\xf9\xf1v\fk\xcaz{{\xcbj\xf46\xb7\x8bm\xdf}\x059\x01u\xa8\x86Y\a:\x1a}2\xbe\xa6O\xea掮\x8d1g\x0e3\xba慧D%4\x86\x11\xa4y\x8d\xef\xbb6\x05L@\xa2\x9d\xf9\xf1jCd\x16\x99$^;Kos\x1b\x1a\xc1\x17\xd0\n\x1c,\xb8\xa4\b\xd5yt$J\xe6tg\xc5c\x1a%ws[Q\x8c\xe7\x1c@\xa2慷DY\x86\x11b\x93\x9a\x94\x9b\xa2B\x8f\xd7kuz\xbd\x81Ќn\x8fzZ\xe7\xcb?\x0e\xae\xae\x1f\x1c\x8c\x1e\t.\xb3\x0f\xe18\x11\x8e\xa1\x8d\x01\x1c؈\x8e\xe9\x9c\xe0xvM[A\x91\xa5n\xb3ů\b\x15\x19t\xea 1d_\xc6LWs\x0f:H\x1e/j\x88%\xd1>\x94\x9c'G\x00cxK\x94i\x181\xcaz\xe0e\xeay#C\x9agqa!\x97\x06\xaa;\x92\x18_vP6\xe9\xec\x1e\a'\xc5B[\xf1\x11\xf1U\xef\xa6\xd2\xe9;lu\x81\x93E\xb9ͪ0\xc2\xcd\xd7\x01\x17\xc9\xd3I\xb1f\x84\xc63\x97\r\x8c\x1b>3\x05$\x03\xde\x12\x05\xccI[1\x82\x1f\xa3\x99\x13\x90( 1>\x00\x0eT\xa6\x04$\n\x00\xa6\x06$\n\x00\xa6\x06$\n\x00\xa6\x06$\n\x00\xa6\x06$\n\x00\xa6\x06$\n\x00\xa6\x06$\n\x00\xa6\x06$\n\x00\xa6\x06$\n\x00\xa6\x06$\n\x00\xa6\x06$\np\xc0\x95\xdd \xbe\xf6\xe4&\xb6L0@\x00\x89\xa6\x04\xed\x95~FhF\xfc\x95\xed\xda\xc4@\xf6Z4\x86\xf1}\xb6x~t\xc8,a\x1a\xc3]\xa2\x1a\xc3\b\xf1?\xf0\xd5\x17\xf6\xbd\xf0jܿ\x92\x9e\x86lAM\x8c0~\xe2\xf7\xaf\xb8y\xb6dh]/\xfa3\x85Y\xedxܲ1*}tE~\xf6\xec\xcd\xf2\xff\xbc˞\x93\xbf\x91\xfc \x8eU\x82><\xcf-)\xf0\x96\xa8\xd60\x02\aZچdž\x8f\xb4\xa4\xbdF;\xfb\x8dr\xe8М\xe1f\x84\t\x10\xbf\u007f\x85\x88\xc1jۃ\xef\xc6ގ=\x99\x9a\xa5\x9az\xad\xc1\x82V\xf1\xea\x12\xb5\x9e\xc4\xc87fo\xf7l̙M\xd7\xc8Y\x98Q\xd7ހZuJ\x90\xf2\xb3\x12\x13:\xb7T\x84\xb7D\x19\x86\x11\xdeV\xd2\xfd\x11Z\x13\xf1JHI*t\x970\x8a\xcd%\xcbzF\x98\b\xf1\xfbW\x88\xdd\x1c\x14{Q\x89u:\xeb\xb4Dh\xb0F\xaff\xe6\xcf܃\x86\x82\x85\xd1\xf6\x16K\n\xc8\xff\xfcp6i\\\x97X\xbb\xc9\xfa,\xcd:%\x10\xd85K\xe4\xdcR\x12\xce\x12e\x19F\x9c\x96\x16\xealO\xcaj\xd7<)\x8bg\x19\x13\x06\xceY\x01F\x98\b\xf1\xfbW`\xdcc\xb0\x8c\x91\xdeRJ\x11\x02\xb3\x9c\xd1I\x8f\xa1\x85\xe2\xe1\xa2ǘ\xc5\x05\xf4\xed\xbe\nrT\xda\u007f\x1f\x91V~`\x94\x80\xf5j\x96ȹ\xa5$|%\xca4\x8c\xf0\xb7t\xf9\x05\xbf\xb7\xc5Գ \t0\x90\x89P\xc3Ȫ\x82\xac*r\x15j\xa9\xcc.\"\xee\x12\x1eyy\x922\xb2NuF\v\x1e\xb5\xa0bU\xde:dq\xad-ʮҴ\x1fBΓѡ\xae\x8d\x84\x0e\xf1\xfbW\xb0\x850\xb8\xa9\xb6z\xf9\xa6\xda\x1b\xf8ui\x9d\x16\a]7\xf4Ʃu\x8bWホ\xf1.G\xf5\xf1\x9d\xb5K7}$goȊ\x9e\x16\n\x0e\vx\x99f\xb2\xa8[\x92\x91\xb3P\xfc\x9bX\x02X\xb1Y[\x02֓h\"疒\xf0\x95(\xdb0B8\xe9r\xb9:\xe2\x99\xecK\t\x84\xd6\x03\x05E9\xf9kW\x90ILgF\x9d\xa7\xd9V\x16āno\x91\xdd\xeb\xf5\x8a\xdd\x06\x9f\xd7\"~\x93z\x9cVU\xde\xe1\x03\x99\xc8ִ=\xe7\xbe\xe8\xf2\"MC8Ա\x91\x10\xe4\x85\xe95\u007fʸ\xfd+\xfc\xa3\xa3GБ\xd1Q\xf5\xe5\xf2\xdf\xee\xday\xe6\xfc\xa9\xe5\x8e/\xf1\xb5A\xba\xda\xd9\xe0\a$y\xa7c\xf7\xf9\xe3\x0f>~\x03_>S\xed\xa8=t\xa8v\xd1e)\u007f7KK\xda\xc9\"\x19!o\x95\xd8è\xd8S\x9c\x91\xe7\f-\xa9\xaf-\x81]3\x9c\xc0\xb9\xa5*\\%\xca6\x8c\x10N\xb6\x0e\xfb\x86[O\xa6\x8dF\xc5/\x1c\x9a'\x9e)m;\xc9\xecN/:HS\xc3\x1d]\xea$\xd3dU\xe7\xc5\xd6\\Qӫlхy\"\xb3,\x8a\x90e#a\x97[j;\xd6\xc3\xc0\xbfBgi\xfb\xe3\x0f\x92\xc6\xfa\xf8\xd2\x1b\xe4C\xb8\xa3\xfb\xba\xe3\x94\xf8\xfa\xae\xe3\x8c\xf8Z\xfd\xb0X\x93k\xb5\xf2\xa2\xdcc\xac\x81\xa0f\xb2H&\xe8\xcc\x12/[\xf9\x19\xb6-\x1d\xcdy\xf9r?^SB\x1c\x8b\xee\x1bzs\xa4(<%\xaac\x18\x11\x9a.J\xa3e\"\xcbB\xd3\x1d\x0f\x14\n\x84|:\xb4ґhxj\xc4ꌤ*h\x8b|+\x15!\xcbFbD^\x98^\u007fN\xd6\xc0\xbf\"\xd8\xe9\xf14\xa1&\x8fG=\x90\xfb\xb4\xf6\xe1ݧ\u07bfq\x9d~\bKt\xdb\xc3\u05ff\x14\xa9\xdd)\xc6\xd5\xfbI\xcaq\x87t\xc9\x18\x93.Ij\nu.\x1cut\x01\xe32+\x11\xf0X\xb6ܧה\xa0S3%F\xde\x1c\xa9\nO\x89\xb2\r#\x82{.\xd0\xf0¾\xf4\xb9\x00\x96U\x84\x02\xf9\xd2O\x17\xd7ӑh(\xaf*U\x81b\b\xa6\bu\xac,\f0\xf0\xaf \xb0F|\xd7N=\xb3ڱ\xfc\x97\xeaV\xf4qGd\x01\xd1\xeaC$e\xd0!ݐ\xe9e\xac\xca\xebEm\n\xc3\xe50\x81\x9aLz\x17\xa9\xa6\x98~\\V&%\xb3J0\x9aȊ\xe3\xdcR\x12\x9e\x12e\x1bF\x04\xf7I\x12\xedO'\x89\x86ĸ\xa2\xb0\x9f\xe2\x0f\xa7\xd2[\xc1T\x8c\rVu^=\x89\x06\xacM\x8c\xd0xb\x95\x85\x81\u007f\x05\x81!\x84w\xf7\x8b\xe2\xbcvf\xd1q\xf2\x81\x1e\xf8ԧ\xa4\x15}\x97BZ\xce\xea\xddd\xd3)\xb9\x15m\xb2h\xe7\x9dkl\x02vF\xaa/\xe3+˕\xbaS\r9t\x9c\xb3D\xbe^\xb1J0\x92h\x1c疒\U00014a04\xc60\xa2S\xee\xe8\xa6\xcd,\xb9Bv\x1dҽ\xf8\x8d\x9bɫ]\xec\xea\x8d\xd3\x04ҟ\vV\xc4)Q\\sGP\x1bNL\xa2\x06\xfe\x15\x84K9\x9a1\xe3!\xc7y\xf2V\xbf\x8b\xbe\xd6c\xfc\x19\x19\x80\x9e\xa7\xa3P\xbc\xff\x97\xe2K\xf5r2\x16}\xb8\x9ef\x0f\x16/\x8c.\x01\xfb-\xebq?j\xcaP[,\x0e\xcc*\xbaD\xfcM\xc9=Or\xf2\x97裼\xec\x12\x985S\x12ǹ\xa5$\xbc%\xca0\x8c\x10\x0e\xb6\x0e\x8d\r\xb5\x1eL\x97\xe9\"\xa1\x87\xce\xddJ\xa3\xc6\xf5\xe8\x81\xd6v'\xa2\x97\xa5&\xeb\xf6\xb6y\xd9\xe4\x94+m[6W\xa2L\xf7\xb0\"\xaf\xcfkq\xf6\xe0~\xa7\xc5\x1b=\x17\xf9N\xc6\xf6\xa80\xa6\x8d\x84>\x86\xfe\x15:\x1cr,>\xf4\xfa\xeb;\x1d\x83\xf4C\xf5\xf1\xd7\xeb\x17\x93C\xef\xbfk\xdb\x191\x95N\x179֝9\xb5z\xe9\a4\xfb\x0e\xa4}\x8cj;\x1a\xc1\a\n\x83VU;x,k\x96\xc7\xeb\xf5:\xf3\xc5x\xa3\xa5\xa1c\xbb\xad8\xa0[\x82\x01\x13=7\xf3\xc3[\xa2,\xc3\b\xa1\xf7\x88\xbb\xad7m\xfe\xb2\x03\x92\x0f\x85\xdc\x0et\xd8m\xb9v\xe9&\xb0P\x97\x9be\xa7&\x81#\xf6\xac\x9c\xaa\x8d\b\xd5)\xf2։\uf5a1l\xf1\xb5.\xbaĆ\xafw\xab\xc3\t\xdaH\x9cDF\xfe\x15lN\xd5\x1f\xaa\xad~\xb0\x9e*\x14_\u07fdtQ\xbd4\xe6<_\xbf|i=m`\xabw\xef\\Z\xbb\xed/4՛\x15\xbe\x8f\x1b\xe1\x0e\xb1\a\xe1\xb5x\xd4\xf3\xb1\xa1\x19hڻm\x9d\x9dU\xd4\x10\xd0/\xc1\x80\x89\x9e\x9b\xf9\xe1-Q`\"<fie\x84&B\x9a.\xa2\x1c\xb48\xb5W\xdbqtD\xecAU\xa2\x15\x9a-\f\x98%L_@\xa2)\xc1\x8e\xfcqFh\x1e\"\x12\xf5\xcfb\xfeL\x85\xdeX\x12މgFP\xa7\x84i\vH\x14\x98\x04\x14\xad(0ɀD\x81\x9b\xe6\xb3\xc1\xea]\u007f\xb8a\x94\v\x98\x18 Q\xe0\xa6\xd9\xe5p8\x18\x0f;\x01\x93\x02H\x14\x00L\rH\x14\x00L\rH\x14\x00L\rH\x14\x00L\rH\x14\x00L\rH\x14\x00L\rH\x14\x00L\xcdt\x96h\r\xb2\xad\x1a6\xca\x04\x00\xc9e:K\xd4\xd7\xe9.\xb6Mh\xd1K\x00\xe0\x06w\x892\f#\x82\x03m\xfbڒӜu\xa5\xe1Z7@z\xc1[\xa2\fÈ\xa0\xc7\xdd?ڷ\xa7/\xe6~SD\xaf\xc1\xba\xce\x00\x90lxK\x94a\x18qa\x0fY\x85\xe1\x9d=\xc9\xe8r\x82D\x01\xb3\xc3Y\xa2,\xc3\bO\a\xdd\xd4\xd2\x17c\xbf\xa9\x02$\n\x98\x1d\xbe\x12e\x1aF\xc8K\xea\xb6\x1f\xd3\xdfo\xca\x18\x88\xac\xf4\x0e\x00\xa6\x84\xafD\x99\x86\x11\xdd-t\x05@\xf7\x91X{N\x11\x82\xad\xb2{,\x9e\xa5\x00\x00 Ip\x95(\xdb0\"\xe0\xf6\xf8\x05_\xbb+)k\xf2\x1cC\b\xddc\x94\t\x00\x92\aO\x89\xea\x18F`\xbf\xc7\xe5r\xf5x\x92a\x9f\x1e\xb0\x15\xee\xe8\xd4u\t\x01\x80\xe4\xc3S\xa2l\xc3\b\x82\xe0\x0f\xe2\x96Wc\xed;E\xf4\xa2\x93FY\x00 \xa9\xf0\x94(\xdb0\x02K\xbe\x92#\xaed\xb8\xcd\xc1\x8c.`vxJTBc\x181\xec\xf2\x8bb=\x90\x94\xa9U\x90(`vxK\x94a\x18\xf1\x8e덱\v-\x9ed<\xb9`\xe4\xe4\x03\x00I\x87\xb7DY\x86\x11\xfd\xadnO\u007f\x12\xee|\b\xbe\xfe\x1ak2\xba\xd7\x00\x10?\xbc%j&\x96 T\x90\x8cid\x00H\x80\xe9,Q_\xff\x18\x06\x00\x933\x9d%\n\x00)\x00H\x14\x00L\rH\x14\x00L\rH\x14\x00L\rH\x14\x00L\rH\x14\x00L\rH\x14\x00L\rH\x14\x00L\rH\x14\x00L\rH\x14\x00L\rH\x14\x00L\rH\x14\x00L\rw\x89\x86\r#0\xee\n\x99DD\xbc#\x00\x00P\xc3[\xa2a\xc3\b\x8c\xc7]\xd2*\x80\n\xef\bs\xd0\xd9o\x94\x03\x00\xb8\xc1[\xa2!\xc3\b\xb1\xe9l\x95%\xaa\xf0\x8e0\a\x155F9\x00\x80\x1b\x9c%\x1a6\x8c\xc0]\xae\xae}\x92D\x15\xde\x11\xe6\xa0l\x99Q\x0e\x00\xe0\x06_\x89F\f#\xb0\x10\b-w\xad\xf0\x8e\xe0\xca@&B\r#\xab\n\xb2\xaa\xc8%\xa2\xa52\xbbhm@l\xe6\x91D\x19\xc6u(\xa3\x05\x8fZP\xb1*o\x1d\xb2\xb8\xd6\x16eW\xa9;旫\x1d\x8e\xfd\x1fm{xѦ/\xd9G\x03\x80\x89\xc1W\xa2\x11\xc3\b\x82,Q\x85w\x04W\x84\xd6\x03\x05E9\xf9kW QmΌ:O\xb3\xad,\x88\x03\xdd\xde\"\xbb\xd7\xeb\x15\xdbt\x9f\xd7҄q\x8fӪ\xca;| \x13ٚ\xb6\xe7ܧ*\xec\xfa\x993\xb5\xab\x17\xd7\xee\xdevק:\x87\x03\x80\t\xc1U\xa2\n\xc3\b\x82,Q\x85w\x04o\xca\xd0<\xb1F\xb4\xedtc\xb2d\xe7A\x9a\x1a\xee\xe8ZE\x89\xe2&\xab:/\xb6抚^e\x8b.\xecqG\xfd5|\xe3Zt2\x00\xdc\x14<%\xaa4\x8c \x84ZQ\x85w\x04gʬrw\xf5\x81B\x81\x90朗l\x89\x86\xf2b\xab3\x92\xaa\xe0\xf1jh@\x81ɇ\xa7D\x95\x86\x11\x84\xd0XT\xe5\x1d\xc1\x95\xb2\x8aP \x8f@\x97\xd0\x0fl\x89\x86\xf2\xaaR\x15<\xbe.:\x05\x00n\x1e\x9e\x12U\x1aF\x10d\x89*\xbd#8\x13\x16\xe3\x8a\xc2~\x8a?\x9cJ\xef\xd3R16X\xd5yu%\xfaLt\n\x00\xdc<<%*\xa1\x19\x8b*\xbc#x\x13\x96]\a\xa2։\x1b7\x93W\xbb\x1d\xe3q\x9a\x90\xfd\xa4X\xbd\n\x90(\x90DxK4l\x18!\xf8|\xeeN\xdf8I\x8bxGpE\xe8\xa1s\xb7\x92u\xe1z\xf4@k\xbb\x13\xd1\xcbG\x93u{ۼlR\x9fJ͕ۖ(\xd3=\xac\xc8\xeb\xf3Z\x9c=\xb8\xdfi\xf1*\x9fY\xfc\U0008f0eb\xeb\a\aa4\nL6\xbc%\x1a6\x8c\xe8\x93F\xa5\xd4\xc9%\xe2\x1d\xc1\x93\x81\f:\xfc\\(}\xea\xb0\xdbr\xed\xd2\x1dZ\xa1.7\xcb\xdeK\xa2\x11{VN\xd5F\x84\xea\x14y\xeb\xc4w\xcbP\xb6\xf8Z\xa7(첃\xb2\t\x03\xc0\xe4\xc2[\xa2\x00\x00$\x04H\x14\x00L\rH\x14\x00L\rH\x14\x00L\rH\x14\x00L\rH\x14\x00L\rH\x14\x00L\rH\x14\x00L\rH\x14\x00L\rH\x14\x00L\rH\x14\x00L\rH\x14\x00LM*H\xb4\x06\xd9V%\xe1Ǥ\x00`\x06RA\xa2\xbeNw\xb1-`\x94\v\x00\xd2\x12\xee\x12e\x19F\xa8B&]h v\x06\x00HSxK\x94e\x18\xa1\n\xd9\xf4\xa2\x9e\xd8\x19\x00 M\xe1-Q\x86a\x84*\xd4\x01$\nLW8K\x94e\x18\xa1\f\xf5\x00\x89\x02\xd3\x15\xbe\x12e\x1aF(C=\x06PW\xec\f\x00\x90\xa6\xf0\x95(\xd30\"*d\"\xd8*\xbbǒ\xb0D \x00$\x1b\xae\x12e\x1bFD\x85l\x8e!\x84\xee1\xc8\x03\x00i\bO\x89\xea\x18FD\x85L\x02\xb6\xc2\x1d\x9d\xa3\xb1\xf3\x00@:\xc2S\xa2:\x86\x11Q!\x93^t2v\x06\x00HSxJT\xc70\"*d\x023\xba\xc0t\x85\xa7D%&4\x16\x05\x89\x02\xd3\x15\xde\x12e\x19F(B=z@\xa2\xc04\x85\xb7DY\x86\x11J\xef\b\x16\x82\xaf\xbf\xc6\xca\xdfP\x02\x00\xcc\x00o\x89N\x84%\b\x15\xb4\x1be\x02\x80\xf4$\x15$\xea\xeb\xe7\xee\x9a\x06\x00f!\x15$\n\x00\xd3\x18\x90(\x00\x98\x1a\x90(\x00\x98\x1a\x90(\x00\x98\x1a\x90(\x00\x98\x1a\x90(\x00\x98\x9a\xff\x0f5\x16\x1d\x16\xa8\xc9g\xc2\x00\x00\x00\x00IEND\xaeB`\x82",
+
+ "analysis/callers2.png": "\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x03\xfc\x00\x00\x01\xb0\b\x03\x00\x00\x00#z\x9e\xf7\x00\x00\x00\x01sRGB\x00\xae\xce\x1c\xe9\x00\x00\x02\xfdPLTE\x00\x01\x00\x04\x06\x02\a\t\x05\n\v\x15\a\x0e\x10\x0f\x11\x0e\x0e\x12\x1d\x15\x16\x15%\x19\x10'\x1a\f\x1e\x1d\x17\x16\x1e.!# #$\"$%#%'%'(&)(\"()'-+ *+),-+-.,12053'O.\x0f352786<:.9;8=?<B@4#Cxb<\x1aAB@j=\x11DFCLH9\x00f\x00\x00g\x00\x00h\x00\x00i\x01JLI\x00j\x02\x02k\x03\x04l\x050R\x95OPNVQ@\tn\a\fo\tRTQ\x83L\x1d\x0fq\v\vr\x17UVT\x0fs\x18WYV\x11t\x19_ZH,`\xae\x14v\x1b7]\xad>]\xa1Z\\Y\x16w\x1d\\^[\x19y\x1e:b\xac_a^Ya\x8bac`\x9aZ\x1d*{!@f\xb1Ke\x9e(|*dfclfP+\u007f,fheMj\xaf.\x81.Fm\xb1ikh0\x8301\x841/\x859Jq\xb5mol\x89j_oqn;\x86:>\x88<\xb3h\"{s[Vu\xb5sur?\x8a>@\x8b?uwtB\x8c@@\x8dG\\z\xba\xadq?y{xJ\x8fI^~\xb8L\x90K\x94wq\x85}d~\x80}O\x93Nb\x83\xbdN\x95U\x81\x83\x80W\x95V\xa7|e\x8e\x85gm\x87\xbcZ\x98Y[\x9aZ\x87\x89\x86]\x9b\\^\x9d]\xba\x82Z\\\x9ddr\x8d\u008a\x8c\x89\x96\x8cnd\x9ddf\x9ff{\x90\xc0\x8f\x91\x8eh\xa1h\xe3\x83+ЇK\u007f\x93\xc4j\xa3jz\x97Ɠ\x95\x92s\xa4l\xa0\x96wq\xa5s\x81\x9aė\x99\x96\xe4\x8b@u\xa9w\x9a\x9c\x99\x86\x9eȜ\x9e\x9b\xef\x904~\xaby\xa8\x9e\u007f\x9e\xa0\x9d\x80\xad|\xa0\xa2\x9f\xf9\x94.\xa1\xa3\xa0\xa2\xa4\xa1\x81\xb1\x85\xff\x952\x92\xa6ˤ\xa6\xa3\xb3\xa6\x82\xa5\xa7\xa4\x8b\xb2\x88\xa7\xa9\xa6\x8d\xb5\x8a\x8e\xb6\x8c\xaa\xac\xa8\xb9\xac\x88\x8d\xb8\x93\x9e\xaeΕ\xb8\x95\xad\xaf\xac\x97\xba\x96\xaf\xb1\xae\x98\xbb\x98\xa3\xb2қ\xbe\x9a\xb3\xb5\xb2µ\x90\xb5\xb7\xb4\xa3\xbf\x9d\xac\xb7Ң\xc0\xa4\xb7\xb9\xb6\xb9\xbb\xb8\xa5ħ\xb1\xbc\u05fb\xbd\xba\xa7Ʃ˾\x98\xbd\xbf\xbc\xa9ȫ\xb8\xc0կǫ\xbf\xc1\xbe\xc1ÿ\xb2ʮ\xc2\xc4\xc1\xbd\xc5\xda\xc4\xc6òͷ\xb9̸\xd6ǝ\xc7\xc9ƻκ\xbcϻ\xc4\xca\xd9\xc9\xccȾѽ\xc0ӿ\xca\xce\xde\xcd\xcf\xcc\xc4\xd0\xde\xc8\xd3\xc1\xcf\xd1\xce\xdfѥ\xc7\xd6\xc9\xd1\xd4\xd0\xd2\xd3\xdd\xca\xd8\xcb\xd3\xd5\xd2\xce\xd6\xdf\xcc\xda\xce\xe7\u05eb\xd6\xd8\xd4\xd4\xdb\xd0\xd8\xd8\xe3\xd8\xda\xd6\xd3\xdb\xe4\xda\xdc\xd9\xe6ݯ\xd7\xde\xd3\xd5\xdf\xda\xdd\xdd\xe5\xdc\xdf\xdb\xd7\xe1\xdc\xde\xe0\xdd\xf0\xe0\xb3\xdc\xe1\xe4\xdf\xe1\xde\xe1\xe3\xe0\xe3\xe5\xe1\xe1\xe6\xe9\xe4\xe6\xe3\xe8\xe5\xea\xe5\xe7\xe4\xe6\xe8\xe5\xe4\xe9\xeb\xe7\xe9\xe6\xef\xf2\xee\xfe\xff\xfc(t:\\\x00\x00 \x00IDATx^\xed\xbd\x0fp\x14G\x9e\xe7\xbb\xcc{\xbe}ϯ\x84zf$\xf5\xae4b\xef8M\xb4BB\xc7\x19\x9e%`\xd7z\b\x8b\xf3\xc2C\x1b\x02\xc1\x03\x9d\xe1\x16\xc6\xd8\xf3\b\xb3+0\xecB\x888\x9be,\xeel\xe4\x85~\x92\xb5\x1e\x99\x91X\xd9 \xa2ό\xa4\xc0\x9a6 ,\x06#\xd9H0\xd8\xc6\v\xde\x18\xf5\x10\xb6\xc5ȱ\xf66a\"\xda1\xd1\xe4M\xbcʪ\xee\xaa\xcc\xea\xcc\xca\xeeVw\xb6\xd4\xf5\xfb\x04!\x15\xa9\xac\xac\xac\xac\xfev\xfd\xe9\xea\xfa\xfc\xc1\xef\x93\a\x01\x000{\xf9\x03Q\xc2m\x10\xb5\r\x00\xc0\f\x06\xc2\x0f\x00\x0e\x05\xc2\x0f\x00\x0e\x05\xc2\x0fd+aQ\x05\xa7\x03\xe1\a\xb2\x92@c\xa1\U00084a12Á\xf0\xf7.\x9e\x14U\x91I\xc2ݙZ\xdc+\xaa2\xa3\x90\xd3\xdfpI\x89w \xaa\xe5p\xe4\x86?\xd0w\xbc\xbd\xfbB\x10O\x06/\xbc\xd1\xfe\x86>I\x94\xf2\xf8\xd7#kk\xf7=\xb0\xab\x11C\xb3\x92\x8b_e\xbe<\xa5ٮZ\x8b\xfd\x9f\xd9\f\x14\xfaDU\f\xa6\xb6\x15歈\xfb\b4\x89\xee\xb4\xe4\x1c\x14U\x91\x8b`t\x92\xeeo\"\xa3~U\xe9\x13U\x01\xa4\x86\u007f\xd2\xeb\xbb\x11\xb8q\xf2\xb8\x9a\xf3`\xe7I<\xd9\x19\xa4J\xb9\xecn8\xfbR\xed}\x9b\n\xb1L\xd5\xe7-U\u007f-ͫ\x9f\xb2\xa9՚\xd3a\xf3W\x1e\xbe\xfc7DU\f\x96\x16z\x1b\xf3l\xdf\xd9\b\x92\xea\x8eon\xab\xa8Jz\x18\x1ce\x16\x8bFG\xd8\xdf$\xdb%\x19V\xfc\xa2*\x80\xd4\xf0\xdf\xf6\xe2\x03\xb1\xa0\xf7\x06B\xfe\xee\x90:\x19\xea\xf6S\xa5<\xeeW\x9fA\x0f\x12\xcb>BM+\xd4\xccM\xe5\xadh\xb2\xa9s\xdbe\xf7W>q\xef\xc9єҊ\xc2\xf1f?\xc9\xee\xecqe\xe6\x00wa=\xbb\\4:\xa2\xfe&\xdb.\xc1\xb02$\xaa\x02H\r?\xd2B0\x89\xc3>\xa0\x9f\xf8\xf5\x0eP\xa5<>\xab~\x97\xffG\x1eM\xf5K\xbbP\xe7\xf2z\xbb<5\x16ś\xcbd\xb9\xa9\xc4\u007f\xac\x9alw\x82E\x8d\xa2*i\xa1\xacNT\x83\x8d\xa8\xbfɶK\x00\xe1\x8f\x03\xb9\xe1W\t\x05\xba}\xea;\xf8T\xe7\xe0Th\xca\xdf9E\x952\xf9vm\xb5\xc61\x84\x8eTW\x9fC\x9f\xd5Voœ\xb5g\x8fm\xad\xdd\xf7[\xad\xceg/\xac\xadm\x88LGi\xaao\xadC+\xbc8\xfc\xc1\xba\"W\xf1ʫj\xe16en\xeb\x93\xc5\xee\x957\xb5*\xa1\x02\xed\x9d!T\x98\xdbT\\4\xb8\xdd]\x15\xe4\xd4%g\v\xe6)J\xceq\xa4U\xc8\xf5\ue61f\xb7\\{ۚZ\xef.ޱÝ\xdfMt!\xe4V4v\xe0\xba9\x9d\xea\x9e])\xb1̆n\u05f9s\vW\x04\x88\ue82bs\x15e\xcf\xcd\xf5\xf3\U000961f8\xb3u.Ο\xbf#\xfaV\xb1'/\x84(\x12n\x81\x81\u007fyq\xae{E1\xafԧ\xaf\x9aRF--\xbeщ\xe9o\x8a\xda5\x19\x84\xf0\x8b\x91\x1c\xfe)\xaf\xd7ۡ\xbd\xe0B\x03\xead_\xc8R\xca\xe4ӱs\xd5=cc_\"\xf4۱\xda\x1e\xf4`\xecH-B\xb7\xce\xd5V7\xf4\xf4\xac~\x01\xd7\x18\xab}\xb6\xe7J\x8fzn@\xd2T\x1fȟ\xfa^\x00\x87ߧ<9ؽ2g\x18\xa1\x1b\xc7\xe7*\xc5\a\x9b\x8b\xf3\xc6q\x95QeP\xab:X\xa0\xecX\xaa\xb8\x0f\x16\xb6p\xeaR\xb3]\xf6\xfb]\xdae9\\Z\xd8\xdcR\x80wT\xa1\x92\xa2\xd6fW^\xfb\xf2\x16\xb2\x0f\xef\xfb\xbb\x94f\xbf_}\x9d\x06\xfc\xb9\xea<C\x8d.z64\x98_\xd62Ь\xb4\x90\xdd\tu\x1f/\x9e_P\xbcc\xbd\x12\xe0\xcd֘\xb3\xdd\xd7ZX\x16yü`}\xa9'\xdcB,\xc3\xca\xfa7\x06\xbcn\x85\x8e\xa9Y\x1a\xbc\xe0\x9f_\xe5\xf7\xfboPK\x8botb\xfa\x9b\xa2v#\x84&\a\x17\xba\x93:\x86r\x16\x92Ï&\x03\xe3\xdd\xf8\xd2^h\xa0\xfbF\xe0F\xf7@\x88*\xe5a\x1e\xf6\xab\xe1G\xa8\xa7V\x9b\\\xad\xee\xe9_lP\xa7\xbeݴ\xef[\xf5\xe79\xfa\xaa@S=*۶\x10i{\xfen\xdcx\x99\xf6\xb9\xafk\x1e\u07bd\x17/\xc6\xd3>\xe5\xb6^\xb7h\xbd:\xedC\x8dOr뒳!\x94\x17\xb9&\xefr\xab/\xcb\xf5\x85\xeaT\x97\xa2\x1e,\xb4*\xe3Ȃyد\xbdt\x9b]\xf4l\xa1bu\xaf\xa6\xbeʵ# \xa3;\xea\xf2\x95\xa5A\xfd\x84\x889\x9bO\xc1\x17\x06\x87\x95.\xbdv@\x89\xbd\x14\x96X\v\xb1\xb4\x16\xe2m\xd3\xea\xa6\xdf\x1d\xa8R\xe2\xf0\xdc\\\x1a\x8actb\xfb\x9b\x9av#<\xa1\x1e8$p\xb2\xe5Xd\x87\x1f\xe1W\xfa\x80y\xc1\xef\x02Uʃ\x1d\xfe\x97\xa2\x93W\xaa?e̤\x86\xbfE9\xa8\x85\x1fM\xb5.\x9fW\x80\x8f$\xd5W\x8evhݪ\xe0\xb8\xf5\x1a\xe1\xefBCJ\x10\xcf«K\xceF\xbc\f\xf1ɫ\x96\xab&7\xc2I\x8f\xf9\f\x9b\x1d~c6\x9f\xf2\xbeY\xb7\x97\b\xbfqM\x8c9[\xfd\xbc\x10\xa68r\xee\x1c`d8\xb1\x16b\t\x14\xcd\xdb\xe6}?l9>\xa7Jɐ\x92\xd7\xf0\x84\xa3\x13\xdb\xdfԴ\x1b!\xd0\xe7-\x81=\xbf\x18\xa9\xe1\x0f\xe9{\x91\xab\xdep\xb8]\u007fͿ\xdf\x1e&J\xb93\xb2\xc3oL\x9e\xa9\xfe\x961\x93\x9a\xe4\xa9\x1d\x93Z\xf8\x87\v\x8b\x9bN\xfa\xab\xf4@k\xaf\xa0A\x05\u007f\x9c4\x14=\xfc,\xeaC\xc3.m\x16^]r6\xe2eh\xe4\xaa\x05\xbf-\xf4Ż\xe7'f#\xd2etG}їE\xa7\x98\xb3\x95EN\x8c#\xf7\xb0\r+ƛ\xa8Ab-0\bz\xebJ\x94B\xeax\xdaRJ\x86\xd4X\x1a\x8act\x18\xfdMI\xbb&~e8\xa6\f\xb0 3\xfc\xe1N\xfd\x94VM|4\xfc\xa3\xea\xa4Yʝ\xd3\x12\xfeW-\xe1\xbfR}\x8b1S\x93\xfe\x81\x11\x0e\u007f\xc9b\xbc\x1f\xa8\xd3\x03\xbd\x1d\xff\xf4*\xb8$芼\x9c\x88\xf0s꒳\xb1^\x86\x81\x9c\x15\x81\xab\xf3\x17Ǭ\x83%\xfc{,\x19\x1cP\x88ϴ\x8d\ue42f\u007f\xe6l\xeb\xe7\x8djD\xae\x976\xbbb\xf7s\x89\xb5\x10\xcbe|\xa8\x13\xecʣ?\x93\xa7J\xb5E\xb4\a\x8c\xc9(\xc2щ\xedoj\xda5\x81\xab\xfdq 3\xfc\xe8\xb8vוv\x80?\x189\xec\x1f\xa4Jy\x10\xe1\u007f\x15\xa1\a\xcfZ\xc2\u007f\xbfa7\xde\xf5\x1f;F\xcdD\x84\xbf\x18\xbf\x84\xc2\xfa^\xc4U\x88O\"\xe7U\xe9\u007f\x9c\xa7\xbfn\x88\xf0s\xeaR\xb31^\x86\xa3J\xa1\xa2T\xc5~\\i\x86?O\xedHx\xa1%\x83\xc1\xa2*<\x10۵\xb7\x16\xa3;䋞9[\x9f\xa2]\xdeޣ\xdf+\x17.Y\x81bH\xa8\x85\xdb\xcd1\xf7\xd54\xeb\xf7\xc8Um\xe3\x97V\xa9\xa31\xa9\xb7#\b)=:\x8c\xfe\xa6\xa4]\x02\b\u007f\x1cH\r\xffM\xef\x00\xbeʧ]\xf0\xeb\xea\x1e\x0f\x8cww\x85\xa8R6\x91\xab\xfd\xdaݽ\xbb\x1bzz\x9e\xad\xae={\xeb˱\xda#c\x0f>=R\x8b?\x05\x18\xab\xddz\xf6ʱ\xea\xb3\xe4\\S\xf5ڋ\"PU?\xa5\xbe\xb4\xeaZ\x0f\x96)\xee\x96!\xf5\x95\xa3\x94u\xb7\xcfw\xebg\xd77s\xb4\x03\xcd\x1b\xee\x96`W\xee\xd5 \x9e\x85Sל\f\r\xf9\xfd\xaeF\xbf?\x88\xaf\xe07\x0e\xa1\xd1\xc6\\\u007f\x00\x8d\xba\x06|\xfe\x80u\x17\xa4_\xed\x1fҊ\x17\x17\x1e<\xb8X\x99\xdbq\x83\x9c\r\r~\xaf\xc4\xebۮ\xb4\x93\xddQ\x97\x80/x\xeb]d\xcf֤\xd4w\xf76*\x9dZ\x95\x16\xc5\x1a\xddD[X\xa9\xe4[\x87\xbfY\xc9o\xf6\x9dl\x8c|\x00\xc1,mv\xb5\xf4.\xcd\x0fPK\x8bgtb\xfb\x9b\x9av\t.3N\x84\x00\vRÏ\x02\x83\xdd\xed'\x87\xb4\xb3\xdc\xd0\xf0Ɏ\x93\xc3!K)\x8boWk\x1f\xf3\xd7\xfe\x06\xff\xe7\xb3ݵ\xab\xf7\xbdZ]}\xe4\b.\xfa\xb4V\xfdyD-\xfe\xcd\v\r\xab\x9f\xa5o\x04jV\x14|]h\x9b\xa24\xa3p\xcb|Wa}\xc7<\x97\xbaKq\xedh,(Z\x1f\xddY\xec\xf9\x9e\xfa\"\t\xab\xbb\x8f\xe3\x05J~7>\x05\xe6\xd45'\x87s\xf4\xb3e/n[\xc9\x1d\xcfW\u007fnC\x17\\\xb8,\xb7\x8a:\xfd\x8c|\xce?W\xbby\xf1fU^\xc1\xf2&\xb5.9\x9bZ\\W\\\xb0\xf0$\xd9\x1dtU_\x82\xbe{\xe4\xcc\xd6W\xe5v/\xd6\xf6\x96ȟ\xb7\x03YH\xb0\x05Ԟ\x1fs\x8e\xdcY\xd5\\\x9c[TEg\x9f.\rmw\xe7U\r\xd3K\x8bct\x18\xfdMI\xbb$\x93s\xeb\xaeN2\xde\x14\x00\x02\xb9\xe1\x9f\t\x98\xe7\xd5\x1a\xdb]\xd6\xfbC\b\x88\xba\x96٬L\xe6o\x9b\f\x85\x82\xc3uӼ\xcal\xdb\x1d6]\xaeF\xee\x1bg\xdc\xf4*\xd3\xeb\xb7=\xd4褤\xbf:6\xa3\xde[bw1\x13\xc08>\xfc\xa8\xa5\x98\xff\x1d\xda\xf8\xc3\xdf\x1b\xf9<<\xec\x9e\xe6\a\xccv\xdda2U\x94\xe4\x97\xe4\b\xc2\x1d\xee'Eu\xa6\x039:\xa9\xe8o\x14\xdbQ\x9f\xbcʸ\x16\x00\x10@\xf8\xed\x88?\xfc\xa39\xfa\x91\xe7x\x0e\xf1\xb9\xfd\xac!\xe0ޑ\xaa\x9d1\x93t\x8dN\xba\xdau\bN\v\xbf~\xb5(>\x88\xba\xc2\xd9\u008dyOv\rv=\x99\x97\xd6=\xe8l%]\xa3\x93\xaev\x1d\x82\xd3¯]-\xba\x8d₨\x1b\xc7l\xbe\xe5E\xae\xa2\xe5\xd3<\xe8\xcfZ\xd25:\xe9j\xd7\x118-\xfc\x00\x00D\x80\xf0\x03\x80C\x81\xf0\x03\x80C\x81\xf0\x03\x80C\x81\xf0\x03\x80C\x81\xf0\x03\x80C\x81\xf0\x03\x80C\x81\xf0\x03\x80C\x81\xf0\xa3\x03\aX\x93\x00\x90\xed\xc8\r?[ץ2\xee\xcd\xd8MZ\xff\xecy\x991\xa9\xf1\x91G\xe7z\xccL1\x1c\xf0x\xfaEuf\x12\xa9\xe9\xef\xc5\xcawDU2@j\xd6M̝R\xcf\x1aQ\x1d\x9aSt\xcf2=|R\xc3\xcf\xd6u\xa9\x04\xdb/t\n\xe6M\x1b{\x17\xdceLj\x84?\x189\xe591\xf2\x81͗^.}\xa8\xff\xbe;R\xdaƯ\x958\xd1vSM\x92\xfd\xe5t\xe7|\x85\x94\x94%H\x82\xeb\x96<\xd7\xf6\x97\x8b\xaa\xd0\xdc\x1b\xd9H\xf6,\xd3\xc3'5\xfcl]\x97\x8ao \x90\xa9\xf0Ox~\u00984\xb8\xe6\xf9 \xa6\x8c\xe4\xff\xd9\x15\x9d*O\xe9\v\xcel7\xb5$\xd9_^wf\xe8\xe32\x12Z\xb7iЖ`\xf8\x11\xdaI\xf5,\xc3\xc3'5\xfc\x1c]\x17\x1a\xef\bf,\xfc\xfb\xcb\xef2&\rD\xe1ߐ\\\x98\x84lHS\xf8\x93\xeco\xba\xba\x93&\x12Z\xb7i0\xdd\xf0g\x18\xb9\xe1Wa躂\xed7Q\xa6\xc2\u007f\xa7\xf4\x10c\xd2$\x12\xfe\xe7=\xa5\xa7\u007f\xb2\xaa\xe2\xa9ϩ?\xbe\x13\xb9&\xb0\x01\xff\xa7\xfc\xb0Y\xe1\xe7\x9b+V\xfd\x84>Yh\xf3\xe0\xf3\xbd~\xf5\xe7Q\xf5\u007f\xa76T\xac;\xa5\xfe\xfe\xa8T\xfd\xff\xc4ޚ\x05O\xabc2\xf2TMi\xe535\x96vI&vU\x96.yF}\x8b\n\xeeZVZ\xb3\xf3#\xadИ\r1\x17L\x90H\u007f\xd9\xdd!\xfb{\xaf\xc2\x139\x85\xa5F\xe7뽕\x8f\x1d>\\i=\xa2et\x9d=\xa8D\v\xd4\xe8\x18cF\x8fd\x14\xaa\x94\xb5n̥\x85\x97\x94\xbe\xf2زK\x87\x16m\tZzv\xe2\xc0c\x8f\ue720&\x119Pw\xf7.[\xb4\x8b{\xd8\xcfiW\v\xff!\xb5\x8f\v\xbeNp\xf8҂\xe4\xf03u]>u\xf7\x9f\xa9\xf0\x1f(\xfd\x9c1i\x12\t\xff?\xf7\x97z*\xdbN<B\xef\x00\x83\x1f\x8c\xac\xda2222\x81\xffS\xeeY\xd3\xff\xce\x12\xad\xc2~ϡ\xf3'*7P\au_=\xb7y$\xa8α\xf9\xb9\xaf\xf01\xc6\xd1\xf3G\xcb\xf7\xaa\xa3\xd0\xdf_\xb3\xea\x91\xc7~\xb2\xd7s\a]\xf7\xec\xed\xbfx\xba\xd2\x13\xa6\xdb%x\xafb\xc3\xeb\x17\xdb<'ԳEρ\xf7\xfawz\xae\xa9\x85\xe6l\xec\x05\x13$\xd2_vw\xc8\xfe\xa2\xeb##\xfa.\x96\x1c\x9dКe\xa7\xda\xca+N?u\x82j\x8d\xd5u\xf6\xa0\x12-PK3ƌ\x1aI\x03\xaa\x94\xb5n쥽\xb7\xc8\xf3\x93\x1fy*_[\x12ӳ\x9a\xd7\xdaj*>!'Ɂ\x9aX\xb4\xea\xf4;Oy\xb8{~v\xbbZ\xf8\xef\xee\xf5\x9c\xd06\\\x02×\x1e$\x87\x9f\xa5뺁\xdf\r2\x14\xfe;\xa5\a\x18\x93\x04\xc6a\u007f\xf9\"\xf5\xadao\xa5\xf5\xef\xc4a\xf4\x92\xaf\xd5W\a\xaep\xde\xf3\x966'\xfd\xe6\xfd\x96~ex\xdd\xcf\x11\xba蹈\xf0\xcf\xf3Z\v\x9e\x1f\x05\xb5\x13\xa2S\x95\xda\xfemQ\x98n\xd7$T\xf3t\b\xe7\xef\x1e\xfe\x81\xdf6\xd7\xedD\xd4l\xec\x05S\xc4\xdf_^w\x8c\xfeb\x16D\x8eb\xcd\xd1\xe9\xf7|\x84\xafj\u007fB\xb5\xc5\xe9:{P\xa9\x16\x8c\xa5\x11cF\x8c$\x01Y\xca^7\xe6Җ\xedU뼃\xf6\x1f\xb0\xf4\xacF]潚\x8d\xd4$\xd1\xd8\xe6Uj\xdd\xf0:\xfea?\xa7]5\xfc'\xca\xcfG+\xc5;|iBv\xf8\x11\xb2꺂\xed7\xc2\xe1p\xa03\x9c\x89\xab\x1fϗ\xdeaL\x12\x98\xe1ߏX\xe7xD\x98\x0eD+\xecz<\xa4\xaeQ\xf8\xb1\xfdT͏<\xa1\xd0[\xf7\xc2\xe5\xea\xc6ݿN+Y\xa3U\xd8P\x1eY\xee\xe7\xcbj\x9e?\xfdQ\xc4X\xc5\n\xffy\xcfG\xc6\xf4ק\x9e~|\x91g\x1d=\x1b{\xc1\x14\xf1\xf7\x97\xd7\x1d\xa3\xbf\x18\xe3\xd5k\x8c\xceˋ\x10\xbet\xfa6\xa2`w\x9d=\xa8T\v\xc6҈1#F\x92\x80,e\xaf\x1bsi\xcb\xfa\xd5m\x1cD\x87\x9fCtϴ\x0f}Oy\ue453fc\xf7<\xa7q\xe1Q\x9b\xf0\xb3\xdb\xdd\xd9v\xd4c~\xbe\x17\xef\xf0\xa5\t\xa9\xe1g\xea\xban{\xa3\xc8\u007f\xde\xe2\xdd\xf2\x03\x8cI\x123\xfcx;نߨ\xb0.r\x8e\xbc\x93\xaa\x19*\xfd\xe4\x84z\x06\xebQӴY\xff\xcb\u038dZ\vƙ\xfd\xbdӻ\xd6x\x96\xbc\xaeM\xb3\xc2\u007f\xc2c\x9c\x96_[Rs\xf8\xed\x91-\xeb\xe8\xd9\xd8\v\xa6\x88\xbf\xbf\xbc\xee\x98\xfdEī\xd7h\xec\x84\xe7k\xbc\x83\xb6\xec\xba8]g\x0e*Ղ\xb14b̈\x91$ K\xd9\xeb\xc6\\ڲ\x8b\xe8Z\xa9\x1a\xba\xe7\x18=C#\x9e\x0f\xc9I\xb3\xb1\xeb\x9e\x11\xc4hL\xdc\xee\xce%\x8f\xac1\xc72\xde\xe1K\x132\xc3\xcf\xd1uMM\xaa\x8cwLf\xe01\xeb\x87<\x13\x8cI\x92\xb8\xc2\u007f\xfa\x0eUa\xef\xe3\x1fj|MW]ӿe\xf3\x9a\xb7\xf1\xc1\xe9\xfeǵ\x82\x9a\xfdF\v\x98\xebx\x0fs\xaf\u007f\xc1)\xba]\x93K\xe6\xees\xcdFmO\xbf\x8e\x9e\x8d\xb3`\x92\xf8\xfb\xcb\xeb\x0e\xf5\xb6\x14\xfb\xea\xbd\xe3y\xfa\xceG\xab6[\xb6%\xbb\xeb\xecA\xa5Z0\x96F\x8e\x999\x92$D){ݸ\xe1/\xd7CJ\xf5L\xbb\xf8{Z\xddw\x13\x93fc_{\xb4a\xb1\xf9\x9c\x9f\xd3\xee\xce\xcaO\xee,2\xce\xe7\xe3\x1d\xbe4!3\xfc\x1c]\x97FF\xce\xf9\xef\x96\xefgLR\x88¿e\x8b:\xaf~FiT\xb8\xa8\x9f=\x1f}\x8d\xae\xfa\xdc\xf3\xa5\x17=\a\xf0\x8b\xf9\xbcV\xa1?r\xce\x1f}y\xb7ig\xb5h\xcb\x01\xba]\x93в-x\xd0\x0e\xa9/\xc6\x1a<Sx\xdd:z6z\xc1w\xda\xe8\xe3b\x8d\xf8\xfb\xcb\xeb\x8e \xfc\x1fz\x96x<[\xac\x9f\x99\xb2\xbb\xce\x1eT\xaa\x05ci䘙#IB\x94\xb2\xd7M\x14~\xaagK\xd4\xfe\x06\x1f\xdfBM\x12\x8dm\xacQO\b&\x16D\x1ac\f5\xa7]\xfcQ\xdf\xf9\xd2k\x91J\xf1\x0e_\x9a\x90\x1a~\xb6\xaeK%\x1c\x18\xef\bp\x95\x91i㰹\xb7?\xcc\xda\xf1G\xee\xf0\xbb\x16\xc27\x8d\xed\xbf\x86>\xdc_:b\xd9.m\xe5'\xde\xfeQ\xc5\xe7t\x85\x97=\xcf\xf5\xbf\xbd\xdfC_\x90B\xafU,\n\xafZ\xa0%l\xaf\xe7\xe5\xf3/{\xf6\xaaK\xb8\xa6]H\xd7v\xa9m\x9e\x8a\xb6\xf3\xeal\xef\x91\xedR\\Z\xb0\xe6\xd4\xf9C\xf8t\xb3ͳ\xeb\xd4k\x1b<\x95\xaf_\xa3f\xa3\x16\xbc\xd3Sq\x0fY\x89\xbf\xbf\xcc\xee\x90\xfd\r}02R\xbe\u007fd$H5\xf6Q\xf9\xa5\xf3#wc\xf6\\\xac\xaes\x06\xd5l\x81\\\x9a9f\xd4H\x12\x18\xa5\xecuc/\xed\x9f\x1e=\x11\xea/\xfd$\xf4ܖ\xcf\xc9AE\xe5\x9e\r\xfd\xa7W-\x9a@Ԥ9P\x9fT<\xd6v\xf4QO\xe9[\xff\x84[\x89\x1djv\xbb\xf7F6\xee\xff \x14ڹ\xec\xd2W\x89\r_z\x90\x1a~\x8e\xaeK-ǧ\xfc\xc7mfL\v_U\xeceL\x12\x98\xf7\xf6\x1fP\u007f\x96~\x82?\x99\xb5\\\x19\b\x1dzt\xc1\x96k\xc8R\xe1\xe2\x96\xcaE\x9b\x8dk\xba\x11\xae/:\x8a^\xaf\xd0\xde\xf4\xc3'\xd6U\xac;\x156\x96\xa0\x9d\xcf\xfe|s[M\xe9\xb2-\xefQ\xed\xd2L\xecz쑍ok\r\xac*\xaf\xdcuzU\xe9\x16z6r\xc1\xa7+<1\r$\xd0_fw\xc8\xfe^\x8f\x8c\xcei\xaa\xb1\x0fJqY\xe9f\xebY+\xa3\xeb\x9cA5[ \x97f\x8e\x195\x92\x04F){ݘK\v\xab\xfb\xd9\xfeG<\x15\xfdx)Ġ\xa2\xf2\x9f\xec_\xb4l\xaf\xf66AL\x12\x035\xb1\xf3њ\xc3o\x95\xea\x8d\xc5\f5\xa7\xddSxu\xae\xeb7#$6|iAn\xf8g\x16\xafx\xfe\x991\x99=\xbc\xed\x89\xdd\U000e76ef*\x0e|\x15\x0e\u07fb\xbe\xeb\xd1d\x97=\xfd\x16R\x01q\x8f`<\xb7\v\xa6j\xa8宼\x93ß\xdd\xdf\xe5\r\xbf\xb5(\x03+\xf5\xb6~_\x00\nWZ\x0f|\xe2e\xfa-\xa4\x82\x84\u009f\xba\xa1\x96\xbb\xf2N\x0e\u007fvs\xb7\x92\u007f\x9fo\xfa\xf80\xf2)\xd5'\x1e\xc6\xd5Ƹ\x98~\v\xa9 \xa1\xf0\xa7n\xa8\xe5\xae<\x84\x1fH%\xe1\xfd\x15\a\xfa\xdf\xeb?P\x91\xf4\xaep\xfa-L\x1f\xfd\x12\x9cuR\x02rW\x1e\xc2\x0f\xa4\x96w\x9eZV\xba\xec\xe9\xe9\x1c\xb5N\xbf\x85\xe9\xa2]\x82\xbbc\x9d\x94\x82̕\x87\xf0\x03\x80C\x81\xf0\x03\x80C\x81\xf0\x03\x80C\x81\xf0\x03\x80C\x81\xf0\x03\x80C\x81\xf0\x03\x80C\x81\xf0\x03\x80C\x81\xf0\x03\x80C\x81\xf0g\xf9-\xfe\x00\xc0Cn\xf8\x99\xba\xaeP\x87\xf6\x10\xaf\x8e\x14\xdd\x1e\x9d(6\xba.\x93\x03\x12<K\xfb=\x1eOń\xa8V\x8a\xe8\u05feNZ\xb93\xde{\xd7\xd8k\xfcAe\x1c&3\xe9\xa4Fו\x96m\x8c\x12k7ͣ.5\xfcl]W\xd0\xfb~@eR4w\x9a\xb0\xd1uq\xedVi\xf1,}>2rJ\xa0\b\x11\x12\xb7\xe5+\xf8\x8e畑\x91\x9f\xaf\xab\xb4>\xf2K(\xe6\"+\x9c֟c9\xc3H\x8d\xae+-\xdb\x18%\xd6n\x9aG]j\xf8ٺ\xae`\x06\x9e\xdcib\xaf\xeb\xe2٭\xd2\xf4\xa8\x15\x91\x1fHH\xfc\x96/\xfd\xa1\\_WXc\"\x14s\x91\x15\xfaS\xb1\x8bM\x03\xe2/\xe2\xc5A\x9a\xb6qB\xed\xa6wԥ\x86\x9f\xad\xeb\xcal\xf8\xedu]Iڭ\x92e\xda\xe1\x8f_\xab\x15y\"\xdf:\xeb\f\xc2\x16\xc8\n\x97<\x97\xf8\x153\x88\x94\x8d%\x95\xb4\x8c\xba\xdc\xf0\xab\xc4\xea\xba2\x1a~;]\x17\xc7n%\xf6,\x91\x02\xad(\xcf{<?\x8fH\x9d\x89\xd9h\x19\x14\x11~\xc3\v\xc5\x16s1\x9dW\\\xcb\x17\v=\xfcw\x17\xbcF\xf6\x8cӂ\xb9Ɩ\nף\xf6r\xd6\x1aӥQ\xd9\x16\x01i\xe32W\x88vt\t\xc5gL\xd3X\xf9\xa1\x03\xcb\xf4A\xe5\xb4KJ\xb1X-p\xb6\xb1\tǗfL\x9a\x83J\x99\xbbį\x1d\x93dG=~$\x87\x9f\xa5\xeb\nz\a\xde\xf0\x1e\xf7g\xe6z\x9f\x9d\xae\x8bg\xb7\x12y\x96H\x81\x96\x81~\"\xaaI\x9d\x89\xd9(\x19\x14\x11~\xd3\v\xc5\x16s1\x9dW<\xcb\x17\x93\xbb\x9eӡ\xe0\a\xeb\xd6\x04ɞ\xf1Z0\xd6\xd8R\xe1n\xa5~\xac\xc4\\cZ$\x16\x95m\x11\x906.s\x85hG\x97P|\xc6\x14\x94\xe1gn\xf6\xafÃ\xcan\x97\x94b\xb1[`nc\x02\xf6f1'\x89A%\xcd]\xc2\xd7\x0e\xb3\x0f\t\x8dz\x02H\x0e?K\xd7\x15\xf4v^U'\xbb2\x91~\x91\xae\x8be\xb7\xc2\xd8z\x96(ѕ\t\xf1\xe4hB\x1cEx\xa1\xcc\xf0\x13^(\xb6\x98\x8b\xe7\xbc\x12\x1e\xb4\x1b\xdc\xd5\xf6%\xab\xb4\xf7;\xf2\x99ּ\x16\xa2k̬\xc0^c\xa2\x94\x12\x94\x11\x186.r\x85\xccR\xa1\xf8\x8c#(+_\xa3\xb6\x16Z\xb5\x91\xd7.\xb1\xb1\xf8\x8a\xb3\xd8mL\xc0\xde,\xe48\x98\x83J\x98\xbb\xd8\xed\xf2\x1d]I\x8cz\x02\xc8\x0e?BV]\x17\n\x8fk\x93\x1dC\x82\xf9ҁH\xd7Ų[al=K\x94\xe8ʄ\f\xbf)\x8e\"\xbcPf\xf8I\xc9\x14S\xcc\xc5s^%\x12\xfe\xa3\u05ee]<\xa0}j4\xed\xf0\xb3ט(\xa5\x04e\x04\xa6\xfb\x8bX!\xb3T(>\xe3\b\xca\xca_\xc1?\xb5Ae\xb6Kl,\xbe\xe2,v\x1b\x9307\v9\x0eD\xf8\ts\x17\xb3]\xbe\xa3+\x89QO\x00\xa9\xe1g꺢\u007f\xf4\x9fdϔN\x84\xba.\x96\xdd\nc\xefY\"EW&d\xf8-\x93\xba\x17\xca\f?!\x99b\x8b\xb9xΫD¯\xed\xebv\xadB\xf1\xb5`\xfb2䬱YJ\t\xca\b\f\x1b\x17\xb9Bf\xa9P|\xc61\x8d\x99\x83\xcan\x97\xd8X|\xc5Y\xec6&`o\x16r\x92\b\xbfi\xeeb\xb7\xcbwt%3\xea\xf1#3\xfcl]\x17\x1a\xf0i\x93\x83>\xee\x8ciC\xa8\xebb٭0\xb6\x9e%Jte\xa2\xd5=\x1a\x13~\xd3\ve\x86\x9f\x90L\xb1\xc5\\<\xe7\x15\xcb\xf2\xc5&\x12\xfe\xd3\xf8uG\xf4\x8c\xdb\x02\xfd2\xb4T`\xaf1QJ\t\xca\b\x8c\xd74\xb9Bf\xa9P|ƩP\xae}f\x8b\a\x95\xdd.\xb1\xb1\xf8\x8a3\xdb\xf0\xb37\v9\x0e\xe6\xa0\x12\xf2\x1ev\xbb|GW\x12\xa3\x9e\x002\xc3\xcf\xd1u\xf9\xb4]\xfeT\xc7\xfb\xb6\xf3\xa6\x03\xb1\xae\x8be\xb7\xc2\xd8z\x96(ѕI\xc5a\xf5\xfdocL\xf8M/\x94\x19~\xc2\v\xc5\x16s\xf1\x9cW\xa4\xe5\xeb\xcek\x13\x88O\xa4\xd6\xdeG\xc2TϘ\x9e0\x8c\xf12dU`\xaf1QJ\t\xca\b\x8c8\x92+d\x96\n\xc5g\x9c\n\xe5\x8f\xe1s\xfe5[x\xed\x12\x1b\x8b\xd3\x02\x12\x84\x9f\xbdY\xc8q0\aU\x18~\xbe\xa3+\x89QO\x00\xa9\xe1g\xeb\xba\x02\u07be\x9b\x81\xcb\xed\xbe\xa4\xaf[$\x8dHׅ\xb7M\xac\xddJ\xe8Y\xa2DW&\x9b+_\u007fm#\x16<Q\xe2(S\x06\xa5\xdd\xe1wB\xb7S\x99^(\xb6\x98\x8b\xe7\xbc\"-_;=\xcf .!\xed\x0e\xbf\xb7\x9f\xf3\xbcN\xf6\xcc҂Q\xd9XcN\x05\xf6\x1a\x93\xa5\x84lˀv\x95EW\x88rt\t\xc5g\xec\n垧\xaf]ڌ\a\x95\xdd.)\xc5b\xb6\xc0\xde\xc6\x04\xbc\xcdb\xae\xb11\xa8\xa4\xb9K\xf8\xdaa\xf6\x01%2\xea\t 5\xfc\x1c]\xd7\xe4\xc0\xf1\x0e߸\xfc\xec\vu]l\xbb\x95гD\x89\xaeL&\xb6,x\xe4\xa9WԺ\x948ʔA폴\xab\xed\x9e\f/\x14[\xcc\xc5s^\x91\x96\xafӕ6w\x81\xea\xf7\xf6\x97\xaeӪ\x18=\xb3\xb4\x10\xc5\\cN\x05\xf6\x1a\x93\xa5\x84lˀ\xb4q\x99+D9\xba\x84\xe23v\x855m\xbb\x1e\xd1\a\x95\xdd.%\xc5b\xb5\xc0\xde\xc6\x04\xec\xcdB\xae\xb11\xa8\xa4\xb9K\xf8\xdaa\xf6\x01%2\xea\t 7\xfc3\x8bT꺒\xf6,\x95\xb7!@2Io\xac\xf4\x90\xb1\xee89\xfc\xa9\xfc.oҞ%\b\xbf|\x92\xdeX\xe9!c\xddqr\xf8SIҞ%\b\xbf|\x92\xdeX\xe9!c݁\xf0\xa7\x86$=KreP\x80N\x92\x1b+]d\xac;\x10\xfeT\x91\x94gI\xb6\f\n\xd0Ijc\xa5\x8f\fu\a\xc2\x0f\x00\x0e\x05\xc2\x0f\x00\x0e\x05\xc2\x0f\x00\x0e\x05\xc2\x0f\x00\x0e\x05\xc2\x0f\x00\x0e\x05\xc2\x0f\x00\x0e\x05\xc2\x0f\x00\x0e\x05\xc2\x0f\x00\x0e\x05\u009f\xd2[\xfc\x01`\xf6 7\xfcL]\x97ʍ\xbe\x8e\xee\xcbv3\xa6\x11{]\xd7\xd7\a\x96,xF\xff\xdeE\"\x9e%\x06\x91\xaf\x94z\x92W-Y|^\xfaӶ\xe3\xab\x1b'|\xd1U\xecʟb\xd6MR\x95\x95\xe8l\xc4f\x89B\xacqr+\x9f6flϤ\x86\x9f\xad\xeb\xc2O\xf1\x1e\xba=\xea\xbd-\x9a==\xd8\xea\xbaЏ\x96\x9c\xda_\xa1\u007f\xd32\x11\xcf\x12\x83\xf0\aڳ:>\xd0\x1ea\x10\xb7V\x8b\xc4\xea\xf3\xd2\x1e\f\x1dg\xdd\xf8\xe0\x8b\xaebW\xfe\xde\xc8FF]n\v\xec5\xe6\xe8\xd0b+X 6K\x14b\x8d\x93[y\x94\xd8f\x89\xbfn*z\x96\x16\xa4\x86\x9f\xad\xebB\x03\xed\x01\xfc\xc6pC0wz\xb0\xd7u\xdd\xf3\x9c@\xc6\xe3Q\xa7\xfd\xb8\x11\xd3\xc9\x11\xbfV\x8b\x86V\xfa\xc4<R\x96\")\xfd\x0f\xf7K\x86\x8c\x95\xdfɬ\xcbi\x81\xbd\xc6<\x1d\x1a\xa3\x02\t\xb5YL\x885Nj\xe5\x13\xda,\x89ԝ~\xcf҂\xd4\xf0\xb3u]\x01\xef\xfb\xc6\xdf\xe4c\xaf\xeb\x9a\xf0L\xebP߂\xb9\xdd\xe3\u007f\xca.M\xe6\xc2\xcf \xa1\xf0\xb3\xd7x\x83(\xfc\xec\xd98\x9be\xda\x11Kd\xb3$Rw\xfa=K\vrï\x12\xab\xeb\x1aj\x0fM\u007f\xa7\x9a,v\xba\xaeP\xa5~\x96\x8e\x8f\ax\xfe&\xa6-\x8aGd\xbbs\xb5Z\x13\xbb*K\x97<\xa3\xbd\x03E\xedV\x84K\x8bhA=N\u07bbl\xd1.\xeba?\xe9\x90\"\xea\n\xacYT\x05\xc3JFڭ8+\xaf\x86\xff\x90\xfa\x87\x05\xf4\x83o\rU\x96P\x03\xc6ѡ\x99k\xc1\x9e\x8d\xdc,\x9c5\xe6\xac<\x01c|\xd9K#ט\xd93\xa2\x05\xb6\u007f\f\x13۳\xf3\xeaܯD\xd4c\x99Br\xf8Y\xba\xae^ߍ\x93\xde\xe3\x17\xe2MPj\xb1\xd3u\xa1\x8fF\xfa=m#\xfa\x93\x1b\xd9\xfe&\xb6\xeb\x89Gd\xbb\xf3\xa4X\xefUlx\xfdb\x9b\a;\x9b\f\xbb\x15\xa1}\"Z@\x13\x8bV\x9d~\xe7)\x8f%\xfc\x84C\x8a\xa8+\xb2fQ\x15\f+\x19e\xcdb\xaf\xbc\x1a\xfe\xbb{=',\xcf#0TYB\r\x18G\x87f\xae\x05g\xa0\x88\xcd\xc2^c\xc4^y\x02\xd6\xf8\xb2\x97F\xae1\xb3gD\vl\xff\x18&\xb6g\xa1\x0fj\x0e\xdcE_\xb5-\x1a\xc9\xcc\v\x1f#9\xfc,]W\xb7\xa6\xeb:ޝ\x89A\x10麨\xe3\xcbX\xcf\x12\xdf\xf5\xc4\xc4\xfe\xb0?T\xf34~\xe0t\xff=\xdanE=9:\xda\xc2\xe6U!\xfc\xe4hK\xf8)7\x95QWh͢$S\x84\x95̰[a\x18\xf2*5\xfc'\xcac\xbe\x84n\xaa\xb2␁\x10\x87\xfdƂiÖ\xfda?{\x8d\x11s\xe5\tx\xe3\xcb\\\x9a\xb9Ɯ\x9eQ-0\xfdc\xccc\x926|\x88\xb1\x97\xf9\xc4xI\xc8\x0e?B1\xba._;~}\x05;\x86E3\xa6\x01\x91\xae\x8b\x1d~ó\xc4w=1\xb1\x0f\xffy\xf3)N\xa4݊\x15\xfe{\xfa#]\x8fZ\xcf\xf9I7\x95\xb14\xa15\x8b\x92L\x11V2ӥ\x85\x98\xf2\xaa\x9dmG\x19\xe7ބ*K\x98+2A\xe6\x82)Ö\xe0\x9c\x9f\xb9ƈ\xb9\xf2\x04\xbc\xf1e\x87\xdf\\cvϨ\x16\x98\xfe1f\xf8?\xf7|\x82B\x8f\xa4ȶ\x9d\x14R\xc3\xcf\xd6u\r\ua7ae\xc1^\xee|iC\xa8\xebb\x87\xdf\xd8\xd8|\xd7\x13\x13\xfb\xf0\x9f\xf0\x18/Q\xd2n\xc5\n\xffu\xcf\b\"J\xa3Pn*siBk\x16S2\x85L\xbb\x15\x86\xa1\xb0ع\xe4\x915\xb1롟\x1fh\xfe1a\xae\x98\t\xa2\r[\xf6\xe1\xe7\xac1s\xe5\tx\xe3\xcb\x0e\xbf\xa8g\xcc1\x13\xf7\f=}\x18]\\\x94\x89\xe3\xdd(2\xc3\xcf\xd1u\x8dvh\xef\t\x033Q\xd7%\b?\xdf\xf5\xc4\xc4\x12~\x8b}\xe9\x12\xb1\xe7'\xecV\xdaҢ\xfb\xf8H\v_{\xb4\x8bv\xd6\v~\x94\x9b\xca<\xed\x15Y\xb3b$S\xac(\xb0\xc2_\xf9ɝE\xb4U\x1aW0TYT\xd7YkL\x96\x9a\xed\xc6\x1a\xb6bf36\v{\x8d\x11s\xe5\tx\xe3\xcb\\\x9a\xb0g1- k]v\xf8ߩ\f\xed\x8f\xf3\x981=\xc8\f?G\xd75\xa5}\xd4\x17l\x97\u007f\x8b\x9fX\xd7%\b?\xedz\xb2\xf7c!r\xbb\xb3\xecK\xa1e[\xf0\x98\x1c:DۭH\x97\x96\xd1\xc2\xc6\x1a\xf5\xa8zb\x81%\xfc\x94\x9bʨ+\xb4f\x91ڧ\x84¯N\x9e/\xb5>\u007f\xd4Teš\x01c\xe9Ш\xb5`\xcffl\x16\xf6\x1a#\xe6\xca\x13\xf0Ɨ\xb94a\xcf\xc8\x16\x8c1\x13\xf6\f\u007fl\xf1Σѣ~\xe1k'\x1dH\r?[ׅ.\xb7_\x0e\x8cw\x9e\x94\u007f\x00$\xd2u闕\xaf\xe1\x03\x13\x8e\xbf\x89r=\xd9\xfa\xb1\xa2w\xf8]\xd3V\x93e_B\x97\x16\xac9u\xfe\x90v:OحL\x97\x16\xe1\xf3\xfa\xa4ⱶ\xa3\x8fF\f[\x06\x84C\x8a\xa8+\xb2f\x11\x15\x88u#\xedV̕\xbf7\xb2q\xff\a\xa1\xd0\xcee\x97\xbe\xa2Z3UYB\r\x98YJ\x0e*\xb1\x16\xecو\xcd\xc2^c\xce\xca\x130Ǘ\xb9\xb48zf\xb4\xc0\xf6\x8fqz\xa6\xf2\xf2\xe3ƅH\xfb\xd7N\x9a\x90\x1a~\x8e\xae\v\xdd\xee\xed8yY~\xf6E\xba\xae\xd0\"턾t\x02\xf1\xfdM\xa4\xeb\xc9֏E\xdf\xdbϲ/\xe1\xcf\xf9\x1f{d\xa3fi'\xecV\xa6K\x8b\xf4yM\xec|\xb4\xe6\xf0[\xa5\\\x87\x14QWd\xcd\"*\x10\xebFڭ\x98+\u007fJ[\x19\xac\xfd:J\xb5f\xaa\xb2\x84\x1a0\xc4ԡ\x11k\xc1\x9c\x8d\xdc,\xec5\xe6\xac<\x01s|\x99K\x8b\xa3gF\vl\xff\x18\xa7gxFs\xf3ٿv҄\xdc\xf0\xcf,R\xa9\xeb\x02\x80\x84\t\x95'\xef\xd9K\x05N\x0e?|\x97\x17\xc8(\xfd\x95q\xde\x1d\x96&\x9c\x1c~\x00\xc8\x1cm\xef\xa1\x1f\xb5\x89*\xa5\x17\b?\x00d\x80\x90g\xc3\xf3\xcb$[y\xad@\xf8\x01 \x13\xb4Ul\x99\x10\xd5I3\x10~\x00p(\x10~\x00p(\x10~\x00p(\x10~\x00p(\x10~\x00p(\x10~\x00p(\x10~\x00p(\x10~\x00p(\x10\xfeYA\xef\xe2I\xea\xffS\x8bm\x9e{\x04\xdfY\x00\xe2Bn\xf8Y\xba\xaeP\xa7W\xe7\xb8`f\xe9lSr\xbaEu\xa6K\xa3\xa2(y7E\xb5Z\x94fkI\xceAfMd\xeb\x1fK\xce\x16\x15\x97K+V\xa0\x15\xd7l@\x06\x91\x1a~\xa6\xae+\xe4\x1d\r\xa8\\\xf6^\x15\xcd.\x9b\x80?ך9\x9d\xc1Qfq2\x04\xfc\xfeVeHP\xa95\xa7#\xa6\xcc7\xb7\x95Q\x13c\xe3\x1fK\xcc\x16%ti\x91\xc4\n\xb4\xe2\x9a\r\xc8 R\xc3\xcf\xd6u\x8dk\x0f\xef\xed\xbc \x989\x13\xb8\xd8\xe1_X\xcf,N\x92aQ\xf8o\xbb\x9a\x18\xa5{\\\x01F\xa9\xc8?F>PJ\x84ХE\xc0\x14h\x89g\x032\x89\xd4\xf0\xb3u]\x1a\xbe7\xe4?\xc9G\f'\xfceu\xcc\xe2$\x11\x86\xbf\xb1\x88\xa52\v\x1652JE\xfe\xb1D\xc2/ti\x110\x05Z\xe2ـL\"7\xfc*\xb1\xba.\xcc\r/}AK\x02\xa1\xc2ܦ\xe2\xa2\xc1\xed\xee*|\x16RW\xe4*^\x89O<n\xccU\x94\x95\xa8XQ\xdc껑k{c\x91{\xa5zJ\xeeSO͛P\xb3\xfa\xb3\x1bObʴV:\x17\xe7\xcfߡeӿ\xbc8\u05fd\xa28f9\x1d\x85^\xfc+P\x10\x99\xaf\xc0\xba\xc36\xc3\x1fml\x9b\x92\xeb\xdd1?o\xb9^3T\x10\xdd\xf1\x8f\xed\xdbT\xbbvߦ\a\xfa\xff\xf6\xe4\xb1\xde\xfbI\xf1\xdf\x00\x00 \x00IDAT/\xed\xfcc\x183\xfcQ\xd3\x18\xa5\xe0\xfazo\xe5c\x87\x0fWV\xf4s\\Z\x14Q\xe7\x15)\xd0\"1\xcc]\xc0\x8cDr\xf8Y\xba.Lw\xf4\b@\"\x83\x05ʎ\xa5\x8a\xfb`a\v\x0e\xf7\x93\x83\xdd+s\x86\x11\n\x0f5\xe7\f\xa1\x0e\xa5\x13?Rإ\x94uu\x95卣\xe0\x85\xe2m\x93h\xb2\xb9\xc0\x1f\f^\xf0ϯ\xf2\xfb\xfd\x9aT\xb81g\xbb\xaf\xb5\xb0,\x8c#\xbc\xfe\x8d\x01\xaf[\x89\t\xe4\x13\xcar\xfc+\xd4Ѫ\xd3a\xada\x84\xdfh\xec\xc6\xf1\xb9JasK\x81~\x801\xaa\xe8O<G\x1f\xff\xd9K箜][\xfd;\xfd\xbf\x17\x98G\f\xb6\xfe1D\x84\xdf0\x8d\x91B\xaaКe\xa7\xda\xca+N?u\x82\xe3\xd2\"1\xdd_\xa4\u05cc\xc00w\x013\x12\xc9\xe1g\xe9\xbaP\xf4b\x80l\x8a֫\xa1\xf7\xa1\xc6'\xd5=\u007f7~G*{B+o\\8U\xac_Kw\x95\xe0\xc7P\xcf_\xacN6\xe3=\xfdz\xfdH\xdb8\xec\xf7)\xf8Jܰ҅Pk!^\x95Vw̃\x99n\x1f\xbc\xad\xfd\x9e\xbc\xad\x13s\x88\x13\r?\xd1\x18r\xb9\xd5\x01Y_\x18)\xd7\x1b@g\x1ap\xecϬ\x8e\xec\xf9\x03\xca\x1b֦\xc4\xfe1#\xfc\xa4i\xcc\x14R\xf5cw\xc0)\x8f\x1eW\x96K\x8b\x80r\u007f\xb1\x0f\xfbMs\x170\x03\x91\x1d~\x84bt]*\x03i\xffH\x8dEQ\x17\x1aR\x82\xa8\t_\xbe\x9bj]>\xaf r(\x1f*+\\\xa9\xd7Я\xb4y\x95)\x1c\xb5q\xf5\x00\\?@1\xc2_?/\x84)V\xdf\x13\x02E\xf3\xb6y\xdfgH\xe3#\xdcV\xa2ܶ\xfc%\x1a~\xa21\xe4\xc2?\x9a]Zyot\x8e/\x1b6\x1d;\xfb\xe9\x83o#\xf3\x05\xb4\xb7\t\v\"\xff\x98\x11~\xd24f\n\xa9^^\x84p\x90\xb5'\b\xb3]Z&\x94\xfb\x8b\x1d~\xd3\xdc\x05\xcc@\xa4\x86\x9f\xad\xebR\xe9\x90/\xecP)\xeaC\xc3j\xbep\xf8\x87\v\x8b\x9bN\xfa\xab\xf4\xf0\xa37\x94\xc8G\x0f\xfa\x05?\xbf\x82?\xda[\xb1\x03\xf5\xb9\xf5l\x1b\xe1/\x8b\xe4\x19\x1f1\x04\xbdu%\n>\x85\xe0\xe0\xf7\xe9\xf8\xad\u007f\x88\x86\x9flL[p$\xfcC\xc6\xe1\xfd\xfd\xb3/l\xad^\xdb\xf3 :_\xec\a$B\xff\x98\x11~\xd24fj)Nx\xbe\xc6;\xf3\x98=?\xa1\xf20\xa0\xdc_6\x17\xfc4s\x170\x03\x91\x19~\x8e\xae\v_\t\xb0\xee\r\xa5@\x84\xbfd1>\xec\xaf\xd3\xc3\x1f(\xdaS\xac_\x88t\xed\xc0?\xdb\x15\xfcG\x9f;\xd4\x18\xb9\xbe\xae\x85\xbf\x1d\x1f\x98\xcf\x1b\xd5Pk_\xc6\a\t\xc1\xae<ާ\xef|\xa2\xe1'\x1a\xa3\xc2\x1f\x8c~\xe6p\xebU5\xf6\xf7\xcf՞\xd1\xff\xdb\xec\x8a\xfd\x10@\xe8\x1f3\xc2O\x9a\xc6\xccl\xdf\xf1<}\xe7\xa3U\x9b\xf57i\x96K\x8b\x80r\u007f\xb1\xc3o\x9a\xbb\x80\x19\x88\xcc\xf0st]\xf8\x94?#/\x0f\"\xfc\xc58\xce\xe12-\xfc\xa1\xc5{ГK\xb5\u05ff\xab\x18\x9f\xb4\x96Ti\xc5n\x9f;r\xe5\xadJ-\x98T\xd4S\x95>E;_\xd9sP\x8d\xa2\xa2\xad\\\xd56\xebR\xa2\xe7\xfc\\\xa2\xe1'\x1a\xa3¯\x9e\x0f\xe8a쩾\x82\u007f\xed>\xa2\xfd/\\\xb2\x02Y\x11\xfbnj\xf0\x93\xa613\xdb\x1fz\x96x<[\"\x17\xeeX.-\x02\xca\xfd\xc5\x0e\xbfi\xee\x02f R\xc3\xcf\xd1u\xa1\x1b\xdeL|\xc8\u007f\xc3\xdd\x12\xecʽ\x1a\xac\xaf\n\xa8ѭk=X\xa6\xb8[\x86B\x17\xb6\x15\x06\xd0\xed\x82\xed\x17\xf0G}\xca\xf2\xa1\xc1\xc5n=\xbdM\xf3\"G\xfdj*[z\x97\xe6\xe3k\x94MJ}wo\xa3҉ß\xdf\xec;\xd9\x18\xbd2o\xb2R\x89\r\xa9\x89v\x87_\x8b\xdfO5\x16\xf0\xe76\x0e\xa1\xd1\xc6\\\xad\x18\xdd\xcc\xd1O&z\xaak{\xde}\xf7\xa5\xea1\xed\u007f-J\xec}\x86\"\xff\x18i\x8b2Lc\xa4\x90\xea\xa3\xf2K\xe7G\xeeF.Z\xb2\\Z$\xa6\xf3\x8a\x10h\x91\x10\xe6.`\x06\"5\xfc\\]\x17\xe3\xb2u\xda\t\x17*\xca\xf1\x02%\xbf\x1b\x9fe\x87[\xe6\xbb\n\xeb;湪\xfaԳ\xee\x1dh\xbb\xfaS\x8dqIs]A\xd1\xfa\xc8'\x117\x95'#\xb3\x86\xb6\xbb\U000ea1b5ɾ*\xb7{1\xde\xe7wV5\x17\xe7\x16U\xc5d?\xfa9?\x87\xc6ȉ\xbev\xcf`\xb4\xb1mjA\xeex\xbe\xfaS?\x8e\xd8\xf3=\xed\xec\xfe\xec\xee\x9eM\xb5\r\xbb\xf5\xec\xfb\xf3v\xc44&\xf2\x8fѶ\xa8\xa8i\x8c\x14R}P\x8a\xff\\\xbaY;\xe9g\xb9\xb4H\f\xe7\x15)\xd0\"!\xcc]\xc0\fDn\xf8g5AWl\xb2%\xb1\xdde\xfd8\xa4\xcb\xd5\x18{\xb44m\xff\xd8W\x15\a\xbe\n\x87\xef]\xdf\xf5(\\\xa0w\x00\x10\xfe\xb8\xe9v\xc7\xc6M\x16-Ŗ\xaf\xf4\x16\xb1\xbe\xd47\xed\xef\xf2\xbe\x1d\xb1Ɔ+\xcf\vj\x02Y\x00\x84?>\x9a\a\xd1R\xf6\x8d\xfe\xd9ć\x91\x0f\xf9>\xc1\xf7\xfa\x00\xd9\x0e\x84?.\x82J\xd96\xe6\xd7k\xb2\x8b\xf0\xfe\x8a\x03\xfd\xef\xf5\x1f\xa8H\xea\xb8\x01\x98e@\xf8\xe3\xa39\xbfꆨN6\xf0\xceS\xcbJ\x97=\r\a\xfd\x8e\x00\xc2\x0f\x00\x0e\x05\xc2\x0f\x00\x0e\x05\xc2\x0f\x00\x0e\x05\xc2\x0f\x00\x0e\x05\xc2\x0f\x00\x0e\x05\xc2\x0f\x00\x0e\x05\xc2\x0f\x00\x0e\x05\xc2\x0f\x00\x0e\x05\u009f}L\xfb\x16\u007f\xc0\x19\xc8\r?K\xd7EMf\b\x19b.\x84.\x94\xe5/\x1f\x12U\x9a>6\xba.\x11\xd30l\xcd\b]םRϚ8K/V2\x9e>\x12%\x03]\xcf\x04R\xc3\xcf\xd4u\x91\x93\x99B\x86\x98\v\r\xb8ֿQ\xefJ\xff3\xcamt]\"\xa6a\xd8J@\xd7\x15Հ\xa5\x81k\xfb-\x8f\x1b▞\xaf\xb0\x89\xf74\xc6a6!5\xfcl]\x171\x999\xd2/\xe6\n\x15\xe2's<Y\x94\xee\xef\x05\vt]\x02\x92\x95\xec$\xa2\xeb25`\xa9\xc7\xfa\xac1~i\xcc3\xd6)\x92\x1d\x87Y\x85\xd4\xf0\xb3u]VsWFH\xbf\x98\xcb\xeb\xc2_\xc9\x0f\xe4\xda=\xd7'\x15\bt]\x02\x92}\xd1'\xa2\xeb\xda0#\xc2oO\xb2\xe30\xab\x90\x1b~\xc4\xd2uY\xcc]Ҡ\xa4X\xe9\x17s=\xa1=\x06\x14U\xa5\xee턉\x9d\xae\x8b\x10s=\xef\xf1\xfc\\?\x19\x0e/)}\xe5\xb1e\x97\x0e-ڂW\x8e4lE}^\x1f\x95z<G'\xf6\xd6,xڲ\xb7\x8c[\xd7u^\xfd\xe3+\xa8M\xfdIk\xc0\x8cE 4\xf2TMi\xe535\x96\x16\xd8N14\xb1\xab\xb2t\xc93\xda;[\xb4\x0f\xea\xb1\xfa\xdee\x8bvE\x0e\xf0\xcdv\xc9R\x83{\xf8\x99d\xdaa?ݮ\x89#Lc\x92\xc3\xcf\xd4u\xd1\xe6.iPR\xac\xf4\x8b\xb9J\xf4'\x006\x96XgK-v\xba.B̥\x9f\xd5j'\xc3\xef-\xf2\xfc\xe4G\x9e\xcaז\x9c@\x94a\xcb\xf0y\x85\xfa\xfbkV=\xf2\xd8O\xf6zh\vH\xfc\xba\xae\xd0\a5\a\ue8af\xda\x16\x8d\x84(\r\x98\xb1\btݳ\xb7\xff\xe2\xe9J\x8f\xe5\xed\x85\xe9\x14C\xefUlx\xfdb\x9b\xe7\x04Շ\x89E\xabN\xbf\U000d49dcn\x97,%\xb8>2\xa2\xef۩v\t\x1ca\x1a\x93\x1c~\x96\xae\x8b6wɄ\x90b\xa5_\xcc\xe5\xd6u\x9bMn\xebl)E\xa0\xeb2\xc5\\\xc4㸗\xedUw\xcd\xef\xa0\xfd\xb8\xbai\xd8\"}^h\x83\xe7G\xc1\xc8Y\x9bAB\xba\xae6\xbc\xa7߫?M\xdc8\xec'\x16q\xaa\x12\x0f\xe7\xa9E\xf4\xa0\xb2\x9db\xa1\x9a\xa7q\xbb\xfd\xf7\xa8>l^\xa5\x16\x86וӳ\x11\xa5\x16\x16D\x0e\xec\x89!!p\x84iLv\xf8Q\xac\xae\x8b6wɄ\x90b\xa5_\xccU\xb2^\xfbU\x9f\xde=\xbf@\xd7e\x8a\xb9\xc8\xf0\xf7\xabA\t\xa2\xc3\xcf!ҰE\xfa\xbcІ\xf2ض\x12\xd2u}\xeeQ\xf7\xff\x8f\\Ҋ\x8d\xf0\x13\x8b\xf8|Y\xcd\xf3\xa7?\xb2\x0e*\xdb)v\xde|Șه{\x9e\xd3x\xeah95\x1bYj\xc1\b\xbf9$\x04\x8e0\x8dI\r?S\xd7e1wɄPc\xa4_\xcc\xf5\x84~\xe9 \"\x03M\x13\"]\x17a\xdf \xc2\u007f\x11]+E\xe8\xe5碥\x9aa\x8b\xf4y\xa1\r\x1bb\xdbJL\xd7\xf5\xf4atq\x91>\xa8F\xf8\xc9E\xdc;\xbdk\x8dg\xc9\xebt\x03<\xa7\x98\xf1\x1ea\xf6\xe1\xbag\x04E+\x98\xb3\x91\xa5\x16\x8c\xf0\xb3\x84$\xce0\x8d\xc9\f?[\xd7E\x9b\xbb\xa4B\x86?\xedb.\xafv pSI\xeb\xd5~\x91\xae\xcb\x1a\xfe\xa3\xd1\xf0\x97G\xc3o\x18\xb6H\x9f\x17\xf3\x02}b\xba\xaew*C\xfb#\x0e!C\x03F,\xe2:\xbe\x1b\xe9^\xff\x82ST\x03l\xa7\xd8%b\xcfo\xf4\xe1k\x8f6\xabviϜ\x8d,\xb5 \b\xbf\x13Lc2\xc3\xcf\xd1uQ\xe6.\xa9\x90\xe1O\xbb\x98+T\x88\xdfH\xea\n\xd3yiC\xa8\xeb\"^\xe9\x15\x87շ\xe3\x8d1\xe17\f[\xa4ϋ\x19\xfe\xc4t]\xa1\xcaw\x1eՏ\xfaM\r\x18\xb1\x886\xed\xe4\x1dm\xa1\x8fV\xd8N\xb1в-x\x10\x0f\x1d\xa2\xfa\xb0\xb1F=D\x9fXPN\xcfF\x94Z\x10\x84\xdf\t\xa61\xa9\xe1g\xeb\xba(s\x97D()V\xfa\xc5\\\xa8\xcfU\u007f\xb2\xde\xd5gWe\xba\bt]\x94wks\xe5\xeb\xafm\xf4\x94\xbe\xf5O\xff\xf4\xe8\x89P\u007f\xe9'\xa1\xe7\xb6|\x8eHÖ\xe1\xf3\n_\xd3.\xd0ǜ\xf5'\xa6\xebz\xf9\xf1\xe8ռ\xa8\x06\x8cX\x84\x1a\xfe\x8a\xb6\xf3\xea\xe4{t\vL\xa7\x18\xba\xb4`ͩ\xf3\x87\xb4\xd3y\xb3\x0f\x9fT<\xd6v\xf4Q\xbcBd\xbbd\xa9I胑\x91\xf2\xfd##A\xae\x8a\xcc\x11\xa61\xa9\xe1\xe7\xe8\xbaHs\x97D()V\xfa\xc5\\\b]X\x9aW\x96\xd6\xdb\x18E\xba.ʻ5\xb1e\xc1#O\xbd\xa2N.\xf1x\xfa\x1f\xf1T\xf4k\xa7֤a+\xea\xf3\xfa\x888\xf9'IL\xd75aȾ\xa2\x1a0d.\x02\xfd|s[M\xe9\xb2-\x96쳝b\xf8s\xfe\xc7\x1e\xd9\xf86\xfe\xbb\xd1\a\xb5p\xe7\xa35\x87\xdf*\xd5*\x18\xedR\xa5\x06\xd7#\x17\x05NsUd\x8e0\x8d\xc9\r\xff,!\x83b\xaei1m]W:\t\x95\xc7$\x1b\xc8,\x10~\x06\x99\x14sM\x87\x19\xfd]\xde\xfeJ\xe9\x17t\x01{ \xfcV\x9c!\xe6\x92L\xdb{\xe8GN\xb8[~v\x01\xe1\xb7\xe0\x101\x97\\B\x9e\r\xcf/\xcb\xea\xfbef%\x10~+N\x11sI\xa5\xadb˄\xa8\x0e \x1b\b?\x008\x14\b?\x008\x14\b?\x008\x14\b?\x008\x14\b?\x008\x14\b?\x008\x14\b?\x008\x14\b?\x008\x14\b\xff̾#\x1e\x00҆\xdc\xf0\xb3u]\u1afd\xed'3vW\x1d\xdfn\xf5vi䛟\xa5o\xcb\xf57\xf1\x97FH\xb1b\xfdXl\xf8\x8d\xd9\x1a\xab\xf8\x15\xe2.ݯ\x0e]ńM\x05\vlٖ\x90\xf4\xce\x16ז'\xb6\x85x5g\x0eR\xc3\xcf\xd6u\x85}\x1d\xa3\xb7/\xb7_\x16͝&\xf8v\xab\xd7=##\xa7<'FF<\xaf'\xefo\x12\xba\xa9\x18\x15\xf8K#\xa4X\xb1~,6\xfc\xc6l\x8dU\xfc\nf)\xd9uF\xdd\xcf\xf1\xf0}`S\xc1\n[\xb6%$-\xb3E\xd7-\xae-Ol\v\xd1j\n_\x0f\x12\x91\x1a~\xb6\xae\xeb\xfdv\xac\xeb\xb8ٞ\x99o\xd3\xd8حN\x94\xe2\xe7?\xab\xafފ\x13\xd1':&\x8e\xd0MŬ\xc0Y\x1a!\xc5b\xfa\xb1\xd8p\xbb.<n`W0J\xa9\xae3\xeb^3\xc3/^Z2f\x1d\x8dt\xccf\xae\x9bx\xcbS\xdbB\xb0\x9a\xc2׃D\xa4\x86\x9f\xad\xeb\xf2\xe9O\xb6\xea\xcc̮\xdf\xc6n\x15\x9a\x88\xbcz'B\xf1\xbc\x04\xd8\b\xddT\xcc\n\x9c\xa5\x11O\xcac>4\x8fM\xb2]\x17\"\\7*\xfcq\x90\x8e\x14\xf3\xb1\x9dmC\x02\xe1O`[\xc41f\xf2\x90\x1b~\x95X]\xd7I\xfd\xd1V\xbd>\xc1\x9ci\xc1\xcen\x851^\xbd\xe5\x87M\xab\x93)\x83\"\x89\x8a\xa3L\x13\x16\"\xdcT\xcf{JO\x1cxL3@\xb1+P\x18\xb6(\xa2.!Ţ\xfdX\"\xad\x16S=e\x1a\xab8\xaa,\xb6\xd2\xca,%\xbbN4\x16ܵ\xac\xb4fg\xf4\xf1\xba\xd1\xe1#*\xac\x89̷\x19\xffG\xa0\xd5\"\a\x95\xad\xd5b8\xba(\xff\x98\xd9\x1d\xaa\x05\xceҢP\x9bE\xb0\xe5\xc9ma\xae&\xb5-\x8c\xf1\xe5m\xee\f!9\xfc,]ׅN\xed\f\xa0\xe3\xa4\xfd\xac\xe9\xc1\xcen\x851\xc3\xefY\xd3\xff\xce\x12\xedm۔A\x91\x18\xe2(\u0084E\xb8\xa9\xb0\x17\xaa浶\x9a\x8aO8\x15(\f[\x14Q\x97\x94b\x91~,\xa1V\x8b\xad\x9e2\x8cU<U\x16[ie\x94R]7\x1b;\xef9\xf0^\xffN\x8f\xfe\x88>s\xf8\xcc\n\xf8\xc1\x99##\x1b=\xf8\x11\xfdB\xad\x961\xa8\x1c\xad\x16\xd3\xd1E\xfa\xc7\xcc\xee\x90-p\x96f@\xad\x9bh˓\xdb\xc2XMr[\x98\xe3\xcb\xdb\xdc\x19Br\xf8Y\xba\xae`\x87o2\x14\xe8\xf5v\x8b\xe6M\x03\x02\xbb\x15\x19\xfe%_\xab\x1b\x1f[\x9d(\x8f\x95\x01)\xaf\"\x9f\x06M\x1c>֨\xeb}\xaff#\xb7\x02\x01a\x8b\"\xeb\xb2\x0e\xfb\x85Z-\xbez*\xf2\xf4j\xb6*\x8b\xa8`QZEK\xe9\xaeGJC\xfd\xf8\xad|]\xe4i\x9f\xe4a\u007f\xa4B\x9b\xba\x1b\x0e\xef\xd7D{B\xad\x165\xa8,\xad\x16\xdb\xd1E\xf8\xc7\xc8\xee\x98-\xf0%^\x06\xc4v\x13ly\xcba\xbf9:\xd1mA\x8d\xaf\xa3\x0f\xfbQ\x8c\xae\vM\xf9ԃ\x80!_\xafh\xc64 \xb0[\x91\xe1\xc7o\rZ\x06)\x8f\x95\x01)\xaf\xe2\x84_\xfb\x1cQ3@\x89\xc3oڢD\xe1\x17j\xb5\xf8\xea\xa9\xc8딭\xca\"*X\x94V\xb6\xe1G_\x9fz\xfa\xf1E\x1e}4X\xe1W\t\xed\xd2R$\xd6jQ\x83\xca\xd0j\xb1\x1d]\x94\u007f\x8c\xe8\x8eт\x8d\xc4ˀ\xd8n\x82-\xcf\r\u007ft[P\xe3\xeb\xd8\xf03u]\xda\x1f\xa6¨S\xbe\xabOh\xb7\"\xc3od\x90\xf2X\x19\x90\xf2*N\xf8\xb5W\x85f\x80\x12\x87\x9f]\x97\x15~\xa1V\x8b\xaf\x9e\x8a\xbeN\x99\xaa,\xb2\x02-\xb6\xb0\r\xff\xb5%5\x87\xdf\x1e\xd9b\x17\xfe\xd03\xa5\xdac\xb7\xc5Z-ޠFa;\xbaH\xff\x18\xd9\x1d\xa3\x05\x1b\x89\x97\x81e\xbb\xd9lyn\xf8\x8dmA\x8e\xafS\xc3\xcf\xd6u\xa9/\x06<u\xd3K\xd9\xec\xe5 \xb2[1\xc3Oy\xac\fHy\x95V\xf7(\x91m\xec\xa6B\xe5\xda\xf5D\xcd\x00Ů@@آȺ\xac\xf0\v\xb5Z|\xf5T\xe4u\xcaVe\x11\x15l\xc3\x1f\xedz\xa4t\xcdF\xbc9wل?\xb4\xb9\xfc\xbc>%\xd4j\xc5\f\xaa%\xaflG\x17\xa9 \"\xbbc\xb4`#\xf12 \xb6\x9b`\xcbs\xc3\x1f\xdd\x16\xd4\xf827w\x86\x90\x19~\x8e\xae\xeb\x86wR=5:>(\x989\r\b\xedV\xcc\xf0S\x1e+\x03R^e\x9a\xb0\b7\x95z\xee\x88/p<\xbe\x85[\x81\x80\xb0E\x91uY\xe1\x17j\xb5\xf8\xea\xa9\xe8Y8S\x95ET\xe0\x85\x9f\xeaz\xa4\xb4\x06\xf7 \xbc\x8e\x1f\xfe{\x1b*\xf0~\xf7<m\x04ck\xb5\xc8Ae\x85\x9f\xe3\xe8\"\xc2Ov\xc7l\x81^ڝ6\xc3\xfdgBl7\xc1\x96\x17\x86\x9f\x1a_\xe6\xe6\xce\x10R\xc3\xcf\xd6u\xdd\xf4\x0e\a\xde\xef\xf4e\xe0\x1e\x1f\x81\xddJ\xe5\xc3S\x9e\x13בEteʠHLq\x94i\xc2B\xf8U\x13uS\xe1\x8b\xee\xa7W-\x9a\xe0V lQf]B\x8aE\xfa\xb1\x84Z-\xa6z\xca4VqTYl\xa5\x151\x1b\xd1u\xaa\xb1]\xa7^\xdb\xe0\xa9|\xfd\x9a~\x87\xdf\t\xadCf\x85{\xeb<\xaf\xe1\xcb\xfd\ap\x9aDZ-sP9Z-\xa6\xa3\x8b\xf4\x8f\x99\xdd![\xa0\x97\xb6\xd3øS2\xban\xe2-Ol\vs5\xc9mA\x8d/ssg\b\xa9\xe1\xe7\xe8\xbaF\xbb;|\xa3q\xdc\xff\x95jDv+\xb5\x93\xf8sۊ\xa0\xd5\x16eʠ\bHqTԄ\x85\x9b0\xdcT\xe5?ٿ(b\x80bW lQF]B\x8aE\xfb\xb1DZ-\xa6z\xca4VqTYl\xa5\x151\x1b\xd1u\xa24|bUy\xe5\xaeӫJ\xb7h\xf7\xf6cv\x91\x15>\x8a~aB\xbb\xad@\xa0\xd52\a\x95\xa7\xd5b8\xba¤\u007f\xcc\xec\x0e\xed*#\x97v\xba\xc2c\x1d\u007fs݄[\x9e\xdc\x16\xc4j\xea\x13ڶ\xa0Ɨ\xb9\xb93\x84\xdc\xf0\xcf,$ۭ\xca\xdb\x100#y;\xf6\x83\x10G\xe0\xe4\xf0K\xfe./\x84\u007ff\x12~k\x91\x84\xad?\x13qr\xf8%\x03៙ܭ\x8c\xbdU\xdb\x19@\xf8%\xa1_8\x02\x80\x99\x03\x84_\x12څ\xa3\x99\xf1\xf1.\x00h@\xf8\x01\xc0\xa1@\xf8\x01\xc0\xa1@\xf8\x01\xc0\xa1@\xf8\x01\xc0\xa1@\xf8\x01\xc0\xa1@\xf8\x01\xc0\xa1@\xf8\x01\xc0\xa1@\xf8\x01\xc0\xa1@\xf8e\xdf\xe2\x0f\x003\x04\xb9\xe1't]\xa4\xa3+\xd0\xdbї\x81\xe7\xf8\xe8\xf0u]\x16R&b\x8a\xcb\x00\x95\x02L!\x15\xd1\xf5$\x84_@\x96\"5\xfc\x84\xae\x8btt\x05\xda\xfd\xb7\xfd\xed\x99J?_ׅ\x84B\xaa\xe4\x88\xcb\x00\xc5$Aד!\xa4\"\xba\x9e\x84\xf0\v\xc8R\xa4\x86\x9f\xd0u\x11\x8e\xae\xf0q\xfc\xe8\xce\v\xc73\xb3\x0f\xb2\xd1u\xa1x\x84TI\x91\xec\x17\xfc\x12u=\x19O\xbd2\xba\x9e\x9c\xf0\v\xc8J\xa4\x86\x9f\xd0u\x11\x8e\xae\x1b\xed\xf8\x15\x18lό\xa7\xd7Fׅ\xd2\xf6\xac\xd5dßhwb\x9fO\x9b\x9c\xf0\v\xc8J\xe4\x86_%\xa2\xeb\"\x1c]\x03\xfa\xfb\x80/\x03O\xf0\xb4\xd7u1\x85T\x94\f\x8am\ue88dU&\x13\xbb*K\x97<\x83\xdf`L\x03\x94Y\x97\x14<Q-Dg\xa3]O\"G\x97)\xa42\x1dR\x89\t\xbf\x98\x12/ \x8b\x90\x1c~C\xd7E8\xbaN\xea\x0f쿐\ti\x87\xad\xae\x8b-\xa4\"ePl\u007f\x13m\xac2x\xafb\xc3\xeb\x17\xdb4U\x8di\x802뒂'\xb2\x05c6\xaa;\"G\x17)\xa42UY\x89\b\xbf8\x12/ {\x90\x1c~C\xd7E8\xba:\x87\xb5\xbf\fw\nfM\a\"]\x17KKAȠ\xd8\xfe&\xdaXe\x94\xd6<\x8d\x9f\xa0ݏ\xaf\xb0\x99\x06(\xaa\xae!x\"J\xc9\xd9\xcc\xee\b\x1d]\x16!\x95\xf1<\xe9\xf8\x85_|\x89\x17\x90%\xc8\x0e?\x8a<\xb7\x9fptE\xce\x00\x063!\xea\x14麘\xe17eP\x1c\u007f\x13e\xac\x8ar\xdec\x9e\b\x98\x06(\xaa\xae)\xdb2K\xc9\xd9\xcc\xee\x88\x1c]V!\x95m\xf8ٍ\xf1%^@\x96 5\xfc\xa6\xaeK\xfb_\xc4\xd15\xa0\xbb\xb9{3p\xce/\xd4u1\xc3oʠ\xd8\xfe&\xdaX\x15\xe5\x84\xc7̑遠\xea\x1a\x82'\xa2\x94\x9c\xcd\xec\x8e\xc8\xd1e\x15Rن\x9f\xd3\x18W\xe2\x05d\t2\xc3O\xe8\xba\x10\xe1\xe8\xba\xe1\xc5G\xac\xda\a\x80\xb2\x11\xea\xbaXB*\xc2\a\xc3\xf67\xd1ƪ(\x97\xc8=\xbf\x11~\xaa\xae\x91m\xa2\xf4R̞\x1fwG\xe4\xe8\xb2\n\xa9l\xc3\xcfn\x8c/\xf1\x02\xb2\x04\x99\xe1'u]\x84\xa3+\xac\xfd\x1c\xcc\xc0\xe7\xfcb]\x17KHE\x84\x9f\xedo\xa2\x8dUQB˶\xe0D\x1f\xc2\x1f)\x98\xe1\xa7\xea\x1a\xc1#J\xc9\xd9\xcc\xee\b\x1d]\x16\xfd\x95m\xf8ٍ\xd1\x12\xaf;\xafM ː\x1a~B\xd7E:\xba\x02탷\a3q\x87\x9fX\xd7\xc5\x10R\x912(\xb6\xbf\x890V\x91\\Z\xb0\xe6\xd4\xf9C\xea\xc98i\x802\xeb҂'\xb3\x05c6\xb2;BG\x17!\xa4\"\\Z\x89\b\xbfh\x89\xd7N\xcf3\b\xc82\xa4\x86\x9f\xd4u\x91\x8e\xae@_{o\x06\xb2/\xd6u1\x84T\x94\f\x8am\xee\"\x8cU\x14\x13\xbb\x1e{d\xe3۴\x01ʬK\n\x9e\xa8\x16\xa2\xb3\x91\xdd\x11;\xbaL!\x95\xe9\x90JH\xf8EK\xbcNW\x9e\xb6.\x01\x98\xed\xc8\r\xff\xccB\xb2\xae\v\x00f\x16N\x0e?|\x97\x17p4N\x0e?\x008\x1a\b?\x008\x14\b?\x008\x14\b?\x008\x14\b?\x008\x14\b?\x008\x14\b?\x008\x14\b?\x008\x14\b?\x008\x14\b\xfft\ta\x8c_\x000k\x80\xf0O\x93\v9\x8a\xa2\xe4\x05\x83y\xea\xaf\x1c\xbf\xa86\x00\xcc\x1c \xfcӤ[\xf1\r\x0f\x8f#4><\xecS\xbaE\xb5\x01`\xe6 7\xfc\x1c]\x17B\x83\x19x\x8cO\"lSr8\xc1\xeeV\x8c/#\a\xf4\xf0\xf3\xeb\x02\xc0LBj\xf89\xba.\xfc\x87a\xfb93M\xc0\x9f\xdb\xcc\xfeKl\xf8\xb9u\aG\x99\xc5\x00\x90\x19\xa4\x86\x9f\xad\xebR\xe3\xd2=\xd3Ï\x90+\xee\xf0s\xeb.\xacg\x16\x03@f\x90\x1a~\xb6\xae\v\rz\a\u06dd\x10\xfe\xb2:f1\x00d\x06\xb9\xe1G,]\x17\n\x05\xa3\xe2\x0e\xa9t+\x8aҌ\x9a՟\xdd(XW\xe4*^yU-\xbd:WQ\xf6\xdc\\?/o9\xfd\xc1\x9dk{c\x91{\xe5MF+\x8c\xf0G\xeb\xfa\xd4ƛ\xf4E\xe0IL\x99V\xa3sq\xfe\xfc\x1d\xb4f\x03\x00$#9\xfc,]\x17&\x13\xe1\x0f\xfa\v\xf6L\xa2\xc9=n\u007fPM铃\xdd+s\x86\U0007314f\x17\xcf/(ޱ\xde\f\xb5\x86K)\xeb\xea*\xcb\x1b\xb7\xb6\xc2\f\u007f\xb4n\xf0B\xf16u\x11\xcd\x05\xfe`\xf0\x82\u007f~\x95\xdf\xef\u05eel6\xe6l\xf7\xb5\x16\x96\xc9\u007f^1\x00\x98H\x0e?Kׅ\xc9D\xf8\xd5\f\xe2\x93\xf0\xfaF\xf5G\xb0\x1b\xbf#\x95=\xa1\x15\x97)Kc\xf4W\xc8U\x82\xef䙿\xd8\xda\x063\xfcf\xddf\xbc\xa7_ߨ\x15\x1b\x87\xfd>\xa5C\xfd9\xact!\x00\xc8\x1c\xb2Ïbu]\x98̄\u007f0/\x88\x82y\x9aId\xaau\xf9\xbc\x82\xc81y\x99\x8b\xf1(aW\x13\xfe\xe9U\xa6,\xe5\xcc\xf0\x9bu\x03\xca8\n\x15\fh\xc5F\xf8\xeb\xe7i\xf7\x03\x167\"\x00\xc8\x1cR\xc3\xcf\xd6ua2\x13\xfe\x90\xfb$\xeau\xe3\xce\f\x17\x167\x9d\xf4WE\xc2_ƨ\xab_\xc4\xf3+֏\xeb\xf8\x17\xfc\xf4\xba+v\xa0>\xb7~\xf9\xc0\b\u007fY\xe4\xfc\xff\t\x04\x00\x99Cf\xf89\xba.Lf\u008f\xb6?\x81\x9e؎'J\x16\xe3\xa3\xfc\xbaH\xf8YW\xe5];\xf0\xcfv\xc5z\x95\x8e\x19~\xa2\xae\xcf\x1dj\x8c\xec\xe1\xb5v\xb1\x9cd\xfd\xbcQ\r\xebQ\x04\x00\xc8Df\xf89\xba.L\x86\xc2?\xe4\n\xb8\x86\xf0D1\xcee\xb8\xcc.\xfc\xc5\xf8<\xbe\xa4\xcaZ\xce\f?Q7\xe4\xf6\xb9#kY\xa5\x16L\xe2:}z\xc5=\a\xad\x8d\x01\x80D\xa4\x86\x9f\xa3\xeb\n\x05\x02\x1d\x83\x81I\xd1\xdci \\\xb4\xbcH;\x05iV\xeaZ\x0f\x96)\ue5a1АvU\xfe\xb6\xb5\xaaKY>4\xb8\xd8\x1dSξ\xdaO\xd4m\x9a\x179\xeaGͮ\x96ޥ\xf9\xb8z\x93R\xdf\xddۨtZ\x1b\x03\x00\x89H\r?G\xd7u٫\x91\x89\x8f\xbd[\\-\xda\xefp\xcb|Wa}\xc7<W\xd5\xd5\x1c\xedt|\x85\xb5fIs]A\xd1\xfa\xd8+\x81\xdd\xca\xcd\xe8WzoF\xc3Oս\xa9<\x19\xa9\x1a\xda\xeeΫ\xd2\x0fq\xfa\xaa\xdc\xee\xc5}1\x8d\x01\x80D\xe4\x86?\v\xd1nމ|\xa5W\xf11*\x04]\x83\b\x00f \x10\xfei\x12\xba:\x1c\xfdJ\xef\xf0U\xd6\xd3<\xbaݬR\x00\xc88\x10\xfe\xb4\xd2<\x88\x96r\xbe\x14\x00\x00\x19\x06\u009fN\x82Jٶ\xa2L\\\xcb\x00\x001\x10\xfe\xb4Ҝ_5\xc3\x1fS\x028\x17\b?\x008\x14\b?\x008\x14\b?\x008\x14\b?\x008\x14\b?\x008\x14\b?\x008\x14\b?\x008\x14\b?\x008\x14\b?\x008\x14\xb9\xe1g뺂\xfe\xee\xf6^\xe6\x97b\x00\x00H\x1bR\xc3\xcf\xd6u\x05;z\xc7o_\xee\xe8\x85\xf4\x03\x80L\xa4\x86\x9f\xad\xeb\x1a\xec\xc6\xcf\xf4\x98\x8az\xfb\x00\x00\x90\x82\xd4\xf0\xb3u]'\xf5\xe7\xdf\f\xb2\x9e\x84\x01\x00@\xba\x90\x1b~\xc4\xd2u\x05\xf4\xe7]]x\xc3n6\x00\x00R\x8c\xe4\xf0\xf3t]\b\x85\x8f\xfb\xf9\xb3\x01\x00\x90r$\x87\x9f\xa7\xebR\xdf\r:\xe0)\xf6\x00 \x13\xd9\xe1Gl]\x17\x1a\xf2\xc6<\x14\x1b\x00\x80t\"5\xfc\\]Wh\xd0\v\x0f\xbc\x01\x00\xb9\xc8\f?W\xd7\x15\xf4u2Ԙ\x00\x00\xa4\x13\x99\xe1\xe7麦\xbaN\xe2\xdb~\xe0&\x1f\x00\x90\x89\xd4\xf0\xb3u]\x81\xf6\xaeہ@\xe0\x82q\xed\x0f\x00\x00\tH\r?[\xd7էۺ\xbcp\x93\x0f\x00\xc8Dn\xf8\x01\x00\x981@\xf8\x01\xc0\xa1@\xf8\x01\xc0\xa1@\xf8\x01\xc0\xa1@\xf8\x01\xc0\xa1@\xf8\x01\xc0\xa1@\xf8\x01\xc0\xa1@\xf8\x01\xc0\xa1@\xf8\x01\xc0\xa1@\xf8\x01\xc0\xa1@\xf8\x01\xc0\xa1@\xf8\xb3\x9a\xb0\xa8\x02\xe0` \xfc\xd9K\xa0\xb1PyBT\tp.\x10\xfe\xac%\\R\xe2\x1d\x80\x87\xa4\x00\\䆟\xad\xeb\"Je3\xb5\xad0oE\x9c\xc7\xc6\x03\x85\xb3\xebK\xc7W\x95>Q\x15\xc0\xd1H\r?[\xd7E\x94Jgi\xa1\xb71/\xce\x05\xfb\xf2g\x97Y`X\x81\x87\xa1\x03vH\r?[\xd7E\x94\xcafJiE\xe18\xb3?뮞\r+C\xa2*\x80\xa3\x91\x1a~\xb6\xae\x8b(\x95\xcdMev\x1d\xc9'\x04\x84\x1f\xb0Gn\xf8\x11K\xd7E\x94J%\xe4V4vh\xffk-\xcb+kU\u007f_\x9d\xab({n\xae\x9f\x97\xb7\x9cz\xa0h0OQr\x8e3Z1\xb9]\xe7\xce-\\\x11\xf3\x16\xd6Q\xe8ſ\x02\x05\xfaҔ\x02\xb2\x06\xb9\xb4`]\x91\xabx\xe5U\xb5t\x9b\x92\xeb\xdd1?o\xb9Vsj\xbd\xbbx\xc7\x0ew>~\xc4a\xe7\xe2\xfc\xf9;\xacG*c\xfb6ծݷ遥\x18\rB\xf8\x01[$\x87\x9f\xad\xeb2J\xe5\xf2\xbe\xbfKi\xf6\xfb\xb5\x885\xba\xf6\xf8\xf6\xb8\xd6\xe3g\v\x1f/\x9e_P\xbcc\xbdB\xc7\xf8\xb2\xdf\xefjf6\x13a0\xbf\xace\xa0Yi\xb1\x96?\xa1,ǿB\x1d\xad:\x1d\xe4\x9b\n\xb94\x9f\xf2\xe4`\xf7ʜa\x84n\x1c\x9f\xab\x146\xb7\x14\xd4\xe1\x1a%E\xadͮ\xbc\xf6\xe5jÍ9\xdb}\xad\x85e\xf4\xbb\xe4\xc7\u007f\xf6ҹ+g\xd7V\xff\x8e*\rM\x0e.t\xcb\x1fR`6!9\xfc\x1c]W\xb4T6\xc6a\u007f\x9fve\\\xff\x89ʔ\xa5\xc1\xc8\xc9\bE\x9e]\xf8C\xc5\xf8P!\xd4\x1d#\x1d\xbb}Pw\x11M\xde֙\xb4\xfc\xddXZ\xb0\x1b/\xb2L\xfbd\xde\xe5V\xdfz\xd6\x17\xaaS]\x8az,Ъ\x8c\xab\x93>\xa5\x03\xe1\xa3\xf9.j\xfe3\r8\xf6gV\xd3{\xfe'\xd4c\x8c,>\xa5\x01R\x81\xec\xf0#\x8e\xae+R*\x19#\xfc\x8d%گ\x92F\xfc\xb3\xccž\xfc`\x1b~\x9f\xf2\xbe\xcd_\xd5\xf7\x00%\x8a\xc5Kf.m\xaau\xf9\xbc\x02\xa5\fO\xbapG\x9a]\xea\x8f&7\xc2\xfd\xc4\xe3T?/\x84)n\xa4\xe6\xff\xb2aӱ\xb3\x9f>\xf8\x96*D\x81>o\t\xec\xf9\x01[\xa4\x86\x9f\xad\xeb\xa2K\xa5b\x84\u007f\xf1J\xed\u05ca\x85\xf8gY\x19\xbb\xb6m\xf8[\x14\x81t\xc4\xefӱ~\xfef,m\xb8\xb0\xb8餿J\x0f?^\x94\x16\xfe\x16e\n\x1f\x92\xe0=\u007fY\xe4\xdd\xc3r\xd7\xde\xfd\xb3/l\xad^\xdb\x13s\xce\xefW\x86\xadE\x00@ 3\xfcl]\x17U*\x19s\xcf?O\xfb5O\xdf\xf3ױkۆ\u007f@\x19\xb5\xf9\xab\r\xc6\xd2J\x16\xe3=u\x9d%\xfc\x81\x9c\x15\x81\xab\xf3\x17\xe3\xb1Y?oT\x83>\xb3\xb8\xf5\xaa\x1a\xfb\xfb\xe7j\xcf \vp\xb5\x1f\xb0Gf\xf89\xba.\xa2T6F\xf8}ډt\x97\xfe_q\xf8o7\xc7$=XT\x85\xdf϶o\xb7\xfe!z\xce\xcf\xc3XZ1\x9e\b\x97Y\xc2?\xaa\x14*J\x95vfЧhWH\xf6\x1c\xa4\xe6奄\x82\u007f\xed>\x82,@\xf8\x01{\xa4\x86\x9f\xad\xeb\"J\xe5\xa2_\xed\x1f\xd2\x0e8\xd6\xe74\xf9\x9ar\xf0\xd5\xfe!\xff\xfc*\xbf\xdf\x1aX\xb5\xd8\xefj\xf4\xfb\xf5N\xaeT\xf2cz;\xf8\xbd\x12\xafo\xbb\xd2n-_\xa9\xac\xb0\x16\x99\x90KkV\xeaZ\x0f\x96)\ue5a1\x80?\xb7q\b\x8d6\xe6\xfa\x03h\xd45\xe0\xf3\a\xf4\x83\xa2&\xa5\xbe\xbb\xb7Q餚詮\xedy\xf7ݗ\xaaǬm_V.X\x8b\x00\x80@j\xf8ٺ.\xb2T&\x91\xcf\xf9\xe7jw\x16\x86\xb5\xcf\xf9\xd5\xfe\\\xcd\xd1J\xad\x81\x1d\u058b\x15\xed3{Ԟ\xcf8\x9f\xbeYW\\\xb0\xf0dLq\xe4s~6\xe4\xd2\xc2-\xf3]\x85\xf5\x1d\xf3\\U\xdbԢ\xdc\xf1|\xf5\xe76t\xc1\x85+\xe4V\xe1\x93~\xd4W\xe5v/\xb6ܱ\u007fvwϦچ\xdd1\xd9G\x93s\xeb\xaeN\xca?\x95\x02f\rrß5\xf4*\x92\x8eS&\xf3\xb7M\x86B\xc1\xe1\xba$.\xdd\xf7\x96\xc4\\\x1c\x04\x00\x13\b\u007f\x12\x84;\xdcO\x8a꤈^\xb7\xbe\xef\x0e\xbb\x93\xf9\xd4~\xf2j\x06\xee\x99\x06f\v\x10\xfe$\b\xb8w\xc8:I\x19\xcdю\xf7\xd1x\x8e\xfdm\x04\x00\x900\x10\xfe\x99M\xb81\xefɮ\xc1\xae'\xf3d\x1dj\x00\xce\x01\xc2?\xd3\xf1-/r\x15-O\xe6\xa0\x1f\x00l\x81\xf0\x03\x80C\x81\xf0g%\xffh\"\xaa\n8\x16\b\u007fV\x02\xe1\a\xc4@\xf8\xb3\x12\b? \x06\u009f\x95@\xf8\x011\x10\xfe\xac\x04\xc2\x0f\x88\x81\xf0g%\x10~@\f\x84?+\x81\xf0\x03b \xfcYI$\xf8\xff\xf5?\xfd\x03\x15\xfe\xa9Ž\b\x00\"\xc8\r?[ץ2\xee\x85[\xd8\x12\xe4Jû\xfc?\xea\xd9\xff\x9b꿲\xec\xf9[r\xe8'\x81\x00NFj\xf8ٺ.\x95`\xfb\x05\xfa\t\x15\x80\x90wk\xcf\xf1\xff\xa8g\xbf\xf6\xbf\xc6\x1c\xf6\xfb液\xe7\x00\x9c\x87\xd4\xf0\xb3u]*\xbe\x81\x00\x84?Qb\x9e\xd8i\x12\xfeǟ\xfd\xe3?\xfe\u007f\xb5\u007f\xc58\xe7\xdf\xc3y41\xe0<\xa4\x86\x9f\xa3\xebB\xe3\x1dA\b\u007f\n\xb9Y\xf6\xc7\u007f\xfc\xef\xff8\xe7\xff\xf8?\u007f\x16\x1b\xfe`\x11\xfd\xe4o\xc0\xb9\xc8\r?b꺂\xed7Q\x16\x85\x9f#\xfcB\xf6\xe6\xae߭\xad}\xb5\xa1a\xec\xd8\xea\xdd\xf7\x11\xba\xffBC\xed\xa6}\xb7\xd4\xe2#յg^jX\xbd\xef3j\x12ݯ\xad\xae\xae\xd6\x0e\xfb\xd5ҳǶ\xd6\xee\xfb-\xfe\xcf\xfd\x17\xd76\xbc\xfa\xea\xda\u007f\xa3TU\xcdɫZ8\xe7\xcf\u007f\xa6\x85\xff\xb3\x17\xd6\xd66\xe85\xd4]\u007f\x9e\xacg\x11\x003\x1c\xc9\xe1g\xea\xba|\x03(\x9b\xc2\xcf\x13~\t\xcc]c\xab\xab\x8f\xed\xae^۳\xf6\x8cz>_\xfd\xd2ع}\xd5\x1f#t\xeb\\m\xf5\xa6\x9e\x9eM\xb5\xb7\xc8I\xb5|l\xac\xb6\aφK\x1bzzV\xbf\xa0N\u007f\xbb\xb5\xe1LOm\xed\x99\xff\xf5\xe0\xef\u007f\u007f\xe3\u007f\xfe\xfe\xf7\x0f\xfd\xfb\u007f\xc0\xe1\x1f\xab}\xb6\xe7JOu\xe4\xd9\xde\x17\u087e\x80\x8e\xe4\xf0\xb3t]7\xf0\xbbA\x16\x85\x1fq\x85_\xf6殆\x17ѕ\xeaw\xd1K/\xe1\xc7\xf0\xab\xbb\xff\a?ƁF\xb5\x9b\xf0\xa1\xc0\xa6g\xe9I\xfc\xbf\x9e\xc8\xef\xd5\xea>\xfd\xc5\x06u\xea\\\xb5\xfa\xbep\xa6\xfa\xe3\x929s\xe6\x84\xeb\xe7\xcc\xf9Ο\xe3\xf0\u007f\xbbi߷\xea\x1b\x03n\x12\x13P\xde@\x00\x80\xe4\x87\x1f\xc5躂\xed7\xc2\xe1\xf5殛\x00\x00\r\xefIDATp\xa03\x9cE\x0f\x9a\xe5\t\xbft8殆s\xe8\xe3\xea\xfb\xe8\xd5\x17\xd5\xe9\xfbg\xf6mZ]\xfdc\\\\\xfb*\xfeyF\xfd\v9\x89\x88\xf0\xab\xef\x16\xa8\xa7V\xfd\xf1\xeaj\xf5\xc7o\xaa\xdf\rl\xffc5\xfc\xff˿\xfb\xf3\xff\x86\x0f\xfb\xafT\u007fJ.&`q\xfd\x01\x8eEj\xf8\x99\xba\xae\xdb\xde(\xd9s\x19\x9a'\xfc\x8a\xc06w5\\A\x1f\xab\x11\xc6\xe1\xff\xb8aӫ\xef\x8e\xed\xd6ïe|\f\xefԉID\x84\x1f\xff\xd6\xc2\u007f\xe6\xcfԷ\x85+շ\xc2\xc1?W\xc3\xffo\xfe\xdf\u007f\xd0.\xf8\x9d\xa9\xa6<~\xc3\xf08\u007f@Gf\xf89\xba\xae\xa9I\x95\xf1\x8e\xc9,z\xc6<\xcf\xf9c\v\x11\xfe\xad\xcf\xe2\x9d\xfb\vz\xf8\x8f\xe1\x9fg\xb5=\xbf9\x89X\xe1\xff\xb2zߗ\xb7\xb6\xee~\x80\xd0\u007f\xc1\xe1\xff\xcf?\xd3>\xea\xbb\x12y\xb3\x88\xd0\xecJ\xfc!\xe0@V\"3\xfc\x1c]\x97F\x96\x9d\xf3\xb3\xc3oo\xee\"¿\t\x9f\xed?\xf8\xb1\x1e\xfe\xb5ډ\xfenz\x12\xb1\xc2\u007f\xabzmu\xf5n|U\x1f\x87\xff\x0f\xff\x93\x1e\xfe\xfb\r\xbb\xf1\xae\xff\x98\xf6\u0381\xc2%6\x02!\xc0QH\r?[ץ\x12\x0e\x8cw\x04b\xcc\xf6\xb3\x14\x8e\xf0\v\t\xcc]\xb7V\x9f\xb9\u007f\xae\xf6\xd6\xfd\x17\xd5\xf4\xf6T\xbfp\xa6\xe7\xc7\xd5k{\xc6\xd4lW?{\xee\xec\xd6տA\xe4\xe4\xb7ccc\xb5G\xc6\xc6\xee\xa3/\xf1\xef\a\x9f\x1e\xa9\x1d\xfb\x12ݪ\xbdre\xec\xb7\xf8\xe6\x1f\x1c\xfe\xff\xed?\xfc\x8d~\x93\xcfX\xedֳW\x8eU\x9f\xd5\x16Ӓ\xacP\x14\xc8:\xa4\x86\x9f\xa3\xebR\xcb\xf1)\xffq\xfe|\xb3\n\x8e\xf0\vٛ\xbb\x1e\xa8;\xeds\xab\xabk\xcfUW\xbf\x80\x1e\x9c\xd9Z\xdb\xf0\xe2٭\xb5\xbb\xf1\xb1\xfeK\xab\x1b^\xfc\x12\xd71'?\xae\xd69\x8b\x8e\xa8?k?\xc5\x1f\xfb\x1fQS\x8e\xcbjw\xdf\xd2\xc2\xff\xbf\xff\xe7\xff\xeb\xbf\xeb7\xf9\xfc慆\xd5\xcf\xea\xdf\x04\xf0\xe7\xed\xe0v\x01p\x18r\xc3\x0f$N\xf4螞d\xf1\xaf\xb5G\xfe\xf5w\xbf\xbb\xff\xf1\v\xab\xefk\xe1\xffo\u007f\x85o\ue9eat\xb9\x1a\xe1\x16\x1f \x02\x84\u007f\xa6\x13\u007f\xf8\xdf]\xad\xdf\xee\xff`\xed\x15=\xfc?\xfb\x9b\xff\xdb\xf2\x95\xde\"\xf8R\x1f`\x00\xe1\x9f\xe9\xc4\x1f\xfe[\x91\xcb\xfa\xb7\xaa?\xfd\xb7\xf8j\xff\u007f\xd0\xce\x02lg\x01\x9c\f\x84\u007ff\xf3[\xedz\x9eu\x92̓\x97j\x8f\x9c\x1b;w\xa4\xf6\xa5\a\x10~@\f\x84\u007ff\xa3]\xcf\xfb\xcc:\xc9\xe1\xc1\xbb\xfb\x1aj\x1b\xf6\xbd\xfb\x00E\x0e\xfb\xe11^\x80\r\x10\xfe\xac\x04\xc2\x0f\x88\x81\xf0g%\x10~@\f\x84?\v\t\xb5\xd6\xe1;\xfc\x9a.\xc0\xc7z\x80\r\x10\xfe\xec#\xbc8\xfa\x95ޓ\x90~\x80\x0f\x84?\xfb\b=t\xf0\xf7\xbf\xff\x9f\xea\x06z\xe8\t\xf8\x0e\x0f\xc0\a\u009f}\x04\x15\xa5\xaa\xea\xa1ª\x85s\x1a\xb3\xe5\xfb\x12@:\x80\xf0g\x1f!\u007f\xb1\xdb=\xdf\xedv/\x1d\x86=?\xc0\a\u009f\x85\x84\x02\xdaS\u0086\xea\n\x95'Du\x01\xe7\x02\xe1\xcfF\xc2\xe1\x90\xfao\xfe|\xef@\xf6<\x1d\tH9r\xc3\xcf\xd4u\x85:\xb4\x87xudӕ\xe9\x81BC?6\xb5\xad0o\x05\xf5\x90\xa2#\x91\xa7nO\x8f\xe8\"\x1a\x15EɻɨpU\xe9c\x94\x02@\x14\xa9\xe1g뺂\xde\xf7\x03*\xf4\xa3lg9\xbe|\xe3\x11\xb9K\v\xbd\x8dyԹ\xf7o\xc7\x04\xdfЉ\x8b\xe8\"\x02~\u007f+\xf3i\xdc\xc3\n\xfd\x8c@\x00\xa0\x91\x1a~\xb6\xae+\x98EO\xee40v\xf5SJ+\n[\xaf\xbb\xa5\"\xfc\xe6\"Ԙ\x0f1\xfe\xce,\x9d\x932b\xdb\x06f\x19R\xc3\xcf\xd6uee\xf8\rn*\f\xffpJ\xc2o\x92H\xf8\xbfI\x11\x10\xfeُ\xdc\xf0#\x96\xae+\xeb\xc2\x1f\xccS\x94\x9c\xe3x*\xe4֟\xcfo}tV\xed\xb1\xa8w˄\x90x1}^h\x9b\x92\xeb\xdd1?o\xb9v\xf4d,\x02\xc3\x0e\xff \x84\x1f\xb0Er\xf8Y\xba\xae\xa0w\xe0\r\xefq\u007f\x16]\xef\xbb\xec\xf7\xbb\x9a\xb5\xa9\xf7\xfd]J\xb3\xdfo}w\xc3O\xe2<\xf7\xe3Z\xea\x91ڄċ\xed\xf3\xbaq|\xaeR\xd8\xdcR\xa0=\x19\xd8\\\x04b\x86?49\xb8\xd0\xcd\xf8\x94\x1f\xc2\x0f\x18H\x0e?K\xd7\x15\xf4v^\r\xdc\xe8\xeeʢ\xf4#\x94\x17M&\xfb\xb0\u007f+\x16hm}\x96*$$^l\x9f\x17r\xb9\xd5w\x91\xf5\x85\x91\xff\xe5م\xff\t\xf5\xb8\x81\xb1`\b?`\";\xfc(Fׅ\xc2\xe3\xfaA\xc0\x90`\xbeY\x85 \xfc\x9aw+j\xdf\xd0!$^\x1c\x9f\x17ra\xbbv\xb3+\xf2?\xdb\xf0\a\xfa\xbc%\xd3\xda\xf3\xcf\xd1\xfe\xd9\xfc=\xb6m`\x96!5\xfcL]W\x14\xffI\xf6L\xb3\x13A\xf8)\xefV\x04B\xe2\xc5\xf6y!\xed@?\xbe\xf0\xab\xf8\x95\xe1\xd8B\x1c\xe87\xffH\x8f\xf5\xbf\xfc\xe5\xc3s\xbe\xffS^\xb8!\xfcY\x8f\xcc\xf0\xb3u]h@O\xc7 \xeb(u\xd6\"\b?\xe5݊\x9b\xc4\xc2Ͻ\xda\xff\x837\xf5X\xff\xc5\x0f~\xf9\xc5/\xff\xe4\x17\x9cpC\xf8\xb3\x1e\x99\xe1\xe7\xe8\xba|\xda.\u007f\xaa\xe3}\xdbyg\x19\x82\xf07h\xe7\xfc\xbbc\xffbK\x8a\xc2\x1f\x8d\xf5\x1f\xfeJ\xfd\xf1\xab\xff\x18I\xf3O\xbf?\xe7\xe1\xbf\xfb\xe6\x9b_\xfe\xf0\xa1\xef\xfc\xf0\xd7F\xf8\u007f\xfa\xdd9\x0f\xff\xe57Ą\xfa\xf79\xdf\xff{\b\u007f6 5\xfcl]W\xc0\xdbw3p\xb9ݗ5\x9e\xceА\xdf\xefj\xf4\xfb\x83ѫ\xfdC\xd6U\xab\xad\xde76\xf6\xac\xa6\xe0\x8a\x9f\x80?\xb7q\b\x8d6\xe6\xfa\x03\xe4\"\xb4;\xfcZb?Q@\x97Y:\xde\xd8\xf0?\x1c\xc9\xfe\x1f\xfe\xf4\x8b_\xaao\x04\xdf\u007f\xf3\x8b_\xff\xe9\x9fF\xc3\xff?\xbe\xff?ԃ\x83\xbf$&\xbe\xff\u05ff\xfe\x97_\xfc\x10\u009f\rH\r?G\xd759p\xbc\xc37\x9e5\xd9Gú\xafK\xf1F?\xe7\x9f{\xc3Rck\xcf\vQ\x05W\xfclS[\xca\x1d\xcfW\u007fn#\x16\xa1\xddۏ\xa9\xb7֟\x9c[w5\xc6|L\x86_?\xec\x8f\x1c\xdc\xff\xd1\xdf\u007fc\xf0뇣\xe1\xff\xc1/\"\xef\x0f\xc6\xc4w~\xa5ׁ\xf0\xcf~\xe4\x86\x1f\x90Io\x89\x12\xf3\x95^2\xfc\xf8\x82\xdf\xc3\u007f\x17\t\xff\x9c_\xeb\xbf\u007f\xa5\x1e\xd6ϙ\x13\r\xffC\xfa\xad\xbc\xc4\xc4_<\xf4\xa7\u007f\xf7+\b\u007fV\x00\xe1\xcff&\xafZO\x06\xc8\xf0k\xbc\xf9]\xfd\xf7C\x91\xf0\xff\xe0/~\xf5\xcd\x17F\xf8\xe7D\xf6\xf3\xe6\xc47\xbf\xf8\xeb\x1f>\xf4\xd7\x10\xfel\x00\xc2\xef,b\xc2\xffÿ\x8c\x84>r\xd8\xff\x9d/\xd4\x13|#\xfc\u007f\xf4\xb7\x91j\xc6\x04\xe6\x97߁\xf0g\x03\x10~gA\x86\xffO~\xf1/\xbf\xfc\xd3?\xfa\x17=\xd0o>\x1c\xb9\xe0\xf7\xd7_\xfc\xe2\xbbF\xf8\xdf|\xe8\xef~\xfdś\u007fBL\xfc\xc9O\xbf\xf8\xe2o\xbf\x0f\xe1\xcf\x06 \xfc\xce\x02\xc7>r\xf6\xfe\xcd\xdf\u007f\xf7\x0f\x1e\xfe\x8b/\xa2\xbb\xf3\xbf\xff\xae\xf6Q\xdf/\xbe?\xe7\xe1\xbf5\xc2\xff͛?\xf8Μ\x1f\xbcIL\xfc\xf4\as\x1e\xfa\xe1/!\xfc\xd9\x00\x84\xdfY\x10\a\xfc\xd3\x03\xc2?\xfb\x81\xf0;\v\b?`\x00\xe1w\x16\x10~\xc0\x00\xc2\xef, \xfc\x80\x01\x84\xdfY@\xf8\x01\x03\b\xbf\xb3`?\x8c3\x19DK\x02f<\x10~\xc0\x96\xec\xf9\xca\x05`\x05\xc2\x0f\xf0\t4\x82\xf0+\x8b\x81\xf0\x03\\\xc2%% \xfc\xcab䆟\xa9\xebR\xb9\xd1\xd7\xd1}\xd9f> \x82\xad\x06,\xe5\x80\xf0+\xbb\x91\x1a~\xb6\xae\v\x85\x06\xbcC\xb7G\xbd\xf4\xc3*\x01\x16\xb6\x1a\xb0\x94\x03¯\xecFj\xf8ٺ.4\xd0\x1e\xc0o\f\xd6'^\x00\f\xec5`)\x86\xfdx0 [\x90\x1a~\xb6\xae+\xe0}\xdf\xf8\x1b\x10/\xccg\x03\xa6\x18\b\u007fv#7\xfc\x88\xa5\xeb\x1aj\x0f\xc1\aJ\xf1 Ҁݪ\xad\xae~\xf5\xb3\x177\xd5\xee\xfb\x1dQ*Ԁ\xa9|\xf6\xc2\xdaچ}\xbfE\x16\x98\xc2/ k\x90\x1c~\x96\xae\xab\xd7w\xe3\xa4\xf7\xf8\x85\xac\x12\xf6\xa4\a\x81\x06\xec\xdbs\xe76m]\xddp\xec\xc5?#\x9f\x0e(Ԁ!4V\xfblϕ\x9e\xea3T!O\xf8\x05d\r\x92\xc3\xcf\xd2uuk\xba\xae\xe3ݐ\xfe8\xb0\u007f$8\xfaq\xf5\xee\xfb\xe8\x01\xad\x03\x10j\xc0\xbeݴ\x0f?I\xfc\x1c=\x1bO\xf8\x05d\r\xb2Ïbu]>\xed\xaa_\xb0\x83\xe1\x97\x01\xac\x88\xc2_\x1b\xf3H`\xb1\x06\xecJ\xf5\xa7֙\x10_\xf8\x05d\rR\xc3\xcf\xd6u\r\ua7ae\xc1^\xfe\x8c@\x14Q\xf8i\xf7\xa7\x86P\x03v\xa6\xfa\xdbع\xb49Y\xc2/ k\x90\x19~\x8e\xaek\xb4C{/\x18\x80c\xcc8\x10\x85\xff\x05F\xa1\x88+\xb43\xd0\x04\xae\xf6g72\xc3\xcf\xd1uMi\x1f\xf5\x05\xdb\xe1\x16\xbf8HG\xf8\xef7\xecƻ\xfecǬ\u007f\x80\xf0g7R\xc3\xcf\xd6u\xa1\xcb\xed\x97\x03\xe3\x9d'႟\x00\x91\x06\xecwcc[w\x8f\x8d}ƙ\x9d\xcfX\xedֳW\x8eU\x9f\xb5\x963\x85_@\xd6 5\xfc\x1c]\x17\xba\xdd\xdbq\xf22d_\x84H\x03v\xabZc\x1fgv\x1b~\xf3B\xc3\xeagߍ)f\n\xbf\x80\xacAn\xf8\x81\xd9\x05K\xf8\x05d\r\x10~\xc0\x8eX\xe1\x17\x905@\xf8\x01\xc0\xa1@\xf8\x01\xc0\xa1@\xf8\x01\xc0\xa1@\xf8\x01\xc0\xa1@\xf8\x01\xc0\xa1@\xf8\x01\xc0\xa1@\xf8\x01\xc0\xa1@\xf8\x01\xc0\xa1@\xf8\x01\xc0\xa1@\xf8\x01\xc0\xa1@\xf8\x01\xc0\xa1@\xf8\x01\xc0\xa1\xc8\r?K\xd7\x15\xea\xf4\xea\x1c\xb7\x9f\x17\x98!\x10\xca0`V#5\xfcL]W\xc8;\x1aP\xb9\xec\xbd*\x9a\x1d\xc8\x18\x83\xa3\xe64\xa1\f\x03f5R\xc3\xcf\xd6u\x8dk\x0f\xef턇\xc6\xcc`\x16\xd6\x13\xff\x81\xc7{d\tR\xc3\xcf\xd6ui\xf8ހ'\xf9\xcc`\xca\xeaD5\x80ه\xdc\xf0#\x96\xae\v\xa3=\xcf\x13\xc8\x14\xb7\xebܹ\x85+\xb4\xc7v\xb4\x96啵\xaa\xbf\xb7)\xb9\xde\x1d\xf3\xf3\x96\xe37\xea\xc8\xc3\xfe\xcb\x10\xa9\f#*lSr:\xd1m\x97R\xa25ֹ8\u007f\xfe\x0ex\xe0\xff,@r\xf8Y\xba.\x8c\xe6\xf1\x002\xc4`~Y\xcb@\xb3ҢN6\xba\xf6\xf8\xf6\xb8֫o\xc7\xc7\xe7*\x85\xcd-\x05\xea.?x\xc1?\xbf\xca\xef\xf7kO\f4\x94aD\x85\x80?W-\x1ajt\xe1\xf2Ɯ\xed\xbe\xd6\xc2287\x98\xf9H\x0e?Kׅ\xa2\x17\x03\x80\xcc\x10*^\x1e\xc2OT\x9fB\xa8O\xc1\xa7c\xfaO\x97[\xdd(\xeb\v\xb5*\xd4a\u007f\xf4\xf1\xe1D\x05\xed\xfd\xa0\x19\x87ߧt \xfc\xd0\xef.\x04\xcctd\x87\x1f\xc5\xea\xbaT\x06\xba\xedg\x01҉Oy?:٨\x1f\xb9\x974\xaa?\\\xf8\x87\x16h^\xf8\xcd\nf\xf8\xeb\xe7\x850ō\b\x98\xe9H\r?[ץ\xd2\x01\u008e\fҢ\x18\x17[\x17\xaf\xd4~\xadX\x88\xc8@\xf3\xc2oV0'\xcb\"\x17\b\u087f3\x1f\x99\xe1\xe7\xe8\xba\xf0\x95\x00J\x1c\t\xc8e@1>\xc5o\x9c\xa7\xfd\x9a\xa7\xed\xf9\xad\xe1o\x8f\x9c\x9b\xf1¿\aO\xae\x9f7\xaa1\x85\x80\x99\x8e\xcc\xf0st]\xf8\x94\x1f.\x0eg\x90`Q\x15~+\u07be\x1d\x9f\x01\xe0s\xf5.M\x05F\x86\xbf\xaa\n\xa1I%rr\xc6\b\u007f^\x93\xfa\u07be\x10O\xf6\xe9\xb5\xf6\x1cD\xc0LGj\xf89\xba.\xf5\x9d\x00>\xe4\xcf$\x83\xdf+\xf1\xfa\xb6+\xed\xea\xe4\xfa\x9c&_S\xcez\xed\n~\xe3\x10\x1am\xcc\xf5\xe3\xfd}\xb3\xab\xa5wi~\x80T\x86Q\x15\x16\x17\x1e<\xb8X\x99\xdbq\x03\xa1&\xa5\xbe\xbb\xb7Q\xe9\x14-\x14\xc88R\xc3\xcf\xd5u\xc1\xfd\xa2\x99\xe5f]q\xc1B\xedSװ\xf69\u007f\x18\u007fv\xaf(\xb9\xe3\xf9\xea\xcfmjqh\xbb;\xaf\n\xfb\xbaMe\x18U\xe1fU^\xc1\xf2&\xbdn_\x95۽\xb8\xcfvy\xc0\x8c@n\xf8\x01\x00\x981@\xf8\x01\xc0\xa1@\xf8\x01\xc0\xa1@\xf8\x01\xc0\xa1@\xf8\x01\xc0\xa1@\xf8\x01\xc0\xa1@\xf8\x01\xc0\xa1@\xf8\x01\xc0\xa1@\xf8\x01\xc0\xa1@\xf8\x01\xc0\xa1@\xf8\x01\xc0\xa1@\xf8\x01\xc0\xa1@\xf8g\x0f\xf5\x8a{\xfd\rQ%\x00\x88\x17\b\xff\xec!0\xd8Q\xe2\x86'\x1f\x00\xa9Bn\xf8Y\xba.\xfct\xd87\xda߸\x00\xaf\xea8\x18T\xc0k\x04\xa4\n\xa9\xe1g\xea\xbaP\xb0\xf3$.\xed\x84\xf4\x8b\x19V\x86DU\x00 N\xa4\x86\x9f\xad\xeb\xf2wk\x8f\xf0\xef\xf6\v\xe6\x06 \xfc@*\x91\x1a~\xb6\xaek@\u007f|w/x;\xc4@\xf8\x81\xd4!7\xfc\x88\xa5\xeb\x9a\xea\x1c\x9c\nM\xf9;\xe1y\xafb\xae*\x83\xa2*\x00\x10'\x92\xc3\xcf\xd4u\x85\x06\xd4\xd2>x\x86g\x1c\x84\xdc\v/\x04\xc0\x84\x05\xa4\x04\xc9\xe1g\xe9\xbaB\x03\xdd\xf8\x99\xbe\x03\x90\xfe8\xe8S\x14e\xa5\xa8\x12\x00ă\xec\xf0\xa3X]W\xf4\x82\xdf\x05ь\x00\n\x16\xcek\x19\x04\xc3\t\x90\x12\xa4\x86\x9f\xa9\xeb\n\xb7\xeb\xa68\xcd\xe3\x03\xd83\xac\xc0eQ U\xc8\f?[\xd7\x15\r\xff(\x84_\f\\\xed\aR\x87\xcc\xf0st]\x83\x91\xc3~\xb8\x8e-\x06\xc2\x0f\xa4\x0e\xa9\xe1g\xeb\xbaB]\xdd\xe3\x81\xf1\xee.\xb8\xe0'f\b\xc2\x0f\xa4\f\xa9\xe1\xe7\xe8\xbaB\xc3';N\x0eC\xf6E\x84\x02\xa3\xf5\xae\x80\xa8\x16\x00ĉ\xdc\xf0\x03\xd3\xe1\tE)\xee\x15U\x02\x80x\x81\xf0\xcf\x1e\x02\xa3\xb0\xdb\aR\b\x84\x1f\x00\x1c\n\x84\x1f\x00\x1c\n\x84\x1f\x00\x1c\n\x84\x1f\x00\x1c\n\x84\x1f\x00\x1c\xca\xff\x0fL\f\x1em+\xfdz{\x00\x00\x00\x00IEND\xaeB`\x82",
+
+ "analysis/chan1.png": "\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x04\xc0\x00\x00\x02n\b\x03\x00\x00\x00aR\x8e\x00\x00\x00\x00\x01sRGB\x00\xae\xce\x1c\xe9\x00\x00\x02\xfdPLTE\x00\x01\x00\a\n\a\x0f\x11\x0e\x1a\x1a\x14\x1f\x1f\x18!# #$\"\x15%D$%#%'%'(&+)\x1e()'*+)/,!+-*,-+-/,02/63(241564796<9.9;8#?r@=2<>;>@=C@4DA5AB@DFCFHELH:IKHKLJNOMUP?PRORTQTVSVWU]XGWYV_ZI,`\xaeZ[Y7]\xad[]Z\\^[9a\xab;b\xac<c\xad_a^faO>e\xafac`hcQcdbAg\xb2efdCi\xb4fheDl\xb0Mj\xafqjRikhGn\xb2Ip\xb4lmkKr\xb7npmUt\xb4{s\\rtqWv\xb6tvsuwt[y\xb9\\{\xbbxzw]~\xb8e|\xb8\x84|dX\x80\xbf{}za\u007f\xbf|~{~\x80}b\x82\xbc\u007f\x81~d\x84\xbf\x81\x83\x80|\x83\x97\x83\x85\x82l\x86\xbch\x88Ð\x86hn\x88\xbej\x8ać\x88\x86q\x8b\xc1\x89\x8a\x87t\x8e×\x8doz\x8e\xbf\x8c\x8e\x8b|\x90\xc1\x8e\x90\x8dx\x92Ȑ\x92\x8f~\x93ĝ\x93ux\x96Œ\x94\x90\x81\x95Ɠ\x95\x92{\x98Ȕ\x96\x94\xa2\x97y\x96\x98\x95\x81\x9aė\x99\x96\x84\x9cƇ\x9b̙\x9b\x98\x80\x9eͦ\x9c}\x87\x9fɜ\x9e\x9b\x89\xa1˞\xa0\x9d\xa0\xa2\x9f\xa1\xa3\xa0\xa2\xa4\xa1\x91\xa5ʏ\xa7Ѥ\xa6\xa3\x94\xa7̥\xa7\xa4\xb3\xa7\x83\x92\xaaԧ\xa9\xa6\x97\xaaϩ\xab\xa8\x9d\xac̫\xad\xaa\x9b\xaeӟ\xafλ\xae\x89\xad\xaf\xac\x9e\xb1ע\xb1ѯ\xb1\xae\xb1\xb3\xaf\xa5\xb4Ԣ\xb5۳\xb5\xb2ö\x91\xab\xb7ѵ\xb7\xb4\xa8\xb8ح\xb9ӷ\xb9\xb6\xb9\xbb\xb8\xb0\xbc\u05ed\xbdݻ\xbd\xba\xb3\xbeٽ\xbf\xbc\xb7\xbf\xd4\xcd\xc0\x9a\xbf\xc1\xbe\xb6\xc1ܹ\xc1\xd6\xc1ÿ\xbb\xc3\xd8\xc2\xc4\xc1\xbd\xc4ں\xc5\xe0\xc4\xc6\xc3\xc6\xc8\xc5\xc0\xc8\xdd\xd7ȝ\xbb\xca\u07bd\xc9\xe4\xc5\xc9\xd9\xc0\xcb\xe6\xca\xcc\xc8\xc7\xcb\xdb\xc2\xceܿ\xcf\xe2\xc9\xcd\xdd\xcd\xcf\xcc\xc9\xd0\xe6\xcc\xd0\xe0\xc6\xd2\xe0\xdfѤ\xcf\xd2\xce\xd1\xd3\xd0\xd2\xd3\xdd\xd3\xd5\xd2\xcd\xd5\xea\xce\xd7\xdf\xd5\xd7\xd4\xe6ת\xd6\xd8\xd5\xd1\xda\xe2\xd8\xda\xd6\xd9\xd9\xe4\xd3\xdc\xe4\xd5\xdb\xea\xda\xdc\xd9\xd8\xdd\xe0\xdc\xdd\xe7\xdc\xdf\xdb\xda\xdf\xe2\xe0\xde\xe2\xde\xe0\xdd\xf0\xe0\xb3\xd6\xe2\xf0\xdc\xe2\xe4\xe0\xe2\xdf\xde\xe3\xe6\xde\xe2\xf2\xe2\xe4\xe1\xe1\xe6\xe9\xe4\xe6\xe3\xde\xe7\xef\xe8\xe5\xea\xe5\xe7\xe4\xe6\xe8\xe5\xe4\xe9\xeb\xe7\xe9\xe6\xe8\xe8\xf3\xe8\xea\xe7\xe2\xeb\xf3\xe9\xeb\xe8\xec\xee\xeb\xe6\xef\xf7\xe8\xf1\xf9\xef\xf1\xee\xf0\xf0\xfb\xf1\xf3\xf0\xf1\xf6\xf9\xf4\xf6\xf3\xf7\xfa\xf6\xf5\xfa\xfd\xf9\xfb\xf8\xfa\xfc\xf9\xfd\xfb\xff\xf9\xfe\xff\xfc\xfe\xfb\xfe\xff\xfc\xc5\xe5[\xa2\x00\x00 \x00IDATx^\xec\xbdqLS[\xda\xef\xef93\x8b\xab}\x87Ax+\xc3}\xf5^8#\xbe\x1c\xbc^gk\xa9\x17\u007f\xe2A.U\xe1u^\x05މ9\xf6\xe8}\xc9\x18\xc5\x174z\x8fg<W\xb7i\x86\x1e\xa0D\x99`1\xbcD0\f\rp\x022\x04\xa5i\x99\x89\xa9F\xc2;\x8d\x8d\x9c\xd83\x89\xf6L\x8c\x90BL\xbb\xfe\xfc\xe5\x97\xdc\xff&\xbf\xb5\xd6\xdem\xf7nw[@\xd9Px>\t\xddk\xaf\xfd\xac\xb5\xf7j\xd9߮\xf5\xec\xd5\xf5l\xf8\xdb{\x80\x01\x00\x00V\x8e\xbfmH&R\x89HV;\x00\x00\xc02\x02\x02\x06\x00@\xca\x02\x02\x06\x00@\xca\x02\x02\x06\x00@\xca\x02\x02\x06\x00@\xca\x02\x02\x06\x00@\xca\x02\x02\x06\x00@\xca\x02\x02\x06\x00@\xca\x02\x02\x06\xac\v\x02\xc9\f\x80\x94\x04\x04\fX\xfbx*\xb6\xa0\xfdɌ\x80T\x04\x04\fxO\xda\v\xbc\xc9L\xd4\xc1[Ю| \x90\x97\xc7\xf7\xb8\x95\x8f\x01\xa9\x8d\xda\x02\xe6\xe9j6Y\x06|\xb2\xe4|\x13/М\xa0\xe0_\xaf\x95\xe9k\x83\t\fbiۈ\x046\xb6%3]\x94\xed\x12\xa9C\x9b\xe8\rf\xcd@u\xca\x06w\xd9\x05d\xeds)\x1f\xc6\xd8L\x0eבz\x102\xc53\x890\x9aƪK{ \xecNnByds\x84de(\x9c\xc0\xb1'#\xbb\xb47{:\xf6H2\x1aйd&K`\xec\xd0p2\x13F\xbf\x8e\x13\xd0\xf5\x93KIkP4\x1aG]\x8a\xf9@ꣲ\x80M\xf3V\xa7\xdb\xd9\xd6\xec\x93&g\xf8Q\x0f\xe1\x01?\x9e\xa0\xe4\xe9C\x9d\x17\xf5o\x13\x18\xc4Ҁl\xb6\xaf\xd1e\x9b\r)\xff_SzG\x17n\xbbDB\xa7\xf0\x96f\xec\"\x9b]\xe9\xa5qz,\xbe\x81MGl\xbd\xbfٖ\xeeT>\x8e}f\xd4\xe0\xc5\xde\x06d\xf6ű\x88\x9c\r\xcf\x0f\xb2\x06\r\xfa\xc5\xfd\xc1#\x1a\xf2\xea\xa6\xcd\x1c\x8c)Օ\xb1\x83oَP\xbc3\xc7\xe77if!\x11>q<\x1e=Y\x84\xc1pq\u007f|C\tw8\xbb\xbd\x93\xeb\xb0\xdbw\xdf!{֍W\x95\x8c\x86\x90M)\x1bX\x03\xa8,`.\x9e\xf6\xe4}\xbcS\x96t\xd0\xfb\xd1\xd74\x90\xa0\xe0\x0f\\'\x0e\xce&0Pಆ\xfe\uf4bb5\xfdr\\\x9b\x1d\xa5\v\xb7]\"\xa1S\xe0S{3|؛\xbe\xf7T\\S\r\xed\x9b\xf9r\xf6\xc4;\xee`]\x89^\xe4\x88g 9\x1b\x16\x1b\x14\xa6N\xa3\x94\xcb\xf0f\xee':\xe7۶x\x01\x9bԄZ#=\xb1\x04oaH\xaek.(\x1aD\x90\x19,\xb0\xb3ݡ\xc3\xf817\x81\xb1\xbe\x83\xee\x9e\xd1(\x8d\x14\x15Z\f\xac\x11T\x160̺\x0e^\xde#OR\xeeޚW.\xc2x\xc1-lH!\xc5\xef\x12\xffw]~\x1c\x8f\xfc\x83\v\xb7]\"\xa1S\xe0S\xa5\xbbZp\xd3/J\x93\b\x18>\x97\x1e\xef\x91\xd9\x02\x04,|6\xbc\b\x01;\x95\xceƎ\x97P\xdc\xd1k<*\xb2C\x9dA\xe9\x89%8\xc2\x17[\x95L\xc0\x92\x1a(0\xf7B\x14\xb0\x17stח]\xa1`\x04\x02\xb6vQ[\xc0\b3n\x8b5\x10\x93t\xf2\xf1\xfd/se\x82\x9f\xe3&\xc6\xd78\xae\x0f\xbf\xd0q\xbf\xa4Iݽ\x9b\x95\xfa\xda\xef\x99͋\ve\xbaCbZB\xe4\u007f\xb7\xa9 #\xb7\x9a\xddm\xb6=9\x9b\xb4{\xb7\x92\x11\x87\xe8\xf7ʗَoD茫|k\xfa\x9ey\xec;\x98\xad\xc9\xd9G\x87\xb6\xc7\xd0&\xbe:7c\x8f[V\xc31\xb4\xf1jEN\xc8mu=?c\xfbuy\r\xd2S\x9c*\xbd~\x00\xef\xbdN\x05,R\xaf\x93\xd8\xee\xc39\be\xf9C\x02ְ\xd1/\xb9^\xe9\xe5\xc8\x04,t\xb6\xa4\r\xc2\xd8S\x9e\x9du\x80\r!\xb1\xe2[\xb2M\xb8\xed\xbd\x97\xfc\x92z%-Vn<\xc1\x9f\xf99\xdbF\x9d8\xc4\xd5\\\xab\x139\xad\xb9\xd7\xf1\xb0說\xa1\xd9\xc1\xfb5ŕ7Y\u007f\xda^{XWV{8(3x\xab\xe7\xe8nj\xa3>\xe3W\x17\xcb\f7o\x96\x15\xf7\xc9O\"\b\x98ș\xf4\x19\x1cC/\bؚEu\x01\xf3\xf2</\xbap$I\x8c-=\xf1\xcb\xe0\xa7\xf6>\xae\xd5n\xff\v\xc6\xdf\xdbu\xad88\xf1e\x11\xc6S}:\xeeP띒\xf3\xd4\xe2Qq͝\xb1V\xae#\xbad\xf8n\xadH;n\xbd\xaa\xcd\x0fЬ#\xb7\xbay-\"\xf24`\xcb-\xb4\xd9lN\x99팥yknfNu9r\x93\x1b\xb3\xa2ײ/m\x88\bM\xf3F\xa4\xad\xbb\x94y\x00Kk\xa0\xb9[\xeb\xea\xb6fPI9\xa29c=\xa3)\x97\xd5 =ũRw\x86\xf7'\x1e*`\x91z\x03\x83ui\x83،\x9a\x1ebQ\xc0\x02\xf9ۥ\xd7+\xbd\x1c\a\xb2\xce\xcc\xcc\xdcE\xb2\xb3%m\x10ve\xe6\x9a\xdb\u007f\x814\xf1\xde\x12\u007f\x9ad\xdc\x1c\xaeW\xd2b\xe5\xc6\x13FQ/+\x14u\xe2\x10\x9er\x94\x87>A\xa5n<;a\xaf4\xda\xed\xf6\xe74\xfb\nwc\xa4\xf3P\x15\x19%>\xdd}\xb1\u007f\xec^\x19\xf7Nn\xf0\xd8n\u05f7҄\xf43\x9e;a\xe8l\xd5\xeb\xef\xd5F\u007f\xc8R\x01\x1b\x88Ѫ\xf9\xe9\xde\x1dY\xf1}\x86@j\xa3\xba\x80a\xaf\xc7ai\xf6E'\xdd|\xe2\xc7ܑ!d\x11\xfd\xcfn-b\xc9\x12\xf2\xcd|\xf1\x10I\xcd\x1d\xae%C\x88\xb9\xbe\x1f\xa2˅\xeeV+2\xb3\xbd\x16\xd2\xc3\xd0\xd2{\xef\xeb,\xd6\xf5S\x1eq\xe5\xa3]>6\xc6\xf5Y\xe8\xe5}\xc2\xe6\x10i\xb2\xc8%\x96k\xb1\xbc\x06\xcdVj\x96S\x80q\x17\xeb\x1eu\xa1\xbb\xb2\x1adCH\xfcɱ\x1d\x98\xf5\xc0$\xf5\xe2#\x05\xde\x1c\xe1с\xe6_g|\xe3\aP\x8f\xecz%\x959Ď\x8eCv\xb6\xa4\r\xfat\x1b)\x1bخ\x91\xe7FN\xe1F\x91\xf9\a\xd2VDZ\x1c\xa7\xf1\xa4\x8e\xc9PA\xe5!d\xd7&\xb4鮐\f\x8f\x10\x87\xb9\xfb\x98\xca\x0e\xe9Iu\x1ezG\x92\x9d%A\x99\x01E\x100\xe9g\xdc\xc7=#\xa6\xdc\x14\x8eF*`nt+\xea\xe8~\xf2~Y1\xb0FQ_\xc0\b~Kwt\xb2\xdb\x12ך\xa1,`\x17C\xc9\x11\xee\xa9r\xb9\xd0\xddZ\xba\xcd?O\xc8!c%w\xf6\xd6\u007f\xe6\x1f\x06\x04_W\x1c\x01\v\xfb\x82\xbd\xd7\xf7l\xcbD\xb4K\x845G\xc8\xcb9\r\x96נ\xf9\x82\xbe~\x8d\xbc\xb8\xe2\x13V\"\uf23c\x06\x99\x805\xa0\x06&`\xd2z\xf1\xcc\xf6-\xfb\x04\v\rU'-U\x13\xc9\xf5J*s\xa0KCCC\x97\xa9\x80IΖ\xacA>\xc4\xd3\xcd\x19\x8d,Wr\n\xff\xc6H\x0fLڊH\x8b\xe34\x1e\xb7'\x160o\xb5&\aekN2?~X\x9f\xea\x8fν#\x18\xae`\xfc\xd2p\xf4ƽ\xa7A濊#`\xe1ϸ\xb1\x84\xbc<\xe7\xbe\xc5\xd1\xc8\x05\xac%\uaa3b\x8bσ\x1eؚEe\x01\xf3\v\x1e\xafq> M\x12\xcc\x0f\xe2\x96a(\vX8\xd9\xc1\xcd)\x97\vݭ\xdbž\v\xed\xf3\xf8\xf8\x83yh\x8b\xd0\xe7\x89#`;BY[r>o\xb3\xed\x14\x04\xec\x1c\x0ey\xc2%5\bn\xab^4\x8a?\x15Tho\x81\xac\x06\xb9\x80yɽL\x05LZ/Ʒ\x90\xf8\x00VS14$\xb8Ӥ\xd7\x1b\xa9L\xe2\x03\x93\x9e-I\x83\x1e\b\xb3\b\x04%R|KD\x1f\x98\xbfK^\xaf\xa4\xc5ʍǃ\x91\x11\x9b\x92\x805hy'r\xfeF\xcbޣ\xb0>\x9d\x10\xdd]gI\xfa\xed\xbd\v\x95\\ٝ\x04=\xb0\xc8g\xbc\xfb\x15\xfd\xa6J\xdc\x03\x1b\n\xbd\x95Rlh(6\x13X\x13\xa8+`\x81&\xc1e\xf2\xd0\x14\x90$1u\x87%\x99(\x1d%`\xdfD\t\xd8\x18\x1d^(\x11\xba[˷\x8d2H_\xe0\x01\xed\x01\xf9Zҙ\x03\x9c\xddv&\xb7̖\xe4\x1e\x10\x13y\x05\xf4\xbb\xfb\x80 `\xf46d\xf7\xb0\xb4\x06M5=\xc6#\x1f\xae\xd8Ɗl=\"\xabAr\x8aS\xc2D\x03*`\xd2z\xb1'\xfb\x8b\xad\xc2\\\x03Mx\x8a\xab\xe4z%\x95I\x04Lr\xb6d\r\xf2\"v$ډ/9\x85\xf8\x14\xd2B\xfb\x91\x92VDZ\x1c\xa7\xf1\xd8DŽ\x8d!=q\x18?{\n)\xf4֘>\xdd{I{`O\x18D\x8f\x1e7\x12\xe9zۧ\xef\x94\x19Pb\x05\xec%W\xfb\xf2Y\xa51v~\x85T\xc0\xea4\n\x9d-x\n\xb9vQW\xc0p3\x9b\x12\xed\xa7\x1e{I\x12\xe3I>I'?\"`\xfaF\x8c\x83\xff\x12%`\xb3\x06#\xed\x82ݸ\x11].\xf4\xbfۅ\xd8\x18\xf5\x8b::#\x9e\x9d\xb9\xf0\x18{-\xc4xZ8&\x15\xb0Po\"\x87JG`{\x94\x80Ik\xd0l\xa1\xee\xa9m\x85\xd4\x1fDG/-\x82\xc3E\xd2\x1f\t\x9fB\"`\xd2z\xfd\x05g\xf0\xb1]\x81\xf0)\x18\x92\xeb\x95T&\x110\xc9ْ6\xa8 \x87\x88\x94\xeb'\x1a,˕\x9c\u009by\x80\x88L\xa0p\xab\xbc\x15\x8a\x02&;\x1b\x19\x87\n\x1di\xf9\x89%\xb8\xb3B\x9af4b\xfc\x9a:\xbeƄ'\x8c\x8d\xb7ɇǍ\xb0C\xd7d\x06\x94X\x01{\u0095q\xdc\xe9\xd0sfwCx\xf0*\x11\xb0@\xde^\x1c\v\b\xd8\xdaEe\x01s\xf1\xddN\xb7\x93y\xee%I:\x89\"\xe1\xf4+\xe1)\xe4\x04\xfb\xf25\x1e\xbas\xbb\x86\xd3ݟ\xfa\x8b]\xf7\xe5D\xf0\xe9\x97:\xfat\xf2\x91\xfeD\xe7\xc8\r\xee^T\xc1ѯ\xd1\xe5\a,u\n\x95Z\xda+P\x13\xbd\x037\x9f\xb3\xb6U\b\xcf\xcf\xcei.\xb5\xef\xcapKm\xe7\a\xd9\x135v\u007fԡ\x83\xd7\xeb\xf2\x91\xb6a\xd0c\xdbtd\x10\x8f\x1e\xd9d\xf3\xc8jР|\x8b)7\x8bZ\x97\xa7\x9d\xb2\x9eJ+\x97\xd7\x109\x85\xb7t\xa7\x87\xeczv\x96z%\xf5\xce\f\x1cӺ\xf1df\xf5\x80\x9f\xce\xc4\x0f?\xc6\v_\xaf\xa42\xd9L\xfc\xf0\xd9\xe24H2\x13ߑ\x91Sw&+m\xa3\xd9)\xccĿl\xb3\xb9eo\t\xee\xca(0\xb7\xffb〴\x15\x92\x16\xc7k<\xf9\x14\xd3.ay3\xe3\xd2Z\xd4\xd1\u007f\xba\x98v\xb0\x1aw\xd7\xf7\u007f{\x85JU+W\xdc:\xdc\u007f\x85{$3\x98\x9b\xb0\xdb\xf5_\xda\xedo\xb1\xf43~\xa6\x1f\x1b\xb1\u007f\x1f\xea\x80\xedC!\xa9z\xda\xc9u<\x16ӗ\x91\xd2\xef\x01\x1e(\x8d+\x815\x81\xca\x02\x86==\x16S\x9b\xf0\xf3\x16I\x12\xbbo%*4W\"\xfc܍=b\u007fa\xd4\x17\xd7~\xc3q\u05eeѬ\xff(&\xaf\xf4\xfb\xfb\xf9\x05CqM\xf4\xcfO|\x9b\x11B\xe9B\xe7\xaek\xa76\xebS\xfa@\xac\xa9\xb0.gSv\xa1p\x03\xfa\x8fg\xa5\x17\x0e\xc9lDž\x1f\x11\xb2\xfb#p9W\xa3-5o\xd3\x14\x1e#Y\x9b\x1c\x19\xe4\xf5\x98\xac\x06MuEfv\xb9\x87\x19\xfff{\xc6\xf6\xaf\x03\xf2\x1a\"\xa7\xa8C\x88\xba\x9a\x8e\xd1\xdf3F\xea\xed\"\x86\xd5\xf88y\xed\xa5\xbf\x85\xcc\v_{\xe8z%\x95E~\v\xc9K\xce\x16\xa7A\x0f%\xbf\x85t\xed\xcb\xdazҼ\x91\\\xfa\x11\xd1\xf1U*=\x05\xc1\xf1\x8b\x8c-\xfb\x1c\xb2VHZ\x1c\xaf\xf1\x843?\x19\x9073.s7>\xd3\x1b\x05\xa5\x19;]Vb\xa4}\xaf\xfb\xc6ۇu\x06\xe3#\xb9\xc1S\xd1Iv\x0fK?\xe3\t\xf6\xb3G\x9dQp\x82\x99\xb5\xbcP\xed,=*\xfe\xc8̖~2\xfa\xac\x94\xe9\x8d\aǧ\x03\x18X\x83\xa8-`k\x8eȨo\x9dR\xad\x89\x196.\v\xaf\x8b\xaf\xbd~\xf7\xee\xed\xd3\xf3\x9f\xc5\xfdEl\x8b\xa6B\xf9\xd7\x1c\xedy\b\x96\xd3Y\x9b\x80\x80\xbd'\xeb^\xc0\xf0\xe5\x9c%\xaca\xb1x\xfa\x85\xc9b8X6\x12\xc7\u009b\x1d\xff\x87\xf8\xd3㞸ǀ\x14\x06\x04\xec=\x01\x01S\x89'\xe2\x04\x8a\xa9xS\xfe\x80\xf5\b\b\xd8{!x\xb7\x01\x15\b^\xd1_\xeb{\xd4wM\xff\xd5\x02\x17\xaa\x00\xd6\x03 `\xef\x05\xf3nOb@\x05\x82õ\x06\x9d\xa1v\x18\xf4\v\x88\x00\x02\x06\x00@\xca\x02\x02\x06\x00@\xca\x02\x02\x06\x00@\xca\x02\x02\x06\x00@\xca\x02\x02\x06\x00@\xca\x02\x02\x06\x00@\xca\x02\x02\x06\x00@\xca\x02\x02\x06\x00@\xca\x02\x02\x96\"\f\u05fc\x96\xed{\v\"\xeb\xd8\x03\xc0zEm\x01\xf3t5\x9b,\x03\xbe\xa8\xa4o\xe0\x96\xe9\xd6\xc0\xca,\\>\xb9I\xb2\x86M\b\xef\xb1-\xe9{\x17\xbf\x00\xcb_\xaf\x95\xe9k\x170S\xbc_'.\x18\xa3[X\xfci\x1a\x81\xba5\xaaކ\xb4\x0f\x1eC\x1c\x00R\r\x95\x05l\x9a\xb7:\xdd\xce6\xba\x8a\xa1$\xe9kj\xa3ɦ\x95Q\xb0\xc1\xd0Z\xcb\x12vm\xb9~$}\xf1\x97s\xfaP\xe7Eai\xaaGO\x12\xd9\xdd\xe1\xec\xf6N\xae\xc3n\xdf}'\xae\x8d\xac\x86N\x16\xc8G\x9ek\xddx\x15\x03\xc0\xfaFe\x01s\xb1\xb5\xef}\xbcS\x96\xb4Y\xe82N\xf3\x16[\x92\xd2\xcbD(du\x04/\xba\x8a\x03\x8b\u05ef\x1f\xb8N\x1cd\xf1Zq\x8d4@E\f\x1d:q!d}L \xcb0\xd2\x1a^\xe8\x1a\x15r\xcfh\x12\xac\u007f\n\x00\xeb\x01\x95\x05L\x88\x94\xe8\xe5=\xb2d\x8f\xe0\xceiO\x14\xdbv\x19\x89\x150\xd7\xd2\"\tF\x16\xee\x97G؉a\xee\x85(`/\xe2\x04S\xc2\xf2\x1a\xae\x18f\x15r}\xd9\x15\x18\x00\xd65j\v\x18a\xc6m\xb1\x06dIoS\xaf\xd7\xef\xb55y\x13\x17\\\x06<\xe5\xd9Y\a\xc4!dSAFn5QU\xbfVXu\xb9Z\x96;\xbe\x11\xa13\xae\xf2\xad\xe9{d\x8b~\xbe\xbd`\xd0\x1d>KC\"͕\tn\xad\x9b4r\xab@\r\xb5\bޯ)\xae\xbcI\x04虎\xe3\xbeyq\U00068f96\x06s\x8d\x84\xa2\b\x1b`l\xaf=\xac+\xab=\x1c\x94׀犅\x0e\x98<\x97t\xc1\xd2g0\x00\xacgT\x170/\xcf\xf3f_Tr\xa6\x9b$\xbbԿ\x1b]\x99\xb9\xe6\xf6_ \rMW\xa4\x1d\xb7^\xd5\xe6\x13=}hkAu6\x9bG\x96;ciޚ\x9b\x99S]\x8ed\xe3\xb6a\xee\xabG}g9\xb6\x92;\x8b<B#\x8c\xccN\xd8+\x8dv\xbb\x9d\xad\xe1\u007f\x85\xbb1\xd2y\xa8*\x88\xe7\xfa\xfa\x0eW\x16\x1bn\xd6\xeff\x91\xc3\xc2\x02\x166\xc0Ow_\xec\x1f\xbbWƽ\x93׀\x9frv\xb6\x95\xe7b<\x00\xd1v\x80u\x8e\xea\x02\x86\xbd\x1e\x87\x18\x8a(\x9c\xf4w[\x9c\x1e\xa7\xa5[yA\xf3e\xe4\xd3m>\x1a\xddL\x83i813\xa6\x01\xb8X`\xe7\xf0\x10R\x96\x9b\x8fv\xf9đo\x98\xd9>\xd2u\n\x9e8\xcfv\x94\x86\x90\xc3\xcc\xfd\xfeX\x88\x16Vŝ~\x8b\x83\u009a\xee!\x01\x93\x18t\x1e\xa2}\xb3Β\xe80\xaf#\\H\xb2\xe4CS7\xba\x85\x01`=\xa3\xbe\x80a\x1a\f\xb2[\x96\xb4Y\xfc,\xa9v\xf0+\x1fb\x91m\xceh0\rp\xe8\x9f'\xe40\xb7RX\xc0d\xb9\xf9JN\xf3W\x9d\xb5GK\xb8\x13,\xad$`\xf5G\xe7\xde\x11\fWXn\xd1\xcbp\xc1\x90\x80I\f^\x1a\x8e\u07b8\xf748'\xaf\x01\xe3~\xeeE(\x19%`-\x18\x00\xd63*\v\x98_p~\x8d\xf3\x01I2`zȒB\x90n\x15y\x80\xd8s\xcfs\x1a\xf2\xb2]\x8c7Ƃׄ\x05L\x96\x9b\xbf#\xb6\x8aLJ\x0e7\xf6\xdbO\xc7\x17\xb0\x13\xa2\xdf\xea,\xcb\ry\xafpD\xc0\xa4\x06o\xef]\xa8\xe4\xca\xeeD\xf7\xc0&\"\x91[e\x026\x04\xf1\x0e\x81u\x8e\xba\x02\x16h\x12\xc2\t\x12\xa9\x92&E\x01\x1bU[\xc0\xbc\xe8:\xdd0'~\xf9\xb6Q\x06{\x90\x10\x160Yn\xfe\x81\xd8**k\xa8\xf7\xfd\x82\xb2\x80\xdd{I;XO\x18\xaf¹\"\x91\x1eX\xd8\xe0q#\x91\xae\xb7}\xfaNY\rd\x9c\xca\xc2S\xcb\xeb\xa5\xd4i\x16?\xd5\x03\x00\xd6\x12\xea\n\x18nfa\xe9\xfd\x96\x1eY\xb2G\x1cB\xaa>\x8d\xa2 \x87(\x93\xeb'\x1a\x92\xecB,\xbc\xe1\x17,\xc8PX\xc0d\xb9\xf9\ack8L\x05%X\x15#`F#Ư\xa9_kL\xf0~5ަ\xafJ\x02&1h\xe5X\xc40\xe35Y\r\x84\v\x95\xa1i\xf8\xd2\xdc@^(85\x00\xacST\x160\x17\xdf\xedt;\x99\xe7^\x92\x9ci\xb18\xdc\x0eK\x8b\xea\x8f!\x1d\x199ug\xb2\xd26\x9a\x9d\x18\x9fB\xa5\x96\xf6\n\xd4\x14z\n9Ⱥ\x83\xe1\xdc\xf9A[n\xa1\xcd\x16\x1d\xc0\xa3\x95\xbb\xd0y\xbb\x8a\f\xfb&ħ\x90\x13\x82Դ\x16u\xf4\x9f.\xa6=\xa5\xc6\xdd\xf5\xfd\xdf^!\x9a\xf3\xeeO\xec\x19\xa2\xe8\xcez\xda\xc9u\ba\xaa\xc3\x06\xa4\xb2\xe2\xd6\xe1\xfe+\xdc#y\r\x18?\xe7B3\xf6\xa5\xb9\x97\xd1(\x06\x80u\x8d\xca\x02\x86==\x16S۠?*\xe9\x1fj3\xb7\r\xf9\x13\x17]\x0e\\\xfb\xb2\xb6\x9e4oD\xc7H\xbak\xa76\xebӻ\xe4b\xb2\x98\xdbk\xa3\x93Y\x84r\xc7\xd3Xnt\x9f'\xd8QYt\xa8\xfe~\xa5\xce8W\"\xfc\xbaQx`8w\xe33\xbdQ\x10\xa8\xb1\xd3e%Fҵz&\xf8\xbajY\xe6l1I\n\xbf:\n\x1b\xe0\xfb\xc6ۇu\x06\xe3\xa3\xe8\x1a\x88n\xe9E/\x98$ז~\x12\x03\xc0\xfaFm\x01\x03\x96D\xf0\x86\xae/*\xabES\xa1\xfa\xb4\x13\x00Xe\x80\x80\xa5\x06\xc1\x0e\xc3+Y\x867\x1b\x16\xa3\x00\x00\x100\x00\x00R\x16\x100\x00\x00R\x16\x100\x00\x00R\x16\x100\x00\x00R\x16\x100\x00\x00R\x16\x100\x00\x00R\x16\x100\x00\x00R\x16\x100\x00\x00R\x16\x100\x00\x00R\x16\x100\x00\x00R\x16\x100\x00\x00R\x16\x10\xb0UG{\x81\xfaљ\"x\vړ\x99\x00\xc0\xaaAm\x01\xf3t5\x9b,\x03\xbe\xa8d`\xbc\xdd\xd4\xe6L\\r\x859\x86\xd2,\xc9l\x16L'\xc7E/.\x11\xa6\x01\x9d\x93\xed\u007f\xd0\x13S\xba\xb5\t\x83^6\xa4\xc1\xafā\x94Ae\x01\x9b\xe6\xadN\xb7\xb3\x8d\xaeb(I\x06\xac\xe6Q\xf7\x03Ӄd\xa5W\x12\x8fmS]2\x9b\x05\xf3\xd6^ӊ\x95\xf9M\x9aY\x9e\xb1\xf4\x13\xf7*\xafwh\u0378\xa5\x98\x1f>\xbe\xf1j\xc2\xe3\x00\xb0zPY\xc0\\<\r\xec\xe3㝲\xe4C\x13\x1d4\xb9L\xab{\x85w\xcd\x12uD\x91\xb3q\x04lRs*&o\xa9'\xdeQ\xaa\x9c\x9f,\xf2\xc0\x19\xa5\xe8K\x00\xb0\x1aQY\xc0\x84\xa8\x8a^\xde#KZ\xd9\xf2\xf8\xb8\xe9A\x9cB\xab\x83\xa5\xea\x88\"\xf1\x04\xac\";Vŗzb\xa55\xfc\x17\x82/\xbb\"\x99\t\x00\xac\x0e\xd4\x160\u008c\xdbb\rȒm,\xba\x19n\xbf\x9b\xa0\xd4r0\xbe\x11\xa13\xae\xf2\xad\xe9{\xe8ڦM\x05\x19\xb9\xd5L>l{r6i\xf7ne6\xae\x03\xdaM[\xf6zHJs\xb2:7cOl\xe7ļ\x85E\x97tg\x8a!\xd82%&\xef\xcat\x8d\x06ã\x1b%\xc6Y2p\xbc`\xd0\x1d>\xfb\x8c\x1d \x02v\x83.*\xfd\n\xe3\xe0\xfd\x9a\xe2ʛ\xb3,۟\xf9y\xa8\xa8҉}\a\xb359\xfb\xc61\xf5\x8cm\xe2\x95.'|\xe9V\xf1j\xf2\xe5\xcd\xf4\xa5#\x94\u058c\xa3k\xf0\x96ksN\x9e\xd4n\x16\xbcmg\xd2U\x8fN\x00\x00KBu\x01\xf3\xf2<o\xf6ɓ\x03M,*\x91\xb9-a\xc9\x0fό\xa5yknfNu9\"wqE\xdaq\xebUm~\x80\x86[<r\xab\x9b\xd7\"\xaaj\xbd\x9b\xf3\x1b\xbaϡ\xcb$\xa9Ay\xcd\xed[bC\xab\xedG{\xe8\xc6o\xbe*`\x96\xae\xed\xff\xa8\x84\xbby\x9a+\xbb]\xd6Acp\u007f\xf5\xa8\xef,\xc7V\xb4'\x02\xf6}\xbd\x10\xd6\xe3\nwc\xa4\xf3P\x15\v\x062\x8azł\x8a'\xb6\xa2\x8a^˾\xb4!\x8c\x9d\xcd\x1b\x91\xb6\xeeRf\xd4\xe5D.\xdd7\xc0\x82\x90\u061cQ\xcd|`\xb3\t=:i\r\xfe\xbc\xec\xaf\xcfi\xd2M\xbf\xb8\xccj\x19@\x83\x18\x00R\x01\xd5\x05\f{=\x0e\x16\x8aH\x92\xf4\x99\xad\xde\x19O;\xffa\x9f\xb6-\x88|\xb4\xcb\xc7F\xb3VD\x9d\xe7C4\xd6\xf5u-\x95\xae\xaf\xb3\x88\x96\xcd\xe4\xec\xf1Ӏo\xd4G\xa7\xd9B^+\xb41UL\xd6\t\xa1\x8a\xa6'\x05\xa6eG\r\x17\xf1\b7\x8c/~\x85\xf1l\x1f\xe9f\x05O\x9c\xa7\xd9D\xc0:\x8aX\x10\xb6a\xee>\xa6A\xd6\xd8cI+\x12\xc3\x1e)\x9f\xd8g\xa1o\xdc',̮&\x8b\xc8Qy\xd4\xe5H.]6\x84\f7\x93\x92.\x0eI#5\xb4 ҫ\xfb\x1a9Dk7\xba\x85\x01 \x15P_\xc00\xbd/\xbb\xe5I\xaf\x95t\xc6\x06\xad+0\x03)?\xe4\xb0.\xdd\xe6\x9f'\xe4T\x90\xfb7{\xeb?\xf3\x0f\x03\xb4#u\x17=\f\x9bj\xa8g\x88E\xf1Vd\x12\x85\x90\r\xeb\f}D\x9cfqc=I\xbf\xea\xac=Z±\x18\x92g[[\xc5 \x92\xf5G\xe7\xde\x11\fW\xe8N{H\xc0\xe2\x9c\xd8{}϶L\xb4\x9d\xe5\x1e\xc1\xb1\x97#\xb9t\xb9\x80I\xfd\xf2a\x01\v\xd7p*\v\xd3`\x98\xa1\xf7\xdfMe\x1c\x00R\x00\x95\x05\xcc/8\xbf\xc6\xf9\x804I\x98\xf1\x06p\xd3@\xfc\x82\xcbE\xfe\x0e1\xb1]T\x1fڻ\xf1\xf1\a\xf3\xd0\x16:\x1d\xea2\x8ax\x834t~V\x9d&\xb6\x0e\x11\x9bU\xc0&\xcb5\x8c\xe0\xc7:\xcc\x04\xec\xf1\xa1Í\xfd\xf6ӂ\x80\x1d*\xa9<\xcfF\x8d'\x84hk\xdcY\xba3\x18\x1a\xbc)\x9fxhK\xce\xe7m\xb6\x9d\xdb\xe5\xb9R\"\x97.\x17\xb0\x1d8BX\xc0\xc25\\F^\x1a\xc47\xd4\x03\x1bB+\xf0I\x00\xc0\x12PW\xc0\x02M\x82\x8b\xe7\xa1) Ib\xcc\u20f9سI\x95\xc9\x0f9\x91ʷ\x8d2ȝ\xfc\x80\xced\xf0\xb5\xa4_ǸG\x12;\x96\xb9\x8e\x12\b\x982\x861\xfc\xb8H\x10\xb0\xca\x1aꩿ \n\xd8ԋ\x92\x0e\x9a\xaa?\xfa\x84\xc1\x82\x0e\xf94\xe2,V\xe5\x13\xe7\x15\xd0Q\xe0\x81\xed\xf2\\\t\x92K\x17\x05\xccĺ^\xf9R_YX\xc0\xc25\xb8\xd3\xf6\xba\xc7s\vB\xf3+\xea4\xab{B\v\x00\x84PW\xc0p3\x9b0\xe1\xb7\xf4ȒN\x9eȆ\xaf9\xe4\xbfV\x93p/\xa5\v1\x0f\xdc\x17䦮C\xec\xd2\n\x8f\xd1\x19\x05\x85t8v\xbc\x1a\xc7\x170wCt\xb8n)\x12\x01;|\x81\xec\a\xab\xc4!$\xc6#:\xea\xc3\x1f\x13\xbc_\x8d\xb7\x99y\xe96AE\x94O\x9cCu(\xb0=\xbe\x80I.\x9d\xbc\x16b<-4K6\xa3\"V\xc0F\xd1\x16\x84vz\xc4ぼ\xe8\xf0\xbd\x00\xb0JQY\xc0\\|\xb7\xd3\xedd\x9e{Yr\xc8\xfd\xb0ɪ\xfa\xd7\xfe\xfc {R'\xe8\xcf)Tji\xaf@MT\x056\x9f\xb3\xb6U\xb0\a\x82\xbd?ɻ~\xf782\xd1\t\xf1G\x06\xf1\xe8\x91M6OT-\xfbb\xc2uK\x98\xfa\xacc\xb6O75[\u007f\xfa{\xdc\xca]\xe8\xbc]ŕݙxk\xaf\xf9rbn\xb6\xd6\xf0\xe85\x91\xae\xdd\xf5\xfd\xdf^\x11\u007f[\xe4J\xbb$\x14T<q\x1d:x\xbd.\x1fi\x1b\x06\xe3\\\x8e\xf4\xd2\xf19ͥ\xf6]\x19nY3\xfd\x836\x9b\xe6\x88\xcd\xe6\x93\xd5;\xaa\xe9\xb1\xda<\xa1\x0e\xd8e\xa4<\x85\x1f\x00V\x1d*\v\x18\xf6\xf4XLm\x83\xfe\xa8\xe4\xa8\xc5l\x1dM6A\xfc\xc33\x9e\xc6\xdc^\xa2\xfet\xed\xd4f}J\xa7\xa25\x15\xd6\xe5l\xca.\x14:\x84\xae\x839\x99\x05mt\xda\x14B\x9b\x1c\x19\xe4\xf5XT-f-\x8f\xe3\x11,㸾b\xae\xb8\x8f\xe3\xce\xe3`Geѡ\xfa\xfb\x95:c'uz=%\x99\x1c\x9d\xcf:v\xba\xac\xc48\"\x968\xf3\x13\xd1\xff\xa4t\xe2\xc0\xe5\\\x8d\xb6ԼMS\x18\xe7rd\x97\xee?\x9e\x95^8$o搐F\xbc\xac\xde\x01\r\xcd\xdbTȜ`\xb6\xf4\x93\x18\x00R\x03\xb5\x05\fHF\xb5F\xf5\xd9$\xde\xcdǼ\xf3\xf3\xbe\xa1\x03Y\xa4\x13ܢ\xa9\x98OV\x00\x00V\t `\xab\x8e\xcb9\xf2\x99d\xcbO\xbb0o\f\a\xb4w\xb17\x1b\x16\xa3\x00R\a\x100\x00\x8f\xa6\t\x13(\x1ci\x91\xc9g\x00\x90\n\x80\x80\x018P\x91~\xac\xa5\xb7\xe5X:\xfc\x88\x1bH1@\xc0\x00\x82uO\xb6&{O\u0085\x0e\x01`\x15\x02\x02\x06\x00@\xca\x02\x02\x06\x00@\xca\x02\x02\x06\x00@\xca\x02\x02\x06\x00@\xca\x02\x02\x06\x00@\xca\x02\x02\x06\x00@\xca\x02\x02\x06\x00@\xca\x02\x02\x06\x00@\xca\x02\x02\xb6\x9ai/\xf0&3\xf9 x\vV`5o\x00x\u007f\xd4\x160OW\xb3\xc92\x10Z\xf9\xcb\xc1\x8b\x93\xbf=\xed\xe6.O\xbc2+\x87\x99\xae2\xa3ݳ\x9c\xcbcur\xe2J`\n4\xa0s\xb2\xfdc(m\xc1+U$\xb7=Bږ\xe1\x12\xd2\ri\xf0\x13n \x15QY\xc0\xa6y\xab\xd3\xedl\x13\xa3\x12\xf9L\x03M,\xe16\xd9\\6\x93,\x18Ɗ\xd2+J\x96ό\x1az\xcd\x05\xe1Xg\xcb\xc0[{M\x9c\x18\xb7\xf87ify\x86Ƕ\xa9N\xd94\x96\xe4\xb6n\x9b\xed\xebp\xfc4\xebƫ\t\x8d\x01`U\xa2\xb2\x80\xb9x\xaaR>\xde\xc9\xf6\xac=n&`\x81f\xba\x88\xdf@\xb3\xfaK\x1a\xc6aG\xa9\x98p\xd0%\x9a\x03\x9f\xe6&\xb4~O\xe2\x05\xe9\x9eԜ\x8a\xc9[L\x90\xee\x05\xd8\x0eE\x02@\x9eѬ\x9e\xef\x0f\x00X(*\v\x98\x10\x9a\xd0+\x84\xefp\x98}\x1e&`N\x13\r\xc1\xe339\xe3\x97S\x97\xf0\x12\xf2L\xc0\xf0o\xd0r\xaev\x1dO\xc0*\xb2cϺ\x00Q\n\xb3\x00[\x89\x80\xf9\xb2a)\n \xf5P[\xc0\b3n\x8b\x95\xf6\xb5|&\x17\x16\x04\xac\xe7.;pw\x19Gjq\xf0\x96ksN\x9e\xd4n\xa6\xee\xa2\xeb\xf9\x19\xdbi4\x1f\xab\x18`-\x1f\x87\x04\xac<\x87\x197\x15d\xe4V3Q\xf1}\x9e\xb7\xb9p0\xe7ntu\xe6-luiw\xa6XE\xa6\xa4W\xf3\xaeL\xd7h0<\xbaQb\x9c%\x03\xc7\v\x06\xdd\xe1\xb3\xcf\xd8\x01\"`78\x8eӿ\xc28x\xbf\xa6\xb8\xf2\xe6,\xcb\xf6g~\x1e*\xea:\xa0ݴe\xaf\x87\xa44'\xabs3\xf6\xb0^\xec\xc1lMξqL\xbd]\x9b\xf8P\xae\x14\xcd\xf1\x8a\xec\xac}\x82\x93+\xd46yR*`\xf8Lz$\x90\x1b\x00\xa4\b\xaa\v\x98\x97\xe7y3S\x01k7\x16\x05\xacMX\x06~@\xf5Ga\xfe\xbc\xec\xaf\xcfi\xd2M\xbf\xb8\x8c\xf1\x11\xcd\x19\xeb\x19M9\x91\x86\x01\x16\x03\xc3F\xfb\x83\x0ed\xf59?G\xac/S\x91v\xdczU\x9bO\xb4\u05f7M{\xe9\xee1\x84B:\x10f?\xdaê5_\x150\xfb%\a\x1f\x95p7Ose\xb7\xcb:h8\xee\xaf\x1e\xf5\x9d\xe5hT\"*`\xdf\xd7s\x1d4}\x85\xbb1\xd2y\xa8\x8aŋ\x1c\r{\xdez7\xe77t\x9fC\xe4\x1a\xb1\x06\xe55\xb7o\xa1\xb1\x89\xac\xa8\xa2ײ/m\x88\xf4_\x9b7\"mݥLi\xe44\xccl\xf3[Z\xb6gе\n\xc3m\x93%\xe5\x026 I\x03@\x8a\xa0\xba\x80a\xaf\xc7\xc1B\x119\xa9\x8c\t\x02\xd64Ď\f5%,\xb8\f\xb4 ҅\xf9\x9a\x05t\xedb}\xad.\xc4zU\x92!$\x85\xdd\xeeVD]\xeaC4huy\x96\x87$\xabc\x05l\xb2N\x88p4=) _\x1b\xdap\x11\x8fp\xc3\xf8\xe2W\x18\xcf\xf6\x91nV\xf0\xc4y\x9aM\x04\xac\xa3\x88E\xe9\x1e\xe6\xee\x93\xd7\xc7\xc2cIk(H\xf7L\xce\x1e?\x8d?GgTh\xb6\x90\xd7\n-I\xf9,\xf4[\xe0\x13\x1a\x87\x17k\xb2H\xef\xab\\\x8b\xe5h\xf2H\x97j&\xb7@\xd66Y3e\x02\xe6F\xb70\x00\xa4\x18\xea\v\x18\xa67c7\xf5x\x05\x02\x01wS\x80\xf4hڄ`ֽmI\xca}pNe\x91\x17\x17\xa2=\xbf\x8aOXN\xde\x11\xfa*\x11\xb0K\x83ւt*%\xa5\xdb\xfc\xf3\x84\x9c\n\x1c\xc8`\xb3\x1b\x9c\xb1\x02&2\x89BȆu\x86>\"N\xb3,D$~\xd5Y{\xb4\x84\x13CD\xb6rL\xbfp\xfdѹw\x04\xc3\x15\xba\xd3\x1e\x12\xb0\xbb(\xb2г\x86:\xaa\xceih\xd2{}϶L$\x84\x88<\x12Ε\xa0\xf9\x82\xbe^G^i\xdbd͌\x12\xb0\x16\f\x00)\x86\xca\x02\xe6\x17\x1e4\x8e\xf3\x81I>\x84\a\xf7\b\xb3\xc1\xda{\x12\x15]\x0e.\x93\xbb\x9btGh\x0f\xec\xd3},go\x01}\x95;\xf1}iԳ\xb5]Ԥ\xfd\xe4VgJ\xeb\x8b+`\xd8f\x15\xb0\xc9r\r#\xf8\xb1N\x88q\xfb\xf8\xd0\xe1\xc6~\xfbi1HwI\xe5y6j<\xc1\t\x9c\xa5;\x83!q\xb9\x8c\"\xce)\x16\xb8\x9bŢ\x1dڒ\xf3y\x9bm\xe7vy\xae\x14\xc1\x89oC\xa3Ҷɚ)\x13\xb0!4\x80\x01 \xc5PW\xc0\x02M\x82_\xe7\xa1)\x10\xf0R\x1cf\xaf7\x80\x9d<\x1d\x0e\x85&W\xa8\x88;m\xaf{<\xb7\x80\xaaj\xc56\x96\xb35\xd2\x03\xa3\xf3\xd2\x04'~&\x15\x88\xf2m\xa3\f/\x0e\b\xa1\xad\x1d\xf1\x05L\x19I\x90\xee\xca\x1aꩿ \n\xd8ԋ\x92\x0e\x9a\xaa?\xfa\x84\xf1\x8a\xee\xf84\xe2,\xd6\x1eI\x9c\xd9H0\xed\xbc\x02\xfa\x9e\x1d\x88\x1f\xa4\x1bkhTolB>i\xdbd͔\tX\x9df9\x1f\xb5\x02\xc0\xb2\xa0\xae\x80\xe1f\xaa\ad\b\x19\xeaky\xc4y`T\xd7z՟\a6\x8a\xb6 \xb4\xd3C\x93V6\x82jA\xac3XX\x88\xf14\xb2\x84\x04lK\xf5x\x1d騱\x99\xed_\x10\xb1(\xd5R\u007fTy\xac\x80\xb9\x1b&\xa3\xb3$H\x04\xec\xf0\x05\xb2\x1f\xac\x12\x87\x90\x18\x8f\xe8\xa8\x0f\u007fL\xf0~5\xdef\xe6\xa5ۄ\xf7×]H\x9f\x05\x1c\xa7z\x14\x91\xaa\x1c\xea\xb3\x0flO$`9\xd4u\x96W(k\x9b\xac\x99R\x01\v\xe4%\x88/\x0e\x00\xab\x14\x95\x05\xcc\xc5w;\xddN\x8b8\x13?\xe0q\x98=T\vܦ\xde\xc9\xde\x15\x98\x89?\xaa\xe9\xb1\xda<\x82N\x94\xa7\x9d\xb2\x9eJ\x13\x1eϝ\xd3\\jߕA\xaeg\x9cy\xbbw\xee=\xf2\tƧP\xa9\xa5\xbd\x02\x11\xc9\xf5d\xe7\\oۯ\x89\x15\xb0}(\x81\nL}\xd61ۧ\x9b\x9a\xad?\xfd=n\xe5.tޮ\xe2\xca\xeeL\xbc\xb5\xd7|917[kx\xf4\x9aH\xd7\xee\xfa\xfeo\xaf\x88\xbf-r\xa5]\x12\n\xf6\xfe$\xef\xfa\xdd\xe3\xc8Dg\xd7\x1f\x19ģG6\xd9<\xb8\x0e\x1d\xbc^\x97\x8f\xb4\r\x83\xd2\\)\x1a\xb4g\xb0\xa7 \x8bJ\xaa\xa4m\x91$\x9b\x89\u007f\xd9f\x13\xde\xf6\xcbh9\u007f0\x05\x00˃\xca\x02\x86==\x16S۠8\xbb\xc0C]`\xcd,\xd5ej\xf7$(\xb6L\fh\xa8WkS!u\x82\x05~\xb3=c\xfbׂ\x98\xf9\x8fg\xa5\x17\x0eal!G\x1b\x88\x8c\xe5ji\x8f\xa5k\xa76\xebS\xf6\xf8\xce[\x91\x93\xbe\xebA\xac\x80\x99\xb5|tV\x98`\x19\xc7\xf5\x15s\xc5}\x1cw\x1e\a;*\x8b\x0e\xd5߯\xd4\x19;\xa9\xd3\xeb)\xc9\xe4\xe8|ֱ\xd3e%\xc6\x11\xb1ę\x9f\x88^)\xd7\xc1\x9ĉ6:\xe3\x8b\\\xac#\x83\xbc\x1eÁ˹\x1am\xa9y\x9b\xa6P\x9a+%\xaf\xee`fv\xb9\x87&%m\x8b$\x8f\x88N=\xf6\xab\x03[\xfaI\f\x00)\x87\xda\x02\xb6\xaa\xf0n>束\xf7\r\x1d\xc8Z\x8a\xfb'\x81\x13\xff\x03Q\xad\xb1$3\xf9@\xb4h*\xe6\x93\xd9\x00\xc0\xeac]\vX{\x96\xd0\xe1\nhc\xe6\xd4/\x80\xe5\x170|9G>\x93l\xb9\xf0f\xc3b\x14@J\xb2\xae\x05l4\xcd\xc1\xb6\x8e\xb4\xc8L\xab\x85\xa3\x82\x80\x01\x00\x90q~\xef\xa6\x00\x00 \x00IDAT\x90u-`\x81\x8a\xf4c-\xbd-\xc7җ\xf2;fW\x17\xaa\x1eT\xfd\xb9)\x00\x00\x12ֵ\x80alݓ\xad\xc9\xdecMf\xa6ħ\b\xa1\x8d\xaedV\x00\x00,#\xeb\\\xc0\x00\x00He@\xc0\x00\x00HY@\xc0\x00\x00HY@\xc0\x00\x00HY@\xc0\x00\x00HY@\xc0\x00\x00HY@\xc0\x00\x00P$\x15f9\x82\x80\x01\x00\x10\x8b\xa7b\vڟ\xcch\xe5\x01\x01\x03B\f\u05fcNf\xb2\xec\xb4\x17x\x93\x99(\xb1\xc4b\x80\xb7 N$\x9d@^\x1eߣ\xfe\x02W\x8bFm\x01\xf3t5\x9b,\x03\xa1\xc5\x1f\x1c|x\x12|\xaf\xea˱~\b\xaeq\xe2\xe2]\xcbǣݜ1\x88\xfb9n\xf7\xa3x&S\xb5\x9f\x95\x18\x1f\x9d\x98\x88w|a\xdc\xe1Z\x83\xf8>\xc7q\xb7\xf1m\xf2z/\x81\xe9\v\x1d\xf7K\xb2\xf9\x92F\x83{\x11\xdf̾[\\#[\xff,\xbe\x91\x8c\x06$.C\xfb\xd7ke\xfa\xda`b\xe3\b\xe1b\xb1\xd0\x06q\x9f\xd5>\x8dw|\xa9|\xc5qt\x15\xdd\x0e\x8e\xfb*\xea\xc8ءa\xa5\x02\x1f\x8a\x0fܠ\x864\xe5\xdf\U0004fce5<W?*\v\xd84ou\xba\x9dm₆>\xd3@S\xf8\xc0P\xfcR\xcbH\xef\xfb-\xe3\xf7\xbd]'\tK\xfb\xe8\x89RR\x82rnb\x83\xb91Nodz\xfd\xdc\u061cB\x01\xca\x13\xdd\xd9\xfe\xbe\xf3\xef+\xa5\x9d,$\xd2\xdb\xfb\xdc\xed\xd7\xf8\xf5\x1d\xee\xfe\xdb\x04\xb6\xc1\x89/\x8b0m\xbd\xbd\x93K \x9bs\x13\x87j\xed\x84\xfb\xdc\b^\x10\xbfI3\x8b\xa9Ӈ:/\xea\x13]\x82\x94H\xb1Xh\x83\x1eݯ\x89\xaf\xfeK\xe4e\xf1\x9d\x1f\xc8\xe6\x87;\xc5/\xa3\x8e\f\x17\xf7\x8b\xa9\xa4\x1f\xf7R\xf8 \r\x92\\\x99u\xe3U%\x8b!$\x0f\xe8\xb0ZQY\xc0\\<\v\xca*\xae~o\xedq\x8b\x02汬\x90\x80\xed(Mf\x91\x84\"\x89\x80\xd5\\PJJP\xceMb0\xcb]\xfc\x92tz\xb8\xd9\xd8C\x02\xb5\xa7IW%\xf8\xe5\xfb\t\xd8\v]#\xdbNqc\xe4\xf5\x117\x95ؼ\xb5H\xd8>N$`\x18\x1f\xbdF_\x9f/P\xc0&5\xa7\xc4\xd4\x0f\\'\x0e\xc6mp\x14\x91bJ\xb0\x06\x05\x8d\x95\tL\x96\xc4\t\xa1\x8bz\xefD̑p\xc71\xe9ǽ(\xbc\x85\xc20\xf9C4Hzeg4J#š\x14\t\x13\xaa\xb2\x80a\xd6\xf5\xf2\xf2\x1e\xbaq\x98}\u009a\xf8\xb8\x97\xef5\xad\x8c\x80\x85\xe3\x0f-\x15\xa9\x80U]PJJP\xceMb0\xcb=*\x9eM$`G\x99\xf4Lq\xa1/\xfe%q\xc5 Կ\x1c\x026\u05f9\xb0\xbeTEvȷ\xf0\x82[\xc40,RL\t\xa1A\x9d\xf1\u07fe%r\xfe\x1b\xb6i<\x1f\xdf$\xe9ǽ(\x1cHX\xfc\xe9C4Hze\xbel\xa5\xc5X@\xc0\xe22\xe3\xb6X\xe9\x03Z\x9f\xc9%\x06\xf5\xc03\xbePp[U\xb1\x8a\x8b*\xe7\xd3\x1d۞\x9cMڽ[c\x8c\xcc[\xd82\xd1\xeeL\xd18S\xfe}U\xd4x\xb3R_\xfb=\x8dJ+P#K^\xe3t\x9d_\x19>;\xfbB\x96K\xbeA\xef\xd7\x14W\xded\xff\x83\xf6\xdaú\xb2\xda\xc3A\xb9A\x84Y\xeeEU\xbf(`\xe1b\xad\x1c\x1d2\n+Q\xd7\x1b\xa8\xda\x04Gd\x06\xcft\x1c\xf7͋\x8bG\xf5\xb5凞\xe0\xd7\xeaS6 \xe5抅\x0e\x98T\xc0\xde^0\xe8\x0e\x9f\xa5\xee+Ҋ{b3\xc9\xc0\xb1\xdePr\xe1\xcbh\x01S\xaeW\x100,:\v\x05י\xac2\xfc\xe2B\x99\ue410\xf6g~β\xe6ʄ\xf7\xe1\xe6⊝#\x1fN3n&\xafg\xb0\x04\xa1A\xf5\x06\x9aVz\xd7%\x9f\x101\xe8\xac\xd1Wu\x06\xa3\xce\x16\xb6\x95\xd6\xc0\xc2{b|\xa1Q\xd6\xe2\xb7zN\x1c\xcb+\u007f\xdc\xf2w]\x81\xf1\x8d\xe4\xfa]\xe5[\xd3\xf7ȖȽ\x9aku\"\xa75\xf7z\xdc\x06\xcd6\xfe\xb2\xd88a\x18\x91\xbeg\v\xfb?;\x93\x1e\x89\xdb\x17\xa6\x17\x04L\x19/\xcf\xf3f\xf6\x8di\xed\x0eE%\xa2\xac\x84\x80\xf9\x06l\xb9\x856\x9b\x8d\x0eh\x87Б[ݼ\x16Ŭ\xac\xbc\x1f\xed\xa1\x1b\xbf\xf9\xaa\x80\xd9/;\\\xc4U\xf6\r\x97\x91\xaf\xe1\xd9\t{\xa5\xd1n\xb7?\x97%\xa7\xfat\xdc\xe1۷\x0f매\xb9\xa4\xc3\xc3\xdd\x18\xe9<TE\ue267\xbb/\xf6\x8f\xdd+\xe3\xde\xc9\r\"\x10\x01\xeb\xac\x15\x05,\\\xecu}\x8d}\x96\x940ֿ\xc2/\x0fs\xb5\xb7\xff$x\xc8\xc2\x06s}}\x87+\x8b\r7\xebw\xbf\x9c\xb5\x97\xb4\xbeƯ[KH\tE\x03R\xee)g\x17\xce6ō\xcc\xcd͍P\x01\x1b\xe6\xbez\xd4w\x96{,\xb4\xe2P\xeb\x9d\x12\xda\xdbxQRy\u007f\xb8\x96\x8b\x160\xe5z\x8f^\x99\x9b\xeb0b\xd1Y(\xb8Τ\x95\xe1G\xc55w\xc6Z\x99?\x1c\x8f\xa2^\xa1\xae\xa7\xf6>\xae\xd5n\xff\xcb\xe2\x8ayK\vl>\xf2\x99~Z*[Ɩ4h\xf6y#w[v\x91\x92w]\xf2\ta|\xb1蛑o\x8a.\xca\xcf\x16\xb1\x95\xd6p\xaf\x06O\x18&p\xd5=y\x8b\x1f\xdb\xedz\xd6)W\xfe\xb8\xe5\xef\xba\x023\x96歹\x999\xd5\xe5\xf2\xa0Ȟr\x94\x87>A\xa5\xeex\rz{\xf4\xb3\x8e\x11\xa2]\x9d\xd2\xf7la\xffg\x031Z5?ݻcIˬ\xab\x8f\xea\x02\x86\xbd\x1e\a\x8bJ\xe4\xa42\xb6\xb2\x02\x86%C\xc8\xebZ*]_g\xc5Lޛ\xac\x13B\xa5MO\nD-\xf2\\t\xe8\xaf\xe4\xdf\xe4\x10K+\x0e!\x8b\x8e\x92\xf1\xd3\xdb\xc35\xb2\xdca\xe61\u007fL\xbf\xab;\x0f\xd1\x1b\xa3\xb3$\x18UC\x18\"`\xaf\xf4\xaf\x98\x80I\x8a\xddg_\xb0\xf8\x04\xcd\xf8\xe1\xf6\xbf踒>y\xbd\xa42\xee\xf4[\x1c\xa4\xa3\xb7+\xf5\xe4\xa5\xfeJ|\x03<\u0089\xff\xceS\xe2\xd73\xb9\x9dg\xfb\xc8)\x83'\x98b\x14\x95\x90\xbe\xc8E\xdaLc%ˍ\x12\xb08\xf5\x1e\xa5U\xb1\xbe\x820\xd6\x16F\x9e\x91\xca\xe6\x0e\xd7\x12\xe1\x9d\xeb\xa3\xfep\xd2!\x0e\a\xa5\x8b\f!\x17Q̜\xc76\x9f\x84\xff\xa7\x18B\x83.ҷ7λ\x1e\xf9\x84FX\xe7f\x8c\xb9\xec\"g\x93\xd8Jj\xb0\x97\xe1F]#\xfe\x8c\t\xbf\xe4\x9d\xc4X\x1f\xf2*(}\xdcQ\xb6J\xe4\xa3]>\xd1\xd9\"\xa1k\x13\xda\xc4V>Wn\xd0Ez\xb9\xf8\x06\x110\xe9{\xb6\xa0\xff37\xba\x85\xe5\xec'\xdd\xd8%-\x92\xa7>\xea\v\x18\xa6q!\xbb\xc9\x00\xd2\x19\b\x04\xdcM\x01Q1VZ\xc0\xdc\xd9[\xff\x99\u007f\x18\x90w\xaf$L\xa2\x10QCH\xfa\x14]\xf4\b)\v\x18\x1b\x9bur?Hs\xeb\x8fν#\x18\x88\xa6\xbc4\x1c\xbdq\xefip.\xba\x860D\xc0pm\a\x130I\xb1g\xdc\xdc\xec\xfd\xb7\xef\x8a\xc4\t\nsc\xb5\xf4\xb6\x93\x18\x90ʊB\xdf\xf2\x8f\xf4\xa4\xb7\xa6\u007f\x84\xe3\x1a\xe0~N\x9c\x0e1\xc5\xddy\xfc\xf8q\a\xf3\x81\xbd\xea\xac=Z\xc21/5핰f\xbe\x15\xe6W|\x13%`q\xea=z\xf6\xf1㋱\x02\x16\xaa\x8c(\x86d:@{2\x01KRl<\xcd\xef3\xfb\xe65\xe3X\nm\xd0p\r\x9b\xed\x11\xe7]\x8f|BW\x04\x8f\xfc\x89/\xb1\xf4l\x12[i\rܬ\xf1\xa2q\x96cM\x95\xbc\x93J\x02\x16\xef]W&_\xc1\xab\xee\xad\xd6\xe4\xa0l\xcdIo\x9c\x06\x05\x85\x93NE\t\u0602\xfe\xcf\xdc,V\xa8\x14w\x17\x9f\a=0%\xfc\x82\\\x8d\xf3\x81I>\x84\x87e\xad\xb4\x80a\x1f\u007f0\x0fm\x89\x1f\xdc\xc2f\x15\x88z\xba,\xb9\xc1\xe2\b\x18\xfbϲsO\xa4\xb9'\xc4~\xceY\x92~{\xefB%Wv'Q\x0f\f\xf7W1\x01\x93\x14\x9b\xd3Mup\xad\xcf9\xf2\x0f\xf9\x989j\x82Ƴ\xf2zqUؙ\xf6\xee\xb3~\xdc_\x16\xc4q\r\xf0Dh((\xf1\x81=>t\xb8\xb1\xdf~Z\x10\xb0P3\x1f\vc\xcdh'~\x9cz\xa9\x0flJx\\'U\xa2p\xb2\x83\x93\xcc\r\x19\x8c\fe\x94\x05,I1\xff\xc6\xf1\xcb\xe8_\x9di\xf2/!\xd6 Av\xe3\xbc\xeb\x91O\xc8\xc8.\x1f\xd7\xd6`ى#\xb6\x92\x1a\x82ES\xc5ϊ\xa7t\xc2\xe7&\xf5[\xc6\nX\xbcw]\x99\xfc\x1d\xb1y\rZމ\x9c\xbf\xd1\xd6\xc5i\xd0\xf7\xc2#\x9c\xd9(\x01[\xd0\xff\xd9\x10\x1a\x88>\x1d\xf9wG+sC.\x16u\x05,\xd0$\xb8+\x1e\x9a\x02\x01/\xc5a\xf6z\x05M[I\x01\xa3!u\x1f\xd0G\xf1\xbe\x96\xf4\xc5\x06\xea\x88\x11\xb0{/\xe5ɢ\x1bt\xff\x1e\xf7V\x9a[\u007f\xf4\t\xe3\x15\x91\x80F\xea\xc1\xe8\xd3wF\xd5\x10\x86\n\xd8l\xf1\x98\xd0\x03\v\x17Õ}\xa7\x8d\x95\xfdt i`g\xc0\x8d\x95r\x03\xe9\u007f\xe9\x8d\xf3\xf8<\xb3\x8ag0\x1bz\x9a*\x11\xb0\xca\x1a\xeav\xbb \x17\xb0\xbf\xb2[\x04_\x8c\xe9\x81)\xd6\x1bv\xe2\x8b5|\x13\xa5Dc\x9cd\x8a\xabO\x13\x9e\x8e\x1a%`\v,\x96\u05fc\xf3Ӽ\xf6<,ChP\t-\x1b\xe7]\x8f|BW\x8e2G\xfdQ\xda\xf9\x8a\x9cMb+\xfb\x00\xee\x18\xb0\xa1\xa3\x92\x9dD&\br\x01\x8b\xfa\xb8\x95\xbf\xa4d\xe4\x1fP\xc8\xf4\xb3\xa7\x90T\x9b\x15\x1b\x14\xd43\x9f\xd8\u007fD\x04\xec\x9b\"\x1c\xb7\xc5\xf2\xff\xb3:\x8dBg\v\x9eB*\xd2̦\xf7\xfa-=\xe2\xfe\x8a\xfb\xc0\n\v1\x9eF\x16\xf2)\n3\x8f\v\xe5\xc1a\t\xee\x86I\x9c\x00\xa9\x80\x19\x8d\x18\xbf\x16\x1c\x1d\x91dQ\x19\x91\x81٣FY\xee\x98`\xd5x\x9b>Od\x93\xa4\x8cעj\b\x9f\x98\n\x18\xbeXO\x05LR\f\xd7\xdfЍp\xd7\xe8?b\x99\x81\x0eO\x83\xf4\x9fRj \xbdS\xfe\xa4\xff\x8b\xfeO4\x11\xcf\x00_\xa8d_\xcdR\x01;|\x81U+\x170\\s\x98\x9c\xed\xb9>J\xc0\xe2\xd4+\x110=\x19\xa8\x05\xff%J\x89f\rFڗ\xba!Hp鶀h\x1c\x11\xb0\xc5\x14+\xfdgM\x17:\x165\xb3OhС\x1bS\xb7\xe3\xbd\xeb\x91Oh\x84\x19\xf4\t>\xb0\xf0\xd9$\xb6\xd2f\xd6\u0590o\x05c-;\x89\xb2\x80)}\xdcr\xdb\xc9:\x85\x89\xd4q\xa6\xf6\xb8\xb3\x84\x91\xa5r\x83.\x94\x11\x91\n^d\x02\x16y\xcf\x16\xf2\u007f\x16\xc8\xdb\x1bs.\x10\xb08\xb8\xf8n\xa7\xdbi\x11g\xe2\a<\x0e\xb3\x87\xceΛ\xf1x̽\x1eub \xca9\xa7\xb9Ծ+\xc3M\x05l\xf39k[E\xe8AX\x84}H\xe9\xf3\x15\xf9\x8b]\xf7\xe5D\xf0\xe9\x97:\xfaȌ\xfc\xbbw\xf4\x9f\x16ffG\x92E\\M\u07fdʒ\xe7\xf2\xdc\xc6\xdd\xf5\xfd\xdf^\xa1\xffB\xad\\q\xebp\xff\x15\xee\x91\xdc |\xe2\xb91\xae\u007f\x16?ҳ\xa7\x90\x91b\xf8\xb6\xbe$Xɾw\xcb8C\xebH\xffi\xfds\xa9\xc1\xbb?\xb1GM\xa2g+h\xa85\b\x02\x15\xc7\x00?\xe7\xeeЍt&~+w\xa1\xf3v\x15\x19uLH\x9b9\xa57\xdc\xfe\xe63Nw\u007f\n\xbf\xa43\xf1;\xec\xf6\x97q\xea\xa53\xf1'f\xc5\x13\x18\x0fݹ]C\x8b\xc9\u07b3G\xfa\x13\x9d#7\xc4\xdf-\xb9\xd2.\xb1\xad\xf0\x14r\"\xb8\xc8b\xb8!#3\x90\x9b^\x87eL\xb1\x1b\xf7t\xed\x97'\xe2\xbd\xeb\x92O\xa8\x9ek\x1cn\xe4\xea\xe5\x1f\xac\xd4V\xf2\x01\xdc\xd8}\a\xdf\xd9M4T\xfaN\xceM\xd8\xed\xfa/\xedv\xe6\xa3W\xf8\xb8\xa3\xde\xf5}hsT\xefg~\x90=\x19O\xf0\xa5\xa9ܠ\xbf\x18\x0ew\xf6\x9f\xd73\x01\v\xbfg\v\xfa?\xbb\x8c\x94~\x8d\xf2@i\\\xb9\nQY\xc0\xb0\xa7\xc7bj\x1b\x14\xbd\x14\x1e\xea\x02k&\x89\a\x827l\x05܆\xfe\xe3Y酴\xf3\xd7TX\x97\xb3)\xbb0F\xbf\xb0Y\xcb\xc7\x16\vq\x8d\xe38\xdd\u007f\x14\x93W\xfa\xc56w\xe33\xbd\xf11;\x10I\x16ݼRb\xb8\xf8\x97\xa8\\<v\xba\xac\xc4H\xff\x13\xef\x1bo\x1f\xd6\x19\x8c\x8f\xa2\rB'~\xb4\x9b\xce\xeb\t\xd6\b\x02\x14.\x86\x1f\x93Aĝbj\xfb/\xf7\x1a\u007fY|\xe8\xecsY\xbd\xcf\x04\xe7\x87\xd0A\xc0\xb8\xa3\xa8CL\xc51\xc0\xadzڗ\x12~\vIg\x99\xdd\xc3\xc1\x8eʢC\xf5\xf7+uFY3_\x9c\xfd\xech\xe3}\x1dI^\x14=,\x17\xe2\xd4\xcb~\v\xd9'\xd6\xff¨/\xae\xfd\x86\xd4 \u007fϞ_0\x14ׄ\xa6\xe0\x9e\xf9\t\xbdk\xe6JX\r\xba\xe7\x8b+F\xfe\x8d\xb2\xfe\x157l\x96w\xe5\xe9$8\"\xcdS\x95e\xb4O\xa7\xf8\xaeK>\xa1`\xe7\t\"\x8dA\xf9\a+\xfb\x84\"\x1f\xc0\x88\xfe\x19\x9e*\x1e\x96\xbf\x93Oŷ\x84I\xab\xc2\xc7\x1d\xf5\xae\x9b6G\xbb\x9a\xc6\xd3ؓ\xa2\xf8_\x9aq\x1a\x84_]9\xac?\xfd\x98\tX\xf8=\xc3qZ,\xbd2[\xfaI\xa5\xd3Lo<8>\x1d\xc0\xab\x1e\xb5\x05l\xfd!\x9d\xaa\xbf\x9a\t\xde\xd0\xf5ᕦZcIf\xa2\xc4\x12\x8b\x89\xac\xe4'Ԏ>跶\xe0\xc4_\f-\x9a\x8a\x98\xa9\x8f\x8c\xf6<\x04\xcb\xe9\x00+{{,\x8a`\x87\xe1U2\x9be\xe7rΒ\x1c\tK,&\xb0r\x9fP\xc0\x9c\x15\xe3s}/\x16-`\xde\xec\xf8\xcfݧ\xc7=q\x8f\xad\x1a@\xc0\x96\x9b\x95\xbb=\x80\x85\xb1r\x9f\x90G[\x1dw\xe2\xe1\x92X\xb4\x80\xa5< `\xcb\xcb\xf7\xcc\x19\x9c\xcc\nX9\xd6\xd2'\xf4b\x84\xbb\xf9\xa75Җ\x05\x02\x02\xb6\xbc0gp\x825\xff\x80\x95f-}B\xc65Ԗ\x05\x02\x02\x06\x00@\xca\x02\x02\x06\x00@\xca\x02\x02\x06\x00@\xca\x02\x02\x06\x00@\xca\x02\x02\x06\x00@\xca\x02\x02\x06\x00@\xca\x02\x02\x96j\x04\x02\xf3\x01\xfa\x97\xcc\x0e\x00\xd6\x01 `)\x86kG^\xde\xdeO\xf2\xf2\xaa?\xe8o\xe8\x00 5\x01\x01K-\xe65hg\xe1G\x19;wl\xf8W\x85P2\x00\xb0\xceP[\xc0<]\xcd&\xcb@\xa8\xf7\xe0\xe0\x85\xd0\x01>\x9b\xc5\xd4>\xae\xfc\xab\xf8\xb5\xc8\xd2\xc3\xc3\xfb>\xae\xfb\xdbߜ\xff\xdf\xdf\xfe\xef\xc7\xfb\xbc\xc9l\x01`ͣ\xb2\x80M\xf3V\xa7\xdb\xd9&.h\xe83\r\xb0\x15Y}\xe6v\x87\xfb\x81\xb9}\xcd+X(\xa2\xfbR\xc2ÿe\vV\xcd|\xb2aÆ@\xe9\x86\r\x1f\xd5IƐ\xbdJK\xd2\x01\xc0\xdaGe\x01s\xf1tY\\\x1f\xefd{\xd6\x1e7\x13\xb0\x1e\vuI{M\x0f\xe2\x17\\\x1b\x84#\xba/:<|\xf0^\xc9i\xba\rx\xaa\xf3\x89\x80\xfdh\u007f\x83K\xb2\x8e\xc1\x8e\xa8e\x94\x01`\x9d\xa0\xb2\x80\t\xd1\xee\xbcB$\"\x87\xd9'\xac\x89\xdf&,Gכ\"\xa1\xe8\x96N\x95L\xc0\x16\x11\x1e~\xaa\x86;+\x84\xa4\x0e\xf8x\"`\x1bG\xbd\xd2uX⬢\x0e\x00k\x1d\xb5\x05\x8c0\xe3\xb6Xi\x8f\xcbgr\x89A=<B\xb4\x82\x81[\tJ\xa5\x16\xaf.\x96\x19n\xde,+\xee\x93D\xab\x97FtO\x16\x1e^\xce\xecM\xce0\x1c\u07b3P\x01sE\x86\xdbV1^e\xbe,.\xfd1\x94ք'5(\x8f\xd94\x15d\xe4\xc2sK`\xed\xa1\xba\x80yy\x9e7\xb3[\xc9\xda-\x8dJD\xfa\x16\xcdQ!\x17S\x97\xb9\x13\x86\xceV\xbd\xfe^m\x87$Z\xbd4\xa2{\xb2\xf0\xf0R\x82\xfd\x06]\xa3\xd0U\x9b{A\xf8:J\xc0|\x03,\f\x84\xcd)\x8bK\xef\xb1m\xaa\xc3x\xf0\x88\x86\x9aT\xa4\x1d\xb7^\xd5\xe6\xc3\xdc1`\xad\xa1\xba\x80a\xaf\xc7\xc1\xa2\x129\xa9\x8cI\x05l\xc0\xbcf\x9e\xab\xf5Ѹ\x85\x9d,\xba\xb54Z\xbdt\bII\x14\x1e>\xc25\xaejJL\xd2\xf5\x9e\xb8\xff\x1c%`X6\x84\x8cĥ\xd7\xd0\xf0<u\x1aL\xfbhfL\x03eE\a`\x06\x80TG}\x01\xc34.d7\x19@:\x03\x81\x80\xbb)\x10\xea\x16\f\xf2\xb1\x01\xd5S\x95\xc6\x12L\x03\x95}K^\xa5\xd1\xea\xa5\x02\x96,<|\x84\xfbE\x9f\xdd\x17W\xd9|>L\xf8_\x89\x05,\x1c\x97>\"`\xa5\xdb\xfc\xf3\x84\x9c\n\f\x00k\v\x95\x05\xcc/\xc8\xd58\x1f\x98\xe4Cxh\xce|\xaf\xf8drMб\xfb\x15\xed{ю\x934Z}\x94\x13?axx\t/j\xb9\x9a\xa9\xc8n\xb4\x0f\f\xcb\x05,\x1c\x97>\"`\xdbE/Y\n\x04\x99\x01\x80E\xa1\xae\x80\x05\x9a\x84\xb8\x8b\x0fM\x81\x80\x97\xe20{\xbd̡om\xf2$,\x99Z\xbc\xe4j_>\xab4\xd2~\x934Z}$\xa2{\xf2\xf0\xf0R$^0\x1c_\xc0L\xac\xeb\x15\x89K\xcf\x04쌆\xbc\x94o\x1be\xac\x99!:\x00\x88\xa8+`\xb8\xb9\x8b\xbe\xfa-=\xe2\xbe\xe8\x03\xf3\xb6\xb4\xf9\x88\xbc\xad\x99\x1f\xc7<\xe1\xca8\xee4\x9b\xf7 \x8dV\x1f\x89\xe8\x9e<<\xbc\x1c\xfa\x1crLL+\bXa!\xc6ӈMF\x89t\xc62>'o\xe9\x0e\rIu\t\x87\xbe\x88\x8aY\r\x00)\x8f\xca\x02\xe6⻝n\xa7E\x9c\x89\x1f\xf08\xcc\x1e\xd2-p\x9bZ\xdc\x1e\x8fg\xe0}\xa2\x93\xae*\x9e\xe9\xc7F\xec\xdf\v\x8e\xabp\xb4z,\x89\xe8\x9e<<|4S\xc6\xd0\xf0SA\xc0\xcei.\xb5\xef\xcap\xcb\xe3\xd2\u007f\xaam\xa8+@\x1b\xcddh~\n\x95Z\xda+\x90\xe4\x89\t\x00\xac\tT\x160\xec鱘\xda\x06\xc5I\x98\x1e\xea\x02k\xc6\xf8\xae\xe8\r[3\x13Y'tԫ\xa53R\xcfU8Z=\x8eDt_@x\xf8\xf8(\b\x98\xffxVz\xe1PT\\zWaz\xe6\x9e/\x10\xa2\xa1S\xbbvj\xb3>\xbd\xabT\x1b\x00\xa42j\vغ\xe0u\xf1\xb5\xd7\xef\u07bd}z\xfe\xb3\xb7\xc9L\x15H\x16\x9cTA\xc0\x00`\x9d\x02\x02\xb6\f\xf4\x97\b\x1d\xae`Y\xf4\x9c\xfa\x85\x00\x02\x06\x00\v\x05\x04l\x19x\xc2\t\xb3\x1e\xa6\xb8%,\x98\x13-`\\\x14\xff\xf9?\xd1\xd5(>\x1f\xf8\xb01\xe9\x01 %\x01\x01[\x06\x82W\xf4\xd7\xfa\x1e\xf5]\xd3\u007f\xb5\x840\xef\xd1\xe1\xe1\xa3\xf4\xeb?\x85\x96\xd3i\x03\x05\x03\x00\x10\xb0\xe5 8\\k\xd0\x19j\x87\x97\xa0_I\xc2\xc3\xcf\xd0\x05\r\xff\u07ff\xfd\xed\xff~\xbc\x1f~\x9b\r\x00 `\xa9\x85\x0f\xa1\x9d;?\u07b2sdž\n\x98\x96\n\x00 `\xa9ż-'++7++k\xd7К\x99\xf6\v\x00K\x06\x04,\xc5\xf0{&]\x93\x93.\x97\x1bF\x90\x00\x00\x02\x96r@\\H\x00\b\x03\x02\x06\x00@\xca\x02\x02\x06\x00@\xca\x02\x02\x96\xfalXq\x92]!\x00,\x13 `\xa9φ7+\f\b\x18\xb0R\x80\x80\xa5> `\xc0\xbaEm\x01\xf3t5\x9b,\x03\xa1)\x00\x0eq\x05\x1dy.\xb08@\xc0\x80u\x8b\xca\x026\xcd[\x9dng\x9b\xb8\xa0\xa1\xcf4\xd0\x14\x9b\v(\xf2\xf6/\U0004e000\x01\xeb\x16\x95\x05\xcc\xc5B\x0f\xf9\xc4\x00\x1e\xd6\x1ewSl.\xa0@\xf0^\xc9\xe9x\xc7$\x02\xb6`-[\xb0\xe1\x9b\x05\u0602\x80\x01+\x85\xca\x02\xc6\x02\x16b\xaf\x10\x89\xc8a\xf6\x89k\xe2Ks\x01\x05\xa6j\xb8\xb3\xdf\xc7;\b\x02\x06\xac[\xd4\x160\u008c\xdbbe\x91\x88L.I`\xdbP\xee\x1a`~˦/r\xb2{\x8fg\x15Ra\xb6\xed\xc9٤ݻ\x95\x1e\xf0\x96ksN\x9e\xd4n\x8e^\xfb\u07fc\x85\xa7\x1bw\xa6\x18\xfe,3*B&\r\xe91,\xcfz\xa6\xe3\xb8o^\\<\xaa\xaf}\a\x02\x06\xac_T\x170/\xcf\xf3f\xd6\xe3\xb2vG\"sGr\xd7\x02\xbd\x99\xa8z\x17\xd26l\xb9L\xe3a\x1f\xb9\xd5\xcdk\xd1<\xc6\xfe\xbc\xec\xaf\xcfi\xd2M\xbf\xb8\x1ce\xbf\x1f\xed\xa1\x1b\xbf\xf9\xaa\x80Y\xb6ԗ$\xa8\xda\xdc\v\x819<\xd7\xd7w\xb8\xb2\xd8p\xb3~\xf7K*`\u007f\xf8\xf9\xc7\x1f\xfd\xf4\u007f\x13)\xf9\xdf?\xfd\xe8\xe3\u007f\xfc3\x11\x95_\xffxÏ\u007fM\x0e|L\xd2\xffH\xfe>\xfe\xa3 6\xbf\xfd\xe9G?\xfa7\x89!)\xf9\xf1\xcf\xff,ɈT\xf1ۿ\xfb\xe8\xc7\xff\xf4&\"`b\x95o6\xd0\x04\xa9#rV\f\x00+\x83\xea\x02\x86\xbd\x1e\a\x8bJ䤂\x15\ue045r\xd7\x06\xd9\xe5؊\xac\xf8H\x05\xc6\u05f5t\xf1篳H\xef\xb2\x05\x8d\x93\x14rĘO\xd6\tq\x84\xa6'\x05\xa6eG\xafqU\xa1\xb0\xb6FqUC#ݩ\xe2N\xbf\xc5\xc1\xb7l\b\xf9\xd3_\xfd\xf9\xbb\u007f\xff9\x91\x92\xbf\xfb\xddw\u007f\xfcG\"X\xff\xe7G\xbf\xfb\xf3\xef~\xf4\xdb7o~\xfc\xfb7\u007f\xd8\xf0\xc77\xff\xfecQ\xbf>\xfe\xedw\u007f\xf8G\x89!\xd9\xfe\xf9\u007f\xfc7IF8\xf1\xef\u007f\xf7\xef\xdf\xfd\xe1\xbf\xfcSX\xc0\xc2Un\xf8\xd1\xef\xbec\x89\xf0Y1\x00\xac\f\xea\v\x18\xa6q!\xbb\xc9\x00\xd2\x19\b\x04\xdcM\x81\x804w\x8d\x90݂\a\x91\x0f\u007f^Jƅ\xd9[\xff\x99\u007f\x18\xa0}\xaaSY\xe4Ņ\xda㕚D!dC\xc8\xfbE\x9f\xdd\x17WF|>,\xf0\x9c\xeeT\x15\xbd\x14r\x89\xc0|$\xf6\xaf6\xfc\x9e\xbc\xfc\x99\xf4\xba\xfe\xfe\xffP\xc9\xf9\xfb7o\xfeǯ\xde\xfcjÿ\xbd\xf9\xa7\xffG0`\xf9RCʟ\u007f$\xc9\b'\xfe\x81&\xfe\xf8㰀\x85\xab\xdc\xf0[\x9a\xf8\x99\xe4\xac\x18\x00V\x06\x95\x05\xcc/\xc8\xd58\x1f\x98\xe4Cx$\xb9\x89ʦ\x10\xd9]xHC\x14\x8b\b\x18\xf6\xf1\a\xf3Ж\x06\x92\xba\x8c\xbc4\xc8ll\x0f,\x84\xcd*`\x93g\xbf\xa8\xe5j\xa6p\fU5b\x82\b\xcc\xff\xfc\xf8\xbf\xff\x1bU\x13Ak\xc8\xeb\xc7\u007f\x16e\xe8\xb7\xff\xf5\xcd\xcf\xfe\xdb\xcf\xdf\xfc\xfdo\x05\xad\xf9\xe8\xcfoB&\xc2\xeb\x1f\u007f\xfe\xf1\x86\r\x1fI2\"U|\xf4\x11\xfd\x99PX\xc0\xc2Un\b%\xc2g\x8d\xbd8\x00P\x05u\x05,\xd0\xd4˶\x0fM\x81\x80\x97\xe20{\xbd\x01In\xa2\xc2)\x84D\xc0\x1e\x9c\"\xfb\xbe\x96\xf4\xeb\xa43\x96\xb6\xd7=\x9e[\xb0\xf8FJ\xbc`\x12\xaaB\x91n\xa9\xc0\xfc\xfeW?\xff\xf8WJ\x02\xf6\xdd\xc7\u007f\xfc\xe8\x8f\xe4\xef;\x89\nI\x05\xecg\xff\xf3\x8fo\xbe\x93\xeaV8\x11\xea_\xc5\x17\xb0\xf0Y\xa3/\r\x00TB]\x01\xc3\xcd]\xf4\xd5o\xe9\x11\xf7\x05\x1fXtn\xca#\x11\xb0:\xc4\x1aWx\f\xe3Q\xb4\x05\xa1\x9d\x9eXsw\xc3dl\xa6\f\xfa\x1cr,*O&`o\x04\u007f}X}X\x8f\x8b\x8e\xf7\xde\xfc\xc3\u007f\xff\a\xf6'\xf0\xb3\xd0\x102\xf4J\x95\xed\xdf\x15\x05\xec\xef\u007f\xfdFj\x1b\xa92<\x84\xa4\xb0\xb3F_.\x00\xa8\x84\xca\x02\xe6⻝ng\xc8]\x1f\xf08\xcc\x1eotn\xea\xe3̺\xeck\xd94\xee+\xdd\xe9&\x02\xb6\xf9\x9c\xb5\xad\x02\x91N樦\xc7j\xf3(t\xc0\xf6\x89\xb1\xb4\x131e\xbc\x80%\xbc\xfb\x93\xbd\xd2h\xb7\xb3\xe0\x1fD`\xfe\xcb\xef\xbe\xfb\xee\xd7?\x95\xa8\xcf\xff\t9\xda\xdf\xfcjï؟\x00\xc9\x13\x9c\xf8!ß\xfe\xea\xbb\xdf\xffXQ\xc0~\xf7\xf1\xbf\xfd\xf9\xbb\xdf\xfdװ\x80\x85\xab\f;\xf1\xc3gU\xbed\x00XvT\x160\xec鱘\xda\x06\xc5i\x02\x1e\xea\x02k\x8e\xceMy\x02\xa4\xa3՜\x892,\b\xed\xc7M\x85u9\x9b\xb2\v\xe9 y@C\x1d\xf4\x9b\nc\x9c`f-\xafPMB\x9e\t\x8f#ki\x9a\b\xcco\u007f\xf6\xd1\xc7?\xff\x83D}\xde\xfc\xfa\xc7\x1f\xb19\x0fo~\xbf\xe1\x0fo\xfe\xc0<\xf3\x82\f\xfd\xddGt\nD\xd8\xf0\xf7?\xfd\xe8G\xbfV\x14\xb07\xbf\xfb\xd9G\x1f\xfd\xecwa\x01\vW\xb9\x81&\xe84\x8a\xf0Y\x93]-\x00,\x13j\v\xd8:ƻ\xf9\x98w~\xde7t \xeb\x03\xf74C\x02\xa3\x161\xe7\x03\x01\x03V\n\x100\xd5h\xcf\x12F\x8f\x01\xed\xdd$\x96\x8b\x04\x04\fX\xb7\x80\x80\xa9\xc6h\x9a0vt\xa4=Lb\xb9H@\xc0\x80u\v\b\x98j\x04*ҏ\xb5\xf4\xb6\x1cK\xafHf\xb9H\xd4\x16\xb0\x18@\xc0\x80\x95\x02\x04LE\xac{\xb25\xd9{\xac\xc9\xcc\x16\v\b\x18\xb0n\x01\x01K}\x92\x85\xdcX~\x92]!\x00,\x13 `\x00\x00\xa4, `\x00\x00\xa4, `\x00\x00\xa4, `\x00\x00\xa4, `\x00\x00\xa4, `@\"\xfc333\xf3\x18ϓ\xcdZ\xf9\xa9*\xb0\x96\x00\x01\x03\x120\x90\x86\x10J\xf7\xf9\xd2\xc9&-j\x9dE\x00Xy@\xc0\x00\x05\x86k^\xb3\xad\x05Y\x87\x86\x1c\x18;\x86\x86\xac(:\x98\xd2Bi/\xf0&3!x\v\xda\x15\x92\x00\x90\x10\xb5\x05\xcc\xd3\xd5l\xb2\f\x84\x96cp\xf0\xe1i\xe9\x92$\xf0\x01\xf8\x8a\xe3:Ȧ\x83㾊:2v(*D[,w\xb8Va\x15~Kdy~\xb7 `\xc7P\xda\"\x85\xac\x01\x9dKf\xc2hHkPH\x02@\"T\x16\xb0i\xde\xeat;\xdbĥ\v}\xa6\x81PT\"I\x12\xf8\x10\xbc,\xbe\xf3\x03\xd9\xfcp\xa7\xf8eԑ\xe1\xe2~1\xf5\xe8\tV\xa4\x93\xbb/\xa6b\x05\xccc\xdbT\xa7X\xa8wT1\x1b\xff&ͬ| \x06\xebƫ\nI\x00H\x80\xca\x02\xe6\xe2\xe9\r\xe1\xe3\x9dl\xcf\xda\xe3\x0e\xa9\x96$\t|\x10N\xdcc\x9b{'b\x8e\x04C\x89\x1a\xd9\"\xafa^\xe8\x1aC\xc9X\x01\xc3X\xa3,`;J\x15\xb3'5\xa7\x14\xf3\x958\xa3q+$\x01 >*\v\x18f]//\xef\xa1\x1b\x87\xd9\x17\x8a\v)I\x02\x1f\x86\xf3߰M\xe3\xf9\xf8&U\xca\x02v\xc5\x10\x0e \xb2\b\x01\xcb?\xa8\x98]\x91\xbd\xf0\xe5\x1b}\xd9\x15\nI\x00\x88\x8f\xda\x02F\x98q[\xacti?\x9f\xc9\x15\nl+I\xae\x17\x9a\n2r\xabɽ=\xbe\x11\xa13\xae\xf2\xad\xe9{\xe6%\xc9(c\xf3\x16\xb6\xe6\xb4;S\x8c\x1b\x99)ힴr\x1cׇ\xfb\xc8k\xab\xb4Lc=\xdb\\h\xc4\xcft\x1c\xf7͋\x8bG\xf5\xb5\xef\xf0[=\xb3&\f\x8bArYp\xb6\xe0\xfd\x9a\xe2ʛb\xf8\xef\xe2p\aLY\xc0\x8eWdg\xeds\x91^3\xb9\x92/p\x1dy\xb5X\xc5\v\xcbg\x16\xa1\xb6\x11\xfc\x99\x9f\xd3ͻ2]\xa3\xc1\xf0\xe8F\x89\x91\x9e\xc3^{XWV{\x98\xf6\x04_],3ܼYV\xcc.\t\x9fI\x9f\t\x9dN\x92\x04\x80\xb8\xa8.`^\x9e\xe7\xcd\xec\x9f\xdb\xda\x1d\x8e\xcc-I\xae\x13*Ҏ[\xafj\xf3\x03x\xc6Ҽ573\xa7\xba\x1c\xb9%\xc9(\xeb\xfdh\x0f\xdd\xf8\xcdW\x05\xcc\xd29Y\xaf\xebk\xec\xb3xv\xc2X\xffJZ\xe6^\r\x9e0L\xe0\xaa{x\xae\xaf\xefpe\xb1\xe1f\xfd\xee\x97\x18?\xb6\xdb\xf5L\xe8f'XX\x10;\v\x92{\x85\xbb1\xd2y\xa8\x8a\r.\x9fr\xf6p%\x8a\x02\x86\xf2[Z\xb6g8\xb0o \xe7\xd84\xf6\x9e˴\xf9|\x03\xb6\xdcB\x9b\xcd\xc6\\\x03\xe1\xb6a\x1a\x89I\b\x99\xf7\xa8\x84\xbby\x9a+\xbb]\xd6AN\xb0\xfbb\xffؽ2\xee\x1d\x11\xcb\x13\x86\xceV\xbd\xfe^m\a\xb3\x1a@\x83\xa1\xd3I\x92\x00\x10\x17\xd5\x05\f{=\x0e\x16\u007f\xc8IeLP-Ir\x9d`EԳ=\x84Z\xe8N>\xda\xe5\x13\aג\xa4\x94\xc9:!\xee\xda\xf4\xa4\xc0\xb4\xec\xe8\xfd_\xb2͉\x90\xe7]\xc0^\x86\x1bu\x8d\xf83\xa6FU\xdc\xe9\xb78\xf8V8\xa2\x0f\xf5\xd4\xc2C\xc8a\xe6\xb5\u007f,t\xcdF\xb8\xe7\xe1J\x14\x05,\x8f\xf4\x8dfr\vH\xb2\x8e\xf6\xb8\x8e\b\x83\xbd\xf0\x10R\xd66+\x12#\xc6\x19.\x92\x8a\x87\xf1ů0\xee<D\xa4\vw\x96\x10\xb9\xec\xe3\x9e\xd1g\x06\xa1\xb0\xbdnt\v\xc7&\x01 .\xea\v\x18\xa6\x11 \xbbɨ\xd1\x19\b\x04\xdcM\x81\x804\xb9^(\xdd\xe6\x9f'\xe4\xb0{??\xe2\xb0\xceO軞D!dVϸ\xb9\xd9\xfbo\xdf\x15=\x93\x19\xbf\xe4f\x8d\x17\x8d\xb3\x1c{\bYU$y\x16\x19+`\xf5G\xe7\xde\x11\fW\xe8N?\xf7\"l\xaa(`_\xd0\xd7\xeb4̸\x1b9\xc8 Q\b\xe7\x19\x160Y\xdb\xda\xc3\x02\xd6G\x04r\x96\rl_\x1a\x8e\u07b8\xf748Gr\x1bK\xc8\xcbs\xee\xdb\xf09Zpl\x12\x00⢲\x80\xf9\x05\x8d\x1a\xe7\x03\x93|\b\x8f$\x99\xb8\xf4\xdaa\xbb(D\xfb\xe9N\xfe\x8ep\xbe$\xa9\x84\xcd* \x9f\x13?\xa7\x9b\xea\xe0Z\x9fss\xb2\xdc`\xd1T\xf1\xb3\xe2)\x1d\x1b\x16V\xd5H\x8e\xc4\n\xd8\t\xd1\x1fv\x96\xeeLp\x13a\xd3\xf8N|\x1b\xa2\xd3&\xf6\x9e\xc4]Y\xc2x6,`\xb2\xb6\r\x86F\x82\x86\x11\xfcX'z\xe6\xde\u07bbPɕ\xdd!Wֱ\xfb\x15\xed\xf2\x85z`Ch\x00\xc7&\x01 .\xea\nX\xa0I\xf0\x88<4\x05\x02^\x8a\xc3\xec\xf5J\x93Iʯ\x19ʷ\x8d2\xd8\x14\xf5\xfc\x03\xe1|Ir\x11T\xf6\x9d6V\xf6\xff2:\xf7\x8e\x01\x1b:*YZ\xf6\xbcQ.`\xf7^\xd2\x1e\xd8\x13\x06s\xa2\xcd\x16E\x1e\x06(\nX5}5!:еj\xfd\xe2\bR\x100\x93;\xaam>\x8d8\x8b\xd50\x86\x1f\x17\t\x02\xf6\xb8\x91H\xd7\xdb>}'\xed&־|Vi\fM\xec\xa8ӄGϒ$\x00\xc4E]\x01\xc3\xcd]\xf4\xd5o\xe9\x11\xf7%\x8e\xaf\xb5\xeb\x03\x9b\xac\x8b\x99\xe3\xd9%\xa8\xc1\x17\xac3#\x99\x80\x10g.\x82\xbbaR1_\xa4\xfe\x86n\x84\xbbv!ʶ\xb6\xe6<>od\xa1o\xe3\b\x98ш\xf1k\xea\xf8\x1a\x13\xbc_\x8d\xb7Y\xf6\x85\xca\xf0L1E\x01\xcb!].\u007f^!M\xfb\xb5\xd6,\xf1\xb3,$\x19\xd3\xd4F\xd662\xa0\x14\xbe\x95$\x02\xd6ʍ\xd0\x1c\xe35\x8c\x9fpe\x1cw\xfa{\xf1\x14\x81\xbcp\x84rI\x12\x00⣲\x80\xb9\xf8n\xa7\xdbi\x11g\xe2\a<\x0e\xb3\xc7\x1b\x9d\\s\xecC\x9bcz\x13\xa7P\xa9\xa5\xbd\x025\xe1\xf9A\xf6\xfc\x8e\x8a\x8e$\x19SC\xc2\xdb\xf9\xb6\xbe$X\xa9\xbf\x1de{c\xf7\x1d|g\xf7\r\x8c\xdf\xfd\x89=od\x9e\xad\xb9\t\xbb]\xff\xa5\xdd\xce\xfc\xf9\xadE\x1d\xfd\xa7\xd9L\xfd\xc6\xdd\xf5\xfd\xdf^\x11d\f?\xe7\xee\x84jV~\n\xb9g\xb0\xa7 K\xb8\xccS۲\xc49\x1f\xe74\x97\xdaweP\xf3p\xdb(\xae\xb4Kt3\xf5Y\xc7l\x9fnj\xb6\x9e\xa8U+W\xdc:\xdc\u007f\x85{\x84\xf13\xfd؈\xfd\xfb\x90^^Fa\xa5\x97$\x01 >*\v\x18\xf6\xf4XLm\x83\xe2,\x00\x0f\xf5{5G'\xd7\x1c\xa6\xcdh(&\xb3k\xa76\xebӻ\x18\x8f\xa71\x87\x11\x15\x1dI2\n\xb3\x96\x8f͌\xf0\xb8\xa4\x15\xdf)~\x1ce;\xa2\u007f\x86\xa7\x8a\x87\xa9\x93\x9f\xc1\xfabOEo\x17\x9b\xa6?w\xe33\xbdQ(6v\xba\xac\xc48\"\xd6ת\x0fy\xc1,\xc8\x15ZN\xc7\x15\x12\xb0\xbc\xba\x83\x99\xd9\xe5\x1eaDžB\x13N\xfddz\xd2\v\x85v\x86\xda\xc68\xf3\x93\x01\x8c\x83\xa4\xa3\xd5W\xcc\x15\xf7q\xdcy|\xdfx\xfb\xb0\xce`$\xfa\x85't\xf4btF\xe6\x04\xb3\xa5\x9f\x14\xcbH\x93\x00\x90\x00\xb5\x05l]ҎR˟\x13\xbc\xa1\x13\xfabl\xaejh9\x1d\xa4\x14Pܧ\xe9UȕQ\xad\xb1\xc4;\xf4\xba\xf8\xda\xebw\xef\xde>=\xff\x19\xe9\x11\xb6h*B\x13x%I\x00H\x04\b\xd8r0#\xce\xd7b\x93\xc9\x03\xe6\xacc\xc9\n\xac2\x82\x1d\x06aR\xec\xfc\xf8Ph9\x9d\xa1q%M\xb1h\x93+\xcd\xe5\x1c\xf9\xbc\xb5\b\xfd%\xc2\xe81X6\x82\xbd\xd9\xe1\x15($I\x00H\b\b\xd8rP(\xce$`\x8en\x8f\xb6z\x8d.fZ\u05cbw-l\xa9\x9c\x89'\xb4\x8b\x00\x00 \x00IDAT8<\x11'PLqO\x93X\x02\x80\" `ˁK\x9c\xaf\xe5Jf\x98\xd2\xf8P\xfe\xb1E\xfcT[\x81\xe0\x15\xfd\xb5\xbeG}\xd7\xf4_\x051\x00,\x01\x100`ɜۼә\xcc&1\xc1\xe1Z\x83\xceP;\f\xfa\x05,\r\x100\x00\x00R\x16\x100\x00\x00R\x16\x100\x00\x00R\x16\x100\x00\x00R\x16\x100\x00\x00R\x16\x100\x00\x00R\x16\x10\xb0uɺY\xb7\bX\u3000\xad?<\x15[\x84\xd5\x06\x01 \xd5\x01\x01[w\x04\xf2\xf2\xf8\x9eD+W\x03@ʠ\xb6\x80y\xba\x9aM\x96\x81\xd0\xefO\x1c\xbc\x95nf\xcclAi\xf3Z\xfa\xc9`\xb7\xd6\x1aJz\x8fmI\xdf\xfb^\x836k\x96\x15/\x94Љ\x8f \x842\x94~\xcb4\x8e\xba\x14r\x01 \x15QY\xc0\xa6y\xab\xd3\xedl\x13\x174\xf4\x99\x06تw>\xfe\xa1\x87\xb0\xa6\xd63\xb4f\xdc\n%wm\xb9~$\xfd\xbd~3\xf89\xfa<\x99I\x98Љ\xdd6\xdb\u05ca\xa1Ɇ\x90|I}\x00H]T\x160\x17O\xc7.>^\xf8\t\x9d\xb5\xc7-\n\xd8\x1a\x1cф\xbb\\^t\x15\a\xdeK\xbf\xf0\x19t&\x99I\x84H_o(\x8e\x80A\xc4E`\xad\xa0\xb2\x80\t!\x0f\xbdB\xf8!\x87\xd9\xe7Y\xbb\x02\x16ƅ\x16>\xfe\x8bC\x1d\xaaKf\xa2\x04\b\x18\xb0\xd6Q[\xc0\b3n\x8b\x95\xf6\x12|&\x17^\xa3\x02FW0Mc\vd\xfb\xb5\xc2\xca`\xd5Q\x16\xc1\xfb5ŕ7g1~\xa6\xe3\xb8o^\\<\xaa\xaf}'IFY7 \xb6\u009f;S\\g,S\xfa~\x1dC\x9b\xf8\xea܌=\xaco\x1b>1EY\xaazA\xc0\x805\x83\xea\x02\xe6\xa5\xdez\xd6\x0f\xb3v㰀u\xdf\xe2\x9bm3\x89K\xa6\x12\x0fl6!|\"~hkAu6\x9b'\xca\xe0\nwc\xa4\xf3PU\x10\xcf\xf5\xf5\x1d\xae,6ܬ\xdf\xfdR\x92\x8c\xb2\xbe\x8a.Ӎ\xdf|U@\xf6\xb8\xc3ټ\x11i\xeb.e\xb2\x88l\x91\x13cE\x01\x9b\x9f\xeeݑ\xf5~\xe3Y\x00X=\xa8.`\xd8\xebq\xb0\xa8DN*c!\x01k\x1aw;--k\xe9)$N\x0f\xe9\x88\xd2\x10r\x98\xbbO^\x1f\va\x80\xaa\xb8\xd3oq\xf0mTR\n\x8f\x84@\x1d\xd3\xe2R\xd5QK4k\xb2h8F\xad\xb8\x97\x9eH\xc0\xf6\x93\xfe\xdb{\x8fh\x01`\xb5\xa0\xbe\x80a\x1a\x17\xb2\x9b\f \x9d\x81@\xc0\xdd\x14 \xa3ɀ\x83v\xbef\xcckjh\x93P\xc0\xea\x8fν#\x18\xaeН\xaa\xa2p\x8fK\x92\x94bFf\xba\x99D!\xe4Cn\xcd\x11LÚ\x89{\t\x05\xcc\xdd\xc5\xe7A\x0f\fX3\xa8,`~\xe1\x11\xd98\x1f\x98\xe4CxB\amm\xf1\x8a\xa5\"\t\x05\xec\x84\x18\xdd\xec,ݩ\xaa\t\xe7K\x92R\x06\xb2\x04%\xb2\x89KUG̓`ѯ\xeb4\xe2^B\x01#\xd8\x14\x82\xbc\x01@j\xa2\xae\x80\x05\x9a\x84 \\\x0fM\x81\x80\x97\xe20{\xbd\x01\xdc#\xdc\xe1\xbdkjl\x93\xa4\a\xf6\x84\xc1b\xffH\xc2f\xcb\"h/\x18\xe6\xf5Z\xb0\x80\xc1SH`\xed\xa0\xae\x80\xe1f6\t\xdco\x11\xc3ы>0+\xebzy\xcd\x0f\xe3\x94JI\x12\nؘ\xe0\xfdjdѴ\x17 `\x89\xe7\xf1\x83\x80\x01\xeb\x15\x95\x05\xcc\xc5w;\xddN\x8b8\x13?\xe0q\x98\xe9\xfc{7\xdf\xe5r?0Y\xdf\xeb\xe76\xab\t\xff\xa0ͦ9b\xb3\xf9BO!\a\xa3\x9bָ\xbb\xbe\xff\xdb+D\xc6\xde\xfd\xc9^i\xb4\xdb_\x90<I2\n\xeb\xe6\x04\x9dS\x8fmӑA<zd\x93\xcd#=1\x9b\x89\u007f\xd9f\x8b\x99\xa1\xf2\x00\r(U\x03\x00)\x88\xca\x02\x86==\x16S۠\xf8\xb8\xd1C]`t\xd6\xd2tw\xb3\xd9\xeaX3\xfa\x85\x87\xd2\x04_;\x8f\xfdY,\xb11&z\xcf\xd8\xe9\xb2\x12\xe3\b\xc6\xcf\x04gX-\x96%\xa3\xb8\xabU\x8a\x8a-r\x8cԿɑA^\x8fIN\xcc~\vI)\x8d\xb6\x9f\xdexp|z\xed\xbc\xd7\xc0\xbaFm\x01\x03V\x9e\xf6<\x04\xcb\xe9\x00k\x03\x10\xb0\xf5\xc8\xf4\xb8'\x99\t\x00\xa4\x02 `\x00\x00\xa4, `\x00\x00\xa4, `\x00\x00\xa4, `\x00\x00\xa4, `\x00\x00\xa4, `\x00\x00\xa4, `\x00\x00\xa4, `\x00\x00\xa4, `\x00\x00\xa4, `\x00\x00\xa4, `\x80*\\Ϡ\x91\xe1\x06\xb3\xd6T\xf0O`\xc5\x01\x01\x03B\f\u05fcNf\xb2d|\x19\xd5t\x1d\xec\x03\xda\xf9d\x96\x8b\xc4[О\xcc\x04Xè-`\x9e\xaef\x93e \xb4(\xbb\x83\x0f\xads\xe5\xbck\xb6<\x88S\x06H\x88}\xb7\xb8>\xb5\xfeY2S\x8c\xbf\xa4v\xe1\x15\xc7\xfez\xadL_\x1b\x14w\xeep\xad4\xe9Ԛ\xb1I\xeb¸\x02\xa1Kd\xff\x12B\x15Q\x95tk\x17\xbdv\xee\xe8F\u007fv;\x9e\xde\xf4ET~\xf8lK\xa6!\xad!\x99\t\xb0vQY\xc0\xa6y\xab\xd3\xedl\x13\x174\xf4\x99\x06؊\xac\xd8\xdf\xcd\x0fN\x8e\xf2\xef\xf3\u007f\xbcNx\xf4$&kn\xe2P\xad\x9dp\x9f\x1bIj\x8b\xbf\xb7\xdb;\xb9\x89\xd0\xde\xe9C\x9d\x17\xf5b\f\xa4N\x16(\t\xe3\x1eT\x8d\xabQ\x0f\xc6\xee\xcd\rt\xbc\xe7mȌ^\x13њqKL\xf5\x8e\xe2\x851\xa4\tl\xb5\xe0\x064\x19\x95\x1f>\xdbұn\xbc\x9a\xcc\x04X\xb3\xa8,`.\x16\xc2\xd6\xc7\v\xeb\xfbY{܂\x80\xf5\x98<4bd̪\u007f@45JkN\x1f\xbdF_\x9fG\v\x98\xa2-\r\xe6\x16\x12\xb0\x1f\xb8N\x1c\x9c\x15\xd2/t\x8dB\xe2\x01:\x87\xcf!*L\x9f\x98X\x86i{L\x15\xe1\xe5\x10w\xc4,\x97\x18\a\xefF\x13r\x04\xb6\xee\x8aΏ\x9cm\xe9\x9cѬ\xb1\xb8\xc8\xc0\xc2QY\xc00\xebzy\x85HD\x0e\xb3OX\x13\xdf\xc3?\f\x1f\x03\x12\xa2\xb8h\xbe `s\x9dQ\xf1$\xe3,\xb0\x1f\x11\xb0\x17\xdcp8\xf7\x8aAT2\x17\xba\x8c\xaf\"\xda\x19>p\x86e|q\x00\xc7%\xff`\xfccr\x8e\xa3\xbd\xb8\x17\xc5\xf8\xab\"g[:\xbe\xec\xe81.\xb0nP[\xc0\b3n\v[\xfd\xdegr\x89A=\x06M\xf3I\xc2V\x00\x94a\xd1\xd9\x15\x1d{M\x100\xca\xdb\v\x06\xdd\xe1\xb3Ϣl#\xb9\x14Q\xc0\xe6\xca\x04\x83\x9b,s\xaeX\xec\x80a/j\xc2\x16D\a\x8f_\bݫ\xd2/\xf0\xf8F\x84θʷ\xa6\xef\x99Ǿt\x84\xd2\xe8:\xe0\xd8*.Z\x9d\xcf̚\n2r\xab\xc5\xef \xf3\x16\x1eG\x11p\xce\xe3\x83Z\xba\x96\xb8\x85\x14\xa9\xc3u\xe4\xd5\"=[\x1c\x82\xf7k\x8a+o\x12q}\xa6\xe3\xb8o^\\<\xaa\xaf}'I2\x9b3\xe9k(\xa8;\xb0(T\x170/\xcf\xf3f\xf6\u007fn\xed\x0eE%j\xb7:\xdb\xf8\xe6\x01\xf8/L\xc2\xec\x04\x8b\xfaa\u007f\x1e\x95\u007f\xf4\xca\xdc\\\x87\x91\xa6\x86\xb9\xaf\x1e\xf5\x9d\xe5\x1e\xcbm#\xb9\x94P\x0f쩽\x8fk\xb5\xdb\xff\"\xecpv\xb1\xb2@\xce \x1eʡ\xdf'\xa6\x1dx\x90\xec\xe4\xf3x\xc6Ҽ573\xa7\xba\x9c>I|`\xb3\xb10H\xd87`\xcb-\xb4\xd9ll\xe4_\x91v\xdczU\x9b/|\x0f\xedG{p,\xa2\v\xdfg\xcb<\xe3\xc5\xde\u007f͢\xa1G\"g\x8b\xc3\x15\xee\xc6H硪 \x9e\xeb\xeb;\\Yl\xb8Y\xbf\xfb\xa5$\xc9l\x06 \xceҺEu\x01\xc3^\x8f\x83E%rR\x19\x13\x04\xcc\xc27\x8d\xbb\x9d\xcd\x16\u007f\xb2\xb2\x80\xf2\x10\x92\xf6\xa4\f45\xdbG\xfa*\xc1\x13\xe7嶲\\\xe5!\xe4\b\x17\xad\x8a\x18۴\xf8s\xcdI\xace\xb1<\xf3\xd1._x\x94\x1f\x8e\xdc\x16\x1eBZY\xec\xf0!\xd4\xc2\xf6&뢝\xf5\x94\xb0\v\xbf\x82v\xedJ\x174\xee\x1bf\x8f\x16\x1e\vQ誸\xd3oq\xf0mT\x12c7\xba\x15\xaf<\xb0\xc6Q_\xc00\x8d\v\xd9M\x06\x90\xce@ \xe0n\n\x90o_\xab\x89\xde\x18>3D\x8cN\x8a\xb2\x80\x9d}\xfc\xf8\"\x130\xfc\xaa\xb3\xf6h\tw\"\xcaV\x9a\xab,`\xfd\\l477\xf2\x15\x1e\xf9ԇ\x98\x8b<_\xea)\x8f\x15\xb0\xd2m\xfeyBN\"UڶSL\xf4\xa6\xfb\xb0/\xa37\x81i\x98\xfa\xa3s\xef\b\x86+t\xa7\xaa\xe8e(_\x92\xa4\x17\xda\x12[\x12X\x17\xa8,`~a\xb00\xce\a&\xf9\x10\x1e\xdc\xcb\x02\xdb\xe2^\x98\x92\x98\x94\xb8N\xfc\xa9{4\xf5\xf8\xd0\xe1\xc6~\xfb\xe9(\x01\x93\xe5*\v\xd8DdnE\x98\x80Ʊyt\xb3c\x13\xfb\xcc\xf2wH\x8e\xc4\n\xd8v\xd1\x1f\x96 ڑ\r\xb5\x89\xcf/\xe7\xb5m\xb8]\xbb \xaf\xe7\tѕw\x96\xeeTE\x9c\u007fUR?\xe0\x10D\xba\\\xb7\xa8+`\x81&\xe1k\xf7\xa1)\x10\xf0R\x1cf\xaf7\x80G\xcd쟹g\xd1\xd3#\xd7\x1fL\x94\xeeIz\x1f\x94\x88\x13\xbf\xb2\x86>K\xbc \x110j+\xcbU\x16\xb0٢V\x1cCnC6ι\xb4\x8d\xa5\xf3\xa5\xcf\"\xe5\x02f\"}\xb3\xf2m\xa3\x8c\x04\xee\xf8R\xad\x1fW\b\u07b3\xe3\xfb\xf1\xfe\xe3\xf1-%\xd4\x1f}\xc2xEw\xe2\x850\xaf\xd3\xc0\x03\xec\xf5\x8a\xba\x02\x86\x9b\xbb\xe8\xab\xdf\x12\x9a\xb9(\xf8\xc0\xbcl\x1a\x85\xcf\xf4 N) \x8cш\xf1k\xc1#\x84\xdd\r\xa2O)\"`\x87\xe9}\x1d\xac:!\xb7\x95\xe5ƙFq\xa12\x88\xa3\xd9[\xb0\x1f\x1f(\x10\xfc\xf1\xb2\t\x13a\x01+,\xc4x\x9a>M\xec\xa2/\x18\u007f!\x1c\b_\x99\x04\xaf\xe6s<\x8aΥM\x93\xf4\xa0ƣQ\xf0\xbbO\xd6\xc5L\b\x1b\x13\xda\xdax\x9b\xbe\xc6\x11\xb0@\xde^\f\xacST\x160\x17\xdf\xedt;-\xe2L\xfc\x80\xc7a\xf6\xd0\xef\xec\a\xa6\anGSۇ\xfe\x9d\xdc\x1a\xa4\xb5\xa8\xa3\xfft\xb1\xd0\x03ۇ؍Kg\xe2O\x88\x93\xb8Z\xb9\v\x9d\xb7\xab\xb8\xb2;\x13R[I\xeeK:\x13\xbf\xc3n\u007f\x19z\n9!\xea\xd6s\xeeN\xccɪQ\x03n@\xa4\xab4?Ȟ72U\xf2\x0f\xdal\x9a#6\x1b\xfb\b\xcfi.\xb5\xefʠޱS\xa8\xd4\xd2^\x81\x84\x89\xc9\xe2\x95ɸ\x84\\\xb8yk\x80\tW {O\xb6\xc2\br\x1f\xda\x1cӕj\xdc]\xdf\xff\xed\x15\"c\xef\xfe\xc4\x1e\xabRW\x9d$I\xb9\xfc\x9e\x13a\x81\x14Fe\x01Þ\x1e\x8b\xa9mP|\xdc\xe8\xa1.06\xa5\xc8\xd5nn{\x00\xfa\x95\x9c\xb9\x1b\x9f\xe9\x8d\xe2|\b\xb3\x96Ͷb\xbf\x85\x14\xfad8\xd8QYt\xa8\xfe~\xa5\xce(\xb5\x95\xe4^\x14}J\x17\xf0\\\tK\xe8BO\x1f[\xf51^0k\xc68vd\xb4c<\x9e\xc6\x1c\\L\x95\x86\x844b\xe7\xf6\x1f\xcfJ/\x14\x9e\xbdt\xed\xd4f}zW((^\x99\x8cm\xa4\xb3f\xd3X\x85G\x02\x975\x97c\f\xc8Xt3\x8a}\x8e3v\xba\xac\xc48\x82\xf13\xe1\xc2k\xb1,I\xb0\xa5\x9f\x8c)\x04\xac\x17\xd4\x160`\xb5\x12\xbc\xa1\xebKf\xf3\x1eL3\x17~\x01J\xf8ۣv\xb4xgV\x8b\xa6\x02\xbe\xf9\xd6/ `\x80H\xb0\xc3\xf0*\x99\xcd{\xc0z^~W\x82g\x8f\x01sֱ\xf8G\xe3\xe0͆\xc5(\xd63 `\xc0j\xc1\xa3\xad\x86\xa9\xcc\xc0\xe2\x00\x01\x03\x00 e\x01\x01\x03\x00 e\x01\x01\x03\x00 e\x01\x01\x03\x00 e\x01\x01\x03\x00 e\x01\x01\x03\x00 e\x01\x01\x03\x00 e\x01\x01\x03\x00 e\x01\x01\x03\x00 e\x01\x01[\x0eJ\x91\xb6\x1cb\xc4\x01\xc0\xb2\x03\x02\xb6\x1cxz\xcdy\xda\xc5\xff.\x19\x00\x80š\xb6\x80y\xba\x9aM\x96\x81н\xed\xe0\xe9\"\xac\xf3M\xe2\xe2\xd2͉J\xa6\x18\xbdh<\x99\t\x00\x00\xef\x89\xca\x026\xcd[\x9dng\x9b\xb8\xa0\xa1\xcf4@\x17\xc0\x9b\xe1G=\x84\a\xfcZ\xba\xe5\x87 \xd4\x17\x00,;*\v\x98\x8b\xa7\xab\xaa\xf8x\xc1Ad\xedq\xb3\x15<\x1d,(QӚ\x8a\xcc\x00\x02\x06\x00ˏ\xca\x02&\x04\x16\xf4\xf2\x1e\xbaq\x98}\u009a\xf8\x8c\xbb\xb7\xd6Ժt `\x00\xb0\xfc\xa8-`\x84\x19\xb7\xc5J\x97\xb5\xf3\x99\\8\"`N~:A\x99\xd4c\x1c-(\xee!\x00\x00\xef\x81\xea\x02\xe6\xe5y\xde\xcc\xfaa\xd6n,\x11\xb0p\xa0\xa25\x82_[0\xe0^P\xe8C\x00\x00\x96\x8a\xea\x02\x86\xbd\x1e\a\x8bJ\xe4\xa42\x16\x1607/\t\xfc\xbc&\xb8\x8b\x10ڗ\xcc\b\x00\x80\xf7A}\x01\xc34.d7\x19@:\x03\x81\x80\xbb) \xf4R\xba-Iʤ\x1a>\xed\xd6\xcb=kM\x94\x01`\x95\xa1\xb2\x80\xf9\x05\xb9\x1a\xe7\x03\x93|\b\x0f\xcd1?HP*\x15\x19B\xdd\xc9L\x00\x00xO\xd4\x15\xb0@\x93\xe0\xd9~h\n\x04\xbc\x14\x87\xd9륚\xe6]s#Hx\n\t\x00ˏ\xba\x02\x86\x9b\xbb\xe8\xab?\xec\xb1\x0f\xf9\xc0&\xf9\xb5\xf6\xc3\x1b\x100\x00X~T\x160\x17\xdf\xedt;-\xe2L\xfc\x80\xc7a\xf6xi\xcaɯ\xb5\x80Z\x83 `\x00\xb0\xec\xa8,`\xd8\xd3c1\xb5\r\x8aj\xe5\t\xff\x00\xd2}+A\x99\xd4\xc3\xef\x19-\xd5x\x92Y\x01\x00\xf0\x9e\xa8-`\xeb\x83\xfd\bmmOf\x04\x00\xc0\xfb\x02\x02\xb6\x1cxF\xd7\xda3\t\x00X\x95\x80\x80\x01\x00\x90\xb2\x80\x80\x01\x00\x90\xb2\x80\x80\x01\x00\x90\xb2\x80\x80\x01\x00\x90\xb2\x80\x80\x01\x00\x90\xb2\x80\x80\x01\x00\x90\xb2\x80\x80\x01\x00\x90\xb2\x80\x80\x01\x00\x90\xb2\x80\x80\x01\x00\x90\xb2\x80\x80\x01\x00\x90\xb2\xaco\x01+E\xdarg2#\x00\x00V+\xeb[\xc0<\xbd\xe6<\xad\xb0\xb4\x8f\xb7 \xfc\xebkI\x12\x00\x80Ռ\xda\x02\xe6\xe9j6Y\x06B\xab\x17:x+\xdb\xfa\x06n\x99n\r\xacȚ\x86\xbdH\x8c\aސ\xd6\x10ʓ$\x01\x00XŨ,`Ӽ\xd5\xe9v\xb6\x89\v\x1a\xfaL\x03lEV_S\x1b\xcdmZ\t\x05\x8b\xac\x9cj\xddx\x15\xc7&\x01\x00X\xbd\xa8,`.\xb6\xf6\xbd\x8f\x17\x1cO\xd6\x1e7\x130\x9b\x85\x06垷\xd8\x12\x94\\.$K?\x9fѸ\x15\x92\x00\x00\xacZT\x160\xcc:Y^!\x12\x91\xc3\xec\x13\xd6\xc4\xef\x11|N\xed+\x11\xdbV\"`\xbe\xec\n\x85$\x00\x00\xab\x16\xb5\x05\x8c0\xe3\xb6Xi$\"\x9f\xc9%\x06\xf5\xf06\xf5z\xfd^[\x937I\xc9\xe5`\x1c\xf5\x86\xd3g\xd2g\x14\x92\x00\x00\xacVT\x170/\xcf\xf3f\xd6\x0f\xb3v\x87\xa3\x12\xcdt\x93ܮ\x15\x91\f\xbf\xb6`\xc0-D\xab\xc4\x03\x91\xde\xd8\x00\xc4\xe4\x00\x80Տ\xea\x02\x86\xbd\x1e\a\x8bJ\xe4\xa42&\b\x98\xbf\xdb\xe2\xf48-\xdd\xf3\xc9\xca.\aw\x11B\xfb\x84\xa4\x1b\xdd\n\xe5J\x92\x00\x00\xacV\xd4\x170L\xe3Bv\x93\x01\xa43\x10\b\xb8\x9b\x02\x01\xea\xc4\xf7\xb3܁d\x05\x97\x01\x9fv\xeb\xe5\x1e\xd1c\xefF-\xa1lI\x12\x00\x80Պ\xca\x02\xe6\x17\x06k\xe3|`\x92\x0f\xe1\t\x98\x1e\xb2܇\xa6@\xa2\xb2\xcb\xc3\x10ꖤ\a\x14\x92\x00\x00\xacV\xd4\x15\xb0@\x93\xe01'R\x15\xf0R\x1cf\xaf7\x10\x12\xb0ѕ\x11\xb0\x88\xb3\xabN\xe3SH\x02\x00\xb0ZQW\xc0ps\x17}\xf5[B\x13&\xc4i\x14\xe2\x10r\x85\xa7Q\x04\xf2\xf6*$\x01\x00X\xb5\xa8,`.\xbe\xdb\xe9vZę\xf8\x01\x8f\xc3\xec\xf1b<\xd3bq\xb8\x1d\x96\x96\x95x\f9\x18\x11\xb0\xcbhT!\t\x00\xc0\xaaEe\x01Þ\x1e\x8b\xa9m\xd0/\xeeP\x17X3I\xf8\x87\xda\xccmC\xfe\x84%\x97\x03\xbfg\xb4T\xe3\x11wl\xe9'ql\x12\x00\x80Ջ\xda\x02\xb6\xba؏\xd0\xd6\xd0\xca\x13-\x9a\x8a\xf9\xd8$\x00\x00\xab\x98\xf5-`\x9e\xd1\xf0O\x1e\xbd\xd9\r\nI\x00\x00V3\xeb[\xc0\x00\x00Hi@\xc0\x00\x00HY@\xc0\x00\x00HY@\xc0\x00\x00HY@\xc0\x00\x00HY@\xc0\x00\x00HY@\xc0\x00\x00HY@\xc0\x00\x00HY@\xc0\x00\x00HY@\xc0\x00\x00HY@\xc0\x00\x00HY@\xc0V3\xc35\xaf1\xf6\x16\xb4c\x00\x00\x94P[\xc0<]\xcd&\xcb@h\xb5S\aoe\xdb\xc0x\xbb\xa9\xcd\x19\xbf\xd4r2\xb9\t\xe5\xc5dz\x8fmI\xdf\xfb\x81և\x9d\xaa-6\xd4?2\xbc\xc6_r\x1c\xa7\u007f\x91\xcc\\\xc2\x1d\xae5H6\ri\xf0\xe3r\x00PDe\x01\x9b\xe6\xadN\xb7\xb3M\\\xd0\xd0g\x1a`+\xb2\x06\xac\xe6Q\xf7\x03ӃD%\x97\x8f\xc1#\x9a\x98\xbc][\xae\x1fI_آҏ\x9e$>>V\xfc/\xf7\xfaNp\xdc\u007f\xe0\xef\xed\xf6Nn\"\xb1\xb5\x94N\uef90\xb0n\xbc\x9a\xd8\x12\x00\xd6)*\v\x98\x8b\xa7\xeb\xd7\xf8x\xa1\xb7e\xedq3\x01{h\xa2!m]\xa6\x85)\xc6\a\xa7N\x13\x9d\xe3EWq`\x81WSs!\xe1\xe1\x1fJ\xce\xcea<[I\x04\x8c\xf0x\x11\x02\xf6B\xd7\x18J\x9eф\x97\xfd\x01\x00 \x82\xca\x02\x86\x99*xy\x0f\xdd8\xcc>aM|+[)\x1f7=\x88Sh\x99\x89\x150\x17\xb2*\xd8)S\x95X\xc0\x1a\xf5\u007f\xa1\x9b\x0e\xee9\xdd,F\xc0\xae\x18fCI_vE\"K\x00X\xaf\xa8-`\x84\x19\xb7\xc5J\xddK>\x93K\f\xea\xd1fc\a\xda\xef&*\xb6,xʳ\xb3\x0e\x88CȦ\x82\x8c\xdcj\x1f\x8dՍ\x18ղ\xdc\xf1\x8d\b\x9dq\x95oM\xdf#]\xacu\x98\x13\xa8\xa1;\xf6\xdaú\xb2\xda\xc3A\xd9\x19*\xaf\xb0ͫ\x8e9\xba\t\vX\xb0\xb3F_\xd5\x19\x8c*\x16\xbc_S\\ySЭ\xb9\xe2p\a\x8ct\xc1\xd2W\"^\x00\x00\xacvT\x170/\xcf\xf3f\xd6\x0f\xb3v\x87\xa2\x12\r4\xb1\xa8D涄%\x97\x01Wf\xae\xb9\xfd\x17HC\xd3\x15iǭW\xb5\xf9DZ\x1f\xdaZP\x9d\xcd\xe6\x91\xe5\xceX\x9a\xb7\xe6f\xe6T\x97#\xe9hnv\xc2^i\xb4\xdb\xed\xb4{\xf5t\xf7\xc5\xfe\xb1{e\xdc;\xe9\x19\xe6\xb8\x0e\xe9nX\xc0.\x16}3\xf2M\xd1ŨbW\xb8\x1b#\x9d\x87\xaa\x98\xae=\xe5\xec\x91r\x03\x92\xe0o\x00\x00\x84P]\xc0\xb0\xd7\xe3`Q\x89\x9cT\xc6\x04\x01\xf3\x99\xad\xde\x19O;oIV\xf6C\xf3\xe96r\r\x81\xed\x1a\x92\xb4\"3\xa6A\xd6X@\xee\xf0\x10R\x96\x9b\x8fv\xf9\xc4A\xb0\x84\xf0\x10\xb2\xf3\x10\u0560\xce\x12Y\x0f\xec\x05\xf7\xadt7$`#\xdc\x18y\x1d\xe3Fdņ\x99\xd7\xfe1\xd7'\x98<\x8f\x94s\xa3[\x18\x00\x80h\xd4\x170L#@v\x93\x01\xa43\x10\b\xb8\x9b\x02t4鵒~٠U\xed\xf9N>\xc4\xd3\xcd\x19\ry)\xdd\xe6\x9f'\xe40gSX\xc0d\xb9\xf9\x8a\xae\xf4\xb0\x80\xbd4\x1c\xbdq\xefipNvtN\xa7\xd8\x03\xbbr\x82mN|)+V\u007ft\xee\x1d\xc1\xc0F\x9d\xfd\x9cdƅ[\x90P\x00\x00d\xa8,`~an\xd58\x1f\x98\xe4CxhΌ7\x80\x9b\x06\x12\x15]\x06\x1e \xe6|;\xa7!/\xdb\x05\xc7\x17\xdaOs\xc2\x02&\xcb\xcdߡTIĉ\xff\xf6ޅJ\xae쎢\x0fln\x8cmB\x02f<\xcb6\xb55\xb2b'D\x8f\x1a;8!\xf5\xf7\x0f!\xb5\xdf\x1b\x00H\x05\xd4\x15\xb0@S/\xdb>4\x05\x02^\x8a\xc3\xec%ʅ\x99_\xdc%H\x99\x8ax\xd1u\xbaaN\xfc\xf2m\xa3\f:\xa1#\"`\xb2\xdc\xfc\x03J\x950\x01\xbb\xf7\x92\x88S#Ѡ\xb7}\xfaN\xd9\xe1F\xfd+\xba\xe9\xe3^\xd3M\xb8\av\x94\xf9\xec\x8f^\x94\x15\xab?\xfa\x84\xc1J\xcc\x16\xb5Fj\xa9\xd3,pR\a\x00\xac+\xd4\x150\xdc\xcc&L\xf8-=\xe2\xbe\xe0\x03s\xf2D |ͽq\x8b-\x17\x059\xe4Į\x9fhH\xb2\v1\x0f\xdc\x17u\xf45,`\xb2\xdc\xfc\x83Ju\x18\x8d\x18\xbf\xa6n\xabV\xea\xd1\"\xfb\xd7X\xb6\xbba\x92m\u007f(9OF\x87A\xe3Q\xb6\x17\xf1\x81Q?W\x1f-!)6&x\xbf\x1ao3\x9b\v\x95\xe1\xbe\\ o/\x06\x00 \x06\x95\x05\xcc\xc5w;\xddN\x8b8\x13?\xe0q\x98=TB\xf8!\xf7\xc3&\xab\xfa\x9d\fGFNݙ\xac\xb4\x8df'ƧP\xa9\xa5\xbd\x025\x85\x9eB\x0e\xb2\xd1n8w~Ж[h\xb3M\xc6\xd4\xd1Z\xd4\xd1\u007f\xba\xf8%U\xa2\xe2\xd6\xe1\xfe+\xdc#\x96\xbd\x0f\x89\x9a3\xa27\xde\x1f\xae\xd5\x11\xe1zIg\xe2w\xd8\xed\xc4\x16\xd7s\x8dÍ\\=\x96\x17k\xdc]\xdf\xff\xed\x15A\xc6\xf0s\xeeN\xe8\x1c\x97\xd1(\x06\x00 \x06\x95\x05\f{z,\xa6\xb6A\xbf\xb8C]`\xcd$1j1[G?\xd0O\x0f\x17\x85k_\xd6֓\xe6\x8d\xe8\x18Iw\xed\xd4f}z\x97\xf4\x0f\xb3\x98\xdbk\xa3\xf0k\x81P\xeex\x1aˍ\xed\t\xcd\xdd\xf8Lo|L\x12\xf7\x8d\xb7\x0f\xeb\fFA\xbf\xb0Yˋ\x06S\xb5\xfa\xb2\xb3t\x1e\xfeE\xd1\xc5Eǜ\xc1\xce\x13\xfa\x13l\x1e\x98\xac\xd8\xd8\xe9\xb2\x12\xe3\x88X\xb0U/z\xc1l\xe9'1\x00\x00\xb1\xa8-`\xc0\xc2\t\xdeб\xbeX\x8b\xa6B:y\x16\x00\x80\x10 `\xab\x98`\x87\xe1\x15\xc6\xdelX\x8c\x02\x00\x94\x01\x01\x03\x00 e\x01\x01\x03\x00 e\x01\x01\x03\x00 e\x01\x01\x03\x00 e\x01\x01\x03\x00 e\x01\x01\x03\x00 e\x01\x01\x03\x00 e\x01\x01\x03\x00 e\x01\x01\x03\x00 e\x01\x01\x03\x00 e\x01\x01\x03\x00 e\x01\x01\x03\x00 eQ[\xc0<]\xcd&\xcb\x00]\xf9k\xc6\xcc\x16\x946\xb3\xa5u<\xed\xe6.O\xe2\x92+¨\xb0\x88N\xda\x03awr\x13\xca#\x9b#$+\xc3\x15k\xedؓ\x91]ڛ=\x1d{\xe4C\xe1.\xcf\xc9\xf8\xa4N\xfd\x85\xd3\x00`u\xa2\xb2\x80M\xf3V\xa7\xdb\xd9F\x174\xf4\xf1\x0f=\x04\xb6X\xb3\xdbds\xd9L\xab0\xfa\xf4\xfc\xa0\xedkt\xd9\x16Z\xc0\f\x0f\xb2\xe5\xa7\xdd6\x92\x1b\x1b\xe7\xac+c\a߲\x1d!g̑\x0f\x85k\xf3'\x97\xac_d~\x02\n\x06\x00\f\x95\x05\xcc\xc5S\x95\xf2\xf1N\xfa\x12\x16\xac@3\rY1м\x12K\x1a&eH&U\xa1(\xdeC\xb1\x02\xe6\xcd\xdcOtηm\x19\x05l\xffV\x1a\xdf֙\xf1E2C\x00X\x1f\xa8,`BTE/\r\xdf!\x110\xa7\x89ޗ>\xd3\xf2\xdd\xf9\xef\xc1\x82\x05\xecT:\x1b;^B\n\x83\xcb\x0fD\xdeV\xb69\xa0\x18\x1e\t\x00\xd6\x1fj\v\x18a\xc6m\xb1\x06d\x02\xd6s\x97m\xee\xaa\x1c\xd5c~˦/r\xb2{\x8fg\x15\xd2\x11\xed\xc1lMξq\x92\xed܈\xd0>\x9c\x83P\x16\x1b8\x86\xa5\xcaS\x9e\x9du\x80\r!\xa5\xb9\xb8\xa9 #\xf7\xffo\xef\xfcc\xe28\xee\xfe\xff\xfdg\x10\xac\x8c\x0eN\x1cB:\xa4\x039\b\x13Y\xc9`|',\x1cS\x041\x17\xd1`\x93\xafj\xe3\x1f(\xa9\x12\xfb,\x13\x9b\xa8NS94D\xc6`\xf2\x03\xc5%ND\x83c\x14\x1axL\x1d\x91\x1fv\xb8\xa8\x8ay\xda\xe2|\x85\x1e\x92HϵV{\xcf#5\x8e\xb1]\xe1m\x1cR\x82}\x86Z\xa3\xef\xce쯙\xe5\x8e=(\x06\xce\xf9\xbc\x12\xf9\xf6n?\xf3\x99\x99ݝ73\xb3\xb3\xfb\xa9\xa1\xba\x9c͂Gʡ\x034\xd9\xe1\xfb\x1c\xabiȣ*\x94\xd2X\xe3q\x14\x8e\b\x9b\xb2\xdcS\x98\x95\x92\xb1\xce-[iv\xb17Q\x8f\xa4k\xf1\xdc҅qu\xaf\x1a\fes\xf6\xact\x00\xf0\x83d\xc9\x05,D'\xeei{\x0f7v\xbd\xd2\xd8\xdaC\xfb^\xedj\xd0\xc3ޥ\x0el\u06dd\x8ej֢\x8czW\x03\x8d\xc1\xed\xefn\xf3%\xf5+\x03ھ@R\x9f܌Z>dF\xbaT\r\xa5{\x9a\x8f?\x88$Y\xf8U\xf6'Uw\x1cʸo\\\x1eKj0=o\x96\xea:\xea\xa4rE\r[\x93QF\xe0@z\x89\xb0\xa9$\xdf\xfcJWc\x06\x9a\xf5\xaa\xe8\r\xa8\x90~\x8c5\x1fRi\xd6g\xdf8.\xb9\xcag\xff\b\x00?D\x96\\\xc0\xe4\xd0\xe8`\x9b:\x89\xdfrv$\xd8vLi\xa1-\xfdlO\u007f\x8bM\xd2E'\xb3\\\x11\xae\x0ey\xb3\xd2w\n\xb7QU\xcde\x11l\xe5\xcd\xf9\xa1,\xfd=κT\xad\xc9V\f\xc6WK\xe2\xaf\x1d\xa8\x99};&\x8f S\u007f;Q'\xfb\x97\xf6,%\xa7҉*ϐ\x85\xcd\xc3\x19T\xba~\xe1\x9c5\xeb7\x1cP\xe3\x1e}9\xac\x12\xe5\x8e\xe6\xf8\xe6\xd4\x159\xd6\x06\x80\xa5g\xe9\x05L\xa6q!\xbb\x94v8H;_\x97\x9a\x15!hg\x01\xb2\xe5\xee\xf6\xb9\x93->\x99\xc7\xe4>\x14\x96kK\x95\xed\xd0\xe1\xc2\xect\xb4\x9a\xfd~i\xb5˧\xdbhR\x15FllW'\t\xbfʥ\xd9cW\x15\xb2\xfc\xf2X\xb2\xd9\x03\xf3粏\x9c\xcd\xca?\x12\xfd\x87\x05\xff\xe66G2ݏ6~8\x1e\xa5{\xa52\x8ctfߚ}T\x0fZ\t\x00?x\x96X\xc0\xc6\xd4.\xc7\xd9F\xa3\xebѣ\xa8\xd6I\xb5E\x1e\xd7\xc3\xdd.\x19\x99\x9dr\xbf$\xcb;\x14\x01\xebweն\xf7ܯ\n\x98\xfc\n\xea\xd5m4\xa9:\x83\x98ʪJd\n\xd8jMg6\x18s`cJ\xe7k\x8d*\u007f\xeb\xf2\x95\u007f\xa4=\xb2>\xf7\xcfm\x86\x1b\x1f\xcaA\xae\xd8\xd1:z:Tz\xac;¥\xc9\xcd\xd1\x12\x00\xc0\x0f\x91\xa5\x15\xb0\xf1\x16u\x9e\xfeæq]\xb5\xba;hdnuRl\xc9GF\x9c\x80\xe5\xe4\xd32\x94\xa8\x026\x9a\xb9\xcb\x1d\xd2l4\xa9\n!:'/['\xf1˳\a\x18!\xe3.d\x1b\n\xc9~u\x96\xdd\xcdz`4\xaa\xb7&`\xc6\xe6\x99\x1d\xca?\xe1c\xa9\x87\xe5y2z\x9fs\x96\xa6\x01\xc0\x0f\x96\xa5\x150\xb9\x95\xce\r)CH\xa5\xaf\xd5\xc1\x06\x8c\xa1\xe6\x0f\xe9:0\xaak\xddK\xbf\x0e\x8c\x13\xb0,:\xb7>\xbe\x9a\t\xd8X~\x9d\\\xb5V+\x8d.U\xf9Y4\x86\xf8*I\xfc\xb5\x13\xb5я]\x01\xba\x0e\xacD\x19\x12\x8e\x17\xb8\xe9\xcc\xd81\xe5\xc7cl\xac\x17U\xc0\x02l\x92L.\xa8\x92-\x8c\xd4ώ\xfd\xcdq6\xd33\xa4\x94\xef.\xae\xf5\a\x80Db\x89\x05l\xa8\xb1+8\x12d\x93\xf8#\x8d\x9dC#g\x9a\xe8\x8a\ny\xa4\xa9{\xb8{\xe9W\xe2\a\x9d\r\xe1c)gå\xf7\x8f(\x92\xf2\xd0\xe1\xc0}(\xa3\xbe\xefRoUƈ<\x9c^\xd3;Ư\xc4\x1ftd\x05\xea\x9cI\xc9\xcdAu%~CO\x0f-\xf0\x0eT\xdav\u070f\xe8\xfd\x87NG~\xf3\xf1\a\x93\xe9\xe0\xb3<iGǎ\xa4r\xa5\xc7ԓ\xb2\xb9O\x1e\u061c\xd23\xcam*\xb9\xa5\xed\xe9h\xf7\xa3Y\vG|Qb\u007f\x9b\x9cH\xcd\xec\xe8\xe9\xe9\xf1g\xcda\x03\x00? \x96X\xc0\xe4ѓmM\xed\xea\x939_v\xb56w\f\xaa\xfd\x9c\xd1Φ\xe3\xa3s\xa5\xbb\x1b\x8c\xbb\x10jMG\x8e6:\x855\xde\xe0\x912J\x9b\xb3\xa5\x82N\x84P\x8d\\\xad\xfc\xdb-\u007f\xc8=\v9\xe4s\xba\xb75'\xa3*\xf6,$\x85\xce\xfd˝\xf7g8ר\v\xd9\x06\x1ft\xb8|\x83\xcc\xf5\xcfW;V\xffb\x9c.\xfeB(eС\xfc[\xc5m\xca-\x05\x81\xac\x94̂\xd9\vߚ3\x1ag\xfdfR\xa0e\f\vY\x01\x80\xb1\xd4\x02\x06\x00\x00\xb0h\x80\x80\x01\x00\x90\xb0\x80\x80\x01\x00\x90\xb0\x80\x80\x01\x00\x90\xb0\x80\x80\x01\x00\x90\xb0\x80\x80\x01\x00\x90\xb0\x80\x80\x01\x00\x90\xb0\x80\x80\x01\x00\x90\xb0\x80\x80\x01\x00\x90\xb0\x80\x80\x01\x00\x90\xb0\x80\x80\x01\x00\x90\xb0\x80\x80% K\xfe\xd6\x0e\x00X\xa1\x80\x80%\x1a\xa3~\x17\xda`g\x04\x00KD)\xca(_\xf2\x17\xf9\x99\x80\x80%\x18\xe399\x8d'\x97\xfc\xc5C\x00\x10\x83\xd1\xee朌勴\xbc\xd4\x026\xda\xd9\xda\xd4\xd6K\xeb{\xa9\xb9\x91\xa2\x87\xdd\xe9^F\x15\xffw\b\xadu\xaa/\x86~\xb7\b\xab\x14\xbdk\x93\xe4\xdf\xe2\xac\xfa*\xc4\xd7iN\x0f<\xf2\xd6u\xf5\xd7\x0f~\xf4\xdb\xd8I\x9e\xc3\xf8\x1d}\xfbgJ2\xef\x17\x16\x83\xf7\x1e\xc0\xf8S\xf9\x13e\xcfWr<\xbc\xee\xfd\x15\xfb\x14\x9d\xcdY\x86\xb8\bU\xb9R\u05c9\xe3c\xfa\xe6\"Ǽ\x03m\xbe\x8a\x8bhY\xde\xf3\xe2WcX\xfcQ;Y\x9f\xaa_\xbf(\xc2?\x96c\x1c\x1d\x85Ϟ(\xae\xd8\xffQ\xc5_g\xef\x89\r=\xa8\x18oz\xf2\xbfb\x19\xbc\xad\xec~U)*\xc6o\xc52\xf9\xb7\xb9\xfbդt\xa3\xb3v&w\x8d%\x16\xb0/\x1b;\x82#\xc1v5*ч\xa3\n!}G\xff\xdc)\xef\x12\xdd\x03v\x166lˮObu\xf8\x15>w\xeeM\xfc\xfa\xb9s\x0f\xfc\xca.\xcd|\xf9\xe8?\xcd\xed~\xf5\xdd\xfc\xff\xf3+\xfc\xf6\xb9\xf7\xf6\xe3\x97\xd4_\u007f[<\x87j\xfe\xe9\\\xd1K\xe6\xb6R\xc8O,\x06_\xbf\x8b?\xba\"_y\xe4\xb1?\xcaq\xb1\xa5h\v\xfb\x14\x9d\xcdY\x86\xb8X\xeb:\xbc9U\xfcc\xce\xde\x1d9+\x86\xb0\x1d\u007f\xd9\xefݭ|\xec\xf6\xee\xffK\f\x8b\xbf\u007f\xc2N\xd6'Wԯ\xd7?\xf9\xd9z9\xc6\xd1Q\xa4\xb9\xf8\xff\xbe\xf5\xce\x16\x8c\xff߬=s\xf0\xf5'E?;\xf7ћ\x8fx?\x8ba\xf0\xd5\xdb\xf8տ\xca\u007fUNd\xec?\x1b\xfc\x99_\bw\xbf\x9a\x94(Q\x9e\x97\x8c%\x16\xb0!\x16͖\xbd\xfd\x9e\vl\xabt\xccږI\xc0\xf2J\xed,l\xc8\v\xc8\x0e&)\xaf\x17\xc9\xf2\xa7\xf4\xb2\xf0\xben\x97f\xbe<\xb6\xcf\xdc\xd6/\x96\x0f\xb0\xd20\xae?\x87\xb5?\xf0ף$3Y\xff\x92\xb9\xad\x16R\xe4\v\xfc\xb5,\xbfT\xf6\xdf\xd6ߣ\xf35\xdeO\xed\x19\xbc\xb3\xb9\xcb`O\b\x1d\x92\xc7g\x0fF\x16\xd2<\x8e<\xa1t&\xff\xc7\xfbđ9l\xc4\xe3\xf0\xd2\xfah\xbf2\xfeg㓊\x00|\xfd\xc8|[6;\xea_W<\x11k\xffg\xf8\x03\xe5ߏp,\x85\x93\xc53\xbf@\xeez5\x17v\x86\x16\x8b%\x160\x99]\x9f\xa1\xc6QQ\xc0\xba\x1b\xbb\x9b\x96G\xc0\xee{\xc8\xce\u0086\xdc\xe6\x11Ć8W\xbe\xd0.\x8b/\xaeإ\x99/[c\t\x98|e\xe3sѓ\x88\xc4#`\x1f\x14}d\xfd9\x06\x1f\xe1?b\xdd6\x8a\xb3\x053\x14=^\xdcB\x9aǑ\xfd\xbbߑ\xdf~b\xff\xa2\b\xd8\x11\xef\x9f\xe9\xc7\xeb8\xe6h0:\xeaQ\u007f\xc9\x1bK\xd8\xe3\x10\xb0\xadK(`\v\xad\xe6\xc2\xce\xd0b\xb1\xd4\x02\xa6pi\xa4\x8d\xbe\b\x9f\x17\xb0Ka=\xb8\xed\x92ҡ\xbd\xa1\xf9>Y>\x9b\x8cP\xddP\xb9;\xb5\xd0\x1a,\xbb\xd9\xc5^\xf2<\x92\xae\x19\xa7\x8b3\xe8\xeb\xea6\xe4*\x89\x93\xd9\x14\x9evY\xfc\xb1\b\xe3\xa3_<]\xe9}\xe2\xef\xf2W\xfb*\x8a\x1e~\x92\x8e͞\xc3Eo\xfd\xf2\x11\xef\x13\u007f\xa2&\xe7\x9ex\xb8\xa8쉇\xaf\xd3_\xdf|\xb6bӓlJ\xe2\xfa\x9b\x8fy\xb7\xbey]\xf0\xf0[m\x1a\xe315\xbfnA\xc0\xe4\xe7ʔ\xb1\x88\x17\x1b\xb3\\\x86_.c\xa5)=\xff\x8c\x9e\x05w\xed^\u007f\xfb\xb1\xe2G~I\xfbR\x8a\x80}\xb1\xf1U\xeb\xaf\xe6\xa6PH\xf9\xa5\n\xb9BWDݙY\x86w\x8c\xa9\x9dw\x04gf\xc9d\xe3\xa0r\x8ce\xa8\x87\xb7F\xd9\x0e?\x94)e\xf9\xf4y\x15\xa3y\xf4\x14f\xa5d\xacs\xb3\xed\x96|\x87\xa7&\xf6\xd4\xf1\x91\xfdo\ue55fx\x93\n\x98y\x1c>S\x0e\xea\x93\xd7+0\xde\xc8\xfe\xc4\x18\xc7\xe1O\xfb+6\xee\xfb\x99\xb5e\x9bE\u007f\xe4\x19\xf6\xc3_^\xbf\u009d!\xeelF?\xb1\xba\x80\xfd\xaa\xe8\n猿4x\x013\xfcr\x1e\xaa6\xf9\v\x00\x00 \x00IDAT,g~\xd61\xfb{Yё\x8a\x8a\x8f\x9e߸\xf3\xeb\xe5\xac&\x9d\x97\x9d\xfdn\xf4\xa5b\xc9\x05,D'\xee\xd5(j]\xaf4\xb6\xf6\\\xd2~_\x0e\x01\v\xf7\xf6x\nzzz\x14\xf1\xb9\xd4\xd6\xea\xf6\xa4gՔϊ$\xbb\x01\x15ҏ\xb1\xe6C*\xcdb4\xda@\xbat\xe6꺂>6\xf7\xac]\x16W\xdey\xe7\xe1G\x8a+~\xb9\xff\x81\xffV\xae\xc2g?z\xe7I:\x8b\xfa\xd9;E\xf8G/\xfdj\xe3^\xc5\xe2\xf7\x0f<\xfd\xee\ao\x95ῳ_\x1f~\xf5Շ\xd9T\xc9\xd3돾wt\xfdӂ\x87\xaf?9\xf7\xc8\xces\xe7\xceѿ\x8bW\xbf\xec\xces\xaa\xcdV\x13\xb0\xb7\xe8`\xee\xd3s缪\xa2\x98~\xb9\x8c\x95\xa6\x84\x1f{\xe7\x9d-\xdal\x8cq\xed>\x83\x9f\u007f\xef\xcd\x1fm\xbdN\x05\xec\xaf[\x8a\xafX\u007f57\x85Bʻ\xf7\xc9\xfbv\xabƦ3\xa3\f_\x9f\xdb\xf8\xd2_忾\xb4\xf1\xdc\u05fc3\xaed\xb2qPy>\xec9\x86\x02==\xa32\xfd\xc3\xe2\xefn\xf3%iW\x84.`\xfdh\xf3+]\x8d\x19\x88\xfe\x85\xf1'Uw\x1cʸ/悸#\xfb\xffT\xfc\xbf\xde?S\x013\x8f\xc3\xf5\u07fd\x84\u007f'\xbf\xfd\xc0ۿg6zѿ\xd8\xf8\xc8ۿ}\x02[[\xb6Q\xf4+\x98\x9b\x130\xce\x10w6\xa3\x9fXM\xc0\xae?\xb6Ep\xc6]\x1a\x9f\xe1\xf7\xae\\\xb9\xf2\x1e\x16\xce<\xe7\x81?\xf3r\xb4c\xf6\xd1F\xfc\xcbݸ\xecղח\xb3\x9a\xf4\x8fO~\xef\xc82-N\\r\x01\x93C\xa3\x83m\xea$~\xcbّ`\xdb1M\x0f\x96C\xc0da\by\x1fZ\x1b\xd6Ƹ<\xc3\x015\xd0ٗ\xc3*\x96\x90f\xf5\xa8Q\x0e;Ԡ\x1e\\\xc7|+\xde\xfd\x95|\xfd+\xa5=\xbf\xa3\xb4\xe3\xeb[\xe8Y\x97\xd7oT\xfez=\xfd#e\xeb\xcd\x1f\xd1S\xff\xe6F\xf6\x87\xbaR1\xfb\xeaa\xe5\xef\xec{\xecO\xf2\a\xf8=\xc1\x037\x90ؠtQ\xb4a\x96&`\xefi\x1d~M\xc08\xbfB\xc6?V\xd4\xe9\xca#\xea\x9fr\xbd\x90\xbf\xc5o\xb3o\xefP\x01\xdb\xffȏ\u07b4\xfe\xcamr\x85\x94\xaf\x17\xbf.\xbf^\xac\x8d\x8b\xf8\xa1\x88V\x06\xf9\x99\xfd\xca?\xfb\x9f\x11\x9d\xf156\x0f\xaa\x801\x84\f\xb7ѳ\x90\xab\xadv\xd3\x05\xecp\x06\x95\xae_8ǩ\xc25\xb3\x1d\xc7f;Q9\xb2_\xde\xf2\xdcc2\x150\xfe8\\\u007f\xfa\xb1\xbfT\xe87&\xf5\xa2\xef|\x84\x19XZ\xb6Y\xf4/\xf0\u007f\x18~\xf93d\x9e\xcdX'\xf6\xa5+_\xffq/M\xc1\x1fI\xf3\xc4~\xa6\xf5\xb0>\x13\xfc\n\a\x8a\x1fBF9f\x15O+)\u007f+?\xfd\xecrVS\xe1\x84r]\x1a\xa1엖\xa5\x170\x99ƅ\xec\x92\xe5\xf1A\xda\xf9\xbaԬ\x8d\x0fV\x80\x80Is-\xaf\x1aF:\x82U\x1br\xd6\xc8\r\x99ڸ\x93\x13\xb0\xf5\xfa\x8c\xf8_\xde|\xa2r#f\xb7\xed\xd8_X6\v\xf1\xdf\x15\x95Ͽ\xf5\xfb\xeb\xacӳ\x9eMԼ\x89\xffG~F\xbd\xb9\xb7\xe5g\xa2\a\xf32\x1e\xe9l\xcc\x11{`o+\xc9(\x9ax\xf0~\xf9\x8c\x8f\xd2\u007f\xdfTm\xf5B\uebfc\xf2w\x85\x8ag\xa8\x80y?{\xab\xec+˯\xdc&WH\xf9\x8f\xf8\x93+\x9f`\xed\x86e4\x01\xfb\xc8\xfb\xb5\xfc\xb5\xf7#\xd1\x19_\xb2\x18\x98s`\xa1Å\xd9\xe9H\x8b\x92\xae\v\xd8H\xa6\xfb\xd1\xc6\x0f\xc7\xe9\x1f\xbc\xd2챫\nY\xfe\xa8~d&`\xbf¿b\x02\xc6\x1f\a\xf9\xcaֲ'\xf5))\xad\xe8_\xa9\xab\x18\x8eZZ\xb6Y\xf4+Efׄ?C\xe6ٌub\xd9:\x8a\xff\x90\xc5#i\x9e\xd8\xcf\xf0\xaf>\xfd\xf4\xd3\xd7\xe9\x89\xe4\xfc\n\a\xcaf\x0e\xac\xe2\x1d\xa5\xbc_\xd3\xda.c5\x95?8\x19\xee\x86\xe5Z\x9b\xb8\xc4\x026\xa6v4\xcf6\x1a\x1dΞv\xf5s\x05\b\xd8\xdc\xc1\xcaz:T\x84\xc0\xd8_:j\xbaW\rg\a\xb4\xaf\x9c\x80=\xa6\xff\xf4\xa3\x87\x8f\xbc{n\xb7\xaa#\xb4\x85\xab\xd7\xc2Wo\xed{\x04\x97\xfdʜ*9\x87\xffS\xde\xf9$K\xf2\xc4c\x82\a\xf12\xeeA\xea\x81\xd2\x04\xec\xc8F\xf5g]<L\xbf\xb32fY\xc8f!\xb7h\x1d\x80'\xa9\x80\xbd#\xff\xfd\x91#\x96_\xb9M\xdeÛ\xecG\xb5\xbf\x16U\xc0\xfe\xbe\xe9]\xf9ݲ\xeb\xa23\xbe\xc610\x04\xacߕU\xdb\xdes\xbfE\xc0\x94>\xfbC9\xc8EWݭ\xd6\xfe\x96\xc4|\"Ai\xd2\u007f9\xf2W&`\xfcq\x90\xe5w\xcd\xf2jE\xff\x14\x9f\xa3\x1f\xd6\xd9m\xae\xe8\xda\xe4\xd0\x15\xa5W\u009f!\xeel\xc68\xb1\xcf~\xfa\xe9\x17\xd7-θ\x13\xcb́\xf1~\xf9\x03e'`\xefɟ\x16\xb1\xda.c5\xe9\x19꒗\x8b\xa5\x15\xb0\xf1\x16u\xb6\xefæq\xf9\xa4z\xb5vk\x17\xedr\n\x98\x1aR\xf7\xbe\x12\x1b\xdb(\x1cG\xc3r\x89;]\x1fwr\x02\xa6_y\x8f<F'H\xf7Y\x04\xec\xd3#t\x9a\xfd\x1d/\x95\x81\xf5\xcf\xd3}o\xe1\xaf\xe4g*\xe9\x05q\xbd\xf2i\xc1\x83\xb6\xf9\x96\xfaw\xdbr\x17\xf2G\x9a\x95&\x1e\x9c_!c#\v\x99\xff\xe3\xfb\x9f\x8c\xbfh\xcb(\xde\xf3\xfe\xb7\xf8+\xb7\xc9{\xd8\xf7\x98\xd2o\xd0\xef\xefG\x130\xf9\xf9\xbd\xf2\xde\xe7-Y\xf05\x8e\x81!`9\xf9\xf4\x80\x96X\x04\xec\xcc\x0e\xe5\x9f\xf0\xb1\xd4ò\\\x9e=\xc0\bE\xf5#\xabMZ\x81\n\x18\u007f\x1c\xe4?U\x1cy\xf8\u007f5\x1b\xad\xe8\xff\xabj\xf1ӳ\xba&Fяx\xd9j\xb2w\xf0_\x853\x14\xb5e\v'V?\x1e\u00914O,'`\x9c_\xe1@\xf1g>\n\x15\x1fȟ\xaeWk\xbb|\xd5\xfcA݅l\xed\xa4\xff\x8e\xb5\x9d\x94\xe5\x0e\xd6\xf5\n5\u007f\xa8\xeeY&\x01+(P\xbaQ\xa8\x8dn\xc6XQ1R\x1fe\xbaF\xa7\x1d\r\xc9\x1f\xa2Ry\xdc͌\xa2\b\xd8\xc3t\xe3\xfaV\x8b\x80\xbd\xa4\xces\xed\xa4\x8b ֗)\x97\xdeו;\xe9\xd4\x03\x9d$yG\x9b\x033\x05l\xa7\xb2\xef\xaf\xda}FQ\xc0\x8e\xe8C9M<8\xbfB\xc6\x15t\x0el\xcbNf\xa3\x17\xf2\x03\xd5\xe3\x91W5\x01\xbb\xbe\xf3g\xe2\xaf\xdc&WH\xb9\xe2\x97\xca?\xbf\xac\x90\x05g\x14C\xc0~\xe7\xfd\xb3\xf7w\x96,\xf8\x1a\xc78\xa8\x86\x80e\xd1?%\xe3\xab-\x02\x16P\x9fA(\xa8\x92\xe5N\xf5\x8c\xedR{\xbeÁY\xab\x919\x01\xe3\x8fÕ\xc7^\x92\x9f\xdbm\x99\xbe{\xecae\\\xfc_^K\xcb\xe6\x8a\xfe?\x1b\xf7\xd2\x1bs;+\xc53\x14\xb5e\v'\xd6\x100\xfeHF\x150ίp\xa0\xf83\x1f\xe5\x98q\x02\xb6|\xd5\xfcA\t\xd8PcWp$\xc8&\xf1G\x1a;\x87F\xce4\xd1\x15\x15\xf2\xa5\xd1\xd1\xe6\xeeQ\xcb\xf4\xf8\x92\xb0G:p|\xadcD\xbe\xda\xc7nHFiV>\xb4n\xf6\x8f:_:J\xdb\xdd\x1e\xa9:\x90B;\x03\xbf\u007f\x13\xbfN\xef\xfa\xfd\xfdw\xec\xf6\x11[t\xf0\x12\xde\xf7\xe6\xab[\x95\xde\xf6'\u007f>W\xf4\xb3O\xae\xff\xfegE\xe7\xfe\xac\xfcZ\xfc\xd2o\xdf}\x86-\xa7\xa2\xb7\b\xdfzd#\x9d\x8cߏ\x8f\xfc\xf6\b\xde/z\xa0\xd7\xcc\xeb\xef\xee.V\xff\x0e\x9fA\xbd\xf4C]\x89\xff4[\x89\u007f\xe5\x93s\xe7\xbc?;w\xee+\x99\xf7kfL\xb3x\xe2w\x1f=F\xb3\xf8o\xedq\x01\xea\xec\xc8\x03\xfb\xdf\xfd\x8fg\x94kU]\x89/\xbf\xfb\xc0{W\xb8_\x85M\xa3\x90W\xde\xc3G\xbe\x96\xbf>\x82\x15[\xce\x19W\x06\xa5\x11T<Q\xa16\x1f\xd3\x03_\xe3\xa8\aU\xbd\v\xc9\xee\xe6\x06\xd0C\x87\x03\xf7\xa1\x8c\xfa>u%~CO\xcf\b\xfd5mOG\xbb\x9fݲ߁Jێ\xfbQ\x8b\xe6,\xcdr\xeb\xe5\u007f\xf7\xef\xa6k\x9a\xfe\xbc{\xff\xffr\xc7\xe1\xca'\xcf\xfd\xe8O\xf2\x17\x1b\x9f\xff䊾D\xfdwJ\x85?\xf3V\xbczt\x13.z\xfb\xb3\xe8G\x87\xf6Mw\xbe\xfd\xdb'\x8ah\x937\xce\x10w6\xa3\x9fX\xba\x12\xff\xbf\xf4\x02\x19θ\x13+\xac\xc47\xfc\x8a\a\x8a?\xf3\xb3\x8f\xd9g\x9b^\xff\xfa\x9d\xa2Ͼ\u07bf\xfbO\xcbVMJ\xdf\x0fG\xc0\xe4ѓmM\xed}\xec\xce\xe3\x97]\xad\xcd\x1d\x83\xf4\x82\x95ϰ\xc7\"\x1b\x97\xe1\x91бjgj\x81\xd2\xf9;\x9b\xc4&U\xa2hUs\x86u\xc9\x12\xcf\xc9쌪p\x97ǩ\x8ck䯋\xb1\xfa8\xa1\xf6\x04\xda\x13\xd4\xe0\xfa돬\xff\xd1\xfe\xb7\x1f)\xda\xf9\x9c\xf2S\xd1\xff\xa36\xcf\xc9o\xef|\xf5ᢊ\x9d\xec\xfc\xaf\xff\xe53\x1b+\x9ef\x8b\b\xaf\xbf\xb9Ż\x85\xad\x03\xe3<(\xea\xf0\xfc&\xefN\xedq\xb6/\x93\x1f:\xfb\xe5\xb8\xfa,$\xaed\x13\xb3\xbf\xd7\xe61\x94/\x9c_3cY\xde\xf2\xea\xbeb5\x8b\xa75[\xd6\v\xf8`w\xd9Ɲ\xef\xd1?\xb8\xeci\xb9\x9d\xf8\x81O\xb8_\x85M\xa3\x90\x1f<@\x17x\xbd\x8b\xf1\x03\x1f\xf0θ2(\xbc\xbe^\x9f\x106<\xf05\x8evPǜ\xec\x04\xb0\xf5t\xe3\r\x1e)\xa3\xb49[*`\xcfBRJ\x95>zA +%\xb3@\x9d\x84\xe8\xbc?ùF\xbb\xf7۔\x86,\xdd\xf7\x970\xa6\x13:\xcf\xd1\x15i\xe6q\xf8@)\xdf\xf3\xf2\xf3J\xd1?2\xcaK\x8f\xea\x17On\xaa<\xf2v\x91rZ\xa2\x1e\x1d\x99>$\xe8-{\x92-P7\xce\x10w6\xa3\x9fXzP\xb7\x18%ҝq'V}\x16\xf2%\xf5\xa0\x19~\xc5\x03ş\xf9Y\xc7\xecz\x99r*\x8aq\xf1;\x18\xef]\xb6j\xcac\xa3\x03\xa5Ҩ\xbc\\,\xb5\x80\x01\xb3\x10\x96\xc9\xdbs<g\x8e\xc9\xeb\xbb\xc6<\v\xb9\xb4\x1cG\xcb\xf0\xa7\x0fPـ\x90\xfb\xb8\x9d\xd1\xdd\x03\x04lٙ\xb76|yv\xd4\xcedљw!\x97\x8e\xf1fg\x95\x9d\rp\xd7\x18\x1dX\xa6\x05\x14* `\xcb\xce\n\xd6\x06\x93\x15\\\xc8ь\x1a\xf1\xe1\b\xe0\a\x04\b\xd82\xf3'65jg\xb5\xcc$D!\x81\x1f\" `\xcb\f\x9b\x1a\x8d\xf2r\xb9\x15EB\x14\x12\xf8!\x02\x02\x06\x00@\xc2\x02\x02\x06\x00@\xc2\x02\x02\x06\x00@\xc2\x02\x02\x06\x00@\xc2\x02\x02\x06\x00@\xc2\x02\x02\x06\x00@\xc2\x02\x02\xb6B\x18\xb73\x00\x00`\x16\xe4\xff\xec\x02\x00\x00HP\xfe\xad\x1e\x18\x00\x00\xc0r\x02\x02\x06\x00@\xc2\x02\x02\x06\x00@\xc2\x02\x02\x06\x00@\xc2\x02\x02\x06\x00@\xc2\x02\x02\x06\x00@\xc2\x02\x02\x06\x00@\xc2\x02\x02\x06\x00@\xc2\x02\x02\x06\x00@\xc2\x02\x02\x06\x00@\xc2\x02\x02\x06\x00@\xc2\x02\x02\x06\x00@\xc2\x02\x02\x06\x00@\xc2\x02\x02\x06\x00@\xc2\x02\x02\x06\x00@\xc2\x02\x02\x06\x00@\xc2\x02\x02\x06\x00@\xc2\x02\x02\x06\x00@\xc2\x02\x02\x06\x00@\xc2\x02\x02\x06\x00@\xc2\x02\x02\x06\x00@\xc2\x02\x02\x06\x00@\xc2\x02\x02\x06\x00@\xc2\x02\x02\x06\x00@\xc2\x02\x02\x06\x00@\xc2\x02\x02\x06\x00@\xc2\x02\x02\x06\x00@\xc2\x02\x02\x06\x00@\xc2\x02\x02\x06\x00@\xc2\x02\x02\x06\x00@\xc2\x02\x02\x06\x00@\xc2\x02\x02\x06\x00@\xc2\x02\x02\x06\x00@\xc2\x12\x8f\x80\xc9\xf5\xf9\x19)\xaeu\xafD\xec\fc0F\x13\xb6\xa1\rvv\xf3\x87ynE\x0f\x99\xbfē\x8d\x90`!\x1cF~;\x13\x00\x00\x96\x808\x04\xac9\x15\xa9\xb8G\xecL\xa3r8u\x92ħ,\xf3E\xf5\f\x02\x06\x00?T\xec\x05l\x0fB\x05\xbd\xdfF\xc2\xcdYH\xea\xb73\x8eB\x04!*3\xa3\x87{\xec,\xe7\x8b\xe6YУx\xb2\x01\x01\x03\x80{\x04[\x01\xebA\xe8\x17\xea\xd6\xe4\xfd\xc8\xf9\xed\xdc\xc6\xd1\xd0d\xe6.\x10M\xc0\xe2a\xde\t\xac\x80\x80\x01\xc0\xca\xc0V\xc0\xb2Q\x8d\xbe9\xe9B\xd5s\x99F\a\x04\f\x00\x80\xbb\x84\x9d\x80\x9dAIW\x8d/-(-B\xdb\xff\x81P\x893=\xff\x84\xfa\xe3\xd86\xb7\xe4\xdc0@7\x9bQ\xe3@vj^\x98\x90\xbe\xd2LɑS\xf7\r!\xb5l\xfalT\x9f\x9c\nUe\xa587\xb0\xa1h+j\xf8v[\x96䮛\xa0\xdf\u008f\xbaS\xd2\xd74\v7\nb\x1a3tϊ\x1e}\xb3-Sr?>E\xf49\xb0h\xceµ\xd9J9\x83\xcc\x17\x97\x80/\xab\x98\x8b%K\xae\x9e\xaa\x80\xe5\xa2Z\x02\x00\xc0rb'`{\xd0}\xe6\x97q\x84\xfai\xc3.M\x93\n\v\x92P\x15\xfdm\xc0\x81\xa4\xd5n\x84\x02\x84\nضU\b9\"\xa4\x1a\xa1\xcc\xd5.\xe5\x9f\tr\xbc\x14\xa1\x92\xd21MY:RP\xda}\xca\x0e\xda\xf4[QM&Jw\"\x94\xa3\b͗\xe9ș\xe7A\xe8A.\xef\x98\xc6*\xba\xe7V\x94\xebB.eWnD\x13\xb0h\xcezSQZ\x9e⬇\x88\t\xf8\xb2\x8a\xb9\x88Y\xf2\xf5\x04\x01\x03\x80\x95\x81\x9d\x80\xad\x13F\x8dY\xa8\x996l\xe4Q:Y#Nt\\闤\xa3\xda[\x84\f:Q\x17\x15\xb0$Ow\xff+\xa4\x1f\xa5~\xa8X\x0f\xa6\xa1\xc3\xc6@\x8f)\xcbH\x12\n(j\xd0)\xa1\x16Տ\xd2!\xea\x91P;!\x1bPݴ\xb2?\x1d\xf5\x1a\x99\xc56\xd60\x86\x90({H\xe9H\xa5\xd0\xf2\xb0l\xa28\xbb\x9a\x86\xea\"d\xe6\x00Z5!&\x10\xca*\xe4\"|\x11\xea\xa9\nXG\xe3 \x01\x00`9\xb1\x13\xb0<\xb4\xc7\xfa\xad\x95\x8e\xdb\x14N 7\x1d\xc7\xf9\x88\xfa\xc5C\x05\f\x85\xe8\x97\x1dZ\xa2\x1dT\xfdx\x01+\xd1&\x8f\xdaPF\x84\xfaa\xd6U\xb4+\xe7V}6\x95\xf7\x19\x99\xc56\xd60\x05L\xdbU\xade\x13\xc5\xd9\x1e\xb4\x8e}\x16\xa061\x81PV!\x17\xe1\x8bPO\x98\x03\x03\x80\x95\x81\x9d\x80\xadF\xf5ܷ|\xb4\x8b6\xec5\xecKDR\x1ax\x16\xeaV\xbf$\xa1\xb0\"`n\xd5.\xa2\x8e\xf3\xeaiC\xe7\x04,\x92\x8a\x86\xd4\xfdi(\xa8\xf8\xc9a_\x9aP)!\x85(?8Mx\xe60\xd6-t\x01\xcb\xd5v=\xa4\t\xd8lg$\a\x9dd\x9fcW-\t\x84\xb2\n\xb9\b_\x84z\x82\x80\x01\xc0\xca\xc0N\xc06\b\x13=٨\x816\xec]\xea\xb7\\\xd47\x85Pn>#\x05\xf5+\x02\xb6N3\x8c\x04\xdb\x03\xa5n\x846\v\x02\x16FH\x9b\xc1Z\xa3\x8c\xdeZ\xb5N\rӜ\xa0\x84Pz\xe9qn\x99\xc6\x1c\xc6z&\xba\x80\xa9\xbb\x8e\xd3\xcf\x18Έ\xa4\xf6\xa6\x18B\x02\xa1\xacB.\xfc\x17\xb1\x9e `\x00\xb02\xb0\x13\xb0:\x94o~\x99DtV\xa9U\xef\x94\xe5\xa3\x13\xe3ȤK\x110\xad{\xd4\xe4\xa2?\xac^c\x11\xb0Q\x94\xacy\xf2\xa1f\xa2\xaffP5)\xb4١$I\xae\xbe\xa5g6\x97\xb1\x8ae\x19\x85)`\xb3\x9d\xddBh\xccH'$\x10\xca*\xe4\xc2\u007f\x11\xeb\t\x02\x06\x00+\x03;\x01\x1bBIf\xcb?\x8eR&iîS\xbf\xe6\xa03\x8a\xa4\x85Mc]\xc0\x0e \xf4h\xc7\xf0\x14i\x88\xd9\x03\xcbg\x9d*Q\x93\"\x83\x81\\dJ\xc3\xdc\xc6,AL\x01\x9b\xe5\x8c \xa1\a\xc6%\x10\xca\x1aS\xc0\xc4z\x82\x80\x01\xc0\xca\xc0N\xc0\x88\xc7l\xacS\xd9l\xbbU\x1b(\xdeJQz5\x19\xf4\xae\x1ce0<\xad\v\xd8t\x1ajc\xbfm\xb3\b\xd8\xf4*qZ\x8bS\x8bp\x90m\xb7\xa0d}\xf2j\x0ec\x8d\x98\x026ۙR\r\xf5\x11\xa3\x93\x85MB\x02\xb1\xac1\x05L\xac'\b\x18\x00\xac\fl\x05l\x10\xa1\x03\xea\xd6-\x1fJ\xbdDh\xc3Na\x9d\xb2ct\x89X\x15ʛ\xa1_\xfa\x904\xa1\v\x98\xacuw\xa62\xe9\xf7hw!\xdbQzD\x10\b%\x89L\xb7C(\xc9X\xe7\x15\xd3X'\x96\x80EsV\x8bJاO\xa9\r\x9f@,kl\x01\x13\xea\t\x02\x06\x00+\x03[\x01\xa3c\xac\a\xfb'\xc9\xf8\xf1l\x94\xd4M\u007fhE\xe8>E\xc1\xfaR\xe9\xaa\u0590\x84\xaa\xa7\x94\x91\xa6\x13m3\x86\x90\xd3\xe9l\xe6\u007f\xbc\x10\xb1I\xa6\x14\xd4ukZ\x95\x81\x91dT\xafhJw*j\xb2\bă\xa8P\x11\x9d\xa9R\xe36\xc0\\\xc6:\xaa\xe7\xd9=\xb0(\xce©\xa8~\x9a\xcc\x1cB\x8eq\xb1\a&\x945\xb6\x80\t\xf5\x84u`\x00\xb02\xb0\x170ҡ\xbfN'\x93=G\xa34\xec\xecU\xc9\xf7ek=\xb3n\t\xad\xcaS\xbe\xdc\x1f1\xe7\xc0\x9a\x10r\xfb\xf2\x92\x9c\x01\xb6^!OI:\xa0)OG2J\xcf\xcbDT\x05D\x81\xb8\xe4DR\xce\xeaT\xe4⦚b\x1a먞g\vX4g=\x12r\xe69QJ\x8f\xa5\xcb&\x945\xb6\x80\t\xf5\x84\x95\xf8\x00\xb02\x88C\xc0\x88| ?=)c]\x9bvOOiأ\xbe4\xa7\xef\xac\xfa5\\\xe3\x96R\xf3\x9a\xe8`\u0378\v\xd9\u007f\u007f\x86\x94\xb3\xe7\xdb)\x89\xde\xfb\v\x15\xacJ?\xa1+Ϩ?S\xca,\x19\xd0\xfc0cu\xcf\xd86\x8f\xb4JI\xc3g\x1c\xd3XC\xf5\x1ce\x12?\x9a\xb3PUfrF\xf9(\xb1\b\x98P\xd69\x04\x8c\xaf'\b\x18\x00\xac\f\xe2\x110\vz\xc3\x06\x00\x00X^@\xc0\x00\x00HX@\xc0\x00\x00HX@\xc0\x00\x00HX@\xc0\x00\x00HX\x16 `\x00\x00\x00+\x03\x100\x00\x00\x12\x16\x100\x00\x00\x12\x16\x100\x00\x00\x12\x16\x100\x00\x00\x12\x96E\x13\xb07\xf0\x8b\xd1w\xc0MK\x00\x00\xee\x12 `\x00\x00$, `\x00\x00$, `\x00\x00$, `\x00\x00$,v\x02v\x1a\xff\xfa\xbb\xe7ʼ[?&wNoY_\xf1\xe2M\xf6\xeb\x1f\x0eV\x14y\xb7\xbc\xfcO\xf6\xe5\U000fd6ca\x9f\xba\xa8\t؍\x17+\x8b6\xed\xbd\xc0yP\x04,\\\xeet\xe4w\x10\xfa\x96z5\"#9`\x04\xfc\xeeI\xd6^\x97\x98\xdcM옏\xed\x029\x84Rh8\xef>\a:\x14ݠ\x9f\x15 \xe3!\xee]\x89\"\x1d\xca\xeeC\x8a\x1fD\xe3~\xdb1\x92\xc4\xdc%\x8d\xa8_\xc7R\xd8\x01\xaaV~rD\xc9 \xe4K\xcb\xf4\x0ff\n\xaf9\x03\x80\x1f2\xf6\x02\xf6\xe2&\\\xb6\x1e㏟\xc5\xde2\x8cw\xd3\x1f_ĸbk\x85\xf2\x0f\x95\xb3S\xf4KQ\xd1n&`\x17\x8a\xb1wk%Ư\x99\x1eZQ\xae\x13\xe5z\x10*'d\"E\v\x0e\xe4AAmw#\n\x06\xdbPK0\x88\x1aI,Ύ\xc4o\xbb@\xf4,&\xfc\x0e\xfa\x96C\x9f\xc3?\x11\xdd0\x12L\xa9\x0e\x0e\x1e\xf38\xcc(G\"S\x1d\xe8\xf0\x04\x99hB\x1dS1,\xcc\xdc\xc8\xf4\x10\xabА\x1e|d\xa8ZR\xfe\x1d\xa7\xd5\x1c\x9a\x95j m\xcd\xf1\xce<!>\x12\x00\xfc\xb0\xb1\x170\xbc\xe52\xb9}\x10{\xbd\xa7\uf40f1\xbe\xa8\xa8\x14\xf6~\xae\xec\xfa\xbc\x18\x9f\"\xe4\"~@\xd9\xf1\xfdS\x98\n؍b|\xf4\xb6\xb2g\x13\xfe\xd8\xf0ЊP\xb6\xd2\xd8\a\x1c4\xfcO\t\n\xd0\xdfF\xf4\x10\xdeJ\xa7Li\xb1ô\xb5\xa6\xb6\xcc\xce]c\x8d?~\xdb\x05\xa2gA\x02%\x8e)2\xe9(\t\xc44\x95\x1a\x94\u007f\xa6\xdcܛaEB\x88\xbeC\xf6,\x8a\xa5p\x84ˍh\x152h\x90\xa2\xfdʘL/\x8d\x10r\xcb\x03\x02\x06\x00:q\b\xd8e\xe5\xe32\xc6oЯ;\xf1iB\x8e>\xf02\xdbw\x14\xbf@\xc8A|\x94n\xdf,\xa3\x02v\x14\xefe{\xde\xc7?6<\xb4jq\u007f\x8e\xa1le\x10\xa8*\xd7.d\xe8C$\xac\xb5ְ\x11Ah\x16\xf9\x9b\xe3\xb7] z\x16$\xe0\xf7u\x91\x13>\xbf\x8d\x80\x91\x86ԙ\x18\xfb\xe3\x100#72\x0f\x01\v\xa4\xb2\xb1c3\b\x18\x00\xe8\xd8\vX%\xfd\xb8\x8d\xf1\xdf\xe8\xe7A\xda\xe9\"\xb7o\xb3}o\xe0gɝ\x8d\xb4OF\xa8v)\x02\xf6\xb0\xd6\xf3R̯\xe9\x1eZ\xd1Z\xf69\x95\xa4\xb4\xbc\x88\x936\xcc\x19\x97\xd8\b\xcd\xd6z\xa2 -\xe7q\xf6\xee\xfd\xa0ϝ\xe2*Q4\xafW\x9b\xf7\xca\x17lG\x93\x11\xaa\x0fWe;6L\x93\xa9\xcdY\x92\xbb\x94\xbe\xed\xbe\x16\xa5\xb4\xd7\xe58|ょZ\x94\xdcZ\xe3\xce(U\xf3l\xcbw䵉\x1e\xf8,\x02\xfe\xb6rR\xf2\n\x150\xd3oH\xb1-%n\x84\x9c\x11]\xc0\x1a\x93#\\y\xf9\xe2\b\x02\xa6\xe7f[!B\xe4\xaa,gy\xf5,\x013\x0e\x89\xa7\x86}\x9fh\x8ep~\xb9\x1aG\xaf<\x00\xdc\xcb\xd8\v\xd8S\xf4\xe3_\x18\u007fO?\x9fe\x02Fn\u007f~\xfa\xb5\x83\x95X\x11\xb0\xef1\xbe\xad\x19\xbeHn*\xe3\xcd\xed\x8c\"l\xcc\xe3\x1b\x81\xbc\xb3i\x18\xb6mh\x872\x9cDyB&Fk\xadI\xda\xd1\xd7\xeaʟ\xa1\x83\xccG\xbb\a\xda]h\x9a\xdc\n\x06s\x1e\f\x06\x83a\xc16r\xb23;'\xdd]W\x85\xae\x92>T3x\xb24iX\x11\x9a\xced\xe4jhN/'\xbc\a\xfak\xf6\xe1\x9fg\xb3i\xabj\xa9\xbe\xaf^\xaa\x12<\xf0Y\x04\xfc\xe3i\x93\xabd*`\xa6ߙ\xa1\x86\xa4!ҁNP5S\x05,?\x8f//_\x9c\x10\xea\x8bD\"\xfdH\xc8ͶB$\xec\xcc\xe9\xe8\xf5!\xab\x80\x99Y$q\xe3f\xc3/W\xe3\xe8\x95\a\x80{\x19{\x01\xdbG?\x14\x01c\xb7\x1c\x99\x80\xdd9U\x861~`\xebNE\xc0\xaea\xac\x1a\x9eW\x04\xec;lbL\x82\xb5\xa2zuc5\xea&d\b\xb9f\x88\x1f\x89sXzk\xedC\x1d\xec[\xa7\xd2\xc3pѶ\xd7\xe6d\xbfG\x1fq\xe5#ߔ\xd2MR\xa4\xa8\x8bN\x97籈H\x92S\xe9\x80T\xb9\x88\xe8A\xcaV,&\xdd\x05\x84\x9caݣ\x01\xaa\xa5\x9c\aa\bI\xf2\xb6\xad!T\xc0x\xbf\xa4\xba`\xc2}\x98mI\xf5\x91[\xa3\xe5\xe8C\xa1\xbc\x9c\xb3\x90\xd6\xc3\n\t\xb9\xd9Vh\xadG\xe9f\xcd\xe4Y\x04\xcc\xccb\f\xf5\x1ai\xf8Z\x985\x8eQy\x00\xb8wY\x88\x80\xbd\x81\x1fx\xe1\xf4śl\b\xa9t\xbaԕ\x15\xef\xab=0c\xe4hЊ\x1eW7ܴ\xcd\x13\x0f:\x1bq$\x8b+\x01\xf4\xd6\xea\xf7LS\xdcՄ\x8cgyj\x8f\x8f\x12\xb5\a\x11C\xc0\xa4\xab\xda\xd6D\xdb\x06\x8fS\xed\xd5Ity\x06\x9bH\xe2=HlF\xab\rM\x92\x9a\xd5,\xc5\xeajу `M\xa8\x91\t\x18\xef\x97D\xf22\x1fR-$\xaaN.\xaa&\\y9g!\xd4<<<\xdcB\x05\x8c\xcbͮB\x93ꪋz\x8b\x80\x99YL'\x9b\xaa\xcf\xd7¬q\x8c\xca\x03\xc0\xbd\xcb\x02\x04\xecv1\x9d\xc9't5ų\xe4\xce&\xfc9\xfb\xf2\x1a\x9d\x03+\xd3;^\x9f\xff\xe3_\xba\x87V-\x92\xe3$Btv\xa6\x01\xd5\xf6\xf3\xb1\x1d)zk\xcd\xd3\xfa.\xb4\xcf3پ9\x17e\xaa\xcb%b\bX\xbe\xfeS\xa6{OOp\x9d*`t|\xa76g\u0383:\xea\x1bD#d\xad\xaaB%\x05\x82\aQ\xc0&\xf6L0\x01\xe3\xfd\x12ҭ\xaf\xfc\x90j\x86\x87\xd5\xe1\x1f_^\xd3\x197\a\xc6\xe7fS\xa1\x11սu\x12\x9f\xcbB\x9b\x03\x9b\x1e\x10\xfdr5\x8e^y\x00\xb8wY\x80\x80\xfdS\xbd1InV\xe0\x83\x84\xbc\xa0\xa8\x98\xc2\xedJ*`\xcf\xe1\xedw\xe8\xb7?`\xef\xf7\xba\x87V\xb4\x8aM+\xff\x02\xb1n\xc3\x18rע\x93b&zk\xad\xf2\x8c0&\x94\xf6L{@S\x9d\x0e6\x01\xce\xda{\xc7U\xc1V\xf9\xb5\\\xdb\xc8-\xa0\xd3\xda\xe5\x16\x01\xe3=Hl\x1a\xae\x1dM\x91j\x0fK\xe2\xa9\x16<pY\x04\xd4\x15\x0eT\xc0x\xbfDάϞ$F\x16\f\xae\xbc\x9c3N\xc0\xb8\xdc\xec*4\x89\xd8\x1e\xeb$>\x97E\xc0\xc1\xfa\xad]hB\xa8ET\x01\x13r\x03\x80{\x96\x05\bؿ6⣊Lѥ_{\t\xb9\xb6\x1e\xff\xfa\x0e\xb9y\x90\xad\x03\xbb\xec\xc5/(#ʋ\x9b\xb8\xe7\x8aZ\x11\xcaS\x14줤\xcd\xe1\u070f\x1c\xe9\x96U\x10zk\x1d@]\xf4\xa3\xfe0\xed\xa8\x9d\xa1\x9b\x85\xdbؿ\x85\x84|\xab\xee\xe3\x05L\xefƸ\xa9t\xcc\xe4Y\x04\x8c\xf7 eN\xd1\x15T\x85tN\x89NXu\xa2>\xc1\x03\x97\x05'`\xbc\xdf\xe9\x82z\xb2\xcd7cd\xc1\xe0\xca\xcb9\xe3\x04\x8c\xcbͶB\x05nE\x1fë,\x02\xc6e1\x99^\xae\f\tg\n=b-\xa2\n\x98\x90\x1b\x00ܳ,@\xc0\xc8\xdb\x18W>\xf5\x13\xbc\xf1e\xbcU\xf9\xe9\xe3\"\\\xf6\x13/\xde\xc74\xeb\xfcz\xec\xdd^\x89\xf1\xeeۆ\x87V\xe4KM\xb9ύ\xf4\xb9\xfc\xe3\xc8x\x8cHc\xa4\r\xb5\x8c\xb0\xad\x00\xf2\x9f\xec\xadF'h\vL?\xd0\xd7S\x8d\x06\xe9\xcf\rRs\x8f/m\x9c\xb7\x9d\x1eb\xb7\xf2\xc6\xd8n\xb4\xb9\xedp>r5\r\xc9\xc1\x94\xea!2R\x9d\x12\x94\x05\x0f\x12\xca\xef:\x9e\xe3\xa4\x03\xbf\xaa\xa4@_ \xa9J\xf4`f1\xe9_\xf7\x8d\xf2\xf5\x9bu\xfeI\xceo$X\xeb\x1a'\x97\x9c\xbb\x82\x11\xba\x12\xdfX\x03b\x94\x97s&\xac\xc47r\x8bQ!n%~\xc8\xe1>T\x9f\x91\x94\xdc\x11RW\xe2\xb7\x04\x83W\x85CB\xce8\xee\xef\xe8\xf5%\a\xf9Zp5\x8eUy\x00\xb8wY\x88\x80\x91\v\xbb˼[^\xfe\xfef\xd1\x037\x94o\u007f;X\xe6\xdd~\xe1c\xb5\xd3u\xed\x85\xca\"\xef\xf6S\xa6~)\x02\x16\x18\xf5\xa59\xd6\xf6kߧ$\xe31\"\x95[\xe9\b\xa1T\xf5\xb9\x9b\x81u\x19Nfy\xa2\xf0\x90;%\xb3Pm\x80\x91\x1d\x19\x8e\a\x87\x05\xdbQ\xf5!\xc2\x12\xfa\xe3LK\x8e\xe4\xf2wx\xa4\xc2Z委P\x9a\xf2o\xad\xe0Az\xbcڙU%3g\xc7\xf2\xb4u`\x9c\a3\x8b\x06\x84\xe8T\xd36\xfa<\xa3\xe9w@1\xac#;\x94\u007f\xcf\xd2g!W\x1be\xd7\xcb\xcb9S\x9f\x85T\xfc\xb0Yy=\xb7\x18\x15\x1a垅\f\x97fd\xef\xe9HV\x8a^\xadM|\xf9\xf9,\b}\x16ґY\x1a\x12j\xc1\xd58V\xe5\x01\xe0\xde\xc5N\xc0\x16\x9fK\xe6cDK\x869\xea\x03\x00\xe0\x1eb\xe9\x05\xac\x1e\x1d\xb03Yt@\xc0\x00\xe0\x9ed\x89\x05,4ֵJ\x92\xed\xac\x16\x1d\x100\x00\xb8'Yb\x01+G\b-\xb9\x98\xa8\xb3\xdb\x00\x00\xdcs,\xb1\x805\xa5\xba\x96~\x00\xc9f\xb7\xc7\xec\xac\x00\x00H8\x96X\xc0\x00\x00\x00\x16\x0f\x100\x00\x00\x12\x16\x100\x00\x00\x12\x16\x100\x00\x00\x12\x16\x100\x00\x00\x12\x96\xc5\x12\xb0\x1b\xc2\xc3C\x0f\xc56\x04\x00\x00X,\x16G\xc0\xee\x9c\xf2\xde4\xbf\x81\x80\x01\x00\xb0$,\x8e\x80\xdd\xd6\xdf\xcb\xca\x00\x01\x03\x00`I\x00\x01\x03\x00 aI\f\x01\xeb-\x88\x11';~\xb6\xd5\xd8Y\x00VV\xca1\x9b\xbcߌgr\x17X)\xd5\x04\x16\x80\xad\x80]{\xe1ᢍ;\u007f\xa3\xce\xd1\xdfx\xb1\xb2h\xd3^\x161\xed4~\xe3\xfb\x17+\x8a*_\xfe\x9eƄ\xa4\\֓(\x02\x16.w:\xf2i<\x9d\x16\x94\xab\xfex@x\x8d\xe1\xe4\xb6LGI\xacȰ\xb3h\xfc\xf7\x9f\x9f\f\xa3\x00\xa9EI]vvQ\xa0/\xf8B\xae\r#vv\xf3\xa5\x06\xa1fB\x03\xd5\"k\x03\x1ap\xdd\xd5\x06\x1b/+\xe7\x985%\x1d\x8e\xfa\xfb\xa2\x1c\xa8\u007f\xa3\x9a\v\xa4'Y{\xe1[r\xb7\x9d\xe9\xbcl\x17\xc8!\x94B\x0fc\x9f\x03\x1d\x8an\xd0\xcf\n\x90\xf1P̈\xca\xea;\xf0\x0e!\xf5\x1dx6\x8cp\xef\xc0S\x18Ka\x12A߁爒Aȗ\x96\xe9\x1f\xcc\x14\xa3\x00q\xd8\t\xd8\xe5b\xbci\xfb\x8f1\xfe)}\xd7\xfd\x85b\xec\xddZ\x89\xf1k\x84Ł\xac\xc0ś0\xder\x9b\x9c>\x88\xf1\xbe\x837\xf44\xad(\u05c9r=\b\x95\x132\x91\xa2E\xa8\xf6\b\xaf1\xf4e\xbeR\x9d:I\xe2\xe3XR\x87\x9d\xc9lΊ\x8d\xa7jշ\xf4\xa1nN\b9\x83\xb3s64\xfa\x8a\xd5\xc1\x8e\x82E\u007f\xbb\xe9xz\x13=\x02\x93M\xe9\xe3\x96=}i\xdd\xda\xd6\xdc%[lV\xd81\xe3\xb2\xe8Kn\x8dfa\x1e\xa8\xf9\xb0x\xd5\\\xa0A#\xd2^\xb9\x8bbG]ѓ\xc5c\xbb@\xf4,&\xfc\x0e\x9f\xf2\xe1s\xf8c\x8cs\xe8[\x88\x83\x83\xc7<\x8eP\xf4\xfd\xe2[\x88c`\x1c\a\xee-Č!\x16\a\x82\xbd\x85x\xf6+\x17\x06\xd2\xd6\x1c\xef\xccC\xb1\xa3\xd1\xdb\t\xd8>\xfc\xb2\xd2\xf9\xba\xb8\x11\x9fW\xfa_\xc5\xf8\xa8\xf2\xe5\xf3M4\xf6\xd0i\x8c\u007f\xfc9!\xe7\x8bh\x88\"\xeb\x10\x12e+U\x1dp\xd08\x15%\x88Ɨ #\xc2k\f'Q\xab\x16\x8f1\x0e.\xa9A\xd1\xe6\xc9\x1a?\xff-\xacF\xd7\xe5_\xab\xc3\x19\x88\xb6\xb3P_r\xbf6gN\xa3\x05\x90\xa7\xea\xf2q1ʯ\x80M\xc9\xe6\xc9D\xe1\xdc#\xf1\x15v\xcc\xf8,\xea%\xab\xca/\x9cE\xac\xe6\xc2\fZ$-\xe8A\xaa\x18\x1f\x95GO\x16\x8f\xed\x021J\x16(qL\x91IGI\xecvƎΔ\xdb\x12M\xccD\x88F\x1f\x1d\xfe8\f\vRe\x8d\xc4\xc51\x99^\x1a\xa1\xd1,\x16.`\x95\xea\xc8\xf0\xed\x83\u007f\xa0#Ž\xec\xb7\xf7\U0004f640\xb1=\xcf\xe1\xe7\xa2\b\x18\xab\xc81\x94\xadt\x81U\xe5څ\xf8\xa3\x13F\xf3\xe8\xfaWgݲ3\x89\x02\x1f\xb9\x8c\x06\xfba/!\xe3\xafR\xce@\xb4\x9d\x85zv\x8e\xa1\x85\x14c.\xca\xd5(\x01\xf5fl\xa4Yؔl\x9e|9\xd7\x05FV\xdc1㳸\x95e\t\xa4\xf0o\xb0\x88\xd5\\\x98A$\xac\xb5ְ%\xba\r\x87\x9e,\x1e\xdb\x05\u0085\x12\xf4u\x91\x13>\xbf\x8d\x80\x91\x86\xd4X\xb3>q\bX\xf4؈\x949\x04,\x90\xcaƎ\xcd\v\x17\xb0\x9f❟\xeb!\x1e\x1f֢>ަ\xf1kO\xe3-\xec\xcb)\xfa\xd2|\xab\x80\xade\x9fSIJ\xbe\x11'-\u058c\xcb,\xc2t\x86:\xa8\xaf\xa3/\xbaI:A\xc6$:\b\xaeE)\xedu9\x0e\x9f\xfa\x876\\\xeeJ\xc9\xdc\xc0\xae\xac\xe9\xf4=\xec\xa7\x03J\x92N҉\x8c\xe8 \f1ى\x82\xb4\x9cǕ6ӫ\xcd\x1b\xe4kVcɻا\xb4G\xb3\xe5\f\xb8\xcdZ\x94\xdcZ\xe3\xce(\xb5\x1c-\xf5\xecT\xb9\x85,\b\t\xfa\xdc)\xae\x92lk\xb2\xb6|\xfdm\xf5\\\xc9\f[ރ\x19\x00i4Y\xa9U\xb8*۱a\x9aL\xa6\"\x94\xc4b}\x8b\xb5Г\xf1\xb6Q\x89aК\xd3\x17Fᾜ\xb6\xe5<fS{r\xd3\x1f\x1cr\xf7\xf3g\x9eD=\xa8\xd6\xe2ԧZ\x1b\xb0y\xa0\xc4\n\xe9,A5\xa3\x9f\xa19jab\xb6V\xfbd\x9a-\u007fb\xa76gI\xee\xd2Q\x12\xeb:\x8b~Mr\x1e\xf8,\x02\xfe\xb6rR\xf2\n\x150\xd3o(\x99F#u#\xe4\x8c\xe8\x02֘\x1c!\xd1/DA\xc0\xf4\xdcl+D\x88\\\x95\xe5,\xb7\x86\x12\xe4\x0e\x89\x16\vu\xa29B\xa2\xb6\xacZd'`\x9f\x17a\xbc\xf1\xe0i*O71\u07b2\x9dQ\x84/(\x02\xa6v\xc7NG\x13\xb0:u#\x1b\xf5\xd3\xf8\x18;ht0n\x9c4\x1a\xecD\r\xc1\xe07D\x9bz`\x83\xe0Pg2r54\xa7\xb3\xee\xc8`z~\xd3@\x03b\x9d\xe6\x11m\"e\xc2_\x10\x9c\"S\xc1\xb5~~BOHV\x93\xb4\xa3\xafՕ?Cn\x05Y\x90\xa0\xa0~\xb9\xd5h\x03\x10\xa5\xc1t\xf6f*\xb6\x9c\x01\xb7I\x9de\x1f\xfey\xb6e\xac\x1fB}\x91\xf0\x1etX\xc8B)ף\xdd\x03\xed.4-&\xab\x96\xea\xfb\xea\xa5*\xb1d\xa6-\xef\xe1\xf8\x1a2\xe4\x1e\"\xf9\xc7I\xe4dgvN\xba\xbb\xae\n]U\x8c\x83A\xf5z\x11ja$\x13l\xa3\x11\xc3@\xaeB\xab\x95\xff6\x8f/\xe31\x9b\xf4\xb8\x9a\xfak\x11j\xe3\xcf|\xf4\x97\xdcG\xa5\x00\x00 \x00IDAT\x83j-Np\xf6\x9fg\xe3@\t\x152X\x82jF?Cs\xd4\xc2\xc4h\xadq$\xd3l\xf9\x13ۇj\x06O\x96&\rǺ\u03a2_\x93\x9c\a>\x8b\x80\u007f<mr\x95L\x05\xcc\xf4;3Ԑ4D:\xd0\t\xaaf\xeaq\xce\xcf\xe3\xcb\xcb\x17\x87\x9e\xeeH\xa4\x1f\t\xb9\xd9V\x88\x84\x9d9\x1d\xbd>d\x1503\x8b$n\xdc\x1c\xade\x85:\xed\x04\x8c\\>\xe8\xc5\x18\x17\xbdx\x9b|\x87M>\xd6\xc3\x15E\x170\xad\x8f\xb4\x1au+\x17)r\xcd\x10?\x12F\xf0\xe6\x10\x92\x8fj\xe8T.\xa5*\x97\xb2\x15qoP\x14w\xfa$\x9b\xe5\xef\xd3\xfbn\x1d\xea_\xeb\xd5'\x88\x80\x99\xac\x0f\xd1I\xa5a\x163Q\xe8\xb1^M\xa9\xd5l3\x15\x975.b107\xa5\xec)\xa5\x99\xb9\v\bO\x88\xfd\xf1\xa0g\x84Ϣ\xcdE\xe5\xa8\xcd)&;\xc3\xfe\x14\rP\xe5\xe6J\xc6\xd9r\x1e\x82.\xb2G\xdaC\\L\xa0\xf3\x91oʘ\x17t\xe8\xe3\x19\xa3db\xddx\xdbhD78\x93\x82R\xfa\xd9\xd6r\x1d\xb3*'\xedTױ\x18\xbe晏qP\xc5\xc1\xd78\xbd\x96f\xa1\x1f(\xb3B<w\xbf\x9a\xd1\xcfP\xecZ\x98\xe8\xad5\x9ed\\,T\xfd\xc4F\xba\xe8\xd9\xcdc1\xe1\xa3^g1\xaeI\xfe\xd2\xe0\x86\x90$o\xdb\x1a\x16\v\x95\xf7K\xaa\v&\xdc\xea\xed_\xa9>rk\xb4\x1c}\x18\xebB\fi=\xac\x90\x90\x9bm\x85\xd6zn\xd1ȫ\x16\x013\xb3\x18㦚\xa2\xb7,\xdb!\xa4\xc2\xed\xcf_ۊ\xf1\xb3\xb4\av\xcd\xfcuN\x01{\\\xddp\xd3\x1a\x13\x0f:\x1bq$\v\xf7A\xa3\vX\xb5\xbeُFM\xdb\x1e\xa4\xbdLu4)r\xabcrZ\xe2\xf6\x89\xc9\xfc\x9ei\x8a[\x8d\xba\xcd\x1d\xafZ\xfd}\xacR\r1\x86\xdcѯR6\rІ\x84\x1b\xa4!\xd4<\xd4W\xe0\xa0>\xb8,Ƴ<\xb5\xc7Gɴ\x98\xacF\r\xb9\xb6\x9a\xc5\xcc6J\xc6\xd9r\x1e\xae\xa2[\x0f>\xbavJ\xed(\xe5K\\\u007fi\xb6\x80\x89u\x93\x84\xbe\xd5l\xa2\x19L\xd6In\x94%\xed\xa1U[\xaec\xe68\xa0\xee\x13\x05,\xc6A\xb5\nX\xb4u\x0e\x86\x80\x19\x15\xe2\xb9\xfbՌ~\x86b\xd7\xc2Do\xad\xf1$\xe3\x04\xcc8\xb1\x13m\x1b<Nu\\\x13\xf5:\x8bqM\xf2\x97\x06/`M\xa8\x91\t\x18\xef\x97D\xf22\xb5\x15\x9d\x12U'\xb6f%\xfa\x85\xa8\x9c\xee\xe1\xe1\xe1\x16*`\\nv\x15\x9aTW]\xd4[\x04\xcc\xccb:\xd9\xec\xf7DoYv\x02v\xe7\x1f\x9f\xb3\xcf\xdf\xe0\xa2\u007f\x912m\x0e\x8c|\xfe\x8f\u007f\xcd-`\xea݊I\x84h\xf7\xbc\x01\xd5\xf6#\xf1\xfeEt\x0136[\x107\xdf1\xa4\x9f\xbdH\xf2h\xb32\xe8N\xb2̅\x98\xc9\xf2\xb4?\x03\xec\xcf\aw\xbcd\xa9f\x96m\xac\xab\x945\x88A4B8\xd8\x00\u007f2\xa9\x9d\x88YL\xb6o\xceE\x99\x8db\xb2\xb5\xea\x19/) Bn\xa6-\xefA\n\xa5\x8f\xa4\x87R\xd8\xcch>?M2[\xc0ĺ͞R\x11\x89f\xd0\xe8j\x0f\xa1\xd01\x17\xfd\x93\xbaL\xc7l\x1c\xf5\xd0}S\x16\x01\x8bqPŦ?l\x89&\xaab\b\x18WH\x93\xbb_\xcd\x18g(f-L\xf4\xd6\x1aO2N\xc0\xf4\x13;\x9c\xe9\xde\xd3\x13\\g\x89Fo\u007fM\xf2\x97\x06/`\x13{&\x98\x80\xf1~\t\xe9\xd6\x0f\xbaT3<\xac\x0e\x84\xc4#\xa9;\xe3\xe6\xc0\xf8\xdcl*4\xa2\xba\xb7N\xe2sYhs`\xd3\x03$V˲\x11\xb0\xef\xf1\x03\xff\xa4\x9f\x971\xbeM\x9e\xc3\xdb\xe9j0\xf2\a\xec\xfd~n\x01[\xc5\xe6\x15~\xa1F\x80\x1dC\xeeZtRpk\x11\xb0z\x8b\x80}\xc8_%\xb7\x8c\xfbC\xb9\x9d\xeb\xd6\xe6\xf6\xe4\x12\x113Y\x95g\x841A\u007ffǫ\x83\xfd\x81\xa8K\xba4\xcbV007%6{\u05ce\x84їzv\x9c\xb4\xf7\xc0e1B\xff^Mu:ڄd\xd5\x1e\x96\xc4S-\xe4\xc6\xd9\xf2\x85\xcci\xca\"\xeef5E>?\x81#\n\x18-\x99X\xb79\xee[\x92\x98\x06t\xaa5\xa4\xfdu^\x9ec6\x93\xfasu\x9f!`\xf5\x962\xf0\a\x95ύ\x90CR\xb4!s\xbc\x02v\xb7\xaa\x19\xfd\fŮ\x85\x89\xdeZ\xe3I\xc6\t\x98~bs\v\xe8\xdf\xf1r\x8b\x80\xd9_\x93\xfc\xa5ada\xdeM\x12\xfc\x129\xb3>[\xedp\x1am0ƅ\xc8\t\x18\x97\x9b]\x85&م@\xac\x93\xf8\\\x16\x01\a\x1b\xb9u\xa1\x89\x18-\xcbN\xc0\xc8O\xf1O\x15\x05\xbby\x10?\xa5\xa8\x98\x17\xbf\xa0\xe8\xd4\xc5M4\b\xb7 `\xa4\b\u007f|[\xbfYI\x97Q\xe4)\nvR\xd2d\xea~\xe4H\x17\xbbM\xa6\x809\xf6(\x83\xe05\x16\x01\x9b\xca,\xa4\xedl\x17;\x05d\xb3G\xbby믕ΠZ?\x111\x93\r\xa8\xa3\x8cz6l/,$\xe4[\xf6\xc37\x92q\a\x9e\xbfJM\x03nSʜ\xa2\xcbN\n\x99\xc5\xd8a\xf5\xeaV\xcfNf\xdd\xe8/\xf8,\x1a\xd0\x19\x96v\x9b\x90\xac\x8fM\x0et\xa2>!7Ζ/䆂rR~\xbf\x8fe\"\xfc\xa16\x04\xcc(\x99P7\xdev\xac\xc1\xd2%\xb0\x1ap\x8c;\xd5\t\xebe;f\x9b]\xf4\xba\xafb\u05edy\xe6c\x1cT>72\x93\xab\x85P\x17\x89W\xc0\x16\xbb\x9a&\xd1\xceP\xccZ\xe8G\x87\x98\xad5\x9ed\x9c\x80\xe9'\xd6M\xa5c&\xcf\"`\xf6\xd7$\u007fi\x18Yp\x02\xc6\xfb\x9d.\xa8'\xdb|3F\x16\x8c\xe8\x17\"'`\\n\xb6\x15*p+\xfa\x18^e\x110.\x8b\xc9\xf4rE\tf\n=\xb1Z\x96\xad\x80\xdd\u0604\x8b\xb6l\xf5\xe22:\xfdu~=\xf6n\xaf\xc4x\xf7m\xab\x80m\xc7\x18_\xd0Ӵ\"_j\xca}nc\xbd\xc3q$<F\xa4݅Ԧ\xf1\\\x8d\x87\vPrGH\x8d}6R\x9d\x12\x94\x95#\xb1j\xf5+\xfd;\xb4\xe7\x12\xc2I\xcdj\xba\xc3\x0e\xe7L\x8e\xe30\xef\x8a\b\xc9\x02\xc8\u007f\xb2\xb7\x1a\xb1Y\xfe\x06\xa9\xb9ǗF\x1b\xec\xe3\xfa]\x00\xc1\x963\xe06%\x94\xdfu<ǩ&(\xd5\x06\xbe\xa3l\xe2p݆\xea\xfb\xf8,\x1aP\xfa\x81\xbe\x9ejv\x8f\x94KV\x95\x14\xe8\v$U\x89\xb9\xf1\xb6\\!\xebP#i\xa27i\xa7\x87\xd8M\x1a6\x1d\xa3l\a\xa5\xea`pJ,\x99\x91\x8c\xb7e\x85L\xb7\xcc\xcaX\ff\xb3|\xc7\xec\x9bLw[w\xa9\xc4\x04\xcc8\xf3\xb1\x0e*\x9f\x1bi\xb1\x0e\xdd\xf8\x03%\x16R\xe7nV\xd3$\xca\x19\x8a]\x8bRc*e\xa4\r\xb5\xa85\xb2O\xa6\xdb\xf2'\xb6\x01mn;\x9c\x8f\\MC\xb1\xae\xb3hפxi\xe8YL\xfa\xd7}\xa3|\xfdf\x9d\u007f\x92\xf3\x1b\tֺ\xc6\xc9%\xe7\xae`\x84\xae\xc47\xea\x1d\xedB\x14V\xe2\x1b\xb9Ũ\x10\xb7\x12?\xe4p\x1f\xaa\xcfH\xa2\x17\xc1\xb8\xf6\xc0\xc1Uᐐ3\x8e\xfb;z}\xc9A\x12\xbde\xc9A;\x01c\x8f?z\xb7\xbc\xac\x8e\x10\xaf\xbd\xa0|\xd9~J\xd1/\x8b\x80]\xde\xed\xdd\xf8\xbe\x9e\xa4\x15\x05F}i\x8e\xb5\xfd\xda\xf7)I\x98\xbf\x888\xd9\b7\x99\x1d\x92p\xa1#\xdd\x17@\xa8\x96\xc5>\v\xa5)\xff\xd2\xdbB\xe1\xcd\xee\xf4\x82\x1e-A\xfd*5\xf9\x882\"iL\x1f&<b\xb2\x81u\x19N-\xdbȎ\fǃ\xd4\xf6\xdbԪ\xa8\xb6\x86\x01\xbf)=^\xed̪ҚA\x87\x8bN\xe1(\xfdW\x84\x9a\x94&\x99\xe3\xea\xe3\xb38Qxȝ\x92Y8hMv,O_\xadb\xe6\xc6\xdbr\x85\xecs\x8c\x92PZ/\xbd?\xc1\x0e\t\xebdh\x8f\x8a\xa1v\xb1dF2ޖ\x162\x1d\x89G\xc4j0\x9b\xe5;fd\xa2\xda\xed\xf0\x8d0\x013\xce<\x89qP\xf9܂\x8e=Ċy\xa0\xc4B\xea\xdc\xcdj\x9aD9C1k\xa1\x1f\x1d\xa5g\x94\xaed\x95:\x15W2Ö?\xb13-9\x92\xcb\xdf\xe1\x91\nc]gѮI\xf1\xd2гhP\x9f\xc6\xddF\x9fg4\xfd\x0e \xbaTs\x87\xf2\xefY\xfa,\xa4:\x85Η\x97s\xa6>\v\xa9\xf8a}\x0e=\xb7\x18\x15\x1a垅\f\x97fd\xef\xe9HV\x8a^\xad\x9eL\xe4\xe7\xb3P\b\xf9\x1c\x99\xa5!\xa1\x16\\\x8d\xedׁ-\x06\x97\x84Lj\x16\xc0.)\xda\x1d\xa88\t\xc4^\xc5;\x1b\xb3\xab</\x16\x98lQ\xe8\xb1\xce\xca,\x02w\xf7\x98\xa9\x93\xf8\xf3\xa1K\xaa\x9e\xb6\xb3Y\x00w\xb7\x9a\xcbL\xa2\x95w\x81,\x85\x80գ\u007f7\x98m\x8b\xfb[;\x93\x98\xd4Ԑ\xf8Y\xe0Y_`\xb2Šù\xcd\xced\xfe\xdc\xddc6o\x01\x9b\xcc\x12\xe7\r\x16\x8b\x05V32\xa6\xb2\xe8\xcf\xf6,*\xf3>-\x89\xc9]\x17\xb0\xd0X\xd7*iV\xc7{\xa5\xb2\xc0\xb3\xbe\xc0d\x8b\x80\xec\xaa[\xeev4\xef\xca\xcf[\xc0V\x04f5\x1f\xd4F;\xd6\xf9\xfc\x95żOKbr\xd7\x05\xac\\9Ӊr(\xd5\xd9\xc1y\xb3\xc0d\xf7\x06\xf3\xaf|\xf8\f\xaa\x9b_\x8a\x15\x00_\xcdp\xaf\xca<ƟK\xce\xfcOK\x82r\xd7\x05\xac)\xd5\xf5\xef\x0e \x97\f6;\x18\xfb\xee],\x16\x98\xec\xde`\xfe\x95_\x8b\xf4;8\t\xc4\xfc\xab\xb9\xbc$Zy\x17\xcc]\x170\x00\x00\x80\xbb\x05\b\x18\x00\x00\t\v\b\x18\x00\x00\t\v\b\x18\x00\x00\t\v\b\x18\x00\x00\t\xcb\xe2\n\x98\xfe|\xd1ܼA\x1f\x06\xd7X\xfc\x18\x92\x00\x00\xfc`\x00\x01\x03\x00 aY\\\x01\xbb\xfc\xeb\xf3v&\x04\x04\f\x00\x80Ebq\x05,>@\xc0\x00\x00X\x14\xee\x15\x01\xdb6\x9f\xe7r\x01\x00\xb87\xb0\x13\xb0\xdf\xe0S\x17*\xbd?\xb9\xa6\xbe\x18l\xd3^\xed\xad\x85\u05ceT\xaeߴO}_>\xb7\x83\u0381\xbd\xa1σ=\x8b_&\x96d\x9f\xef\xddT\xfc\xd4E\x8b\x80\x85˝\x8e\xfc\x0eB_Z\xa7\xbd.\xfa\x80\xf8\x02\xc48\b\xa3\x00\r5\xf8o\xbcug\xbe\xf4$k\x8f\xf4&wۙ\xce\xcbv\x81\x1cB)\xf4%\xb7}\x0et(\xbaA?+@\xc6C1\x9f\xe1Q\xdf\xe9t\b!\xed=\x92s2½\xd3Ia,\x85\x9d:\xfaN'G\x94\fB\xbe\xb4L\xff`\xe6\xc2\xdf(\x02\x001\xb0\x17\xb0\x17\xbd\x18\x17\xdf&\x17\x8a\xb1wk%Ư\xd1_\xcf{q\xf1\xf62\x8c\xe9\x8c\x17\xbf\x83\n\xd8?p\x11{\xfb\xe1\xedb\x1a\xba[Hv\n㊭EE\xbb\x05\x01\xcbu\xa2\\\x0fB\xe5\x84L\xa4h\x91}=Q\x038\b\x9c\x15_\xd0Y\xb5\xea[-\xd4`\x14\x03\x8b\xedl\x16bЈ\xb4WH\xa2\xc6(\tT\xf4d\xf1\xd8.\x10=\x8b\t\xbf\x83\xbe\x9a\xda\xe7\xf0OD7\xa4o\xd5\f\x0e\x1e\xf3X\xe27\x9a\boՌ\x81q\x1c\xb8\xb7j2\xd4\x00\x8f쭚\xb3\x1f!\x1eH[s\xbc3\x0f\xcd\xe7\xe5[\x00\x10\x1f\xf6\x02\x86+\xcf_8Mn\x14㣷\x95.\xd4&\x1a\x99\xe8\xbbb\xfc\xf2mr\xe7\r\x1a\xdcC\xd8\xc1\xeeB\xeeħi\xca\xf3x+\x11\xf7^\xc4\x0f\x9c\xbeC\xbe\u007f\n\v\x02\x86\xb2\x95&5\u082fX)A4\n\x00\x19\x89\xe3\x05\x88k\xfc\xfc\xb7\xb0\x1aJ\x97\u007f\x83\bg \xdaFa!\x06-\x92\xf6\x12\xefT3\xf2\x93\x15=Y<\xb6\v\xc4(Y\xa0\xc41E&\x1d%\x81\x98\xa6\xec\xe8L\xb9\xc5\xf8P\x1cq\x84\x87\xe7\x8fC\xdc\xe1\xe1'\xd3K#\xf4\xed\xec `\xc0\xe2\x13\x87\x80]\xa6\x9fG\xb5@\xdc\xef\xe3\x1f\x13\xf22\r\xf1\xa1\xb0[\x91*a\a\x13\xb0\xd3\xeaރ\xf8\x94%\xd9A|\x94n\xdf,\x13\x05\x8c5\x98c(\x9b\xbe\\\x94)\xd7.\x14\xbb\x15\xea\x88a+\xaa\xd57\x8e\xf1\x02\x1654V\f\x16b\x10\tk\xad5\x1c\xfb}\\z\xb2xl\x17\b\x17\x1a\xcb\xd7EN\xf8\xfc6\x02F\x1aRgb\xec\x8fC\xc0\xa2\xc7\xfa\xa2\xcc!`\x81T6vl\x06\x01\x03\x16\x1f{\x01\xabd\x9f\x0fk1!o\xd3\xe8\xb6[\xb4/7n\xdc\x11w0\x01\xbbY\x84\xff\xa9\xfc\xeb\xa5\xff\xf2{\xefl\xc4\x17ٗ\xa3\x82\x80\xade\x9fSI\xca\xf5\x1dq\xd2\xcb\u007f\xc6e^\xea\xb5(\xa5\xbd.\xc7\xe1c\xc1\rȉ\x82\xb4\x9c\xc7o\x11ҫM)\xe5kVcɻا\xb4G\xb3\xe5\f\xb8\xcdZ\x94\xdcZ\xe3\xce(\x15\x1b\x92\xe8Lς\x90\xa0ϝ\xe2*ɞ\x9d\x9b\x89\xd9Z\xed\x93i\xb6\xa3\xc9\bՇ\xab\xb2\x1d\x1b\xa6\xc9\xd4\xe6,\xc9]:J,\xd54<\x88\xe5m\xcb\xd7\xdeknz\xe0\xb3\b\xf8\xdb\xcaI\xc9+T\xc0L\xbf\xa1d\x1a]ύ\x903\xa2\vXcr\x84+/_\x1cA\xc0\xf4\xdcl+D\x88\\\x95\xe5,\xb7\x86\xc6\xe2\x0e\x89\x16\xdbo\xa29\xc2\xf9\xe5j\x1c\xbd\xf2\x00\x10\x0f\xf6\x02ƺS71\u07b2\x9dQ\x84/\x90\xf5\xf8o\xfa~q\x87\xba\x90u\x1f\x1dC\xbeO\x13\n{\xbf\xa7\xb1%)\xa7\x05\x01\xabS7\xb2i\x18\x9bm4Dπ\x16\x17\x98\x12\xeaLF\xae\x86\xe6t\x16\u007f\xae&iG_\xab+\u007f\x86\xdc\n\xb2x(A]\x89j$U\xe0$\x94\xdbٛ\xa9\xd8r\x06\xdc&u\x96}\xf8\xe7\xd9\xe24\x90\xe0\xcc\xc8B\x19\xc7>\xda=\xd0\xeeBӳr31Zk\x1c\xc94\xdb\xc8\xc9\xce\xec\x9ctw]\x15\xbaJ\xfaP\xcd\xe0\xc9Ҥa\xb1\x9a\xa6\a\xa1\xbc\xd5R}_\xbdT%x\xe0\xb3\b\xf8\xc7\xd3&W\xc9T\xc0L\xbf3C\rIC\xa4\x03\x9d\xa0j\xa6\nX~\x1e_^\xbe8!\xd4\x17\x89D\xfa\x91\x90\x9bm\x85Hؙ\xd3\xd1\xebCV\x013\xb3H\xe2\xc6͆_\xae\xc6\xd1+\x0f\x00\xf1`/`\a\xe9\xc7w\xd8\xe4c\xa5;uC\xdf/\xec\xd0\x04\xec<\xdeM\xc8S\xf8}\xcb\xdek\x18\xabi\xce\v\x02\xa6\xc5^[\x8d\xbai\x14n\xd7\f\xf1#~\xa6H\xa2\xb1\f\xab\\\x84\xb6Kz\xabr\x98\x85\x87\x13\x063WS\xb4`4R\xe6\xa4\xd2r\\\xc4b`nJ\xd9S\x84L\xba\v\x88\x88a\xc0e\xd1梍\xa8\xcdi\xf1 \xa0\xb7\xd6x\x92q\xb1\xfd\x90O)\x85\xf2\u007f\xa4\x8bN\x97\xe7\xb1\x18\xc7f5y\x0ffyϰ\xee\xd1\x00\vVfz\x10\x86\x90$o\xdb\x1a\x16ۏ\xf7K\xaa\v&\xdc\xea\x1b\xe5\xa5\xfaȭ\xd1r\xf4\xa1\xf5H\xea\xceBZ\x0f+$\xe4f[\xa1\xb5\x9e[4\x92\xa0E\xc0\xcc,ƌ\x18\xa0b-\xcc\x1aǨ<\x00\xd8\x13\xa7\x80ݤ\x03D\x9d;ڼج\x1d\x9a\x80\xddވ\xbf\xff'\xf6\u07b4콩\x87\xef~_\x10\xb0\xc7\xd5\r7mYă\xceF\x1c\xc9\xfc\xfdv\x16z\x94Ͱ\xf8=\xd3\x14\xb7\x1a`\x98kJ\xb5\xfa\xab'Y\x9c\xf89\xc3ó\x19\xa26d\x89\xa4h\x18pY\x8cgyj\x8f\x8f\xaa\x81\xac\xed\x04,\x9ed\x9c\x80Iz\x98扶\r\x1e\xa7\xda\xdf4\xab\xc9{0\xcb[\xa3\x86\xb5Z]-z\x10\x04\xac\t52\x01\xe3\xfd\x92H^\xa6\xb6\xd2N\xa2\xea\xe4\xa2j\"\x1eI\xddY\b5\x0f\x0f\x0f\xb7P\x01\xe3r\xb3\xabФ\xba\xea\xa2\xde\"`f\x16\xd3\xc9\xe6\xdf#\xbe\x16f\x8dcT\x1e\x00\xec\x89S\xc0H\x996\x99E>\xffǿH%V\x9f\x18\xfa\xf8\xa7\xa7\xc4\x1dڳ\x90/\xe2ӧ\xf1\xb3\xd6dw6au\xe1\xd8k\x82\x80\xa9w\xc5&\x11\xa2\xc3\xc0\x06T\xdbo\x04\xffd\x98Ax\xf3\xb4\x1e\x02\xebYpMI\x96\xf4E\xac|t\xe5\xe8\x02\xc6FQ\x83\xd6 \xa9\x86\x01\x9f\xc5d\xfb\xe6\\\x94\xd9h\xf1 \xa0\xb7\xd6x\x92q\x02\xa6O\xa6\rg\xba\xf7\xf4\x04\xd7Y\xa2+\xf3\x1e\xcc\xf2\xaeUU\xa8\xa4@\xf0 \n\xd8Ğ\t&`\xbc_B\xba\xf55)R\xcd\xf0\xb0:\xfc\x13\x8f\xa4\ue31b\x03\xe3s\xb3\xa9Ј\xea\xde:\x89\xcfe\xa1́M\x0f\x88~\xb9\x1aG\xaf<\x00\xd8\x13\xaf\x80=\x87\xb7ߡ\x9f\u007f\xa0K'\x8ejkU\xf7\xe27\xc4\x1d\x9a\x80]\xc4O=\xa5\x06\xea\x16\xf6\xbe\xa0\x8a\xda\xedJA\xc0V\xb1\xf9\xab_\xa8\x913ǐ\xbb\x16\x9d$\x1c\xe6\xc5]\xe5\x19a\xb0\x85N\xac)u\xb0\xbeC]\x92\x1e\xaf}\x96\x80\xa9\x06\xe6\xa6\xc4&\xdcڭ\x91\x14\r\x03.\x8b\x11ڕ\x99\xeat\xb4Y\x9c\xf1\xe8\xad5\x9ed\x9c\x80\x95k\x1b\xb9\x05tZ\xbb\xdc\"`\xbc\a\xb3\xbc\xd5\x1e\x96\xc4S-x\xe0\xb2\xe0\xc2\xc3\xf3~\x89\x9cY\x9f\xadv8\xcd{\xb4\xe2\x91ԝq\x02\xc6\xe5fW\xa1I5Đu\x12\x9f\xcb\"\xe0`=\xea.4!\xd4\"\xaa\x80\t\xb9\x01\x80-\xf1\n\xd8e/~A\x19\x00^\xdcD\xc5\xe7\x86\x17\xbf\xc1ց\x15\u007f'\xee\xd0\xdfFQYTTqgV\xb2k\xeb\xf1\xaf\uf41b\a-\xeb\xc0\xf2\x14\x05;)i3%\xf7#G\xba\xb0\xd6\xc0\xbc\xb8\a\x10[h_\xcfft\n\v\t\xf9\x96\xfd\xf0\x8dd,\xdb\xe7\x05\xcc4\xe06\xa5\xcc)\xba\"\xc9\x1a\x0f\xcb0\xe0\xb2h@gخm\x16gd찮\x97Fk\x8d'\x19'`z7\xc6M\xa5c&\xcf\"`\xbc\a\xb3\xbc}lª\x13\xf5\t\x1e\xb8,8\x01\xe3\xfdN\x17ԓm\xbe\x19#\v\x86p$\rg\x9c\x80q\xb9\xd9V\xa8\xc0\xad\xe8cx\x95E\xc0\xb8,&\xd3˕!\xe1L\xa1G\xacET\x01\x13r\x03\x00[\xe2\x150r~=\xf6n\xaf\xc4x7\xbd\x93x\xbe\boܾ\t\x17\x9d\xb7\xec\xd0\x05\xec\r\xcc\x1e#\xb2&\xfb\xb8\b\x97\xfdċ\xf7\t\x02\xe6KM\xb9ύ\xf4\xb9\xfc\xe3Hx\x8cH\x8d\x0e5R\x9d\x12\x94i e\xff\xc9\xdejt\x82\xeeh\x90\x9a{|i\xb4\xf3\xf6\xb8\xbe\xe8B\xb0\xe5\f\xb8M\t\xe5w\x1d\xcfqZ\xef'\x9a\x06f\x16\r(\xfd@_O5\x1a\x14\r\b)5\x86\xb8#m\xa8E\x1d\x8c\xda'\xd3m\xa7\x87ح<6i׀6\xb7\x1d\xceG\xae\xa6!\xbe\xe8\xbc\a\xae\xbcUI\x81\xbe@R\x95\xe8\xc1\xccbҿ\xee\x1b\xe5\xeb7\xeb\xfc\x93\x9c\xdfH\xb0\xd65N.9w\x05#t%\xbeQo\xa3\xbc\x9c3a%\xbe\x91[\x8c\nq+\xf1C\x0e\xf7\xa1\xfa\x8c\xa4䎐\xba\x12\xbf%\x18\xbc*\x1c\x12r\xc6q\u007fG\xaf/9\xc8ׂ\xabq\xac\xca\x03\x80=q\v\x18\xb9\xf6Be\x91w\xfb)u%\xc4\xe5g+\x8a\xca\x0e^\xb6\xee\xd0\x05\xec\x869\xcd/$\xfb\xdb\xc12\xef\xf6\v\x1f\v\x02\x16\x18\xf5\xa59\xd6\xf6kߧ$\xe11\"\x16\x1d*\x94\xa6\xfcKo4\x0e\xac\xcbpj\x96\x91\x1d\x19\x8e\a\x87\x95\x8doS\xab\xa2\xda\x1a\x06\xfc\xa6\xf4x\xb53\xabJ&\x168[#\x8b\x13\x85\x87\xdc)\x99\x85\x83V\x03\xd2\xe1jW7n\xa5+Y\xa5Nŕ̰\x1dU\x1f\",\xa1?δ\xe4H.\u007f\x87G*\xe4\x8b\xce{\xe0\xcb{,O[\a\xc6y0\xb3h@\x88N5m\xa3\xcf3\x9a~\a\x14\xc3:\xb2C\xf9\xf7,}\x16R\x9dB\xe7\xcb\xcb9S\x9f\x85T\xfc\xb0Yy=\xb7\x18\x15\x1a垅\f\x97fd\xef\xe9HV\x8a^\xadM|\xf9\xf9,\b}\x16ґY\x1a\x12j\xc1\xd58V\xe5\x01\xc0\x1e;\x01[j.\xc5\xf1\x18\x91@`>\v\xbc\x13-Zq\xa2\x95\x17\x00\x96\x98\x95&`\xf5h\x9eapkjH\xfc\x98\x82\x10\x19SY\xf4g{\x16\x15\x100\x00\x98\x93\x15%`\xa1\xb1\xaeUҬ\x01\xde\"b\n\u0083\xdah\xc7:\x9f\xbf\xb2\x00\x01\x03\x809YQ\x02V\xae(\xca]l\xb2\xeal\xb1J\xb8We\x1e\xe3\xcf%\x87//\x00\x00QXQ\x02֔\xea\x9a\xe7\x00r^\xb0\xd9\xe21;\xab\x95C\xa2\x95\x17\x00\x96\x9c\x15%`\x00\x00\x00\xf3\x01\x04\f\x00\x80\x84\x05\x04\f\x00\x80\x84\x05\x04\f\x00\x80\x84\x05\x04\f\x00\x80\x84eq\x05L\u007f\x94hn\xeeF\\H\x00\x00~\x80\x80\x80\x01\x00\x90\xb0,\xae\x80]\xfe\xf5y;\x13\x02\x02\x06\x00\xc0\"\xb1\xb8\x02\x16\x1f `\x00\x00,\n\xf7\x8a\x80m\x9b\xcf3\xdd\x00\x00\xdc\x1b\xd8\t\xd8o\xf0\xa9\v\x95ޟ\\#\xe4Ƌ\x95E\x9b\xf6^P\u007f\xbev\xa4r\xfd\xa6}\xea+\xee\xb9\x1dt\x0e\xec\r}\x1e\xecY\xf6RC!\xd9\xe7{7\x15?u\xd1\"`\xe1r\xa7#\x9fưiA\xb9\xea\x8f\a\x84\x97\x1a\xc6C\x18\x05H-J겳[<z\x92\xb5\xc7\xc1\x93\xbb\xedL\xe7e\xbb@\x0e\xa1\x14\xfaJ\xdb>\a:\x14ݠ\x9f\x15 㡘\x0f\u007f\xaa\xef\x03;\x84\xd4\xf7\x81\xd90½\x0fLa,\x85\x9d:\xfa>0G\x94\fB\xbe\xb4L\xff`&\x1f\xab\x05\x00\x16\x05{\x01{ыq\xf1mr\xa1\x18{\xb7Vb\xfc\x1a\xfd\xf5\xbc\x17\x17o/\xc3,\xb6\a\xbf\x83\n\xd8?p\x11\v>t\xbb\x98\xbe\xd4PHv\n㊭EE\xbb\x05\x01\xcbu\xa2\\\x0fB\xe5\x84L\xa4hQ\xa1=\xc2K\r\xa3rV\x8c\xcbQ\xb5\xea[\xfa\xec3\xf7$8g`\xb1\x9d\xcdB\f\x1a\x91\xf6\xfaQ\x14;\x02\x85\x9e,\x1e\xdb\x05\xa2g1\xe1w\xf8\x94\x0f\x9f\xc3?\x11ݐ\xbe\x9158x\xcc#\x06\xc5\xe4\x10\xde\xc8\x1a\x03\xe38pode\f\xb1w\xe2\xb37\xb2\xce~\xfc| m\xcd\xf1\xce<4\x9f\x17\xb7\x01@|\xd8\v\x18\xae<\u007f\xe14\xb9Q\x8c\x8f\xdeV\xbaP\x9bh\x98\xa1\xef\x8a\xf1\xcb\xec\x9d\xf8\xde\xef\xc5\x1d\xec.\xe4N\x1aזF\u007f\xdcJĽ\x17\xf1\x03\xa7\xef\x90\uf7f2\xbc\x13?[iR\x03\x0e\x1a\x1b\xa2\x04ј\x0ed$\x8e\x97\x1a\xae\xf1\xf3\xdf\xc2jx\\\xfe\xed3\x9c\x81h\x1b\x85\x85\x18\xb4H\xda\v\xe0S\xf9(\x96\"z\xb2xl\x17\x88Q\xb2@\x89c\x8aL:J\x021M\xd9љr\v1\x9fx\x84\xc8\xdc\xd1\xe1\x8fð U֨D\x1c\x93\xe9\xa5\x11\xfaf\u007f\x100`\xf1\x89C\xc0\xd8ˡ\x8f\xe2\xbd\xec\xfb\xfb\xf8DŽ\xbc\xac\x86\xeb&\xbb\x15\xa9\x12v0\x01;\xad\xee=\x88OY\x92\x1d\xc4G\xe9\xf6\xcd2Q\xc0X\x839\x86\xb2\x95\xa1\x96\xaa\\\xbbP\xecV\xa8#\x06:\xabV\xdf\"\xc6\vX\u0530j1X\x88A$\xac\xb5\xd6p\xecw\"\xea\xc9\xe2\xb1] \\X5_\x179\xe1\xf3\xdb\b\x18iH\x9d\x89\xb1?\x0e\x01\x8b\x1e'\x8e2\x87\x80\x05R\xd9ر\x19\x04\fX|\xec\x05\xac\x92}>\xac\x05x\xbcMC\xd5nѾܸqG\xdc\xc1\x04\xecf\x11\xfe\xa7\xf2\xaf\x97\xfe\xcbウ\x11_d_\x8e\n\x02\xb6\x96}N%)\xd7w\xc4I/\xff\x19\x97y\xa9ע\x94\xf6\xba\x1c\x87O\x8d\xa7q\xa2 -\xe7\xf1[\x84\xf4jSJ\xf9\x9a\xd5X\xf2.\xf6)\xed\xd1l9\x03n\xb3\x16%\xb7ָ3Jņ$:ӳ $\xe8s\xa7\xb8J\xb2g\xe7fb\xb6V\xfbd\x9a\xedh2B\xf5\xe1\xaaldži2\xb59Kr\x97\x8e\x12K5\r\x0fby\xdb\xf2\xb5w\xe2\x9b\x1e\xf8,\x02\xfe\xb6rR\xf2\n\x150\xd3o(\x99Fft#\xe4\x8c\xe8\x02֘\x1c\xe1\xca\xcb\x17G\x100=7\xdb\n\x11\"We9˭aոC\xa2Ņ\x9ch\x8ep~\xb9\x1aG\xaf<\x00ă\xbd\x80\xb1\xee\xd4M\x8c\xb7lg\x14\xe1\vd=\xfe\x9b\xbe_ܡ.d\xddGǐ\xefӄ\xc2\xde\xef1VC{\x9c\x16\x04\xacN\xddȦ\xf1淡\x1d4\"W\x9e\xb1;ԙ\x8c\\\r\xcd\xe9,vaMҎ\xbeVW\xfe\f\xb9\x15d\xb1t\x82\xba\x12\xd5H\xaa\xc0I(\xb7\xb37S\xb1\xe5\f\xb8M\xea,\xfb\xf0ϳ\xc5i \xc1\x99\x91\x852\x8e}\xb4{\xa0݅\xa6g\xe5fb\xb4\xd68\x92i\xb6\x91\x93\x9d\xd99\xe9\xee\xba*t\x95\xf4\xa1\x9a\xc1\x93\xa5I\xc3b5M\x0fBy\xab\xa5\xfa\xbez\xa9J\xf0\xc0g\x11\xf0\x8f\xa7M\xae\x92\xa9\x80\x99~g\x86\x1a\x92\x86H\a:A\xd5L\x15\xb0\xfc<\xbe\xbc|qB\xa8/\x12\x89\xf4#!7\xdb\n\x91\xb03\xa7\xa3ׇ\xac\x02ff\x91č\x9b\r\xbf\\\x8d\xa3W\x1e\x00\xe2\xc1^\xc0XT\xa2\xef\xb0\xc9\xc7Jwꆾ_ء\t\xd8y\xbc\x9b\x90\xa7\xf0\xfb\x96\xbd\xd70VӜ\x17\x04L\x8b\xa7\xb6\x1au\x132\x84\\3ď\xf8\x99\"ɩ\x88S\x95\x8b\xd0vIoU\x0e\xb3Ђ\xc2`\xe6jJ\xadf\x9b9\xa9\xb4\x1c\x17\xb1\x18p\x91\xb9\xb3\xa7\b\x99t\x17\x10\x11Àˢ\xcdE\x1bQ\x9b\xd3\xe2A@o\xad\xf1$\xe3\xe2B\"\x9fR\n\xe5\xffH\x17\x9d.\xcfc\xf1\xb1\xcdj\xf2\x1e\xcc\xf2\x9eaݣ\x01\xd4/x\x10\x86\x90$o\xdb\x1a\x16\x17\x92\xf7K\xaa\v&\xdc,\xfe#\x91\xea#\xb7F\xcbч\xd6#\xa9;\vi=\xac\x90\x90\x9bm\x85\xd6zn\xd1(\x94\x16\x013\xb3\x18\xd3\"~R\xf8Z\x985\x8eQy\x00\xb0'N\x01\xbbI\a\x88:w̠i\xe2\x0eM\xc0no\xc4\xdf\xff\x13{oZ\xf6*_\xd8\xedI\xa5s\xc6\v\xd8\xe3ꆛ\xb6,\xe2Ag#\x8ed\xfe~;\v[\xcbfX\xfc\x9ei\x8a[\rN\xcd5\xa5Z\xfd\xb5\xa5R\r1fc\xa2\v\x18\x9b!jC\x93D\xc00\xe0\xb2\x18\xcf\xf2\xd4\x1e\x1f%\xd3\x16\x0f\x02zk\x8d'\x19'`\x92\x1e\xe2{\xa2m\x83ǩ\xf67\xcdj\xf2\x1e\xcc\xf2֨!\xd1VW\x8b\x1e\x04\x01kB\x8dL\xc0x\xbf$\x92\x97\xa9\xad\xb4\x93\xa8:\xb9\xa8\x9a\x88GRw\x16B\xcd\xc3\xc3\xc3-T\xc0\xb8\xdc\xec*4\xa9\xae\xba\xa8\xb7\b\x98\x99\xc5t\xb2\xf9\xf7\x88\xaf\x85Y\xe3\x18\x95\a\x00{\xe2\x140R\xa6Mf\x91\xcf\xff\xf1/R\x89\xd5'\x86>\xfe\xe9)q\x87\xf6,\xe4\x8b\xf8\xf4i\xfc\xac5ٝMX]8\xf6\x9a `\xea]\xb1I\x84\xe80\xb0\x01\xd5\xf6\x1b\x81c\x19f\xd4\xe6<\xad\x87\xc0z\x16\\S\x92%}\x11+\x1f\x99;\xba\x80\xb1Q\xd4 \xb2\xac\x8a0\f\xf8,&\xdb7\xe7\xa2\xccF\x8b\a\x01\xbd\xb5Ɠ\x8c\x130}2m8ӽ\xa7'\xb8\xce\x12\x99\x9b\xf7`\x96w\xad\xaaB%\x05\x82\aQ\xc0&\xf6L0\x01\xe3\xfd\x12ҭ\xafI\x91j\x86\x87\xd5\xe1\x9fx$ug\xdc\x1c\x18\x9f\x9bM\x85FT\xf7\xd6I|.\vm\x0elz@\xf4\x1b52\xb7\x90\x1b\x00\xd8\x12\xaf\x80=\x87\xb7ߡ\x9f\u007f\xa0K'\x8ejkU\xf7\xe27\xc4\x1d\x9a\x80]\xc4O=\x85/\xccJ\xf6\x82*j\xb7+\x05\x01[\xc5\xe6\xaf~\xa1F]\x1dC\xeeZt\x92p\x98\x17w\x95g\x84\xc1\x16:\xb1\xa6\xd4\xc1\xfa\x0euI\x97f\xd9\n\x06\xe6\xa6\xc4&\xdcڑe\xa5\x93a\xc0e1B\xbb2S\x9d\x8e6\x8b3\x1e\xbd\xb5Ɠ\x8c\x13\xb0rm#\xb7\x80Nk\x97[\x04\x8c\xf7`\x96\xb7\xdaÒx\xaa\x05\x0f\\\x16\x01u\x85\x03\x150\xde/\x913\xeb\xb3\xd5\x0e\xa7y\x8fV<\x92\xba3N\xc0\xb8\xdc\xec*4\x89\xd8\x1e\xeb$>\x97E\xc0\xc1z\xd4]hB\xa8ET\x01\x13r\x03\x00[\xe2\x15\xb0\xcb^\xfc\x822\x00\xbc\xb8\x89\x8a\xcf\r/~\x83\xad\x03+\xfeNܡ\xbf\x8d\xa2\xb2\xa8\xa8\xe2άd\xd7\xd6\xe3_\xdf!7\x0fZց\xe5)\nvR\xd2fJ\xeeG\x8eta\xad\x81yq\x0f \xb6о\x9e\xcd\xe8\x14\x16\x12\xf2-\xfb\xe1\x1b\xc9X\xb6\xcf\v\x98i\xc0mJ\x99StE\x925\x96\x9aa\xc0eрΰ]\xdb,\xce\xc8\xd8a]/\x8d\xd6\x1aO2N\xc0\xf4n\x8c\x9bJ\xc7L\x9eE\xc0x\x0ffy\xfb\u0604U'\xea\x13<pYp\x02\xc6\xfb\x9d.\xa8'\xdb|3F\x16\f\xe1H\x1a\xce8\x01\xe3r\xb3\xadP\x81[\xd1\xc7\xf0*\x8b\x80qYL\xa6\x97+C\u0099B\x8fX\x8b\xa8\x02&\xe4\x06\x00\xb6\xc4+`\xe4\xfcz\xec\xdd^\x89\xf1nz'\xf1|\x11\u07b8}\x13.:o١\v\xd8\x1b\x98=FdM\xf6q\x11.\xfb\x89\x17\xef\x13\x04̗\x9ar\x9f\x1b\xe9s\xf9Ǒ\xf0\x18\x91\x1aYl\xa4:%(\xd3 \xdc\xfe\x93\xbd\xd5\xe8\x04\xdd\xd1 5\xf7\xf8\xd2h\xe7\xedq}х`\xcb\x19p\x9b\x12\xca\xef:\x9e\xe3\xb4\xdeO4\r\xcc,\x1aP\xfa\x81\xbe\x9ej4(\x1a\x10Rj\fqG\xdaP\x8b:\x18\xb5O\xa6\xdbN\x0f\xb1[ylҮ\x01mn;\x9c\x8f\\MC|\xd1y\x0f\\y\xab\x92\x02}\x81\xa4*у\x99Ť\u007f\xdd7\xca\xd7o\xd6\xf9'9\xbf\x91`\xadk\x9c\\r\xee\nF\xe8J|\xa3\xdeFy9g\xc2J|#\xb7\x18\x15\xe2V\xe2\x87\x1c\xeeC\xf5\x19I\xc9\x1d!u%~K0xU8$\xe4\x8c\xe3\xfe\x8e^_r\x90\xaf\x05W\xe3X\x95\a\x00{\xe2\x160r\xed\x85\xca\"\xef\xf6S\xeaJ\x88\xcb\xcfV\x14\x95\x1d\xbclݡ\v\xd8\rs\x9a_H\xf6\xb7\x83e\xde\xed\x17>\x16\x04,0\xeaKs\xac\xed\u05feOI\xc2cD,\xb2X(M\xf9\x97\xdeh\x1cX\x97\xe1\xd4,#;2\x1c\x0f\x0e+\x1bߦVE\xb55\f\xf8M\xe9\xf1jgV\x95L,p\xb6F\x16'\n\x0f\xb9S2\v\a\xad\x06\xa4\xc3ծn\xdcJW\xb2J\x9d\x8a+\x99a;\xaa>DXB\u007f\x9ciɑ\\\xfe\x0e\x8fT\xc8\x17\x9d\xf7\xc0\x97\xf7X\x9e\xb6\x0e\x8c\xf3`fр\x10\x9dj\xdaF\x9fg4\xfd\x0e(\x86ud\x87\xf2\xefY\xfa,\xa4:\x85Η\x97s\xa6>\v\xa9\xf8a\xb3\xf2zn1*4\xca=\v\x19.\xcd\xc8\xdeӑ\xac\x14\xbdZ\x9b\xf8\xf2\xf3Y\x10\xfa,\xa4#\xb34$Ԃ\xabq\xac\xca\x03\x80=v\x02\xb6\xd4\\\x8a\xe31\"\x81\xc0|\x16x'Z\xa4\xebD+/\x00,1+M\xc0\xea\xd1<C\xdb\xd6Ԑ\xf81\x05!2\xa6\xb2\xe8\xcf\xf6,* `\x000'+J\xc0Bc]\xab\xa4Y\x03\xbcE\xc4\x14\x84\a\xb5юu>\u007fe\x01\x02\x06\x00s\xb2\xa2\x04\xac\\Q\x94\xbb\xd8d\xd5\xd9b\x95p\xaf\xca<ƟK\x0e_^\x00\x00\xa2\xb0\xa2\x04\xac)\xd55\xcf\x01\xe4\xbc`\xb3\xc5cvV+\x87D+/\x00,9+J\xc0\x00\x00\x00\xe6\x03\b\x18\x00\x00\t\v\b\x18\x00\x00\t\v\b\x18\x00\x00\t\v\b\x18\x00\x00\t\xcb\xe2\n\x98\xfe(\xd1\xdc܍\xb8\x90\x00\x00\xfc\x00\x01\x01\x03\x00 aY\\\x01\xbb\xfc\xeb\xf3v&\x04\x04\f\x00\x80Ebq\x05,>@\xc0\x00\x00X\x14\xee\x15\x01\xdb6\x9fg\xba\x01\x00\xb87\xb0\x13\xb0\xdf\xe0S\x17*\xbd?\xb9Fȍ\x17+\x8b6\xed\xbd\xa0\xfe|\xedH\xe5\xfaM\xfb\xd4W\xdcs;\xe8\x1c\xd8\x1b\xfa<س쥆B\xb2\xcf\xf7n*~\xea\xa2E\xc0\xc2\xe5NG>\x8daӂr\xd5\x1f\x0f\b/5\x8c\x870\n\x90Z\x94\xd4eg\xb7x\xf4$k\x8f\x83'wۙ\xce\xcbv\x81\x1cB)\xf4\x95\xb6}\x0et(\xbaA?+@\xc6C1\x1f\xfeT\xdf\av\b\xa9\xef\x03\xb3a\x84{\x1f\x98\xc2X\n;u\xf4}`\x8e(\x19\x84|i\x99\xfe\xc1L>V\v\x00,\n\xf6\x02\xf6\xa2\x17\xe3\xe2\xdb\xe4B1\xf6n\xad\xc4\xf85\xfa\xeby/.\xde^\x86Yl\x0f~\a\x15\xb0\u007f\xe0\"\x16|\xe8v1}\xa9\xa1\x90\xec\x14\xc6\x15[\x8b\x8av\v\x02\x96\xebD\xb9\x1e\x84\xca\t\x99HѢB{\x84\x97\x1aF\xe5\xac\x18\x97\xa3jշ\xf4\xd9g\xeeIp\xce\xc0b;\x9b\x85\x184\"\xed\xf5\xa3(v\x04\n=Y<\xb6\vD\xcfb\xc2\xef\xf0)\x1f>\x88\x9f\x8f(\x00\x00\ttIDAT\x87\u007f\"\xba!}#kp\xf0\x98G\f\x8a\xc9!\xbc\x915\x06\xc6q\xe0\xde\xc8\xca\x18b\xef\xc4god\x9d\xfd\xf8\xf9@ښ\xe3\x9dyh>/n\x03\x80\xf8\xb0\x170\\y\xfe\xc2ir\xa3\x18\x1f\xbd\xadt\xa16\xd10C\xdf\x15\xe3\x97\xd9;\xf1\xbdߋ;\xd8]ȝ4\xae-\x8d\xfe\xb8\x95\x88{/\xe2\aN\xdf!\xdf?ey'~\xb6Ҥ\x06\x1c46D\t\xa21\x1d\xc8H\x1c/5\\\xe3翅\xd5\xf0\xb8\xfc\xdbg8\x03\xd16\n\v1h\x91\xb4\x17\xc0\xa7\xf2Q,E\xf4d\xf1\xd8.\x10\xa3d\x81\x12\xc7\x14\x99t\x94\x04b\x9a\xb2\xa33\xe5\x16b>\xf1\b\x91\xb9\xa3\xc3\x1f\x87aA\xaa\xacQ\x898&\xd3K#\xf4\xcd\xfe `\xc0\xe2\x13\x87\x80\xb1\x97C\x1f\xc5{\xd9\xf7\xf7\xf1\x8f\tyY\r\xd7Mv+R%\xec`\x02vZ\xdd{\x10\x9f\xb2$;\x88\x8f\xd2\xed\x9be\xa2\x80\xb1\x06s\fe+C-U\xb9v\xa1حPG\ftV\xad\xbeE\x8c\x17\xb0\xa8a\xd5b\xb0\x10\x83HXk\xad\xe1\xd8\xefDԓ\xc5c\xbb@\xb8\xb0j\xbe.r\xc2\xe7\xb7\x110Ґ:\x13c\u007f\x1c\x02\x16=N\x1ce\x0e\x01\v\xa4\xb2\xb1c3\b\x18\xb0\xf8\xd8\vX%\xfb|X\v\xf0x\x9b\x86\xaaݢ}\xb9q㎸\x83\t\xd8\xcd\"\xfcO\xe5_/\xfd\x97\xdf{g#\xbeȾ\x1c\x15\x04l-\xfb\x9cJR\xae\uf213^\xfe3.\xf3R\xafE)\xedu9\x0e\x9f\x1aO\xe3DAZ\xce\xe3\xb7\b\xe9զ\x94\xf25\xab\xb1\xe4]\xecSڣ\xd9r\x06\xdcf-Jn\xadqg\x94\x8a\rIt\xa6gAH\xd0\xe7Nq\x95d\xcf\xce\xcd\xc4l\xad\xf6\xc94\xdb\xd1d\x84\xea\xc3Uَ\r\xd3djs\x96\xe4.\x1d%\x96j\x1a\x1e\xc4\xf2\xb6\xe5k\xef\xc47=\xf0Y\x04\xfcm\xe5\xa4\xe4\x15*`\xa6\xdfP2\x8d\xcc\xe8F\xc8\x19\xd1\x05\xac19\u0095\x97/\x8e `zn\xb6\x15\"D\xae\xcar\x96[êq\x87D\x8b\v9\xd1\x1c\xe1\xfcr5\x8e^y\x00\x88\a{\x01cݩ\x9b\x18o\xd9\xce(\xc2\x17\xc8z\xfc7}\xbf\xb8C]Ⱥ\x8f\x8e!ߧ\t\x85\xbd\xdfc\xac\x86\xf68-\bX\x9d\xba\x91M\xe3\xcdoC;hD\xae<cw\xa83\x19\xb9\x1a\x9a\xd3Y\xec\u009a\xa4\x1d}\xad\xae\xfc\x19r+\xc8b\xe9\x04u%\xaa\x91T\x81\x93Pngo\xa6b\xcb\x19p\x9b\xd4Y\xf6\xe1\x9fg\x8b\xd3@\x823#\ve\x1c\xfbh\xf7@\xbb\vM\xcf\xca\xcd\xc4h\xadq$\xd3l#';\xb3s\xd2\xdduU\xe8*\xe9C5\x83'K\x93\x86\xc5j\x9a\x1e\x84\xf2VK\xf5}\xf5R\x95\xe0\x81\xcf\"\xe0\x1fO\x9b\\%S\x013\xfd\xce\f5$\r\x91\x0et\x82\xaa\x99*`\xf9y|y\xf9\xe2\x84P_$\x12\xe9GBn\xb6\x15\"agNG\xaf\x0fY\x05\xcc\xcc\"\x89\x1b7\x1b~\xb9\x1aG\xaf<\x00ă\xbd\x80\xb1\xa8D\xdfa\x93\x8f\x95\xee\xd4\r}\xbf\xb0C\x13\xb0\xf3x7!O\xe1\xf7-{\xafa\xac\xa69/\b\x98\x16Om5\xea&d\b\xb9f\x88\x1f\xf13E\x92S\x11\xa7*\x17\xa1\xed\x92ު\x1cf\xa1\x05\x85\xc1\xccՔZ\xcd6sRi9.b1\xe0\"sgO\x112\xe9. \"\x86\x01\x97E\x9b\x8b6\xa26\xa7Ń\x80\xdeZ\xe3I\xc6ŅD>\xa5\x14\xca\xff\x91.:]\x9e\xc7\xe2c\x9b\xd5\xe4=\x98\xe5=úG\x03\xa8_\xf0 \f!I\u07b65,.$\xef\x97T\x17L\xb8Y\xfcG\"\xd5Gn\x8d\x96\xa3\x0f\xadGRw\x16\xd2zX!!7\xdb\n\xad\xf5ܢQ(-\x02ff1\xa6E\xfc\xa4\xf0\xb50k\x1c\xa3\xf2\x00`O\x9c\x02v\x93\x0e\x10u\xee\x98A\xd3\xc4\x1d\x9a\x80\xddވ\xbf\xff'\xf6\u07b4\xecU\xbe\xb0ۓJ\xe7\x8c\x17\xb0\xc7\xd5\r7mYă\xceF\x1c\xc9\xfc\xfdv\x16\xb6\x96Ͱ\xf8=\xd3\x14\xb7\x1a\x9c\x9akJ\xb5\xfakK\xa5\x1ab\xcc\xc6D\x1706CԆ&\x89\x80a\xc0e1\x9e\xe5\xa9=>J\xa6-\x1e\x04\xf4\xd6\x1aO2N\xc0$=\xc4\xf7D\xdb\x06\x8fS\xedo\x9a\xd5\xe4=\x98\xe5\xadQC\xa2\xad\xae\x16=\b\x02ք\x1a\x99\x80\xf1~I$/S[i'QurQ5\x11\x8f\xa4\xee,\x84\x9a\x87\x87\x87[\xa8\x80q\xb9\xd9UhR]uQo\x1103\x8b\xe9d\xf3\xef\x11_\v\xb3\xc61*\x0f\x00\xf6\xc4)`\xa4L\x9b\xcc\"\x9f\xff\xe3_\xa4\x12\xabO\f}\xfc\xd3S\xe2\x0e\xedY\xc8\x17\xf1\xe9\xd3\xf8Yk\xb2;\x9b\xb0\xbap\xec5A\xc0Իb\x93\b\xd1a`\x03\xaa\xed7\x02\xc72̨\xcdyZ\x0f\x81\xf5,\xb8\xa6$K\xfa\"V>2wt\x01c\xa3\xa8AdY\x15a\x18\xf0YL\xb6o\xceE\x99\x8d\x16\x0f\x02zk\x8d'\x19'`\xfad\xdap\xa6{OOp\x9d%27\xef\xc1,\xefZU\x85J\n\x04\x0f\xa2\x80M\xec\x99`\x02\xc6\xfb%\xa4[_\x93\"\xd5\f\x0f\xab\xc3?\xf1H\xeaθ90>7\x9b\n\x8d\xa8\ueb53\xf8\\\x16\xda\x1c\xd8\xf4\x80\xe87jdn!7\x00\xb0%^\x01{\x0eo\xbfC?\xff@\x97N\x1c\xd5֪\xee\xc5o\x88;4\x01\xbb\x88\x9fz\n_\x98\x95\xec\x05U\xd4nW\n\x02\xb6\x8a\xcd_\xfdB\x8d\xba:\x86ܵ\xe8$\xe10/\xee*\xcf\b\x83-tbM\xa9\x83\xf5\x1d\xea\x92.Ͳ\x15\f\xccM\x89M\xb8\xb5#\xcbJ'À\xcbb\x84ve\xa6:\x1dm\x16g<zk\x8d'\x19'`\xe5\xdaFn\x01\x9d\xd6.\xb7\b\x18\xef\xc1,o\xb5\x87%\xf1T\v\x1e\xb8,\x02\xea\n\a*`\xbc_\"g\xd6g\xab\x1dN\xf3\x1e\xadx$ug\x9c\x80q\xb9\xd9Uh\x12\xb1=\xd6I|.\x8b\x80\x83\xf5\xa8\xbbЄP\x8b\xa8\x02&\xe4\x06\x00\xb6\xc4+`\x97\xbd\xf8\x05e\x00xq\x13\x15\x9f\x1b^\xfc\x06[\aV\xfc\x9d\xb8C\u007f\x1bEeQQŝYɮ\xadǿ\xbeCn\x1e\xb4\xac\x03\xcbS\x14줤͔\u070f\x1c\xe9\xc2Z\x03\xf3\xe2\x1e@l\xa1}=\x9b\xd1),$\xe4[\xf6\xc37\x92\xb1l\x9f\x170Ӏ۔2\xa7\xe8\x8a$k,5Àˢ\x01\x9da\xbb\xb6Y\x9c\x91\xb1ú^\x1a\xad5\x9ed\x9c\x80\xe9\xdd\x187\x95\x8e\x99<\x8b\x80\xf1\x1e\xcc\xf2\xf6\xb1\t\xabN\xd4'x\xe0\xb2\xe0\x04\x8c\xf7;]PO\xb6\xf9f\x8c,\x18\u00914\x9cq\x02\xc6\xe5f[\xa1\x02\xb7\xa2\x8f\xe1U\x16\x01㲘L/W\x86\x843\x85\x1e\xb1\x16Q\x05L\xc8\r\x00l\x89W\xc0\xc8\xf9\xf5ػ\xbd\x12\xe3\xdd\xf4N\xe2\xf9\"\xbcq\xfb&\\t\u07b2C\x17\xb070{\x8cȚ\xec\xe3\"\\\xf6\x13/\xde'\b\x98/5\xe5>7\xd2\xe7\xf2\x8f#\xe11\"5\xb2\xd8HuJP\xa6A\xb8\xfd'{\xab\xd1\t\xba\xa3Aj\xee\xf1\xa5\xd1\xce\xdb\xe3\xfa\xa2\v\xc1\x963\xe06%\x94\xdfu<\xc7i\xbd\x9fh\x1a\x98Y4\xa0\xf4\x03}=\xd5hP4 \xa4\xd4\x18⎴\xa1\x16u0j\x9fL\xb7\x9d\x1eb\xb7\xf2ؤ]\x03\xda\xdcv8\x1f\xb9\x9a\x86\xf8\xa2\xf3\x1e\xb8\xf2V%\x05\xfa\x02IU\xa2\a3\x8bI\xff\xbao\x94\xaf߬\xf3Or~#\xc1Z\xd78\xb9\xe4\xdc\x15\x8cЕ\xf8F\xbd\x8d\xf2r΄\x95\xf8Fn1*ĭ\xc4\x0f9܇\xea3\x92\x92;B\xeaJ\xfc\x96`\xf0\xaapH\xc8\x19\xc7\xfd\x1d\xbd\xbe\xe4 _\v\xaeƱ*\x0f\x00\xf6\xc4-`\xe4\xda\v\x95E\xde\xed\xa7ԕ\x10\x97\x9f\xad(*;xٺC\x17\xb0\x1b\xe64\xbf\x90\xeco\a˼\xdb/|,\bX`ԗ\xe6Xۯ}\x9f\x92\x84LjXd\xb1P\x9a\xf2/\xbd\xd18\xb0.éYFvd8\x1e\x1cV6\xbeM\xad\x8ajk\x18\xf0\x9b\xd2\xe3\xd5ά*\x99X\xe0l\x8d,N\x14\x1er\xa7d\x16\x0eZ\rH\x87\xab]ݸ\x95\xaed\x95:\x15W2\xc3vT}\x88\xb0\x84\xfe8Ӓ#\xb9\xfc\x1d\x1e\xa9\x90/:\xef\x81/\xef\xb1<m\x1d\x18\xe7\xc1̢\x01!:մ\x8d>\xcfh\xfa\x1dP\f\xeb\xc8\x0e\xe5߳\xf4YHu\n\x9d//\xe7L}\x16R\xf1\xc3f\xe5\xf5\xdcbTh\x94{\x162\\\x9a\x91\xbd\xa7#Y)z\xb56\xf1\xe5\xe7\xb3 \xf4YHGfiH\xa8\x05W\xe3X\x95\a\x00{\xec\x04l\xa9\xb9\x14\xc7cD\x02\x81\xf9,\xf0N\xb4H\u05c9V^\x00XbV\x9a\x80գy\x86\xb6\xad\xa9!\xf1c\nBdLeџ\xedYT@\xc0\x00`NV\x94\x80\x85ƺVI\xb3\x06x\x8b\x88)\b\x0fj\xa3\x1d\xeb|\xfe\xca\x02\x04\f\x00\xe6dE\tX\xb9\xa2(w\xb1ɪ\xb3\xc5*\xe1^\x95y\x8c?\x97\x1c\xbe\xbc\x00\x00DaE\tXS\xaak\x9e\x03\xc8y\xc1f\x8b\xc7\xec\xacV\x0e\x89V^\x00XrV\x94\x80\x01\x00\x00\xcc\a\x100\x00\x00\x12\x16\x100\x00\x00\x12\x16\x100\x00\x00\x12\x16\x100\x00\x00\x12\x16\x100\x00\x00\x12\x16\x100\x00\x00\x12\x16\x100\x00\x00\x12\x16\x100\x00\x00\x12\x16\x100\x00\x00\x12\x96\xff\x0f}\xc6-\xc8\xe3>\xf6\xcf\x00\x00\x00\x00IEND\xaeB`\x82",
+
+ "analysis/chan2a.png": "\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x04\x89\x00\x00\x01\x95\b\x03\x00\x00\x00M@Q-\x00\x00\x00\x01sRGB\x00\xae\xce\x1c\xe9\x00\x00\x02\xfdPLTE\x00\x01\x00\n\x03\x01\x04\x06\x02\a\n\x06\x0e\x10\r\r\x12\x14\x0e\x12\x1d\x11\x13\x10\x16\x18\x15\x1b\x1a\x13\x13\x1e7\x1f\x1f\x18!# #$\"%$\x1d%%\x1e$%#%'%'(&+)\x1e()'*+)/,!+-*,-+-/,02/63(241564796<9.9;8<=;=>FA?3>@=#CxDA5AB@DFCFHEKH<MH7IKHKLJNOMUP?PROSTRUVTWXV]XG<Z\xa5_ZIY[Y,`\xae7]\xad[]Z\\^[9a\xab;b\xac<c\xad_a^faO]ao>e\xafac`hcQbdaAg\xb2efdCi\xb3ghfMj\xafEm\xb1qjRikhIp\xb4lmkLr\xb7npm{s\\rtqWv\xb6tvsuwt\\z\xbaxzw]~\xb8e|\xb8\x84|dX\x80\xbf{}za\u007f\xbf|~{~\x80}b\x82\xbc\u007f\x81~d\x85\xbf\x82\x83\x80\x83\x85\x82m\x87\xbdh\x88Ð\x86hj\x8ać\x88\x86r\x8c\xc1\x89\x8b\x88t\x8eė\x8do\x8c\x8e\x8bz\x8f\xc0\x8e\x90\x8dx\x92Ȑ\x92\x8f~\x93\xc3x\x95Ē\x93\x90\x81\x95\xc6{\x98Ȕ\x96\x93\xa0\x96w\x96\x98\x95\x82\x9aė\x99\x96\x83\x9cņ\x9b̀\x9d̚\x9b\x98\xa5\x9b|\x87\x9fɃ\xa0Ϝ\x9e\x9b\x89\xa1̞\xa0\x9d\xaa\xa0\x81\xa0\xa2\x9f\xa1\xa3\xa0\xa2\xa4\xa1\x91\xa5ʮ\xa4\x85\x8f\xa7Ѥ\xa6\xa3\x94\xa7̥\xa7\xa4\xb4\xa7\x83\x92\xaaԧ\xa9\xa6\x97\xabЩ\xab\xa8\x9d\xad̫\xad\xaa\xa5\xad\xc1\x9f\xaeλ\xae\x89\xad\xaf\xac\x9e\xb1ע\xb1ѯ\xb1\xae\xa5\xb4Ԣ\xb5۳\xb5\xb2ö\x91\xb5\xb7\xb4\xac\xb7ҩ\xb8ط\xb9\xb6\xb9\xbb\xb8\xad\xbcܱ\xbc\u05fb\xbd\xba\xb3\xbeٽ\xbf\xbc\xb7\xbfԱ\xc0\xe1\xbf\xc1\xbe\xb6\xc1ܹ\xc1\xd6\xce\xc1\x9b\xc1ÿ\xbb\xc3\xd8\xc2\xc4\xc1\xbd\xc4ں\xc5\xe0\xc4\xc6\xc3\xc6\xc8\xc5\xc0\xc8ݽ\xc9\xe4\xd8ɞ\xc6\xca\xda\xc0\xcb\xe6\xca\xcc\xc9\xc3\xceܿ\xcf\xe2\xc8\xcd\xdc\xcd\xcf\xcc\xc8\xd0\xe6\xcc\xd0\xe0\xcf\xd1\xce\xc6\xd2\xe0\xdbҥ\xe1ѥ\xd1\xd3\xd0\xd2\xd3\xdd\xd3\xd5\xd2\xcd\xd5\xeb\xce\xd7\xdf\xe6\u05eb\xd6\xd8\xd4\xd1\xda\xe2\xd8\xda\xd6\xd8\xd9\xe3\xd6\xda\xea\xd3\xdc\xe4\xda\xdc\xd9\xd8\xdd\xe0\xd2\xde\xec\xdc\xde\xdb\xdc\xdd\xe7\xe0\xde\xe2\xdb\xe0\xe2\xde\xe0\xdd\xf0\xe0\xb3\xd5\xe2\xf0\xe0\xe2\xdf\xde\xe3\xe5\xde\xe2\xf2\xe2\xe4\xe1\xe1\xe6\xe9\xe4\xe6\xe3\xde\xe7\xef\xe8\xe5\xea\xe5\xe7\xe4\xe4\xe9\xec\xe7\xe9\xe6\xe8\xe9\xf3\xe2\xeb\xf3\xe9\xeb\xe8\xec\xee\xea\xe6\xef\xf7\xe8\xf1\xf9\xef\xf1\xee\xf0\xf0\xfb\xf2\xf4\xf1\xf1\xf6\xf9\xf4\xf6\xf3\xf7\xf9\xf6\xf5\xfa\xfd\xf9\xfb\xf8\xfa\xfc\xf9\xfd\xfb\xff\xf9\xfe\xff\xfc\xfe\xfb\xfe\xff\xfc\xfa<^\xc5\x00\x00 \x00IDATx^\xed\xbd\x0fX\x15\u05fd\xef}^\xdb\xf7\xcd\xed\xdb\xc5y`\x1f\xe9\x16\nD\xde\xcb{\xc0s\x94\x83xߛ\x8cA\xbc\xafy\xfd\xcbE\xe5`Qo\x8f1\xb4\xc46\x86T\xebc8\xf14\x98\xee\xa6H\x11o\x12RJ\xbc\x1e\"\t\xdd\x16\"\xd1Rk$\xec<MHKbO\tI(m\xec\xb17x5h\xaa\xd3\xd4\x1eBD=>\xf3\xbc\xb3\xe6\xefZ\xb3g\xefa#\xcc\xf0\xe7\xfbɓ\xbdמ\xf9\xad5k\x96{\xbe\xac\xb5f\xf6\xfa\xfe\x854vD\x00\x00\x18\x17\xfe\xc2In\xa2\xe0T6\x00\x00\x8c\x0e(\x11\x00\xc0{\xa0D\x00\x00\xef\x81\x12\x01\x00\xbc\aJ\x04\x00\xf0\x1e(\x11и\xec\x14\x00\xc0\xc4\x01%\x02\x94\xbe\xa2T\xb2\xdc)\b\x80\tc\xda+Q}N\x9fSH\x8c\xf4\xe7\xd4;\x85LB\x94v\x88\\\xf5\xac\xac@\xd3\xe9\b\xfb\x00\x98x\\W\xa2\xe6\x10}\xbdT]\xa9R\xa3n\xed\f4D\xcb$\xfe\xcfG\xd7\xe4o\xbb\x125Ğ\x1dd\xbbSH\xcc\xec\x88\xdb\xe1\x14\xe2D\xe7b\u007f\xda\xea\xe6\xb4>q\x1d!\xc4ߥonJ\x89\xde\f\f\xf5Y\xb3\xe7\xd5.\x18u\xb8\xd6\x0e\x91\xaa~\x8a4\xdan\a\xc0%\xdcV\xa2\xbe\xca6\xfav\xbe\xb2\xbdW\xe6X\xe5)e\xeb\x99@Ku\xb4\\\xe2W\v\x0e\xef\xce\xff j\x88-\x15qUN!c\xa0!\xbe\xc2)Ġ\xb9\xddfc\xa3?;\xb0\u007f>!!\xb1'\x18\xdcCZ\xf5\xed\r\xfe\xa7l\xa2M\xcc\xc2*Ha\xfd\x16BF[\x0f\xa3\x1d\"T\xbd\x8d\x04\xed6\x03\xe0\x16.+Qo\xad\xaaDb\xe7\x80\xfc2PݢnnhꉪD\x1f\b\x87\xc4+\x17\xa2E\xd8\xd3\xed\xbb?z@\u007fn\u007f\xf4\x00{\xca|=N!:\xd9+÷\xf5'\xdd;(\x9f}\x06Q\xfa\x87m\xa6\x129a\x14\xd6E\xca\xe4\xd7M\xa3U\"\xa6\x1d\xec\xab\x1eC\x1d\x00\x98\b\xdcU\xa2\xe6\xca\xe6@\x9b\xf9\xf1\xe0S\x97\x94\xf7Ϊ\x81ިJ\xf4\xaep4\xda\xee\x88\x14\xa5\rD\x0f\xe8$\x9d\xd1\x03\xec\x19H+r\n\xd1Y`\xa3D\xf7'*sW\x15D\x19\x96Š\x02Fa\x85)\xb2\x94\x89!\xb2'Z\xb4\t\xd3\x0e\xf6U\x8f\xa1\x0e\x00L\x04\xee*\xd1\xf9\x01\xb1\xba\xcd\xf8\x14\xaaT'\x93\xcf\x06\xba\xc4(Jtq\x8d\xa0\xb0W\x14\x1f\x15\x84#\xe2\xbby\xc2\x06\x9a\xcc;\xbcwC\xfe\xb6\xdf(1\xef>\xb4&\xaf@K\x9b\f&mՓ]+S\x12R\xef\xe9\xe5vWd6\x84H\xa8!s\x0f_\u0095Û\xf37\x1e\xba\xc2\x1d\x82?\x9aܳH<\xcf\x15%\x16\x93\x84\xc0\xa6L\xff\xe2\x1e\xe5Ӟ\x05\xfe\xf9\xb4\xd4\x06\xa2\xb2@\xd9Z\x9d\xe3\xcf\xdcD%!C\x15\x83\xfe\n*'\x86\n\x9cI$$N\x9b73b\x99r\xd9\u0092\xd5\x13\xab8\xcd\x1e\x8d\xaf\x83q4\xae\x1dl\xaaNi\x86\x12\x01oqW\x89d\x18%\xaamR\xdf\x1b\xe4\xf7h}\xa27:\x8e\b\a::\xde\x17\xc5\xdft\xe4\x1d\x10\xaf\xbc\xfa\xc8\x12Q|\xebH\x9ePp\xe0\a+\x1e\xa2\x11//\xdb\xfc\x83\x13\a\x84g-\x19\xdbI\xb3\x96j\x9e\xb3`G\xd3v\xcb`\xa6\xb7\x90d\x91yde\x0f_\xc2\xee%\xfb\x8e\xef[\xb2\x9b;\x04w4\x99\x16\xeb\x95\x1b\xaa\x89')\xdb+\x92\x94;\xe1\xeb|e\re\xbeB\xb9\x03\xd2\x12\xcc\\\x18\f\x06\x95QXQ\\ICEʂ\xcb\xe2`\x1cW\x0f\xa3?r,\x18\xf4i\xf3\xebF,S.S\xd8\x19\xc2L\u007f\x19G\xe3\xea`\x94 \xb2\xed \xdaT]\xbc\xd4ל\x9d\xec\xd0y\x04`b\xf1P\x89\xba+{\x94\xf7P\xd5@t%bGgK\x0e\xc8/\a\x96(\xc9\x15r\x0feg\x81\x9c\xba\xb8v\xdbE\xf9\xf5\x88uJ\xbb\x81t\xab\x89\xf3s\x17\xcbݏ\xc1Z\xeb\xa4Pc\x02I8(\xf2%\x1c\x17N\xc8\x1bN\b\xc7E\xf6\x10lR\xa6\x87\x84M-\xfb\x92{訉\x96\xaa܈j$J\xc9ƀ\xaaAQ\x8f6\xb2_\xec&ܽtvd\x94\xb8\xdd\x12˖k\x16֩\xde\xea:\u007f~\x90?\x9a\x19˖`\xb6\x03%\xbc\xea\xf7\xca\x1d\xadQ߄\x03`B\xf0P\x89\x9aj\x95\xb7\x81@\xe8\xf2\xe5˧\xab\xa3=\xe2k\xafD\xbb\xf5\xe4q\xe1\r\xdbl\xf5\xfa\x15x\x90\x9c\xb4\xd9ݿ\xc97\x97\xa4\xf9\xb6\xf4s%\xecޠ\xbcmxDd\x0f\xc1&Ez9\xef\xb7\x14&\xfa\xd6\xc9/\xdb}\xf2K\xd1<eC\x16\xdd`*\xd1\xea\x8c\xc1K2s\x8b\xc4\xc1x\xfb>\x91h(\x91\x19˖k\x16vVљղ\x824qG3c\xd9\x12\xccv\xa0\x84W\xfdtce\x16\xfaD\xc0[<T\xa2\xaac\xca[w\xa5\x0e?\x8b\xc3b\xafDF\xf2Y\xe1\xa2m\xb6V\xfd\x1a\xaf 6s#⎔\xca\x10\tU\xa4\x94s%\x94nS\u07b6m\x16#\x1c\x8d\xd2FZ,\x85\x89\xca\xc0JQ\x81\x85K\x95\r\xf7\xe4\xd0WC\x89\xe6k\xd3<\xf7\x1a\xf3D\x83\x8dZYaJ\xc4\xc42\xe52\x85\xa5Љ\x9f\xbe:r\xff w43\x96-\xc1l\a\x8aM\xd5E1H\xda\xc27\x02\xe0\x1e\xde)Q\u007f\xa5\xf6\x87\xba\xbfO\xa6\xb3\xaa/ʳ\xd0\x16%\xdagц\x13\xc2/l\xb3\r\xe8\xd3.M\xc4\xee\xa9\x1eqP\xb9wF\xa7\x8d\x99\x12v\xaf\xa7OP^YO\xfb@\x11\x95\xa8\xdcw\xd6Z\x98\xa9\x02E\x19ʆ\f\xb3O\x148-\x0f\x9a2\xda\x15\xfa\x8d{g\xb5Dy\xb3Q\"&6\\\x89\x94\xc2Ri\xad\xeb\xe8\xc4\x17{43\x96-\xc1l\a\x8aM\xd5q\xef\fx\x8ewJ\xd4]y\x86\xd9<\xday\xa2\xfc\xbd\xb2J\xfc7\x8b6\\((\xa5]\x9a\xc7\xf6Z\xf3\xad\xccP\xc7|\x03i\xb9\xf4\xca-\xd9d\r\xe8\xa1\x13+\"W\xc2qሜ:\xa2\xce\x13EP\xa2\xcbY\xf7XKbT\xa0A\x19\xff\xecW\xe7^rs\xe5\xce\v\xa9\xa539\xb5\xf4sY9}\x9eh\xb9\\\x9d˹\xaa\x86\xd8(\x11\x13\xcb)\x91QX\x97\xf2\xc8t.U\"\xf6hf,[\x82\xd9\x0e\xa2}աD\xc0s\xdcU\xa2\xf3\xbd\xbdUͽj\xe7'T9hl\xbf,\xf7\x89z#>c\xa8\xde;{\x95vU\xc4҂\xa7\x9f\xde,\xe4=\xff\xd6\xfb\x1dy\x8f\xbcz\xe5\x8dG\xf2\xe8=\xb5\x97\xf37\x1c>\xfe\x98pؚ\xb3K\xbfK\xd5<;\xeb[\aKH\xc0\x1a`\xc0\x94\xb0Sx\xe2\xa5'\x84\x9d\xa2\xc8\x1c\x82;\x1a\x1d\xedY\xfbX\xbd\xc1\x84u\xadb\xfb\xba\x84\xa0<\xc6,\x8c\xbb\xbf\xe1\xfe\xb8Be\xc7v_E\xfd\"\u007f\x8f\x9c\xba\x9f\xac\xae\xad/\"Tr\x1b\xfd9U\xf5w\xc5\xcb\xc3$\xe5\x19\xeb\x8a`P\xee\xe7\f\xb6\x06\x83\xbeu\xc1\xe0Y6\x96+\x97)\xac\x82\x145\x14\xa9\xcfX\x1bG\xe3b\x99\xa31\xed`Wu\xca1\xbb!\x1b\x00\xee\xe1\xae\x12\x1dS\xe6\x83\x02\xca𠛹\x85\xd3\xcb\xfc\x04-\x8c\x8b+\x94lj\xf2ަ\x1f\xde-\xcd_\xb6m\x9f <\xfa(\xdd\xf4\xcbe\xf2\xeb\xa3\xf2\xe6\xb7\x1f^\xbbl\xb3\xdeob(\x9b\xad]a]+\xe7&\xe5ԅ\a\x18\x98%\\9\xb4Q\u007f\x9e\xc88\x04\u007f\xb4`\xe2\x16k\xf6bBHB\xa7_~-\x96?U\xccW\x9f\xf0\x91\x19,IN\\ئ$\x1bsS\x92\x17*7\xd4\xc4λ\xfc\xa9K\xe9C\x95\xeb\xb4\xf9\x1cy\xd8\xd5\x16\xa7&+\xd9X\xbe\\\xa6\xb0\xfa\xacĜ\x83s\x95\xd2\xf4\xa3\xf1\xb1\xccјv\xb0\xa9:\xa5/~\xe5\xa9>,\v\x02\xbc\xc3]%r\x9fM\xbeZ\xa7\x90\x98\xd9\xef+\xba\xe4\x143\xd9\xd0\xda!b\xd5보\xd9m\x00<a\xba+\x91X1w\xdcW\x05I\xbb\xed\x9f\xe2{\x80\xd2\x0eѪ\xdewj\xbc\x1b\n\x80\xd13\xed\x95\b\x000\x05\x80\x12\x01\x00\xbc\aJ\x04\x00\xf0\x1e(\x11\x00\xc0{\xa0D\x00\x00\xef\x81\x12\x01\x00\xbc\aJ\x04\x00\xf0\x1e(\x11\x00\xc0{\xa0D\x00\x00\xef\x81\x12\x01\x00\xbc\aJ\x04\x00\xf0\x1e(\x91\v\x1c\xdd\xfc\xfb\xa9jb\r\x80;\xb8\xaeD\xe1n\xd4竔T\x95\xb9\\Ѥ\xe6\x17t\x89\x92\xddQ\x02\x0e\v\xcaZk&O\v\a\xe8\xdaJ\xe3`b\r\xc0t\xc5m%\xb2q\xa3>Sy\x92\xa6\xa7\xca/\xc1\xff\xf0\xeaƍ\x1d\xbf\x8e\x12\xf0A\xc7\xe6\x03\xec\xe7C\xc2\xf3j\"\x16\x13k\x00f\x16.+\x91\x9d\x1b\xf5\x99\xca\xd3ѲL>\xbeZ\xea\x10\xb0\x8dU\xa2w\xf3\x9eГ1\x98X\x030\xb3pW\x89lݨ\xa7\xb9\x12\xed.\xb8\xa0'c0\xb1\x06`f\xe1\xae\x12ٺQ{\xa8D\xe1&\xd6\u007fX\x93\xb7om\xc1ˏ\xad(\xbd\xc0z_s0Jd8Ws\x85\xc9J\xf4\x98 \b\xf9\xbf\x93\xd3\x17\x971\xeb\xfc\xdb:A\x03\x00\\V\"\xd1\u038d\xfaLe\xd3S\x955A\x0f\xaeQ;\x13\xeb\x97W\b{K\x855O\xafy\x96\xf5\xbe\xe6`\x94\xc8p\xae\xe6\n\x93\x95\xe87;\x85g_\xa3\x9b\xdf\x10:̜\xe1N\xd0\x00\x00\x8a\x87J\xa4\xbbQ\x9f\xad\xac>\xd5\x13\xaa\xdd\xef\xfa\xbd3{\x13낝\xe2qᨸ\xdb\xe2w\xc6`*\x11\xe3\\\xcd\x16&+ѳK^\xd2C\xde6sژX\x03\x00DO\x95Hs\xa3\x16\xc5N\xda\x1d:_\xe5zw\xc1\xdeĺ\xe0\x88\xf8\x9apA|b\xa7\xe8\xacD\x8cs5[ض\x03\a\f\x83\xb6\xa3»fN\x1b\x13k\x00\x80\xe8\xa9\x12in\xd4:\xc1h\x1e@\x13\x82\xbd\x89u\xc1q\xf1\xb5<qtJ\xc48W\xb3\x85m+X\xb1\xe1!u\xf2H|Ux\xd5\xcci\xeb\x04\r\x00\xf0P\x89\f7\xea&\xc5+Uln\xb0\x8d\x9f@\xecM\xac\vN\x88\xaf-a\x95h\x9f\xbd\x12]8\xf0\x01\xeb\\\xcd\x16\xb6\xad\xe0\xadwWh\xb3O\x17\x9607\xd2l\x9d\xa0\x01\x00\x1e*\x91\xe1Fݠt\x86\xfa\xabN\xdag\x988x\x13\xeb\xee\x1d\xaa2\xb2J\xc4x_\x9b\x01\x9a\x12ѩhƹ\x9a-\x8c\xde\xc5?\x9e\xf7\x9a\x1a\xfd\xf0\x86+\xfa\x01흠\x01\x00.+\x91\xad\x1buO\xa0\xb1\xeb\xf4\xb1\x80\xeb]\"\x8b\x89\xf5R\xa2\xc8\xc4[\xab\x9e\xbdp$\xef\xad\v;K\u007f\xc3x_3\x01\u007f\xf8\xf9ƍ\x1d2\x87\xe9M1ù\x9a)샎͏\xbcz\xf1¶\x82\x97\u007fO\xb7\xbf-\xfc@?\x9e\xbd\x134\x00\xc0e%\xb2w\xa3\xeek\xaa\xa9j茜k\xe2`M\xac\xabR\xa8\r\xf4\x955\x82pd\x99\xb0\xec\x88 <\xc4x_\x9b\x01\xe2[\x82F\xfeیs5S\xd8a\xba\xf3\r\xb9\x00A\x1d\x97\x1d\xc8\xd7f\x8a\"8A\x03\x00\\V\xa2\x19ɕ\xbdy\xca/b\xa7\xa2\x895\x00.\x01%\x9ax\xae<\xbb\xf6wS\xd5\xc4\x1a\x00w\x80\x12\x01\x00\xbc\aJ\x04\x00\xf0\x1e(\x11\x00\xc0{\xa0D\x00\x00\xef\x81\x12\x01\x00\xbc\aJ\x04\x00\xf0\x1e(\x11\x00\xc0{\xa0D\x00\x00\xef\x81\x12\x01\x00\xbc\aJ\x04\x00\xf0\x1e(\x11\x00\xc0{\xa0DS\x18\xb8\\\x83i\x83\xebJ\x14\xeeF-\x13:XU˯%\xeb\x16\xdd\t$+lc\u007fqj\xe2=\x97m\xa2LJR\x81\xda\x17\xd1eC8\xe3\xb4G\xe8J#̢\xd7V\xe0r\r\xa61n+\x91\x8d\x1b\xb58\xd8\x14h\xedn\xaf슞s\x82h]\xe7\v۶(\xf5[\xeb\x12\xcf\xd8\x04\x8f\x0f\xef\xee\x15^\xbe ^\xe8\x10\xf6r\xba\U000db38eC\xec\xa2\xd7V\xe0r\r\xa61.+\x91\x9d\x1b\xb5\xd8\x14\xe8\xa5\x12\x15\x8a\x92o\x02\xd9\x1e\xa6D\xfdD\xbe\xb2\a\xecbljC\xca\xea\xfb\u007f\x10\x0eYw\xbc\x16M\x89\xe0r\r\xa61\xee*\x91\xad\x1bu_\xa5\xb2\x82\xb5Wk͇+Q\x17\x99\xe0\x95l\xc7E\x89\xe0r\r\xa6\x13\xee*\x91\xad\x1buk\xc0\xab\xa5\f{\vӒWj\xa3\xb3\xea\x1c\u007f\xe6&\xb9#4\x98B\x146q[O\xc5\x13R\xd6U\x98\x9e\xb8\xd8R\xd71\xf9Y\x9bJ\xf4\xa8\x90wx\xef\x86|\xbd\x00C\x89\xe0r\rf\x18\xee*\x91h\xe7F]\xdf\x10\xaa\vԴ\xb8\u007f-u%eV\xd5\xdfE\x14%*\x8a+i\xa8HYpY\x14O\x06\xf7\x93\xed\xc1`\x1f\xb7\xf5|mMzf\xd2\xdcM\x85\xe44W\xc4\xd8\xfc\xacM%z\xebH\x9ePp\xe0\a+\x1eRw\x18J\x04\x97k0\xc3\xf0P\x89t7\xea\xda\x00u\xa3\xae\xa9uݍza\x86\xdc۹<\x9f*Q\x03\xa9\x12\xa91\xa2b\xd1j\x8cθ\xad\vȢ\xb3\xd61\xe4\x18\xfd\xac\xd9\xd1ْ\x15rogg\x81\xbaCW\"\xb8\\\x83\x99\x86\x87J\xa4\xbbQ7(^\x1f\x03U\xc6\x0e\x978C\x02\xf4\xad\x8c*\xd1\xea\x8c\xc1K2s\x95\xf9\x16C\x89\xb8\xad\v||w\x882F?kN\x89v3\x01\xba\x12\xc1\xe5\x1a\xcc4<T\"ݍ\xbaY\xb5\xa1nv\xfb\x01\xbdc$Hߔ\x19\xeb\xf9\xea\xe4\x10\xb9\x97n1\x94\x88ۺ ;\xbc\x881\xfaY\x1f\x16h\x0f\xe7\x82b\xb4\xc6\x05\xe8J\x04\x97k0\xd3\xf0N\x89\f7\xea\xf6*\xe5!¦\t\xbea\x15F?\xd9Cߔ\x19\xeb\u008cv\x85~\xba\xc5P\"n낕\xe1E\x8c\xd1ϺCɦ\xce\xf4\xd8*\x11\\\xae\xc1L\xc3;%2ܨ\xfb\x95\xbb\xf8g\x03\xae?d\x9d3W\x96\x98\xae\xd9T\x89\x1aI-\xddRVN_\r%\xe2\xb6\xda)\xd1\x18\xfd\xac/\xac\xa2C\xb2ݫ\xe8mx[%\x82\xcb5\x98i\xb8\xabD\xb6n\xd4\xe2\xb1\xc0\xb1\x9e\xce\xea:\xd7\xef\xe5w\xfa疗%\xc7\xc5W\x85D\xf1~\xb2\xba\xb6\xbe\x88T\xeb\xf7\xce\xd4{Q\xc6\xd6K\xad\xc1̅\xc1`\xb7\xb5\x881\xf9YS\x8dy\xf4\xf8\xa3Tm\xde\xef\xc8{\xe4\xd5+o<\x92\xd7\xf1\xbe\xf8k\xfa\x8c\xf5\xb3\x1d\x1d\xbf\x16\xe1r\rf\x1c\xee*\x91\xbd\x1b\xb5\xd8U_Uw\xccu!\x92\x8f\xbb49}KU<)\x96Ӎ\xb9)\xc9\v\x0f\x8a\xe2`\xb225\x14\xaf>\xf1\xado=\x15\xa7l\r\xefz\x8c\xc5\xcfZ\xe6\xf8\xe6e\x9b\xe5\x0e\x0f}\xe0H\xc8\xfb\xe52\x81\x06\xec\xd6\\\xae\x1f\x16\xe1r\rf\x1c\xee*\x11\x18G\xe0r\r\xa6\x11P\xa2\xa9\v\\\xae\xc1\xf4\x01J\x04\x00\xf0\x1e(\x11\x00\xc0{\xa0D\x00\x00\xef\x81\x12\x01\x00\xbc\aJ\x04\x00\xf0\x1e(\x11\x00\xc0{\xa0D\x00\x00\xef\x81\x12\x01\x00\xbc\aJ\x04\x00\xf0\x1e(\x11\x98VL\x9cM\x1d\x98P\xa0D`\xfa\xd0W\x94J\x96;\x05\x81I\t\x94\bL\x1f\xb2\xb2\x02M\xe1k\xfc\x82\xa9\x80\xebJ\x14\xe6Fm1\xa6v\x97\xa6\x14c\xa5ȱXP;\x19H3\xbc|\xb7Pz\x85ZP\xdf\xfdr\xe4\xa0\x13\x05\xfa2\xd5\xe2\xff|tM\xfe6c-\xb4\xe84$\x8f~\xbdK\xfd\x8c\xd7\x11B\xfcᶻ\xfd\x8b\x92w\x84'9F}4\xbeu\x98ss\xe2\xe8\x86\xfc\x8dG6\xbe\xe4\x14\x16\xc6)\xd2\xe8\x14\x02&+n+Q\xb8\x1b5gL\xed6\r~c\x95\xa4\xb1XP;\x19H3\\<!\xe4w\x88\x17\x8e\b',K_\xbf\xcc,@\xfbҲ#z\xf2\xab\x05\x87w\xe7\xf3\x9e!\x11\xd9J\xb6:\x85\x18\xe8g\xdc\x13\f\xee\xb1\xf1&ڒ\xb1#\xae/,\xc91\xea\xa3\xf1\xadÜ\x9b-f;\x1c\x12v\x1e\xdd+\x84\xfbR:Ҧ\xaeL\x0e\xa6\".+\x91\x9d\x1b5kL\xed\x1dc\xb5\xa0v\xb0m5\xb9 \xec|D\x14\xdf\x15.\x88<\x9b\x1ff>\x18\x9d\xa0\x0f\xe4\v\xf1\x8a54\x12e\xa4\xcc)Ď6\x1b%\xca.\x17\xfd\xc1\xb0$G,Gc[ǡ\x83g\xb4\xc3\xdbw\xef\x93_\xf7\x8eI\x89`\xfb6eqW\x89lݨ\xadIo\x18\xab\x05u\fJ\xf4\xf2\xb2\v6J\xb4\x91U\"\x83w\x85Q\x8feD\xb1\x9c\x94;\x85\xd8aw\xe1Ϋ\xea!]aI\x8eX\x8e6\xea\xd6a\xdaaw\x01\xed5\xfe\x12J4\xb3pW\x89lݨ-I\xf78\x93HH\x9c2;\xc5[P3\x84\x9bM[\xb7\xda\x19Hwl[\x9b\xb7f\xdbZş\xe3\xf9\xcd\xcb6\xec\xa5\xeasAxw\xe3\x11M\x89\x8cأڊ\xb1\x9b\xe5\x8d\x1f\xe4\v\x82\xb2\x92\xbexq\x8d\xbau\xaf<\xa6\x91\xdf\xf6\x89Ok{\xec\xab#\xee ʄNO\x92抔\xd4\xc3\xec,&\t\x81M\x99\xfe\xc5t\x9by\xc6\x14\xbb\v\xf7\x9e\xb2{睊W\x16\xcfe\x92\x1c\xda\xd1\xc4XZ\xc7<7\xa6I\x18+n\xb6\x1dV=\xa1\x84\x1d\xa2\xeby\x1b\r\xc5\xd9v\x9b\x8d\xca\xd3\f%\x9a\xba\xb8\xabD\xa2\x9d\x1b\xb5%\xe9\"ǂA\xdfv%\xc5ZP3ؙM[\xb6\xda\x18H\xbfq\xf7\xee#'\x0e\xaf\x11\xfe@\xb7\n\x8f\x1d?T\xb0\xf1\x8a\xa2D\x87\xb6iJd\xc4^x\xb5cCiGG\x87\xe2\xe7\xfaZGG\xbe\xbaD\xf5\x1b\x1dG\x84\x03\x1d\x1d\xefӀ\xb5\x8f\xfe^\xfc\xfd\x81\x15\x1d\x17\"U\x87\xae\xa8_A\xdf\x06\xab*T\xaaX;\xddPM<I\xd9^\x91\xa4\xdc\xdd6\xcfX\xb4W\xa2\xf2$߱K\xf7,l\xe5\x93\x1c\xda\xd1bk\x1d\xf3\xdc\xcc&a\xac\xb8\x99v\xf8@x\xde,\xcch(ζ\xdblT\x86K}\xcd\xd9\xc9c\x18^\x83Ɂ\x87J\xa4\xbbQ\xf3I\x97IԯK\xbbљ\xbd\xd94\xbf\xd5\xc6@\xfaP\x01\u0560C+\xae\xd0.\xcd\xf3J\xcc\x11E\x89~\x97\xff;E\x89\x98X\xcb\xe8L\xbfZ\x99\xd1\xd9\x01\xdaOP\x9c\xad\xed\xab#\x13 \xeaJ\xfd}\xdd*\x16A\xf5%\xf7\x88ba\x8a\xf6)1\xaa\x12\xed \x01\xf1\xac\xff\xa0%ɡ\x1f-\x96֡h\xe7\xc64\tgŭ\xb7\xc3/\x95ƹr\xf1\xe2E\xbe\xa1\xccX\xb6\x04\x93{\xe5\xce\xe0\xd8\x06\xd8`2\xe0\xa1\x12\xe9n\xd4|\xd2e\xa2*\x91\xbd\xd94\xbf\xd5\xc6@\xfa\xd7\x05\xeb\x1f;\xfc\xc6\x15:۱s\xfd\xc5?Ȭݭ(\x91\xb8\xedYE\x89\x98Xg%\xfa\xcdݿ\x14/\xae\xa0W\xa4}ud\xaaH\x15}\xeb&:\xbc\x1b\x92o\x9d\xa8Y\xddR\xa2*Q-I\xde$V\xa4]\xe2\x93<\xda\xd1bj\x1d\x8avnL\x93pV\xdcz;\xa8}\xa2\x9d\xf2P\xed\x04\xd7Pf,[\x82\xc9\xe9\xc6\xca,\xf4\x89\xa6.\x1e*\x91\xeeF\xcd']&\xaa\x12ٛM\xf3[m\f\xa4\xc5\x0f\x0e?\xbcAX\xf3\xb4\xdc'ڨ\xcd\u007f<\xa4*ё\x8d\x8a\x12\xb1\xb1\x8eJ$n\xdb+\x1e_A\x0fi_\x1d\x99\x96dUR\x82\r*\x96;^\xcaxlTJ\xd4\xe7\xdf\xd4<\xbb;c;\x9f\xb4\xa0\x1f-\x96֡h\xe7\xc64\tg;i\xb4\xc3\x1a:O\xf4\xfe\x11ቋ\\C\x99\xb1l\t\x1cA\xd2f\xdd\x04\xa6\n\xde)\x91\xe1F\xcd%\xdd&\xaa\x12ٛM\xf3[m\f\xa4_{BN~p$\xff\x10\xfd\xf3\xfd\v\x85ߩJta\xd9\t\xa5Od\xc6jW\xe0\xe1_\xab\xa5\xd9)\xd1\xd1U\x17\x95\xc1Y\x84\xea83z%\xaa\x97{S\xcbӓ\xce\xf0\xc9\b\xc4\xd2:\x14\xa3Od4I\xb8\x12\xd1vؽ\x86j\xd9Qz\xef\x8cm(3\x96-\x81\x03\xf7Φ0\xde)\x91\xe1F\xcd%\xdd&\xaa\x12ٛM\xf3[m\f\xa4\x0f\xa8\x13@\xa5\x8f\xd2\xebR\x99\xcc\xd8\xf7\xb4\xaaD\xe2\xee\x9d\xea<\x91\x11+\x87\x95\x8a\xe2\xef\xf59\x0f;%\xba\xb8\xe6誗\xc3\x0f<zF\xafDu\xa4K<IV\x8b\x97ӻ\x99\xa4hO,\xadC\xd1\u038di\x12N\x89\x8cvx\xfbny\xeb\x95R\xaaDlC\x99\xb1l\t\x1cP\xa2)\x8c\xbbJd\xefF\xcd&\xddd\xb05\x18\xf4\xad\v\x06\xcf\xf2\x16\xd4\fvf\xd3\xecV{\x03\xe9\x03²\x03/\x1d\xdd-P\xf9x\xe2\xee\x9dG\xe4\xe4\x11\xfa\x8c\xf5\x91\vrV\xe5\xde\x19c6-_\\\xcf\x1e\xfd\xea2\xb9\x84\x8b\xafvt\xe4?\xd2\xd1\xf1\x81~\xef\xecU\xed\xe6\xd0\x13\xebW\xfc!\xbc:\f\rs\xa2L\xd5\xf6\x06\x13ֵ\x8a\xed\xeb\x12\x82\xbd\xec\x19+\xcfXW\x04\x83\xdcϴ\xfa\xfc+\xeb\xd23}%\xe5\t}L\xd2R\xa0q\xb4\x18Z\x8797\xb3IX+n\xa6\x1d\xe4\x01\xde\xee\x97v\xab\xcfX\x1b\r\xc5\xc5\x1a%X8F<~<\x16\x8c\x1dw\x95(\x82\x1b5\x93t\x936\xd5b\x9aTZ,\xa8\x19\xc2ͦ\xb9\xad\xf6\x06\xd2ϗ>\xbd6\xaf\xa0T\xfd}ى\xd25+J\x8f+\xbf;\x93/\x9d+\x9b\v\xaep\xb1\xf2E\xfaت\xfc\xd2\xd7\xe4\xc4\x1bZa\x87ŋ+\x94D\xde\xdb\xda\xe1\x04}n\x96\xad\x0e\xc3\xc1\x94\xf0;\\\x06\xc5\xf2\x89%t\xfa\xe5\xd7b挕ߝQVr\xc1M\x19)\xc5\x03M\x99\xc9{\xb8$\x8fy\xb4ѷ\x8eyn\xa2\xd9$\xac\x157\xd3\x0e\xca\xef\xce6\x1f_K;BFC\xf1\xb1z\t\x16\xfa\xe2W\x9e\xea\x8b\xf1\xa7\x83`\x92\xe0\xae\x12\x81\xb1paI\x94\x1f\xcd\x02\x86\xfa,B\xeeu\n\x02\x93\x12(\xd1\xe4\xe7Ț?8\x85\x00\x8d\xbeS\x1e<\xac\x0f\xc6\x01(\xd1$\xe7闯|\xf5\x80\b\xc04\aJ4\xb9\xb9 l~\xb4`\x94\x8b\x83\x000u\x81\x12Mr\x0e,+}\xdb)\x06\x80)\x0f\x94\b\x00\xe0=P\"\x00\x80\xf7@\x89\x00\x00\xde\x03%\x02\x00x\x0f\x94\b\x00\xe0=P\"\x00\x80\xf7@\x89\x00\x00\xde\x03%\x02\x00x\x0f\x94\b\x00\xe0=\xae+Q\x98\x1b\xb5(\x0e\xb4<\x15x\xaae\xc0!\xe34b\x92\x98X\x030yp[\x89\xc2ݨ\xc53\xd5u\xa1\x9eP]\xb5g\xeb6\xba\xce$1\xb1\xa6|\xf0~\xe4}\xcd\xed\x91\xf7\x010\xbe\xb8\xacDvn\xd4\xc1Z\xea\x1fq\xa9vFy\x9a\x8f\xda\x1cu\x02M\xac\xa9\xb1\xe1\x8aR-y\xf9\xd2\xe5\xcb\xf2\xff\xec\xdel~\x155\x00&\x10w\x95\xc8֍\xba\xa9^\xf9P\xef\x89\xf9\xa2WĠD\x13fb-\xbe\xb5YмZ\xbb\xb2\xb3\xb2\ue657\x95\xb5\x89\x1d#/\x80\x12\x01\xd7pW\x89lݨ\xfb\xab\x9b\xfb\a\xfb\x83\xd5\xfd\x91rM=Fo\xd3졉\xf5\x85\xbd\xc2ڗ\xd4\xe4%\x1f\xc9͝\xe5\xcf͞\xf5\xc0ymo\x83\xb6\xba\xec\x02Q<\x15OHYWaz\xe2\xe2K\xc5$\xaeZ\xec\xf6\x91,%\xa6:ǟ\xb9i\x06\xcd\xef\x81\t\xc4]%\x12mݨ\xcf7UVV6\xea\x97\xc04 \x16\x9bf\xafL\xac\xaf\x1c-\xc8{B\xedh]|\xf7\xed\xff\xbd\\\x92B\xc3\xd2\xc8g\x97\xea\u007f\x0f\x06Z\x82\x99\v\x83\xc1`H\xfe\xf7\xa9\xadI\xcfL\x9a\xbb\xa9\x90\x9c\xee\r&l\x17\xc5\xd6u\x8aQHQ\\ICE\xca\x02,\x1c\r\xc6\x01\x0f\x95H\xb7\xa0\x1el\xaa\r\xf5\x86j\x9b\xc2\xddF\xa7(\xb1\xd84{fb\xfd\xa8\xb0\xf1--Y*\xfc?\xff\xe7\xacY\xb3ĕ\xb3f}\xa6\x9c\xb9o\xc0\x8c\xce\x16\x90EgE\x91:!\x98\x96E\r\x8a\x17l\x1b\xd9/\x02p\xdbx\xa8D\xba\x05u\xb0\x96z\f\r\xd6N\x1b\x87\x98Xl\x9a=3\xb1~~ɪ絉\uedcf\x1e\xfd\x1f\xff\xef\xff%+\xd1\u007f\xb8wG\x17\xe3\xf7\xc4*\x91Ow#2\x95hu\xc6\xe0%\x99\xb9E\"\x00\xb7\x8d\x87J\xa4[P\aN*o'\x03v\xe1S\x91Xl\x9a\xbd3\xb1~w\x9b\xb0Y\xef\x15\x89\x97\xcf\x06d%\x8ao\xefg\x8d\xe7X%\xca\xd6S\xa6\x12\xcd\xd7f\x92`\xa6\x01\xc6\x01\xef\x94Ȱ\xa0֔\xa8}\xda(Q,6\xcd\x1e\x9aXә\xa2\xbd\xc6-\xb9Z\xaaD]\xdc\bYQ\xa2\xc0i#\xa9\xa0(Q\x19U\xa2\u008cv\x85it\xa7\x01x\x87wJdXP7k\xa3\xb3\xe6\b9\xa6\x1c\xb1\xd84{jb}a\xafPpBK\xdb(Qn\xae(\xf6\x91Z\x9a4\x95ȿU\xeeAeS%jTw\x95\x95\x8b\x00\xdc6\xee*\x91\xad\x1b\xf5\xf9\xfd\xb5\x9d=\x9d\xb5\xfb\xa7\xcfͳ\x18l\x9a\xbd4\xb1\x96y\xabT\x1f\xe4\xd9(\xd1v_E\xfd\"\u007f\x8fx\xa9U\xb9\x8d\xa6\n\xea\u0094\x1d\xe59$\xbe*$\x8a\xf7\x93յ\xf5E\xa4\xdaZ(\x00\xb1\xe3\xae\x12ٻQ\x0f\xb6\xd5Uյ\xb13\x14S\x9d\xd1\xdb4{ib\xcda\xa3D\x83%ɉ\v\xdbD\xf1\x94\xeaa\xad\njWnb\xd2\xe2\xafPkk\xb9W\x94\x9b\x92\xbc0\x8a\x116\x00\xa3\xc6]%\x02.\x12\x9b\x89\xb5\x8d\x12\x01\xe0\x1eP\xa2iKl&\xd6P\"\xe0)P\xa2鉓\x89\xb5`\xe5\xff\x96\x95\xe8\xff\x80\x12\x01\xaf\x80\x12MK\x1cM\xac\xa1D`r\x01%\x9a\x9e\xc4lb\x8d\xd1\x19\xf0\x14(\x11P\x80\x12\x01O\x81\x12\x01\x05(\x11\xf0\x14(\x11\x90\x19ܳ\x92\xfe\x02vk\xcbtz\xaa\vL%\xa0D@&G_\x15\xa4\x0eR\x04<\x01J\x04D\xf1\xfc\x1d\xe5\x924$I#w,\x9f9\xbe\x06`R\x01%\x02\xa28@Hn\xee\x1d\xa9\xb9ٳ\x8a\xf0\xcbz\xe0\tP\" \x8a\x97\x82s\x93\x933\x93\x93\x93\x17\xb5M\x9f\xdf!\x83)\xc5LV\xa2\x95$\xa50\xe4\x1443\x18\xec\xeb\xee\xea\xee\xee\xea:\x8d\xf5\xf1\x817\xccd%\xeam\xae\xcaJ\xc1\xa5\xa7B\xbd\xce,~g\x00\xb8\x87\xebJd\xe3F}\xf9T}\xa0Λ\xceI39\xe5\x14\x02\x00\x98x\xdcV\"\x1b7j\xb1\xa1\xaa\xbd\xfbX\xe0X\xf4\x8c\x13C\x1biu\n\x01\x00L<.+\x91\x9d\x1b\xf5\xc9\x00\xbd_\xd3\x15\xf0b\x9c\x04%\x8a\xc8,\xcfq\xaa!\x98N\xb8\xabD\xb6n\xd4\r\x8dʇj/:EP\xa2\x88\xcc:\xe71P\xa2\x19\x85\xbbJd\xebF]\x17T>\xd5{\xb1\f\xe9)2m\xd6\xf1\x1fo\xa0D\xc0M\xdcU\"\xd1\u038d\xba\xa5Z\xf1\xf6\xa8\xaa\xb3\xcf0\xa1\f\xa6\xe4\xb4\xf4\xe0\x86\x91\x1dP\"\xe0&\x1e*\x91\xeeF=P\xd5\xd0w\xbe\xb7\xbe\xb2\xd6>\xc3\xc4r\x90\x10\xb2\xd4)hF\x02%\x02n\xe2\xa1\x12\xe9n\xd4b\u007fCee\xa0\xb5\xa1\xde6~b\x19Hɨh\xeev\x8a\x9a\x910J4jQ\x1au\xe0\xb9Q\xc4B\x89f\x14\x1e*Q\x959E}\xbe\xff\xb2\xa8\xdcGs\x9b6\xd2\xe4\x142S\x81\x12\x017\xf1N\x89\f7jQY\x9e\xabK\x9d\xbev\x19\xdc;\x8b\b\x94\b\xb8\x89wJd\xb8Q+\xb7\xd0\xce\xd6xr\x13\vJ\x14\x11Y)~\xfa\xb7w\xcc\xfa\xc2?ɚ\xf0\x8d/̺\xe3\xef~%\xab\xc3\xd7?\xff\xbf}\xfe\xeb\xf2\x8e;\xe4\xf4\xdf\xc9\xff\xdf\xf13U5\xbe\xf3\x85Y\x9f\xfb\x06\x13(\xe7\xfc\xec\xdf\xfe\x8a\xd9`\x16\U0005dfda\xf5\xf9\xbf?g*\x91V\xe4\xb9Y4!\x97a\x1eթ\x86`:\xe1\xae\x12ٺQwU\xb6\xf5\x9c\xacn\xf0\xe2\xc1F\xb1\x15J\x14\tY)\xbe\xf0\xe5_\xbd\xf7\xcf\u007f#k\xc2_>\xf3\xde\xcf\xfeNV\x9e\xef|\xee\x99\u007fy\xe6s\xdf9w\xee/\u007fx\ue9f3~v\xee\x9f\xffRU\x93\xef\xfd\x87\xef\xbd\xf7ӿc\x02\xff\xea\x99\xf7\xfe\xe5\xbf\xfc'f\x83\x91\xf8\xe7\xbf\xfa\xe7\xf7~\xfa\x1f\xff\xdeP\"\xa3\xc8Y\x9f{\xe6\xbdg>\xf7ߙ\xa3:\xd5\x10L'\xdcU\"{7\xea\xf6ڪ\x86\xf6ș&\x8c\xc1\xde\xf6\x95\xbe^\xa7\xa8\x99\x8a\xac\x14\x9f\xd1z<\xb3~(\xbf\xfc\x8b\xdc\x0f\xfa\xe2w\xa8v|\xf1ܹ\xff\xf2\xe5s_\x9e\xf5\x8ds\u007f\xff\xff\xa9\x01_\xfc'K \xe5_>\xc7l0\x12w\xd2\xc4\xcf>o(\x91Q\xe4,%q'sT\xa7\x1a\x82鄻J4\xb9\xb8\x97\x90t/n\xd8M\rd\xa5\xf8\xafw\xfc\xe7oPYPEC~\xfd,\x1d^\xfd\xea\xb3r'\xe8\xaf\xcf\xdd\xf9\x9f\xfe\xe6\xdc\x17\xbf\xa7\x89Ư\xce\xe9!\xea\xeb\xcf\xfe\xe6\x8eY\xb3f1\x1b\x8c\xc4\x1d\xea/9\f%2\x8aT\xca\xf8\xd5\x1d\xccQ\x9dj\b\xa6\x133Y\x89\xfa\xda{\x9cBf0T)~\xf8\xe5\xbf\xfd\xec\x97\xed\x94\xe8\xbd;~\xf6\x99\x9f\xdd\xf1\xb3Y\xef\xa9rr\x87U\x89\xee\xfc\xaf?;\xf7\x9e\xad\x12\xcd\xd2z<\x91\x95\xc88\xaaS\r\xc1tb&+\x11\x88\x86\xa6\x14?\xfd,##\xc6P\xeaܝ\xff\xf9?\xca\xffߩ\xa9ʝ\xfa\xe8L\u007f\xfd\x8c,Q\xcf\xd8*\xd1\x17\xbf~\x8e\x8d\xb5\x19\x9dQ\x94\xa3:\xd5\x10L'\xa0D\xc0\x1eY)\xfe\xfa\xbf\xbf\xf7\xde\u05ff\xc0\xc8\xc8w\x94Ye*\x19_\x9e\xf5e\xe5\u007f\x95g>\xa7\xcdX\xeb\x81_\xf8\xf2{?\xfcK[%z\xe6\x8eo\xfc\xea\xbdg\xfe\xdaP\"\xa3Hu\xc6\xfa{\xccQ\x9dj\b\xa6\x13P\"`\x8f\xac\x14\u07fbs\xd6\x1d\u007f\xf3SFF\xce}\xfd\xf3\xb3\x94[\xee\xe7~8\xeb\xa7\xe7~\xaaLC+\xfc\xd3_\xa9w\xf1\xf5\xc0\x1f~a\xd6\xe7\xben\xabD瞹\xf33\xb3\xee|\xc6P\"\xa3\xc8Y4A\xef\xe2\x1bGu\xaa!\x98N@\x89\x80=\xbaR\xb8E\xd8\xf1\xa0D3\n(\x11\xb0\aJ\x04\xdc\x04J\x04\xec\x81\x12\x017\x81\x12\x01{\xdcV\xa20\xa0D3\n(\x11\xb0\aJ\x04\xdc\x04J\x04쉺ؽ+8\xd5\x10L'\xa0D\x00\x00\xef\x81\x12\x01\x00\xbc\aJ\x04\x00\xf0\x1eו\xa8Y\xb3\x9d\x1ehy*\xf0T\x8b\xba(Q_}U\xa3\x17+6:\xf1\x88 \b\xf9\xef\xea\x9fN\x14\x1c\x8d\x16\xccrtC\xfe\xc6#\x1b_r\n\x03\x00h\xb8\xadD\x9a\x1b\xb5x\xa6\xba.\xd4\x13\xaa\xab\xa6\xeb6\xf6\x04\x82]\xc1@O\xb4l\xde\U0001b38eC«\xfa\xa7\x97\x96\x1d\x89\x16,\xbe\xfc\v=uH\xd8yt\xaf \x1c\x8a\x16=z\x9a\xbdX\xbb\t\x00wqY\x89\f7\xea`-]\xbd\xfaRmP\x14/\xd7е\xf4[j&\xa5\xed\xd8k\xa6\x12\x89W\xa2\xc4\xc9l~XK\xbc}\xf7>\xf9u\xefx)Q\xf6J\xa7\b\x00\xa6<\xee*\x91\xe9Fݤ.QV\xdf$\x8a\xa1\xc0y95\x10\bE\xce\xe7\x1d\xac\x129\xb0QW\xa2\xdd\x05\x17\xe5\xd7_\x8e\x97\x12-\x80\x12\x81鏻Jd\xbaQ\xf7W7\xf7\x0f\xf6\a\xab\xfbeQRm\xa8\x0fz\xb0\xa4\xfe\xbb\x0f\xad\xc9+\xd8\xf6\x9b([u%\xfa _\x10\x04mtv\xe5\xf9\xcd\xcb6\xec\xbd \x8a\x8f\ny\x87\xf7nȧ\xa1G\x05\x95\xcd\xf2\xfeUO(a\x87~Mc\x0fo\xce\xdfx\xe8\n\x17˔\xc0ГDT\x92z\x98\xad\r\xda\xc6\x05\xa2x*\x9e\x90\xb2\xae\xc2\xf4\xc4ŗ\x8aI\\\xb5\xd8\xed#YJLu\x8e?s\x93'ˀ\x030^\xb8\xabD\xa2\xe9\xedq\xbe\xa9\xb2\xb2\xb2\x91\xf6\x86\xeaT\xa3\xb3\x16\xf7\x17r}y\xd9\xe6\x1f\x9c8 <\x1be\xab\xd1'z\xad\xa3#\xff\x80\x9a\xdc-<v\xfcP\xc1\xc6+\xe2[G\xf2\x84\x82\x03?X\xf1\x90(^x\xb5cCiGG\xc7۲h\tϛ\x85\xed^\xb2\xef\xf8\xbe%\xbbE6\x96)\x81a\xb0\xaaB\xa5j\x90\xd9:\xd0\x12\xcc\\\x18\f\x06\xe5\x0e\xe3\xf9ښ\xf4̤\xb9\x9b\n\xc9\xe9\xde`\xc2vQl]\xe7\xa3!Eq%\r\x15)\v&\xe5\xe0\x16\x80Q\xe2\x95\x12\r6ՆzC\xb5M\x97\x8c-mՑ3M\f\x17\xd7n\x93\x87Q\x17\x8f|\x10e+;:Ӕ\xe8%Ei^SzHKV\xc8}\x9c\x9d\x05\xcav}t\xf6K\xe1\x84\xfcz\xe5\xe2E\xb9\x98\xe3J\xfa\x84p\x9c\x8beK0\xe9\xebV\xb1\xdeEdFg\vȢ\xb3\xa2H\r\t|\xb2\x12\x89۩\x125\x90*\x91\xda%\xed\x17\x01\x98\xbax\xa5D\xc1Z\xfa\x97\xa8\x1c\x16}\x00\x00 \x00IDAT\u007f\xb0V\xee\x0f\xd5\x05\x95-\xcdu\x913M\fDž7\x1c\xb7\xda(\xd1\xce\xf5\x17\xff \xb3V\xee舴\xb7#\x1eX\xa2lוH\xed\x13픇j'\xc4\xdd\x1b\x94M\x1b\x1e\xe1b\xd9\x12\f\xba\x89\x8e\xc5\x1d\x9bU\"\xdfi-e*\xd1\xea\x8c\xc1K2s\x8bD\x00\xa6.^)Q\xe0\xa4\xf2v2 \x8aM\rJ\xb2\xde\xf5y\xa2g\x85\x8b\x8e[m\x94h\xa36%\xf4\x90\x9c^B7Y\x94H\\C\xe7\x89\xde?\"<qQ,ݦlٶ\x99\x8beK0\t6\xa8\x04E\x1eV\x89\xb2\xf5\x94\xa9D\xf35\xfd\xbaW\x04`\xea\xe2\xb1\x12\xb5\a\xa8\x05#\x1dn\x9c\xadt\xfd\xde\xd9\t\xe1\x17b8\xfcV\xdb>\xd1/\x14~'\xda(\xd1\xe1_\x8b\xe2\xee5Tˎ\xd2{g\xbb\xd7ӹ\xa0+\xebws\xb1l\t\xce(J\x148m$\x15\x14%*\xa3JT\x98Ѯ\xd0\x1f!;\x00S\x01\xaf\x94\xa8Y\x1b\x9d5\xd3\xe7\x89ho\xa8\xd9\xfd\xe7\x89.\x14\x94R\xc9xl\xaf\xf2\xa9{G\xb7\xcdV\x1b%:\xa1\xce\xef\xec{Z䕨\xb4T\x14\u007fO\xf7\xbd}\xb7\xbc\xf5J)U\xa2\xe3J\xec\x11u\x9eȈeKp&7W\x14\xfbH-M\x9aJ\xe4\xdf*7\\6U\xa2FuWY\xb9mf\x00\xa6\x06\xee*\x91\xe9F}~\u007fmgOg\xed~z\xf3\xac'\xd0\xdc\xdd\xec\xc53\xd6/\xe7o8|\xfc1\xe1\xb0\xf2a)\xb9Ǻ\xf5\xd7\xf4\x19\xebg;:\xe4~\xce\xc5W;:\xf2\x1f\xe9\xe8\xa0\xf3\xd8Oܽ\xf3\xc8\xd1ݲ\x9a\xbcߑ\xf7ȫW\xdex$\xaf\xe3}\x91\x8a̳G\xbf\xba\x8c\u07ba\u007fV\xd8\xfd\xd2n\xf5\x19\xeb\x9d\xc2\x13/=!\xec\x14\xf9X\xa3\x84Ѱ\xddWQ\xbf\xc8\xdf#^jUn\xa3\xa9z\xb90eGy\x0e\x89\xaf\x92;\x92\xf7\x93յ\xf5E\xc4\xf5\t\u007f\x00\xc6\x11w\x95\x88q\xa3\x1el\xab\xab\xaakSoX\xf76\x06\xea=q\x85~\xfb\xe1\xb5\xcb6k\xbf&\xabJ\xa9\xb4nݭ\xcd\xe7\xc8î7\xb4\xa4\xa2Z'J\u05ec(=N\x9f\x11\x12\x84\xbc_.\x93_\x1f\x95\xb7^|lU~\xe9kJ\tG7\xe4o>\xbe\x96v\x84\xae\x1cڨ?O\xc4\xc6\xea%\x8c\x86\xc1\x92\xe4ąm\xa2x*N\x99\x0fR\xf5\xb2+71i\xf1W\b)\x96Ӎ\xb9)\xc9\v\x0fF-\x03\x80I\x8e\xbbJ\x04\x00\x00v@\x89\x00\x00\xde\x03%\x02\x00x\x0f\x94\b\x00\xe0=P\"\x00\x80\xf7@\x89\x00\x00\xde\x03%\x02\x00x\x0f\x94\b\x00\xe0=P\"\x00\x80\xf7@\x89\x00\x00\xde\x03%\x02\x00x\x0f\x94\b\x00\xe0=SA\x89V\x92\x94B\xd7\x17/\x02\x00\xb8\xc8TP\xa2\xde檬\x14xW\x000\x8dq]\x89\xecܨͭ\x91h&\xa7\xa2\a\x00\x00\xa62n+\x91\x9d\x1b\xb5\xb95\"m\xa45z\x00\x00`*\xe3\xb2\x12ٹQ3[#\x02%\x02`Z\xe3\xae\x12ٺQ3[#\x02%\x02`Z\xe3\xae\x12ٺQ3[#r\x8a\xb8\xeeA\x04\x00p\x0fw\x95H\xb4s\xa3f\xb7Fb0%\xa7\xa5\xc7u\xf3\x0f\x00\x80Kx\xa5D\x8c\x1b5\xb352\a\t!K\x1db\x00\x00S\x15\xaf\x94\x88q\xa3f\xb6Fd %\xa3\xa2\xd9\xe2\xd2\f\x00\x986x\xa5D\x8c\x1b5\xb35\"m\xa4)z\x00\x00`*\xe3\xb1\x12\xb5\x8fZ\x89p\xef\f\x80i\x8cWJĸQ3[#\x02%\x02`Z\xe3\xae\x12ٻQ\x9b[#\xd2\n%\x02`:\xe3\xae\x12ٻQ3[m\x19\xecm_\xe9\xf3ĭ\x1a\x00\xe0\x0e\xee*\xd1ظ\x97\x90\xf4z\xa7 \x00\xc0\x14f*(Q_{\x8fS\b\x00`J3\x15\x94\b\x000݁\x12\x01\x00\xbc\aJ\x04\x00\xf0\x1e(\x11\x00\xc0{\xa0D\x00\x00\xef\x81\x12\x01\x00\xbc\aJ\x04\x00\xf0\x1e(\x11\x00\xc0{\xa0D\x00\x00\xef\x81\x12\x01\x00\xbc\aJ\x04\x00\xf0\x1e(\x11\x00\xc0{\\W\"\x1b7\xea\x81`m\xa0\xfeԥh\xb9\x00\x00\xd3\x1a\xb7\x95\xc8ƍ\xfalU}g\xf7\xb1\xaazH\x11\x003\x16\x97\x95\xc8\u038d\xba\xb9\x96\x1a\x99\xf5\a\x8eE\xcb\b\x00\x98θ\xabD\xb6n\xd4u\xb5꾆\b\x99\x00\x00\xd3\x1ew\x95\xc8֍\xba\xb7G\xd9\xd2\xf2T\xe4|\x00\x80鍻J$Fr\xa3\x16\xc5\xcb5A\xfb\f\x00\x80\xe9\x8fWJdq\xa3\x96\xbbDU\xfd\x91\xb2\x00\x00\xa6;^)\x91ōZl\xad\x84\xd74\x003\x17\xaf\x94\x88w\xa3\xbe\xd4\x1c\bE\xca\x00\x00\x98\xfex\xacD\xaa\x1b\xf5@C5\xec\xcc\x00\x98\xc9x\xa5D\xac\x1bu\xff\xfe:\xea\xbah\xce^\x03\x00f\x18\xee*\x91\xad\x1b\xf5\xe9\xc0\xfe\xee\xde\xdeޖZ\xa7\xdc\x00\x80銻Jd\xebF}\xb0R\x05O6\x020cqW\x89\x00\x00\xc0\x0e(\x11\x00\xc0{\xa0D\x00\x00\xef\x81\x12\x01\x00\xbc\aJ\x04\x00\xf0\x1e(\x11\x00\xc0{\xa0D\x00\x00\xef\x81\x12\x01\x00\xbc\aJ\x04\x00\xf0\x1e(\x11\x00\xc0{\xfe\xe2+\x00\x00\xe05\xb7\xd3'\x02\x00\x80\xf1\x01J\x04\x00\xf0\x1e(\x11\x00\xc0{\xa0D\x00\x00\xef\x81\x12\x01\x00\xbc\aJ\x04\x00\xf0\x1e(\x11\x00\xc0{\xa0D\x00\x00\xef\x81\x12\x01\x00\xbc\aJ\x04\x00\xf0\x1e(\x11\x00\xc0{\xa0D\x00\x00\xef\x81\x12\x01\x00\xbc\aJ\x04\x00\xf0\x1e(\x11\x00\xc0{\xa0D\x00\x00\xef\x81\x12\x01\x00\xbc\aJ\x04\x00\xf0\x1e(\x11\x00\xc0{\xa0D\x00\x00\xef\x81\x12\x01\x00\xbc\aJ\x04\x00\xf0\x1e(\x11\x00\xc0{\xa0D\x00\x00\xef\x81\x12\x01\x00\xbc\aJ\x04\x00\xf0\x1e(\x11\x00\xc0{\xa0D\x00\x00\xef\x81\x12\x01\x00\xbc\aJ\x04\x00\xf0\x1e(\x11\x00\xc0{\xa0D\x00\x00\xef\x81\x12\x01\x00\xbcg\x14J$\xee\xc8IIH\xbd\xe7\xa9\x11\xa7\xc0\b\fҌ\xb5d\xb9S\\\xec(%א\x95\xe6\x96\xd1\x1c\x86\xcb0\x16\xf6\x90\"\xa7\x10\x00@L8+QU\"QI\xefq\n\xb5eO\xe2\x904:\x89\x88\x15\xb5d(\x11\x00S\x1fG%\xdaNHn\xcbՑ\xb3Us\x89\xaf\xcd)؆\x11B\xa8^\xf4\xee\t:EƊV2',\xa39\f\x94\b\x80I\x87\x93\x12\x05\t٣\xa6\x86rI\xf2\x9f\xa2\aۡ\xe9\xc5\x04`\xa7D\xa3!\xe6\fV\xa0D\x00\x8c7NJ\x94A6\xe9ɡTR\x12-\xd4\x1e(\x11\x00\xc0\x11\a%:F\xe2.\x19\x1f\xaaɜ\x11z!\u007f\xb3\u007ferR\xceAu\xe3\xe0\x96t_\xf2\xbd\xed4YE\x02\xed\x19\x89\xd9\x03\x92Ժ:\xcd\xe7\xcf*\x13%i\xab2\xc5ԫO\xe0\xf4\x15\xcfMH\xbeW\x19\xe5Ր\x8a?m\x99\xebK/\xbbJ?\x9d\xfdRzB\xd2\xc2*nV<b\xb0\x82^\xb2,,\xe2\x964_\xc6\x03Ò>OdW\xd8٭\x19\xbe\xe4\xe5!\xa5,&\x03[W\xfe(\x96C2\xe7\xa9*\xd1<\xb2U\x02\x00\x8c\x0f\x0eJ\xb4\x9d,0?\x88\x84\xb4)\x17\xf2\x1c\xdf\xe2\xdc8RL\xb7\xb5\xfb\x89o~\x06!\xe5\x12U\xa2-\xb3\t\xf1\x8fH%\x84\xa4\xcdO\x95_\xaeJ\xf5\xab\tY\xb9zP\x93\x88\x86\x042g\x81\xbc\x83^\xc35dS\x1aIJ&$KV\x8c\xbe$\x92\x9c\x9dI\xc8]̱#\x06\xab\xe8%אy\xa9$U\xde5oDS\"\xbb\xc2Z\x12ɜl\xb9\xb0\xa0\xc4g`\xeb\xca\x1f\x85?${\x9eP\"\x00\xc6\x1b\a%\xba\x87\x1b\x90\xcd%U\xf4\n%\x99\x03\x92ԝL\xea\xe5\x9eB\x12\xd9zM\x92:\x93I\x13U\xa2\xb8\xcc涧\xa46\x92xR\x8e\xee\x9cC\xbee\x8c\xa1\x14\x898\x1dG\xca\xe5˺\xd1G\xaa\xd5r\xe4.J\xd0G\xea$i9)\xbb!\xefO\"-\xc6\xc1\"\ak\x18\xa33\x92\xd1%wm\x12h}\x94\xc3\xd8\x14vi\x0e)\x1b\x91n~\x93̾\xcag\xe0\xea\xca\x1d\x85\xfb\xc0\x9d\xa7\xaaD\r\x81N\t\x000>8(Q6\xd9n\xfd$_\xa1}\xf4\xc3A\x92A\x87HK%\xf5C&U\"u\xcf\xfdZ\xa6\xfb\xa9\x8c\xb1J\xb4R\x9b`\xa9%)#\xb4\x9c~\xfa\xa1\x98v\xae\xd2\xe5a\x96L\xa0\xb0\xd58X\xe4`\rS\x89\xb4]%\xdaal\n\xdbN\xeeQ\xde\x17\x92Z>\x03WW\xee(\xdc\a\xee<1O\x04\xc0x\xe3\xa0D\xf3\xc9\x0e\xe6S\x0e)\xa3W\xe8B\xe5ÈO\xbeR\xe7\x92f\xf5C\x1c\x19\x90\x95(C\x8d\x1bQ\x87P;\xe8\x15\xcb(\xd1H\"\xe9R\xf7\xcf!!\xb9\x9c,\xe5C\x80N /&9\xa1\x1b\x12K\x94`=BW\xa2y\xe6.E\x89\xc2\v\x93\xb2\xb4z\x0e^\xb2d\xe0\xea\xca\x1d\x85\xfb\xc0\x9d'\x94\b\x80\xf1\xc6A\x89\x96s\x93!\x19\xa4\x82^\xa1_Q?\xcd#\xadÄ\xcc\xcbQH m\xb2\x12ݣ\x05\x8e\x84\xea\xcaW\xa7\x13\xb2\x8eS\xa2\x01B\xb4Y\x9e\x85\xf2\xc0\xa8F\xebf(\xe2\x11\xf2\x11\x92\xb4\xbaޜ\x8f\x8e\x16\xac\x1fDW\"uW=}\x8fP\x98\xe4S\xfb7\n\\\x06\xae\xae\xdcQ\xd8\x0f\xfcyB\x89\x00\x18o\x1c\x94\xa8\x8c\xe4\x98\x1f\x86\b\x9dy\xa9ѻI9\xe4\xa0HL\x9ad%Z\xad\xee\t\xa4\xd2\r\xf3\x17Z\x94\xa8\x8f\xc4k%-%U\x92~3]\x15\x97\xbeu~9K|\xc95\xfd`тU,w\xf1M%\n/\xec\x1a!\x83F>.\x03WW\xee(\xec\a\xfe<\xa1D\x00\x8c7\x0eJ\xd4E\xe2\xccK\xb8\x9e$\f\xd1+\xb4L\xfd\x98E\x8e\xc9\xdat\xc6\f֕蛄|\xa9\xa1{X\xaa\x88\xd8'\xcaQ\xba9\xbc\xb8\x8ct\x96\xcf#\xe65\x1e=X\xc9\x10Q\x89\xc2\n\x93\b\xd7'b2pu\x8d\xa8D\xfcyB\x89\x00\x18o\x9c\x9el\xcc4\xaf\xba\xe1\f%]\xa3\x8d\xc1\xae%\xc8\xfd\x8c\x14z/\x89\xd29pCW\xa2\x1bsH\xad\xb2m\x8bE\x89n\xcc\xe6\xa7~\x98\xcb~ \xa4\xa4\xabI\xbc>\xc1\x13%X#\xa2\x12\x85\x17&\x9f\x86\xfa+\x90\xe6\xc5\x01.\x03_\u05c8Jğ'\x94\b\x80\xf1\xc6I\x89:\t\x9d\x1b\xa2\\[J\x12\xcfK\xf4\nMP\xbaI\xfb\xe9\xa3F\xc5$\xfb&\xfd\xd0J|Wu%\x12\xb5[h\xc3i\xf4\xb3ݽ\xb3:\x924b\x1d\xfd\xd0'\v\xa5~\x12g</\x141X'\x92\x12\xd9\x15\xb6U˷\x94|\x93\xcb\xc0\xd75\xb2\x12q\xe7\t%\x02`\xbcqR\"y\xd8B\xeej\x1b\x92\xc4\xfa\f\x12\xa7\xdc?\xaa!d\x81,E\xad\x89\xf41\xc7~\x1f)\x19\x96\aq\xc9d\x8b1:\xbb\x91\xa4Ls_^L\x94\x89\x98\x04\xd2t\xed\x86z=wǓ\x1d\xb284'\x92\x80\xe5J\xbf\x8b,\x96\xd5cx\xb51\xe7\x1d-XG-9\xbcOdS\xd8@\"\xd9qC\xbaYA\xfc\"\xdf'\xe2\xea\x1aY\x89\xb8\xf3\xc4\xf3D\x00\x8c7\x8eJ$5諂\xa4)?u\x90\xafЌ\xd9\xf1\v2\xb4\xbeR\xb3\x8f\xccΖ?䎘\xf3D\x01Bҗf\xc7%oWn\x97g\xcbY\xdb5\ti\x88'I\xd9i\x84^\xce\xfc\x95~>\x99\xf8\xb2\xe6'\x92\xd4\x01\xe6\xc0\x91\x82uԒÕȮ\xb0\xa0\x8f$g'\x93\x84\xa0\xa5\x13\xc5\xd55\xb2\x12q\xe7\x89g\xac\x01\x18o\x9c\x95H\x12+r\x92\xe2R\xee\xa9\xd5\xeeD\xc9Wh\xef\xd29\xc9KO\xa9\x1f\xcfnJ\xf7%f\a\xe88ȸw֖\x9b\xe2\xcb\xda\xfe\xa7a\x1f\xbdc՟;;\xe9\xa0.!}Ei\xbe\xb4\x95\xedZ9J\xb0\xbagpK\xa6ov\xd6v\xf6\xce{\xe4`\r\xb5d\x9b\x19k\xbb\xc2\xfa\x8b\xd3\xe2S\n{%\x8b\x12qu\x8d\xa2D\xecyB\x89\x00\x18oF\xa1D\x16\xf4+\x14\x00\x00\xc6\v(\x11\x00\xc0{\xa0D\x00\x00\xef\x81\x12\x01\x00\xbc\aJ\x04\x00\xf0\x9eؕ\b\x00\x00\xc6\x1b(\x11\x00\xc0{\xa0D\x00\x00\xef\x81\x12\x01\x00\xbc\aJ\x04\x00\xf0\x9e\xf1R\xa2\xe7\x84o\xdb\xef\xc0\xad6\x00\x80#P\"\x00\x80\xf7@\x89\x00\x00\xde\x03%\x02\x00x\xcf$Q\xa2\x96\\n\t\x8f\x98\x18\xcamq\n\x01\x00Ln\x1c\x94\xe8E\xe1\xb9?\u007f{M\xfe\xc6W\xa4[/n\\R\xf0\xddO\x95\xad?ߵ6/\u007fÓ\xff\xa6|x\xe7\xa1U\xcb\x1e\xfc\xad\xa6D\x1f\u007fw}ު\x87\xdedJ\x90\x95h\xa00ٟ\xd3 ѕ\xa5U\xa71\xa9\x82\xb3\x96\xa5\xeb\x95UHc'\x10\xf7\xad\xa8\xfbK\b!\xfe\x81\xa8!:\x9d\x84\xe4JR\xb3\x9c\xe1T\xe4\xa0\xf6TC\xfa\x86\xb6\xa4\xf9\x97ߌ\x1c\n\x00\x18\x15\x8eJ\xf4\xedU\u009a%\x82\xf0\xca\xe3B\xfe\x1aA(\xa5\x1b\xbf-\b\x05\x1b\v\x04a-ե\x17臼\xbc\xaf*J\xf4\xe62!\u007f\xe3zA\xf8\xbeYB\r\x99\x97L\xe6e\x12R(IW\x13\xd4U\xa3\xa5L\x12b\x8f\xb2?\xaeA\xba\x1dZ\xe3k\xa2\xed\xbe\x1c\n\xd5j\xcb\xf3;1r\x92\xf8C\xd2p399\"q\x9c\xea1ӭs\x9a\xf5\xe4Ҵ\xa7J\x12\x87$\x00\xc0\xed\xe1\xa8D\u0086\x0f\xa5뻄\xfc\xfc\x1fߒ^\x11\x84\u007f\x95\xe5Fȧ\x9d\x9ew\x96\t/H\xd2o\x85\xbb_\xbc%}\xf2\xa0@\x95\xe8\xe3e¾\xeb\xf2\x9eU\xc2+F\tԅ\xbe_\xeeG\xf8\xa9\x89\xc6JRN\xb7\x9d&\xe9\xecA\xce\xfb\xca\xf5\xe4\xd5\xc5c\x1a\xa5\xed\xf0]\x8e\x1e\xd0=J%\x92\x86I\xb1\xdc]\x1b$Ö\xed\vm\x17\xd1\x1f\"\xb2\x04ZC\x01\x001\xe3\xacD\x1f\xcao\x1f\n\xc2s\xf4c\xa9\xf0\xa2$\xed\xbb\xfbIe\xdf>\xe1qI\xda%\xec\xa3\xe9O\xd7P%\xda'<\xa4\xec\xf9\x89\xb0\xc1(\xa1Fs\xcf\xd8O\xad\xaa\x83\xaa\x04\x95\x11Cz(%s\x19\xbf\xc5>i\f\\\x9bˏ\xf6\u0088A\x89N%\x8d\xd8(Q\xce:\xbb\xe8\x01\x82)*\x00\xc6\x03G%ZO߮\v\xc2\xff\xa2\xef\xbbh7H\xba~]\xd9\xf7\x03\xe1\x1f\xa5[+h/I\xa2\"$+\xd1Z\xad/$\x87\u007f\xa4\x97PC\x16)\xef\xc3\xd4Q~$\x99*\xc2\xcdT\xd6\xc7P\xba\x91\xb4]\v\xcdj=Cζf)\x0ed\x03\x85\xa9\ti\xcb\x15\xbb\xa0\xda\x1c\u007f6ݶ\x95$ԕe\xf9\x97^\xe6\x92\n;\x12-\xa3)\xbe\x04F\x89\xf4\xc2$)\xb44=!uy\x86\x92>\x98;'\xeb\x01\xaa\x87\xc3d0\xa7YW\"=\xb6E\xf3\x14\xa0~\xb8C\x89\x84\xc45ҽ7Rԭe\xd4|\x88\xc8\xe2Z\xa18\xc4\x02\x00b\xc7Q\x89\x1e\xa4o\xff.\b\x9f\xd0\xf7݊\x12I\xd7\xdfy\xf1\xfb\xbb\xd6\v\xc2n\xe9\x13APe\xe9Dz\x12}*\b\x1b\xefS\xc8\x13\x8cIk\xc326\x83\xba\x12m!\xf7\xcb#5\x92\xcd\x1e\xa3\x87hv=b1\x99/\xff\xb7\x8e\x8aGgRN\xa0\xbd\x82T\xcb\xc9\x12ߎ\xd6\x1d\xbebI\xeao\x8c'\xa9\x15UI\x85\\R!\x14\xde\xe7aJ`\x94\xc8(L\xde\xf4\xa5\xe6\xf6\xbaTB\xdd\x197\xc5\xdd\xdfZ\x93\x9asSQ\xa2\x9a\xe5\x9a\x12\x19\xb1\xd7B\xa1\xac\xbbB\xa1\xd0YZ\xc2\xe9Pȧί\xf7\x86\x1aIE($Ҁ\xf4-\u007f\x92\xaeV$\x870T\x03`,8*\xd1\xc3\xf4MV\"\xe5F\x99\xa2D\xb7^X#\b\xc2\xdd\x1bKe%\xfaH\x10\xd4\xc0\xd7e%\xfa\xb3`bL\x14Ր\x1djb>i\xa6\xee֩7\xa5\"M\x1e4Z\xe5ΒƱ\x04\x92\xd0F\x13#\xe9\xf7ʝ\x9c\x1bMC\xf26B\xdd=ک\x8eI\xbed\xb9\x13T\x9c*\xf1I\x99\xcbĘD\xd6`J\x90L%b\n\xabM\xa5\x1aT\x9b,\xd1\x1a4(1\x8d\x8a\x12]\x9d}UQ\"\xf6\xc0\xfc\xe8̯\xdf\xe93Gg\x15\xb4\xbf\xf4%\x871\"\x00 \x02cP\xa2焻\x1f\xff\xf1o?\x95\xdfw\xd3n\x90zc\xff'j\x9f\xc8\x18\x94\x19Ԑ\a\xd4D\x069)ѻf\xa7F\xfc\xf1ܴt\x90\f\xaa\x89\xa12_:\x99\xeb\xdb.\x8bG\x1b\xe9\xd5wo\x9a\xaf\xbcͧW\xb9\x8f\xbeT\xf8$>)Q%\xb2\x0e\x8b\x98\x12$S\x89\x98\xc2Ĺ\x99[\xeb{%*GE\x997(\xe9%\x8a\x12I˫\x15%b\x0f\xec\xa8D\x97I\xbf4\x92tR\x02\x00\x8c\x85ؕ\xe8\xfa2:m-\xf3]Y\x89n\xad\x12\xdeQ>|\x9f\xce\x13\xadѻB\xef\xfc\xf1\xdf\xf5\x12j4\x87\xb2!\xd5#\xba\x82lmc=\xcb$\xdaO\xd2FN\x81Ժ~ҿ?u\x0f}\xf2Ș\xf7Y\xa4>\x19\xb9r\xa1\xfc\xa2\f\x8b4%2\x93\x12U\x1a\xee\xb1\x00\x89+A2\x95\x88-l\xa8n\xdd<\x92\x16\x90T\vG\xcajU\x89\x9a\xb3\x15%bc\x1d\x95HZ\xfe\x80t,\xf9\x86\x04\x00\x18\v\xb1+ѿ\xa9\xb7ӤO\xd7\n\xbb$\xe9q\xe1\x1f\xe9\x87\xeb\xeb\xa9\x12}[\xb8\xef\x16\xfd\xf4s!\xff\x13\xbd\x84\x1a2[\x994\xdeC\x94.\xc6 I\xdfj\x19I]\xf3\xe9\x17\xf6\r\xe5\xde\x19\xbd\x9cO\x12\xe3\xf9\x9d\x92L\xe5-S\xe9\x13ER\xa2\n\x9fu\x82\x86)A2\x95\x88)\xec4\xbd\u007f7\xdc试\ay\x99=\nWU%\xba6\xa7\x9d*\x11{`U\x89\x1a.\xa9\xa5\xd9)QKꍒM\x12\x00`LĮD\xff\xbeB\xd8'\xeb\xcd\x1f\x1f\x14\xe8=\xfb\x8f\x96\b\xcfݒ>ݥ<O\xf4a\xbe\xf0\xb8<X\xfb\xed*\xe1\xbbF\t5\x84d_\x96\xa4&\x9fv\xd1\xe6\x12\u007f\x92\xe5>\u05faL\xe3)e1Y\xbd\xd75\x9c\xb6\x98\n\xd2W\x94\xfbR\xf4NU#i\x95\"+\xd1\xcdy\xc6OJ\x06\xbfu\xdeZ\x82d*\x11SX\x059F\xb7,\xdeB炔\xb1ݎ=\xaa\x12I%ET\x89\xd8\x03K\x8b\x17Kҟ\xf4!\xa0\x9d\x12\xddHmI\x89\xf2\\6\x00 \x1a\xb1+\x91\xf4#AX\xff\xe0?\b+\x9e\x146ʛ^\xc9\x13\xd6\xfcC\xbe\xf0\xb0\xf2\x8c\xf5\xebK\x84\xfc\xfb\xd6\v\xc2\u05ee\x1b%Ԑ\xa5\x89\t\v҉>q]O,\xbf\xf4\x90\xa4\xb3qU\x92\x95S\xb3\xe7?\xd5v?\xa9\x97\x93\xc5q\xe5\xad\xe5qŲL\x85\x12J\xba\xa4\x9e\x92\x84\x90\xc8$it\xb5\xd9\x01Z\xad\x8f\xfd\xcc\x12D\xfa\x8cuu(t\x89-LV\xa2\xa4\x8a\xd6`\x89r㮜\x145\xb7\x94\x90\x83\xf4\x19\xeb\xe6a\xa93Q\xb9wf\xc6Rͫ\n.\x9d#\x1f\xecFW(\xe4+\tћd\xea\xbd3\xfd\xa6]y&\x06g\x00\x8c\x951(\x91\xf4\xe6\xd7\xd6\xe4ox\xf2\x93O\xf3\xee\xfeX\xfe\xf4\xaf\xbb\xd6\xe4\xdf\xf7\xe6+\xea\xef\xce>z|}^\xfe}/\x98B$+Qy\xdf\xd29\xfeEm\xda\xe7a_ؔ\x8e\xb4cv\xd8&i`]z\xd2\u00a0\x92ܟ\xad?ODHB\xff\x1c\xf9u+\x93\x94w\x84\xfcۍ|\r\xa9u\xd6\x12J\xb4i\xa0\"\xb60\xe9\xe0\xe2\x8a\xf4\x84\xb4\xc5\xea\x13\x04\xed\xf7\xa4$\xd3*v*\x8f\x04\xdd\xccM\xbb\xc9\xc5J\xd2\xc8\xfd)\xfe\xbb\xba\xe5Dw\x9cZX\x1d}8\x8a\x12\u007fV;\x1c\xc1\xe0\f\x80\xb1\xe2\xa0D\xe3\xcfy\xfe\x97\x1e*e\xbe\xdby\"\xb0\xc9W2\tz#þN\xa7\x10\x00@\x04\\W\xa2\x1d\xe4\x9b6[\xab\xd3\xc7\xf4{3\x85\xa1\xb9\xd1\u007f\x8a\xef\x12M)\x93@\x0e\x01\x98\xa2\xb8\xabD\xfd\x83M\xb3}\xa2S\xd4\x14\xa4\xa2SZZ!\x01\x00ƈ\xbbJTH\xc8m\xadD4Y\x19!9[Ӱ8\b\x00c\xc6]%\n$\xa6NG!\x92\xfbDI\xf7\x9cu\x8a\x01\x00D\xc4]%\x02\x00\x00;\xa0D\x00\x00\xef\x81\x12\x01\x00\xbc\aJ\x04\x00\xf0\x1e(\x11\x00\xc0{\xc6I\x89>\xe6~\xdf1\x1a\x873\x00\x000\x18\x17%\xba\xf5B\xfe\xa7\xe6'(\x11\x00 F\xc6E\x89\xae\xeb+7*@\x89\x00\x001\x02%\x02\x00x\x8fgJԒ;\xb6\u07fcnqg퍡\\8\x99\x01\xe0\x1eNJ\xf4\xd1\xe3k\xf3V\x94\xfeH\x9d\x90f\\\xef_\x14\x9e\xfb\xe4\xbbk\xf3\xd6?\xf9\t\xf5:\xa3|\xa8g\x91\x95h\xa00ٟC\xfd2\xaa\xc9<uc\x85e}\xb4\xc0\x18\u007f\u007fv\x86\x94K[I\xdc\xed,\"2:\x02q\xb7\xfd\v\xff\xbe\xa5sҊ:\xd3\xfe\xa4,\x90\xe4\x1f\xd07\xb7\xa7\x8eZ\xe4Z\xe6\xcd^М\xd3\xea\x14\x06\xc0\x94\xc7A\x89>\\&\xac\xbao\x83 |\x8d\xaeOͺ\u07bf(|\xb7@X\xb6J\x106\\\x97~\xbcK\x10\x1e\xde\xf5\xb1\x9e\xa7\x86\xccK&\xf32\t)\x94\xa4\xab\t\x9a\xa9k&\xbf>\xda\xfe\xb8\x06it\xb0\x86\xf42ų\xffD\xd7ndd\x8c\t\xb0\xc4\xde\x1e\xad\xf15N!\x06\xb6\an\x9f\xb3\xb0\xbe1\x9b\x903\xd2e\xbah\xa4\xbe\xb6\xa3\xd4:\xc7\xea\x88\xc4c\x16\xb6\x9f\x14\xb7l'd\xf4\xf5\x00`\xaa\xe2\xa0D\x0f\vO\xcaݡ߮\x10^\xb7\xb8\u07bf(k\xd0;\x92\xf4z\x1e5\xfa\xb0\x8e\xceHF\xbf|!\xfaI\xad$\xadT\x8d\xa7O\xf3룝\xf7\x19v\xd4W\x17G\x1f\xa5\xf1\x86\xf4\x03\xaa\x8f\xa3\x8fQ\"&\xc0\u07bc~\xac\xec\xf0]\x96F\x89݁\x87\x92V\x8fHҵL\xd5\xefv\xd4v\xd8La\x03ʊ\xbbeP\"0\x03pP\xa2\xf5\xea\xa0\xebG\xbb~nq\xbd\u007fQ\x1b\x8e}\x9b\xae\x1a\x1b\xa6DJ?h?ɠff\x8a\x04\x95\x11Cz(%s\xaf\xe9\xc9>\xad\xd3\x14\tސ\xbeD]݈U\"&\xc0\u07bc~\xac\\\x9bk]p;\"v\a.OT$\xb6\x8a(?ҏA\x89\x8c\u008aS\xa9\xf5\xc0\x19R\x1b-\x1a\x80i\x81\x83\x12}M(}G\xb7.\xe3\\\xef_\xa4r$\xf3\x02]\xe8ڪD\x8b\x94\xf7\xe182@\x17{\x96/\xc1\x9b\xa9j\xcf@\xe3F\x92\xb6\xeetMV\xeb\x19r\xb65\xab\xd6bt\xaf\xdbԳ\x86\xf4\x94\xc1\xf8\xaf(\xef\xbe\xedZ,\x13\xc0$\xb7\x92\xf8\x9aM\xe9)+\a$\v\x03\x85\xa9\ti\xcb\x151\xd3=\xef\x99\x03\xf3u\x90;E\x89\x16\x13\x12>@/\x81\xaf\xa4^u)S\x9dZ\xbfZ\xa5\x14\xa2+\xd1P\"!q\x8dZyz,S.[X\x8a\xdaJ\xfb/\xb1G\xb3o(\x00\xa68\x0eJ\xf4N\x9e \xac\xd8\xf5c\xaa3\xbc\xeb\xfd\x8bZ\a\xe9E;%R\x9d}\xa4\fj伅\xdcOm|\xb2\xd9R{\x88\xb6\xe4\xb3XL\xe6\xcb\xff\xad\x13y\xa3{æ\x9e3\xa4\xa7;\xb4\x01\x93\x8f\xccklI+\xe4\x1c\xeb\x99$-,cOE\x86\xdf\xd2\xdd\xeaL\xca\t\xb4W(^؆\xe7=s`\xae\x0e2!k?\x86\v0J\xe0*iT}$\x8e\xb3\xdc6\xfaD\xa7C!\xbdGg\xc42\xe52\x85\r\x11f.ͮ\xbeL\t\x00Lq\x9c\xee\x9d}\xb8+_\x10\x84\xbco_\xb7\xb8\xdek\xa6\x1f\xaa\"Y\x95H3\x14\x9aO-\x16\xbbH\xeaM\xa9\x88p\x97e\xab\xdcY\xd28\x96@\x12T\xdb\x0f\xd3螱\xa9\xe7\a>\x97\x12\xb6\xaa\t\x1f] qS\xaad\t0\x93\xbe\x8ca\xf9RNϕXF\xd2\xef\x95\xfb'7\x9a\x86x\xcf{\xf3\xc0lR\xa2\x0e\xd3aS\xcbf\x00[\x82y`\xb3ꃄ\xbbCƎ\xce4\xbb4\xf64\xd9\x03\xeb\x85\xf5+G\x90FFF\"\u0557k(\x00\xa62NJ$\xcb\xcc;\xdf\xdf(\b\xffhq\xbd\x8f\xaaD\x0f\xa8\x89\fB}\xe23ɩ\x11\u007f<7-\x1d\xa4\xf6\x86\x94\xa12_:\x99\xeb\xdbN\x17^5\x8d\xee\x19\x9bz^\x89\xb6&h\xf9|\x9b$\xc3v\xd1^\x89\x94i\xa9Z\u00ad\xe8\xdaFz\xf5$\xebyo\x1e\x98MJT\x89\xc2\x1e\x160\x03\xd8\x12\xcc\x03\x9bU\xbf\x11o\xdf'\x92\f%bO\x93=\xb0^ذ\xa23E\xf2P\xedd\x84\xfar\r\x05\xc0T&\xba\x12\xdd\xfa\xa3\xeaz\xff#!\xef\xdfy\xd7\xfb\xa8J\xa4z\x1f\x0e\x11Bgd*\xc8\xd66\xdd\rQ\xa3K\xbf,\x03\xa9u\xfd\xa4\u007f\u007f\xea\x1e\x895uel\xea9\xa1\x11}\xfaS\x8d\xac\x01\xac\xbd\x12)\x17{'\xe7H-U\x13cއ\xf5\xbc\x8fhq\xdd\x1d\xee\xccf\x06\xb0%\x98\af\xaa\xae\xcd\x13\xddh\xd7\xca\nS\"\xf64mOH\x99'\x12\x9bI\xf9H\x84\xfar\r\x05\xc0T&\xba\x12}\"ܭ8.~(\b\xd7y\xd7\xfb\xa8J4[\x99\x13\xdeC\x94?\xe4\x83$}\xabe\x98s\u0378\xf7uC\xb9w\xa6\xd8\xf3\x98\x17\x18cS\xcf\x19җŝײ\x85]\xb8j\x80\x99\xf4)SUu\x8a\x95\xab\xc1IS\x98X\xcf\xfb\x88JT\xe1\xe3\xb2\xf3\x01l\t恙\xaa\x97\xfb\x95\xfa7\x11\xe5\xcdF\x89\xd8Ӵ=\xa1\xe24\xaa\x9cAz\x17\u07fe\xbe\\C\x010\x95q\xbcw\xf65Y\x8a>\xdd%<hq\xbd\xe7\x94H\xca\x13^\xb9\xae\xdfb\xa3w\xf1\xb3/S?Dm\xa6$\x97\xf8\x93,7\xa1\xd6e\x1a\x93\xacb\xb2\xe6:d^`\x8cM=kH/\xfa\x8cQ\b{\xe12\x8e\xf5fҗ6L\x9f\xe5Y\xacD\f~KU\xb0\xe1\xb4\xc5T\xf3\xbeR\xc6{\xdeGR\xa2\x9b\xf3\x8c_\xad\xe8%0\x01l\t恙\xaa\x0f%\x15\xcaG\xbb\xb9X\xd5\x10\x1b%bO\xd3\xf6\x84\x06\x94\xe7\xd0\xef\xa1Jd__\xae\xa1\x00\x98\xca8(\xd1ǫ\x84\xbc\r\x1b\xf3\x855t\x8a\x88u\xbd\xe7\x95\xe8>A\x10\xde\xd4\xf3Ԑ\xa5\x89\t\v҉>q]O,\xbf\xf4\x90\xa4\xb3qU\x96-\x9cѽaS/I\xa6!\xbd\xf4\x80>\xcf\xcd\xc52\x01L\xd2Gr\x9a곒\xd5\f\xab\xf5\xc1\xe1\xa9\xd9\xf3\x9fj\xbb\x9f\xd4K\x8c\xe7=S\x18_\xae<\x983\xbaPZ\t\\\x80Q\x02w`\xa6\xea\xc7\xfc\xb9\r-K\xe3C4_\xa8\x96T\x87Br?\xe7FW(\xe4+\t\x85\x86\xd9\xd8H'TM6\xb5\x96\xa8\xcfX\xdb\u0557o(\x00\xa62N3\xd6\xf4\xa7f\xf9\x1b\x9eT\a_\x8c\xeb=\xafD\x1f\x96\xe6\xaf\xf8\x89\x9e\xa5\x86\x94\xf7-\x9d\xe3_Ԧ}\x1e\xf6\x85Ϸ\xec\x98m\xd9\xc4\x1b\xdd\xeb6\xf5\x12cH\u007f5\xb1\xd86\xd6\b`\x93\xbe\aJ\x92\xe7\x16k\xbd\xad\x86\xd4:-\xe7\xc0\xba\xf4\xa4\x85A%\xa9{\xde3\x85\xf1\xe5\x86\xfc\xdaCOf\t|\x80^\x02w`\xb6\xea}K\xfdi\xab\xfb\xe5D\x896\x9fS$\xf7\x8d\xe2\xd4d\x1d\x1b\x1b\xf1\x84\x82\xf3\x12s\xdb\xd2\xdb\"ԗ?\x1a\x00S\x19'%\x1a\a\xce\xf3\xbf\xf4P)\xf3\xc5\xfa#\xd6r\xee\xe1H\a؇\xb0\xc7F\x93\xaf\x04\xee\xd2\x00\xb8\x85\vJ\xb4\x83|\xd3fkuz\x8c\xf3\xac\x9bbY\x0e䶕hh\xeem\xff\x14\x1f\x000j&Z\x89\xfa\a\x9bf\xfbD\xa7\xa8q綕\b\x00\xe0&\x13\xadD\x85\x84\x8cq%\xa2\xdb@\x9d\xd5\x05\x00L\x19&Z\x89\x02\x89\xa9\xae\v\x91:\xab;\xe8\x14\x05\x00\x984L\xb4\x12\x01\x00\x803P\"\x00\x80\xf7@\x89\x00\x00\xde\x03%\x02\x00x\x0f\x94\b\x00\xe0=\xe3\xaaD\xfaB\x8e\xd1y\x8e.}\xad1:o4\x00\xc04\aJ\x04\x00\xf0\x9eqU\xa2\x0f\x9f{\xdd)D\x82\x12\x01\x00\xc2\x18W%\x1a\x1dP\"\x00\x80\x85i\xa7D-\xb91\xfe\xb26*[b\xf9\xd9-\x88\xc2diɡ\xdcQ{\x81\x8f\x85\xc9r\x9aS\x0f\a%\xfa\x91\xf0\u009b\xeb\xf3\xff\xe1#u\xa1\xa2U\x0fiˡ}\xb4o\xfd\x92U\x0f\xabk\\3;\xe8<\xd1\x0f\xb4\x85\x8b\xa4Dž'%K\xb6w\x1eZ\xb5\xec\xc1\xdfZ\x94h\xa00ٟ\xd3 \xd1u\xc1\xe6\xa9\x1b+\xb8\x95Ն\xb6\xa4\xf9\x97\x8f\xdaG'0\xae\xbfr;Cʥ\xad$.\xd6\x05L(\rt\x15\xa2\xd4{{\xa4qf\x13!t\x95\xb9*B\xac\xdf\xf9\xf6\xd4\t\xbd\xc6n\x8f\xc9Ӓ\x818\xfbU\x16ƥ\xf9n\xe34\xc7H0^[\xfc*>\xbaǹF\xdf\xd29iE\x9di\u007fR\xd6\xcc\xf2\x0f8\x85+t\x12\x92+I\xcdr\x86S\x91\x83\x98\xe6c\xae\xd8\x18\x1a\xd5Q\x89\xbe\x9b/\bˮKo.\x13\xf27\xae\x17\x84\xefӭ\xaf\xe7\v\xcb\xee[#P\x8bjn\aU\xa2?\nyʲjחQ\x93X.\xdb\v\x82P\xb01/\ufadc\x12\xcdK&\xf32\t)\x94\xa4\xab\t\x9a\x1dl&\xb7\xb2\xdaҴ\xa7J\x129\x8f\x8e(\xec\x8fkp\n\x89\x8a\xc5\xe0\xbex\xf6\x9f\xe8\xcfi\x19qc\x02NE\xbd6\x86\x1bȷ:\x1brug\xb7qCL\n\xd0\xc6\x18\n$YW8h\x9d\xa3\u007f\x17\xa3\xd7\xcc\x1d&YK2\x87h\x8d\xb7\xb5\xf76\x9b/\x16\xc6\xef4\xc7\x18\x10 ڂ\xa0$`\x93A\xc5\xcc\xd6>ga}c6!g\xa4\xcb4\xdb\xe8~&>r\x92\xf8C\xd2p39iY\x04\x9a\xad\x0e\xd3|\xcc\x15\x1bC\xa3:*\x91\xb0\xfe\xf57_\x94>^&\xec\xbb.wjVQ\u007f\x8f?/\x13\x9e\xbc.\xddz\x8e\xae\xac\xcf\xedP\ue755\n?\xa69_\x176J\xfc\xde\xdf\nw\xbfxK\xfa\xe4A\x81S\"\x92\xd1/7\x90\x9fZ.\xafT-\xabOs+\xab\r\xd1\xc5S\xc3V\xb6\x8f\xc0y\x1fgz\x1d;\xbc\xc1\xfd\x80\xea!\xc9.1\xc2\x04\xf0\xb1a\xf4)\x16e\x8b\xb2\xa2\x06\x8d\x81lUk\xeb9/K\x1e\x87\x9a\x8d\vW\x17G\x1f\x05O\xb2\x96d\x0f\xb1\xc3wY\x1a/\xc6\xf14\xc7\x16P\xed\xd3\x16IO\xe4\\\xad8\x8clCI\xabG\xe8\xfa\xeeꢃ\xa3vH\x1f&\xc5%\xd4\x1a\xc3z\x19\xda\xd77\xa6+\xd6\xc4Y\x89>\xa4\xef\xfb\xb4\xfb\xf3?\xa1&\xd4O\xd2\xf5\xf5%\xaa9/\xf2;\x14%zQݻKx\xc1\x92m\x97\xb0\x8f\xa6?]\xc3+\x91\xd2\x0f\xdaO2\xa8\x8b\x85\"Ae\x84\x95\x93\x012\xea\xfe\x9d$\x95̽\xe6\x14\x12\x1d\xde\xe0\xbeD]Y\x89\xfdb\xd9z\x1a٢^?\xfb\xc9m\xd6(\x8cBuy\xf0\x1d\xbaS\xad\r\x0e5\x1b\x17\xfa\x88\xc5`\xd7\xc2$kI\xf6\x10\xd7\xe6Z\xd7U\x1f;\xe3x\x9ac\v\x18\x19\xd0$e\xc0\xd2aa0\xb2\x95'*\u007f>\xaa\x88\xe2W\x1c\x83\x12\x9dJ\x1a\xb1Q\"\xfb\xfa\xc6tŚ8*\xd1z\xe5}\xad\xe6uv\x9d\xda/n\xd0>|\xfc\xf1-~\x87\xa2D\x9f\xe6\t\xd4\x0e$\x9f\xbe\xb2{o\xad\x10\xfeU\xf9\xb0\x8fS\xa2E\xca\xfbp\x1c\x19\x90F\x92i\xd3\xdcL5\x97\x89\xbd\x91\xa2\x8e\x81\xcb\xe8J\x1fq\a\xa5A\x1f\x9dK\xe2\xad\xe1\x19\xaf\xfb\x1bI\xea\xd2ӽ\xf2\xd8y\xc7@q\x86\xff\xde\x1b\x15r\xeeF\xa9\x91\x18\xeb\xfb+؛\xcb\xf3\x06\xf7\xf2\x1f\x81\xf8\xaf(\xef\xbe\xed\xe1\xa6\xf5Lr+\x89\xafٔ\x9e\xb2r@\xe2P\xaf\x9f\xe2t\xee\x10\x92\x14Z\x9a\x9e\x90\xba<Ú\xcd\xd6\xf6ވeK(W\xff\x10\x15\x95\xb3\xa7)\r%\x12\x12\xa7x\xc1\xf2g\xa1gccm\xe1\x03\xcc\xfa\x0eo\x9f\x97tW\x97\xba\x96\xb6AMV\xeb\x19r\xb65\xab\xd6˖4j\xc6|5$ۦ\xb6VgG\xa2\xf5\xaa5\x9b\x8f?!\x1d\x17N\xd3\xfe\xdf-\xcaY\x98\x98\x92\xe2\x90M\xf3\xe0\xbbZ5\xc2gӿ}\x11\xber\xc3d0\xa7YW\"=\x96-\xd7l>\xe6\x8ae\xb62\x85E\xfc\":*\x91\xd2\xc1\xf9T\x106ާ\x90'\xbc)-\x11\xfe\x97\xbe\x9fߡ>\xd9\xf8\xb0\xdcU\x92{A\x0fZ\xf6~B=\xd3(?攨LMdP\xa3\xe5-\xe4~j\x9dÌ;zC\x8d\xa4\"Dm,\xd4\xd1wW\x89\xcfb\r\xcfxՄ8\xd0\x00\x00\t)IDAT\xddK=\xda\\\xc2HScFVRFY1\xb9t\xb5(74,\r\x87\x16\x15\xb1\x83\t{sy\xce\xe0\x9e\xee\xd0z\xf1\xf2w\xbc\xb1%\x8d7\xadg\x92\xb4\xb0\x8c=\x15\x19~\xbe\x93\xd0GZG\xcen'{\xb8C\xc8\xff\xfa_jn\xafK%7\xf8l\xb6\xb6\xf7f,[B\xfdB\xa9+\xa3KʩgOS\x1eӆB\xea\x9fb\xee,\x8cl\\\xac\x1d\\\x80y\xb4\xa1\xcc\xd4@\xdbVBj\xb9`\xb1\x98̗\xff['zؒf͘\xaf\x86}S[\xab\x13\n\xef\f\x18\xcdǝ\x90\x81\v\xa7i\xff\xef\x16\xe5,L\fIq\xc86\x12g\xefKl|\xfb\"|\xe5d%\xaaY\xae)\x91\x11\xcbU\xc7h>\xe6\x8ae\xb7\x8e\xe2\x8b\xe8\xa8D\xbb\xe8۟\x05\x93W\xe4\x0e\xce\xc7\xfa~n\x87\xa6D\xaf\v\xa5\x92\xf4\xa0\xf0\x13\xcbޏ\x04A\xcd\xf3:\xa7DZWe>5g\xec\"\xa97\xa5\"\xc25\x97\xd9\xd7c}\xc9\fkx\xc6랺\x82\r\xe8\xd9r\xc8\xd2ae\xb4ڠ\xfe\xa5\x9coq\xe2\x89`.\xcf\xf67/%l\xd5b\xd3\xe4\xd27\xf1\xa6\xf5\\җ!\x1fh(=Wb\xe9S\xfe6(~$\xcc!jS\xe9?rm2\x9f\xcd\xde\xf6\x9e\x89eJ\b\xa5J\xdb}ۥTEt\x8dӤ\xf8\xf5A\x81Q3\xfe\xdc\xd8X;\x8c\x00&[\xb1bGWfQ\"\xb9\xc6\t$A\xed'yՒl\xcdX\x1b:ۦ\xe6\a\x12\x97\x89\xdd<\xaa\xde|\xe6\t\xb1L\xfci\xda\xff\xbbE>\v\x13]R\x9c\xb2\r\xf2\xe3&=\x1b\xf3\xed\xb3\xff\xca\xc9Jtu\xf6UE\x89\xd8o*_\x1d\xe3\xdbǍδ\xad\xa3\xf8\"\x8eN\x89>\xa5c/\x9d[\xda\xdcQ\xd8\x0eM\x89\xae\xaf\x10\xfe\xf8oB\xfe\xa7\x96\xbd\x9f\xeaF\xb1?\xe1\x94\xe8\x015\x91ANJ\xf4\xae٩\x11\u007f<\xdb{\x89\xa0D%z\x92\xf1\xba\xa7\x13M\xc6B\x8d9>Mr{\xe3F\xae5\f\xdd\xf01a|\t\x9c\xb9<۶[\xf5e\x1f\x15\x13\xec\xa8\xde\xd7\xca\xc4V-\xe1\xee\xf0\xf5\x91\xaa\xae\xd6\\?-\x839\x8487sk}\xaf\xe6zkd\xb3\xb7\xbdgb\x99\x12.\x91kw}iѰ\xfa'\xc58MJ\xb8\x12\xf1\xe7\xe6\x8b\xd0\x1d\xd21\x02\x98lj\x99\xfd\x16%\x1a*\U000e54f9\xbe\xed\xf4\x84\xbdjI\xb6f\xe6W#BS[\x95\xc8\xee6\xbb\xa1D\xc6\t\xb1L\xfci\xda\xff\xbbE>\v\x13]R\x9c\xb2݈\xb7\xed\x131\xdf>\xfb\xaf\x9c\xacD\xd2\xf2jE\x89\xd8oj\fJ4\x8a/\xe2\xe8\x94HZ\xa3M\xf8H\xef\xfc\xf1ߥ\xf5\x82\xfa\xa3\x8eW\xbe\xf6\x02\xbfC\xfb\xdd\xd9w\x85\x17_\x14\xfeњ\xed\xd6*A}\x00\xe9\xfb\x9c\x12\xa9\xa6\x88C\x84пp\x15dk\x9bn\x93\xa8a\xafDF\x92\xf1\xba\xa7}*\xa3ם\xa3\x8f\xa6G\xe2\xfb\xaaȎ\xb3q\x96\x99\x01\xb3\x04\xce\\\x9ei[ѧ?\xb0\x13f\x15-Y\x92j\x17\xb4\xd3tj\xa4(\xb3\x1bCq\xd4،=\xc4Pݺy$-\xc0g\xb3\xb7\xbdgb\xd9\x12|}I=I}\t\xca\x03\x1b9\xec\xa4A\xb8\x12\xf1\xe7\x16>\xc1\xc0c\x04\x98\xd9.\x13\xc5\x1dnآD\x81Ժ~ҿ?\x95\xb7\xafu\xb5%\xb9\x9a\xd9ׁij\xfe\xa2\xe9\x0e7\xe0\x93\x18%b*i2\xf1\xa7\x19\xe1\xdf-\xe2Y\x98\xe8\x92\xe2\x98M\x9b'\xba\xd1\xceec\xbf}\xb6_9\xaaD\xcdي\x12\xb1\xb11(\xd1(\xbe\x88\xa3T\xa2o\v\xf7ݢ\xef?\xa7w\xee\xf7i\x0f/>$<\xc7\xefД\xe8\xb7\u0083\x0f\xaa\x96\xb0\xdc\xde\xc7Uu\xba\xbe\x9eS\xa2\xd9ʈr\x0fQ\xb4v\x90\xa4o\xb5\xf4\x9c-J\xb4âD'\xd9\u007f\xcdk\xe6M\x8b\x1cc\x9c?\xaf\xf1\x9eE\xf3\x82\xf3$\x1e\xb3\x04\xce\\^i\xdb\x06E\xb2\xcb\xe2·\xc5r\x01fҧLv\xd5\xf1\xf7\x16\xd4y\xd6d\x9a\x979\xc4i\xfa\xd7p\xb8\xd1_\xcbe\xb3\xb7\xbdgb\xd9Jf\x05\xe6J\xe9Uj\x0e\xf34%\xab\x12њ\xf1\xe7\x16\xe5n\x9b\xc4\x05\x98\xd9n&*eZ\xfbD\xf2\x1fMz\xefL\xed\xd9yӒ\\\xcd̯F\x84\xa6f\x8fFk`7F\x1d\xad\x12M\xd4i\xda\xff\xbbE>\v\x13]R\x1c\xb3\x95\xfb\x95J7\x91\xabl6\xe6\xdbg\xff\x95\xa3JtmN;\xad.\xfbM\xe5\xab\x13U\x89F\xf1E\x1c\xa5\x12}\x98/<.\x8f\xad~\xbbJ\xf8\xae$}\x9c/\xfc@y\x9ehٟ\xf9\x1d\xfao\xf1\xd7\xe7\xe5\x15\xdc\n\xcb\xf6\xd1\x12\xe1\xb9[ҧ\xbb,\xcf\x13e_\xa66\x87Z\xeds\x89?\x89x\xe7E=Yo.\xb4(\x11\xe3u/\xb3.\xf3\xa6\x16l\xcau\xd1V\xdf1\xb2\xd5\xfa\xe4\x83Y\x02g.ox\xd2\xcb\u007f\xe1J\xc2c\xd9\x00&\xe9K\x1b\xa6Oi,V\"\x06\xbf\xa5~!\xd5\xeb'\xad\xaco\x0f{\x88\nrLɻ\x85\xcbfo{\xcfIJ\x95\\\x9e[(\x15\xe6.U\x0eb\xffWɨ\x19wnl\xec`\x85\xe5\xcf1\x17\xc0d[\x97J\xbf<\xc5a\xf3D\x92\xa8L\xd3H\u07b5$[3\xf3\xab\x11\xa1\xa9٣I7\xe7\xa9\u007f\xd8-\x8cV\x89\xc6\xfb4M\xec\xfe\xdd\"\x9e\x85\xde:\x92))\x8eن\x92\n\xe5\xab\xe5\xe6\xe2L.\x1b\xf3\xed\xb3\xff\xcaQ%\x92J\x8a\xc80\xffM\xe5\xaa\x13]\x89\"~\x11MF\xa9D\xd2\xebK\x84\xfc\xfb\xd6\v\xc2\xd7\xe8\xfd\xaf\xd7\xf3\x84\x15\xf7\xad\x12\xf2^\xb7\xecЕ\xe89A\xf9\xa5\x875\xdb+y\u009a\u007f\xc8\x17\x1e\xe6\x94hib\u0082t\xe3\x1e{=\xe1~\xe9\xa1\xcd\xc4k\x9d\xc8\xd4\xca=\xb9$\xbe\xa1\x9f\xb3\x86g\xbc\xee%\xe9l\x1c\xfd%\x045\x9f\xa7\xd3\xfa\xea\xa8\xfd[\xfe\xe4\x9bY\xfe=l\xa9\x91\xcd\xe5MO\xfa\a\xf4\xd9\xefH\xa6\xf5L\xd2Gr\x9a곒\xd5\f\xab\xb5\xe1e\x9f2\xabw\xcf\xf2\x92\x05\xec!*HREk\xb0D\xb9\xc9\xc7d\xb3\xb5\xbdgc\x99J\x96\x91\x80\x14\xa0w\x19\xd9Ӕ\xd3!_I(4\xcc\xd7\xcc\xc8\xc65\t}\x884iH\xe2\xe0\x02̣\x89i\xe9\xb5ͫ}\xe1J\xa4\xe1]K\xb253\xbe\x1a\x91\x9a\x9a=\x9a<\xa2\x0f\x93a\xb3\xf9\xf8J\xeaL\xe4i\x9a\xd8\xfc\xbbE>\x8b\xd5\xc64FO-\xa9>\xad\xa4\x1c\xb3\x1d\xf3\xe76\xb4,\x8d\x0f\xd1Z\xaa\x8ff\xd3\x1e\x8d\xf1\xed\xb3\xffʍ\x9c$\xcd\xc3Rg\xa2҅3c\x99r\x99o\x1fsŲ\xdf\xc9H_D\x93\xd1*\x91\xf4\xd1\xe3\xeb\xf3\xf2\xef{A\xbd\x11\xff\xe1\xe3\x05ykv}hݡ+\xd1\xc7\xe6\x9c6\x97\xed_w\xadɿ\xef\xcdW8%*\xef[:\xc7oX\xbb\x0f\xfb\xb8!\xfcH\xb22\xba\x8cW\xee\x14\x0e,\xf6'--\x0f\xf3\xafg\xbc\xeeeѝM\xb3\xf7\xaa\xe6\xf3\xea_\xbe\xd3\xc9ߔ\x02I\xdd\x12KDsyÓ\xfejb\xb1m,cZo&}\x0f\x94$\xcf-־\xb9\r\xa9tBC\xee\x01\x13\xfa\xfc}_Vj+{\x88\x83\x8b+\xd2\x13\xd2\x16wZ\xb3\xd9\xd9\u07b3\xb1L%[\xfd\xbdRߜ\x16\xfe4\xbb\xd54\xa9\xe3kfd\xe3\x9aD\xaed\x12\xe1[\xc4\x12`\x1e\xedjI\xba\u007f\xe9\xe9\x88J\xe4]K\xb253\xbe\x1aR\x84\xa6f\x8f\x16\xf2o\x97\xac\x98\xcd\xc7WRg\"O\xd3\xc4\xe6\xdf-\xe2Y\xe8\xad#\xf7\xad\x92\xe4C%\x0e\x8f.[\xdfR\u007f\xdajY\xb0\x95ߝQ\x94\xc1\x82\xfe\xed\xb3\xff\xcau\xcaaM\xd2\xcdܴ\x9b\\,S\xae\xd9|\xec\x15\xcb}'#|\x11M\x1c\x94\xc8m\xces\xbf\xf4\x18\x03e\xbe&\xa7\x90QQn>^\xe9\x8c9=\x15\x13c\xcc6.\x04\xc3\x1e\x98\x8d\x86u\xc6:\x16&\xb6%c\xafY\x93\xaf\xe4\x86S\xcc\x18\x98\xd8Ӝ\x01L2%\xdaA\xbe\xe9\x14\xe2@u\xfaU\xa7\x90Ѱi\x934z\xc6\xf8\xc5\x1ac\xb6\xf1\xa0!y\x8bS\bK\xec\u05fb\xc9Ķd\xcc5\x1b\x9ak\xffS\xfc\xdbe\x8c\xa792\xa8\x12\xf9\xa7\x1a3\x85ɤD\xfd\x83M\xb3}a]\xd6)@\xcc\u05cf\xca\x18\xb3\x8d\x03bjYL_\xfd\x98\xaf\xf7\xb1\x12s\x93\xb8V\xb3q\xc5<ͻ\xb4A\x92u\xf2z\xe61\x99\x94\xa8P\xfe\x17\x89\xf5\x9b8\tPg(cf\x8cټ`\xe0\x18)s\xa3\xaa\xb17\x89[5\x1bW\xd8\xd3\x1chQ\x19\x88\x96aF0\x99\x94(\x90\x98:\x05\x85H\x9d\xa1\f\xbf\x17\xe0\xc4\x18\xb3y\xc1\":\a9\xe0\x14u\xfb\xc4\xde$n\xd5l\\\x89\xfd4g\x02\x93I\x89\x00\x003\x15(\x11\x00\xc0{\xa0D\x00\x00\xef\x81\x12\x01\x00\xbc\aJ\x04\x00\xf0\x1e(\x11\x00\xc0{\xa0D\x00\x00\xef\x81\x12\x01\x00\xbc\aJ\x04\x00\xf0\x1e(\x11\x00\xc0{\xa0D\x00\x00\xef\x81\x12\x01\x00\xbc\aJ\x04\x00\xf0\x1e(\x11\x00\xc0{\xa0D\x00\x00\xef\x81\x12\x01\x00\xbc\xe7\xff\a\xfd\xa4@\x82&\x8eJ\xdf\x00\x00\x00\x00IEND\xaeB`\x82",
+
+ "analysis/chan2b.png": "\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x04Q\x00\x00\x011\b\x03\x00\x00\x00\x83\v\xcdh\x00\x00\x00\x01sRGB\x00\xae\xce\x1c\xe9\x00\x00\x02\xfdPLTE\x00\x01\x00\x03\x06\x02\b\n\x06\x0e\x10\r\x19\x1a\x18!# #$\"$%#%'$&(%'(&()'*+)+-*,-+-.,01/2313425747968:7:;9<>;>@=AB@CEBEGDFHEIKHKLJMOMPROSURUVTVXV,`\xae7]\xad[\\Z8^\xae8`\xaa]^\\:b\xab;b\xac<c\xad_a^Fb\xa1=d\xae?e\xb0ac`Kd\x9dAg\xb2cebefdCi\xb3fheLi\xafDl\xafMk\xb0Fm\xb1ikhei\x8fjliGo\xb3Ip\xb5lnkJq\xb6ll\x8dnolKr\xb7pl\x88Us\xb3Vu\xb4xp\x84Xv\xb6surZx\xb8uwt[z\xba\\{\xbbxzw\\}\xb7\x8evve|\xb8^\u007f\xb9{}z\x95wq_\x80\xba|~{a\x82\xbc~\x80}b\x83\xbd\u007f\x81~c\x84\xbed\x85\xbf\x81\x83\x80k\x86\xbb\x84\x85\x83m\x87\xbdn\x88\xbe\x86\x88\x85p\x8a\xbf\x87\x89\x86\xb3\x81_\x88\x8a\x87q\x8c\xc1\x8a\x8c\x89s\x8dË\x8d\x8ay\x8e\xbe\u0083Wz\x8f\xc0\x8d\x8f\x8c|\x91\xc1\x8f\x91\x8eƇT\x90\x92\x8f~\x93\xc4x\x95Ā\x94Œ\x94\x91z\x97\xc6{\x98Ȕ\x96\x93\x96\x97\x94\u074bE\x81\x9aė\x99\x96\x98\x9a\x97\x84\x9c\xc6\xe1\x8eA\x9a\x9b\x98\xe9\x8e<\x86\x9eț\x9d\x99\x87\x9fʜ\x9e\x9b\x9d\x9f\x9c\x89\xa1˞\xa0\x9d\xf6\x935\xa0\xa2\x9f\x90\xa3ȡ\xa3\xa0\xa2\xa4\xa1\x92\xa5\xca\xff\x952\xa4\xa6\xa3\x94\xa8ͦ\xa8\xa5\x96\xa9Η\xaaϨ\xaa\xa7\x98\xabѩ\xab\xa8\x9d\xac̪\xac\xa9\x9f\xaeά\xae\xab\xa0\xb0Ю\xb0\xad\xa2\xb2Ұ\xb2\xaf\xa4\xb3Բ\xb4\xb1\xa5\xb5ճ\xb5\xb2\xb4\xb6\xb3\xab\xb6ѵ\xb7\xb4\xac\xb7Ҷ\xb8\xb5\xad\xb9ӷ\xb9\xb6\xb9\xbb\xb8\xb0\xbbֻ\xbd\xba\xb2\xbdؼ\xbe\xbb\xb3\xbeٶ\xbeӽ\xbf\xbc\xb8\xc0տ\xc1\xbd\xb9\xc1\xd6\xc1ÿ\xbb\xc3\xd8\xc2\xc4\xc1\xbc\xc4پ\xc5\xdb\xc4\xc6ÿ\xc6\xdc\xc0\xc8ݻ\xca\xde\xc7\xc9\xc6\xc5\xc9\xd9\xc9\xcb\xc7\xc0\xcc\xda\xc7\xcb\xdb\xca\xcc\xc9\xcc\xce\xcb\xc3\xcf\xdd\xca\xce\xde\xce\xd0\xcc\xcc\xd0\xe0\xcf\xd1\xce\xc6\xd2\xe0\xd0\xd2\xcf\xd1\xd3\xd0\xc8\xd4\xe2\xd2\xd2\xdc\xd2\xd4\xd1\xd3\xd5\xd2\xcd\xd6\xde\xd4\xd5\xdf\xd5\xd7\xd4\xcf\xd8\xe0\xd6\xd8\xd5\xd8\xd8\xe3\xd2\xda\xe2\xd8\xda\xd6\xd3\xdc\xe4\xda\xda\xe5\xd9\xdc\xd8\xd8\xdd\xe0\xdb\xdd\xda\xdc\xde\xdb\xdc\xdd\xe7\xd9\xdf\xe1\xdd\xdf\xdc\xe0\xde\xe2\xdb\xe0\xe3\xde\xe0\xdd\xdf\xe1\xde\xdc\xe2\xe4\xe0\xe2\xdf\xdd\xe3\xe5\xe1\xe4\xe0\xdf\xe4\xe6\xe0\xe5\xe8\xe3\xe5\xe1\xe4\xe6\xe3\xe8\xe5\xea\xe2\xe7\xea\xe5\xe7\xe4\xe3\xe8\xeb\xe6\xe8\xe5\xe4\xe9\xec\xe7\xe9\xe6\xe8\xea\xe7\xeb\xed\xea\xf0\xf2\xef\xf4\xf7\xf3\xfa\xfc\xf9\xfe\xff\xfcS\x19\x91\xf7\x00\x00 \x00IDATx^\xed\x9d}P\x14\xd7\xde\xe7\xcdݧQ\t\xa8\xf8\xae\xb9r\x91\xd82\x16\xb8S\xd9I\x14\x1c\xf7֔\x0fٰ\x9aD\xddK\xb6\xa2\\\xa3\x0fX>IH=\x88k\x89Z<P\xeel\x15(W\x85X\x18//F \xa5\x80o1\xbe\x11\x1c\xd1@\xe2\vP\xb7\\ū\xa5\xa4H\x95rE\v\x84\x92\x02\xce>\xcfsS\xdb\xe7\xf4L\xf7\xe9\x99\xd3Ӄ6\r\xcc\xfc>\u007f̜9\xfd;\xa7\xcf\xe9\x9e\xfe\xce\xe9\xd3=\xfd\x1d\xf3\xeb+\x80\x00\x00\x00h\xc6h\xa9\x867\xb4*\a\x00 \xc0\x00E\x01\x00@?@Q\x00\x00\xd0\x0fP\x14\x00\x00\xf4\x03\x14\x05\x00\x00\xfd\x00E\x01\x00@?@Q\x00\x00\xd0\x0fP\x14\x00\x00\xf4\x03\x14\x05xE\xfa\xb5\x02\x80@\x02\x14\x05x\x15Z\xe2\xa7poi\x05\x01\x01\x04(\xca\b\xe6PD\xabV\x881\xb4E\x1cb/\xe8\x9f=\xdb^\xde\xc4^\x06\x04$\x06)ʱzW\xaa\xfe\xf0\xee\xfc\xf38\xd1Q\x95o?t\xa9\xc7-\xa9\xc6\xdfv,\x89I\xee\xf3\x16\xe1A\xe1XNd\xec\x01\xadPL\xdd\xfc\xd0)\x8b\x8fM\xb9\x87\xe2\x85\"\xa1\u05f5\xc2\tG9.\xa2\x1f\x1d\x10\n|\xa3\x1eT>\xb9ȕl]1%dA\xbf{\xae\x1a\x9b\xb9\x8dZ!/AM\xdc\x19\xad\x10\xc2i\x13/b:!4%\xe8\vf\xd0%\xee03\x1f\bX\x8cQ\x94{\xd9߉\x89\x9er\xfb\xa9\xa6\x8b\xd97\x10j\xcf=T\xd7t~wa\x8f\"\xa9\xca'q_\xa7\x9b\x9fx\t\xf0d3WU\x95\xc9m\xad\xaa\xe26\xab\xc6\x1c\xbd\xe8J\x1d\t\x8d\xb0\xef\x9f\xc3q\xf5\xe8\x16.vJ\xb5\bMW9\x17R\x85:\x0ep\xe5]\xca\x05r\xbd\b\x95\x84J\x8a\xf6\xe6\x94\xcc\xf8\x906\xf7\\\x152\x83v\x8b\t\xba2&\xb5\xd7\x06\x11p\xd6|B=\x90\xe2 \xefp\x94\xf2\xc5\x0eǼ\x83§\x92\xb1\xdbYA\xdfq\xc7Y\xd9@\xe0b\x88\xa2\xb4\xe4\xbb\x14\xa5\xdc\xde\"\xfcRg\v#\x96o\xf2\xf1ou\x9b\xfd\xbc\"\xa9\xc6c\xbe\x14\xf5u\xaa/g\xb1u<B\xdfbi\b٪\x1a\xf3\xbb\xc5\xceD\xdbķ\x04Q\xe8\x98ɑ\xc1Է>*\n\xea\xe0\x96\xc6#\xd4\xc4u\xb8\xe5K\xf5b\xa4\xa9\xcb6n;\xeaw\x85jMh\xde\x18\xbf֙RT&\xd3\x1a\xe9:'Z\x9d\xca\f\x90Q\x04\xf88\xd2+6!\xd4\xc0_E\xc8\\\x8c?\xae\x0f\xbe\xc5\b\xf2yC\x01\x81\x82\x11\x8ar,\xfb\x98]T\x94\x96\xec\xef\xf1\x1b\xfe\x95.\xcc'9G\x8b\x14I5\xee\xf2\xbe\r\xd5i\xban8\xbf\xf17\xdc\x06\x10\x14\xe1\xef8\x13kC\xee\xe1\xb7-\u070f\xf8\xcd\xe7\x03\xa5\x83\xfbf\xc2S\x86\xa2H\xf5*\xb8\xcei\x9e\xe9\xc8\xc4OuUʮ\f\xd5qu\xce\xd4J-E\xd1\f`\xd0}ש(w\xbb\xf1ǎ\xa9\xf1\x8c \x9f7\x14\x10(\x18\xa1(]OQ\x9e\xa8(\xa7\xec=\xae\xdf\xe6\x96;\xe4\xed\xe4\x01E\x92Io\xacxB\xbf\v\xa1\x9d|T%\xbao\xe2\x97㤩lW\x82y\xc3\x03\x12s75\xd6\x14\x97\xfc\xc0\xbd\xa8\xfc\x8dϋ\b\x9d\xb5\x8a\x1c\xa3\xc7\xe7O\x1f\x17\xb6`\x06BE\xcey\x96p!s\xa6x\xbc\xb4n\xe9R\x16\xcb\f\x0f\x9d\x93\x89\x14\xc5\xe8\xca:\xb8\xa6\xf0|\x97\xa2\xb8b\xe9z\xdbB8.h/^\xda\x13&\xe6\xaeR\xe4R\x95]\x1a\xcbq\xeb\xaf/\x9d\x112\x1f\x9f\xfe\xf5L\xfc\x98,\xa5+\xa3\xd8>\xab\xa8\x9e\xab/\x99\x95\x89\xce8\xa7;V\xe3쁊Ds®\xe78yy\x83\xcd\x14\x9bl\x1bP\x04<1\xf3x\v\"\xb7\xcd\xf78=֖\x93\x13k\xaeV\xaeDT\x14'\xebC\x18\xc2|\f\x14\x05Pb\x84\xa2\b8\x15\xe5PQ}\xa1}\xefI\xf9\xabٿ\xb7\x8a\x91t禣\x92/p8~F\xe8\x81\xc3T\x80\x06\xaen\x8bF\xa8\xb9\xd2\xc4\xc7\x15\xfc\xd9\xf2\x19\x8e\xa85\xaf\xfe\xaa\xa6\x80/v/)IC|\xd0\a%\xdb'\x87\xf7\xe3S\xff\xf8\x03\xe5\xf60\xae\au\x9c\xac\x9a5\xb7\xaa\xaaJ8\xd1\xe9\nR\x9c\x19\xc9łח\xac\x0f\xfe=\xa2\x8bѕ\t\x8a\xb2}\x81SQ\xa4X\xaa^\x84\xceWU\x05o\"u}_\xb5\x9f\xdbTUբ̕+\xeb\xca\xdf;c\xd6\xc4髖r\xf8\xe2\xc9E\xee\x18Y\xac\xa8L\xa6e)\xf7\x06\xf7[n\xf1\x1d\xd4yő\x90\xe4p8n\xe3쌨\xacs\xa5q+\x85\x13\x9b\x9f楟\xa8)\x8b\xe5_(\x03\x1a\x1c\x8e\x98\x02\x9c\xa07_\xefrk\xe9\xbe\x18s\xd9\x06\xf7\xedG+\xcaI\x0f\xf1\xe8\xb9w\xecw\x93\xdcGg@\x80c\xac\xa2\xe4\xdb\xf3.ݪߛ/\xcd\xc1\x9e\xccmc$=\x91\xcfz\xa2\xf1\xf1P\x10M\x92\x16\xe1\a6=NHuے\x85\xa1yo\xf5c\xf7r.i(\xe2rɧ\xfd\xc2Hb2^{\xe6$2Vr\x9dP4q\x87X\xc5\x0esG\x84\xd7#\xf8\x82\x06U\x8c\xaaLP\x94{\xaf\xdf#\x8aBź\x9d\xa8\x848\xb5Cy\xd6\xe3̥*\x13\x8aqo\xb6\x89'\x85\xa8\x84\xbb\xe1\x8ad\x9f\xf5\x1c\x1eǍs^h\x91Nj\xce\xf2\x15\b\xeb\x800\n)\x8d{!$K-}\x8a\x00\x8c\xa8(\xf4\xe6\xab\xe6\x1b\x85P\xbe\x19\xb9C+\xca-\xce}\f\xf9\x960t\x1a\xc4i\x1c\x10\x10\x18\xab(E\xf6v\xe1\xb5#\xf7[g\xf6\xa9l\xe9^\x06*ɀ\xad(\xe9\xae\xe4\x05\xfe&\xbb\x9cK\x1a\x16\xcf\xec\xc1L\x13\xcem\xeeL\x9d\xb1\xc2\xfe}\xbf(j\xae\x83\xb5g,s\x8c\x12\xff[\xf2\xf6\x86\xb2\x18U\x99\xa0(h\xc1V\xa2(T\xec`\x14\x85\xaaL(\x16,m\x84BNJ\xb2\x14\xa5m\xd5\xf8i\xdc\xd4\xe0\x8f\xc8\xe4\xac$\x18i\xef\xf6\xbe\x10\xb0e \xf4к,\xab\xecf_/R\x04`$E\x916_\x8eEx\xb9͟F\xee(\x15e\xbf\xdbҦ\xc3ٳ\xc3`\x8c\x02(0VQ\x8e\x15\x8ao\x87\xc8[\xcfQ\xbbk,O%\x99\xb0\x15EJ\x16\xf3\xdd\xecr.i\x98㜍\xc0\xb7w\xb6e\xbf3\x9b\x9b\"^Q\x96\x0eV\xe7<J\xcf\x11E\xb1\xb9\v\xc9ۂ\bE1\xaa2\xac(\xf9s\x88\xa2б\x83P\x14\xbae(\\\x9e-9%\x9fd\xb0\x14esXv=W\x9f\x19\xf69\xfe \tƇ\xce)\x93\x14!\xfd\xa4,5\x81_rp@\x11\x80\x91\x14E\xde|\xf3\x1ecU\xf6>F\xf9\x96;\xe9\xb1\x1cUq\xdf\"\x00\xa00VQ.\xee&\xe7\x1a\xe5\xe4\xc0zZ\x94\xd7\xe2\\L%ٸ)\xca\x1e7E\xa9\xe1U\xee\xc8pI\xc3ҙ\x17\t\xc2O\xfay|Q\xb6m\u007f\b\x99o%\a\xab\xbdI\xba֓ϵ\xd2\xc5\xe2g\x92\xb7\x19\xf1\x8abTeXQ:B\xcb\xc9\x18E\x8e\xa5\xea\xc5xU\x14\xaa2\xa1\xd8\xdb\xd2\xe2\x8e`\xe9\xf66Ee.zȵ\x1eq\xa4E\x04\xa3\xe2!\x1e\xa3\\#\b\x02ѐ#hɓʘRE\x00\xc6SQ\x1eF%?lLH\xf4\xbc\xacL+ʧ\xe3\xdb=\x96õ\x1e\xc0\x1dc\x15\xa5\x8d\\=n'w\x9e\xb4\xee? |E\xfb\xbb\x94I\x15dE1\xe7 \xd4\xf7\a7E\xe9\xb4&\xe1\xe1}V\x96{9\xd77\xfe\bG\xaeP\xffQ\xf8I\xdf$\xcetD\xae \xaf\x91\b\xdd\xc3\xcb\xda&\xbe-\x1c\x9d\xfd\x913\x14\xc5J\xc8H\u007f?W\xa2(FU\x86\x15\x05\xc5/ƊB\xc5R\xf5b\xbc*\nU\x99r4\xb2x\xa6\xeb\x8e\x15Ee2w&\xddq\xa6\x92\x92\x10z\xc4Wce%Wkr\x0e\nۅ\xbf@\x16\xedP\x04`<\x15\xe5\x1a\xbf\x84\xe7\u05f9.\x945}!\xcd\xe0P\x8a\xd2?{\x01\xf2\x04\x14\x05p\xc3\bE\xe9ji\xc9=\xdaB\xc6\x00\xe7\xed\xe7o\xd5\xe5\xe1\xbbc\x9b\xec\xfb\x9bZZZN\xe6+\x92l\xc4k=W\xc9ohb\xdc\xc1\x82D\xdeT\xd1\xfc\xb3ô\xed\xea\xc0\xcdm&|\r\xa86f\xf9\xd7\x17\xb2\xf82\xb7\x82\x173\xb9\xad\xe2}sk\xb9\xc5\xf9\x87\xe2\xb9<,\r\x136\x96\x14Ƌ\x97R6\x06o)|3\x14\x1f\x99\x87C#r\x0f\xcd\x1f+\x8c\xec\xef8o\xb5Ń\x82\xa5Ak\x8b\xd6\x06-E\xcabRe]\xe5܁\x0et4\x84\\\xeb\x91c\xa9z{NUU\x05\xc7W\x1dos]\xeb9\x85u\x82ʕ+\x132\xf1U\x1d\xd7X\xe4Ǡ-Δ\xdcH\x15\n\xa2\x8bO\u007fb\xc6C\x90\x9cyi'Ng\xe0\x99\xd9\x02\u07bc\ufb10\xacU\x04\xf4^u8b\xb69.?C\xf4\xe6\xbb\x16Ss\xce\xf1\xc05DYȹ\xb4\xe3f)_\xdc\xe0Lo\xe5Xw\xee\x9eg\x9d\n\x01\x81\x8c\x11\x8ar>\x1bC&eэC\xb9\a\xce\xe3\xb1\xfa\xe1l\x91\"E\x92I\xb7E\xfc\u007f\t\xb9\xfcy7)Ʋa\x0f\xcf\xef܉\xb3\xfeb\x16^w\nٷSm\x96D\xf7\xa9Ŏ\t\x1c\xc79\xefz?\x12\x196i.\x1ef\xe4\xcd\xfdt\xfa\xb8)\x91\xe2\xb5ٮ\x0f\xc2B\xe6\x8aS\x01\xf8\u007f=\v\xf1=c\xf1Ι\r|\xa7j\u007f\xe6\x9c\xd09\x99\xfd\xee\xc5\\\x95\x1d\x13\xc2\xf2Q\u007fĔ~E,U\xefwAbe٨k\x12I\x8c\xadW\xe4R\x95]\x123\xa5\xa1\xc0\xfaםG+\xd5H6\xddY\x8bb\x92\xc4C\xbff]\xace\r\x1e\x9dT\xac)\xb0\x99\xacI\xb5ʀ\x9f\xa2ĉ\x962Do\xbe+\xe4/<\xa65\xe2DJ\xee\xe4l\xb1\xda\xe7x\xa9\xf9\x19I\x1f\x0f\xf9\xc8}\xad\x98{c߹tO\xeb\xee_ \x900BQ\x80\x97c\xd5x\xd5Q\x9b\xae<2\xefx\xf4\xe2œ\x9f>[\xa4\xfaǩ\xfd\xe3\xe3{\x10\x8b\xc2\xd9\x1c<\xcd\x00\xa0\x00E\x19\xc1l\x9dvO+D\x0fN\x8b7\xad\xa0\xbe\xd8\v*\x11mS\xd9\u007f=\xc6ܻ\xe4}R\x1d\b,@Q\x80kQ\xe2\xe9Ns\x94\xca]=\x00\xe03\xa0(@_\x86yGum\xf5\x0esƀV(\x00h\x00\x8a\x02\xa0\x813\x1b\xac&k\xf2Y\x10\x14\xe0\x95\x01E\x01\x00@?@Q\x00\x00\xd0\x0fP\x14\x00\x00\xf4\x03\x14\x05\x00\x00\xfd\x00E\x01\x00@?@Q\x00\x00\xd0\x0fP\x14\x00\x00\xf4\x03\x14\x05\x00\x00\xfd\x00E\x19\x1d\x9cI|\xa4\xf8\xac\xea\x1b\n\x00ÊA\x8a\xe2ݥ\xb4\xe5\xc8^{\xfeI\xc6#\xc2\f\xa0i\x1c7\xdb#\x93r\x13\x1d\f\xbeZ\xa9*\f@}\xe2 _\xe0vC\xab\x9ao(\x00\f+\xc6(\x8aw\x97\xd2{\xd9%\xf5w\xea\x0f\xec}꽒!\xe2T|\xb0G\x1e\xe5&:\x18d+UᄀJ\x03P6\x8a\x1aJ\xa3*<rU|C\x01`X1DQ4\\Jod\xe3\xe7\x93=\xcd\xf6\xfa\xec\xea\xa1c\x93\x87\xa2(\xdcD}\x87\xb2R\xf5\xee\x1b\xeaf\x00ʄ\xae\xe1\xae)\x87\x91\xcb\xf6\r\x05\x80a\xc5\bE\xd1r)EdpҚ=L\xcf\xd9\xf0T\x94A\xb9\x89\xcaPV\xaa\xdemA\xdd\f@\x99\xd05dX\x9f3rپ\xa1\x000\xac\x18\xa1(Z.\xa5$\xe6V~\xd1\xe0'.^\x95\x96\xa5S'\xbd\xed<\xebq\x99\x85\xd2n\xa2j\x16\xa2\x12\xcfR\xad&[J#RX\xa9\xb2}C\x1bM<\xbf\xe7n\xfa\xb2\x98dl\xcd%?\x14Z\xcbXT\xa8\xda\"\x0eQ\x94\xb9*\xbe\xa1\x000\xac\x18\xa1(Hӥ\xb45;;;\xd7\xf8\x99\xd9\xeb\x13g\xe5\x1e\x9a\xcf\x11E\x91\x9dGi7Q\x15\vQ\x89\xb3|FmuJ\x14~\x84\xabl\xa5\xca\xf6\r\xed\xae\xae\xb4%Xl\xbb\xd2\xe6\x11\x97\vIQ4\x8dE\xd1M\xdeAޕ\xb9,\xdfP\x00\x18n\x8cU\x14U\x97\xd2֖\xba\xfc\xbd\x86K\xcaܙ\xc2\xe8\xa3\u007f\x0eV\x14\x85Y\xa8t֣f!*\xf1\xbc\xbaS\x18e\xbc\x9fB>\xb0\xcez(\xdfP!\x97\xff\xe4\x19\x1a\x10\x1f\x05\xedR\x14\x1f\x8cE\xcf\xf1\u007f\xf5\xa8\x17\xe3\xe9\x1b\n\x00Í\xb1\x8a\xe2ť\x14\xf5\xe4\x97{\x96\x1bR\xda8;~[\x8f\x15Ea\x16*)\x8a\x9a\x85\xa8\xcc\xe3\xd2\xe4w-\xfc\x87$\xcdR\x14\xca7Tȍ~(\x15t)\x8a\x0fƢ\xa7\xf9\xfb\xae\xa4\x9b\xa2\xb8\xfb\x86\x02\xc0pc\xac\xa2\xb0]J\xbb\xc4\t\x94Kv\x83'R\xces\xe4\x94k#V\x14\x85Y\xa8\xa4(j\x16\xa2\x12\rq\xb6\x9cӎu\xea\x8aB\xfb\x86\xa2\x95\xae\x19\x10$+\x8a\x0fƢWe\x1f.\x85\xa20}C\x01`X1VQ\x98.\xa5\xfdyG\xc9\xc2\xef\x8dV\x94V\x8e8\x95\x92\x99Y\x85Y\xa8\xa4(j\x16\xa2\x12\t\x89xJ5\x95\xad(n\xbe\xa1J=\x90\xc7(\x9aƢϣ\v<\xea\xc50}C\x01`X1VQ\xd8.\xa5{\x89}\xb9\xf1g=(bz\x9b \x1f\xafcEQ\x98\x85J\x8a\xa2j!\xea\u0086\x8f\xf0\xbe\x95\x1e\x8a\xc2\xf2\re+\x8a/Ƣ\xa9\xef\xb9nĥsپ\xa1\x000\xac\x18\xa1(Z.\xa5?f\x97\xd7ߩ\xcf7\xfe\x9eٺ\xd0韮\x0f\v\x1a\x9b[OۘRn\xa2\xaa\x16\xa2.\n\xf8\xd4҂\x95|\xecWW\x15V\xaa,\xdf\xd0\x17?\x90+5\xf7ł\xb2\x01\xa8\x96\xb1\xa8\xc0\xed\xa8?\xbb\xd6G\xe5\xb2}C\x01`X1BQ\xb4\\JQ\xcb7\xf9\xf6\xc2S\xc3ps\xc5\xf5\x85a3>\xca\x1d˭@\xb2Y(\xed&\xaan!꤯8!:.\xad\xe2=S\x92\xc2J\x95\xe5\x1b\xda(\x1a\x84&\x93L\xda\x00T\xc3X\x14\xb3/\xe6\nr\xcfU\xf1\r\x05\x80a\xc5\bE\x01^\x95\x81,S\xb5[\x96\xaao(\x00\f'\xa0(\xa3\x82\x81b\xdb/\x8a\fo\xbe\xa1\x000|\x80\xa2\x00\x00\xa0\x1f\xa0(\x00\x00\xe8\a(\n\x00\x00\xfa\x01\x8a\x02\x00\x80~\x80\xa2\x00\x00\xa0\x1f\xa0(\x00\x00\xe8\a(\n\x00\x00\xfa\x01\x8a\x02\x00\x80~\x80\xa2\x00\x00\xa0\x1f\xa0(\x00\x00\xe8\a(\n\x00\x00\xfa\x01\x8a2\x829\x14Ѫ\x15b\f\xe0\x89\n\xf8\x8aA\x8a\xe2ݥT\xa0\xce\xfeR\x169CK.~\x80A\xd8\xfc\xa1|\f\xc9\xd7|T\xa5ڲ\xcd\xdcF\xc5\xe7\x15\\P\xbeJ\xa8\aڱ\xf1B\xdfB\xaf{\x8fA\xefd\x8a\xef\xe0\x89\n\xf8\x881\x8a\xe2ݥ\x14ao\xc1\x93y^\xca\x1b\xccQ\xa7\x86\xb4\xe5r_\x1c͍\xe0\x8ey\x0f\u007f\x15\x9e\\N,@l2\x83v+3Z\xaa\xc6mb\x87z\xa2\x1d{\xab\xaa*S˞\xe3;n\xad3\x05\x9e\xa8\x80o\x18\xa2(\x1a.\xa5\x02E\xe5wF\x90\xa2\xfcn\xb13Q\xc7\x1dA\xa8\u007f\xee,\xafѯH\x8a\x8a\xa2\xdc\x18\xbf\x16\xb9\x13쳢\xf8\x14\xfb\xad\x86\xa2\x1c\x9f&)\nx\xa2\x02\xbea\x84\xa2h\xba\x94\xa2\xba\xddO[F\x90\xa2HO\x94%\x8a\x822\xb9\xc1{ \xfb\x8e\x9a\xa2\xc4O\xf5\\\xab\x0f*!\xe1C\xac\x86\xa2\xbc\xc3-\x0e\x95\x14\x05<Q\x01\x9f0BQ4]J\xdb\xed\xd7Ѱ(J\xebҰi\x1f}\x146\x01\xab[fx\xe8\x1c<kP\xe4t\xd4\xc0^\x1a\xa2\xa2,\x9dF\x82]\x86\xa5\xc2\xd1\xf5\xf1\xec\tsOM;\xec^]\xee\x14b\x00tk\xa2\xb3\x8a\x89w\xe4e/\x96\x98rl\xd6\xda,KR'mnJ\x14%\x8b\xe7\xf9\x98\xc7\n\xc3R\xd43\xf1cW\xd1\x1bo\x87\x8d\x9b\xb2\x00\xfb\x06\x04\u007f\xb4jV\xe8|<Xh{g\xea\xf8\xe9\v/!<c2\xce\xeeʥ\t\xfe ~j\xd8Bq\xa2\xc4\xd57eRKQ\ued60I\xf28\t<Q\x01_0BQ\x90\x96KiI9\x1a\x16E\xe9ycJ\xe6\xc6\xe0\x10\xfb\xfc\xad\xd8cc}\xc9\xfa\xe0\xdf\vrq\x92<\xa3\xba\n\xcf%\xd7q%O\xeb?\xe6ȣ\xf0e\x1bӶ\x99a\x9bKVp\x9c\xeb\xc0\x94x\x8b\x9bO\xaaݽ]$\x97~nc\xad\x85ߵ\x8e\x8f=\xb8\xa4Xan\x8a\x15\xe5AZ\x14y\x8c\xb5lX\x8a\xd0Ei\xf6\xe6\u0604\xf0\xcd\xe5\x1b9\xa1\x8d(\x98\x9b\xbd\xf7\xd0\x14\xec\xf2Q\xc4\xc5\x1f\xcb_\x18\xf4-B\xf5{\xc7r\x937m\x99\xe8\xee\xfd\x11̅\xef\xdf?'\xb4\x0eQ}S$5\x15E\x80R\x14\xf0D\x05|\xc1XEa\xbb\x94\xd6\xe7v\f\x8f\xa2\xec\xe7.\xe1s\x1a|\xd0\x1d&\xa3\x91#\x1c\x19wPg=\x98\xa58I\x19\x96\xfe~\x12\x1e/\xac\xf2T\x94\xa6\xcfo\x90\xf7{M\"\xf7\x14K\xad\xe9\xe8\x1c\u007f\x06\xa5g(\xcdM\x05E)\x8e>\x8bS\nG\xd3\x12N\xac\vuM\x9f߅\xbdG\xf0\xa9b\xf0\x94VA\x14&\v\xa9\xa7\xf9x\xb4\xf4[bM\x16<I\x18\x9f,\x9d\x8c\x94\x04\xcf\x16\x8au͊P\xf4M\xd1\xcd\xc1)\nx\xa2\x02\xbe`\xac\xa20]J;\xec\xf5\xfd\xfd\xfdMy\xfd\x06\x1b\x80!\xb4v\x12\xc2\xe6<\x87\x84\xd7\xf8ߒ\x9c7D?RYQ\xb6\x9c*\x89\b\xc1\x9e\x1a\xb2ai\u007f(\xb9\xa8[\xef\xa9(N\x9a8\x17\n3\x0ek\xa5\xa0\x16\x9d('\r)\xccMS\n\xf69}~\x14\x8e\xa6\x85\xae\xc2%\xdc\xf7R\x15\xc1\xb8y\xc4\x03\x11\xb5fΟ9\x91\x9b\xe3\x96K\x11\xfcG\xfc\x9aɵ\xd1}Sts\xb0\x8a\x02\x9e\xa8\x806\xc6*\nӥ\xb4)\xdbE\x8bJ\xe9\xa1b+\u05ca\u007f\xb6\xf1\x18e\xeeB\x92\xb3 \x02\xbf*gfۂ\xb2\x11mXz\x8b#\xbdhWU\x14TU$R\xa5ȵ^@\r&D\x14\x8567M\x89\xb3$|F\x8cI\x15\x8e\xa6\xa7\\G\xfbVN>I\f\xc6Z\xb6\tkǷS\xa6\u007f\\X\x159G\x99K#\xce\xccVq\x17\xe9\xbe)\xba98E\x01OT\xc0\x17\x8cU\x14\xb6Ki+\xa6.\xb7\xb5\xd5\xe8AJSЂ\xa6K\xb3\"\xf0j\xe3g\x92\x9c\x19\xf2\x18\xc5\xde䚙\x9d\x88\x8fXٰ\xb4?\xe4S\x1cT\xa7\xae(l\xac5\xa8!ZT\x14\xda\xdc4%\xae\xf9\xbe\xa5\x18\xa7\x14\x8e\xa6\x1d\xc1\xce\xdb\xdb\xca)\xa3/\xa2\x12D;fG`\xbf\xb4\xb7\xe7(si\x82W\xe1W;\x1e\xa3\xcc$\x19\xb8o\x8an\x0eNQ\xc0\x13\x15\xf0\x05c\x15\x85\xedRJ\x18\x8ey\x94\x8b\xdc\x14\x8e\x8b$\xb2VB\xc6\xf4\xfb\xb9\x12\xfc!2\x12\xa1{ؠTT\x94)\xab.}J\x1b\x96.\x0e\xc37\xc7/ẹ|q\xc3=\x8b\x82R\x14\xda\xdc\x14_=\xbe`\xc2\x13\xb3\nGS\xe14K\x14؎)\x91x\xda\xe9\x03,\x10\xb2vL\xc7\x13\xb1\xfds\xbc)\xca4<\xfd2;R\xd17E7iEi\xdaļ3XV\x14\xf0D\x05|\xc2\bE\xd1r)\x15\xe8o\xa9\xcbmi\xf3Z\xcb\x10p1\xb8\xbc\xa4\xaaE<p\x97\x06\xad-Z\x1bD&a\xd1\xc6\xe0-\x85o\x86\xdeA\xe8\x12\x99\u008c\\\x80\xa7\x1fd\x1bӖ)\xd33\x0f\xbc\x15\xec\xa9(\v=<\a)\x9a\x17\x15?\xaf45>O[\xf7\x8027}r9q\xdb\xd5\xde\xcedk\xed#ڰT\xe0Ǡ-b\xc1\xa3\xaf\xbf\x91Y\xf2\x01g\xc7\xf7\xc1ƟB\x17\xe3\xc7U\xb5\xa0M\xdc;\x99\x9f\x87sa\x9bOѹ4\xc1\xdc\xfcS\xdfDL\xc2\x1aG\xf5MN\xde\xc1\xf7\xccnu\x19\xaf.\xe4&xl\xfe{UU\x13\x16;\xedZ\xc1\x13\x15\xf0\r#\x14Eӥ\x14\xdf\xfa&\xb0\xd7[%C\xc1\xc9\xf1xfd\xdc\\<\x91ҟ9'tN\xa6x\xf4t}\x10\x162\xf7[\x84\U0008595b\x05]\x99\x15\x86\u007f\xd3]\x86\xa5\xc2\xf0*~zț\xe7=\x15%wr\xb6{\x96D\xdf\x12\x9e\xaf\xb4\xf0\xe6j<O\"\x9b\x9b~\xcd\xf3|\xd4O\x95\xc2\xeb>D\x19\x96bֿ\ue738\xb8\xfeδ\x89\x11\x85\xf8\xce\x13\xa1\xb1u\xa1\xc2\xeb\nԿuV\xf0\xe4Ź3\xc7Gҹ4\xb3?}g\xe2ԥ\xe2y\xa5\xdc79\x19\xef\x9c\x18\x12\xef\x0f\xb6O\xe0\\\xd3\xe5\x12\xeb\xc9\xf2\xb1\xe4\x96\x16\xf0D\x05|\xc3\bE\x19\xa9\xb4NX\xd1\xda\xd3\xd3\xf6\xdd\xdba/3:\xea\x18\xec<ʠY5\xde\xe7?\x06\xbe:\x85\x9c\xb7\x8d\x00\x9e\xa8\x80\x8f\x04\xb2\xa2\x14N\x12\x87$\xfda%\x1a\x91,\x86^Q\xd0\xd6i\xca;Z\x86\x8e\xfe\xdcI\xca\x11\x8e\x12\xf0D\x05|%\x90\x15\xe5bP\x1dy\xaf\v\x92\xef\xf8\xf0\x1d\x03\x14\xc58Z\xc2V\xc1=\xf6\x80\x1e\x04\xb2\xa2\xf4LJ\xac\xd8\u007fl\xff\x8a\x90\x97\xf9\x0f\xdc\xf5\xc3ܪSF_\xee\x06\x80\x91N +\nBE\U000e739f:\xff\xa5\x9e\xf54W\x9a\xb4\x04\x00@\"\xb0\x15\x05\x00\x00}\x01E\x01\x00@?@Q\x00\x00\xd0\x0fP\x14\x00\x00\xf4\x03\x14\x05\x00\x00\xfd\x00E\x01\x00@?@Q\x00\x00\xd0\x0fP\x14\x00\x00\xf4\x03\x14e\xd4\x01ޥ\xc0\b\xc6 E\xf1\xeaRڵ\x9b<\xd7 w$\xfe\xbb\xb5n~\xe8\x94\xc5Ǧ\xdc\xf3\xcd\xd4S/\xc0\xbb\x14\x18\xad\x18\xa3(\xde]J۲\xbfo\x11\x18!\xbf\xbc\n\x8e\x84F\xd8\xf7\xcf\xe1\xb8z\x9fL=u\x03\xbcK\x81ъ!\x8a\xa2\xe1Rږ\xadxf\xfc\b\xa2m\xe2[]\xc2hj&G\x86Xڏe\xd5\x0f\xf0.\x05F'F(\x8a\x96K\xe9\xc8U\x94\xb5!\xe4\x01%[\xb8\x1f\xf1\x9b֡\xa6'\xe0]\n\x8cN\x8cP\x14-\x97\xd2\xe1S\x94\xe3\xf3\xa7\x8f\v[0\x03Ѯ\x9f\x1b9\x8eۋ\xf6\n\xaf\xeb\xd1L\xf1xi\xddB\x1e\x1e\"\x1fj\xb2է\\\x03mc\xaa\x00\xbcK\x81\x00\xc2\bEA\x1a.\xa5m\xd9\xe5\a\xb2\xf7\x1e7\xfe\xab\xf9\x1d\x17\u007f\xa0\xdc\x1e\xc6\xf5Ю\x9f\xad\x8b#\x8e\xb7\xa3\xf6\x93s\x17\xdf\xeb\n\xdaJ\x87K\x87\x9al\xf5I\xd5@٘*\x01\xefR \x800VQ\xd8.\xa5m\xd987\u007f\xbfᒒ9\x197$\x13?\x1c\x92r\xfd\xdc=\x9b,\xfcm\x1ej\"v\x83\x12\xaeC\x8d\xb2\xfa\xa4j\xa0lL\x95\x80w)\x10@\x18\xab(L\x97R\xd4_\x87\xb5\xa4k\xb7\xd6\x17Yw\xeeL\x9d\xb1\xc2\xfe}?\xd17\xd9\xf5\xf3RPW\xc7\ued9e\xe0K\xa8g,s\x8cBY}R5\xc86\xa6l\xc0\xbb\x14\b\x04\x8cU\x14\xa6K\xa9\x8b\xe3\x85\xc8hڲߙ\xcdMٌ\x14\xae\x9f]c/m\xe5\xfe\xa9>H\x909\xe7<J\xcf\x11\xf2\xe6:\xd4h\xabO\xb9\x06\xd9\xc6T\x05\xf0.\x05\x02\x00c\x15\x85\xe9R\x8a\xca\xc5G\xd1\x1f}\xa9\xa73\xbe\n\xe7\xf1\x91Ѷ?$S\xe9\xfa9{o\xe4\xdcم\xf8\xdc\xc7y\xad'\x9f#\xf7\xcaHc\x94\x99\xe4\r[}R5\xc86\xa6\x83\x02\xbcK\x01\xbf\xc2XEa\xbb\x94\x96\x90S\xf1\xb6ܗy\"\xfd+\xb1I\x9c9\x88\\\xa1t\xfd\\\xbcb\xfcan\x05v\xc6j\x9b\xf8\xb6pB\xd3\x1f)^\xcbq\x1dj\x94\xd5'U\x03ec\xaa\x04\xbcK\x81\x00\xc2\bE\xd1r)\xbde?|\xbd鼽\xc4\xf0'\xcbo\xe2&l,)\x8c\xc7\xd7Od\xd7O\x84\xbe\b\x9d\xd8?+\x84(\xc3\xe1Ј\xdcC\xf3ǞT\x9az\xcaV\x9fT\r\x94\x8d\xa9\x12\xf0.\x05\x02\b#\x14Eӥ\xf4^\xf9\xdeܢ:\xc3\x05\x05\xe5\xcd\xfdt\xfa\xb8)\x91X\x0ed\xd7O\xa1\xbd\x93\xfe\tm\x9e \xce\x1e\xe3\xff\xf5,$\xd7Z)SO\xd9ꓪ\x81\xb61U\x00ޥ@\x00a\x84\xa2\x00z\x02ޥ\xc0H\x06\x14e\xd4\x01ޥ\xc0\b\x06\x14\x05P\x05\xbcK\x81A\x03\x8a\x02\x00\x80~\x80\xa2\x00\x00\xa0\x1f\xa0(\x00\x00\xe8\a(\n\x00\x00\xfa\x01\x8a\x02\x00\x80~\x80\xa2\x00\x00\xa0\x1f\xa0(\x00\x00\xe8\a(\n\x00\x00\xfa\x01\x8a\x02\x00\xc0K\xc1\xfc'\x1e(\n\x00\x00\x83\xa7%~\n\xf3\xe9b\xa0(\x80\x933\x89\x8f\xb4B\x86\x9c\x97t`}\xc9b\x80&\xaaN\xb4\xfd\xb3g\xdb\xcbY\x1e\x16\x06)\x8aW\x97R:wt\xb1\x93\x8f\xaa֊yEj\xe7\xf1\x89}\xe8\x04\xcfϫU\viL^dYS\xfb\xfe\x15\xb5\xe5\xbeq\x90/\x18@\x15<\xcf\x17\xa0\x02\xe1\xb5\xccK\xe8}\x13\xbf\\x\xdb&\x84\x99慎9\xe69\x1fh\x19Ө\x1e\xa4@r`\xfdێ%1\xc9}ރe܍[\xd9\xe0\xbe\xf1\x8b\x92oj\xc5\r\x96\f\x9e\xc7\x0f\xdb+\xe6\xf9\f\xb7%5qgX\x05\x86\x16\x9d\xbb\xa9\xe6D{\x89\xf3|n\a\xc1\x18E\xf1\xeeRJ\xe5\x1a\xcd\xd1W{`\xd0\x03\x87\x89rꪽ\xc6JR\xb0s\xbd\at\xd7\xf01\x0e\xd4y\x82\xaf\xe9f\x14\xc0\\3\xa5\x9c\xa8\xfc\x8c\xe7_M\xdbJ\xa3\xf0#\xf7\x9fU\xf0\a\x1f\xa1G_\xf1\x15ϼ\xc4\x0e\\\xdd\x16\x8dp\xef\x1d\xa5\xfcU\xf5\xb0\xee+q\xc9\x0e\x81\n\xfe\x02\xf2\tف\xf5\x93\xb8\xaf\xd3\xcdO\xbc\x06\xcbx\x18\xb7\xb2\xc1}\xab\xadHTW\xe6\x97\xe4\xa1\xf9+\xfc\xc4\xce\xc7_Y\x1e\xba-9k>\xe1Li\xeey\xfdХ\x9bT{U\x9ch\xbf㎳\xb2\rR\x14\r\x97R*\xd7h~\xb7X+B\x83hJQV\xa7\xb2\x92\x14\xec\\\x8d\x80N>}\x9b0,\xe0;=\x17\x89lX7 \x1c\xe4\xdb^MQ\xee\x9ar\xc8{3_#\xbc\xd6\xf2\xcd^\xa3QA\xb4\xf8\xde\xe0MQ\x10Z\xb6\x03\xbf\xde\xf6QQd\a\xd6\xc7|)\xeaS\xed\xb0\x1b,\xe3V&\xa4o}k\x12\xb4\xe2\x06\xcb\xfb\x15\xe4\xad\xecC\x8f%\xd2(Ks\xcf\xeb@k\xa4x\xea\xa7G7\xe9\xf6\xb2\x9dhU\x9fFl\x84\xa2h\xb9\x94R\xb9F\x13\xfe\x8eV\x84\x06\xb4\xa2\xacLe%)ع\x1a\x01\x9d|\xad\xf9\xb97EYF\xb4\xa0\x91?\xad\x16\xe0\v\x19VѴp(\x14\xa5\xb7\xd4ۀGFv`\xbd\xcb\x0f\xe2t\x81e\xdc\xcaD\xec[)\xff\\+p\x90|\xb6\x87\xbc\xe5|\xa6\x1e\xa2\xb9\xe7u\xa0\x8e\xab#\xefzt\x93n/ۉvX\x15E˥\x94\xca5\x94\"\xe7\x13\x10\xc3\xf1\a\xdan\x94ƛǨ@tή\x04\xf3\x86\a\b\x9dq\xce\x19\xacV$w\xf2\xa6\xd2\f뢔\xbb\x8a\\\x85\xf3\xe8\xe5\r6Sl\xb2m@\x19 \xd3\xc9\xdf_y©(R\xb1}B\\%\x12\x1f\x1b\x99fŇ\xff\xc09E@\xa3\x89\xe7\xf7\xdcM_\x16\x93\xfc\xa2\x9aw͍T\xb3\x03\x84r\xbd\x16q\x88B+\x8al\x9a*\xf4\xa2\xcc\xd9M\xe1\\'\xcdjI\xdd\xe6\xae(\xeczEE!5DU:\xa7_\x14\x95\xa1\xbb\xa9\xb1\xa6\xb8d\x92v9\xb0\xf6Ɗ\xdba\xd7\xe0\x8a]\x1a\xcbq\xeb\xaf/\x9d\x112\xbf\x876\x9a\xa5\x10\xfb\x96f\xc5i\xd6\x0e\xa0v\x96\x10\xf0\xf5j\xf3\xca\xd2\x01\xb7\x15K\xb1t\r\xc4k\t\xa1\xd4\x1cE矘y\xdcz\xa4\xb6\xe7\x95;\x80\x01\xd5!D[\xe0v|<{\xc2\xdcSӔ\xd3\x18\xdbg\x15\xd5s\xf5%\xb32U\xbbٙ\xb3ܜt\xd5v\x81ި\xbe}\x11\x99N\xb4džSQ\x90\x86K\xa9G\xaeAt\x9c\xac\x9a5\xb7\xaa\xaa\n\x9fm\xd1v\xa3\n\xbcz\x8c\n\x8a\xc2'T\x9eY\"\xfc:u^q$$9\x1c\x8eۊds\xa5\x89\xb7\x15\x14\xd8\xcc\xcdt.\xed<\xfaӼ\xf4\x135e\xb1\xfc\ve\x80\x8c\xa0(\xa5\xc9NE\x91\x8a=JK\xbc\xdc)\x94X\x93\xf6\vzh\x8bJ.\xf8\xa1\x17)\xea\xed\xae\xae\xb4%Xl\xbb\xd2\xe6=\xec\xbcl\xd9\xf7\b=\xdag\x11J0\x03\x84r7y\x87\xb8\xb6f\xfe\\ww\xf7\x05\xac(\xb2i*\xeeE\\\xc1\x9f-\xf8G\xf8\xae%\xa1\xe2\xcc\x06\xde]Q\xd8\xf5.\xcb\xe8\xee.ND\xce\t'q\xfa\x85\xae\f՚W\u007fUS@f6e\a֛\x8eJ\xbe\xc0\xe1\xf8ypź\xf2\xf7Θ5q\xfa\xaa\xa5\\\x13e4\x8b(\x84\xbe=\xbf\x9d\xc3\x17(\xdaK\xed\x00jg!\x94\x1e\xbd\xe7ܞ\xe8t\xe5\x8a\xe5X\xba\x86\xb2\xd5\xe8\xaa\xed*ZY\xa6\xec|\x83\xc3\x11C\xd6\xc5\xde\xf3\xca\x1d\xc0\x80\xea\x10m\x81\xdb63ls\xc9\n\x8e\xcbD4-K\xb97\xb8\xdfr\x8b\xef\xa8u\xf3ɻ\x8b\x8a/\xec\xe4\xf9\xaf\xe9\x8d\xea\xdb\x17\xd1Ӊ\xb6\xe7ޱ\xdfMR\x19\x19\x1a\xab(l\x97R\x8f\\\xe3\x90\xcez(\xbbQ%\xde=FQt\xdc߄\xdd\x12G\xd2̳\x9e\xe8e\u0090\xff\x89-Q\x91K9\x8f\x96\xc6\xe1\xafg\xa9\xa5ϭ\x06\tAQ~\x89\xf9\x85(\nU\xac\x82\xfc\u0088\xa7\xf0\x8f\v\xfe`\xe2-\xd5\xc8\xcd\xd1t%\xff\xc934\x80O82\xf0\x8fhZ\x86z\x00:\xc7\xffU\\[\xb3\xf3\xf7\xa9Yi\x9a\x1am\x11~\xa2\xd3q7\u05fc'\xfc\xa0\xf5}\xe8\xa6(*\xf5.\xc3U\x91\x1fK\xf1\xf4P<Y\x92+\xeb\xb6%w\v\x83\x92j\xe2E$9\xb0\xd2g=\x83*\x16ν\xd9FΞe\xa3Y\x1a\xb1o\xe9x\x80\xa1\xb2\x03\xe4\x9du\x81\xfc\xd0א\x19 y\xc5T,U\x83#\x16\xe5\x98r\xd0\"\"\xca\xd4FE(\xc6uN\xcc\xda\xf3n\xb1,\xa4\x0eQ\x16\xb8\xbf\x9f\x84\x9f;\xbe\xcaMQ\x10:<\x8e\x1bG\xc6-\xecn\xa6\xe3N\xa0,AQ\xe8\x8d\xea\xd3\x17\xd1Ӊ\xf6-a\xf8\xa7\xe6\xaee\xac\xa2\xb0]J\xdds\rDR\x14ڰ\x94\x85\x8a\xc7(\x8a\xc6ǩsV\x81\xad(\xe4t\xa2\x94\u007fL\xe7RΣ\x0f\xad˲\xcan\xf6\xf5\xba\xd7 !(\nJ.&\x8aB\x15k\x8c\xea~^\xf1\xe4E\xb4\xf3\xbalwM2\u007f\xce\xcd\xd1te\xb4\xebǯ6\xe69zn\xaeE\xaa\x01贰\x12B3\xff熆\x86b2\x8fB\x99\xa6\xe2\x1fk\xd2\xcd'\xe2e\xe5=n\x8a\xa2Rﲔ\x86\x86tOEqU&\x1c\xb7\xd4E\xceByӲ\x15E\xb3Xx\xb03)\x1b\xcd\xd2ྜྷM\x8c\xb9\x8fTw\x80\xbc\xb32\xde'E\x96oC\xf4\x8a\xa9X\xba\x06\xfeyR\xfa\x9aN\x9e\xf4\x9aڨ,EQ\xdb\x01l\xa4\x0e\xc9\x16\xb8\xfd\xa1\xe4Jy\xbd\x9b\xa2\xb4\xad\x1a?\x8d\x9b\x1a\xfcQ\xabJ7\xfb\xcc\xd8UAX\xa6T\x14\x9f\xbe\x88\x9eN\xb4M\x87\xb3g\x87\x8d\x881\nۥT\x99k(\xf2̬l7ʆ\xed1J\u007f\xe3U\x14\x85|\xa9\x1c\xfc5:\x97v\x1e}R\x96\x9a\xc0/98\xe0V\x83\x04V\x94\x13+\x89\xa2PźM\x8d\xc5\xfc\xbe\xdbQ\xc2ou\x039\xc3\xefKLqs4])MȼXt\x1a\x9d\x8e\xedC\xaa\x01\xe8\xaa\xeb셚G\xa1MS\xa5n6\x88\xa7G\xee3\xb3*\xf5\xe2y\x94f\xf1J\b-\rR\xb2\x98\xa7.\x89\x9f\x92\a\xd7lE\xd1,\x16\x1e\xeeLPF\xb3\x14\xa4oO\xa2\xb0$\xaa\xec\x00yg%\x92\x9e\xa0\xe4D\xa4h\x83\x1cK\xd5\xd0\x17\xddl\xbefn6\x89\xbf\xee\xf2Fe)\x8a\xda\x0e`#uH\xb6\xc0\xbdő\xa3\xa5\xddMQ6\x87e\xd7s\xf5\x99a\x9f\xabt\xf3\x818q\xdf\xe9\xa6(>}\x11\x99N\xb4U\x9e\xbe+\"\xc6*\nۥT\x91k,DQ\xecM\n\xbb\xd1A\xe1\xa1(\x15\x0f\x95\xc9\xe8,\xfc\xb9\x8c\u007fF\xe7RΣ\r9\xc2.|R\x19S\xeaV\x83\x04V\x94\xe7\xe6\x1aq\x8c\"\x1b\x96&T\xae[\x93p\x1a\x9f\xfbX\xc9\x1aP\xce{n\x8e\xa6Է\"+\x05}F\xa2\xd4\x02\x9e\xbb\xaeYQ\x8aB\x9b\xa6J\xdd\xfc\x1bO\x1a\x9a\xee\xa6(*\xf5J3\xb3\xce\x1a\xf6\xb8IC\rOݧ!9\xb0z(\x8a\xaf\xc5\xc2\xdfv\xa5d\xa3Y\n\xb1o\x16\xfcc\xad\xb2\x03䝕\xf1.\x99}]\xee\x03\xcf]\x00\x00 \x00IDAT\x86\x87'\xf2\x8a\xa9Xž\xf8ʊ\xac\xc5\uf455(\x8eE\xa5\xa2\xb8\xedy\xf6\x0f\x88\x02\xa9C\xb2\x05n\u007fȧ8\xa3\xce\xfd\xac\xa7\x87\\\xeb\xc1clf7\xfb̤)\u007f\x91\x15\x85lT\x9f\xbe\x88L'\xdaa\xbdփ4\\J\xe9\\\x83\x89\x8cD\xe8\x1e\xb6\x17\xa5\xecF\x95x\xf7\x18U(JR\x12B\x8f\xc4\xdbB\xe4d\xf4\x12A\n:\xdfMR\xe4RΣ\x05\xe2\xcd\x1aI;\xdcj\x90V\x8c\x15\x05\xa5\xa7aE\xa1\rKӲL\x17\xf8\x9dx\xc7\xc7Z\xf1׳\x0f\u007f\t\x14\x8e\xa6\xd4\xf7\xf5\x87\x98\x9fc~\xc0\t\xb5\x00\x94\xfa\x9ex\xef\x04\xa5(\xb4i\xaa\xdc\xcdD\x9b\xb0\xb6\xdb1n\x8a\xa2R/\xa5(fᄢ\xef\x0fn\xd2\xd0iM£\xec,Q\x13]\x0e\xac\xb4\xa2\f\xaa\x98<┍f)ľ\xc5e5\x16\xa8\xed\x00yg\x9d#3\x1d\x95\xf8T\x92Z1\x15K\xf789\xf13\xf4Y\xe2\x06\xb2\x12\xb6\xa2\xb0\xf6\xbc2\x96i\b+u\x88\xb2\xc0]\x1c\x86o;Y\xea1\x8f\x82\xeeL\x12/C\xb2\xbb\x99\x1a+췁t\xa2(\xf2F\xf5\xe5\x8b\xc8v\xa2\x1dVE\xd1r)\xa5r\x8dfc\xf0\x96\xc27C\xef(\xedF\x15x\xf5\x18\xfd\xd9a\xdavu\xe0\xe66\x13\xbe0!|\xe9\x8aO\u007fb&\xc2.'\xa3\xf9\xd5\xd5e\t\x96\xbf*se\xe7\xd1\x02\u07bc\ufb10\xacU\x06H+\xee\xae\xe1Ot\xa2Z3\xb9\xd6C\x19\x96\x1e4[\xfa\x12\xc876\x96\xb7\xee\xbb \x14\xbbM\a\xbc\xf8\x81\xcc\xd7\xdf\x17\xdb\xd9g\xdd`\x15\x15C%\x00ݎ\xfa3~\xa3\uf655MS\xe9n6\x9bm\x05{\x16E\x99*\x9a\xd1C|\xcfl\xb1á\xe8\x10Uo\xf7ո\xe4+\xae\xdbh\x12\xe3\x0e\x16$\xf2B1\xc56\xab\x8dY\xfe\xf5\x85,\xe7-\xff.\aV\xf1Z\xcfվ\xc1\x15\xeb9E\xae\xdc5\x91<\xcahV\xa6\x91\x1c3뒷\xbd\xaf\xb6\x03\xa8\x9d\x95\x16\x95s6'*M\xb9\x8f\xe9Xj_d\xcd;\x88\xbe\x9a'\xe8\x1b\xbdQ{\xaf:\x1c1\xdb\x1c\x97\xc9\xc4+cϻ\xed\x00OCXE\x87d\vܖ)\xd33\x0f\xbc\x15\xec\xa9(.\xd8\xdd\xfc\xd9j+=\x91\x12C\x14Eڨ>}\x11\xd9N\xb4\xe7Y\xa7B\x18#\x14EӥT\xce5\x9a\xae\x0f\xc2B\xe6\xe2\x13B\x85\xdd(\x8d7\x8fQ\xb4S8\x055\xfd\xc5,\xbc\xee\x14>ug-\x8aIj \v\xe4d\xf4\xae\f\x8b5\xfdg\xb7\\\xd9y\xb4bM\x81\xcddM\xaau\x0fp\xad\xb8v\x1e\xbe\x8f\xa4/QT\x04ٰ\xb4A\x18\xd6\x1e4\xe3\xd8?\x94\xe5,7ǥ\xdcV\xd4\xdb\x18EΏ\x93źPqt\xb13\xa5\x12\x80\xf6\xc5\xe0\xff\x05\xd1\xff\xeb\x91MS\x15ݼ\x9b\xb2hYN\x85IH\xa6;O\xc2SU\xea%\xff\xeb\xa9t\xd6\u007f7)Ʋa\x8fP\x83r\x9b\xddN\xb5Y\x12]\xf7\xe6\x89\x0e\xac\xdd\x16R\x83\xe9\xf6\xe0\x8a]\n\"3\r\xa2\xfe\xd3F\xb3.\xf0}9_\t\rL\x88=\x8bTv\x00\xb5\xb3\xfaJ?4\u007fXڧ\xdcNJ\x9d%\xef\x8bs\xe6FAi\xcf(7\xeaObZ\x94=ƞw\xdb\x01\x9e\x86\xb0\x8a\x0eQ\x16\xb8\xad\xf1\xd3C\xde<\xaf\xaa(*\xddD\x8f3l1\x9f4\x10E\x916*R\xd9\x0et{U\x9ch\xef\x8d}\xe7ҽ~\xe4\x89\x11\x8a\x12\xd0\xd07Վd\x06\xb2L\xd5Z1C\xceK:\xb0\xbed1O\x86sgy7\x84u\xa7C}\x8c\xe2\rqfv0\xa8:\xd1\x16\xce\xe6\xe0i\x06\xc3\xc1p~I\a\xc5@\xb1\xed\x17\xad\x98!\xe7%\x1dX_\xb2\x98\a÷\xb34\fa=0JQ\xbc9\xd1\u07bb\xd4\xc2\xc8\x05E\x19b\x86\xefK\n\f\x9a\xe1\xdbY\x835\x845JQ\x06\x0f(ʐ\xf2\x80L\xebiE\x01#\x82Q\xb4\xb3\xae\x1f\xe6V\x9db\xcdbx\xe7\xee\x05~\xd7\x0f}hH\x01E\x19Rȴ\xde}\xad(`D0\x8av\xd6\\\x8e\xe3\xc6^\u05ca\xf2`\r\xee\xe1]\xad\xa8W\x03\x14\x05\x00\x00\xfd\x00E\x01\x00@?@Q\x00\x00\xd0\x0fP\x14\x00\x00\xf4\x03\x14\x05\x00\x00\xfd\x00E\x01\x00@?@Q\x00\x00\xd0\x0fP\x14\x00\x00\xf4\x03\x14\x05\x00\x00\xfd0HQ\xbc\xb9\x94\xf6\xe49\x1fl\xb0W\xbd\xbc\u007f\xa1\xb3\x91$\x00\x8c\x1c\x8cQ\x14\xaf.\xa5]\xd9\x17[\x04\xceg+\x9f3쇸\xbc\x1f_\xc6H\xf2\xd9\xcf\xea\xcb^\xd1k\x15\x00\xf4\xc3\x10E\xd1p)\xad{*\xa4\x9e\xe6\xa9<\x13ʏ\x90\xbc\x1f\am$\xd9WfY\xa7\xbe\xf4\x95\xbdV\x01@/\x8cP\x14-\x97RBɁ\xe1x\x86\x9b\xb1\xacT(\xca \x8c$\x1bW\xf3)\x0f\xd4\x17\xbf\xb2\xd7*\x00\xe8\x85\x11\x8a\xa2\xe5R\x8a\xa9\xcf\xd6\xe7\x999#\x83\xc7鱶\x9c\x9cXs5\xe5vI{?j\x19I*\xe9\xdc\x15e;\x8bԠ\xbcV)_\xcb\x15\\P\x1ej\x1aω\x8f\x83\x97-.\x01`h1BQ\x90\x86K)&\xbf\x9cUl\x94һ\xdcZ\xba/\xc6\\\xb6\xa1\x98r\xbb\xa4\xbd\x1f\xb5\x8c$i\x06N[M9\xe2\xf3\x9f\xbb\xef\x8bPn5\n\xafU\xcaײ\xa5j\xdc&A\xc1\xe3\x83q\x88lq\t\x00C\x8c\xb1\x8a\xc2v)\x15h\xcaV\x1a\x94\x8fn\xaa\xf9F|N\x83}\xf9h\xb7K\xfa\xac\a\xe3\xcdHRf'\xbf\xb2ٙLr\x0es\xd6 %\xd4Y\x8f\xe4k\x89\x82\x05EA\x9b\xb0\xa2P\x16\x97\x000\xc4\x18\xab(l\x97R\x81r\x9d\x1e=<2ȱ\b/\xb7\x89\x8b\x1b\xedvI+\x8a\x96\x91\xa4LE\xf4\xa2\n\xe7\x83\xc5n\x9f\x11q\xf3ZW(\x8a\xcbגR\x14\xd9\xe2\x12\x00\x86\x1ac\x15\x85\xedR*\xb0{\x18ܿ\x86\x8e\xe2y\x8f\xf1\xe8\x04\x0f-h\xb7K\xb7\x99Y\xafF\x92\x14w7\xf0\x89\xcd\xc8\x1b\xb4\xa2\x84\xbbR\xb2\xa2\xc8\x16\x97\x000\xd4\x18\xab(l\x97R|=\xd9\xf5\xcb\xea\x17<\x8cJ~ؘ\x90\x88\x1f\xe8I\xbb]\xcaޏ\xdaF\x924\xd4L\n\x1b\xc9k\x956\xea$\x8a\xb2\x1e+\x8alq\t\x00C\x8d\xb1\x8a\xc2v)\xc5\xd3(\x83\xf1*\x19\xf1\\\xe3\x97\xf0\xfc:r\xb9\x97v\xbb\x94\xbd\x1f\xb5\x8d$\x95t\ue2b2\xd6x\xe4JH^\xab\xf4p%\xf4ca\xebF`E\xa1,.\x01`\x881BQ4]JQ}\xf6\xa0\xac\x05F:\xd7bj\xce9\x1e\x88\xcf\x1c\x97\xdc.\x11\xe5\xfd\xa8m$\xe9N\xf3\x1a\xdaO\xd7\r\x97ת\xc2\xd7r\xee\xe4/>\x8f\xe0\xc6\xe6\xd6\xd3\x16\x97\x000\xc4\x18\xa1(\xda.\xa5M\a\xbcV0ڸb\xc23#\xa65x\xf6Cr\xbbD\xb2\xf7\xa3\x0fF\x92\x83\xc2嵪\xf0\xb5\xbc\x1e\x192q\xfe\x1f9\x0e\x1bK\xc9\x16\x97\x000\xb4\x18\xa1(\x81\xc6#\xf3\x8eG/^<\xf9\xe9\xb3EO\xb4B\x19\x18`\xd2\x04\x00C\x06(\x8a\xfe\x9c\xb6\x88C\x92\xbeX\xf7\xbb_}\x01\x14\x05\x18̀\xa2\xe8ϵ(\xf1bos\xd4\xcb<\xaf\x00\x14\x05\x18̀\xa2\xe8O_\x86yGum\xf5\x0es\xc6KX^\x1aa$\t\x00C\x06(\xca\x100pf\x83\xd5dM>\xfb\x12\x82b\x88\x91$\x00\f\x19\xa0(\x00\x00\xe8\a(\n\x00\x00\xfa\x01\x8a\x02\x00\x80~\x80\xa2\x00\x00\xa0\x1f\xa0(\x00\x00\xe8\a(\n\x00\x00\xfa\x01\x8a\x02\x00\x80~\x80\xa2\x00\x00\xa0\x1f\xa0(\xa3\x99C\x11#\xef)Jm\x11\x87\xb4B\x8c\xe7L\xe2\xa3\x11\xda2\xbf\xc3 E\xf1\xe6R\x8a\x1f\xe7~\xc0~\xe0$\xb8?\f\x96\xcd\xdcF\xf2\u07bc\xc1lM\xab\xb5>B\xdbx\x9e7\xfbv\xc3m\xed<>\xb1\x0f\x9d\xe0yoΆ5qg\\ɿ\xedX\x12\x93\xdc\xe7\x9e\xcbbs\xd0\x17\xacl\x83\x1b\xa9\xe0 _\x80\xef_Vi\x19\xa0'\xc6(\x8aW\x97RԖWX\u007f\xab\xfe@\x9e_=\xc7\xcd\x002\x83v\x93\xf7\x1a\xf3\x1f\xca*?\xe4\xf9\xff\x8b\x1e8\x1c\xa5\xfcU\x8db\"\xdd5|\x8c\x03u\x9e\xe0k\x14^\x1d\xb2\x95*\xe6\xac\xf9\x84+\xf9I\xdc\xd7\xe9\xe6'\xee\xb9LJ\xc6n\xf7\xcc4\xba\x914\xa5Q\x15b\x82\xd92@W\fQ\x14\r\x97\xd2*\xe2\xb6ѓ\u007f\xdc[\x1d\x80;7Ư%\xef\x8f-)\xc2\xf1\xd6\xf9\x9ep\xb0\"\xec\xd3\xe1\xdb\xc1\x8a:\xf9\xf4m\b\xdd\xe7\xdd\x1f`\xbb\x9a~X\x9c\xf4{\xff\x98/E}\xaeP\xad?2\xae\x0f\xbe\xe5\x9ee|#e\xee\x9ar\\IF\xcb\x00}1BQ\xb4\\J\xcb\xc5'\xe4\x1f\xf2'\x130\x03\x88\x9f*\x9e'昉\xc9z1OL7\x06q\xb0֚\x9f3\x0e֕\xcc\xc7O\xde彞\xe9(\xe9\x98\xeaa\xe41\x9c\x8d̰Jn\xb0\x8c\x96\x01\xfab\x84\xa2h\xb9\x94\xb6\xe5\x1dk\xedi\xad\xca\x1by\xb3\x8c/͍\xb7\xc3\xc6MY\xd0▤ɝb\xc7o\xb7&:\xad/&\xd2\x16h\x8d&\x9e\xdfs7}YL\xf2\x8b}<\xcfW\xa2J\xe1u\x9f\xb2\x82\x9e\x89\x1f\x8b\x89\xf72\xc8\xdb\xe3brf \x1d\xac\x92=*B\x977\xd8L\xb1\xc96\xf2T~\xc9\x13\xb5\x93\xbf\xbf\xf2\x84\xf3`eZ\xa9>1\xf3|\x14~\xee6\xea\x8d\x15sw)r\xa9ʨ\xf6\x92\x05\xebCܟ\x1blh#\xcf\no{P\x81\xf0\x8a\x9f\n\xdek\x91\x86(\xac\x96\x01\xfab\x84\xa2 -\x97Ү\xf2\xec\xec\xec#~\xb4\xab\x8fM\b\xdf\\\xbe\x91۪L*x\x8b\x9b\x8f\xdfzvo\x17ɥ\x8d仫+m\t\x16ۮ\xb4y\x0f\x1f\xa5%^\xeeD\x9dW֤\xfd\xa2\xac\xe0\"wL\x8c\x8d*\xa6\xb3\xa5\x83U\xb2GE?\xcdK?QS\x16\xcb\xe3\xa3]\xf6D\x15\x0e\xd6\xd2d\xe7\xc1ʴRE\r\x0eG\f1\xfc@7\x1d\x95|\x81\xc3\xf1\xb32W\xae\x8cj/Yp\x92;\x85\x14\x18\xdb\xc8\xe7Wl;\x1e\xa1G\xfb,\x97q\xb9\x9b\xbcC^\xb3G\xcb\x00\x9d1VQ\xd8.\xa5=\xe5\xf9\xf5-\xf5\xf9\xe5\xf415\xaa\xe9\x9a>\xbf\vO\f\xb5)\x92J\x9a>\xbfA\xde\xef5\x89\xb8\x1bɯ\xe4?y\x86\x06\x9e!T\xb1\x9c|~\xbf\xc2-\xa0\x84\x13+\xb8/\x1a\x87\xb9p\x1d\xac\x94=ji\x1c>LK\xf1\xb3*)OT\xe1`\xfd%\xe6\x17r\xb0\xb2\xadT1.\xedP\x9eP8s\xa9ʨ\xf6bnqn\x8f\"7\xba\x91\x05x\xfc\x92.\x8e\x8b\xce\xf1\u007f\x95c=Z\x06茱\x8a\xc2v)=\x9e\x8f\x87'=\xf9'U\n\x8f:J\xb8\xef\x19I&M\x9c\v7\x0f\xb4\x95\xd1\xe2\xcf=j\x8c\xea~^\xf1\xe4Et\xa3[\xc9Bg\x89^\x13\xf3矲G}h]\x96Uv\xb3\xaf\x17ў\xa8\xf8`E\xc9\xc5\xe4`e[\xa9b\xbc*\nU\x19\xd5^\xcc-w\x8fe\xa3\x1b\xf9`\xde_P\xb7\xa5\x86\xa4O\vuHx\xb4\f\xd0\x19c\x15\x85\xe9R\xdao\x17\x0f\xba\xef\xed\xfd\xac\xa2\xa3\x90\xad\\\x17#ɦ\xaaH\xa4\xca-\u007f\xe5jg\xa2\xdb\xd4X\xcc\xef\xbb\x1d\xe5v\xfd\x14\x9dr\x8dߝS\x14\xbd5\xe4\xcdu\xb0\xd2\xf6\xa8O\xcaR\x13\xf8%\a\ahOTr\xb0\x9eXI\x0eV\xb6\x95*ƫ\xa2P\x95Q\xed\xc5|˹\xff:\x18\xdd\xc8\xe4\x1ct\xc1\xd2K\x92W\xe9i`ϖ\x01\xfab\xac\xa20]J]\x8ar\xd1o\x14\xa5\x9c\xbb\xc8H\x0e\x0e\xf9\x98I\xa8\\\xb7&\xe1\xf4r\xf7\x80\x8e`\xf1\xf66\x94\x13CfX\xaa\xf9G\xf8M\xfa\xf9\x97\xedQ\x1br\x84\xe4\x93ʘR\xda\x13\x95\x1c\xac\xcf\xcd5\xe4\xe7\x9fi\xa5\x8a\xd1\x18\xa3H\x95\xb9\x1d㟎oGJ\x8cn\xe4\x99E\xbdΓ\x1e\xf4<ڵ\x1c\xb1Z\x06英\x8a\xc2v)\xfd\x86\x9c\xf5t\xe5\u007f㭆\xd1DǔH<'\xf4\xc1*ERI\xd3\x177<\vR\xc8GhZ\x96\xe9\x02\xbf\xd3\xf9\x91*\xb6x\xa6\xa8\xc0\x8f-\x9f\t?\xc6}I\xcb\xc8'\xd7\xc1J٣\x16\x88s\x0fI;\x10퉊\x0fV\x94\x9e\x86\x0fV\xb6\x95*ƫ\xa2P\x95)\x15\xa5\u007f\xf6\x02W\xd2\xd5^\xa3\x1b\xd9\x1b{f\x91\xeb>\xdb\xd4\xf7\xa4;V\xa8\x96\x01C\x83\x11\x8a\xa2\xe5Rڵ?\xbf\xeeN]\xfe~\xff\xb9\xd8s\xf4\xf572K>\xe0\xecʤ\x82\x85\x9c\x97\xef\xf6\x8b\x1f\xc8Ռ\xfb\xe4\xc3A\xb3\xa5/\xc1u\xd4P\xc5~\f\xda\"&.\x98\x13+\xcel0]A\xe8!\xbe\x1d\xb5\xd8\xe1\xc0?\u07b2=j\x01o\xdew\xf6t\x06\x8f\x8f0\xc9\x13\xb5\xbb\x86?щj\xcd\xe42\n\xd3J\xb5\xf7\xaa\xc3\x11\xb3\xcdq\xf9\x99\xeb2\xcaU|`R\xb9re\x8a\xf6\xe2S=i`&\xb5\xd7\xd0F\xe2:\u07b5\xbcp\xb6\xe1vԟ]\xcd\xd9\xfa\xb2CF\xc0W\x8cP\x14M\x97Ҟo\x0f\xe4\x16~\xeb7\x97z\x04\xae\xbf3mbD\xa1{\x92&wr\xb6G\x9eDc\x14\x99HH&\x1f\x1a,\xfb\x04Ui\xf0,\xb6\xfeu\xe7\x9c@\xf3\x06\U000d253f\b\x89t\xe7\f\x04\x1e/\xc8\xf6\xa8\x15k\nl&k\x92\xf8\x93\xed\xf2D\xad\x9d\x87\xef\xd6\xe8K\xb4\xf6)be+U\xf4\x93\xd8\b\xbe\fu[H\xc2t[\x91KU\xa6h/:\x1e\xf2\x91\xd4F\xb9\xbdF6R\xe06\x9f!5b_\xcc\x151A\xb7\f\x18\x1a\x8cP\x14`\x88X5>_+d\x18\xd8?>~\x04\xfc8tF\xcb\u007f.\x1c\xc82\x91\x13\xa4\x91\xd12?\a\x14e4\xb3u\x9a\xfbm,\xc3O\xdb\xd4\x11\xf1\a\xdf\xea\xd8\x17\xf2\x87\x81b\xdb/#\xa6e~\x0e(\n\xe0\u007f\x14\xd4\x0e|\xe2\xf6\xa7\x05\xc0 @Q\x00\xbf\xe39\xbfz\xa7\xd5\xf3\xa1\x06\x80\x11\x80\xa2\x00\xfe\xc7>\xf3\xba\xdbZ1\xc0\xd0\x00\x8a\x02\x00\x80~\x80\xa2\xe8ϗL\xb4J\x01\x80?\x00\x8a\xa2?\xa0(@\xe0\x02\x8a\xa2?\xa0(@\xe0\x02\x8a\xa2?\xa0(@\xe0\x02\x8a\xa2?\xa0(@\xe0\x02\x8a\xa2?\xa0(@\xe0\x02\x8a\xa2?\xa0(@\xe0\x02\x8a\xa2?\xa0(@\xe0b\x90\xa2xw)\xed\xbfTh/\x94\"F=\xa0(@\xe0b\x8c\xa2xw)\xed/ʽ\xd8t\x9e<\xd8\xcd/piȟ\xfe\x0f(\n\x10h\x18\xa2(\x1a.\xa5\xdf۱\xf7\u05cfv\u007f\xb1RwJ\xc8?\xff\xe7\xff\x06\x8a\x02\x04\x1aF(\x8a\x96Ki\xc9\x11\x92\xcc\xf3\x97A\n\x11\x90\u007f\xfd\xaf\xfc\u007f\x871\n\x10p\x18\xa1(Z.\xa5\x85\xa2\xb3ġ\x12f\xe9ч \x1f\u007f\xfa\x1f\xa6\xff\xf2/_*\x10\x16\xdcM\x8d5\xc5%?@\xca$\x00\xf8\x11F(\n\xd2p)=\x99\x87\xe7g\xbbr\xfd\xc5\xed\xed\xcb/\xff忘\xfe矈\x8e\xfc\xe9\xff\x88\xfcIP\x94Z\xf3\xea\xafj\nx\xec\x85E%\x01\xc0\x9f0VQ\xd8.\xa5\x1d\xbb\x8bZ\xbbZ\x0ee\x8fć\xa6\xbe\f_\xfe\x0f\xfe\xbf\xfe\xabsd\xf2\x8f\xce\xc74\xff㗨ۖ܍Po\xf5cD'\x01\xc0\xaf0VQ\xd8.\xa5\xa8\xad(;\xdb~\xaa\xe8\x10\xbb\xec\xa8\xe3\xcb\u007f6\xfd\xe7\u007fv*\xca\xff\xfe\x17\x91\xff\xfd%\xba\xc0\xdftEPI\x00\xf0+\x8cU\x14\xa6K)\xa6\xab\xad\x1f\xe5\xf9\x8b\u007f\xa4\xa0#\xffM\x1e\xa5H\xf3(żd4J%\x01\xc0\xaf0VQ\x98.\xa5\x82\xb4\xe0\x97\xeb\xd9-̢\xa3\x0f\xac\x1f\xf2L\x8a\xa4(5\xfc5W\x04\x95\x04\x00\xbf\xc2XEa\xbb\x94\xd6g\xb7\n\x8b\xf6\x1e\xf3Z\xc3(\x82\b\b\xbe\xda\xf3\xbf\x14\x8a\xd2iM\xc2\xd6\xdeYY\x88N\x02\x80_a\x84\xa2h\xb9\x94\xfe\x98\xfdݝ\xef\xf3\x8a\x9ej\xd53ZpJȿ\xfe\xe3\u007fW(\n\xaa\x8dY\xfe\xf5\x85,\xe2\xc6G%\x01\xc0\x9f0BQ4]J/\xe6\xe7\x16]\xec\xf7^\xc9(\xe2K&\u0082۩6K\xe2i\x12C%\x01\xc0\x8f0BQ\x02\rUE\x01\x00\xbf\a\x14E\u007f@Q\x80\xc0\x05\x14E\u007f@Q\x80\xc0\x05\x14E\u007f@Q\x80\xc0\x05\x14E\u007f@Q\x80\xc0\x05\x14E\u007f@Q\x80\xc0\x05\x14E\u007f@Q\x80\xc0\x05\x14\x05\x00\x00\xfd\x00E\x01\x00@?@Q\x00\x00\xd0\x0fP\x14\x00\x00\xf4\x03\x14\x05\x00\x00\xfd\x00E\x01\x00#h\xf5\x9f\xbf\xc2z\x05\x14\x05\x00\f\xa0gҍ\xa7\x01\xa1)\x06)\nå\xb4\xe5\xc8^{\xfeI\xf2\x88\x03\xd4r(\xf7\x88\xbf<\xc1\xcd7\x9a7\x98\xadi\xb5\xd6Gh\x1b\xcf\xf3\xe6\xbbZ\xe1\xc0h\xe7\xe9\x98\t\xdfw\x04\x82\xa4\x18\xa3(\f\x97\xd2{\xd9%\xf5w\xea\x0f\xec\xc5\xcfY\xbac\xaf\xbaQe\xbf\xe3\xb5\n\xff\xa2\xc6\xfc\x87\xb2\xca\x0fy\xfe\xff\xa2\a\x0eG)\u007fU+^\x8dg?\xab/;zQ}\x19`4\xedc\xc6L\xbc\xe47\x0f\x15\xf3\x82!\x8a\xc2r)\xbd\x91\x8d\x15\xe4)N\xf6\xef\xc5Ϭ>\xb97\x10\x14\\\xe4\xb1%\xa5\x1b\xa1\xce\xf7\x04E\x11hxYE\xe9+\xb3\xacS_\xfa\xbb\xc5\xea\xcb\x00\xa3i\x1f\x13\xff\x9b\xb0\xfa\x00\x90\x14#\x14\x85\xe9R\x8a\xc8\xc6mŏ\xab\xae\xb7cK\xb0\xa7҃\xf1\xfd\x9f\x1c3\x19[\x14\xf3\xb7\xf1\xdb\xcb*J\xe3j>ŋ+a\xf8;\xea\xcb\x00\xa3i\x1fSx\xfe7S\xebe\xf3;\u007f\xc5\bEa\xba\x94\x92\x05\xb7\U0008b10f\xe5\x87ɧ\x92\xa3\xac£\x92\xcb\x1bl\xa6\xd8dۀpZ\x92j5\xd9R\x1a\x85\xbc}<\xcfW\xa2J\xe1u\x1fz/\x83\x84=.&&\x1b\x92\xa2\f|\xbdڼ\xb2t@Y\x03\x1a\xa8H4'\xecz\uef8e\xce]Q\xb6\xb3\xee\x99\x12E\x9cH8B\x97\xc6r\xdc\xfa\xebKg\x84\xcc\xefY\xc1\x05塦\xf1\xdcl\x12\x93\x17\x11:k\x95\xbf\xd8\u05cft\xda\xc7\x1c\xf8\xf5\xe4k3\u007f\xf4{I1BQ\x10ۥ\xb45;;;\x17\xcf\xcc\x16\x8aF='\v\xd5J\x8f6~\x9a\x97~\xa2\xa6,\x96\u007f\x81\xd0Y>\xa3\xb6:%\xaa\x01\xa1Gi\x89\x97;Q\xe7\x955i\xbftG)\xecI%EI\x8f\xdesnOt\xba\xb2\x06\x94\x11\x95u\xae4ne\x9fb\x15\x03\xa7\xad\xa6\x9cN\x92\xec\xbe/\xa2\xb0\x00\xea8Y5knUU\x950\xee\xeb\xca\xdf;c\xd6\xc4髖rM-U\xe36\t\xba\x1e\x1f\x8cC\xe2\x83>(\xd9>9<p\xce5\x87\x95\xf61\xf9\xbf\xfez\xe4\xb5\xd97\xfc]R\x8cU\x14\xa5KikK]\xfe\xdevi\xe1wy\xaa\xc5G\x19\xa5qX\tJ-\x82\b<\xaf\x16\x0e\xfb\x81\xf7S\x84\xcf\x15\xcb\xc9\xc2\xf7+\xd0}^\xf1\xccj\x97\xa2\\\xe0k\x10\xf6\U000b9828\xe1,_Ab*\xe9\"h'\xbf\xb2ٙLr\x1a\xa1\xaeAJ\xa8\xb3\x9ep\xee\xcd6\xf1d3XP\x14\xb4\t+J\x11\x97+\xbc~\xcb\xedG\x80\x01\xb4\x8f\xd9\xff\xf7_\u007f-|-\xbc\xc9\xcf%\xc5XEqw)E=\xf9\xe5\xc2\x18\xa5\x8a\xa4\x8f\xf9\xcd\x18\xe5\xa1uYV\xd9\xcd>lɃ\x1e\x97&\xbfk\xe1?\x14R\x8dQ\xdd\xcf+\x9e\xbc\x88nD\xbd&\xe6\x18%\xe3}\xf2\xb6|\x9b\xa2\x86\xb4w{_\b\xd82\x14\xab\xa8\x88^T1 &o\x9f\x11\xb9\x8d\x94Њ\x12\xdc\xe4LɊ\xb2xf\x0ffZ<\x02\f\xa0}L\x9e\xa0(\xbf\xe6\xbd6\xb7\xa9\a\xf93\xc6*\n\xe5R\xda%\x8e\xb6/\xd9\xfb\x9d\x16\x83\xe8\xd07̢\xa3\x91'e\xa9\t\xfc\x92\x83\xc2!\xdf\x10g\xcb9\xedX\x87\x15\xa5\xdb\xd4X\xcc\xef\xbb\x1d%\x9c\x9d8\xe7QzkțKQ\x12S\xc8[r\xa2\xa2\x86\x0f\x9dC\x90\x14\xe5*\xeen\xe0\x13\x9b\x917hE\tw\xa5dE\x99\xe3\x9ciy\x8bQ\x14Н\xf61\xbb\xff\x03KJ\xe6\x98\xf9\xfe-)\xc6*\x8a\xecRڟ'\xce\xc3~/(J}6\x1e\xb9\xb4e\xfb͵\x9e\x86\x1cA\t\x9eTƔ\"\x94\x90\x88\xa7TS\xb1\xa2\xa0\x84\xcauk\x12N\xe3s\x9f\x9c\x98_pF5\xff\x88\x84\xbb\xc6(\uf489\xd8e\xe9\x8a\x1a\xd2\u07bdFx\xec\xb6\x12j&\x85\rQ\x14;\x19\x9c\x84\xbf\xed\xca$\x8a\xb2\x1e+\xcaҙ\x17\t\xad*\xc5\x01]i\x1f\x93K\x14\xe5\xd7/Ƽu˟%\xc5XE\xa1\\J\xf7\x1e\xc1\x19䬧\x9f\x18\x94\x1e\xf5\x9f\xfbQ\n\xf0T\bBI;\x10\xb2\xa5\n\x89\xbe\x95DQҲL\x17\xf8\x9d8\xe3\xb1\xe53ᄦ/i\x19\tw)\xca92WRɟS\xd4P\xc3W\xe3d\xceA\x8f\xd5t\ue2b2\xd6x\xe4JDF\"t\x8f\xcb\xc7Iy\xb8\x12\xfa\xb1\xb0\xbd#\xb0\xa2\x1c\x11\x17\xfd\xf1svi@_\xda\xc7\xd8\xff]\x94\x94\xf5c\x96\xde\xf1cI1BQ\x98.\xa5?f\x97\xd7ߩ\xcf'\xf7\xcc\u07b2\x1f\xbdq\xcc~K\xa3\x9a\xd1C\x01o\xdew\xf6t\x06_\x8b\x93\xa9\xa5\x05+\xf9د\x04\xd18h\xb6\xf4%\xc4\x14\xe0\x88\v\xe6Ċ3\x1bLW\x10z\x88\xef\x99-v8\x1e\n\xb9iQ9gs\xa2Ҕ5\xa0\x9cyi'\x84\xa4rfV\xa4yM*#\xd7\xc9\xc6\xe0-\x85o\x86\xdeA=\xa7\xc8e\x1fq&e\xee\xe4/>\x8f\xe0\xc6\xe6\n\xe3\xc1\xb5\xdc\xe2\xfcC\xf1\x9c\xdḟ\x8fl\xda\xc7d;\x15\xe5\xd7U\xaf\xadh\xf1_I1BQ\x98.\xa5\xa8\xe5\x9b|{\xe1)q\xe2\xbb\xe5\xb0\xfd\x90\x1f\xfd\xaf\xa7bM\x81\xcddM\xc2r\xd0W\x9c\x10\x1d\x97V\xf1\x9e)I\x18\x8bX\xf6\t\xaa\xd2@B\x9a7\x98\x97\xa4\xfcEH\xa4;\xa7I\xc8X\xa6\xf4C\xf3\x87\xa5}\xca\x1a\x84QʺX˚\vj+S\xa5냰\x90\xb9\xdf\"t)\x88̗, \x99\xd7#C&\xce\xff#ǭ\x10\xd2G\"\xc3&\xcd=\xec\xbd\x12@'\xda\xc7d\xfeۿ\xff\x87x\xdcĿ\xb6\xca\u007f%\xc5\bE\x01\x80\x80GP\x94\xff\xe7\x1a\xa4\xfc\xfa\xf6kk\xef\xf9\xab\xa4\x80\xa2\x00\x80\x01\xb4\x8f\xd9ޏ\a)\u007f?y\xfc\xf8\xf1c\xaf\xbf\xb6\xb1\xd5O%\x05\x14\x05\x00\f\xa0}\xcc\xd6\x1e2H\x996\x86\xf0\x9b\xedm~s%B\x01(\n\x00\x18@\xfb\x98-]\xe8\xdf\xec\xff\xfek\xf9\x98\x05\xff\xb4y\xf3\x16\xfb7~\xfaP7P\x14\x000\x80\xf61\x9b;z6\xbe\xb6\xf9ᅫ\x9ft\xb8\xbe\xa9\xa9\xa9\xd5O\xef\xc6\aE\x01\x00\x03\x10\x14\xa5m\u0558\xff\xf4\x0f\xff\xfe\xeb\xde\xd72[z\xfa\xfb\xfds\x84\x02\x8a\x02\x00\x86 (J\xfc\x987>~-\xf3\xef\u007f\xff\x87Yu~:>\xc1\x80\xa2\x00\x80\x01\xb4\x8f\t\x1d3g\xf7\xa9\xd9\xdc\u007f\xfc\xba\xf97\xf9~:\x87\x82\x01E\x01\x00\x03h\x1f\xf3ZD^]k\xf9k\xb9\u007f\xff\x8f\u07fc\xe5\xc7\u007f\x16\x04E\x01\x00\x03h\u007fma~}G\u007f\xdbl\xee\xdf\xda~\x13Y\x0f\x8a\xc2D\xabr\x00\x00D\x9e\xfe\xd3qAPP\xcf\xe1\xdf\xfc\xa7\xdf\xfcç?\x82\xa20Ѫ\x1c\x00\x00\x91\x9e\xb6V\xf2H\xa0\xf6\xa2\x88\xf9[N\xc2<\n\x1b\xad\xcaG:\x8b\xb9\xb0\xdf\xfb\xcdCY\x80\x91\x8d\xf3rq\u007fۍ\xba\xeb\xfez\a>&\xa0\x15\xa5\xe5h\xee\xec0\xf1a\xf0m\x11\x87\\\xb9T\x12\x00\xf4\xa6\xbf\xa7\xa7\xc7\u007fG(\x86)\x8a\x86K)\x1d`,ǸKbbs\xd0\x17\xae<*\t\x00\xc0\xa00FQ4\\J\xa9\x00\xa3\xf9\x96;\xe5L\x95\x8cݎ<\x93\x00\x00\f\x06C\x14Eå\x94\x0e0\x1aYQ\xd0\xfa\xe0[\x8c$\x00\x00\x83\xc0\bE\xd1r)\xa5\x02\f\x87R\x94\x8e\xa9\xf1\x8c$\x00\x00\x83\xc0\bE\xd1r)\xa5\x02\f\xe7\x12wLJ\xaf\x0f\xe9b$\x01\x00\xf0\x1d#\x14\x05i\xb8\x94R\x01\x86\xd3\x13\x16q\xf2\x8eS\xe4N\xca\xe3\x15*\t\x00\x80\xef\x18\xab(l\x97R*\xc0x\x0es\x1c\xb7PL\xde\xe2\x0e\xb8r\xa9$\x00\x00\xbec\xac\xa2\xb0]J\xa9\x00\xc3\xe9\x98<c\xeb7N\v\xcf[\xb2\a\xf0-\xb0\x03\x06\x80\x97\xc1XEa\xbb\x94R\x01\x86\xf3-WN\xa5O2\x92\x00\x00\xf8\x8e\xb1\x8a\xc2v)\xa5\x02\f\x87\xbaփ>\x1d\xdf\xceH\x02\x00\xe0;\xc6*\nۥ\x94\n0\x1cJQ\xfag/`$\x01\x00\x18\x04F(\x8a\xa6K)\x15`4\xa7dE\xd9\xca]d$\x01\x00\x18\x04F(\x8a\xa6K)\x1d`$=-\x17\x17\a\xbb\xdcQ\x8f\x87|\x84<\x93\x00\x00\f\x06#\x14e\xc4\xf2\x16\xc7\xcd8\xe4L\xef\x1f\x1f\xdf\xe3\x99\x04\x00`P\x04\xb4\xa2\xb4\\\xbc\xe3J\xb6M\xfd\x82\x91\x04\x00`p\x04\xb4\xa2\x00\x00\xa03\xa0(\x00\x00\xe8\a(\n\x00\x00\xfa\x01\x8a\x02\x00\x80~\x80\xa2\x00\x00\xa0\x1f\xa0(\x00\x00\xe8\a(\n\x00\x00\xfa\x01\x8a\x02\x00\x80~\x80\xa2\x00\x00\xa0\x1f\xa0(\x00\x00\xe8\a(\n\x00\x00\xfa\x01\x8a\x12(\x9cI|\xa4\x15\x12\x10\x90\xed0\xb4N\xb4\xee\xab\x18ڵ\x8d0\fR\x14\xef.\xa5\x1dU\xf9\xf6C\x97\xe0\xff\xbe\xbeS\xcc\v\xccK(\x1b\x10?\xd6ĝq\x8f\xd8&\x04\x98\xefʟ\x0f\xf2\x058\xb8>,\x17\xd9î\xbbG3\x19L,\x8b\xc6(\xa1\r\x19\xd2GF#u\xa18\xe6\xcfR\xfa\xbe\x89_\ue664qn\a\xb6\x13mc\xf2\"˚\xda\xf7\xaf0\x16\xb9\xf0\xa1\x17\x9e\xab\b$\xdf[c\x14ŻKi{\ue87a\xa6\xf3\xbb\vAR\xd8\xd4^\xf3\xc8z|\x90\xafp\x9cK\xe3\xf7\x89\x1fϚO\xb8G<p8J\xf9\xab\xd2\xc7Ҩ\n\xf2^έB\xab\xb8oH\xfa\xa8\xc6c\xa5\xe8X6\x8c\x96Q\xbc\xb8\xba\xf2}\xc7C\xe9#\xa3\x91Z5\xf8ć\xa6\xf7\xa5\xf4\xc0\xd5mўI\n\xd7v`:\xd1^3\xa5\x9c\xa8\xfc\x8c\xe7\xab\xf1\a\x95\x961{\xa1\x80\xb5\x8a\x00\xf2\xbd5DQ4\\J\xbf\xc9\xc7Ϛm\xb3\x9f\xf7VG\x00\xb3:\xd53\xaf\x86o\x16\x0e\x9a\x9d\xfcm\xf1c\x9fg\x04B\r\xb2\xa2\xdc5刉\xf3\xdcF\xb4\xd1\xf9\x84\xba\xdf-f\x95\x92\xa1cٰZF\xf3I\x12\xfd\x89\xd5H\xad\x1a\xb4\xe9\x8cJ\x8b\xea\x94?\x16D\xb3\x92.\xa4\xed\xc0t\xa2ݰN\x18[\fl\x13\x15E\xade\xccMM\xc1^E\xe0\xf8\xde\x1a\xa1(Z.\xa5\x85\xf9d\xe1\xd1\"v\xf1\x80g\xa5\x9a\xa2\xa0n\xcbN\xcfE\x12\x94\xa2dX\x9f\x8b\x89\xeb\xdcV\xb4\x9d\xbbA\xd2\xe1\xef0\x8bIбlX-\xa3Q*\n\v\xad\x1a\xb4\xa9\xe5\xaf\xf1\xb5\xf2G\xef\x8a\"m\a\xa6\x13\xed2\xa2\x05\x8d\xfci\xfc\xf6\xb2-c\xaf\"p|o\x8dP\x14-\x97\xd2\x16\xf1\xb9G'\x87\xc1t\xeb\xc6\xdba\xe3\xa6, \x0f\x86\xcc\f\x0f\x9d\x93)\xbc\xaf\xe0\xc6\xd9W\xcd\n\x9d\u007fK\x91T%/\"t֪\x0e\x84.\x8d\xe5\xb8\xf5ח\xce\b\x99\xdfC%݂s\xa7\xd8\xf1ۭ\x89\x9c\xc8D\xe9\x89O\x02;ySٮ\x04\xf3\x86\a\xf8\xc3@E\xa29a\x97\xf0\xdd<Ë\xacV\xd6$*\n\xda\x19\x8b\xd0\x133\xcfGU\x92\xdcg\xa9V\x93-\xa5\xd1\x19#+J\xaf\xc5\xf5\xbb\xd9\xca\xe5\xa1|\xae\x15\xa1\"g\x13\xc2I\xb6k;\xac\xe0\xc6n\x8f\x9f\x16\xb6\xf0\xba\"\x96\x8d\xa2e\x977\xd8L\xb1ɶ\x01e\x88\xac(T#\xe5XE\rR\x8f\xd9ۡ\xd1\xc4\xf3{\xee\xa6/\x8bI~\xa1\\G\x81\rYœ\xbf\aiVK\xaax\xaa#%\x95\xc5\xe4\xed\x80XN\xb4iV\xbcQ\a\xceu\xd2-\xa3k\x90{\xa1h\xe4\xe3\xf4X[NN\xac\xb9\xda\xcb*\x02\xc6\xf7\xd6\bEA>\xb8\x94\"Կ\xb7\x8aYt(96!|s\xf9F\xe1\xa7\x18\xa1\xf8\xe0\xf5%\xeb\x83\u007f\x8fP\xfdޱ\xdc\xe4M[&\xbe\xadH\xaa\x11\x1f\xf4A\xc9\xf6\xc9\xe1\xfd\xa8+\u007f\xef\x8cY\x13\xa7\xafZ\xca5QI\xb7跸\xf9\xf8\xadg\xf7v\x91\\Zr\x9a+M|\\\xc1\x9f-\x9f\xe1\x0f\x19QY\xe7J\xe3V\xf6\xa1\xce+\x8e\x84$\x87\xc3q[Y\x93SQ\xcaxa\xc0\xdf\xe0p\xc4\x14\x90ܳ|FmuJT\x83\x18#+\xcaM\xde\xe1L\xf5O;\x85\xbe\x9b&\xc8x\xc7ɪYs\xab\xaa\xaaȔ\xb9\xb4\x1dp\x8fg|\xfe\xe9\x8c\xd0::\x96\rݲ\x9f楟\xa8)\x8b\xe5ݎvj\x8c\"7R\x8eU\xf4M\xea1{;tWW\xda\x12,\xb6]i\xf3\xe4\x99\x19ºT\x94\xba\x0e'\xeeZ\x12*\xcel\xe0\xa3\x15Ie1y; \x96\x13\xedC[Tr\xc1\x0f\xbdH\xd17E\rR/\xe8F\xf6.\xb7\x96\xee\x8b1\x97m(\xf6\xb2\x8a\x80\xf1\xbd5VQ\xd4]J\x85M\x9e\xdb\xc6.;ttM\x9f߅\x1d>ڰY)v\xfb8\xc2\x1d\x16^\x83'\t\x83\x92\xa5\x93\x912ɤ\x88\xcbEآ\x838\x10\x86so\xb69O\xe9\xa8$M\xd3\xe7\xe29Ľ&\x11\xb7\xc7\xffG[\x84\x9f\xbc\xf48\x84\xa5\x01\xcf\xee5\xf0\xe4\xf7P\xfd\xac\a]pN\xa48\x0f\xd6\xe7Ղ\xc0\f\xbc\x9f\"\xc6Ȋr\x8e\xff\xabG\r\xd4Y\x0f\xb5\x1dP\xf0\f\xdc\xf0\xe9\x11\x8cxO\xa4\x96\x95\xc6a-)\xb5\xb8M2(\xcfz\x9c\x8dT\xc4J5\xd0=V\xdb\x0e\xfc'\xcf\xd0\xc03\xa4\xa0\xcf\\\x8c\x8a\u0378\xae5\xef\tC\x99\xbe\x0f\xa3\x95IE1\xc5v`8\xd1>.\xf8\x83\x89\xb7T\x8b\xc5䭮X\xb1\xb3\x17T#\xabyaTX*\xee\x10\xd5U\x04\x8cﭱ\x8a\xa2\xeeR\x8aNe\xbb\xff\xa0\x0f=%\xdc\xf7\xaed\xfco\xc9\xdb\x1b\xf8l7\x18\xbfl\fF\xca$\x93\xc53{0\xd3\xc8Irx\xb0\xd4\x05*ɠ\x89s\xa1\x8c\x8aNGγ\xff\xb4w{_\b\xd8ȵW/\x8aR\xc1?&\x1f]_\xf3ǥ\xc9\xefZ\xf8\x0f\xc5\x0f\xb2\xa2\x9c\xe6\xef#O$E\xa1\xb6\x03\n\xfe#~\xcd\xe4|\x92w\xa9e\x0f\xad˲\xcan\xf6\xf5\xba-g*\x8a\"V\xaa\x81\xee\xb1\xdav\x88v\x1b\x9e`\x1a\xf9+\xddW\xf0!\xfd\x84/ß\xf7D+\x92\xcab\x8a\xed\xc0v\xa2\xed\xaeI\xe6\xcf\xe1\x04\xad(\xf4\x8a%E\x91\x1a\x99c\x11^n\x8b\xb3/\xaa\xab\b\x18\xdf[c\x15Eե\xb4\xe7\xa8]\xbac\xc58\xb6rҹ\xed\\\xd1M}\x01\xfem\x0e\xde(\xbcl\x12\x15EN2\x99\xe3T\x86\xb7\xf0\x87\xf0p)\x9fJ\xb2\xa8*\x12q;ϋ\xc6_V\xf2%\xfd\xd0y\x1eOF\x1b^\x14\x85|\x99\x91\xf45o\x88\xb3\xe5\x9cv\xac\xf3P\x94\xab\xd4ud\x19IQ\xa8퀂7\xe1\xd7c\xbe\x19\x16\xc9-{R\x96\x9a\xc0/9\xa8:\x8f\x82q\x1d\x8bt\xacT\x03\xddc\xb5\xed\xe06\x97D(%\xcbKqo\xc9\xe9\x06.F%\x95\xc5\x14\xdb\xc1Ӊ\xb6\x81̊\xf4%\xbaouŊ%E\x91\x1aY<\xef1\x1e-\x8ac\x14\xb5U\x04\x8cﭱ\x8a\xa2\xe6R\xfa\xb4(\xcfe\x9bc$\xe5\xf2q\x13?\x93\xbc\xcd c\x14|P9\x15EN2Y:\xf3\"\x81L_\x86\xcb\xf3-\xe1^\xa6^ԑ\xbf\xa4i\xef^#\x90\x11\b\xf9nW(\u007f\x9fEE\xe9\x8ds~\xed\x9d_\xf3\x84D|\x9d!\xd5CQ\x9eG\x17 O\x88\xa2؛\x14\xdb\x01\x05\xaf¯\xf6A\x8cQp\xcb\x1ar\x04}xR\x19S\xaa\\.*J\xe7>\xc5@J\x11+\xd5@\xf7\xd8\xdbvp'uuCC\x03\xbe\xd2\xfb7\x9eT\x98\x1e\xadH*\x8b)\xb6\x83\xa7\x13\xad5\x8b\xbc弇_\xa9\xad\xaeX\xb1\xa7\xa2<\x8cJ~ؘ\x90(\x9e\xf1\xa9\xad\"`|o\x8dU\x14\x15\x97\xd2\xd6\xfd\a\x84\xcd\xddo\xf8dxǔHf\b$f\x00\x00\x03\xb5IDAT<\xa3\xf3\xc1*<\xf0ǃ\xd2\xfd\\\tRW\x94\xa6M\x1e?\xdcG8r\xe5\xfb\x8f\x9f\xe3W\xeaj\xacʅ٦/\xbc]\x8b\xa5\xbe\xa45\xe2=\x119\a\xf1k\x92p\\>\x123\xa4\x1aDE\xc9\u1777a9\xbf\xe66\xfc\xd5\xef[\xe9\xa1((\xf5=\xc6m\x14\x91\x91\b\xdd\xc3\x1d\xa0\xb6\x03\n\x9e\xd2!ďt\x0fft\x9ejY\x01\u007f\x81|\xde!ƺ\xba)*\xcaM\xfe2\xf9\xe4l\xa4\"V\xaa\x81\xee\xb1\xcav\xa0\x0fli\x15\xd6]\xc2\xcb.\xab\xf0\x92h\x13t\xe7vL\xb42\xa9,Fm\aʉ\xd6UY\xac\x15+W\x9fX\x80\xda\xea\x1a\x8ar\x8d_\xc2\xf3\xeb\x1e8\x97\xb3W\x118\xbe\xb7F(\x8a\x96Ki\x93}\u007fSKK\xcb\xc9|\xad\x8at\xe7\xe8\xebod\x96|\xc0\xe1K\xbaK\x83\xd6\x16\xad\rZ\x8aPKո\xf8S\xe8b\xfc\xb8\xaa\x16*\x89\xa3\x17r\x13<~\xb9\xd7r\x8b\xf3\x0f\xc5sy\xa8\xe7\x14\xb9v\"\xfc\xe2\xd3I7\x16r^\xbeW?;Lۮ\x0e\xdc\xdcfr\xfc,\x1cC\xf3\xd2N\x9c\xce\x10g$\v\xa2\x8bO\u007fb~H\xd7@\ue67d\x90N\xee\x99\xed\xbd\xeap\xc4ls\\~\x86\x0f\xd6\xd4҂\x95|\xecWW\xd1C|\xcfl\xb1\xc3y\xcf\xea\xed(\xf9Nu\x89\x8d\xc1[\n\xdf\f\xc5\x17\xb0\xa9\xed\x10̅\xe7\xdbgM\xf2P>V\xe7\xe5\x96\x15\xf0\xe6}g\x85\xf6\xd6:cI#_\xfc\xb0\xf2}\x87\xc0\xd7\xc2I\x88\xa2\x91T\xac\xdc7\xa9\xc7\xec\xed\xf0\xe2\ar\xf5\xe5\xbe\xd4\x1c\xb2\x8a\xee\v|N'\xea\xcc\xe1/t\xa3f\xb3\xad`Ϣ(SE3\x95t+Fm\aʉֵ[by\xeb\xbe\vBsn\xd3-\xa3k\x90{A7\xf2ZL\xcd9\xc7\x03\x97\x8e\xb0W\x118\xbe\xb7F(\x8a\x96K\xe9\xe1l\x91a\xb8\xc3\xed\xfa;\xd3&F\x90ɝ\xfe\xcc9\xa1s2\xfb\xf1M(\x1c7\xae.Tx]A%q\x88}\x02'M)K\x1c\x89\f\x9b4\xf70B\x97\x82Ȅ\n\xfejRI7r'g{f\xba\xd8\xc9\xf3\xbc\xe9/f\xe1\x15߶V\xb3.ֲ\x86\xfc\x98\xa3\xee\xacE1I\r\x8a\x1a\xc8\xffz\xf8ed\x02\xf2\xa7(q\xaeA\xf8\xd0W\x9c\x10\x1d\x97V\xf1\x9e)\t\xa5;g \x9c?\xaf\xfbb<\xff\xac\xd2\xf5AX\xc8\\\xb1G\xf2v\b^\x15?q\xeaR\xcfsPf祖U\xac)\xb0\x99\xacI\xce;͜\x8dlt6\x8c\x17\x0eQ\xaa\x91\x8aX\xaao\xae\x1e\xb3\xb7\x83\xb3\xb2d\xa4XE\xcd<|\xcf\xfc\t\x9e\x9fW\x83\xd0ݔE\xcbr*L\xb8\x98\x94t+&o\aډֵ[\xfeP\x96\xb3\xdc\x1c\x97\"^>s\xb5\x8c\xaeA\xee\x05\xdd\xc8+&\x9cgZӬ\xbe\x8a\x00\xf2\xbd5BQ\xfc\x86B\xdff\x17F\"\x03Y\xa6j\xad\x18\x8283\xcb`\x14w\x9eµ\x1dtt\xa2}d\xde\xf1\xe8ŋ'?}\xb6\xe8\t\xf9\xccX\x85\x8ek\x1b\xf1\x80\xa2\xf8L\u007f\xee\xa4\x15Z1#\x97\x81b\xdb/Z1\x18\x15E\x19ݝ\xa7\x10\xb7\x83\x9eN\xb4\xa7\x9dw\xe1\xf4ŊCJ\xcfU蹶\x11\x0f(\x8aϴ\x84\xad2|\xee\xd8xT\x14%0:\xffR\\\x8b\x12Ow\x9a\xa3njD\x06\x04\xa0(\x00\x858\x17\r\f\x86\xbe\f\xf3\x8e\xea\xda\xea\x1d\xe6\f\xb7\xbbq\x02\x13P\x14\x80\x82\xccE3.R\x01^\x188\xb3\xc1j\xb2&\x9f\x05A\xc1\x80\xa2\x00\x00\xa0\x1f\xa0(\x00\x00\xe8\a(\n\x00\x00\xfa\x01\x8a\x02\x00\x80~\x80\xa2\x00\x00\xa0\x1f\xff\x1f\xec\x88D\xdc\xfa\xfa\x88\xfa\x00\x00\x00\x00IEND\xaeB`\x82",
+
+ "analysis/error1.png": "\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x04\xc1\x00\x00\x00\xbd\b\x03\x00\x00\x00\x8d\xa5\x9a\x96\x00\x00\x00\x01sRGB\x00\xae\xce\x1c\xe9\x00\x00\x02\xfdPLTE\x00\x01\x00\x02\x05\x01\n\x03\x01\x05\a\x03\x1e\x01\x00\v\r\n\x10\x12\x0f\x16\x17\x13y\x00\x01\x19\x1b\x18\x1b\x1b\x14\x83\x01\x00\x8c\x00\x00\x8c\x00\x04 \x1f\x19!# #$\"%%\x1e$%#&'%'(&+)\x1e()'++$*,)/,!-/,02/63(241\x98\x1b\x1b786;8,\x82%#:;9><0>?=C@4@B@\xa0*,CEB\x9c.-KH<MH7\x00f\x00\x00g\x00\x00h\x00JKI\x00i\x01\x00j\x02MOL\x04l\x05TO>\tn\aPRP\xa9:<WRA\fo\t\x0fp\vTVT\fr\x17\x11t\x19^YG\xaaDCY[X,`\xae7]\xad\x15v\x1c\\^[\x19y\x1e;b\xac_a^faO>e\xaf*{!bda)}*Bh\xb2egdLj\xafpiR.\x81.Em\xb1ikh\xb3XX0\x8301\x841/\x858Jq\xb5mol;\x86:Vu\xb4>\x89={t\\tvs@\x8b?B\x8c@@\x8dG\\z\xbay{xJ\x8eI^~\xb8\x84|d\xbbkkL\x90K~\u007f}O\x93Mb\x83\xbdN\x95UW\x95V\x82\x84\x81\x8f\x85hm\x87\xbdZ\x98Y[\x9aZ\x87\x89\x86\xc0{|]\x9c\\\\\x9dcr\x8d\u0096\x8cnd\x9dd\x8c\x8e\x8b{\x8f\xc0f\x9fg\x90\x92\x8f~\x93\xc4j\xa3jy\x96Ŕ\x96\x93s\xa4l\xa1\x96xq\xa5s\x81\x99×\x99\x96\x83\x9bť\x9b}u\xaaw\x9a\x9c\x98Ǒ\x92\x9c\x9e\x9b~\xaby\x88\xa0ʞ\xa0\x9d\x81\xad|\xab\xa0\x82\x8e\xa2ǡ\xa3\xa0\xa2\xa4\xa1\x81\xb1\x85\x92\xa5ʋ\xb2\x88\xb4\xa7\x83\xa6\xa8\xa5\x8d\xb5\x8a\x97\xabЩ\xab\xa8\x8e\xb6\x8c\x8d\xb8\x93\xab\xad\xaa\xb9\xad\x88\x9f\xaeή\xb0\xad\x96\xba\x96\x98\xbb\x98\xa3\xb2Ұ\xb2\xaf٨\xa6\x9b\xbe\x9aµ\x90\xb4\xb6\xb3\xa3\xbf\x9d\xac\xb7Ҷ\xb8\xb5\xa2\xc0\xa4\xb7\xb9\xb6۰\xb3\xa5ħ\xba\xbc\xb9\xb1\xbdקƩ\xbd\xbf\xbc\xa8ǫ̿\x99\xafƫ\xb8\xc0տ\xc1\xbe\xb2ɮ\xd0Þ\xc2\xc4\xc1\xbc\xc4\xd9⽾\xc4\xc6òͷ\xbb\u0379\xc0\xc8ݻ\xca\xde\xc7\xc9\xc5\xd8ɝ\xbdϻ\xc6\xca\xda\xc0\xcc\xda\xca\xccɿҾ\xd7ϡ\xcd\xcf\xcc\xc4\xd0\xde\xcb\xcf\xdf\xc8\xd3\xc1\xe0ѥ\xd0\xd2\xce\xc8\xd6\xc9\xea\xcc\xcb\xd1\xd3\xd0\xd2\xd3\xdd\xca\xd8\xcb\xd3\xd5\xd2\xdf֨\xcd\xd6\xde\xcc\xda\xce\xe6֪\xd6\xd8\xd5\xd4\xdb\xd0\xeb\xd4\xd2\xd2\xda\xe3\xd8\xd9\xe3\xeaۯ\xda\xdc\xd9\xd7\xde\xd3\xe1\xdb\xda\xd5\xdf\xda\xdc\xdd\xe7\xdc\xdf\xdb\xd7\xe1\xdc\xde\xe0\xdd\xdc\xe1\xe3\xf0\xe0\xb3\xe0\xe2\xdf\xe2\xe4\xe1\xee\xe1\xe2\xdf\xe5\xe7\xe4\xe6\xe3\xe8\xe5\xea\xe5\xe7\xe4\xf2\xe4\xe5\xe6\xe8\xe5\xe3\xe9\xeb\xe7\xe9\xe6\xe8\xea\xe7\xeb\xed\xea\xf6\xf0\xef\xf2\xf4\xf1\xfe\xf8\xf7\xf9\xfb\xf8\xfe\xff\xfc!l\x99S\x00\x00 \x00IDATx^\xed\x9d\x0fXTם\xf7\xf7\xd9\xd9\xd8w\xd3$C\x03\x9b\x12-K^\xd6fm\xfb\xdc\xe1\x19\xa9\xbe+\f\x8d\x1d\x14\xd7?1+\xbeVQ\x8aV1\x1b1\x18\xe7a\x13\xa3\x82ƄL\n\x19%) B\xe6\x89E\x1eY3*\xbe\">\x19Me\xc1\x96hqm\x12\xe8S\xa6ѱ\xb6\xda\xe4\xf2(\xac\xe4y\xaf\xe7\xed\xa6\xe5y\xcf9\xf7߹ý3(\x03\x97\xd1\xdf\xe7\xd1;\x87;\xbf\xf3\xbb眹\xf7;\xe7\xfc\xee\x99{\xfejh\x14 \x00\x00\x00\xf3\x18\x1a\xfa\xabH*\x15\x8eH\xee\x01\x00\x00\xc6\x10P0\x00\x00b\x17P0\x00\x00b\x17P0\x00\x00b\x17P0\x00\x00b\x17P0\x00\x00b\x173\x15,p\xa0\xaa\xa2\xfa\x18O\x92\u0099\xba\x8a\xba\xceH\x19\x00\x00\x004\x98\xa8`A\xb7\xb7\xb3\xbb\xb3\xae\nK\x98\xe0\xf5\x9c\xee>Yq2R\x16\x00\x00\x00\x16\x13\x15\xac\xcbݍ\xb7\xbc\x1bw\xbd\xceT\\#;*\xf8Hy\x00\x00\x00\x18LT0D\xf5*\xe8\x0e \xe4=@wTB'\f\x00\x80;\xc1L\x05\xc3\xf4wW{\x05\x84\xea|\xf4/\xef\xfe\b\xe6\x00\x00\x00,\xa6*X\xd0\xedv{HO\xecX\xe5\x00\xde\x0ex\xea\"\xe5\x00\x00\x00`0U\xc1P0\xd0^M\"\xf9\xbc\xc7\x1b\xec\x0fx\xddՑ2\x00\x00\x000\x98\xab`\x98\x81\xea&\xbc\xbd\xe6\xc5ݱ\x16\xaf7\x925\x00\x00\x00\x83\x89\n6 З3n\xfa\xda\u007fM@\x95\xc7\xc2f\x00\x00\x00\xd0b\x9e\x82\t\x95b\xf8\xfeL\x05V\xb0A\x92\xea\"\xb7%\x01\x00\x00F\x8cy\n\x86\xaa\xe8\x14\n:\x8a\xect\a\x11\xe2\xab|\x91\xb2\x00\x00\x00\xb0\x98\xa8`]\xee\xa6\xce\xeeN\x1a\xc9\xefr\x9f\xec>S\xe9\x85\t\xad\x00\x00\xdc\x11&*\x18\n4UWԵ\x90y\x14\xe8t\xb5\xc7{Z\x88\x94\x01\x00\x00@\x83\x99\n\x06\x00\x000:@\xc1\x00\x00\x88]@\xc1\x00\x00\x88]@\xc1\x00\x00\x88]@\xc1\x00\x00\x88]@\xc1\x00\x00\x88]@\xc1\x00\x00\x88]@\xc1\x00\x00\x88]@\xc1\x00\x00\x88]@\xc1\x00\x00\x88]@\xc1\x00\x00\x88]@\xc1\x00\x00\x88]@\xc1\x00\x00\x88]bK\xc1\\.\xbd$\x00\x00\xf7+&+X\xbb[z4~\xc0\xeb9\x10\xf1\t\xad\x1fs;u\x92\x84z\x8e\xe3\xcaQ9\xde\xd6\x0fϦ\xd0k\xe3\x16\xe1\x17\x176K\xeb\tc\xa7\xe5\xb8\xe3p\x98w\xef\xd0\xd9\xe8\xc0\a\xab\xc1/5\x1c\xc7\xea\xf7\x8b\x1cר\xfcq\xeeG\x8eY+[\x97|0,\xafH-k\x1b\x81\x17Gd{w\x8d\xfaً\x0e\xfb\x8f\xa2\xf28%\xed\x81\xc3\u007fX\xe3\xc3D(\xc3\xfd\x83\xb9\n\xc6W\x1c\xab\xa4\x89\xee\n_\x97\xaf\xa2;\x82y\x91\xfd\x8aN\x92\xc0\xbf\xcb\xed\xbe\x8e\xae\xbfŽ\x1b\xf6)\x89\x1d.;\xde^\xf2\xfbk9\xa3K|8\xcdi\xe1\xae\xe3;t\xa6\xd2z6\x92\xc5p.\xa5\xbdՇ_\xfaޚq\x89\xd9{\xc5o+\x97\xd3gm\x05\x87\x1a\x9f3\x96\x9e>\xff\xf2r\xa4\x87NqX\xbfa\xb8\xabF\xcdsԺ\xd2\xfa\"Y\x8d\x04\xed\x81\xc3\u007fXw\xd7\xea#\x81\xf5\x1b\xa9\f@41W\xc1\xbcM\xddT\xc1\x84*\xb2\xc6DZ\xaa\xf0_\xca=\\\x89NR\xe4\x02w\x1co[\xb9\v(,\xe5v\xf1\xb5\xe3\x0e.6\x14\xa9\xabpG\xce\x14~P\x18\xc9B\x87%b\x17\xb3~\x89v\xb7]Q\x9a\xd5yd\xeb\n\xd3y*\xd0W%\xdd\xe2\xd8G\xa2`wӨ}\xb8/)\xf4G\xb2\x1a)\xec\x81#|Xw\xd5\xea#@\xe37\xd2\t\x03D\x11S\x15\xac\xdd\xc3\a\xa8\x82uV\x90\xb3\x99\xaf\xe8\fk\xeeR\xfb].m\x17ll\x15,\x12w\xe7l\xd9\xdd\\K\x85e\xf4\xa5,$\xaf\xaa4s\xa9\xc19\xee\x102\xc2@\xc1t\x8b3f\n\xd6\xc3Es\xa0u\a\a\xbe\xabV\x1f\x01c\xe5\x17\x88\x84\x99\n\xc6Wt!Q\xc1\x9a\xf6\xd3\x1d\xfb\xc3.\xf5\xd1k۪\x93\x94`\x14\x8c/̴e\x15\x9c\xc3\u007f\xbe\xc4\xd9\xeaK\x16\xa4\xad\xa6C\xae+E\x99酮a\x17[\xe3ʴ\x05%X?\xcf\xd98\xae\xac\xa7h\xae}\x8d\xe6\x1b\xb4/\x8d\x13\x87d\x82\xc3\xf6jVf\xeb\xd6Yy<\xf1[\xe3\xcaJ/\xe81p\xc6\xda2\x87`\x8as\x98\x13YF\xde\xf7\xafβ9~\x94\x854\xa8\xb5`\xd9)^(\x85;Y\xbfXi\xb6\xba2\xc5\xe2\x14fR\ro\xa6\xbbk\x97\xa5-\xa9\x153\xf6\x14:\xf01\x88\xecc\x05ۊ\x8fl\xff\x8c\xf1\xa0)\x0e\x83\xbdDn\xbeh6\xea\xa0C<\x9a؍\x96\vi\xf0\x01\xe8\xb7\x03[!\xf5\xc0ʇE\x88\xd4\xea\x06\xce\xe4\xe20\xd945fZ]\xc9\xc6\xfaՔA\xc7\x19\x10e\xccT0o\x13\x92\x14\xacN\\(\xf2X]8s\x97\xed\x92NR\xe2\x02\xd7<00\xd0L\x14\xac\x99s\xb56\x16p\x1d\b}\xdch\xe3\x1c\xe553\xc8e\xdf3kA\xfd\xe1\xd5\\\xe8\xc5\xe6\xe2\xb66\xd78\x96\th\xa0\xb11k\xc1\x8c\xac\x92\"\xaeW\xe3\xf8\xac\xdf/\xf6DZgq%y\x9cc\xb7\xa3\x86\xfa\xcd\xda]\x9e\x95v\xc1\xc0\x19c\xcb\xece\x8a\xc3\u007f\xe0_\x90\xe7\xf7\xfb\x89\xe8\x9c\xe5\x8a\x1a\x8f\xd7;8\xed\xd8C\xad\x05K\xfd\x0fPG\xd6\ahY=\xeb\x17+\r\xb7\xac\xb1q\t)No\x16\xb7\xa6\xbccP,\x8e\xbd\xac\xb9\xcc^D\x92\xadi\xcb\xde:^No\x03`\x05\xbbR\xc4\xd5t\xb0\x1e\xd8\xe2\xb0عE\x8d\x87\x1d\xa4\xf9\xa2ڨ\xe7\xfc\x8d\\\xb9\xdfO\x15C)\xa4\x81\xad~;\xb0\x15b\x0e\xac|X\x91[\xdd\xc0\x99R\x1c&\x1b[c\xb6Օl\x1a\xbfl\x19t\x9c\x01Q\xc6D\x05\xeb\xf4\xf0\xb2\x82U\x9e\xa4{NV\x861ﵽ\xa8\x93\x94\xb9 }\r⋸\xbf\x91|C.y\x8e춧c\xa9+r\xe0\xd4\xca\x05x\xaf\xb0$\xe4bk\xe6ޥ\u007f\xd1/\xcde\x1c\xe93\r\xbf\x15 \x9d\x90\x99E\xd8\xfc\xb08\x8d\xc3>\x17\x9b\xf5e-7r\xc6ز\x87P\x8bÌ;j\x1d\xe4r\xa8\x9d\xa5U0\xb6\x16*~\a\xdai+A\x0e\u007f\x88\xdfE\x03X\x02\x16,\xc7ɾ\xdd\xcbm\\:\xd9y\x9cvK\x8fs\xcd\xf8\xad\xac5\xd8`\xb0\x91\x84α\x82\xd5؛\x893m\xe5uG\x91\x0e\xdcSs\x91\xf2F\xb9Q\x95Q$SH}[\xfdv`+\xa4\x1dEJ\x1fV\xc4Vg`\x9c\xb1\xc5a\xb2\xa9IƯ\xa6\f\x1a\xbfR\x19\f\x9c\x01Q\xc5<\x05\xe3+:\x05A\xe8\xae\x14\xf0\x95['\x0e\x1f}\xe1\xfa`/\xd9zu\x922\x17p\xaf\xa2\xa3\xa3\x86\xc6\xc1>\xab]3w\x16G\x83\xddv\"7$N\xd3'N\xb3(\v\xb9\xd8\n\xe7\x0e\xe2B\bYtr\xc22\xfb0\xb7\x14Y\xc1\x1aq6\x1e\xed|\x9e\xec\xa2øZ\x8e\x9e\xbd:\xce\x18[\xf6\x10Jq\x10s\xce_ʜ\xfbR\xfd9a\x10iaj\xa1\xd2\xcb\xf5\xe7\x15\xad\xec'\xdd\x14\x8d\xdfWɛRq\xd0@\xeb\x1arո\x16ѿ\x16Q\x15U\x87a\x05\xe5e\x92|h+\xaf\xab`jy\xa3ۨ\x8a\x821\x854\xb0\xd5m\a\xb6B\xba\n\x16\xb1\xd5\x19\x18glq\x98lj\x92\xf1\xab)\x83\x9e\x82\x198\x03\xa2\x8ay\nv\xd1-\x13@M\xe2\xac02\xac4\xe2\n=\aB\x93\nL\x1c\xacÑ\xb5\xf3\x90?O\xbc\xd8ȹDN\x9c\xb3\x9c\x1f\xa1\xe1A\xe7%R\u05cd~\xc5/\x1b\x16\x1f\x11\x91\x15\xec8\xea\xb0!I\xc1\xe8.?G\xef\xa1\xeb8cl\xd9C(\xc5A\xec9\xdfW_\xb8\b\x0f9\x91\x06\xb6\x16*\x82\xfdBڹ\xb4\v6A\xc7/-N\a\x1d\x9a\t+\vp\a\xa9\x80f)XN&\x90\r(.\n\x1c3\x16\x89\x87\xd6V\xde0\x92O\xcb\x1b\xe5FU\x14\x8c)\xa4\xbe\xad~;\xb0\x15\xd2U\xb0ȭ\xae\xc28c\x8b\xc3dS\x93\x8c_M\x19\xf4\x14\xcc\xc0\x19\x10U\xccS0!Hh\xf7\x04\x83\x02\xeat\x93\xa1\x03\xef\x0es/r+ף\x93T`\x14l\xd1r2\xee(\xd4^l\x9fq\xb5\xe4\xefРs\xd1ܳ\x14\x12\xd66\xbc\x9f\xc4(\x98]V0z'\xa1\x9e\xa3#\x1e\x1dg\x8c-{\x88a\xd7R}/\xd6\x01ҟ\xebk\xb4\xd7j\x0e\xcaւa\xc1[\x99(\xabf\x01\n\xf1K\x83\xe2\xa48\x99/Q\xb32l\xe1\x9aK\x93s]\xa4]\x98>\x98\xe3B\xef,\x1a?\x1a^yR\x1c\x16\xb5\xbcQnT\xb5\x0f\xa6\x16R\xdfV\xbf\x1dZ#\xf5\xc1\"\xb6:\x03\xe3\x8c-\x8e\xae\x821~[\x87\xf5\xc1d\xbfr\x1fL\xdf\x19\x10U\xccS0\x91\x804\x1f\x8c\f#}a\xe6\x83E肱\n\x96EN&a\x89\xf6bC˳\xf0\x10\xab\xc7\x1er\xb1\x1d\x17\x835e\xb4\x03t'\n\xe6\xc0\xd7\x15?\x97N\xbe\xd2s\xc6ز\x87`\xcf\xe3<\x9c\xf9\ny\xaf\x9c\x16\x1d\xe5ic{l-\x18֬|\x0e\x15\xae\\\x8dB\xfcf\x91\x88\xcc\"\xec\xd1A\xaa\x89\x04R\x95fj\xd0H\x06\x94\xfd\x99y\x838\xbd\x95\xe8.\x99M\xd1l\xeb\b\xf1\xa0\x16\x87E-o\x94\x1bUQ0\xa6\x90\xfa\xb6\xfa\xed\xc0VHW\xc1\"\xb6\xba\xbe3\xb68\xba\n\xc6\xf8ՔA\xe3W*\x83\x813\x84zw\x8f\xfc\xc7\v@\x04\xccU0!\xd0\xee\t\\CtN\xfeŰs\xf2K\xd4~W\x89N\x17\x8c\x9d\x93_\xce\x15\xd6\xee^\xc69\xde\xea\xb8ⷹ:\xd0Y\x97\xcd\u007f\x05]H\xcb*/K\xe7l\xef^\x10gq\xd7\xf8\xfd\xbd8\xe3N\xee\xf9\xc6Cd\x02\xa8\xd0A\xef'\xf5\x868\x1e\xfc\xc0ﷻ\xfc~\x1e]H\xaf\xe9o\xb4\x9d\xeb\u007f>\xef\x12\xa27\xff\xea\x17\xa4\xf7 }g\x1a[e/[\x1cr:\xd7\x1c\xcaK\xbbD\x14,\xad\xac\x19\x1b\xb4j\x0e\xac\xd6B\xb3{+\xb7\x1b\xbd\xc5ыF\xf1K\x8a\xb3\xa6\xa3u%)\x8e\x83\xcb,;\x8e\xfd\x92&*\xe2v6\xef\xe4\xc4{\x91\xf6E\xb5\xcd[\xb9z2'\xdf\xf5\xc1`\u007fAf\xebu\x8d\a\xb58*ly\xa3ڨ\xe2\xbd\xc8\x0e\xfa}\xa5\x14\xd2\xc0֠\x1d\x94\n\xb1\aV?\xacȭ\xae\xefL-\x0e\x93M\xe3\x81i3&\x9b\xea\x97-\x83\x9e3b\\\xc0\xfd\b\x01Q\xc2\\\x05\v\x900X\x15M\x1d\xa8\xf0\x86\xf9]\xe4\xf5\xb4\"\x9d\xa4\n\xfb\xbbH\xa1f\x81\xddQX\xbf\xc0\x96\xf7\"\xfe\xdbv\x81L\xd0\xc1\xfd\x9b\x9e\x82\xf4\xb9%\xef\xdap\xd2%\xc52\xe87\xfe\xf1<G\xfa\xcaf2\t\x94R\x10\xe2\xf8\xacd[/88\xaeq\x06\x97\xd6Hc \xf6\x12\u05ec\xcc\"r:\xea9\xd3\xda*\x87\xd0\x14\a\rlM\xb7\xe7\x91˲qey\x96-3O+`L-4\xbb\x9b\xd3\xcea\xdd\x10;0\xb2_<\xd4*/\x9c!\x16gy}٢4\x878SM\xa8Y\x92\xb6\xa4V\xec\xd7\xf6\x14f\xcdX~\x88\xfe.\x92\xe3\xce\xe2\x82qe\x1a\x0fjqT\xd8\xf2F\xb3Q\afѽ6m!\r>\x00\x83vP*\xc4\x1eX\xf9\xb0\x88A\x84V\xd7w\xa6\x16\x87ɦ\xf5\xc0\xb4\x99\x9aM\xf5˖A\xcf\x191\xaew\x84\xfb\xf5.pG\x98\xab`#\xe6U\xeec\x9d\xa4yH\xe3\x04\x00\x00\xcc%F\x14l\xa2=V\a\x14\f\x00&\x041\xa2`\x13\rP0\x00\x98\x10\x80\x82\xdd\x05b`V\xe6\xcdo=\xc4\xf2\xad7\xc3\xe4\x04\x00 \xaa\x80\x82\xdd\x0540\xdb+\xa6\xff\xa8\xd5/\xaaa\u007f\f\x9b\x1b\x00\x80\xa8\x01\n6J\x86\v\x18\x96\xb0H\x99\x00\x00\x88\x0e\xa0`\xa3\xe3M\x1d\x01{\xe8!\x18H\x02\xc0\xf8\x00\n6:\xf4\xba`\xd0\t\x03\x80\xf1\x02\x14lt\xe8\n\xd8C\x0fE\xca\x06\x00@T\x00\x05\x1b\x1d\xa0`\x00`&\xa0`\xa3\x03\x14\f\x00\xcc\x04\x14lt\x80\x82\x01\x80\x99\x80\x82\x8d\x0eP0\x000\x13P\xb0\xd1qo)\x98wf0\x92ɸsm\xa67\x92\tp\x1fc\xb2\x82\xb5\xbb\x95\xd3\xd3\x17~\xb1\xc8\x11\xe3\xb1Z\xadŨ\x18o+\xc2X]\x8c\xb7N\xc3/\xb9\xd8,\xb1+\x8c]$\"+X\xbe5\xae\xda0{\b\xbb\xacqU\x91ldƠ\x9e۰\xc3\xc848\x9dG\xc2\x1a\x1ct:\x9d{\xd1^\xbc=\x18\xc6\xea\xd3l\xe7*\xfc\xf2\n6\x9b\xffi\x18;\xb4-n[\xb8\xb7\x81\xfb\x1bs\x15\x8c\xaf8&/O\x14t\x9f\fk:bx\x8fu[\x10\x05\xb7Y=\xc3W\x1dbh\xc9M\xc0\xdbn\x9fo\x97\xb5%\x9c]\x04\"+X\xc0\x17?\x12]\xa0\xf0G\xa7\xeb\xdb\xfaN\x0f\xdb\x15\xfdz\xee\x8a\xf3D\xb0\xa0\xdch[\xbfW\xf7\x8d\xb6\xf3\x92\xc1A\xe7\xde\xcf\xd1\xe7\xef8\x0f\xdeе\x13\xb9\xfd\xf3W\xb2\xf1\xcb\xef\xdb\xda\x1a\x9c?\x0fc\x87{\x86\x8f\x96\x86}\x1f\xb8\x9f1W\xc1\xbcMݒ\x82\x05\xaa\xa3\xa5`\xa8\xddz\x00o}\xd6\xf6\xf0f\xc5\t\xe2kK\xc4+;\x1c\x91\x15\f\xa1\x84\x11+\x18B\xf3\xf4m\xa7/\x1e\xbe/\xda\xf5\xbc\x18\xbf!\xbc\x81\xc2f}\x05[\xbfEJ|\xe4<\x85\xb7mΏt\xcd\x14\xf6f\x8b\xaf\xe7#(\x18ڔ\x10\xe6\xe9\xbd\xc0\xfd\x8d\xa9\n\xd6\xee\xe1\xc5\xe7\xe4#\x9f\xdbW\x11\xc3\n\xf6\xbf\u007f\xf7_\xff\xf5\xeb\u007f\xfc_x\xfb\xbb\xa7\xc6D\xc1R\xc7A\xc1r\x93\xc3v\xe6\x18\f\x14l\xed\x16)\x11m\x05\xe3\x93s\xc3\x1b\x00\xf7/f*\x18_\xd1%\xad\xf4\x81\xfayy\xd5[]\xaa\x95\x98O5\xe2\x17'ǧ\xcc;\x83\xf7\x9ey\xd4j\xddԵtj\xe2\x9cA֘\xb9\xb2U\xdb|k\xbc{ݴ\xc4\xd9\xf4\xcb<\xb04y\xca\xc2\xdcaWv\xe5\xcc\xc4i\xebx#\xbfݓ\xad\"\x93\xd9\x0e\x81\xa8`o\x92\xb6x\xea_\xc9\xf6_e\x05\x93\xbda\x05\xcb\xcfM\x9e2\x8fF\xa1\x8e\xceN\x89O\x9a\x93B\xb3\xeeJML\xdd%z\xe9Z\x98\x14\x9f<\x87<e\x1b+X>>\xc6cAƃW:p*\xd2\x10\xe5z\x0eL\x96\xbb`m\x9bWd?\xb3y\xc5m\x9c\xbcݰ~\xfeچ\xdbt\xf7\xa7[\x9e\xc9\xce\xd9\xfc{D\x15\xecu\xa7ә\x8d\a\x89\xb7\x0f\xae\x9f\xbf\xea\x8d[\b\x9dp\x8a\xacG\x1a\x05\xbb\xb1%'{\xc5f\"e\xaf8\xb3\x0f\xbe\xb1j>u\x80~\xbf=\xe7\xe9-\xaf\x84*\x98\xe2\xec\xa3l\xa7sϧ\xdbWdo\xfe\x82\xbe\xb1)\xb1\x1f\x01\x80\x1ef*\x18Y\x1e2\xa0,\xd3\x1dN\xc1\xf8\xa3\x937\x05QpӔ\xa3<\xbe\x9es}\xd5\xf3\xe2\xf0\xe5\xd8_]\x95\xf2\xe4\xe4\x94uK\xad\x9aAF\xbb\xd5\xdb\xdf\u07ff\x9f\\٪mgգ֤\xe2\xd2\xc9\v\xb1A\xd7\xe4i\x1e\xeflk蕝\x1b\x97\xef-MJ\x15\f\xfc\x0exJE<\xecR\x85\xa2\x82=\xfc\xe6\xd0\u007f\xfc\xe3C\x0f\u007f\xeb\xd7C\xff\xf6\xb0\xa4`\x8a7\xac`\xd6Ԫ\xaa\xd4D\\\x9e\x93֥\xd5M\xee$+Q\x8c܄M\xdeM\tK\x89\x13_b궦b+\x89\xf6`\x05\v,\x8d+ma\xcb\xc3\x1f\xf3=\x99\xe1\xf3\x85\xde\xea\x88r=O[}\xe2\xfb\xbf\xfc\xfe\xf6#\xa7\x0e>\xe3$\xe2\xb1#{ϩ=\xd9\xdb\xc9\xee\xb6\xf9\xeb\xdf9\xb5\xd7ـ\xa8\x82\xfd~\xbb\xb3\x81\x84\xbdv8_?Ր\xb3\xf66\xba\xd1ֶjc[[\xdbo\x10U\xb0[\xb7n\x9d\"\nv¹\xa3\xed\xc8f'6\xfd\xe8H\xb63g\xef;\xf3\xb7`\x83O\xe7\xaf:xb\xb33T\xc1\x14g\xb7\x8e\x1cY\xb1j~\xce\x1bۿ\u007f\x95\xbeq,R\xff\x11\xb8o1Q\xc1:I\bzd\n\x86/;2\x8cZL\x06\x13|5\xe9ؤ.\xa4\xbbS\xad\xb3\xf9\xd0u\xeaۥ.K\xbb\xd66a\n\xbeN\x97&\xe1T\xc6T\xbcWH\r\xb9\xb2\xbdV\x0f\xfd\xab\xca\xc8o\xf0\xa2\x88f\u0081\x14\xf7zj\xe8\xd7\x0f}\xeb[\x0f\xfdߡ\u007f\x94\xe2`\xac\xb7\x84i\xb8\a\xd1?u&\xeev%\x11\xed\xda5\x05\xeb\xda\x01ڃ:`ݏ\xdfJ\x99\x83Eq\xa0\x9a,ڄ\x15l[\x82wxytG\x91Q\xad\xa7\xd7zQ4l\xc8!\xda\xd5\xf04\xeey\x9d\xa2\x9d)\xba\xbd\xb5b3\xee\x1c\xdd>B\x82\xf3X\xc1\x1a\xb2O\x10\xdb\x13\xf4v\xe3y\xf1\xe6$3\x8a\x14\xc1\nv\x8bd\xb8-\xbe\x93\xfd4\xee\u007fm\xcf\xc1\xa9\x8d\xab\x88\xaf\xb5!\n\xa6u\xe6\xdcx\x03ݖn\x05t[G|;\x17\xb8\xcf0O\xc1\xf8\x8aNA\x10\xba+\x05i\x91\xc8\xf0\n\xe6K\xe4\x11\x9fH{\t\xc1]s\xa6N\x96\x86T\xa9:1\xdevkiKKK)\x8d\x0f1\xb6\tD\xfeHP\x88\xb7\xba\xc9ߛB\xae\xec\xc5S\a\x061)\xb9\x06~/Ze\x86\x8f\"\x1f\xfa\xfb\xa1??\xf5硧\x86\xfe\xfc\xb0\xa4`\xac\xb7\x04:<s[\xaf\xa1\xee\xe4\xa9\xf9\xee3\x02\xe9\xc4\xe5N\xa3\xf9\xa7a\x83\xfd\xd63\x8a\xbfyś\xac\xe2\x04\x13myt\x15,\xaa\xf5\xac\x93\x15\xecjΊ\xd7\x0f\xfe\xea6\x19:\xeeXK\xf7\xacz\x85\xc8دdK\xac`?qR\x01C\xdbW\xdc\xfe\x02\x93\xb3\x83\xfc\xc1(\xd8;\xe7ϟo\xa0q\xb0\x1b\r\x9bW\xccwR?\xd9Ċ\x04\xbfn\x88\xd3,\xf6\x84(\x98\xd6Y\xf6U\xa4\xd0m\x1d\xf1$\x13\xe0>\xc3<\x05\xbb\xe8\x96\x11WY\v\xaf`\x83Iu\xa8.\x89\x88]Krʆ:_\x86\xa4`Ӈ\x9b2\xf1!֖\xc6\xd3ɕ}R\x1c.\x85F\xb8S%}Zh\xe4\xd7\xe7\x15\xf1\xb1;%\x05{过\xfech\xe8\xd7C\xbf\x93\xfe\xd4x\x13#\xf9>\xebi\xb2,\xf9\xe2i\xd6$2\xbfi\xe6<\x9a\u007f\x0e>P\xa9U\x8d\xf2\xccK\x9e<M\xee^\xb2\xe5\t\x1fɏF=\xd58ٍ\x83[V9\x9fy\aK\xd8\xc6\xcdt\xc7\xe6\xf5d\x16\xd8-\xc5ts\xce\xfcU[hpl\xad\xd4ۢvz\x91\xfc\xf39+\xf6\x9ch\xdb(*\x18\xb9\x01@\x14켳\r\xa1\xe1\x91|\xad\xb3\xf5H\xa5\xc5z\f\x01\x80\x1e\xe6)\x98\x10$\xb4{\x82A\xb1\x13\x16^\xc1P\xfeB\xb40\x9f$\xa6\xcd$\x83\x9e\x85\x92\x82-\x1cn\xc9\\٬\xadre_\xb3\xd2\xf8yh\x84{\xe9\xd4Ӕ\xa0\x91_]d\x05\xfb\x0f\xb1=\xfe]V0\xd6[\xc2:bYa\xe5\xd1I\xd2\x1b\xe3\xab\x12q\x01r\xa7\xd2\xfcSqW\xa8ɪ\xce\xf6\x9a\x97\xd4~q2\x9d\xfe\xa4-\x0fQ\xb0\x90\x15\x81\xa3\\O^\xbeez~\x0f\x16\xa7\x1bG\xb2\x1bp\x1fL\f\xe7\xaf\xd8A\xfa`\xe7\x15\xd3\xcd9\x1f}:\x9f\x04\xc4p\xb7\xe9<\x85\x8e\xf6\xa8\x82\x1d\xbc\xaaQ\xb0U\xeb\x89\xf0m\xd1*\xd8\x1fi4\r\xed\x18\xd6\a\vu&S\x1c?\xd2ۤ\xc0\xfd\x86y\n&2\xd28\x18jI\b$\xd0K0\x85\\tB\xaa\xa4`\xe1\xfb&\xac\xadre\xa3\xe9)\xd7\x10\xeaz,\xe4\xca> \xc6Z6\xd1\t\xe0z~u\x91\x15\xec͡\xa1?\xffyh\xe8\xdfd\x05c\xbd%\xa4\x900״\f|xZ4\x94\x91O\xc2Nd`TE\x86\x8c|r\x06\x19W\xe6\x13\xa1#\xb3)\xf6Ǔ\x12iʓ\x813\a\xa5`P\xf76q\xb8\x17\xedz.\x9e*~\x95\xec\xa5\xfa\x836ҡ#\x89I\x1d!;n\xe4l$j\xf6\xfa\x1bH\x9cMq*\x9b(\x9ah\x80\xf6\xd0\xe9\x15\x1b7\"\xf49\xd9\xc1(؊-\x88D\xbc\xb4\n\x86֯\xc0*\xf5\x9b\xec\x10\x05\xd38c\x15L\x986\a\x01\x80.\xe6*\x98\x10h\xf7\x04H\x00\xbb?\x10\xf0\xf8\x02\xe1~\x94'$\xcfN\xa6WX\xb1u\xf1\xaem\xa9x(\xd62\xd8B\xef\xd1]\xd4\x1a\xb2s\xd5Uۀ/>\xb7\x05\x9d\u038d\xf7\x05P{bJ\xf1\xa6)q\x8fz:Ź\xea\xa5>\x1f\xe9\xddl\xb0.\xae\xf6\xe6Z+\x91\xbe_}d\x05\xfbס\xa1\xff\xf3\xefCCO\xc9\n\xa6z#\xf7\"\xe7\xb44͜r\x91\x94=\xb1\xd8[\x97K\x87wK\xe36x7ĉ\xf7\"\x1f\x9b\xe6ޟo\xad s\xf2s[\x06\xf89ɾ\xa0\xc6\x03V\xa4Һىb\x1fl\x9e\x95^\xcfQ\xafgW\x9c8\xf5}\xafs\xfe\xde\x13'vБ\xdev\xe7\x9e\x13{\x9c\xe2\xbd\xc8\xecU\r\xa7^w\x1e$s\xf2_\xf9\xf9\xed\x1b\x9bs\xda>\xc7r\xf3\xfd\xedG\xb0-\x95\x9e\xbd\xd9\r'6ο\xaa\x99\x93\xbf\u05f9\xa5a\xefZ<&\xfd\xf9նl\x9c헯d\xb7]E\x1f\xcd\xcfٻ\xe7ig\xf6\xc1\x8f\xd0U2'\xbf\xa1\xad\x8dD\xbd\x14g_\xfc\x82\xdeؔ\u007flT\xcatR\x01@\x83\xb9\n\x16 a0\xd2\x179)F\xc4\u008d\x15J\x13\xc4\vL(}2!i\xb1gj|ƙ8\x1a\xd0\t\xf9~V\u007f/\xe8fl\xc9$\xab\xf8\xf6D\xbc\xc5\xfd\x9f\xaeyS\xa6\xae\xf3<\x8a\x93\xb9RP\x88vE\x0ed$M\xc9؏\x90\xbe_}d\x05\xfb\xfb\xff\xfa吏\xfa\xef\xdf=\xac(\x98\xe2\r\x8f\xf1\x8a\x17ON^J\xa2}\x95\x19\xc5)\xf1\xc9\x194>%\xd0\xf9`b\xb7\xa7kq\xca\xe4\xe9u\xe4w\x91Vk\xdc\xc9*\xbcݤ\xf1\x80\x06\xf2\xa7$fHq*O\x12\x8d\xd0G\xbf\x9e\x9b\x1e\xa3Ѧ\x83\x1b\xf7\xae\xc8\xce\xd9HCU\xb7\x1b\xd6*\xf3\xc1~\xb3%g\xfe\xfa\x13\xf4w\x91N\xe7/\x8f\xe0\xcdO\xf0\xdeS\x1b\x9fyz#\xed\xb4\xa1[\xaf?\x9d\xbd\xf1\xbc\xf6w\x91\xb7\x1bVe\xe7l?\xb8*{#\xf9\x01d\xf6\xaf\xe6\xe3-\xee\xdc}\xba\xf9\xe9\x15{\x0ef\xe3\xe4\x0e)\xf8\xb5\x051\xce>b\x02b\b\x1dM\\\x87\x00@\x1fs\x15,\xf6yH\x9fH\xd9&&\xeb\xe2'⤅\xaa\xf8\\͌e\x00`\x00\x05\x1b\x1d\xf7\x94\x82\xa1Ҕ\t\xf8t\x9ddx4\x05`\f(\xd8\xe8\x10\x05\x8bi\x91\x98V0\x00\x885@\xc1F\a(\x18\x00\x98\t(\xd8\xe8\x18>\x80\xfc\xeaà`\x000^\x80\x82\x8d\x8ea+\xde>\xfc7\xff\xe3aX\xf1\x16\x00\xc6\tP\xb0\xd1\xf1o\x0f\x85\xf0\xb0\x05K؛\x91\xb2\x01\x00\x10\x15@\xc1FIh'\xec\xab\x16\xcb\xdf\xfcO\xf8\r\f\x00\x8c\x0f\xa0`\xa3\xe4\x8f!\x12\xf6UK\xee_O\xe9\x04\t\x03\x80q\x01\x14lԼ\xa9Ѱ\xafZ\xeaNZ\x92;ᙢ\x000\x1e\x80\x82E\x19\xdeR=t\xcc2\xb5\v$\f\x00\xc6\x01P\xb0(C\x14l\xe8\x80e\xdaE\xf6Y\xd4\x00\x00\x8c\r\xa0`Q\x86\xb7T\xfdeh\xa8\xce2\x1d$\f\x00\xc6\x1eP\xb0(\xc3[*\xb1\x82\rUZ2\xbaA\xc2\x00`\xac1Y\xc1\xda\xdd\xe2C\xe1y_u\x85\xf7̽\xf0\b\x02\xde\xe2\xf9\x92H\xd8.\xcbl\x900\x00\x18k\xccU0\xbe\xe2\x18}\x80\x1f\xef\xf1\xb6w\x9f\xf4\xd4\xdd\x03\x12&+\xd8\xd06\xcbB\x900\x00\x18c\xccU0oS7U\xb0\xa6j\xf2\xa4\xbfkQ[\xb6\xdbDxKŗ\xa2\x84m\xb2,\x05\t\x03\x80\xb1\xc5T\x05k\xf7\xf0\xe2s\xf2\xeb\xc4'\xeb\xf9\xbca\xcdc\x02\xde\xe2\xfe\x93\xa8`C\xeb,\xf9\x01\x900\x00\x18K\xccT0\xbe\xa2KZ\xe9# >\x01\xfe\xd8D|D\xe8\x1d\xc2[v\xfd\xe9\xcb/\xc5\xd6ɵ\xac\x03\t\x03\x80\xb1\xc4L\x05\xf36\xb1k\x15!$Ti\x96b\x8cM\xb0\x82\xfd?\xb9\x136\xb4в!x\x0f\xc4\xf6\x00`\xc2b\xa2\x82uzx\xad\x82\x1d\xf3\\3\xb6\x8e\x15xK\xa9@:a\u007f9v\xf4\xe8Q\xdfc\x96b\x900\x00\x18;\xccS0\xbe\xa2S\x10\x84\xeeJA\x90v\xb4\xb8\xb5+\xba\xc6&X\xc1\x06i',\xc5\"R\xca\v\b\x00\x80\xb1\xc1<\x05\xbb\xe8\x96!됡A\x9f\xbb3R\x96X\x00+X?\xfaSŗCM\x969\x9b\xb6m+u7\x05A\xc1\x00`\xac0O\xc1\x84 \xa1\xdd\x13\xa4W8\xef\xad\fD\xca\x11\x13\xf0\x96m\xfc`\xb1e\xdb_\x86\xe2\xa7\xec\xef\xbcx\xb1;8`\xb9\xe7\x88\xd4\b\x000^\x98\xa7`\"R\x1c\xecZU\x1d\x8fE\xed\x1ex\xa0\x03Q\xb0u\x96I\u007f\xfb\xe5P\x95eW`\x00\x0f\x94\x91\xe5\xe6=\x06(\x180a0W\xc1\x84@\xbb'p\r\xa1\ue2aa\xee@ po̦ؖk\x99\xb6\xc1\xb2\xeb/\u007f\xf9\xdb'\xdb\xe9\\\nP0\x00\x18+\xccU\xb0\x00\t\x83U!\xb4_\x8a\x88\xdd\x133Z\x13-\xa9\x9e\x96i\xd6/\x87\xb6Y\xaa\xe9\b\x19\x14\f\x00\xc6\ns\x15\xec\x1e\x84\xb7X\xa6W\xb6_k\xb2x\xfe\xf2\xa5e\xe1E2\x95\x02\x14\f\x00\xc6\nP\xb0(\xc3[\xe6Uw\xf2\x02?\xcd\xfa'ޒ\xd1I\x86\x91a\x14L\xef\xad\b\x82\x17E=\x8c\xecJ\xdf\x02\x14\f\x980\x80\x82E\x19~\xd3Q,`h\xe0\xc0\x03\x93,_)\xee\xba\xd7\x14\x8c\xee\x00\x05\x03&\f\xa0`Qf\xe0Z\xb0_\x9c\x1e2}v\xe9\xb1k\x11\xe2`\xa0`\x000*@\xc1\xa2\x8d\xf4\x1b\x03\x81\xbf\xd8\xdeu\x8d\xfe\xa2\xc8\"+\x01I\xbc\xf6\xb8e\xd2w?\xc1\u007f\xbc\xfc\xc8_?\xf2\x02\xd9\xff\xe3\xaf[\x1e\xf9\xe1\x1fH\xe2q˃/S\xab\xf7\xbf3\xe9\x81\xef`#˳\x0fZ\x18\x03%\xcbMƑb\xfb\xc2#\x96\xaf\xff\xf4\xe5G,O\xfc\x8cu*\xf1\xb3Ix\xf3]\xfc\u007f҇\xea\x9b8\xcb_?\x82\x8fH|X\x1e\u007f\r'Ȏ\x17nj\xcar\xf3\xa7_yA\xc9Bg\x83\x81\x82\x01\x13\aP\xb0\xb1B\x18\x18\x18\x10\xc5L\xa3`_\xdbw\xf9\xc3\xefb)y\xfb\xc1}\x97\xf7\x11}\xfa\xe9\xdf\xfd\xf4\xf2\xfb\xdf\xfc!\xde\xf3\x95\xb7/\xbf\xffO\xd4\xea\xef\xf6]\xfe\xed?\u007f\x0f'\x9f\xf8\x905\x90\xb3P_\xb2#\xd5\xf6\xfd\xcb\xff\xf2\x00\xd9|\x93ɣ\xf4\xa2\xbe\xf6\xde͟Y>\xbc\xf9\xdeט7-\xd4\xe1\xdb7o>\xfe\xec'\u007f\xf8鷱N=\xb8\xef\xb7\xfb\x1e\xfc\xb1\xa6,x\x1f\x9b\x85\x1e;B\xd5\x01`\xdc\x00\x05\x1b{4\n\xf6\x1e~\xfdO\xdc!z\xe2Ǥ\xa7\x83\xf7\xfc\x03\xd9\xf3\xe1#7o~㵛\xb2\x15\xe1\xb7\x0fJ֊\x81\x92\x85ZɎ\x14\xdb\xf7o\xde\xfc\x84n\x1e`\xf2(\n\xf6\xcf\xcf\xde|\xd6\xf2\xf2\xcd\x1f\xfe3\xf3\xa6\x85:|\xe2\xe6\xcd\a>\x14\x8d\xbeAw|\x83-\xcb\v_\u007f\x9f-\x03(\x180\xb1\x00\x05\x1b{4\n&'&\x91\x91\xe4'$!\xfeP\a\xef\xfcDV\x8d\x9b\x1f~{\x92\xb8\x8b\x8c\x03\x15\x03%\x8bd\x15b\xab\xece\x9d*\xbc\xfd͛O|\xef\xdb7\xbf\xf1v\xe8\x11?\xc1*\xf8/\x93\xbe\xf72\x11\xb1I\xf2\x0e\xa5,?\xfc\xc6oo\xb2e\x00\x05\x03&\x16\xa0`cOx\x05\xb3H\xfd\x1fq\x8f\xf8\xe6\x13\xff\xf2\xe1\x1f\xfe\xa0\xe8\x85\xc6`\x98\x82im\xe5\xc3\xc8y\x14.O\xfa\xf0\x81\x0f'}h\xb9̼\xa9(\xd8\xcd\xf7\x9e\xfdΤg\x19\x05Sʲo\xd2\xdb\xf4U\xc9B7\x91j\f\x00\xe3\x05(\xd8\xd8C\xf4\xea?\x89L\xb0\n\xa6\f\t\xbf\xf1\x82$\x0eO\xbc\xa6\x88\xc4\x03Xg\xf6\xc9֪\x81f\x14\xa9k+o\x94<*\xff\xf0\xbd\u007f\xa0\xff\x997\x95Q$\xe1g\x0f0\xa3H\xb5,\xef}\xe55M\x16\xba\x89Tc\x00\x18/@\xc1\xc6\x1e|\xd5\u007f\xf7\xbb\x1f^\xde\xf75V\xc1\x94\xb0\xfc\xbeI/\u007fry\xdf7q\xe2A%z\xfe\xf8\xb3\x97\xdfS\xac\x15\x03m$_\xdejl卒G\xb2\xc3<ky\x96\xfeg\xdeT\"\xf9\xdf|\xfb\xf2\xe5\x17\x1e\xa7Q\xfb\xcb4\x92ϔ\xe5\xfd\a_`\xb2<\xf26(\x180\x91\x00\x05\x1b{\xb0\f|\xf2O\x93,_\u007f\x8dU\xb0\x9b/?(M\x8d\xd8\xf7\xc4\x03\x96'\xf6\xe1\xc4k_\x97g0\xbc\xf7\xb8\xe5\xc1\x17\x14k\xc5@\xc9\xc2*\x98\xc6V\xd9(y\x14\x05{\xcf\xf2\xfe\xcd\xf7i\xfc_y\x93L\xc0\xa0\xb3)\xde~\xc22\xe9\xdbd\x12\x06\xd9A\xbb[jYn\xfe\xec\x91g\xd5,\xaf=\x02\xb3)\x80\x89\x04(\xd8أ\x88Ƚ\x02(\x180a\x88-\x05s\xb9\xf4\x92\x13\x1dP0\x00\x18+LV\xb0v\xe9\x81:\x81\x03U\x15\xd5\xc7\xf8\b\xd6\x1fs;u\x92\x84fN\xc2\x11f]\x8d\xe3\x8e\xc3\xc6oF\a\xf6\x10\xbd6n\x11M\x80\x82iy\x91\xe3\x1a\x99?\xc7\xe1c\x91\b9\xf0]0z\x0f\x91q\xe1\xd38\xad'\xbc\xcd\xf8\xb5ل\xc7\\\x05\xe3+\x8e\xd1g\xb4\x06\xdd\xde\xce\xeeκ\xaa\b\x12Vd\xbf\xa2\x93$\xf4\u007f`s\xf91;\xb9\xebó\xc94\xa7\x8d\xf9٧9D\x87\xcbN_A\xc1\xb4\\\xf1\xdbʙ?\xc7\xe1c\x91\b9\xf0\x1d\xd0zV|\xbd{\x0f\f\xb23\x03.\xf9\xfd\xb5\xdc\aaMƱ\xcd&<\xe6*\x98\xb7\xa9\x9b*X\x17]\xa6\x88\x8f\xb0\xd6G\x0fW\xa2\x93\x94\xb0\xd33\xab\x91\xfb\f\x193\x0eKnh\x0eQ\x0e\n\xa6\x8f]#\x03\xe3\xf0\xb1\xc8\xd8\xefR\u007f~P(\xa7\xee\xd6\x03\x83\xeä\x8eH\n6\x9em6\xc11U\xc1\xda=\xbc\xf4\x9c|\xda\xf9\n\xba\xc3/\xf6\xe1R\xfb].m\x17\f\xc9gVO\xa8\xb0\x99\x8a\xac`\xf7\x1c\x11\xea\x1d\x91(\xc8\xc0\xddq\xb7\a^\x16M\x05[\x16\x05\x05\x03d\xccT0\xbe\xa2\x8bY\U00076ffb\xda\x1b\xf6\x9b\xa5\u05f6U')\xa3\x9cY/q\xb6\xfa\x92\x05i\xab/\x91\x1e\x19Ǖ\xa3r\x8e\x04/\xfa\xd28)\x86q\xce\xc6qe=Es\xedk\xc8\xe1j\x97\xa5-\xa9\xd5fc\xc0{k\\Y\xe9\x05=F\xd9\xf4\x0f\x81\x87\x1bE\x99\xe9\x85\xd2(\xb2qeڂ\x12\xba\x88\x89\u007fu\x96\xcd\xf1\xa3,\xcd!\x10_\x98i\xcb*8\x87\x8c\xca\xc0x\x18u\xdd\x04\x87\xedլ\xcc֭\xb3\xf2x\x03\xbf\x87\xa5\x80\xe22M\x01\xca\xe8\x01\xc81\xcbpS\x97\xa8\x85\xd4\xf1\xc0\xa2\xd6M\x83}\xab+\x936*Stփ\x9a\x8d\xa9\x10\x89u\xbe*\xd5\xd8\x00\xa5}_\"FJ \xb2\xa7Ёw\x93\xef<\xb6\xe8\nl!\xf5>!M\x93\xe8U^\xc3gE\x8e\xac\x92\x12\a\x1d\xe6\xc9\x1f\x80\x913ր\xb5\r\xaf`\xecy\xa6{F\xddW\x98\xa9`\xde&u\xcd\xee\xa0\xdb\xed\xf6\x84\x0f\x83\xb9l\x97t\x922\xf6\xb2\x81\x81B\xd2\x03\xfb\xb8\xd1\xc69\xcakf\xe0/\xba~\xff\xac\xb2\xeb\xe8z\xd9,?>\xcd\xce\xfa\xfd\xa2\xca\r46f-\x98\x91UR\xc4\xf5\x92\xce\\Ys\x99\xbdH\x93\x8d\x81\xec\xcd\xda]\x9e\x95v\xc1 \x9b\xfe!PϬ\x05\xf5\x87WsT\xc1\\\xdc\xd6\xe6\x1a\xc72,)g\xb9\xa2\xc6\xe3\xf5\x0eN+\xd4͜\xab\xb5\xb1\x80\xeb0*\x03\xe3a\xf4uk\x9dŕ\xe4q\x8eݎ\x1a\x03\xbf\xfc\a\xfe\x05y~\xbf_\x1bJ\xbe\xfe\xfcJ?\x8f\xdf[\xf9\xfcu\xdc\xd4ܢ\xc6ÎB\xa3\x92\xb1\xa8u\xd3`\xe7\x9656.\xc1\x8d\xca\x14\x9d\xf5\xa0fc*\xd4\xffA\u058bW\xe4\x1a뢶\xaf\x18\xaf\x92\x02\x91\xadi\xcb\xde:^\xce\xd5 M\xd1U\x98B\xea~B\x9a&ѫ<\xcb\xe0\xa2\xcc\xda2{Z\xfd\xea\x1a\xe6\x030r\xc6\x18hl#\xf4\xc1\xd4\xf3L\xff\x8c\xba\xaf0Q\xc1:\x89b)}\xb0`\xa0\xbd:l$\xbf\xd7\xf6\xa2NR\xc1N\xbe\xd8\n\xc4d:ַ\"\aI\xbaȩ\xf6\xbc<\xf1B\xe9\xa7-\xe3H\x1f\x04\xff;\xce\x1dGd۬\xcd\xc6\xfa\x9d\x8b\xcd\xfa\xb2\x96\x1bf\xd3=\xc4\xca\x05\xf8*\x13\x96\x90\v\xa8\x99{\x17\x91s\x12\u007fi\xd6:h\xcfh\x96\xf6|\xebo$W\xe4\x92]M\xa7\x00\x00\x00\x11\xe6IDAT\xe7hv\xbd20\x1eF_\xb7\xcc\"\xec\xef0\x9d\x8cb\xe0Ww\x94\xf3\xae؛YDm\x1d\x9f\xe1\xa3\x13[#\x0f\nl\xdd\x18\xec\x8b\x06\xb08-X.\xfd%\x15]\xf5\xa0ɦT\b\x95\x93\x8eK\x91\xf14\x1a\xb6}\xa9S:\x8c\x1f\xc8Z\x83\x8f6\xd8؇آ30G\xd3\xff\x844\xa3H\xddʫ4r\xb83W\xcb\x11qf?\x00\x16\xc5\x19c\xa0\xb5\x8d<\x8a\x94\xdą\xbc\xf7\x11\xe6)\x18_\xd1)\bBw\xa5\xa0\xb4\xfe@uS\x18\xfb\x97l\xbd:I\x05\xbb\xab\xa3c\x89\xa4`\xe4\x1c\x17cP\xad\xf6~ԟ\xe6\x97m\x94\xab\xdc.9pI\x17\xa6K\x9b\x8d\xc1Ngm\xd4r}F\xd9\xf4\x0e\xd1\xc7Փ\x972\xe2\xacp\xee \xae\xa7\x90\x85m/e\xce}\xa9\xfe\x9c\x10:\xe1\xe3\xb3\xda5sgqKhv\xbd20\x1eF_\xb7\xccF|}\xf0h\xe7\xf3\x86~u\x15\xec\x1c7\xd0\xffn\x9f`?\xa7\xb15\xf2\xa0\xc2ԍ\xc1\xfe*ي\x8d\xca(\x98\xea\x81ͦT\b]\xc2\xc200\xa3\x15\x19\xc1\xb6\xaf\xaa`͜:\x8a\x8dTH\x83O\x88U0\xddʫ\xecLG\xe4F\xd3!\xa4\xfd\x00X\x14g\x8c\x81\xd6v\xc4\nfT\xde\xfb\b\xf3\x14\xec\xa2[&\x80\xa4G\x01\x9eq\x1b\u007f\x97\\\xb1\xbbt\x92*\xe4#mnU\x92\xd2i*8\x0e\xa1C\x0e٫z\x95\xcbQ\x9e\x95\xa2\xe6\x15,\xd7fc\x10\xf3\xf8\xb9\xb3F\xd9\xf4\x0eq\x96\xa3\xc2B\x9d-\x91\x02\x1f\xe4+\xbe\xaf\xbep\x11\x1e\xc2!\r\x1d\x8e\xac\x9d\x87\xfcyK\x94\xec\xa1e`=\x8c\xban\x99\xc7Q\x87\rQ\x053\xf0\xab\xab`\x03\xb6s5\\Y\x0f7\xa0\xb15\xf2\xa0\xc0֍\x81mTF\xc1\x14\x0f\x9alJ\x85\x10ZS\x82\x8e\xa7\x87\xb9\\\x99\xf6U\x9d\xd5\xd0B\x8bD,\xa4\xee'4,\x92?\xac\xf2*5\xe4n\xf8q\xda\ac?\x00\x16\xc5\x19c\xa0\xb5\x1d\xb1\x82\x19\x95\xf7>\xc2<\x05\x13\x82\x84vO0(\b\x95>\xba\xebL\x85\xb1\x82m\xe5zt\x92*\xd2Gz\xee3\xedi\xba\xf59\xf4\x9c\x12\xf5W\xafr\xe5[p.}\x99\xebB\x06g7\xb2\xd3\xdc\xf5\x1co\x94M\xef\x10\x9fq\xb5Ԍ8+\x9a{\x96\x82\vv\x96\xf4\xe7\xfa\x1a\xed\xb5\x88e\xd1r2\x88)4V0\xc6\xc3\xe8\xebF\x14\xcc.*\x98\x91_\ua87e\x17iXԘ\xb7r\xd1!\xdaSPm\x8d<\xa8\xb9\x98\xba1\xd8\xe9-c\xb1Q\xf5\x14L\x93\x8d\x11\xd4Î\xc1p\xbf\xc5`ۗ:\xa3\x9d\xe0V\xb6\x0f\x16\xa1\x90\xfa\x9f\x10\xdb$\xfa\x95W\xe9\xe5\xd6\xf4\x9e[\xb0\x92\x9cȚ\xb3\x84Aq\xc6\x18hmG\xac`F彏0O\xc1D\xc48X\xd5\x01\xb2\r7\x8a\x8c\xd4\x05\x93?\xd2̝\xdaӴ\xc3~Ůđ\x87_\xe5\xcd4\x8a\xd1(Ɗ\xf4\x15́Oo~n\x9ea6\xddC,\xcf\xea\xc3c\t;qv\\\f\x94\x94\xe1\xef\xc9r\xee8I\xe6i\xa3xYī\xb0\xc4X\xc1\x18\x0f\xa3\xaf\x1b\xa3`F~\xf3pe\xaf\x84\xde\xf0{\xfe%\xdbq\xeeE\xea[\xb55\xf2\xa0\xc0֍\xc1\x9eE\"S\x8b\U000a4fc6)\x98&\x1b\xa3`\x83\x8e\xc3\xe9\xf2 \xb2\xb7|\xd8-N\xb6}\xd3\xf0\x89 ,'\xce\xfa3\xf3\x06\xf1\xcbV\"\xf6\x91\n\xa9\xff\t\xb1M\xa2_y\x95\xb3\x9c\x83\xe3\xf2\xe8\\\x1f\xcdY\xa2\xe7\x8c1\xd0\xda2\n\xa6SM\x82\xd4fF彏0W\xc1\x84@\xbb'p\x8d\xcchm\xea\xec\xee\f\x17\xc9/Q\xfb]%:]0yN\xbe\u007fV\xc9\x15\xbf\xcdՁκl~r\x1a\t\x99\xab3i\xc7n\xf0\x03\xbfߎmx$tлA\xbd4c\x11\xb7\xb3y'WDg[3\xd9T\xc8m\xb3\xfa\x05\xe9=\x06\xd9\xf4\x0f\x81.\xa4e\x95\x97\xa5s\xb6w\xf1hb'\xf7|\xe3!\x179C˹\xb4\xb2f\x9c\xd4Frʹ\xc2\xda\xdd\xcb8\xc7[\x1dFeP<\x8c\xben\x17\xd2k\xfa\x1bm\xe7\xfa\x9fϻd\xe8\xb7\xdc^s(/-\xe4n\xef\xee\xb4Y\xc2\x02\xfb\ue4062\xf0\xa0\xa0\xd6M\xe3\xccέ\xe9h]\x89\x1b\x95):\xebAͦ\xa9\x10>\xde\xdct\xb9\x9b^\xc0\xa5\xf5!-l\xfb\xaet\xec\u07bd\\\xfc\x00Z\xed\x8bj\x9b\xb7r\xf5#(\xa4\xfe'\xa46\x89~\xe5Y\xce\xd9[\x9b\xfdW\xc4B\xb2g\x89\x8e3\x8d\x81\x9a\xa4s\xf2k\xe4:\xebT\x939ό\xca{\x1fa\xae\x82\x05H\x18\xac\x8a$\x9a\xaa+\xeaZ\xd4xE(\xd7ӊt\x92*\xca\xef\"\xb9\x9a\x17\xf1\xc6v\x81L\x99\xa1_L5\xf6\x1ajqVz\xbf\x1e\x9d\x13\x13b\xe0A\xa8Y\x92\xb6\xa4V\xa0\xbfxc\xb3)\xd8K\\\xb32\x8b\xae \x83l\xfa\x87\xc0\xfd\xaf\x82\xf4\xb9%\xefڨ\xb3\xe3y\x8e\xf4\x95\xe4˵qey\x96-3/\xe4t\x13j\x16\xd8\x1d\x85\xf5\vlyFeP<\x8c\xben\xb8\x83\xd08\x83Kk\x14\xc37\xfa~\a\xb6\xa6\xdb\xf3B'@\x9c\x9dU\x86U\xac#\xd4֠d2j\xdd4\xce\x16\x95\x17Π\x8d\xca\x14\x9d\xf5\xa0f\xd3T\x88\x84ȕ\xfew}ڰI\x1al\xfb\xf6\xe4\xd9g\xac~U,NOa\u058c\xe5\x87FRH\xfdOHm\x12\xfdʳ|`#嵭<\x87BΒ\xe1\xce4\x06j\xd2%5\x89\xd8\xf5ԩ&s\x9e\x19\x95\xf7>\xc2\\\x05\x1b1\xafr\x1f\xeb$\xc7\x03et\x06L\x00\xfa\xed\xea\xc5z\x88\v\xed\x9cL\x00\xae\xa7\xbdx]\x10\xfa\xce\x16\xa6G\xabp\x13\xb2\x9a\x13\x88\x18Q0\xf3\x1e\xab\x03\n6\x91hT\xee\xbd\n\xef\xce\x1a\xdf\x13ad\x1c\x92F\xb9\x82#4\xfauwL\xd0jN bD\xc1\xcc\x03\x14l\xc2Pފ\xf2\xca\xe4?\xae8J\x8c\x83\x0e\xe6qV\xba\xf1y\x8e\xd3\r\xc0\xdf1\x13\xb4\x9a\x13\bP\xb0\xb0\x88\x91[`\"\xd0\xcf-{)s\xa2\x8f\xa8\x04W\x9a\xab\xb1\xb5\x11o#Y\x02\xd1\x01\x14,,4r\xdb\x1b\xc9\n\x18\x17\xca\xd2\xf2\"<\xf8o\"pxu\xa6-sMtƐ@d@\xc1\x00\x00\x88]@\xc1\x00\x00\x88]@\xc1\x00\x00\x88]@\xc1\x00\x00\x88]@\xc1\x00\x00\x88]@\xc1\x00\x00\x88]@\xc1\x00\x00\x88]@\xc1\x00\x00\x88]bK\xc1\xcc\xfby$\x00\x00\x13\x11\x93\x15\xac\xdd\xed\xd5I\x1a\xf11\xb7S')3ҕ\xd8k\x8d\x97\xebR\xd6\xe7\x02\x00 &0W\xc1\xf8\x8ac\x95Ó\x86\x14\xa9\xeb\xdc\x16\r[\xf2v\xc4+\xb1\xf7\xf9\x97\x1b\xfeZ[Z\x9f\v\x00\x80\xd8\xc0\\\x05\xf36uW\x0eO\x1a\xd1Õ\xe8$U\x86=JΈ\x02\xe3\xe7M\f{\xca4\x00\x00\x13\x18S\x15\xac\xdd\xc3\xcb\xebE2IC\\j\xbf\xcb5\xbc\vv\a\x80\x82\x01\xc0=\x82\x99\n\xc6Wt\xc9+\xde2ICzm[u\x92\x12\xba\xab\xd77\xe2}\xe5\xca:\xf5\xea\xb2\xeeX\xc1\xb6\xe2\x9dv\xb2ʌ\xbar\xfc\x95\xa2\xcc\xf4B\x18E\x02@,a\xa6\x82y\x9b\x945\xbb\x99\xa4!.\xdb%\x9d\xa4\x8c\xde\xea\xf5\xfd\xfeYe\xd7\xe5u\xea\x99eݱ\x82])\xe2jȃ\xbfԕ\xe3{f-\xa8?\xbc\x9a\x03\x05\x03\x80\x18\xc2D\x05\xeb\xf4\xf0\xb2l1ICzm/\xea$Y\x94U\xbb\x94\xd5둋,\x97\xf0<\x99x\xc1.\xeb\x8e\x15\xac\xc6N\x9f\xe0Ĭ\x1c\xbfrA?Ys\v\x14\f\x00b\b\xf3\x14\x8c\xaf\xe8\x14\x04\xa1\xbbR\x10ؤ1/\xa9O\x1ad\x92,\x8a\x82\x11\xc5\x12\x03Z\xad\xf6~ԟF\x16\xd0f\x97u/(/\xe3ę\x17\xea\xca\xf1}t\x89!q\x8dT\x00\x00b\x04\xf3\x14\xec\xa2[&\xc0$\r\xcd#.y\xab\xb7r*\x12\x1c\x87\xd0!\xba:\x04\xbb\xac{\x81c\xc6\"q-+u\xe5\xf8\xb3\x1c\xd19\x88\xe4\x03@La\x9e\x82\tAB\xbb'\x18\x14\x98\xa4\xa1\xf9Vu\x9dۭ:K\xde\x12t\x14\fm}\x0e=G\xa3\xfe\xec\xb2\xee\x05\x8e\v\xbd\xb3\xe8R\x8b\xea\xca\xf1\x9fq\xb5\xd4\f\x14\f\x00b\b\xf3\x14L\x84\t~\x85\x8d\x83\x8d\xa0\v\xa6\xab`\x1d\xf6+v\xbaT\a\xbb\xac;\x99M\xd1l#\xbb\x99\x95\xe3\x97g\xf5!\xd4c\x97\x14\xacww\f<\x92\x1d\x00\xee{\xccU0!\xd0\xee\t\\\vM\xeaQ\xa2\xf6\xbbJ\xf4\xba`\xfa\xab\xd7c\xb7\x99\xab3C\x96\x80\xef\xf3/w}0\xd8_\x90\xd9z\x9d]9\xfeBZVyY\xba\xb8N=Y\xec\xfdG\xc3\x0f\x02\x00\xc0\x04\xc3\\\x05\v\x90\xd8WUhR\x87\xebiE:I\x06\xfd\xd5\xeb15\xf6\x1a\xd1BYֽ\x96\u061d%s\xc5\xc8\xe2\x83\xea\xca\xf1=\x05\xe9sK\u07b5\x89\xd9\xea\x1d\xf5:G\x01\x00`ba\xae\x82\x8d\x98W\xb9\x8fu\x92\x00\x00\xdc\xe7Ĉ\x82\xc1cu\x00\x00\xd0!F\x14\f\x00\x00@\aP0\x00\x00b\x17P0\x00\x00b\x17P0\x00\x00b\x17P0\x00\x00b\x17P0\x00\x00b\x17P0\x00\x00b\x17P0\x00\x00b\x17P0\x00\x00b\x17P0\xf3\x18\xe8\xef\xef\x1fDh\x10\xbf\fD\xb2\x05\x00@\x0fP0\xd38\x16g\xb5Z\x13y>\x11\xbf\xc4\x1d\x8dd\r\x00\x80\x0e\xa0`c\x88wf\x10\xa1k3\r\xd6\"\xaf\xb6z[Z\xda\x11joi\xf1Z\xab\xf5m\x00\x00\b\x8b\xc9\n\xd6\ue997w\xbf\x87>c\xda\x13\x8d\xc1\xd4~\xabDR\x18oMI\x06\xb2\x12\x9ek\xf9I\x89sF\xbc\xb0\xee6k1}\x89ۦ\xfbv\xb5\xb5[Nv߁\x82\xdde\xd1Gʩ\xef;Ern\x871\xca9a\xfc&\x00\x8c#\xe6*\x18_q\x8c>\x98\x95w\x9f\t`\x82\x91\xecG\x02\u007f,>ׇ\xd9`\r\xe3Λ8r\xc9`\x98\x9d\xec\xceM\xe4#YI\xec\x8a\xf3\x88\t\uf8e5z\xefGR0\xdf\xe9\xe1\xfb\xd0]\x17}\xa4\xdcj\xcb~\xa5\r\xb3\xc7\xf9\xb9\xb1щ\xf9G\x8c\xdf\x04\x80q\xc4\\\x05\xf36uK\n\xa6\\\xccQ \x81v}*\xc3)\x18\x1aqG\x8a嚵\x14\t#\x15\xb0\x8b\xf1\x1b\xe4\xe4\xa6\x04\xbd\xeaER\xb0鋇\xef#\xdcU\xd1\xef\x80\xec\xbdd{\xd0y#\x8cM\x98\xfe\x19\x00\x8c'\xa6*X\xbb\x87\x0f\x8c\x99\x82u\xad\x8bdw\xc7tY\xef`\x00\x97\x9b\xach\x1d\x9f\x9c\xabc\x10I\xc1R\r\x14l\xac\x11\x15\xec7o\x80J\x011\x80\x99\n\xc6Wt\xa1\x91)X\xb5\xd5j-F\xc5x[\x8d\xf8\xc5\xc9\xf1)\xf3\xce\xe0\xbdg\x1e\xb5Z7u-\x9d\x9a8gPc-*\x18&\xdf\x1a\xef^7-qvw\x88\x87D\xab5\x8e>\xd0Z\xebaWjb\xea.m6\x86\x81$1\xbc\xb6\x8e\x18\xc4U\xe2>\x96uZ\xa8m\xd7¤\xf8\xe49tɸ\x81\xc9J\x17\fw\xc2\x12\xfb\xd10\xf4\x14\xec\xe8\xec\x94\xf8\xa49)\xb8w*\x05\xf3R\xb5\x85T\x8b\xae9ppiRʺuI\x9a\xf1e\xf7d\xc9\xc5dm=n7\xac\x9f\xbf\xb6\x81\xcaS\xdb\xe6\x15\xd9\xcfl^\x11\"U\xa2\x82a^qf\x1f|c\xd5\xfcͿG\xe8\x88\xd3\xe9܋\xf6\xe2\xed\x11tc>}\xc1|\x94\xedt\xee\xf9t\xfb\x8a\xec\xcd_0~\x99l\x000֘\xa9`\xde&\xa4(XS\xb5\xbb\xea\xa8\xcee.\xc2\x1f\x9d\xbc)\x88\x82\x9b\xa6\x1c\xe5\xf1\xb5\x9d뫞\x17ׂP\u007fuUʓ\x93S\xd6-\xb5j\xafфM\xfd\xfd\x8bI\x0f\xac\xb3\xeaQkRq\xe9\xe4\x85Z\x0f\xe8\xa4\xcf'\xaa\x9c\xc6Cn\xc2&濾\xa5\x9al,g|U\xd6b\x9f\x0f\xebS\xc0\x17\x8f\xb3\xb7\xe4&\x84\xd8\xfa\x12S\xb75\x15[i\xd4\xeb\xb4էf=fmA\xc3\xd0Q\xb0\x93֥\xd5M\xee$+\x96\xaac\xbe'3|>_gH!\x95\xa2\xb3\a\x1e\x98\x96\xbc\xab8!\xb1b6\x1bo\x1b\U00014284\xdc\x1fّ\xbd\xe7Ԟ\xec\xed8\xf5\xcb\xefo?r\xea\xe03\xce/4\xef\xa3\xec\x9fܺ\xb5\xe5\r\x9c\xf8\xe8H\xb63g\xef;\xf3\xb7 t\xa3m\xfeO>G\x9f\xef}\xba\r\x8f-Ϸ\xb5\x89*w\xebȑ\x15\xab\xe6缱\xfd\xfbW\x19\xbfL6\x00\x18kLT\xb0N\x0f\xaf*X\xe5\x99\xee\xce\xea*㻇\xb9dH\xb5\x98\f\xc6\xf8j2:K\x15\xe5%\xd5:\x1b\xff\x15\x12\x9aJ =\x8fybr\n\xbe\xea\x97&i=\x10\x12\xe5~\x9a\xe2\xe1\x80\xf5\x00\"\xdb\xfd\xdal,\xea(\x92\xaaHq\x02\xd2\xd8\xf6\xa7\xcc\xc1\x15\x18\xa8\xa6+.y\xad\x17Ռ\xba\xa3D\x1d\x05ەD\xfb\x82Sh\xa8\x8b\x19Ej\xaa)\x17]=p\x95\x15wIwYۑ\x86\xe0E\x11m8\xf0\x94\xf3\x94\xbcm\xc8!\xda\xd5\xf0th\x1f\x8c܉\xdc,&\x9f\xc6\x1d\xa9\xed9$\xb9\x83h\xde\xf6\x1d\xb2\x8d\xdcO[\xeb\xdcx\x03ݾ\xa1\xf1\xcbf\x03\x80\xb1\xc5<\x05\xe3+:\x05A\xe8\xae\x14\xf0\xe5*\xb4\x93\xeeW\xbfG\xa7\xa7\"\xe1K\xe4\xf1\x10\x8avk\x82\xbb\xe6L\x9dL\x86W\x98T\xbd\x18yBnKK\xaa\xa4`D\xb1D\xa5a< V\xc1d\x0f\xb9\xd3\xe8˴\\m6\x16}\x05Sl\xf7\x13!\x91\xa9\xd3*\x98\xce*L:\n֝<5\xdf}F\x10\x85\x9cU0\xb6\x9a\x8a\x82)\a\xde0\x05\r\x0f\xd2]\x94g\x95h{\xa8;\xd6җU\xaf t5g\xc5\xeb\a\u007fu;4ޕ\xbd\xe3\xfc\xf9\xb5\x92\x82\x11\xc5ڛM\x92mٷЭ\xf9m\xb2\x8d\xa2`\xd9W\xc5\x04\xe3\x97\xcd\x06\x00c\x8by\nv\xd1-\x13\x90w\x1d\xad3\xb4\x1eL\xaaCuI\xa4oҒ\x9c\xb2\xa1Η!)\xd8t\x1d[\"/\xfb\x9b\x94\xa4\xa44\xaa\a\x82\xaa`\xb2\x87\x99\xa2\xe6͙\xae\xcdƢ\xaf`J\xb2\xd4\xca\f\x83[\u0601c\x8b\xf5\x18\x1a\x86^\x1c\x8cw/\x9efM\x12珱\n\xc6VSQ0\xe6\xc0A\xd2{\f\xe9\x83\xf9\xbc\"\xcch\x16\xb3QԦ\xcd\xeb\xf1\xe6\xc6\xc1-\xab\x9cϼ\xa3\x13\a;զ$%)\xfa\xe2\xe9\x13\xe8\xc43\xb2\xa9\xaa`\xeb\xa5\x04\xeb\x97\xc9\x06\x00c\x8by\n&\x04\t\xed\x9e`P@M\xa22\xf8\xc2\xdc\xea\xcb_\x88\x16\xe6\x93Ĵ\x99d4\xb5PR\xb0\x90X\x15E\x8a\xe4\x9f\tj\xa5H\xf1@P\x15L\xf6\x90;\x95\xbeL\xcdE#U\xb0M!\n\xd6defp\xf1\xca\xfd\x04\xf2v\xbc\xce\x1c\f\xbd8\x18\x89\xfe\xf3U\x89\xe4~\x82\xa8`\x15\xd4FS\xcd\xe1\n\xd6\x1d7\xa7\xfb\xccԙ#\x9af\xb1\x83\x06\xeeo\xaf\xc0ݤ\xf3{p\xf2Ƒ\xec\x06\xad\x85\xa4N\x1f\xdd\xd0J\xd1\xeb[Ж\xd7Cl\xb0\x82m\x91\x12\x8c_P0`\xfc0O\xc1D\xc48\x98\x97v\xbe\xaey\x98QX(-\t\x81\x04ګI!W\xb3\x90*)\x98ތ\x03I;\x927h\xa5H\xf1@P\x15L\xf6\xe0\xa5#\xbd**R\x11\x15,\x11\xfb\x16\xa6\x87(\x18\x9f\x9cA\xc6\u007f\xf9\xe24\x8e\xc5S\x15E\x11\xa6\xcdA\xc3\xd1Q\xb0b\x1a\x8bC\x19Th32\xf0\x88Y|CS\xcd\xe1\nvښd\xb5f(]ٰ\x9c\xa2\xb7\x11\x8f\x90x\xd5^\x1a\xb4B\x1b_\xa1oto\x93\x86\xbd\x92:\xe5\xec\xd1J\xd1/\xb2\xaff\xffB\xf62\\\xc1\x18\xbf\xa0`\xc0\xf8a\xae\x82\t\x81vO\xe0\x1a\xbez\xdc\a\xba\xbaOVx\xc3\xf4\"\x84\xe4\xd9\xc9\xf4\xedb\xeb\xe2]\xdbR\xf1P\xabe\xb0\x85ޯc\xe2M\x04yN\xbeo\xf2\xba\x80/>\xb7\x05\x9d\u038d'7\x10U\x0f\x03->_B\xae\xef(\x8f4\x1e\x96\xc6m\xf0n\x88[Jo52\xd9\x14\xc4{\x91-\xd4\xc5̤m\xdbfZ\x1f\xf5tjl}\x8fMs\xefϷVP\xf3\xae8\xe5\xce`\xa9Uoz\xbd\xae\x82%\x16{\xebr\xc5ۘ\xc5\t\xa5u\xb3\x13\xbb5\x85T\x8b\xce\x1e\xf8tB\x93\xd7\x17\x18Q\x17\f\xa1\xed\xce='\xf68I\\~\xafs\xfe\xde\x13'v8\xc5\x11\xe3<+\x95YyN~\xdb\xfc7\xae\xe2\xe4\xcfo\xff\xf2\x95\xec6\x12뺝\xb3Y\xfc\xa1\xd1ퟷQ\x9b\x1b\xe8\x8b_\xb4\xad\xda\xd8\xd6\xf6\xa9֯6\x1b\x00\x8c)\xe6*X\x80\x84\xc1H\xd7'\xd8T\xe5\U000761fd\x06K\x13DE\x10J\x9fLHZ\xec\x99\x1a\x9fq&\x8e\x06\xaaC\xfa7\xca\xef\"\xad\xa5\xf9x\x13\xdfN\x9e\xfd\x90\xcfz8)泺\x91ƃ@\xe7\x83\td\xaa\x95&\x9b\xc4\xc0\x14j\xfbh'\xf9\xa3+#q\xf2\xec\r\xd8@k۵8e\xf2t9\x98\xb7\xe91)\xf8u4Qwrm\xb5\xb5K~\xbaN\x97\xa4`\x95\x19\xc5)\xf1\xc9\x19b\xe4j \u007fJb\x06\xee4\xb2\x85T\x8b\xce\x1e\xf8X<\xd9\x17\x9f\x11\x12\b\xd3\xe7v\xc3Zi>\xd8\xc1\x8d{Wd\xe7l\x94\xa2\xf3\x9e$7y9\xe5\x94ix\x05o\xb2\u007fEf\u007f\xd1^Z\x834\xdc\xfc\xa5\xf4\xfeA\xf4\x91\x98ج\xf5\x1b\x92\r\x00\xc6\x12s\x15\xec\xdef]<ե\xaa\xf8\\\xed\x8c[\t:iUz\xba\x0e\x9d\xc3q\xb7\x04\x13\U000c30c3\xfcɅSF\xfa\x8b'\x00\xb8W\x00\x05\x1bCJS\xc8\xd3u\x92\xf5\x1fM\x81\x06ϴ\xc8O\xd7i9\xa3\xabq#\xa4N\x9c?\x86\x84\xa4\xd1\xe8 \x00\xc4\"\xa0`\xb1\xcf\xe98q\xf8\xd8\x1e\x17\xe6N\b\x00ܓ\x80\x82\xc5>Bnb~\x95\xaf*?Q\xef\xf7\xe3\x00pO\x03\nv/\xe0\x9d\x9d\x1c\x9f<\xe7\x0e\x1e\x9c\x01\x00\xf7\b\xa0`\x00\x00\xc4.\xa0`\x00\x00\xc4.CC\xff\x1f\xf8\xaa\xf0z\xf7Oɏ\x00\x00\x00\x00IEND\xaeB`\x82",
+
+ "analysis/help.html": `<!--{
+ "Title": "Static analysis features of godoc"
+}-->
+
+<style>
+ span.err { 'font-size:120%; color:darkred; background-color: yellow; }
+ img.ss { margin-left: 1in; } /* screenshot */
+ img.dotted { border: thin dotted; }
+</style>
+
+<!-- Images were grabbed from Chrome/Linux at 150% zoom, and are
+ displayed at 66% of natural size. This allows users to zoom a
+ little before seeing pixels. -->
+
+<p>
+ When invoked with the <code>-analysis</code> flag, godoc performs
+ static analysis on the Go packages it indexes and displays the
+ results in the source and package views. This document provides a
+ brief tour of these features.
+</p>
+
+<h2>Type analysis features</h2>
+<p>
+ <code>godoc -analysis=type</code> performs static checking similar
+ to that done by a compiler: it detects ill-formed programs, resolves
+ each identifier to the entity it denotes, computes the type of each
+ expression and the method set of each type, and determines which
+ types are assignable to each interface type.
+
+ <b>Type analysis</b> is relatively quick, requiring about 10 seconds for
+ the >200 packages of the standard library, for example.
+</p>
+
+<h3>Compiler errors</h3>
+<p>
+ If any source file contains a compilation error, the source view
+ will highlight the errant location in red. Hovering over it
+ displays the error message.
+</p>
+<img class="ss" width='811' src='error1.png'><br/>
+
+<h3>Identifier resolution</h3>
+<p>
+ In the source view, every referring identifier is annotated with
+ information about the language entity it refers to: a package,
+ constant, variable, type, function or statement label.
+
+ Hovering over the identifier reveals the entity's kind and type
+ (e.g. <code>var x int</code> or <code>func f
+ func(int) string</code>).
+</p>
+<img class="ss" width='652' src='ident-field.png'><br/>
+<br/>
+<img class="ss" width='652' src='ident-func.png'>
+<p>
+ Clicking the link takes you to the entity's definition.
+</p>
+<img class="ss" width='652' src='ident-def.png'><br/>
+
+<h3>Type information: size/alignment, method set, interfaces</h3>
+<p>
+ Clicking on the identifier that defines a named type causes a panel
+ to appear, displaying information about the named type, including
+ its size and alignment in bytes, its
+ <a href='http://golang.org/ref/spec#Method_sets'>method set</a>, and its
+ <i>implements</i> relation: the set of types T that are assignable to
+ or from this type U where at least one of T or U is an interface.
+
+ This example shows information about <code>net/rpc.methodType</code>.
+</p>
+<img class="ss" width='470' src='typeinfo-src.png'>
+<p>
+ The method set includes not only the declared methods of the type,
+ but also any methods "promoted" from anonymous fields of structs,
+ such as <code>sync.Mutex</code> in this example.
+
+ In addition, the receiver type is displayed as <code>*T</code> or
+ <code>T</code> depending on whether it requires the address or just
+ a copy of the receiver value.
+</p>
+<p>
+ The method set and <i>implements</i> relation are also available
+ via the package view.
+</p>
+<img class="ss dotted" width='716' src='typeinfo-pkg.png'>
+
+<h2>Pointer analysis features</h2>
+<p>
+ <code>godoc -analysis=pointer</code> additionally performs a precise
+ whole-program <b>pointer analysis</b>. In other words, it
+ approximates the set of memory locations to which each
+ reference—not just vars of kind <code>*T</code>, but also
+ <code>[]T</code>, <code>func</code>, <code>map</code>,
+ <code>chan</code>, and <code>interface</code>—may refer. This
+ information reveals the possible destinations of each dynamic call
+ (via a <code>func</code> variable or interface method), and the
+ relationship between send and receive operations on the same
+ channel.
+</p>
+<p>
+ Compared to type analysis, pointer analysis requires more time and
+ memory, and is impractical for code bases exceeding a million lines.
+</p>
+
+<h3>Call graph navigation</h3>
+<p>
+ When pointer analysis is complete, the source view annotates the
+ code with <b>callers</b> and <b>callees</b> information: callers
+ information is associated with the <code>func</code> keyword that
+ declares a function, and callees information is associated with the
+ open paren '<span style="color: dark-blue"><code>(</code></span>' of
+ a function call.
+</p>
+<p>
+ In this example, hovering over the declaration of the
+ <code>rot13</code> function (defined in strings/strings_test.go)
+ reveals that it is called in exactly one place.
+</p>
+<img class="ss" width='612' src='callers1.png'>
+<p>
+ Clicking the link navigates to the sole caller. (If there were
+ multiple callers, a list of choices would be displayed first.)
+</p>
+<img class="ss" width='680' src='callers2.png'>
+<p>
+ Notice that hovering over this call reveals that there are 19
+ possible callees at this site, of which our <code>rot13</code>
+ function was just one: this is a dynamic call through a variable of
+ type <code>func(rune) rune</code>.
+
+ Clicking on the call brings up the list of all 19 potential callees,
+ shown truncated. Many of them are anonymous functions.
+</p>
+<img class="ss" width='564' src='call3.png'>
+<p>
+ Pointer analysis gives a very precise approximation of the call
+ graph compared to type-based techniques.
+
+ As a case in point, the next example shows the dynamic call inside
+ the <code>testing</code> package responsible for calling all
+ user-defined functions named <code>Example<i>XYZ</i></code>.
+</p>
+<img class="ss" width='361' src='call-eg.png'>
+<p>
+ Recall that all such functions have type <code>func()</code>,
+ i.e. no arguments and no results. A type-based approximation could
+ only conclude that this call might dispatch to any function matching
+ that type—and these are very numerous in most
+ programs—but pointer analysis can track the flow of specific
+ <code>func</code> values through the testing package.
+
+ As an indication of its precision, the result contains only
+ functions whose name starts with <code>Example</code>.
+</p>
+
+<h3>Intra-package call graph</h3>
+<p>
+ The same call graph information is presented in a very different way
+ in the package view. For each package, an interactive tree view
+ allows exploration of the call graph as it relates to just that
+ package; all functions from other packages are elided.
+
+ The roots of the tree are the external entry points of the package:
+ not only its exported functions, but also any unexported or
+ anonymous functions that are called (dynamically) from outside the
+ package.
+</p>
+<p>
+ This example shows the entry points of the
+ <code>path/filepath</code> package, with the call graph for
+ <code>Glob</code> expanded several levels
+</p>
+<img class="ss dotted" width='501' src='ipcg-pkg.png'>
+<p>
+ Notice that the nodes for Glob and Join appear multiple times: the
+ tree is a partial unrolling of a cyclic graph; the full unrolling
+ is in general infinite.
+</p>
+<p>
+ For each function documented in the package view, another
+ interactive tree view allows exploration of the same graph starting
+ at that function.
+
+ This is a portion of the internal graph of
+ <code>net/http.ListenAndServe</code>.
+</p>
+<img class="ss dotted" width='455' src='ipcg-func.png'>
+
+<h3>Channel peers (send ↔ receive)</h3>
+<p>
+ Because concurrent Go programs use channels to pass not just values
+ but also control between different goroutines, it is natural when
+ reading Go code to want to navigate from a channel send to the
+ corresponding receive so as to understand the sequence of events.
+</p>
+<p>
+ Godoc annotates every channel operation—make, send, range,
+ receive, close—with a link to a panel displaying information
+ about other operations that might alias the same channel.
+</p>
+<p>
+ This example, from the tests of <code>net/http</code>, shows a send
+ operation on a <code>chan bool</code>.
+</p>
+<img class="ss" width='811' src='chan1.png'>
+<p>
+ Clicking on the <code><-</code> send operator reveals that this
+ channel is made at a unique location (line 332) and that there are
+ three receive operations that might read this value.
+
+ It hardly needs pointing out that some channel element types are
+ very widely used (e.g. struct{}, bool, int, interface{}) and that a
+ typical Go program might contain dozens of receive operations on a
+ value of type <code>chan bool</code>; yet the pointer analysis is
+ able to distinguish operations on channels at a much finer precision
+ than based on their type alone.
+</p>
+<p>
+ Notice also that the send occurs in a different (anonymous) function
+ from the outer one containing the <code>make</code> and the receive
+ operations.
+</p>
+<p>
+ Here's another example of send on a different <code>chan
+ bool</code>, also in package <code>net/http</code>:
+</p>
+<img class="ss" width='774' src='chan2a.png'>
+<p>
+ The analysis finds just one receive operation that might receive
+ from this channel, in the test for this feature.
+</p>
+<img class="ss" width='737' src='chan2b.png'>
+
+<h2>Known issues</h2>
+<p>
+ All analysis results pertain to exactly
+ one configuration (e.g. amd64 linux). Files that are conditionally
+ compiled based on different platforms or build tags are not visible
+ to the analysis.
+</p>
+<p>
+ Files that <code>import "C"</code> require
+ preprocessing by the cgo tool. The file offsets after preprocessing
+ do not align with the unpreprocessed file, so markup is misaligned.
+</p>
+<p>
+ Files are not periodically re-analyzed.
+ If the files change underneath the running server, the displayed
+ markup is misaligned.
+</p>
+<p>
+ Additional issues are listed at
+ <a href='https://go.googlesource.com/tools/+/master/godoc/analysis/README'>tools/godoc/analysis/README</a>.
+</p>
+`,
+
+ "analysis/ident-def.png": "\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x03\xd2\x00\x00\x00\xf5\b\x03\x00\x00\x00\x8b\f=\xff\x00\x00\x00\x01sRGB\x00\xae\xce\x1c\xe9\x00\x00\x02\xfdPLTE!# #$\"$%#($#&'%'(&-'\")+(4,\",.+01/>/\"241A2%685G6$8:7;<:Q9$>@=W>#AB@CEB\\B'cC$GIF\x00f\x00\x00g\x00\x00h\x00gF'\x00i\x01KLJ\x00j\x02\x02k\x03\x04l\x05mJ&\x06m\x06sJ(OQN\vo\b\x0ep\nwN&\nq\x16TUS\x10q\f\fr\x17\x0fs\x18~R%WYV\x12u\x1a,`\xae7]\xad\x15v\x1c\x86T)\x16w\x1d[]Z9a\xab\x19y\x1e^_];b\xac<c\xad\x8dZ(>e\xaf)z ac`+{\"(|*\x92]%cebAh\xb2egd+\u007f,\x9a_)Li\xafDl\xb0.\x81.ikh0\x830Ho\xb31\x841/\x858Jq\xb6mol\xa3f);\x86:Us\xb3\xabg->\x88<Wu\xb5\xaej(sur@\x8b>B\x8c@\xb3m,vxu@\x8dGC\x8dA\\z\xbbxzwI\x8dH]}\xb7K\x8fJ\xb9r*_\x80\xbaM\x91L}\u007f|\xc1s-O\x93MP\x94Oc\x84\xbeN\x95U\x81\x83\x80\xc7x+W\x95VX\x97Xm\x87\xbcY\x98Y\xd1z(Z\x99Z[\x9aZ\x87\x89\x86\\\x9b[r\x8c\xc2\xd6~-^\x9d]\\\x9dc\x8a\x8c\x89d\x9ddz\x8f\xbff\x9ff\x8f\x91\x8eh\xa1hޅ+~\x93\xc4j\xa3j\x92\x94\x91k\xa4ky\x97\xc6s\xa4lq\xa5s\x95\x97\x94\xec\x8a,\x83\x9bŘ\x9a\x96\x9a\x9b\x98u\xaaw\x86\x9e\xc8\xf1\x8e/\x9b\x9d\x9a~\xaay\x88\xa0˞\xa0\x9d\x80\xad|\xf7\x93-\xa0\xa2\x9f\xfd\x92/\x81\xb0\x85\xa2\xa4\xa1\x92\xa5\xca\xff\x952\x82\xb2\x86\xa4\xa6\xa3\x83\xb3\x87\x8b\xb2\x88\xa6\xa8\xa5\x96\xa9\u038d\xb5\x8a\xa9\xab\xa8\x8e\xb6\x8c\x9e\xad͍\xb8\x93\xac\xae\xab\x95\xb8\x95\xa1\xb1ї\xba\x96\xaf\xb1\xae\x98\xbb\x98\xa4\xb3Բ\xb4\xb0\xa5\xb5՛\xbe\x9a\xb5\xb7\xb4\xac\xb7ѣ\xbf\x9d\xa2\xc0\xa4\xb7\xb9\xb6\xa4¦\xb9\xbb\xb8\xa5Ĩ\xb1\xbd\u05fb\xbd\xba\xa8Ǫ\xb7\xbfԯƫ\xbe\xc0\xbd\xb9\xc1\xd6\xc0¾\xb2ɮ\xc1\xc3\xc0\xbb\xc3ؼ\xc4ٱ̶\xc4\xc6ó\u0378\xb9̸\xc1\xc8\u07bb\xca\xde\xc7\xc9ƻκ\xbdϻ\xca\xcc\xc8\xc7\xcbۿҾ\xc4\xcf\xdd\xcd\xcf\xcc\xcb\xcf\xdf\xc8\xd3\xc1\xc6\xd4\xc7\xcd\xd1\xe1\xd0\xd2\xcf\xc8\xd6\xca\xd2\xd2\xdd\xd2\xd4\xd1\xca\xd8\xcc\xd3\xd5\xd2\xce\xd6\xdf\xcc\xda\xcd\xd5\xd7\xd4\xd6\xd8\xd5\xcd\xdc\xcf\xd4\xdb\xd0\xd8\xd9\xe3\xd2\xdb\xe3\xd5\xdc\xd1\xd9\xdb\xd8\xd7\xde\xd3\xd5\xdf\xda\xdc\xde\xdb\xda\xdf\xe2\xd7\xe1\xdc\xe0\xde\xe2\xde\xe0\xdd\xd8\xe2\xdd\xdd\xe2\xe5\xe0\xe2\xdf\xe2\xe4\xe1\xdf\xe5\xe7\xe4\xe6\xe3\xe8\xe5\xea\xe2\xe7\xea\xe5\xe7\xe4\xe6\xe8\xe5\xe4\xe9\xec\xe7\xe9\xe6\xfe\xff\xfc\x93\x8dkM\x00\x00 \x00IDATx^\xed\x9d\u007ft\x14\xd5\xdd\xff\a%\x064*\x15\xe1y<\xb3=lbJ0@\x94\x86F\xac(\x98o崆\xf4\x89i\xfa\x8d\xf6\xa4R\u007f`A\x10\x1a͓ñ\"\x02\x15\x1e\x8c\xf5l\xea\x81ش\x91`h\xf6(\xb89r\xb2\x12\xe4Ⱥ(<\x12\xda''\x94\xd2\xf6!\xc5\b\xc8S(ȓv\xd7Գ\xde\xef\xf9\xde{\xe7\u05fd\xb3wfv\x03a\xc8\xec\xe7\xf5\xc7\xee\xec\xe43\xf7\xde\xf9̼\xf7\xde;;\x99\xb7\xf4\xff.\x00\x04\x00\xc0e\x86\xe4$[;\x9c\n\a\x00\xe0R\x03\x92\x06\x00O\x01\x92\x06\x00O\x01\x92\x06\x00O\x01\x92\x06\x00O1\x92$]_/Z\x04\x00\x80\xc1=I\xf7w4\aZv\x9dS?u\a\x82\xb6ј?\xc9\xeb\x04\x8b\x84_˄9\xed\xc9\xdbX\xf0\xb1O.u\x8a\xb1'\xc5\x12\x9e\x95\xe5\x90S\xccP\xe9$;]\x82\x17z\x17\x14\x16TE\xca\xf6!\x94h\x983\xcd7\xed\x9eF\x84\xa2\xb2\\\x95@!\x1c\x11q*\xc7\x0e\xf1n\xa6\xb8\xf3\xa8\x0eW\x9f\xd7\xe7\x14\xa5s\xb6\xbe(wA\xc2)*\x89\xc8\xf4\x9dN!\x19\x85k\x92>\x11\b\xf6\x1c\xeb\xd9\xd2<@?\x9d\v\xecjr\xd8\x00\xd5\xe6\x9e\x16,\x12ο*\xb7G\xbb\x96\xca\r\xc9\x1bYp\xa0\xce\xef\x14\xe2\x80}\t\x91^\xe5\xfdT\xd4\xd7h\x13\x96\x1aZa&\x06\xf6E\v\x16\x1dƊ\xf6=ڹ}\x11\xfd\xee\x88\xc8\vں\xda\x17\xcaQ\x14\x8fȹQ\x14\vɑ\xb8p\xe3T\x11\xeff\x8a\xe9;\x1e\x8d\xb6\xc9\xfb\x9c\xa2t\xaa\x8b\xda\xea\xf2\xce;E%ѕ\xa7}kZ$*\xc3pM҇\x02\xc7\xf0\xeb@\xa0\x87~\nv\x1cs\x92t\x9f\xbcZ\xb0\xa8\x10\x91\U0006937b\xc4?\xa3TiL霴ö\x84\u007f[\xa2-\xf9/\\\xd2Faf\n\xd7◚j\xb2XG$\xbd\xba\x80\b8>\x05\xa7'&\xd7\xd6\xe1\xfeT\x8eYm\x9b\"\xe2\xddL9}\aS\x97\xf4y\xb9\x15%\x86\xd2\\\xbdc\xb7NT&ᚤ\x11\xed\x9eO\x06\xfa\xc9[w\xd3@\xbf\x93\xa4\xeb\xfc\xa7\x04\x8b\n\x8a\xa4\xe3\x05+Q\xaa\xa4|NZb[B\xf9Ŕt\xb9\xbd\xa4K\xe8\xe0\xa4W\xee\xc4\xfd\\\x05]]QC$\x1dɏ\x8d(I\xf7\xc9\x17:\x80\xb6NT&ឤ1\xb1\xa3-A\xf2\x15{.p\b9I\xfac\xdf*\xc1\xa2\x8a\"i\xb4\xb2\x90\xbcn\xafʻg\xb5r&\xf7-*\xf4\x15-\xa0\xfao+\xcf+k\xa3+O\xd5Θ\xb2H\x1d92\xb1\x1a\xbd>Yn\xe8\xab-ɭI\xb0\x01\x03Kf\xf8J\x16\xf6\x9aK\x88֔\xf8\n\x17\x94p%\xec\x94\x15\xca\xc9\a\xff\xda\xd5\xf7\xe4\xd5\x1c\xa7\u007f\x10ԶR\xf6\xb5'\a\x1c\xc6mX\x88f\xcarA\x9c+\xcc\f\x95\xf4\xd2\"\xba\xf3]x\xbb\xaaEt\xf5\xa2*\"\xe9\x8f\xcbC\x02IkU\xf0\x15\xa7\x91(v\xad\x06\x99\xb37\xa2F\x99\x8c\xfe\xd9D\xe9\x92^)\xcbۍ)\xb8 \x0f\x83\x85\xcan\xae6\x1f\x00\xb59\x89\"ߋ3gDV\x15T\x0fp\u06ddϓ\xd5\xcb\x15\\\xa2D\x87%SpQ\xd2'\x03\x18zy,\u0601\x1c%]\xef;.XTQ%\xdd.\xe3\xe3]/\xaf\xeaj\x9d^NN\x87H~\xf9\xab\x91F<\x9e#\x1d{CW\x83\xff)\xbc\xd4WpO\xfb\xce\x1a\x99\x9e\x93L\xacN<\x14*\x99\x93?su\xad|\x9c\r\xe8\x92\xeb#\xa1\x85\xf2A\xbe\x84\xdf\xcaO\x85\"\xed\x852W\x02\x9e\xe4Ω\x8eF\xa3t\x1a\xe0\x97KC;\x8b\x16Y\xd5\xf6\xa7\x90O\x9e\xde\xf8\xeb|> q\xa0Q>\x80ޔ\xb7\xf7\U00085661\x92>^\"\xd74\x1e\x18$\x9f˖\xd1\xd5\xcbʨ\xa4[\x17(\x92\x8e\u007f\xac\x10g\xab\xe0*N#Q\xecZ\x9dX\xb4\xa0\xe1o\xe8o\r\x05\xd1\x18\x9b(\xa4KZ\xb9\xa6\xa0N\xc1Ey@\xbdѐ\xdc\x18\x8d\x9e6\x1d\x00\xbd9\x91\x02yu\xb5\\\xb8\xb1\xa8\x95\xdb\fo\x17U\x06Bl\xa2\x84\x87%SpQ\xd2\xe8d\u007fwK3\xd6tO`\xc0Q\xd2\xc7}\xcf\n\x165TIw\xe1\xc9t\x97\xfc&\"g\x12\xfe掗\xd4\xe0\xb3x0t\x1e\xa1w\xe9\x85߈܅{\xb29\xf8,O\x94\xf9i\xbc\x1e\xcbQ.\x93\xbe`\x80\v\x88\x85H\xb7R\xb6\x10q%\xb4M\xa7=I\x81\xf9\xdca\x06\xdeEg\xf1I<\x1dY\xd6柂\xcf\xdcڤ\x80\xba\x8a\xb337\x9a\v3C%\x8d\xceo\xac\xf0\xc9S\xc8V\xa5\xb5tum)\x95\xf4\xe9\xdc\xd3T\xd2\xd5j\xffU\xc5WaT\x9cN\xa2\x98\xb5,\xf5K\xf1\xcb2\xf2\xd3\"\x93(\xc4\f\xbc\xa9\xee\x1a\xed\xb2\xce\f\xbc\xf5\x03\xc04\xa7\xa8\x16o\xb9\x13\xd5%\xff|\x99\xab\xcdm\xf4DY\x1d\x96\x8c\xc0MIc\xe2-\x1d\xe4\x12Y\"\x918ڔ\xb0;\x00+}\x1f\v\x165\xf4^\xfa<Zz\xc7 .-1\xb3\x9e\x9c;\xfa\x15\xd0\xfa2\xfaVZ\x87\xce\xcb\xf4\xb7\xae\x06rr1\xb1\x1c\xe5~u\x18\xc0\x06\x9cm\xab\xb9\xa3@.C\\\t\x9f\xce(Y\xd9ޛ\x184\x15\xc0J\x9al\xdbhS\x9b\xbfN\x18\x10/+z4\xa903\x8a\xa4It\xe4G\xe4\xb4W{\xe9\xa5J/\x8d\x16\xb4RI\xf7\xedT\xe8\xe3\xab0*N#Q\xecZ\x96Hn\f\xc5\xf2\xa2dQO\x14A i\xab\xac\xb3\x92\xd6\x0e\x80\xd1\x1cT\x14\u0085\r\xa0\xb5ː\x99dI[\x1d\x96\x8c\xc05I\xc7\x15\x01\xef\x0f$\x8e\x044\xfa-\xa3O\xf9\xeb\x05\x8b:\xaa\xa4\xd7\x16\xe0\xb3Z\xed\x92p/\xd1*\xeb?\xe0T)\xf2x\xb4\x02\xf5\xca\xf4\xbc\xa3'\x17\x13\xcbQ\xaeM\\\x99\x80\x83E%k;\xa3\xd5e\x88+\x01\x9do_R*\x17\xbdj*\xc0|y̮6\xab\x80\x90~a\xc9A\xd2\a\xe9\x148Q\x857\xabR6]\xa8̥Q\xa8\xcc<\x97f\xab0*N#Q\xdc\xce3$\n;Qg!9\xa6F\xa2\b\x02I[e\x9d\x95\xb4v\x00\x8c栢w\xd1A\x1fB\xebR\x91\xb4\xd5a\xc9\bܒt\xa2i\a}ǒN\x9c$t\aN\x9e\xb4\xee\xa6W\xc9}\x82E\x1dE҃\xd3\xf1!\xad\xbd\xa3\x97r\x96\xac5:\x9f;\xe8[I\x1d:+\xd3k?tV\xc7\xc4r\x94/R\x17\x98\x80\xd2\n\"\x8eE\xf8LeK\xe8%\xb7\xbc\xfc=\x94\xdbf.\x81\x9c\\\xed\xa4\xab1Ne\x8b\xda,\x02N\x155\x94\x9c5\x17f\x90\xa0sk*颕tM\xc3\x1c<\xc4V\xa4P^\xa3H:\x96\x171I\x9a\xad¨8\x8dD\xb1k9V-D\x8b\xe8UK#Q\x04^\xd2\rvYg%\xad\x1d\x00\xa39\xa8(\x82\x0e\xfaS\x904I\x94\xd5a\xc9\bܒ4j\xee \xafd\xe0\xad`;\x97>M\a\x89\xe6E\x03E\xd2\xebș\x19Q\xe6h\rx\x1e\x1a+\xaa&C\xafU\xab\xc8В\xac\r\x91\xc1iE\t\x9e2\xf6\xe5*\xa7\xb2\x1eˡ\u007f\xdb3\x01%\xe4,K\x94\x913\x95)\xa1Q~\x97\x04T\x9b\a\x0e\xd5ո\xa5ʌ\x95\x11\x8e\xb06q\xc0`E\x03\xaa\xafN\x98\n3h#\xbd\xe5Y\xf9u\xbcX8\x93ܞ\x91 2X\x9dO\u007f\x97ΫW$\x8dꖙ$\xcdVaT\x9cN\xa2\x98\xb5\x1c\a\xfc\xa7\xfc\a\xc8\x02\x93(\xc4H:\x0f\u007f\xfb$*\xec\xb2\xceJZ;\x00LsR\x90\xb4\x9e(\xabÒ\x11\xb8&\xe9C\x81\x8e\x9ec=-\xea\xddc\x89\xfe\xee@\xff\x19\xcb\xe0\xb5FϼV\xd0I+w\x8f=\xa5\xdc=\xb6N^\x16\uab17\xb7#2\xc1+m\xebZEg\u007f\xb5\xf2\xba\xaeu2\xb9zt8ofc\xc34\xd9\xf7\xe6a.V'q\x80^9U\xe6\xebF@\xa3\xbc\xa4mc\xb9\\\xf8\xea\x01\xb6\x84F9\xbf\xa1\v\a\x98\xef\xbal\xf4\xff\xba\xb3:\xefSr\xa5\xb7\xee\x00\xea\xad\xf3EO\x89k\x13\a\xc4\xf7=;\xfd8\xea+X\xbd/\xce\x14\xc6\x12\x91\x17\x84ެ($+\v墆wq@\x1fY[\xd3\x19\xed\xac\x91;\xc9\xddc\xa1\x18\x8a\xe6\x99\u007f\xc4ҫ\xe0*N#Q\xecZ\x96Č\x9a\x19\xf4\x1b\x88Iԧ\xe4\xee\xb1\xd6h\x94\f0\xaa\xa6\xbf\xba\xb1\xc2:\xeb\xea\x15\xef\x03\t\xd3\x01ЛsxZk,\xe4\xeb\x8d-\xab\xe6\x86+\x83\xfb\xa2Q\u007f]4JO#=QV\x87%#pMҨ\u007fGK`\xebnu\x12\xd7O\xa6\xd2\xcdV\xa1\xa7\xf3j\x05\x8b\x06\xca=\xde%\xea=ޑ\xea\xc2)U]t\xb1o\xc9\xcc\xfc\x8aN\xb2\x94x\xbd,\xaf\xac\x8d\x9es}\v\xa7\x95\xac}\xd3'?\xcb\xc7j\xf4*3\xbdGM\x85%Z\xe7\xf8\xa7/m\x9f\xe3\xabfK\xd8^\xd5X\xe2+\xaaN:u⫦\xe5V\x1f\xa4\xf7x˾\xc3\xe4\xb7S\x8b\xda\xc4\x01\x11\x99\xfcB\xbbJV\xee\xd0\xd6\n\xe3\xe8,\xcf+x\x94ʪ\xa2\xbd\xa14o\xfaB\xf2M\x97h\x98S \x17\xcciL\xd0\x12B\xb8[,2Of\xb4*\xf8\x8a\xd3H\x14\xbb\x96\xa5\xd5\xdfJߙDթ\xb3f\xd2\xe7\xf6U\xe7\xe6\u05fch\x99\x87x\x01\x8d\xf4\xfd\xd9t\x00\xb4\xe6$\x8a\xf0\xfe\xe4\xcby!\xd3\x1c\xfc\xb7j\x15\xf4\xd8뉲:,\x19\x81{\x92N\x83\x17\xe5?\t\x16\x01\x00HfDH\x1a\xfe\xab\x12\x00ReDH\x1a\x00\x80T\x01I\x03\x80\xa7\x00I\x03\x80\xa7\x00I\x03\x80\xa7\x00I\x03\x80\xa7\x00I\x03\x80\xa7\x00I\x03\x80\xa7\x00I\x03\x80\xa7\x00I\x03\x80\xa7\x00I\x03\x80\xa7\x00I\x03\x80\xa7\x18I\x92\x86[\xbd\x01\xc0\x11\xf7$m\x18\xe8Ě\x94\xe7\x149\xf8BX\x1b\xe8\x10\x86\xcdF%U\xb7\x98\xa1\xe3\xd8t\xc7\x00\x95\xa1\xda\xf5\xa4it#&\xd5FR\xd2O\xeaP\xf7-\xf3pMҌ\x81ι\xc0\xfe~\xccI\x87-\xac\rt\b\x86\x8d\x8a#i\xfa\xac\xa4f\x95s\x018:\xc08\xedۅ\xda\xf5\xa4it#F\xd8H\xcb\xec\b\x92j\x9fɡ\xee[\xe6ᚤ\x19\x03\x9ds\x81\xa3N\xd1\xc8\xde@\x87\x90\xfa\x03^\xd3\xf5YI\xd1*g\xe88:\xc08\xec\xdbE\xb0\xebI\xc3\x15\xc3\nQ#\xad\xb3\x93\x9cT\xa7L\x0ey\xdf2\f\xd7$\xcd\x18\xe8\xa4&i;\x03\x9d\xf4H\xd7g%E\xab\x9c\x8b\xc0\x10\v\xbb\bv=\x17A\xd2\"\xacw(9\xa9N;?\xe4}\xcb0ܓ4\xd2\rtR\x92\xb4\xad\x81\x8ea\xa3\xc2\xf8\xc2\xe0\xc5\xd6\xfa\x99\xd3\xc8\x13|\x18\xff\x16\vC\x1a\xc3\xf6\x85s\x96\x11\xb9\xc50\xf6,|a\x9a\xf5\x8c\x85\x05\x8f\xd8\xd5\xc5\xc2\x01F\x14\xc0{\xdeh\xa4c\xd7s\xe1F7LR\x11c\xb6#l$\xbfC\xf6\x16<\xe2Lr\xf8W\xd5Ϡ\x15w\xe1\xb8\x17ս0`\xf7-\xa3qQҺ\x81ι@ǖ@s\xd8\xf4\xe0;\x13\xb6\x06:\x86\x8d\n\xe3\vC\x16K66\x96\xe4\x1df\xfd[,\fi\f\xdb\x17\xd6YF\xe8\x16\xc3سp\x85\xe9^/\x16\x16<\x16\xae.B\a\x18a\x00\xe7y\xa3\x93\x8e]υ\x1b\xdd0Ie\xcdv\x84\x8d\xe4Z\xe6`\xc1#\xce$\x87_.\x0f\x85\xcapű}%\xf5\xa7ս0`\xf7-\xa3qQҺ\x81ι@S\xf7ў\x96f\xbb+\xde\xf6\x06:\x04\xedѯ\x86/\f\xf2\x97\xe0\xd1\xfd\xf9\x12b\xe7h<\xe1V<\xc2cm_\x8c\x12\xc4n1\x9c=\x8b^\x18\xe3\xf5\"\xb6\xe0\xb1vu\x11<[^\x1c\xc0\xec\x1bK\x1av=\x17ntc$\x95\xdbcq#\x99\xa7\xf7:Y\xf0Xd\xd2\xc0_\x8aO\x90\xf8\x1cr4\x1bIg\xfe\x94\xf9\x87Lc\xdf2\x1a7%\x8d\xd4\xe7x'\xba\xc9\xc9\x15k\xdam\x13ho\xa0C\xd0\xcf(\xf2\x9coE\xbc\xfe\xff \xafm\xf2ygI\xb3\xb6/z\t\x16n1\x9c=\x8b^\x18\xe3\xf5\x82\x84\x16<֮.\xa9K\xda\xd87\x964\xecz.\xdc\xe8\xc6H*\xb7\xc7\xe2F\xea-s\xb6\xe0\xb1Ȥ\x81\xffE\xf2J\x8f\xe6q\xf90\x8a\xe7\x9b\x1f\x00\xca\xec[&㚤\r\x03\x1dmMx\xabe\xb0\x93\x81\x0eA?\xa3\f\xf1*C\xc1(yb\xbf\x93\xa4Y\xdb\x17=\xd6\xca-\x86\xb5g\xd1\vc\xbc^\x90Ђ\xc7\xda\xd5%uI3{\xc1\x90\x86]υ\x1b\xdd\x18I\xe5\xf6X\xdcH\xbde\xce\x16<\x16\x994`\x8e&\xfa\xd1Z\xf4\xee\x14\U000d78f1o\x19\x8d[\x92f\ftPG\x90.\xee\bZ\x87;\x18\xe8\x10D\x92\xa6\x97ѨE\xad\xe1\xdf\xc2\xf8\xac0\xb0\xb6/z\t\x16n1\x9c=\x8b^\x18\xe3\xf5\x82\x84\x16<֮.\xc9\x0e0\x16\x01v\x92Nͮ\xe7\u008dn\x8c\xa4r{l#iҲ\x14,xę4\xf0\xd3_.\xe9\xd1D;\v\a\x05\x16\x96\xfa\xbee4nI\x9a5\xd0\tn!\x8bg\x02\xfb-\x83\x9d\ft\b\"I\x17\xe1\xb3v\xe0\x8ej\xc4\xfa\xb7\x88\riX\xdb\x17\xa3\x04\xb1[\fgϢ\x17\xc6x\xbd0=\x0e\xe3\x16c\xed\xea\x92\xec\x00c\x11`!\xe94\xecz.\xdc\xe8\xc6H*\xb7\xc7\xe2F\xea-K\xc1\x82G\x9cI\x03\xffL\xe2\x98[J\x8e&\x1a,\xdc9-\xf9\xc1\xfb\xfa\xbea>\xdex\xa1\xb7ÍT\\\x934c\xa0s4\xb0\xed\xd0ѽ\x81\xa0\xf5\x90\xc9\xc1@\x87\xb1Q\xe1|a\xc85\xd2\xf69S\xc8\x06\x8c\u007f\v\x12\x19\xd2\x18\xb6/l\tb\xb7\x18Ξ\xc5(L\xf7z\xb1\xb4\xe0\x11\xb9\xba\x88\x1d`\x84\x01ܾ\xb1\xa4l׃.\xdc\xe8\x86M\xaaa\xb6c\xd5Hc\x87\x9c-x\x04\x994U\\s R5E9\xfc\xeb\ue612|\xba\xe8\xfb\x86Y(/H\xfa{f\xe0\x9a\xa4Y\x03\x9d\x13\x1d́`\xb7\xb5\xa2\x9d\ft\x18\x1b\x15\xce\x17ƿ\xba\xbe`F-=\xffY\xff\x16\x91!\x8da\xfb\u0095 t\x8b\xe1\xecY\x8c\xc2t\xeb\x19\v\v\x1e\xb1\xab\x8b\xd8\x01F\x18\xc0{\xde0\xa4l\xd7C\xb80\xa3\x1b.\xa9\x86َU#\x99\x1dr\xb4\xe0\x11d\x92\xa3\xb4qI\xbeZ1\xb9\x81PtEE\xdb7L\xfb\xf4vA@&\xe0\x9e\xa4\xd3`\xa8\x06:p\xbf\xd10py$5\xe6\xcfLë\x14\x18\x11\x92\x1e\xea\u007fU^\x1eg\x9fǸ<\x92\x1a\x82+\xdbV\x8c\bI\x0f\x95\xcb\xe3\xec\xf3\x18\x97AR\x1b#\xa8\xba\xc1)(c\U00070915\v5\xc0E\xe5rHjL._Yt\xde)*c\xf1\xb0\xa4\xe9\x85\x1a\xe1\x8df\xc0\x90\xb9,\x92ڐ_m\xbe\x11\x1e\xd0\xf1\xb0\xa4\x01 \x13\x01I\x03\x80\xa7\x00I\x03\x80\xa7\x00I\x03\x80\xa7\x00I\x03\x80\xa7\x00I\x03\x80\xa7\x00I\x03\x80\xa7\x00I\x03\x80\xa7\x18I\x92\x1e\xea\xad\xde\x00\x90A\xb8'i\xc3@\aӳ\xad\xa9e\xaf}\xbc\x83\x81\x0e\x00\x00\x04\xd7$\xcd\x18\xe8\xa0xG`\xf7\x91\xbd\x81C\xf6[\xd8\x1b\xe8\x00\x00@pMҌ\x81\x0e\xea \x9e\x1b'\xe9\xa25N\x06:\x00\x00 \x17%\xcd\x18\xe8\xf4+O\x1d;g\x1f\u007f\xf1\ft\x00\xc0ø'i\xa4\x1b\xe8\xec\x0e\f:\x19\xb99\x18\xe8\x00\x00\xa0⢤u\x03\x9d`\xb0gk\xa0yׅ\x18\xe8\x00\x00\xa0ࢤu\x03\x9d\x16j\xa0\xd3\xdcra\x06:\x00\x00 w%\x8d\xb4\xe7xӾz \xb0\xc7&\xd0\xd9@\a\x00\x00䢤\x19\x03\x1d\xd59'l㶑\x82\x81\x0e\x00\x00\xc8=I\xb3\x06:{\x9b\xa8\xbc;.\xcc@\a\x00\x00䞤Y\x03\x1d\xc5:\xe7\\\xc0\xfa\xf6\xb1T\ft\x00\x00@.J\x9a1\xd0A{\x03{\x8fv7m\x15ش\xaa8\x19\xe8\x00\x00\xa0⚤Y\x03\x1dt(\x18ز\xd7Zю\x06:\x00\x00\xa8\xb8'\xe94\x18\xaa\x81\x0e\x00d\x1e#B\xd2\xf0_\x95\x00\x90*#B\xd2\x00\x00\xa4\nH\x1a\x00<\x05H\x1a\x00<\x05H\x1a\x00<\x05H\x1a\x00<\x05H\x1a\x00<\x05H\x1a\x00<\x05H\x1a\x00<\x05H\x1a\x00<\x05H\x1a\x00<\x05H\x1a\x00<\xc5H\x924\xdc\xea\r\x00\x8e\xb8'i\xdd@g\xb0)\xa0\xd0l\xbf\x81\x9d\x81N\xef\x82\u0082\xaaH\xd9>\xf36\xb6<+\xcb!\xa7\x18\xf2\x88a\xb9\xd4)\xe6\xa2\x11\x99\xbe\xd3)D\xe7l}Q\xee\x02LJ%#T%\x93\xfd\f\xe1\xd7*\xa7P\v,\x12U\x87\x8b\xcc\x13\xfd\xf7z\xaa-\xa3\xa4\x91_-;\x96\x15'\x93\xda1\xf6\x14\xaeI\xda0Љ\x05\xf6\xf6c\xf6*\x0f\xe8\xb7\xc6\xc6@\xa7\xd7\xf7h\xe7\xf6E\xa9\x1e\xbdH\xaf\xf2~*\xeak\xb4\x8f\xa4\x1c\xa8\xf3;\x85\xa4\x88V\xb1\xf5ڮ\xbc\xd4v\x81P]\xd4V\x97w\xde)\n\xa1\xbe\xd5r$\x86bQyuj*H\xc6\"Qǣ\xd16Y\xf4-\x9aj\xcb\x14\x04\xf9\x15'Jώe\xc5ɤr\x8c-j\x1b\xa9\xb8&i\xc6@\xa7\x9b<\xd9d\xa0i\x97\xfd\x06v\x06:5\xd5\xe4\xb5.EI\xff\xdb\x12m\xc9\xefx\xb8\t\x8d\x17K\xd2FŖkS\xed\xdb\x10:/\xb7\xa2\x84\xfd\xb3\xcfUZe\xf2\xa0\x89\x04\x8e\x1f2V\x89:(RV\xea-SHί8Qlv\x84\x15\vq>\xc6V\xb5\x8dP\\\x934c\xa0Cٶ\xc5\xfa\xa9&\x14;\x03\x9d\x92\x06\xf2\xda+w\xa2T(wK\xd2\xe5\xc2sG\xbc֑>9\xd51\xfa\xa5\x96t\xea-SHίsJ.\xa6\xa4\x9dk\x1bQ\xb8'i\xa4\x1b\xe8\x10z\x02'\xeccm\rt\x96\x16\x1d&o]\xb4k\xd8^\x95w\xcfj\xa5\x93`\x165v\xca\n\xe5\xe4\x83\u007f\xed\xea{\xf2j\x8e[\xc5\xe2q[\xed\x8c)\x8bԁa[y^Y\x9b\xb2\xbaoQ\xa1\xafh\xc1)\xb4R\x96\xb7+\x93\xc1D\x91\xefř3\"\xab\n\xaa\a\xd8\xc2Vʾv\xb5\n\xb6\xe2\x81%3|%\v{M\xcd9\x9f'\x1bs\a\xad6\xa6\x04\x86\xc1Be\xb3\xd5\\l\xafO\x96\x1b\xfajKrk\xb8\xceސ\xb4Q\x18\xd7^\xa39\\\tњ\x12_\xe1\x82\x12R\x84\x91(#\x96\x90\xac\xac\xb4Z\xc6\xe5W˙8Q|v\x8c\x8a\x99F\x1a\xb0\x8d\xf4\xaf\xaa\x9f1m\xa12\xe70\x92\xaa\x1d7\xfe|\xf0\x04.JZ7\xd0!\xb4t\xd8\xc6:\x18\xe8\x1c/\x91k\x1a\x0f(\xdd|\xbd\xbc\xaa\xabuzy\x82_\xd4\x19\xd8\x17\x9dS\x1d\x8dF\xffL>\xf8\xe5\xd2\xd0\u03a2E\xa6\xcd\f\xfa\n\xeei\xdfY#\xd3S\xae\xce\xdf\xd0\xd5\xe0\u007f\x8a,F\xf2\xcb_\x8d4b\x89(35:\x19\x8c\x14ȫ\xab\xe5\u008dE\xadla\u007f\n\xf9\xe4鍿\xce_\xc4W\xdc%\xd7GB\v僦\xe6\xf4F\xa3Z\x9f\xa2\xd7Ɣ\xc0\xd2\x1b\rɍ\xd1\xe8i.6\x1e\n\x95\xccɟ\xb9\xbaV\xe6\x12dH\x9a)\x8cm\xaf\xd1\x1c\xb6\x84\xdf\xcaO\x85\"\xed\x852I\x89\x91(#\x96 \xe8,\xd3i\x19\x9b_=g\xe2Dq\xd91*f\x1bi\xc0n\xe6\x97\xcbC\xa1\xb2<\xf2\x9d\xaf7\x879n\xdc\x01\xf0\x04.JZ7\xd0\xc1\x1c\xa13k\x1b\x1c\ft\xceo\xac\xf0\xc9S\xc8wx\x97\xfc&\"G<\xc4-r0\x03\uf8b3\xf8\\\x9a\x8e\xacb\xab\xe6\xe0^#QFN\xb9w\xe5\b~\x8d\xc8]\xf8\xfc,\xa9\xc1\x1a\x19\f\x91\v@\xf4$\xa3#ǢZ\\\xc8NTW\xcf\x17柂O\xe2\xda\xe9|ű\x10\x19\x0e\x94-\xe4\xd7\x12r\x95\x93\x96\xa9\x8d+\x81A\x1f\u07b2\xb1\xa8\\\xa6\xdd.\x17\xc9\x0e\xbc\x8d\u0098\xf6\xf2\xcd\xd1Jh\x9bNt\xd2V@%\xad'\x8a\x8bu\x18x;\xb6\x8c\xc9/w\x00ĉҳ\x83\x8c\x8a\xd9F\x1a\xb0\x9b\xf9K\xf1\xde\xc7\xe7T\x98\x92\xaa\x1f7\x18x\xb38\x15\xeeL\\\xed\x9d;Z\xec\xe3R0ЉG~D\x0e\xd6\xd2;\x06\x13\x98\x99\xf5\xdc\"\a#i\xf2'z`\x85\xb1\xe7\xe5v\xf2\xd6@\x02\xea\xcb\xe8\xaa\xd2:r\xf6\x19\x97H\x19I\x87\xf0y6\x80\xd6.\xe3\v\xa3\x8f\x1dO:wζ\xd5\xdcQ \x97\x99\xd6\"\xfd\xa4ej\xe3J`Ѕ\xc3Ƣr\u007f\xb2\x05 'i\xbd0\xa6\xbd|s\xb4\x12>\x9dQ\xb2\xb2\xbd7A\xc7>F\xa2\xb8X\aI;\xb5\x8c\xcd/w\x00ĉ\x12I\x9am$\x03\xb3\x99\xffE\xf2\xda&\x9f\xe7\x93\n\x92\x16\xe2T\xb8\x1d\x8c\x81\x0e\xa6\xc9\xfa\xb1\xfc\x14\a\x03\x9d\x83\xf4rY\xa2\n\u007f-\x97\xa9s#~\x91\xc3ty\x8c\x1eXal\xaf\x1cEZ@գtգ\x15\x9aD\xcc%\x14\xbd\x8b\x0e\xfa\x10Z\xb7\x8c/Lx\xee\x1c,*Y\xdb\x19\xad\xb6\x964S\x1bW\x02\x83.\x1c6\x16\x95\v\xe6\x84m\xf2\xdf\xf1kL&\xb3Ha{\xf9\xe6\xe8%\x9co_R*\x17\xbd\x8a\xb8\u0378X\aI;\xb5\x8c\xcd/w\x00ĉ\x12I\x9am\xa4\x01\xbb\x992X\x8f\xe2\xafa\xab\xa4\x82\xa4\r\x9c\n\xb7\x815\xd0!~\x1bG\xec\xc3\x1d\ft\x8aVҷ\x869xPyG/\xe5,\xb7\xc8A\x0fa;\xe93\x8c\x03+\x8c=KU\x80\xe8\xe5\x9b\xfa;誒:2t3\xf5Ҵ\x9b)\x8a\xa0\x83~E\"laI\xe7\x0e\xa9\xb8\xb4\x82\f\f\x17\x95\xf1k\tZ/m\xd4\xe6(i6\x16\x95\x9b\xe6܄(m\xaf\xa2\x1fF\xd2F{\xf9\xe6h%\xf4\x92\xdby\xfe\x1e\xca\xe5\xbf\t\xb8X\xa7^ڡel~\xb9\x03 N\x94H\xd2l#\r\xd8\xcd\xfc\xf4B];\x1e\x90$%\xb5\xc1tX\xbc\x81[\x92f\rt\xc8TZ\xbbL&\xc6\xc9@\xa7p&\x99\xd7&\xc8Y\x13Qfc\r\x1b\xb9E\x8e\xeaj\\\x8c2\xd1\xd5\xcfTqlE\t.\xb7/\x97\x04tр\x10\x19\xdbNJ\xaa\xc9@o\x15\xb9\ue7b7\x16\xd7[a\x92\b[\x18+H\xbd\xe2\x12rz'\xca\xcaL\xcdA\xfaI\xcb\xd4\xe6(i6V\xd8\xe3\fL#\xe3\x9a\xfai\x03\xc8B\xd2\\s\xf4\x12\x1a\xe5w\xc9[u=\xb7\x19\x17\xeb iǖ1\xf9\xe5\x0e\x808Q\"I\xb3\x8d4`7\xf3\xcf$\x17>J\xab\xf9\xe6\x18\xc7\xcdt\x00F>\xaeI\x9a5\xd0A=\x01;oig\x03\x9dB\xb9\xa8\xe1\xdd\xcejz\x93\xe0:yY\xa8\xb3^\xde\xce/\xb24\xfa\u007f\x8dc?%\xd7=\xeb\x0e\xa0\xde:_\xf4\x94E\xecἙ\x8d\r\xd3dߛ\x87q7\"\xaf\xebZ'גՑ\xdcҶ\xaeUt\"X5\xfdՍ\x15$\xe0\xf0\xb4\xd6X\xc8\xd7\x1b[V}\x9c)\x8c\xabB\xaf\x18\x9f\x88K\xda6\x96˅\xaf\x1e`\xd7\x0e\xee\x8bF\xfdu\xd1(I\x89^\x1b_\x82\x8er]\xf9\x00\x9d\xb5豉\x03\xf4\xeamҥ\x86\x90\xfclW=9g\x99\xc2\xd8\xf6\x1a\xcdaKh\x94\xf3\x1b\xba\xf0^D\xb860M\xff\x94\xdc\xc4\xd5\x1a\x8d\xf2\xfd[:-c\xf3\xcb\x1e\x00Q\xa2\x98\xec0\x15\x1b\x8dda\xf3\xeb\x97k\x0eD\xaa\xa6\xf4!\xee\x10\xeaǍ\xad\xcd\x1b\xb8&i\xce@\xe7\xc8\x16\xdbPG\x03\x9d\x8a\xf6\x86Ҽ\xe9ꏏ\x91\xea\xc2)U]\xe6E\x86\xf8\xaai\xb9\xd5\a\xe9\xfd\xbf\xb2\xef0\xf9\xb9\xf3Y\xabؾ\x85\xd3J־\xe9#\x01\x89\xd7\xcb\xf2\xcaڔ+\x00}Kf\xe6Wtҥ\xea\xdc\xfc\x9a\x17e\xb9\xbeH\x96C\xf9r^H\x99\rj\x85\xf1Uh\x15\xa3D\xeb\x1c\xff\xf4\xa5\xeds|\xd5\xec\xdaߪ\xd3I\xf2U\xa1\xd7Ɨ\xa0\x11/\xa0\x91>\xfaӋ\x1e۫l\xff(2\xd3U\x9eWNv\xcd(\x8ck\xaf\xd1\x1c\xb6\x84\xedU\x8d%\xbe\xa2\xea\b\xdf\x06\xa6\xe9uj{\xb9\xee7\xbd\x961\xf9e\x0f\x80(QLv\x98\x8a\x8dF\xb2\xb0\xf9-m\\\x92?\xa3V\xb9\xd8b\x1cB\xed\xb8q\x87\xc5\x1b\xb8'\xe94\x00\x03\x1d\x00H\x95\x11!i\xf8\xafJ\x00H\x95\x11!i\x00\x00R\x05$\r\x00\x9e\x02$\r\x00\x9e\x02$\r\x00\x9e\x02$\r\x00\x9e\x02$\r\x00\x9e\x02$\r\x00\x9e\x02$\r\x00\x9e\x02$\r\x00\x9e\x02$\r\x00\x9e\x02$\r\x00\x9eb$I\x1an\xf5\x06\x00Gܓ\xb4n\xa0\x83\xd0\xc0\xae-\x81-\xbb\x06\x1c6\xb03\xd0ѹ\xf4\x86)\xe9x\xde0\x88Mf:\xc9\xff\f\x92'\xd8\x1a\x8e@\x89\x869\xd3|\xd3\xeei$O'\x91\xab\x12\xd4\t\xc7\xf4\xbf\x84Cm\x83\x90\xce\xd2ܲPy\xd2\u007f\xa4ړ\x86\xa5\r0̸&i\xc3@\a\x9dk\xda\xdas\xb4gK\x93\xfd\x93M\xec\ft\xd26Ź\x88\xa4\xe3y\xc3 6\x99\x19\xd8\x17-Xt\x98s\x04\x8a\xc8\vں\xda\x17\xcaQ\x14\x8fȹQ\x14\v\xc9\x11\xf3\x03#\x84m\x18\x9a/\xcc\xebrm\xe7Z9\xdd\xc7\xf8\xa7ai\x03\f3\xaeI\x9a1\xd0\t\xb7\x90\xe7\xfe\f\xb6\x84m7\xb03\xd0I\xdf\x14\xe7\"\x92\xba\xe7\r\x83\xb5\xc9L\xe1Z\xc49\x02\xad. \x02\x8eOYM\x9e\bX[\x87\xd0\xc7r\xf2v\xa26\f\xc9\x17\xa6On\xc0\xaf\xabӕ4J\xc7\xff\x02\x18V\\\x934c\xa0ӱ\x95\xae\b\xda?\x9d\xdf\xce@'驟\x97=\xd6&3TҌ#P5}\xbe&\xaa\xa8!\x92\x8e\xe4DŽ\x92\x161\xa4\a_>5\x9d|\x81\xfcI\xe6\x1fϗ\n \xe9\xcb\x04\xf7$\x8dt\x03\x9d3M\xe13\xf13\xe1\xa63v\xb1v\x06:\xe9\x99\xe2\xe8\xf67HhSC檍\xa8QV&\xe5Z\t\x16\xce2ix\xde0\x01\xbcɌ\t*i\xc6\x11\xa8Jy\xb2\xe6\xa2*\"\xe9\x8f\xcbCI\x926\xda`a\xd7\xc3y\xff\xe8\xf0N8\x1a\xd3\xd6ҷ\u05cf[l\xc6fG\xe8\xa5\xc3x\xd3 \xab\x03\x00\f'.J\xda0Љu\xe0\xa5\x0e\xfb#og\xa0\x93\x96)\x8ea\u007f#\xb6\xa9\x89E\v\x1a\xfe\x86\xfe\xd6P\x10\x8d1%X9ˤ\xe1y\xc3X\xf0\xb0&3f\xa8\xa4\x19G\xa0\xb2et\xf5\xb22*\xe9\xd6\x05ɽ\xb4\xde\x06\v\xbb\x1e\xd6\xfbǀw\xc2QQ\x1f\x96\xaf ڌ͎\xd0K\x87\xf1\xa6\xb1:\x00\xc0\xb0⢤u\x03\x9dxGKO\u007fOK\x87\x9du\xa5\x83\x81N\x1a\xa68\x8c\xfd\x8d\x85MM\xfdR\xfc\xb2\xac\xde\\\x82\xd0Y\x06\xa5\xeey\xc3\xd9\xc98\f\xbc\x19G\xa0R\xe5\xf9\x89\xb5\xa5TҧsO\x8b\x06\xde\xda\xd3p\x85v=\\\xc5:&o\x1a\x85\xc3\xca\xc5\xf4x<n\xb5\x19\x93\x1d\v/\x1d\xe3\x01\xc1V\x0eF\xc0p⦤\x91\xfa\x1c\xefp\v\xbd\x00\xd4bg0\xedd\xa0\x93\xb2)\x0ek\u007fcaS\x13ɍ\xa1X^\xd4\\\x82\xd0Y\x06\xa5\xeey\xc3\xd9\xc98I\x1a\xe9\x8e@j/\xbdT\xe9\xa5тV[I3\x15\xeb)\xe1*6\xe0\xbdi\x14\xfeN{\xe9e\xf4w2\x8b͌\xecXx\xe9\x18\x92\xb6r0\x02\x86\x13\xd7$m\x18\xe8$\x02\xfb\xb5E\xcbh\a\x03\x9d4LqX\xfb\x1b\vG\x95Da'\xea,L\x98K\x10:ˠ\xd4=o8;\x19\aI3\x8e@UJ\xf3\x17*si\x14*\xb3\x954S\xb1\x9e\x12\xaeb\x1d\x937\x8d\n\xad\xfdt\xa7\xbc.n\xb1\x19\x93\x1d\v/\x1d\xa7\x03\x00\f/nI\x9a1\xd0\xd1$\xfd\xa1\x8d\xa4\x1d\ft\xd20\xc5a\xedo\xacljV-D\x8b\xe8\x158\xde\xd5E\xe4,\x83R\xf7\xbc\xe1\xecdD\x92NЉ/\x15\x15\xe3\bT\xad|\x93\x94\xd7(\x92\x8e\xe5Eґ4I\tW\xb1\x8eɛF\xe5\xa9\"\xf2\x85\xd7I\xae4\x887c\xb2c\xe1\xa5cx\xd3X9\x18\x01É[\x92f\rtv\xa8\x03\xef\x1d\x96\xc1N\x06:\xe9\x98\xe20\xf67V65\a\xfc\xa7\xfc\xc4\a\x83/A\xe8,\x83R\xf7\xbc\xe1\xecdD\x92n#\xaeUg\xe5\xd7\x11\xe7\b\xb4:\x9ff'\xaf^\x914\xaa[\x96\xa2\xa4\xf5\x94p\x15똼iT\x94ߥ\xab\x89\xa4ś1ٱ\xf0\xd21\xbci\xf8\x03\xf0\xf1F\xb8\xbd\xecR\xe0\x9a\xa4\x19\x03\x9dXsK\xf7\xb1\xee\x96f\xebK\xdeN\x06:\xe9\x98\xe2\xb0\xf67\x1665\x89\x1953\x94\x11\x83^\x82\xd8Y&-\xcf\x1bƿ\x855\x99a\x1a&/\b\xbdYQH\x9c\\\x18G\xa0\x88\\\xd3\x19\xed\xac\x91;\xc9\xddc\xa1\x18\x8a\xe6\x99$m\xb4\xc1®\x875\x8e1\xe0L|\fZ\xe5\xfa\xaez\xe5\xee1\xe1fLv,\xbct\x18o\x1a\xee\x00,\x94\x17\x98\x8b\x02\x86\x01\xd7$\xcd\x1a\xe8\xc4\xf7l\tl\xddcm\x8b\xe5h\xa0\x93\x96)\x0ec\u007fceS\xd3\xea\xd7\xee\x9e\xd2J\x10;ˤ\xe3y\xc3\x04p&3\f\x9d\xe5y\x05\x8f\x1e&K\x8c#P\xa2aN\x81\\0\xa71\x81\xc5M~\rNT\x14\xf1_\x05F\x1b,\xecz8\xef\x1f\x1d\xceć\xa1\xb34\xaf\xa2\xab\xa4\xcbj3dd\xc7\xc2K\x87\xf5\xa6a\x0f@\xfbt\xe6\a2`\xd8pO\xd2i\x00\x06:\x00\x90*#B\xd2\xf0_\x95\x00\x90*#B\xd2\x00\x00\xa4\nH\x1a\x00<\x05H\x1a\x00<\x05H\x1a\x00<\x05H\xda]6_0N5\x00\x19\x06H\xda]\x9c\x04\xeb\x8cS\r@\x86\x01\x92v\x17'\xc1:\xe3T\x03\x90a\x80\xa4\xdd\xc5I\xb0\xce8\xd5\x00d\x18 iwq\x12\xac3N5\x00\x19\x06H\xda]\x9c\x04\xeb\x8cS\r\x97\x92K\xfbD\xa2K[ۈ\x01$\xed.N\x82uƩ\x86KF\u007f\xe5u\xd2\\\x84\xe6I9\xf3{\x9cb/\x1c\xb56 \t\xefK:8\xf9\xa4Sȥ\xe1\xcc\xe4`\xf2J'\xc1:\xa3\x16\xe4\xfan&&N\ft\x1c%\xffa\x17\x98\x983@W\t\xf7\xf8\xe2\xa0\xd5\x06$ឤ\x19\x03\x9d\xc4\xfe\xad\x81\xad\xf6\xdf\xec\xff\xbb\xe1;\xb3\x9f\xfe\xc26D\xcc\x1ai\x85\xbatd\xb44\xd164\x897\x8a1_\xff\xfe[_:\x05j|2\xab\xf8\x01뿮\x19\xf5\\ҺoK\x84\xeb\xff\xaf\x93pu~v\xa5t=\xb7B-[\xdfM!\x1d9C\x12י\x1f\xe4dߞ\xe2\xf8\xb6[ڦ-\x86%\xe595\xc2=\xbe80\xb5\x01<\xaeI\x9a1\xd0I\x04\x03\x1f\x1e\xd9\x1b\xd8k\x17\xfe\xe4}o\xbd0\xfb3\xbb\b1\xebG5\xe9˻+\xb3l\"\x05|\xf6\x9b\xe2\xb7?z\xff\xf9\xe2ל\x025\xbe\xfc݆;m\xfe\x1c\xbcb\xbdy\xd5+ߖ\x1e\xfc\xc9\xe37KwY(8\x99\x9f\xdcr%\xf7\x99\x16\xc3\ue988`\xf6\x96\xe4\x95;l3N\xb8\xed\xba\x97*\xb3\x1d|\x8d4\xf6Hacq\xb7\xba$\xd8\xe3\x8b\x03S\x1b\xc0㚤\x19\x03\x9d\xfd\x813tŀu\xf4g\xc5o\xa0/\xfea\xfdw+\x8e\x8c^\xcc|Z\x91\xaa\xa4ONUF\xb1\x1f\x14\xff\x11\xebtC\xf1_\xec\xc3\x19^\xb3\x934Z\x9ee\x1e+n~B\xfa)\xd6\xe5\xad\xd2\xcf\xc4\x02\x16\xf0\u007f\x92%\xcd\xef\xa6\bQW;y\x9e`%\xcb\x19i=J\xd8\x1c\x15\x0eC\xc7\xecb\xf2\x1e_\x1c\x98*\x00\x1e\xd7$\xcd\x18\xe8\xa8\xce9M6\x9d\xc6'\xc5\xefY\xffц\xca\xeb\xd832eIwK\xdd\xf4\x9dJ\x1a}~\xf7\x06\xfbp\x06{I\x0f\\WiZ\xa3J\xfa\x97W\xdd*֯\x00\x81\xa4\xf9\xddL\x95IN\x92>$\xa51\\\x17K:y\x8f/\x0e iKܓ4\xd2\rt\xb6*c\xa8\xa0\xd5\xec\xe8\x8b\xef\x14S^FhCq\xf1;\xea\x8cuC\xf1\xac\xb7^~`\xf6\xd3\xffCc>y\xe6;\xb3\xeeS\x97\r\xe2c\xb5ޫ\u007f\xfe\xb8\xab\xbf\xa5\x0e\xbc\x9b&gOxD\xd1\xc0\xa1o匾\xee\xf6~n\xa3\xf5\x13\x82=ROp\xc2K\x9a\xa4ц\xef\xe0\x97/\xdf\xfe\xf1\xdd\x0f\xbc\xfc\x99\xd61\x82\x00\x00\x0f\xfaIDAT9\r1j\xfb\xf2\xad\xc7f?\xfc\x06\x9dl\xff\xcf\xf3\u07fd\xf7\x19e\xe0\xad\xc7\xfeqVq\xf1\xa6O\x9e\xbf\u007f\xf6\xd3\xff\xa4\x1b.\xcf6=`M\x95\xf4\xe6[ǐ\xd7\ao\xbc\xea\xfao\xfc\x92*\xf5g7\x8f\xb9r\xccW\u007fN\x16\xbfw\xc3U7|\x8f\xae\xfc\xf9\u05ee\x19s\xb3:\xf0\xd6b\x91\xb1\x9b-xZ\xbe\x02\xad\xc0\xaf-l\x1d\xe7\xb2%iT3Y\xfa\x814:\xf0Ȅ\xec\xdbq\xcf\x19\x94\x14&\xd1\x10-%\xfb\xaf\x90\xa4\xe5\x87\xe6\x8fϾ}0\x9e\xa3\x04<BJ\x987n\xf4\xb8\xb9\xea\x04\x99\xc9\x19\x93I<\x81\xd6E\xd6͌\x8a\x93\xf6\x18\tkc\x16q\xc0K\x93\xb2'\xe1\xf4#~-K\x18$m\x85\x8b\x92\xd6\rtv5\xd1g`\x06\x04\xd3=\x85?|\xf4N\xf1k\x1f}\xf4W,\x9b\x8ff\xbd\xa6\xceX\xff\xfb\x9dY\xc5\xf7\xbd\xf6\x9b\xbb\x9f!\x11\xffy\xf7c\xbf\xf9\xe05<:\xe7٫\x9d[\x87\xc6N\b\x04o\x93\xa8\xa4+G=\x14\\\x9f3\x89\fE\xc3c'\xad\xe9X!\xad\xe16\xea\x9f/M\x94n\x92\xe6\x1d\xd3%\xfdV1\x1e\xf3\xbfP\xfc\xf2\xfbo\xdc\xf70\xb9D\xc7\xd4\xf6\u009d\x9b\xde\xdft\xe7\xf3x铻\x1fx\xfb\xbd\xa7\x8b\xa9\xa4\xf5\xd8\xcf\xdfy\xe7\xfe\xef\xdf\xfdݗ\x9f\xff\xfa_iٻ\xccg\xa2&\xe9\xefIX\x9d\xb7H\xb7>\xfe\xbd17\xfc\n\u007f\xfe\xc9U7|\xfb\x89\xbb$\xa2\xe4[\xae\xbc\xeb\U0007bbbc\x85\xc8\xfc\xaa\xeb\x1f|\xfc_%*i=\x16\x19\xbb9\x10\x1e\xbb\xfc$:\xb9\xfc\xea0\xdfi\xef\r\x87\xb3\xe8ճ\x9e\xe6+\xa4\x9c\x15k\xc6~\x8bxz\x87'L\r\x87\xc3\xf4\xaa\xa4\x9e\x92XK\xf3W&\x8c\x1d\xf7\xc8|\xe9(\xda\x1fn\x96V\x84\xc3D\xbbA\xa92\xdc2w\xd4\x1e\x12\xcb\xe4\xcc\xc8\xe4\xe0\x89\xf0\xe4\xab\xf5J\xe39\x93w\x1dS\x87\xfaI{,\xae\x8d\xad\x18Uf-\x0f.Ϛ\x8f\xb8\xe60\xf0\xb5\x01<.JZ7\xd0\x19h\n\x9e\x8c\xf5\a\x03-֡\xc6\xc0\xfbNr\xadJ\x19\xde\xdey/\xee'\x9f\xbf\x0f/}~\xffӸK\xfc\xe2\x1d\xf3\xf5\xb3\xa0tDY\x98:\x9e\\\x86\x9b\x94E\xd7\x05\x10\x19\xb8\xe1n+6\xee\xf68yڰ\xd9_o\xdbhi4\x1d2\xa8\x92~\x1fO\xa6\xdf+~\x1b/\xfd\x1e\x0f\x12\xd8\xda\xde/\xfe\x80\x86\xbd\x8fЏ\xbfOV>LZ\xc6\xc4\"\xf4p\xf1\x93\xff@_\xaa\xd7\x01\x8eJ\xa6\xef-M\xd2O\xe0\xc9\xf4\xe3҃x\xe9ߥ\x1f\xe2\x81\xf85\xff\x8a\x85\xfd\xcb\x1f\xbeB\xfe\xf2\xc4f\xf5\xf5\xc6k\xb1\xee\u007fu\x03\x91\xb4\x11\x8b\x98\xddD\x95d,=O0\xd6\xcdV/\x88g]\x8d\xc51?\x87.\xeb\x03o&%x\xadt\x1b>&\xf4\x9a\x98>\xf0\x1eh!\x02\xba\x89\xfc\x0e\xcc\xe4\x8c\xd9l.\xeeΙA\xfa6\xfc\xf1\x9b\xcab\xd2\x1e[֦/n\x93\xc8L\xacC\xb9\xa6\xcd\x04\xe8\x98j\x038ܔ4R\x9f\xe3\x8d\xce\x04q\u007f\xbd;hs\x94Ē~A[|\xbf\xf8\x0f\xc2Ͷ\xaa\xe7\xfa9z\x16\xa1\xe5D\xd2\xf3\xc6\xc7\a1\xe3*ɹ\xb3_\xb0љGF\x8f\x93\xc6e->\xa3K\xfa\xed\xe2\xcf\xd0\xf3\xf7\u007f\xf1O\xccw_\xe0j{A\xf9\xcd\xea\x81\r\xe8\xb3\xe2\xb7\xc8\xd2&\xd2\x1c&\x16K\xfaο\x1ae\x1fUNd\x03M\xd2\x0fJ\xafl\xbe\xf9\xda_\xfe\ns\xcd-\x9b\xb5\xb5\xb4;V~\xb3\xba\xfe\x96ͯ\xd0N{\xf3]D\xd2F,2v\x13w\xa1\xd9\x03h [\xf0@t]\xd2D\xee\xea5\x05]\xd2LJ\xf0Zゖ1\x97>\xf9\xd2\xed\xe3\xc7J7!.g\xccfG\xb7\xe9?Fc\x06rƯߡ6)i\x8f-k\xd3\x17+o\xa2o\x13\xcd\x01:|m\x00\x8fk\x926\ft\xc8[\xecL\x025\xd9xb\x89%\xad/\xbeQ\xfc\xb9p\xb3\xdd\xea\xa8O\x1d\x99\xd2Sy\x92:\x89\xc4]\xcezI\xf4\xe8\xf059\x01<\x97^\x9f\xf3\x9c.\xe9_\xdcM:[\x85\xa7\xb9\xda~\xfc4}{\xfa1\xdc'\u007fD\x96hs\x98X\xfc\xe11\xa6\xec=\x92i'5\xf1~\xe3\xaa͛oP[\xf6Uu\x1c\xaep\xe3W\xe9\xdbWo\xdc\xfcS\xe9'\xba\xa4\x8dXd\xec&\x1e\x92\xe6lE[s\x12(\t]\xd2\xe4\xdd,i&%\xf8\xc3$}#]\xd2{\xae\x1b\xb7xk\xf86\"5&g\xdcfxv\xbbG\xfb\xc3\x1eɰ\nO\xdac\xcb\xda\xf4ũJ\a\xff\xcdɦ\x00\x16\xa66\x80\xc7-I3\x06:\xf8D$K\x87\x02\xfcU*\x0e\x93\xa47\x99$\xfdA\xf1\uf15b\r(SHtF\"\x17[\x10\xbd<6\u007f\xfc^\xcaI2\xb6\xfbP\xb4U\x9c^\xf1&\xf3{E\xd2_\xdc\xf7\f\xe9y\u007fO\xf9\x8c\xab\xed\x85\xfbɕ\xb1/\xef\u007f\x01\xfd\xaf2\x91\u007fA\xe9\xa5\xf5X,\xe9g\x98\xa2W\x8c6\xfdʫ]\xf1\x1es\xf3\xe6\xcd_\xbb\xf6\xa7\x94\x9f\xf3\xbd\xf4\xb5\xf4\xedZ\xbd\x97\xa6\x97njXd\xec&桹h\xeeC(\x19KI\a\x8er)\xc1k\xbf\xa5o\xa4Kz\xe2d\xd2'~\x8bH\x9a\xc9\x19\xb7\x99\xc5\x15\xef\xe4=\xb6\xacM_\xac\x1cO\xdf\xc6W\x9a\x02X\xe0\x8a\xb7%nI\x9a5\xd0\xe9\t\xe0\xa3{\xae\xd9\xee\xde\x01Cҳ\u007f\x815\xf6\x98I\xd2\xff\xb8\xefIr\xd9\xea\xe5\x97\xcd\xdb\xcd\x1b\xaf\xf4X\x93\xc7\xe1a\xf4\xa1,r*w(\x97\x83\x97?G~a\x99J\x84\xfbP\x92\x06\x8e]}\x8c\xbe+\x92\xdeD$\xfc\x8123\xde\xf4\x1b\xae\xb6\xf7\xe9\xdaw\xc8\\\xfa\xb1\xfb\xb1\x82\xff2[\xf9\x86\xd1cyI'&~\x13\xf1\xa8⽋\xbc>Af\xd1x\xf9ۛ7\xbf2\xe6_H7}\xeb7Ȭ\x99\xac\xfd\xa1\xf48\uec2fy\x85\\##\x926bI)\xdan\xe2\x0e;\xab?Kt\xb2\x8b$=u*B'H6\x98\x94p?m\xe9\x92\x1eGt\x95\x98D$\xcd\xe4\x8c\xdb\xccB\xd2\xc9{lY\x1b3\xb5'c\xf5f\xa5r\x8b_\xda@Җ\xb8&i\xc6@\xe7P`ϱ\xfdMA\xebɑr\xc5\xfbw\xf4~\xd0\x1f\xdf\xf7\x9b\xd7\x1e+\x9e\xf5\xf6\u007f\xff\xf5\xa3Y\x1b~\xf7\xe5\x1f6\xcc\"W\xc2\xffs\xf6\x03o\xbd\xff\xb22\x9de94J\xb9\x9aݝ=n\xc5\xf2\x9cQW\x90;[\x16K\xf3Z\x82\x95\x12\xb9\xddjG\xd6ė\xb6=\xa4L\xb4\x05pw\x8fm\xfa\xfa\xf3\xef\xbc\xf7\x02\x15+S\xdb\xf3ś\xde\xdbTL\xaex\xffq\xf6w_\xdbt/i\x19\x13\xfb\xcf\xff\xfa\xe8\xfbO~\xf4\xd1'j\x81k$\xf3o\xef\xf4\xee\xb1'nQ\xee\x1e\xbbK\xfa\xda\x0f\x1f\xbf\x85^\xf8\xfa\xc9U\xd7\u007f\xef\x89[%r\xa3\xe8פ\xbb\x1e\xc7\u007f\xc1K?\xbd\xea\x9ao\xdf5F\xba\xf2\xc1\x9f1\xb1\xa4\x14m7\xb1\x84\xc6\xdd>\xce<\xee\x8e\xef\x0e\x87\xb3*\xc3\xe1s\xa8?<\xbar7\xda[9\x9a^\xc7^\x91\xb5f\xebm\xd9\xe4\xcbKO\xc9\xe0nz\x1d\x9c\u0383\x95+\u07bbIi+\xa4y/=7I\xcaY\xb3\x9b\xcb\x19\x93I2\xb9\xd1G\xd8\xc6D@\xb0\xc7\xe2\xda؊\xd1\xfcQ\x8b\x83\x8bG\xcd7\xad\xe5؛4\x9e\aT\\\x934k\xa0\xf3aK \xf8\xa1`\x02\xa8\xf2\xf9\xbdtf:\xeb/\xe4\xc3'Oξ\xfb\xe9M\xc5\xc5\x1b6\x90U\u007f\xb8\x1b\xbf\x92\x1bA\xfe\xf2\xccw\xef~\xec\xbd\xe4m\x97g)\x87\xfe\xd0ܜ\xf1\x8b\x03WH?\xc0\xcb\x1d\xb7\xe5\\=U\xf9\x11\xfcмqc'oM\xdeL\x81\xde\xe3]|\xbf\xfaE\xf1\xc1\x93߹\xf7\xc7\xef\xd3E\xa3\xb6/\xdexx\xf6\xc3o\xd0/\x9bO\x9e\xbe\xf7\xfe_\xbc=\x8b6G\x8b\xfd#3\xa9&\x17\xaf\x92n\xf2R\xee\xf1\xbeV\xf9\xd9y\xf3\x13\xff2f̍O\xd0ş\xdd|\xcdU7>N\x96~E\u007f\x97\xfe\x15]\xf9\xd51\xd7~\xe3\xc1+\xa5[\x99XZ\x8c\xb6\x9bx\xae\x9b\xc5\xff$\x87\xd93J\x99\xbc\x06\xd0\x0f\xf0\xeb\xe8\xeel\xfcJ\xf2\x10\u007f('{\xaa2%\xd5R\xb2_\t%=k\xfcj\xbax\x05\xf9\x95+\xb1fBVμ\xc0\xf8Ѹ_gs\xc6d\x12\x9d\xb8b\xde\xfe\x13\xf8 \xc6\xfb\xf7\xce\xcb\xd2\xe6P\x82=\x16\xd7\xc6,\xe2\xea\xd6ߔ}\xd3K\t\xd3Z\x0e\xad6 \t\xf7$}\x89xht\x8bSȥ\xa2yt\xa5\xf9\x8e\x89\x8b\xf6\x9fX\x97\xc1nn\x9dH/y͕\xa4\xafh\x17\xcaE{|\x91Pk\x03\x92\xf0\xbc\xa4њq'\x9cB.\rg\xae{.y\xa5\x93`\x9dQ\v\xba\x1cv\xf3\xc4~\xdc;\xf7\u007fxL\xfb,\xdc\xe3\x8b\x06\xad\rH\xc2\xfb\x92\xbe\xbcq\x12\xac3N5\x00\x19\x06H\xda]\x9c\x04\xeb\x8cS\r@\x86\x01\x92v\x17'\xc1:\xe3T\x03\x90a\x80\xa4\xdd\xc5I\xb0\xce8\xd5\x00d\x18 iwq\x12\xac3N5\x00\x19\x06H\x1a\x00<\x05H\x1a\x00<\x05H\x1a\x00<\x05H\x1a\x00<\x05H\xda+\xc0\r\xcf\x00\x05$\xed\t\xc0N\x06\xd0\x00I{\x01\xb0\x93\x01t\\\x95tw@\xfd\x97\x9d\xfe`\xa0Ý{\xf0\x19g\x19\v\xb7\x18{S\x9c!\x13\xbc:\xf5\a\xe2i\x8d\xac\x94$)\xfb\x90 \x00\xecd\x00\x1d7%}.\xb0K\xf9\xef\xf9c\x81\xf0\xa1p@\xff\a\x9eK\t\xe3,c\xe1\x16\xe3`\x8a3T\x16KN\x06\x19\x06Z#\x8f\x86\xc3/\t\x9f\xe6\x01v2\x80\x8e\x9b\x92\x0ev\x1c\xa3\x92N4\x93\xff\xdf\xdf\xd5\xec\xca\x05\x1e\xbdRk\xb7\x18{\a\x8d!\xb2\\Z\xee\x14b`dF\xfc\x80\x1exl\x0f\xa0㢤\xbb\x9b\x06\xfa\xa9\xa4{\x02䡓\xd4\x1e\xcbE\xac\xddb\x86E\xd2+\xec\xad&\xad\x00I\x03\x0e\xb8'\xe9s\x81CH\x91t\x872\x11\xdc&x\xfc\xf4\xf0b8˰n1,\"S\x1cda\xd7#r\xcd1\x1b\xe8\x18\xacQ<>\x8e\x8eU*\x96Ʋ\xf3\x0e\xc6\xe8\x86i$A,^\xb0\x93\x01tܓ41\xb7S$\xbdUyn\xd6.\xcbg\x80\r\x1b\xba\xb3\f\xeb\x16\xc3 4ű\xb2\xeb\x11\xb9\xe6\x98\rt\f\xd6KԦ5\u07b4^!\x10g\xfe\xc8\x18ݰ\x8dDBI\x83\x9d\f\xc0⚤{\x88\xf7\xac\"\xe9&\xe5\x91v{\xec-\x92\x87\t\xedi\xb8\u0081\xb7\xd8\x14Gl\xd7c\xe5\x9a\xc3\x19\xe8\x18\x04\xd4璞8\xa2`z\xcc\x10kt\xc34R$\xe9\xb9\x12\xd8\xc9\x00\x06nI\x1aϜ\x13\x89\xc4ѦDBw\xae\f_\xfa^\x1a\xd9K\xda\xc2\x14Gl\xd7c\xe5\x9a\xc3\x19\xe8\x184)\xcf\xca=\"i\xf0O\xb6e\x8dn\x1c$\rv2\x00\x8b[\x92>\x12\xd0\xe8G\x1d\x8a\x96\x82\x97|.M\xb0\x93\xb4\x85)\x8eخ\xc7\xca5\x873\xd01\xd8u\xb5\xa2\xcdpP\xc1\xf4+\x14\xfb\b}\aI#\xb0\x93\x01\x18ܒt\xe2$\xa1;p\xf2d\x02\x8f\xc1ɯ\xc1\xe7ܹ\xe2m'i\vS\x1c\xb1]\x8f\x95k\x0eg\xa0\x932\xe9I\x1a\xaex\x03:nIZ\xa1_\xfd]\x9atQ;\xdc\xf9]\xdav.-6\xc5\xe1\xedz\x8e<\xa7\f\x99\xad\\s\xac$m\xbf\xb7 i`\x88\xb8)\xe9D\u007fw\xa0\x9fx;\x1f\r\xec8\x12&~k\x97\x18\xc3Y\x86u\x8ba\x10\x9a\xe2\x98\xecz\xe6J\xb7+\xc1\"\xd7\x1c\x93\x81\x0eCp\xac\xcd%-\xd6\xe8\x86i\xe41r\xf7\xd8\xfap8)S`'\x03\xe8\xb8)\xe9~2\x95\xa6\xbf\xb8\xf6o\v\x04]\xb8\xc7\xdbp\x96a\xddbXD\xa68\x88\xb7\xeb\t\xe4h\x96Z\x02\xd7\x1c\xde@\x87e[\x8e\xcdm٬э\xd1Hz\x8f7!\xc9\xf9\r\xecd\x00\x1d7%\r\\4\xc0N\x06\xd0\x00I{\x04\xb0\x93\x01\x14@\xd2\x00\xe0)@\xd2\x00\xe0)@\xd2\x00\xe0)@\xd2\x00\xe0)@\xd2\x00\xe0)@\xd2\x00\xe0)@\xd2\x00\xe0)@\xd2\x00\xe0)@\xd2\x00\xe0)@\xd2\x00\xe0)@\xd2\x00\xe0)@\xd2\x00\xe0)\\\x95\xb4n\xa0\x83PؕG\x9a\x8c\x14\x86\xc9\xc4\a\xf0\"nJZ7\xd0A\xe8D \x13\x1e\x9e\xb5c\xafS\x84\x05\xc3d\xe2\x03x\x117%\xad\x19\xe8 \xd4ߒ\x11\x92\x9e\x9c\xf4삔\x19\x16\xc7\x0f\xc0\x8b\xb8(i\xdd@\a\x85\x03ጐ\xf4$\x9040\xec\xb8'i\xc3@\a\xc5\x06\xb4\xc7\xf3{\x82\xfdWH\xd2\xf2C\xf3\xc7g\xdf>\x88?5MΞ\xf0\xc8\x00\x1e\x93\xa8O\x19\x9aD\x9eC4\xaa\t\x1d\x19-M\xe4bY\xd7\x1c\x96\xe13\xf1\x01\xbc\x88{\x926\ft\b^\x92t\xac\xa5\xf9+\x13Ǝ{d\xbe\x84\xd5Y9\xea\xa1\xe0\xfa\x9cI\t4\xb0+<aj8L\xae\x03\xf6\x87G\xaf@hwe\x16\x17˹\xe6\x18\f\xa3\x89\x0f\xe0E\\\x934c\xa0C\xf0\x92\xa41\x93\xa4\xdb\xce\xe1\x81\b\xe9\x9b\xc9\xc3\x06\xf7H\xf4\xa9\x89\xc6\xc0\x9b}\xa6\xaf\x1ekr\xcdQ\x19F\x13\x1f\xc0\x8b\xb8%i\xd6@\x87\xe05Ig\xa9\xc3\xe7y\xe3ヘq\x95t\xadX\xd2Z\xac\xc95Ga8M|\x00/▤Y\x03\x1d\x82\xd7$=I[Pg\xd0\xf4\xf1\x9d\x16\x92\xd6bM\xcf\xe3W\x18N\x13\x1f\xc0\x8b\xb8%i\xd6@\x87\xe05Ik\x13\xe2\xf9\xe3\xf7RNҵD\xd2Ԃ\x80\x8awy\x16\x1f+\x94\xb4\x8b&>\xc0\x88\xc4-I+xw.\xad\xf5\xc7\x1dR\vy[\xfe\x1cy\x9d:\x15\xa1\x13tE\xf6b\xfc\xad69\x8b\x8f\x15JzXM|\x00\x0f⦤u\x03\x9dX\u007f\u007f`G\xbf\xc9ay\xe42\xb8\x9b^\xdbVT\xb6X\x9a\xd7\x12\xacT\x9cgWd\xad\xd9z[\xf61\xbc45\xe7\xb9\xe7&KW\x04z\x98X\xd65\x87a\x18M|\x00/⦤u\x03\x9d\xbdʬ\xfa\x9c\xd3\x06#\x84\xfd\x8a\xe5\xcd7\x95O\x1d\xb7\xe5\\=U1ˉ?\x94\x93=\x95\x0eG\x0eM\xcd\x1e{\xfbbI\xfa\x01\x13˺\xe6\xb0\f\x9f\x89\x0f\xe0Eܔ4\x00\x00\x17\x1d\x904\x00x\n\x904\x00x\n\x904\x00x\n\x904\x00x\n\x904\x00x\n\x904\x00x\n\x904\x00x\n\x904\x00x\n\x904\x00x\n\x904\x00x\n\x904\x00x\x8a\x8c\x96\xf4<)g>X\x02\x00\xde\"\xa3%ݿ#01g\xc0)\n\x00F\x12\xaeJZ3\xd0\x19\b\xb7\x04\x82\xfb\a\x1d\xa2\x87\x85\xb0\xb4\xdf)\x04\x00F\x12nJZ3\xd09\x17\bv\x1f\xd9۴\xd5\rM\xef\x91v;\x85\x00\xc0H\xc2MIk\x06:;Z\xc8\xf3\xc7\xce\x04\x86\xea\x18u!\x80\xa4\x01\x8fᢤu\x03\x9d\xad-\xf4\xf3\x0e\xdd\xc6\xf2\x12\x02\x92\x06<\x86{\x926\ft\xfa\x8f\xd1\x15\xbb\xb6\xd8\xc6\x0f\x0f\xddR\xd8)\x04\x00F\x12\xeeI\x9a7\xd0A(\xd1솸\xe29\x93w\x1dK8E\x01\xc0\x88\xc15I\x9b\ftp'\x1d8c\x1d=|l3\x1e\xfc\a\x00\x1e\xc0-I\x9b\rt\xd0\xee\xc0\x11\xdb\r\x86\x89\x81\x9c\xf1\xebw\xb8R3\x00\f\vnI\xdad\xa03\xb8#\xe0\xcem\\{\xa4\x0e\xa7\x10\x00\x18I\xb8%i\xde@g \xd8\xc4=\x8e\xfe\xd2\x01W\xbc\x01\x8fᖤ\x15Թ\xf4\x99\xe6-\xe7\xb0\xcac\x0e\xd1\xc3\x01H\x1a\xf0\x18nJZ3\xd09\x1ah>\xd2\xdf\u07ff\xab\xc5i\x83a`7H\x1a\xf0\x16nJZ3\xd0٦Ϊ/\xf9\xad&\xf1\xfe\xbd\xf3\xb2\\\x1a\xf1\x03\xc0\xf0ত]g\xae$}\xe5\x92\u007f\x8f\x00\xc0\xb0\x92ђ\xee\xff\xf0\x98S\b\x00\x8c02Z\xd2\x00\xe0=@\xd2\x00\xe0)@\xd2\x00\xe0)@\xd2\x00\xe0)@\xd2\x00\xe0)@\xd2\x00\xe0)@\xd2\x00\xe0)\xfe??\xe8B\x81\x97E\xcd\x14\x00\x00\x00\x00IEND\xaeB`\x82",
+
+ "analysis/ident-field.png": "\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x03\xd2\x00\x00\x00\xde\b\x03\x00\x00\x00\xe6g\xc8\n\x00\x00\x00\x01sRGB\x00\xae\xce\x1c\xe9\x00\x00\x02\xfdPLTE\x00\x01\x00\x02\x05\x01\n\x03\x01\x05\b\x03\f\x0e\v\f\x10\x1c\x0e\x11\x14\x10\x12\x0f\r\x15$\x16\x17\x14\x1c\x1b\x15\x1b\x1d\x1a\x1f\x1f\x19\x13#A!# $$\x1d#$\"$%#&'%\x19(G((!'(&+)\x1e\x14+N()'++$*,)/-\"*.0-.,02/63(241685<9-5:=:;9=?=CA5AB@CEBKH<MH7HIG\x00f\x00\x00i\x01JLI\x00j\x02SN=MOL\x05m\x05PRO\fo\t4U\x98XSBTUS\x0fq\v\fr\x177Y\xa3WYV,`\xae7]\xad\x15w\x1c\\^[c^L9a\xab\x19y\x1e_`^;c\xad=d\xae)z!ac`De\xa3?f\xb0)|*Bh\xb3egdghfLi\xafDl\xb0qjSikh/\x82/Ho\xb3/\x859Jq\xb6mol;\x86:Ut\xb4Xv\xb6?\x8a>|u]tvsB\x8c@@\x8dG\\z\xbby{x]~\xb7e|\xb8K\x90J\x85}e_\x80\xba}\u007f|O\x93Nb\x83\xbdN\x95Ud\x85\xbf\x81\x83\x80W\x95Vl\x87\xbc\x90\x86hZ\x98Yo\x89\xbf\x87\x89\x86]\x9c\\\\\x9dds\x8dÕ\x8cn\x8b\x8d\x8az\x8e\xbfe\x9ef\x8d\x8f\x8c|\x90\xc1\x9b\x91s\x90\x92\x8fi\xa2i~\x93\xc4x\x95Ā\x94œ\x94\x91\x9f\x95w{\x98\xc7s\xa4lq\xa5s\x95\x97\x94\x82\x9aė\x99\x96\x83\x9cƙ\x9b\x98u\xaaw\xa6\x9b}\x87\x9f\xc9~\xaay\x9c\x9e\x9b\x89\xa1ˀ\xad|\x9f\xa1\x9e\x8f\xa2ǫ\xa1\x82\xa1\xa3\xa0\xa2\xa4\xa1\x92\xa5ʂ\xb1\x85\xa5\xa7\xa4\x8a\xb2\x87\xb4\xa7\x83\x8b\xb3\x89\x96\xa9Χ\xa9\xa6\x98\xabю\xb6\x8c\xaa\xac\xa9\x9e\xad͍\xb8\x93\xba\xad\x88\xad\xaf\xac\x95\xb9\x95\xa1\xb0Я\xb1\xae\xa3\xb2Ә\xbc\x98\xa5\xb5ճ\xb5\xb2\x9b\xbf\x9bµ\x90\xab\xb7ѵ\xb7\xb4\xa3\xbf\x9d\xa2\xc0\xa4\xad\xb9ӷ\xb9\xb6\xb9\xbb\xb8\xb0\xbc֦Ũ\xbb\xbd\xba\xb3\xbeٽ\xbf\xbc\xa8ǫ\xb7\xbfԯƫ\xbf\xc1\xbd\xce\xc0\x9b\xb9\xc1ֲɮ\xc1ÿ\xbb\xc3\xd8\xc2\xc4\xc1\xbd\xc4ڲ̷\xc4\xc6\xc3\xc0\xc8ݻ\xca\xde\xc7\xc9ƻκ\xd9ɝ\xc6\xca\xd9\xc0\xcc\xda\xc7\xcb\xdb\xca\xccɿҾ\xc9\xcd\xdd\xd7ϡ\xcd\xcf\xcc\xc4\xd0\xde\xc8\xd3\xc1\xcc\xd0\xe0\xcf\xd1\xce\xe1ѥ\xd2\xd2\xdd\xc9\xd7\xcb\xd2\xd4\xd1\xcd\xd6\xde\xcc\xda\xce\xe6֪\xcf\xd8\xe0\xd5\xd8\xd4\xd2\xda\xe2\xd8\xda\xd6\xd8\xd9\xe3\xd5\xdc\xd1\xd3\xdc\xe4\xda\xdc\xd9\xe6ݯ\xd8\xdd\xe0\xd5\xdf\xda\xdc\xde\xdb\xdc\xdd\xe7\xda\xdf\xe2\xd7\xe1\xdc\xe0\xde\xe2\xde\xe0\xdd\xf0\xe0\xb3\xdf\xe1\xde\xdc\xe2\xe4\xde\xe3\xe6\xe1\xe3\xdf\xe3\xe5\xe2\xe1\xe6\xe9\xe8\xe5\xea\xe5\xe7\xe4\xe4\xe9\xeb\xe7\xe9\xe6\xf1\xf3\xf0\xfa\xfc\xf9\xfe\xff\xfcŃ\x89%\x00\x00 \x00IDATx^\xed\x9d\x0fX\x14\u05fd\xf7/\u05fc\xf5m\xea\x9d(o\xb9o/)\x04S\xac\xb6Y\xd9摖p\xcd<f\t\xe8\x8d\x18\xb9\x8a \x1aR\xa4&J\xa3VL\x8c\x18b\x1e5ָ\xc1\x10,i@\xafJ\xb34\x06\xb4\xa4P\xe3\x1fb\xc0\x98\bj0&$/)i\xc0\x98\r\x1a\x93\x9a?\xf8\xc8B\xe0\xb4<\xef9gfg\xce\xcc\xce\xec,\b;\xec\xf2\xfb<\x0f\xbbgg\u007fs\xe6\xec\xd9\xf3\xdd\xf3g\x86\xf9\xfeK\xff\xa0A\x00\x00\x8c8\xfe\xc5H\xb8\xfa\x18e\r\x00\x80\xff\x01I\x03@P\x01\x92\x06\x80\xa0\x02$\r\x00A\x05H\x1a\x00\x82\n\x904\x00\x04\x15 i\x00\x18Zz\x8d\x02\x86\x17\x904\x00\f!\xce\xf4\x89\xdc,\xa3\xa0a%\xd8%]6\xcdi\x14b&\x1d\xd3ʌB\x02\x91Q\\\xebS\xa6\xd8+?4\n\x1aV̓tӾ\xa2\x92cb\xfa\xb4\xdd\xe15\xf6\x9b\x8ds\x13s\xfb\xbc\x86h\xf3\x18\xb7\xc6(d\xa8h]\x95\x94\x92w2\xe5K\xf5\xf6Ol\xfc\"\xadx\x81\xc7Ư\xf3\xd8V\xc4a\xa2f\x1c\xd7\bgh\t\xe5\xa6\xf8\x1a\xeb#$\xb35h\r~,\xf0\x12%\x1c\xd8\x1bC_\xeb\xfbyL\xf2\xaaw\x8c\xe2|D\xabև\x86\x06n\x9fQ\xc8pc\x96\xa4]\x95\xf6\xc3-\xc7\xed\xcd\xf4\xc5\xe5\x82C\xc5^\xa3\x1fJ\xa9\xc8O\xba\xe65D\x93\xcd㋌B\x86\x8a\x13I\xbf\xaa\xa8\xce\xe2\xf9\x0f\xd4o\xf4\x9d\xd9h\xd3\xdaA\xc41a\xb3zӕ\"n]U\xd14\xaeJ+^\xe6pz\x98ϱީ\x12\u007f\x11HfN\xe4|\x8c+\xba\xe2-\x9c\x1e\xd8\v\xc3P\xeb\xd7\xf6\xf3{O\xeeϾ\xf3\xa4Q\xa07N\xbe+%5j}h\xa8\xe5j\x8cB\x86\x1b\xb3$]Y\x80\x87fN{\x13}\xe1\xa8l\xf7*\xe9\xaf\xf8r\xd4\xd7\xe5-B\x9b\x96\xd0e\xde\x03:\xe2:\xbc\a\xf8\xccWɹ=\buexJ\x1a\xa1Ro\x92F+\xc2\xda՛Nӟ\xfa\xb8\xc9\x1a\xd1,k\xc2|\x8f\xf5\xca\xedsĄ\x90Y\x15w\xda[\xb4x`]\x86\xa5\xd6[\xf9\x13\xf8\xd71'\xc3(\xce\x1b\xd9k\xe5\xb4F\xad\x0f\t\xb5\xdca\xa3\x90\xe1\xc6$I;\xedo\x92'\xa138]\xe4rz\x95\xf4y\xfe\x88\xb7\xb7uI\x9f\xd8\xe9=\xe0\xb4Q\xe3\xf5\x99¤\xcf\xc8S9\xff\x91\xe7{\xde%\xdd91]\xbdIP\xd6fΠ\xf4\x8c\xa4\rc\xbd\x123\xa4\x92\x1e\x96Z\xa7\x92\xc6\xd5;\x88\x1fv\x89,F\xd2\x1a\xb5>$\x8c^I\x1f.\xe8\x96\xd2W\n\x9a\x91\x17I\xf7\xcc\xe5)O#\xb4\x85\xe7\xabŹ\xe9\x16\xdeV\xf1tFҪ\x8b4\xe6\xfcڹ\xb6\x94܋\xaa=]\x11Rw\xd1<'*t\xe2\f\xe5\x9a\xcd\xe6Ɏ&\xae\xc91\xf9)\x9cn\\\x95f\x9b\x9b\x9bF\xa6\xeb}\u007f\xcaN\xcax\x1a7\x9d\xf7m<\xbf\xe3|~Z\xe2\xaao\xab\xf1\xf1KQ)O\x8e\xaf\x19\x8026\xd1<\xbf(\xc7}u_EvRV\x05\x9d\xfa_\xccKM^+\f\xbc\xa5ݐ\xaa\xbc+\xc2]H\x89\xa0\xacy\xd1\xf4E\xf1\xb4\xf0\xc9K\x88H\xae̙\x18\x1a}w\x03\xdd\xe8\x9c71rN\xba,iu,\xea\\6%\"\xeep\xf4>\x94ɍ/\x96\xa7\xbfr@͌\xe8Ш\x19x7\a'\x10\x83T\x9268\xb0\x1c\xd00\x81\xe3V4ϛ\x14>\x83|\xa9\xeeZWn\x95\x90k\x9d\xa9>\xfcm\x96oJM\xce=OC\xb4\xbeMA\xd2y\xa9$\xcd\xd4dWᢤ\x9c3\xa9ul\xd3P\x04H_\xec\x11\xa1\x15\xf1\xd9b\x86\x9e\xb5\xae\xf9\x81\x94\x9f⩘\xf0\x18\xd2\\t>\x1b\"u7Z%]\xe6h\xdae/>Dk\xd5Q\x89\xbcI\x1a}\xd0X͗66\xe2^\xf0b\xa3\xadT\x9c\x9b\xb6V\xdb\xf8\x94\xd2?$璈\x93I\xd9{O\x94\xe2ѹ\x92\xe3\xd2\f\xb3*\"\xe6\xb1\xca5\xdc\x06\xc5\xdb\xcey\xdc\x14\xee6n\x0e\x1e\x81\xbdsg\xfe+'*\xe6\xf2\xdf\xe2͛\xf8mu\xe5)Y}\xa8\xa7\xba:-\xe3\x9eԧ\xf3\xee\xfc\xb4\xab1\xf9\xb9/ї\xcf%7vi\a\xf4\xb0\aϷ\xed\xa8\xdba\xcbǩ\xf3\xc9\x19\xfb\x8f\xac⩤\xa5\xdd\xd4\xe5=\xe4\xd1\nNs\x0eW\xd32\x8e.ᤏ\xcftl\x8e\x8a\xe9%\xdaK\xaf*\xb9{|-\xde\xd8\x1c1\xb9\xa8l:\x17\xa6\x1b{yR\xd4c\x8eL\x8e{\n9kB\xd7H\xd3_9\xa0\x96\x9b\xb7\xab\xd2\x1e\xc5u\xa3\xceC5\x93\xe3jjj\x9a\xc4\xcc\\\xae}T\xd2F\a\x96\x03\\%\xc5ѓ#\xa2\x97\xcc\xe3\xc8R\xaf\xbb֕[%\xe4Zg\xaa\x8f|\x9bi\xa5\xa5iI\xadH\xe7\xdbl\xe5\xeb\xba>*Ŀ\xab\x88\xad\xc9ki\xc9\xe5uX\xcd\x15l\xd3`\x03\xe4/\xb6\xebLcFNcc\xa3{\x14\xe5Y\xeb\x9a\x1fH\xf1)\xd2\xc3V8V\x84\xcd\xd3\xfdl\xddΪ\xdb#\xafg\xb84$\x98$\xe9\x12{qC{Sq\t\xd6tSQ\xa7wI\xb3\x03o\x1b\xf9N\x85\x81\xac-\x19\xff\x8e\xe7\xa7\xe0TO\xda*\xdc7\xf6T\u007f\xa5\xda\xcd\xc1\xb5\b\tW\xf4\f\x17\xf9\x1e\xd4S\xb8}\xa1\\(]\xa0\xacH!b.Oƍ\xe0U~?N\x9e#\xdd1\x1e\xaa\xf1\x0f]C}d]nS\x1e~\xc8#]\xb1f\xc0'\xccԠ\x8ev('\xf8:\x84r2\xf0O@_\x96M\xb9\x9b\xaa\xbc\xed\xdc.\xa4\xe44\xed6瑤\x83#KM\xb5\xdc\xf3\xa4\xfc\xa4\xb5\xdcFNz\xc6M\xc2\xc9ޘ0\xdd\xd8y\x91dD\xb2\x84#]J\x18Y~\xa6ce&\xe0\xa9(ҿl\x8e\xa4\xc7c\x06\xde\x02\xa7}80\x13\x80s\xe0\xa6_\x11\xe7QR\xad+\xb62H\xb5\xce֯-\xed\x1aQh\xb6\u07b7\xd9J\xbb\xd8|\xf2\x83\xc8\xd4d>i\x03h\x1b\x964\xdb4\x98\x00\xe6\x8bU\x0e\xbc5j]\xef\x03I\xc9}t\f#<j~\xb6Y\xb8꼟\xba\xf1\a&I\xdaQ@*\xa3\xb3\xa8\x16u\x164\xf5\xf6\xf6~X\xec\xed\x92\x1bmI结uZkR\x982w\xe3rpoj\xbcݱ$4\x9a\x9b\x18\xb6\x04\v\xfd\xd3Դm\x15\x1f\xf4ᦄ\xf2\xd2z\xbeŤҁt\x96\xedS1\xf8db\x17\xeaJ:\xa9\x17\xd0c\x93;\x95M\xc29\xabE\x1b\xd15\xda\xd6\xd0\x0e\x9br7UyۅF\xc4p\x9a\xdbp\xd81-\x9c\x94\xfe\xdeI\xaenL4\x99\xf9u<5cR\x04w\x1b\xee\x839;\t[\x11\xa6\x1b\x1bN\xcf\"5\xa9$\xcd\x04\xb4O\x9c\x94i\u007f\x13\t\x83OF\xd2\x1bjkk7\x10I\x1b\x1e\x98\r@1aRwU\xc6H:LщQ\x98Zg\xeb\xd7VH\x1e\xcb\xf9\xaft\xbe\xcdV\xfe\x0f\xe7^\xcdN\xfc\x04\xb15ٗT*\xbc\xa7\x944S\xd5\xcc\x17\xeb!iu\xad\xeb} )\x99~\x1b}\x9a\xa2\x0e\x90\xf8p\x9f}ʨ\xed\xa5\xab\x84\x9fȪ2\xd4bw\xa3\u007fu\x82\xb6\xa4\xa5d9ߣ\xb9\xdba\xf7\xd8j3\xe79oB\xe8\xb1(;\x9e\xd5m\x8e\"c\xd6k\x15k3\xf8\xb9{\xfbH\xc7!@G\xf4Y\xee\x99\x17\xfa6\xf9\b:2\x97\xfc\xd8k\a\x88s\xe9\x1e\xdcA?H\xdfA\xb9ٸ\xa3h$)ZHf7Uyk\xb9CH\t\x9d\xd2^\x1eO\xe4\x13#\xf6\x9b\xb8\x8b\xac\x9d\x18\xbdlW\xcdtܮ\x8e\tgJ\xe4\xe51u\xac\xd8\x05]QI\x9a\xc9\f]\xb6ϙ\xc2E=F\x8f\xa7\xb5<fx`63\x14s\xbbT\xf8\xc3\xf2\x88\x96\xd9*\xc1\xd6:S\xbf\xf4\xdbD\x8d\xfc\xbb:\xdf&\x9dK\v?\x91rM^\x14\xdaE\x97J\xd2\xec7$\u007f\xb1*I{ֺ\xde\a\x92\x92\xd3\xee\xa6O3\xa6\xa9\x02Xj\xb8Z\xcd\xed~\xc4$I\x1f/\xa2\xbdr%\x1e\xa6t81\xa7\x8b\x9c\xfa\x8aVKz\x87J\xd2'\xf8\xf75w\xeb\f\x13\xafx\xa8\xe44/\xc5pѵW\xa2\xf6s\x85dbV\x9dXA~\xe2ߥ|A\"\x98F\xb0-\x17\xe5n#\t\xed\x80\xc2D\xfa\xba\x9a\xff\x12m\x12V\xd9\xd2\xf2\xd17B/\x9doS\xee\xa6*\xef\x9aP\xf5\xd0TPV\x04)\xfd\xbcI\xc7)\xb8S\x9b2\x8d\x14u\x0eVV\a\x95*b\x96\xc7T\xb1\xbdB/}Z\x964\xedX\x99̎\x915\xac+χӌ\xa8\xa4\v>TH\xda\xf0\xc0L\x00\xf3\xa3\xc0Ժb\xab\x8c\\\xebl\xfd\xdah\xddV\xf0\xd7t\xbeMay,\x99|\xe7rM\x8a\xbd\xf4\a\xb2\xa4w\xa8\xaa\x9a\xf9bţ\xed\x17\xc7\x05\x9e\xb5\xae\xf7\x81\xa4d\xfa$\xfa4)]\x15\xc02zW\xbc;\xe8I\xac+\x05\xee\xcb\xc7|\x9dK'\xe1\xf1Y߯T\x92\xeeJ\xc9!?\xec۶\xa9\xf7\x9b3Y\x18\xcewN\x8c#M(s\x89:\xa0=R8;YJ&\xbex껑\xe8\x8dN\x92\v\xf7\x92GF\xd2o%~\x96\xf8\x16Ih\a\b\xe7\xa5\xfbr\xd2ȸ\x9a\x04T\x93,\xb3\xd3\xf0\x8c\xf0\xa3D\x9br7ey{\xa7\xcc@*\x04eM\\Ұ\x06\xcf\xdcJȖ\x15\xb8S\x8b&\x8d\xa87\x86\x8c\xfe\xa6E\xe3v\xd7\xfc\x830\xdd\xd89Q\xa4aΣ\n\f\xc7\xea\xed\xbd\x9d\xc42\x01k\x84\x19a\\&}\x8c\xc3\xdf\x00y\x8f\x91\xb4ၙ\x00e\x03w\u05fan\xb3w\u05faB\xd2s\xbbpŤ\xe5\xa8k\xa7e\x9d0\x8c\x17$\x9d\xb2\xad\xb5\x94\xadɵs\xb1l\xfb\xf2\xa9\xa4\xe5\xa6\xc1\x040_,~Ĺ\u007f)\xbc\xa7U\xebz\x1fHJ:\xe8X\xfdya\xba\f\x92Vs\xac\xe0X\xfb\xe9\xe2]\xdd\xf4E/\xe9\xa5u/?\x10V\xbc\xcfбӃ){K\xb3y\xdb\xfe\xd6\xcf\x1am\x1b\xcf\xf4\xbd\xb3\xd1FV\xc2O&.\xaa\xa8\x13\x16I\x144\x8f\x17\u05f8\xab~0\xe5)G\xa6\xfee\x8e\xa5|R\xe9\xabG6\xf1d\xae\\xg\xde+8Y\x8d\xbe}\x8b\xae\x91~\"\x84\xf4\xa5\xaeJ\x15.I\xd5\x0e\xa8Kzp\xff\x91U\xb638\x99\xc7\x17\xbeZȓ\xf5\xb4֤\xd4\xd2\x1dɤ\xbc\xccn\xaa\xf2n\xf0\x1cB\bW\x15N\x9fA&o˸{K\xcaҹb\xa2\xc29O\xad\x8b\xc1\x83\xe5\xc3\xe8tx\xf4\x9a\x15\x91\xe3'\x145\xe9\xc4:'F?\xb5kV\x18\x95\xf4\xb4\xa8u\xeb\xa6q$V\x91Y\xc4\x1aǮtauzM؆\xb2\xe9\xe1\xedʫnj\x0e,\at\x1f\xa6k\xe6\xee)\xb4X몭\x9e(\xaa\xcf\xc6gWWd$\x93\xf5hE\xed\xcc\xe2\x04\xe9\xb5Rm\xe6\xe4n\xccbk\U000b3534\x8aWr\x13i\xac\xd44\xd8\x00\xf6\x8bſ\xff\xe5G\x1eJ\x12zi\x8dZ\xd7\xfc@\x8aO1o\xfc2Dz\xf1\xf3\xbc}\xb6c\x1e\xe3y\xbfc\x96\xa4QsYѮc\x82\xa2\x91\x93L\xa5\xf5\xfa\xe9\x9ed:1\xb2ѳ\x0f\xe7s\x12\xefY\xb5\x83\xe7\xb7l!\x9b>H\u008f[\xf0\xe6\x8f֦ޓ-\xaf9K\xac\xf8\x81X\xc1\xcds\xa2#\xa6\xa9\x978e\xfe\x94S\x9afK\xc9\x11.7<\x91379\a7\xa0\xf7\x9993\xa6\\Z\x01\xd3\x0eh]\x9547\x97\xae\xec\xf4\x95g%e\x95S\xfd\x9f\xcfMN+\xdco\xa3\x85t\xef\x86\x14\xe5\xad\t\xf7\x18;\x94\xe0\t\x1d\x9e\xe46L\x8e\"\xfd\xc1\xbe\xe9Q\x91qD\xb6\xbd\x1b&\x87E\xdd[49\x14\xf7\xa9\xcdwGNZR4\x81\xcbԉE\x1d\xe9\xd1\xe1ӏQI7DžG\xccX\xc6q\x99l@qܚ\xe8Љq\xe2\xf9\xa6\xcc\xc8\xf0\xb8Z\xf6\x1ao\xbbၙ\x80\x86\xf1t\x0e*u{B\xad\xab\xb7z\xa0\xa8>\xdbӛ\x92S\xf3\xe9\xe5:\x8ao\xb3(\x8a.ȑ\v\x03p\xa7ۚ1\xf7U\xc4\xd6\xe4\x17\x9b\xd2\x12\x1f:G%-5\r6@\xf1\xc5\xf6lKN\xcc9G\x93\x1a\xb5\x8e4?\x90\xf2Sl\xbe-\xfc\xb6\xcd\x1e[Y\x9c\x13\xe648\xcd\xfd\xefJ\xd3$\xed\x1f\x96\x84\x96\x18\x85\x98\xcb\xf3\xa1\xe9\xddF1\x83\xa6S\x98\xfa\xfa\x9dAԺ\xb0<68\xba<\xc7g\x06\fc\xad\x97M\xe1\xe0\x9f+\x87\x95\r\xd1^\x96\xdḑc\xe2:\xa3\x90\xeb\xc0,I\x0f\xa2\xd6\xfd*\xe9\xe1\xadug\xc3@?\xfc\xd0\x12\xec\x92\x1e\u0558&\xe9\x81\xe3WI\a7 \xe9\xe0\xa5y\x1f\xb7\xc4\xf4\xf5W\x9f\xb8H\x17;\x8d\xa2t8_\xc7?\xfd\xd6`w\x0eB@\xd2\xc1K\x1c\xc7q\x13\x9a\x8d\xa2F\x02t\xb1\xf3\x13\xa3(\x1dr\xc8\xce獢F\x0f i\x00\b*@\xd2\x00\x10T\x80\xa4\x01 \xa8\x00I\x03@P\x01\x92\x06\x80\xa0\x02$\r\x00A\x05H\x1a\x00\x82\n\x904\x00\x04\x15 i\xb38\x92\xfd\xe5\xf0Z\xb9\x00\xa3\x13\xf3$\xed6\xd0q\x15\xd1\xdb\x14\x15i\xddK(\x88\xd9˗\x92\x8b\x18\x87\xcf\xca\x05\x18\xa5\x98%i\xd9@\xe7\xb2\xfdMr\xab\"s\xff{\xc5\x1f0\xfe-\xe4\xfec\u007f\x12\x12\xc3f\xe5\x02\x8cR̒\xb4l\xa0s\xd9n\xaeџ\xdf`\xfd[\xce\vw\xc4$\f\x97\x95\v0J1IҌ\x81Ψ\x914{\x83\xcaM)]\xee\xe4pY\xb9\x00\xa3\x14\x93$\xcd\x18\xe8\x98(i\r\xa7\x16\xd6\x14GөŇX-7\x1e\xa5\u007fK\xcf=R'\xadm\xe5\x02\x00\x83\xc5$I3\x06:\x97\xed\x958YcB\xb3\xd6rja\\]\xb4\x9dZ\x8cc5\xddx\x94\xfe-\xef\b7\xf8\x16аr\x01\x80Ac\x92\xa4\x19\x03\x9d+4Y\xf2\xbc\xdf5\xad\xe7\xbb#\xb9\xba\xe88\xb5\x18\xc5\xea\xba\xf1\xc8\x03\xef:\xd6\xe0\xd2\xd3\xca\x05\x00\x06\x8fI\x92\x96\rt\x10:M\xc4\xec*\xf2{W\xa5\xe7\xbb#\xb9\xba\xe88\xb5\x18\xc4\xea\xbb\xf1Ȓ>\xc23\xff\xef\xefi\xe5\x02\x00\x83\xc7$I\xcb\x06:nj\xfc\xdeU\xe9\xf9\xeeH\xae.:N-\x06\xb1\xfan<\xb2\xa4\xcf\xf0g\xe4<<\xad\\\x00`\xf0\x98$i\xc6@\xa7\x92\x9a\x17\xa0*\x87\xd7\x1d\x86\x01=\xdf\x1dIz:N-\x06\xb1\xde\xddx\x04\xff\x96.\xf6\xeey\x9eV.\x000xL\x924c\xa0\xe3\xa0\xddsG\x91\x96\xb9䰢\xed\xd4\xc2\xc8Tǩ\xc5(Vύ\x87\xf5oY\x9b!\xdd\xffN\xc3\xca\x05\x00\x06\x8fI\x92f\ft\xda\xed\xfb\x9a?<V\xe0\xf7NZ۩E\xe1\xea\xa2\xed\xd4b\x14\xab\xe9ƃ\x94\xfe-\x1f\xf1\u007fp\x97B\xcb\xca\x05\x00\x06\x8dY\x92f\ft\x9c\x95\xc5E\x8e\xd3F\xf1Á\x86S\x8b\xd2\x14Gө\xc5(VӍ\a)\xfc[\x10z.Q\x9cMk[\xb9\x00\xc0`1Mҁ\xc8\x10\xde\x03\xbeo\x9b\x8dv\xdd\xc3h\xe5\x02\x8cN@\xd2\x03`\b%\x8d\xfa\xcaS\xbf\x18n+\x17`4\x02\x92\x1e\x00C)i\x00\x18\x1e@Ҿ\x03N-@\x00\x00\x92\xf6\x1dpj\x01\x02\x00\x904\x00\x04\x15 i\x00\b*@\xd2\x00\x10T\x80\xa4\x01 \xa8\x00I\x03@P\x01\x92\x06\x80\xa0\x02$\r\x04)\xbdF\x01A\nH\x1a\bF\x9c\xe9\x13\xb9YFA\xc1\tHz\xd4A\x9d{\xae\x9f\x91\xed\xfd3e\x8a\xbdҴ;Ϛ\x8by\x92v\x1b\xe8(\x93\xfe\xa52J\xfa7\xed\x8ę\xf0\x19\xa6\x8c\xd5>\xb1\xf1\x8b\x8cb\x10\xb9\xaf\x12\xe6Ό\n\x9f\xafH\xd5\xc9Wt\xee\xe9\x98\x1e\xf9\x98ƻ\x03`\x88\xbd\u007f\x1c\x91\xbe\xff˼\xfb{K\xe78.\xbcY#\xa0\x81ۧ\xb1ut`\x96\xa4e\x03\x1d6\xe9o\x1c\xe1\xd2\x1dϦO|*=\xfc\xb2\xb7\xe0\xe1\xa2\xef\xccF\x9bQ\f櫽\xfc\xfeƺ<\xfe9\xa3@7\xda\xf9\xba\x9d{\x96Lzl\xfcu\x9a\x16\r\xad\xf7\xcf2n\x99Q\x88\x84\xfb{k\xaf\xa9٬y\xcb\xe4Z\xaeFc\xeb\xe8\xc0,I\xcb\x06:l\xd2<:8\xdc<;\x8d\xa2\x86\x89R_$\x8dN\xf0\xadX\xa7[\xd8\xfb\x05\x1b\xa0\x91\xaf\xe4\xdcs\xfb:\x14~\xbd\xcd~H\xbd\u007fVp+\x8cB\xb4\xa8Ց\xb4\xdfo8;b0IҌ\x81\x0e\x934\x91f\xce\xf7aߐ3\x00I\xa3\x9e\xe4-F\x81\x12\x1a\xf9J\xce=\xb7\x15\xb5s\xd7;0\x1aR\xef\x9f5\xdc\x1a\xa3\x10-@\xd2jL\x924c\xa0\xc3$\xfd\xcb\xe5p\x8e\x1b_LR\xae(\x8e\xe2qˠ\xe2iᓗྻa\x02ǭh\x9e7)|F7\x93T\x05\x8b\xb7/j\x8f\x102\xe3\"T]\x98\x86]\x0fB\x17\xf3R\x93\xd7\n\x03dƂG3V\x904\xda2W7\xb6\xaf\";)K\x98l\xeb\xe4+;\xf7\xccX1\xeb6\xfcY&4i\x1f\xcd7#!\xd9\xfbG\xfc\xf0\n\xa4ݘ\xcc\x14\xf9*x\x8c\xa3s{\xed\xea\xcb\xe4B\xedK&\x87\xcf \xdb\xe4\uf360-\xde*\x90\xf4`0\xca\xda\x1b\x8c\x81\x0e\x93\xf43\xc7jj\u0084\x9e\xe1͚\xe7\xb9555\xea\xb9e\xfa\xf8L\xc7樘^\xe4*)\x8e\x9e\x1c\x11\xbdd\x1e\xf7!\x93TE\x8b7\x19t\x15m\x16P9fk\xd9\xf5\xa0\xf3\xc9\x19\xfb\x8f\xac\xe2\xa9\xf4d\v\x1e\xedXQ\xd2\x15|\x97^l\xbemG\xdd\x0e[\xbe~\xbe\x8csϚ\x88\xb0c\xdd3\xe2\x0e\xeb\x1c\xcd7#!\xd9\xfbG\xfc\xf0\n\xa4ݘ\xcc\x14\xf9*\xd8\xccљ\xb9v\xf55\x15O\xe0\xa2\xd6l\x88\xa0\xe7\xa5\xe4\xef\riJ\xba\xdbYu{\xa4Y\x93(\xf31IҌ\x81\x0e\x93\xf4?\xe1\ue9a15\xf0vpE\x88\xb4\x19j\x86\x11\xc3M\xbf\"N\x0f\x98$\x8b\xfbV\xc0\xce\x16\x01\xe5\x0f\x84\xb6]ON\x06\xd6g_\x16\x91\x1ec\xb6\xa3\x1d+J\x9a\x98\xefh\xc7\xd6\xf1'hX\x9d^\xbe\xacs\xcf:Ύ\xae\x84\x93\x0f}\x1dFB\xb2\xf7\x8f|\x1fd\t\xa5{\x90;3E\x92\xc5\xce\t\xfd\xbcv\xf5\xa1\xb0H\xdcCϋ\x12_\x85{\x93\xf4,\xdcǛ8\x8d2\x1b\x93$\xcd\x18\xe8\xb0^:~ǫ\xa4\xef\x9d\xe4\xea\xc6D\xd3\tcL\x98\xd4+3I\rZ87\x8aF\xaei\xd7sM\xd0\xc6\x0e\"=\xc6lG\xdb\xdaG\x94\xf4~\xfe+\x9d\xd8M\xc29\xabE\x1b\xf5\xf2e\x9c{J\xb8\xc8%h\xc3D2y\xb8\x0e#!\xaf\xde?J\xf7 \x9b\xd4+3I\x96\"\xfa\x03\xaaW}(\x8c|\vk\xc2\xc4W^%\xfd\xe1>\xfb\x14\xe8\xa5\a\x83Q\xd6\xde`\ft<\xbdt\xfc\x88WILjm\x8b\x8e\xf6bn\x97\xb7\xcbI-j\x1c\x02\xca\xf5dM\xbb\x9es\xc28\x98.c1f;\xda\xd6>\xa2\xa4\v\x93\xf5b\x1f\x14n?\x9c\x9b\xad\x97\xaf\xec\xdc\xe3\f_R\xf5\x83\x96I\xf4\xd3_\x87\x91\x90W\xef\x1f\xa5{\x90;3E\x92\xe5P\xa4\xa0M\xed\xeaCt\xa8훤15\x9c)=Ĉ\xc0$I3\x06:L\xd2\xffx\x95\xf4\xbcI\xc7)\x1d\xe4E\xcc\x1ci;\x93\xf4\x1dM\xbb\x9eo\x04m\xe4\v\xbd\xa9d\xb6\xa3m\xed#\xaex\xa7\xacՋ\xdd$XZ\xa7\xe5\xeb\xe5+;\xf7\x94\xe1>p֤\x88\xcbB\xbe\x836\x12\xf2\xea\xfd\xe3\xe9\x1e$\xc0$\a\xc0\xc0$\r+ރ\xc2(ko0\x06:L\xd2\xffx\x95\xf4>\xae\x84<\xad\xa0\x17I\x19KZc:ɠmד\x9d\x86g\xb0\x1f%\x12\xe91f;ڱ\x82\xa4\v\x89\x00\xb5c\xeb\xe8\xd6j2\x97\xd6\xce\x17I\xce=\xbb\xb8f\xf4&w/\xea\x8dn\xb9\x0e#!\xc6\xfb\xa7e\x8d\xc7\x191ŁA\xd2~\xc3$I3\x06:lү\xb8\x0e\xd7Ԅ\xa5\xd7\xd4\\q\xafx{\xb4\x82eܽ%e\xe9\\1\xea>\\39\xae\xa6\x864v&\xa9BkїAˮ\a\xb5&\xa5\x96\xeeH\xe6m\xfb[\x15f;Z\xb1\xc2\xd5c\xf9<\xed'\xb5c\xf3\xf8\xc2W\v\xf9<\xfd|%\xe7\x1eg\xf8\x9c]ѓC3ׅ:\xaf\xc3H\x88\xf1\xfe\x99\xc5\xc5!5\xd2nLf\x8a|\x158\"\xbc\x8cӜ5\xa1\xe9\x87\xd1\xf1\xf4\xd0\x1a'\xfb\xbdѫ\xc76\xd7\xd4x\xacm\x1c\x1b\xc5n\xa0fI\x9a1\xd0a\x93\xfe\xa4v\xbc0U\xb6#W$ML\xf0\xb8\x80m\xdf\xf4\xa8ȸ}\b5\b\xa1\xa4\xb13I\x15Z\xa7fY4\xecz\x10:\x9f\x9b\x9cV\xb8\xdfƓ\xebG\x18\xb3\x1d\x8dXz\x8d7\x9f&\x0ey5c\xfbʳ\x92\xb2\xca\xfb\xbc\xe4+9\xf7TN\x8e\xca쬜\x1c\xf9\x94\xce\xd1|1\x12b\xbd\u007f6\x87E!\x0fܻ1\x99)\xf3e\xd9\x17\xe5\xe5\xb2\xecL\\塧\xc3\xf1c&\xf3\xbd\xd1k\xbc\t\x1e\xc3&\xe7\x849\rNS\xae\xd87\x1f\xd3$\r\x98\x83۹\xe7z\x10\x96ǔ\xde?\xb3\xa6\xebE\x9bB\xd9\x14\x0e\xfe\xb9r\xc0\x18e\r\x8cH\x04\xe7\x9e\xeb\x82JZ\xe9\xfd\xb3nĝ\tv6\xa8\xaf\x1c\x1a%\x80\xa4\x81\x01\xe3i$\xd4\x1e\xb5Y3\x12\xf0? i`\xa0\x80\x91Ј\x06$\r\f\x140\x12\x1aр\xa4\x01 \xa8\x00I\x03@P\x01\x92\x06\x80\xa0\x02$\r\x00A\x05H\x1a\x00\x82\n\x904\x00\x04\x15 i\x00\b*@\xd2\x00\x10T\x80\xa4\x01 \xa80OҢkNw\xb1]\xa0\x18\x01\x00pݘ%i\xc95\xc7e?\xee\xc4\x1c\xb37\x18\xed\x12\xe8T\x1dG\x000\xec\x98%i\xd95\xe74\xb9ۯ\xab8\xf8\xefBq\xfb`nY\x06\x00\x03\xc4$I\xab]s\x1c\xfe\xbfO\x91\xdf\x19\xd4]\b\x01`\x80\x98$i\x95kN\x93=x\xfe]]\xe9\xb0\xe3\xb6\xe0q\x88\xb7ԉ!7\xdd\x19_\x8cZB\xb9)\x8aX\xd6\"\x86e`.4\x00`\x92\xa4U\xae9%\x95^\xa3\x03\n\x85Îd\xc1\xd3y\x88ޅ\xb0\xa6\x89\xde\x1ao\r\xfeQK\x0fS\xc4*,b\x18\x06\xe6B\x03\x00&IZ\xe9\x9a\xd3b\x1fBS\xd3\x11\x80䰣\xb4\xe0\x91\x06\xde\xec\rle7\x1e\xa5E\x8c\xc8\x00]h\x00\xc0$I+]s*K\xbcG\a\x1a\x92Î҂G[Ғ\x1b\x8f\xd2\"Fd\x80.4\x00`\x92\xa4\x95\xae9E\xa6ܖ\u007f\xf8\x90\x1cvb\xc4\x19\xb4`\xc1\xa3-iɍGy\xf3y\x91\x01\xba\xd0\x00\x80I\x92V\xb8\xe6tؽ\xd9T\x04 \x92x=-x\nH\x9fLŻ\"L\x19\xab-\xe9\xa1u\xa1\x01F\x01&IZ\xe1\x9a\xd3b\xbfl\x10\x1e`H2UX\xf0\xc4\xc5!\xe4\xa4\x1b\u0097!\xd4{\xbbO\x92\x1eZ\x17\x1a`\x14`\x92\xa4\x15\xae9Mv\xf7\xcaw0\xa0pؑ,x\x10Q놲\xe9\xe1d!pZԺuӸ\tEML,k\x11\xc320\x17\x1a\x000KҬkN\x8b\xdbw<(P:\xec\xb8-x0\xae\xcc\xc8\xf08\xba\x1e\xd8\x1c\x17\x1e1c\x19\xc7e2\xb1\xacE\x8c\x82\x01\xb9\xd0\x00\x80i\x92\x06\x00`8\x00I\x03@P\x01\x92\x06\x80\xa0\x02$\r\x00A\x05H\x1a\x00\x82\n\x904\x00\x04\x15 i\x00\b*@\xd2\x00\x10T\x80\xa4\x01 \xa8\x00I\x03@P\x01\x92\x06\x80\xa0\x02$\r\x00A\xc5(\x96\xf4\x1c.j^\x93Q\x10\x00\x04\x18\xa3X\xd2Ϊ\xa2)Q\x9dFQ\x00\x10X\x98'i\xd1@\a\xa1\xceC\xbb\nv\x1d2E[U\\\xd0{|\x00\xa3\r\xb3$-\x19\xe8\xa0\xcbŻ\x9aڛv\x15\x9bqg\x93Z\xee\xb0Q\b\x00\x04\x16fIZ6Щ)!7B\xe8.\xa91\xdae\x18\x00I\x03A\x87I\x92f\ft*\x85\xbb\x84\x96\x99qw~\x904\x10t\x98$i\xc6@\xa7\xa3\xb8\xaa\xc3\xd5QS\xdc\xe1-~\x98hઌB\x00 \xb00IҬ\x81\x0e\x9eV\xdb\xed\xfbL\xb9\xa3\xa0+jڡ\xf6^\xa3(\x00\b L\x924c\xa0\xe3\xaa,ir6\x95T\x9ab]\xb9\x8f㸻\x8d\x82\x00 \x800IҌ\x81N\r5\xc6r\x95\x98a0\xdd\x195isU\x90\xf9\x02\x00\xa3\x1c\x93$\xcd\x18\xe8\x14Ѕ2\xf4f\x81\xb7\xf8a\xa2\x963cQ\x0e\x00\x86\x11\x93$\xcd\x18舒>n\x8e\xa4a\xc5\x1b\b2L\x924c\xa0S%\x0e\xbc\xcdX{\x06I\x03A\x87I\x92f\ft\\ϗ\x9cn?]\xf2\xbc\x19KއA\xd2@\xb0a\x96\xa4\x19\x03\x1dW\xed\xae\xa2]\xb5\xfeW\xb4\xcby|N\x98Ҁ\n\x00\x02\x1e\xd3$m>\xb38.\xba\xcc(\b\x00\x02\x8cQ,i\xe7\xf1v\xa3\x10\x00\b8F\xb1\xa4\x01 \x18\x01I\x03@P\x01\x92\x06\x80\xa0\x02$\r\x00A\x05H\x1a\x00\x82\n\x904\x00\x04\x15 i\x00\b*@\xd2\x00\x10T\x80\xa4\x01 \xa8\x00I\x03@P\x01\x92\x06\x80\xa0\x02$\r\x00A\x85y\x92\x96\ftz\x1b\xca\nv\x8d\x1c\xbf\xb9\xd6\xdc\xe4䜓Yg\x8c\xe2\x04N\xa4\x1c\xd1\u007f\xb3\x94\xb7\x91w\xeb\x92\xf8R\xed\x80-<_\xad\xfd\x0e\xfa\xc4\xc6/\xd2ykh\t\x88B\x02\xbec\x96\xa4e\x03\x1d\xe4(:\xder\xac\xe0\x98\xd1\x1e~\xe2][\xee+չ\xfa\xadXūI\xaf\xe8\xbf\xf9E^\xd2C\xf8\xe9\xa1ļ/\x94o\x9c|Wx\xbe\xd8h\xd3\xd1\x11\xea;\xb3Ѧ\xf3\xd6\xd0\x12\x10\x85\x04|\xc7,I\xcb\x06:o\x16\x90\x9b\xf27\x17\x98\xe2s\xe7ɪ\x9c>\xdcT7\xfa*i\xd4\xe7\xed\xcd\xc2ܤk\xe8\xab\xc4\xdcB\xd5\xf6\xec\xb5\ue52eZp\xf7\xe9'\xb5\x04D!\x01\x9f1IҌ\x81\x8ec\x1f\xddR<B\xba\xe94ڲ[y/\xe3i\xdf)\xcc{\xa8\x1a\xfdiU\x9eZ-Y#I-\x01QH\xc0gL\x924c\xa0\xb3K\xf0\xb7+s\xe8\x06\x0f\x0f\xef\xdbx~\xc7\xf9\xfc\xb4\xc4U߲\x9b\xf3RZ\xf1c_]\x17y\xfcSvR\xc6\xd3]\x8a\xd8j\x9eǓ\xceR\x9e\fͯ%\xf1\xf2\b\xfd\xfcڹ\xb6\x94܋\xecnX-\x15\xb9(\xb7\x82\xaaE\xdaz\x84\x17\xc8&{\xd9\n\x9f\xceHZE\xf6B}\x15\xd9IY\x15\xb4\u05ff\x98\x97\x9a\xbcV5\xa6m\x8f\xe0\x04\"Twn\x90\x0f,\xa1\xf8lrqPWᢤ\x9c3\xa9u\x8a\xfd\x87\xb2\x90\x80\xf9\x98$i\xc6@\xe7P1\xbdCh\xd1.\xa3}\x86\x98\x9e\xea괌{R\x9fλ\xf3Sv\xf3\xa7i\xfc\xaaҷzhz\x13\xbf\xad\xae<%\xab\x8f\x8d\xedjL~\xeeK\xf4\xe5sɍ\xb8\xe1\x9fklL\x14{\xb0\x93I\xd9{O\x94\xf2\xe5\xecnX-\x17\x93\xbeI\xfc\x8c\xaaE\xda\xdau\xa61#\xa7\xb1\xb1\xf1#\xb2\x9b\x8dϨ>27\x97$\xf3m;\xeav\xd8\xf2q\xea|r\xc6\xfe#\xabx\xa5Z\\E\x9b\x05\x8a\x94\xb7ic\x0e,\xa1\xf8lrq\xae\xa5%\x97\xd7m\xe1\xf9\nE\x06CYH\xc0|L\x924c\xa0\xd3Y\xe4p\xba\x9ce\xf6\x12\xa3}\x86\x9e,\xfe\xa1k\xa8\xef\x9ar\xe3W\xa5\xbf\xb2\xf1ɤ\xef}\x95ߏ\x1f\xcf\t\xfd\xb0\x1c\xbb)\x0f?\xe4m\x12\xc3EI\xf7\xa4\xad\xea!R\xfaJ\xb1[a\x1e\xcaژ\x8d\x88Z\x94\x99\xc9cڔop\x8e)8Uǟ\xc0\x8f'x܅\xe6d\xe0\x9f\x8b\xbe,\x95Z\x9c-\x02\xca; 2\aV \x95\x979p~2\xe9i\xb7yHz\b\v\t\x98\x8eI\x92f\ftP\x87\xc3n\xb7\x1fv\x98pg\xbf,\x9b\xa2\x83\x96\xe89\xb1\x8a4ڼ\xb4\x9eo1\xa9\x9b\x94\xb1'\x13\xbbPW\xd2I\xf1\x95(\xe9:\xfe\x03\xf7\xde\xccnX-{\xf9\xbdT-\xca\xccd\xb5\x90\xd7tB\xbaI8\x1d\xb4h#\xba&hn\x87R--\x9c\x1b\x85\xe3\x0fs`\x05Ry\xe5\x03\xf7%Ѳ\xb6zJz\xc8\n\t\x98\x8fI\x92f\ft0\xae\x8e^Tl\x82'VV\xb6\xe7\xb6s\u0094\xf1\xc1\\\xd2\xd1\t\xe4*c\xbfM>\x82\x8e\xccu\xaft\x8b\x92.\xe7{\xdc\xef3\xbba\xb5|Q\xf8%U\x8b23\xe5\xca\x13U˃\xf4\x1d\x94\x9b\x8d{\xc9F\x84<W\x9ej\x1c\x025\x8a\xad́\x15H\xe5\x95\x0f|QX\xf3\xeb\xf2\x94\xf4\xd0\x15\x120\x1d\x93$\xcd\x18\xe8 \xbaP\xd6l7\xe1\x8e\xdar\xa3\x95I\xd9F\x9f\n3H\x9f\xf5.\xe5\vU\xec\xb6\\\x94\xbb\xcd\xfdB\x94\xf4\t\xfe}\xf7\x16f\xb7\xc2<aK\xa1Vf\xfbI7*\xabeS\x1a\xf9\x95\xe8K\xcbG\xdf\xf0\xe5\xbd\x1dW\\\xf9>\xa9\x859\xb0\x02\xa9\xbc\xf2\x81\xc5^\xfa\x03OIӸ\x81\x16\x92\xe6\xe2[!\x01?b\x92\xa4\x19\x03\x9d&\"\xe6+\xc5f\xf8簒nY'\x8cg禒Yi\x1fy\xeb\x840\xa7,ܫ\x8a}+\xf1\xb3ķ\xdc/DIw\xa5\xe4\x90\xder\xdb6\xc5n\x8cZ\x14\x99\xe5\xe4 \xf4%\xdd \xab\xa5\x8e\xbe\xae&#\xfe\xec\xff\xfaј1?\xfa\xb9Oja\x0e\x8c\xe4O\xc1\x94\x979\xf0ڹX\xab}\xf9\xa2\xa4ݱ\x83-d\x1a\xae\xa8\x8f\x12}*$\xe0GL\x924c\xa0\xd3l\xafm\u007f\xb3\xd8\xe1w\xb7\x8doߢk\xba\x9f\x88/gq3\xe8\xf3\\>\xa5\xb4\xee\xc8CId\xa9\xb7\xf0μW\x8el\u00adX\x19ۗ\xba*\x95\x8e\xbb{\xce46&nll$\x8bf'\x13\x17U\xd4\t+O\xd2n\xdf\xe4\xe5|\x86_\u007f\x96\x93\xf7\r\xb3\x15\x11y\x94\xe3C|\x8a>k\xb4m<\xd3\xf7\xceF[#\x8e\xcb\xe3\v_-䉾\xde\xff?\xdf).\x18\xf3\u007f\xff\xb3\xa2\x15\x19\xc3\x1cX\xfa\x14\x8a\xf2\xca\a\xfe,%\xad\xe2\x95\xdcDe\xec`\vٚ\x94Z\xba#\x99\xb7\xed\xf7\xa5\x90\x80\xff0KҌ\x81\xce\xf1\x92\"\xc7q\xa3\xf0\xa1\xe7}fڈ)\x8a\xb2\xd3\xe7_U\x14.JJɥ'oЉ\x9c\xb9\xc99u\x1e\xb1\xe56\xe1\x94\xd1;\xe2ԓJ䣵\xa9\xf7d\x1fQ\xecV\xca\xf3dai#O/\x9fvo\xc5\xf4lKN\xcc9G/\x9f\xe6m\x1f\x90\xb3\xdb[\xf0/EyVRV9\xf9\xadp\xfdpV\u007f\u007f\xe4\x8f~N\xb6\x1a\xc3\x1c\xd8\xfd)\x94\xe5\x95\x0f\xfcŦ\xb4ćΉ\x92\x16c\a[Ht>79\xadp\xbfͷB\x02~\xc34I\x03\xfatF\xce\xc1\x92\xbe\xadyxF.\xea\xe51 \xb8\x00I\x8f@\xa8\xa4#nk\x02I\x03\x03\a$\xad\x84\x1f\t\xfc\xe7\xffƒ\xfe\xe1\xff\xfa\xb7\u007f\xfb\xf9p\x88\x1a$\x1d܀\xa4\x95\x18\xa9\xcd/PIG|\xe7\x87\xdf\xfdN\xc3.\xc7\xe5n4\xa4\x9c\xaf\xe3\x9f~\xcb\xeb\xff\x8f\x01\x01\rHz\x04B\a\xde\x13;\xfa\xbbC0\xa1\x87\xdb;\x87R\xd59\xf87\xc3v\xde(\n\bX@\xd2#\x8f\xde+D\xd2w\xe3*\xfe\xde,W\xf3ؐ\x90\xef\xd9;{\x8dv\x02\x00\x01\x90\xf4\x88\xa3%.f,\x96\xf4f\\\xc5ӛ\xfa\xfbӗ\x1c\x8a\v\x99\xde\x01\x9a\x06|\x03$=\xd2pE|\xef\xf6\x1b\xb0\xa4kq\x15/\xfb\a\x96\xb6\xb3\xbf\u007fF\xf80\x9d\xd0\x02\x82\x0f\x90\xf4H\xa3!\xe4p\u007f8\x964\xc2U|\f\xff\x1d\xc6\u007fs\xc2\x1aF\xc8}\x9c\x80\x11\x0fHz\x84ѻ!\xe4\x1f\xfdd.M\xf8\xa7\xf8\a\x92\x06|\x06$=\xc2\xe8\xce\xfc^\u007f\xff\xc49\xfd\xbd\xae\u007f\xf6w\xe3?\x17\xfe\x03I\x03\xbe\x03\x92\x1ea\xb8\xe6\x85\xf5\xf7\xc7d\xfe\xf3\x1f\xfd\xc7\xff\xf1\xcf\xfe\x86\xde\xfe\xfe&\x9040\x00@\xd2#\f\u05ecHZ\xbb\x9b\x1fs\xf6oXw\xa5\u007f\xdd:\x04\x92\x06\x06\x00Hz\x84\xe1\x9a\x1e\xfdO\x0f@ҀϘ#\xe9\xeeb\xbb@1y\xe5,+\xdag\xc2=MF&\xaei\x93\xff\xe1\xc1,\x904\xe0+\xe6H\x94>:\xac\x00\x00\f\bIDAT\xdae?\xee\xc4\x1c\xb37\xe0\x17\xed\x055\xcd5\x05\xaa\x9bS\x8fZ\\\xd3&zn\x8c\x8e\x02I\x03>b\x8e\xa4\xd1iz\xefnz\v\xc1^\xfax\xa8\x18.\x8f\xa2\xb8\x96\x8d\xa9\xb9\xa2bWȽ\xa7AҀo\x98$i\x8a\x83ܧ\b5\x15Py\x17\x8c\x1c\xefJS\xe9m\n\r\xb9Ổ\xb1\x84\x1b0!?(iq\xa1\x90\x00\xc5\xe8\x13\x03C\x8b\x89\x92n\x12n\nZ)xb9̸\x9f\xe0H\xc4uzŬ\xe9230\x99\x8e\x86˽(\xe4j@\x02\x92\xf63&J\xba\xa4\x92>\xed\x12n\xe0}Ȅ[\xf3\x8fL\\Ζ&\x05\xcd-N\xf2\x9fX i\xc0\x17̓t\x8b]X\x11+\xae\xa5O\xb5\xc5ނG\x17\xdd.%\xddt\x9d\x01$\r\xf8\x82y\x92\xae\x14M\xb0D\xe7\xca*\u007f\xdb\xdc\x05\x1c i\xc0\x17̓t\x91h(M\x1d7\x10*\x83\xb9\xb4\x01D\xd2O\x8eŏ\xac\xb6C<\x12\xde\xf0)HB/Z7\x17\xcd7@\xd2~\xc64Iw\xd8E_\x88&;q\xbc\xbbb\x87\x15o\x03\x88`\xc6\xfd\xf9\xaawI\u007f~\xdfMcn\xf8\xe9\xee\xab\xdahi.\xe4\x16\xe1\xf9\x16\x8fl}\x94t\x88F\x8a}\xdb\xe8s\x01C\x8bi\x92n\xb1_\x16\x12\xbd\xd4;\xa7\n\xceK\x1b\x11\xa2%\x1a\xb5\xa4\u007f\xf1\xb3\xd7?\u007f\xfb\xc9[\xd5a^\b\xb9\x89\xfe\x00\xec\xbe\xe9\xfa%\xad\tH\xdaϘ&\xe9&\xbb\xfb>\x1d\xed\x05U-Up\xf5\x98!d\xc8-\x80\x85\xf2\xcc\u007f\x8c\x19w\x9f\xa8\xa7G\xc7\xfd\xeb\xb8߈\xc2\x1a\xf37\xb7\x94\xa4\x88\an\f\x19{\x01'.\x8c}\x9b\xeey\xf3\x98\x1b\x1fe\xdf\u007f\xfc\xc7$\xfcǏ3\xd9\nG\ty\xfc\xe61c\u007fA2\xfc\r9\xc2Uա^\xff\xe9\xd817?\xee\x8e\xc5G!\x85a\xf6\xb9Q\b\x05I\xfb\x19\xd3$\xdd\"/\x879\xf7\x15\x94\xc15ކH\xbd4~x\xf1\xdf_\xbc\xf0\xfa\x8f\xef\xa3\xe9\xdf߸\xfb\xc2\xee\x1bE\x9d\x8d{QT\xb4\x1cq\xeb\xdbW\u007f\xf28\xde\xf2\xf8Oh\xf4w\x9f\xb9\xf0\xfa/\x149܄G\xf3\u007f\xfe\xbe:[\xda\u007f_x\xfbg?\xc3B\xbfq\xf7\xe7\xbbo|Fu\xa8\x9b\x1f\xf8\xdb\xe7/\xfe\xc4\x1d\x8b\x8fB%\xcd\xec#\x84\x82\xa4\xfd\x8ci\x92\x06\x06\n+\xe9[ɜ\xfa\xedqB\x1ak\xed\xea3\xa2Ξ\x19\xfb\xd3\a\xa8\xaa\xe5\b\x9c\xa0#\xf1[\x9f$ѷ<)\x0429<\x8e\x15\xf8\xb3'\xd5\xd9\n{^\xfd\u007fc\xf1>\xf4\b\xb7\xa8\x0eu\xc3\xdb³\x1c\x1b\xc2\xec#\x85\x82\xa4\xfd\fH:``%=\xd6=\x02'i2\xcc\xfd\x9b\xa8\xb3\xab\u007f{\xf4\xae\x9bIW-G|~\xf5\xea\xe7c\u07fe\xfa\xf6\xd8\xcfI\xb4{d\xce\xe6\xf0\xfd\xd7_\xff\xbeG\xb6\xe2\x03y\xbc\x81\x1e\xe1\x06ա\xfe{\xec]\x8f\xbe-\x95\xe9sQ\xd2\xca}@\xd2\xfe\a$\x1d0\xb0\x92\x1e#\xf6\x90\n\xf1H<\xfe}e\xc4իw\xddw\xf5\xbe\xbb\xe4\x1f\x80\xab\xca\xf7\x9f\xbc\xeb\xae'=\xb2Ւ\xb4\xf2P\u007f~\xe0\xa77<\xc0Ƃ\xa4G\x02 送\x95\xf4-\xbf\x91\xb5\xa7\x18\rS\x88\xfa\xd8\b<I\xbe\xe9\xeaM/\n\xd1\xe2\xc0[\xf1\xfe\xcd7_\xf5Ȗ\x91\xa7\xf6\xc0\x9b\xf0\xfa\rz\x92\x86\x81\xb7Y\x80\xa4\x03\x06Vһ\xc7>\xfa\xb7\v\xbb\u007fLӊ5\xab[\x9f|\xfb\xf3\xd7\u007f\xf6\ve\x04\xe6\xa6\an\x12\xf7\xbc\xf1\xf7tyL\xf5\xbe*\xdbq\xbfw\x1f\x8c<\nK]\xea\xe5\xb1\x1f\xff\xfe\u0085\xdf\xdc\xccƲ\x92~f\x1c\x0e\x1d\a\x92\xf6? 送\x95\xf4\xd5ݷ\x8e\x19s\xebn!\xfd\xe8\x8d\xf2\x99\xa5\xdd?\xbda̸\xff\xbe\xa0\x8a\xb8z\xf5\xbe\u007fu\x9f\xf2z\xe6?\x84\x93X\xca\xf7U\xd9>3.$D\x96\xe7\xd5ߌ\v\x11Ob1\x87\xfa\xfd\xadc\xc6\xfe\xe4u6\x96\x954=\x89\xf5\xc0\x18\x90\xb4\xdf\x01I\a\f\x92\xf6\x02\a<\xde\aI\xfb\x1b\x90t\xc0\x10`\x92\xfeş/\xbc\xf8\xef\x0f\x80\xa4\xfd\x0eH:`\b0I?\xfa\xfd17aE\x83\xa4\xfd\rH:`\b0I\xbb\x01I\xfb\x19\x90t\xc0\x00\x92\x06|\x01$\x1d0\x84\x04(F\x9f\v\x18Z@\xd2\x00\x10T\x80\xa4W\xaf\xd6J\x02@\x80b\x8e\xa4\x95\x06:\bU\x99wK\x93\xbfZ\x9e\xd0H\xbayقI\xc0\x89\xf7~\x19\x1f\xbb\xf0\xe8\xfc7pr\xeb\xcc;\xa6\xde1s;B\xf5\x16\xcbB\x84\x0e\xe0\x88\xa3\xea\xfd\x86\x89\xa3\xf1\u007f\x91\xd2mS-\xb3\xbd\x84z\xe7a\x8b\xe5\x80Q̀\x18\xba\x8aZ\x8dìmFQ\x80.\xe6HZa\xa0\x83\x90\xd3^k\xb0\xc3\xf0\xb1\xd2zI#\xe9\xc6\xf5F}\xec\xf2\xf7\x10:;u遗\x96S\x1d\x1c\xb5\xfcr\xcf\xc1\x17\x96Z\xea\x91\xeb\xa8Ŋ\x1f\x0fX\x8e\xba\xd0\x10s\xf4\xac\xe6\xe6\x83VF\x88\xa7V[5\x83|\xe1R\xfd\xd4\xedF1\x03b\xe8*\xea\xe3\xfa\xfa\xff\xb1\xbca\x14\x05\xe8b\x8e\xa4Y\x03\x1d\xac\xe8\x12\xf3$\xddfY\xaf\x91d\x89']\xf7\xe2\xc5$\xb9\x9a\xb4\xd4\xf5\xb1\xb4\xec\xb18\xd8eY\xb9\x9a\xec\xe7CC\x1d \xf3\x97\x1bE`\xb6\x0f^\xd2\bY\x87V\xd2h(+\xea\x14H\xfa:0I\xd2\x14\xc1@\aU٫\nL\x93\xf4j\xb9g^\xed\xd9I\x13hKM\xd8J\x92\uf456\xbax\x01ݼ`1i\xa9Gq\xb3\xf5\xb9\xa5\x0e\x80\x80\x95\xf4\x90T\x14H\xfaz0QҢ\x81\x0er\xb9ܷ\xe7\xf7?mS\xd7k$\x15Ж\xba<\xfe=\x92>\x88\xdb\xe4BAm\xcb\x17\x92\x96\xda6\xff\x80\xba\xa5\x9e\x9dj\xb1lm[\x99`\xbd\x9f\xdc \xf1\xa5\x85֙\xeb\xe9\xfb\xae'f\xc7.|#\xe1 z\xc4byI\x9e\t\xcb\x01\xf5\x8b\x13\xa6\xc6\xff\x12\xcfG\xffb\x11\x98\x8f\x14|m\xb5\x90=)\x97V\xc6\xc7.\xf7\x1cx\xb7-\x8f\xc7Y\xe0_\xa6N\x9cHXJF\xef\x8fX\xa6\xeeY?Ӻ\xf8cU\xa8u\xfd\xea\xf8;\x96\xb6Ѵ\\\x06\x19\xcd\x1c\x0e\xe2\x12\xfc\x16m\xb7h\xce\xc4\aZQdn\xbd]\xccL>\x1aA\x94\xb4^E!\xf4B\xfc\x1e\x04\xe8`\xa2\xa4E\x03\x1d\x82i\x92^=\xf5c\x8d\xa4\x02\xdaR?N\xb0ܿ\xfd\x14\x1dT\xcc\xff5\xdd\xfc\xeb\xf9\xb4\xa5\xee\xfc\xa5\xba\xa5\xba\x0e\xbc\x94036a\xfdJ\xcb\xc7d\x04\xba\xfe\xe0\xce\xf8\xf9X\xdc_'\xc4\xef<\xf8\xb0ŲG\x9cNJ3a9\xe0\xace偣{\xe2-\xbdd^:sa}}}\x9b\xaa$g\xeb\xebž\xb5-v\xe6\v\u007fYlQK\xfa\xb5\xd8\xf9\xbf;\xbaݲ\x93ho\xf5k\a\x96ZN!\xf4ח\xa6Z\xe2\xb7\xef\x8cUw\xfbV\xcb\xfc\x97^\x9ao%\x02\x94\xcb\xc0\xa0\x99\x83덄\x87/\xa1K[c\xeb5\xfa\xdb\x01WT}\xecVwf\xf2\xd1\b\xa2\xa4u*\n\xb3\xdcr?\x02t0O\xd2n\x03\x1d\x82Y\x92\xfex\xea\xc3\x1aI%\xb4\xa5\xa2\xaf\x9f]0\xd5\x12K\xfa\xa6\xd9+\xe9敳iK\xbdd\xbd\xe49\x9e\x9coY܉\xfb9\xa2\x8b?\"\xd2Bqߺ2\x96\f\xeb\xd7[H\xf7B\x85I\x87\xcdL\xc0\x9ex\xd2\\\xff'V\xc8Ag\xe0-Jz\xe1L|\xc8\xde\xf9*I\xbb\x12\xeeǛ\xbb\x0f|M~WH\x99\x84\\\xac\xb1\xf8\xb7ee\xbc:\xa7\xd98\xc25s\x81\xa2\flf\xda9l'C\x87\x95\x9a'\xfb\x06^Q\xabI\xee\xbf&\x99\xb1Gc\x06ޚ\x15\x85i{\xb6\r\x01:\x98'i\xb7\x81\x0e\xc1,I?2\xb5M#\xa9$\xde}f\xcbu\xf4~\xcbA\xa9\xf3Y.t>\xe8\x97;5$m\x15;\xfc\xe5\tݽ\x98\x04\xdcj\xadt\x92\xf9W\x95\xa4\x99\x80\x8f\xe3\x13\x1e\xd9s\x16u\v9x\x95\xf4\xd74\x17\xb4U%\xe9\x83\x16y\x9d\xfc\xef{\xeeO\x88\x15\x86\xeeV\xa2\x19\x8fy\xb7\xf5\xb7\xe4q\x8f\xe5k\xb6\f,\xda9|ly\x0f\xb9b5\xcfE\r\xbc\xa2^\xb3\xba\x90\xcbZO\x92\xcc\xd14%\xadSH\xc0\x13\xf3$\xed6\xd0!\x98$\xe9K\xd6\xd5\x1aI\x15\xb4\xa5\x9e\x12V\xce\x16.\x15\xfe0K\x85)\":0_C\xd2\xeeY\xf0|qV\xbc\x1cK\x81\xce>]*I\xcb\x01X\xa8{\x96϶\xc4\xffN\xd8ѫ\xa4\xcfZ\xa8\f\xd42\xdd)\x17\xe4T|\xc2\x13\a\xea\x17ϗ\xf6\xf1\x944ͩ\x1e\xff\n\xb0e\x90\xd1\xcb\xe1\xfe'\xd0\xd1\xd8n\xa4\xc1\xc0+\xaa7\xfe\x00z\x99\x0eNأiJZ\xbb\x90\x80\x06\xa6IZ2\xd0!\x98$\xe9\xf5\xb8\xa5y&%z\xe9&\xdaR\xe3\x1f\xa1[\xb6\xceDHlw\xf3\x17\v-\xd5e=\xea)iw\xc3[\x99p\x96\xf2w\xd4+H\xe8=YҴ\x8f\x95\x03\xd0Yr\x9c\xaf_\xb2\xee\x91rx\xc1sr/\xe4\xf2w\xa1\x97V/\x8f\x1d\x95{\xe9\xd9\vH\x99\x96{\x934]\f|\xc1\xd2ɖ\x81A/\x87\xbf\xc4w{\\d7\xe8\x8aZ\xbf\x1c-\xa7\xe5`\x8f\xa6\x96\xb4\xba\xa2\x00\xef\x98&i\xc9@\x87`\x8e\xa4\x8d:\xe9=\xa43\xfc;YmB\xf1\t_\x93-Di\xe2\xe9V\xb2\x03i\xa9h\xf5\xaf\xf5%}T蛷>K\x96\x82Ik\\)H\x1a7\xfe\xde\x05Ve\xc0v\xe1Ҫ\x85tJ\xbf\x10wm\x974\x96\x95Ź\xf4\x02R\x9c6\xabJ\xa6\xae\xf8\x85\xa4\xfb\\\x8fE\x92@J\xd0;ߛ\xa4\x13ȼ{\xf6BE\x19\x18\xf4r\xe8\x8e\xff\xcb\x1d\xeaq\xf7\xa0+\xea\x94\xf5\x92\x95.\x89\xb1Gc%\xadUQ\x98\xb6\xedm\b\xd0\xc14I\xcb\x06:.\xa7\xb3\xa8\xcai\x82\xdd\xc6\x13r\xcf\xfc\x84F'M.\u007f:\xf0\xc7\x05\U00064bcc\xb7\xc4o=z`1\xb9P\xf1\xa8\xe5\xfe\x97\xeb_^ly\x99\\\x14u\xc0\x85\xea\xadʖ\xda{\x8a\xaeW\v\xf9=a\xf9\xf5\x81\x97W\x93E\x9dK\xf1\t{\x0e,\xb7RI/\x8c\xffݳ\v,S\xff\xf8\x1e\x1b\xb0\xdd\x12\xbb\xf5\xe0\x81Ֆ\xd7\xc8~ۭ;_^lU\xf6\xd2\xddo\xd4\xd7[W\xd7\xd7w\xe2\xceޚ\xb0}\xeb\x1dB\x0e\fG\xad\xb3\xf7\x1c\\oy\x81d\xb6|ϳ\xf3\xf10\xfeԥ\xfa\xa9\xabO\xa1\xb3\xab\xa7\xd6+Ϻ[-\xf7\x9f:\xba0\xb6\r\xb1e`\xd0\xcdቄX\xb5}\xd9\xe0*\x8a\x10\xbfXX\xb6\x93\x8f&\\=\xb6\xb3\xbe\x9e\xe4\xa6YQ\x98\xa5\xe4\x02S@\x1b\xd3$-\x1b\xe8\x1c\x13.\xf7\xbe\xe2-z8\xb8d]\xa9\x91d90\xdf\x1a\xbb\x94\xaaf\xc1\v[g[\xe3\x85Ӹ[g\xc6Zbɥ˯\xd1S\xaa\xbd\v\xe2\x15M\xfc\xac0\xe9\x13&\x92\xe8\xe8\xe2\xf8\u0605\aI\xea\xef\xab\x13\xac\x8b\xcfRI\xb7-\xb4\xc6.\xfe\xad\xc5\xf20\x1b\xf0\xd2\xc2\xed\tS\xe3\x17\xbeFws\xad\xbfú\xf0\x14R f,\xe4\xb0\xf4\x8e\x84'\xfe8բZ\xa5o[\x9e\x10\xbb\x80tg\xbd;gZ㗿0s\xea\u0087\xf1\x1eS\xdf#\xa7\xb4\x95\xb1\xb3\xb7/\x8f\x8d_)\xc8\\.\xa4\x8cn\x0em\x16\xcf\x01͠*\x8a\xb0Ӻ\x93>\xcbG\xa3\xd7x\xbbg͚\x15EwS/\xe0\x03\x12\xa6I\xda|~k\xf9\xabFrx\x11\x96\xc7\x02\x1a\x97\xf55\xa3\x90\xe1g\xe9b\xa3\x88\xd1\xcb(\x96\xb4\x19\xffU\x19\x04\x92>\xe0\xd9\xd7\xfa\x9dg-\xaa1\x05 3\x8a%m\x06\x81.\xe9\xed\xaf\xa1\xc5[\x8d\x82\x86\x9d\x8f\xe3w\x1a\x85\x8cb@\xd2\xfe\xa4\xed\xa8e\xbdj\x86\x1cP\xb8,\xf3\x1f\x89\xff\xda(\n0\x15\x90\xb4?YHV\x9aڌ\xa2F0[c\x17\xb7\x19\xc5\x00\xe6\x02\x92\x06\x80\xa0\x02$\r\x00A\x05H\x1a\x00\x82\n\x904\x00\x04\x15 i\x00\b*\xfe?\xb6^u\v\xa5[\x1f\x81\x00\x00\x00\x00IEND\xaeB`\x82",
+
+ "analysis/ident-func.png": "\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x03\xd2\x00\x00\x00\xda\b\x03\x00\x00\x00}\xf6\x8a\x1c\x00\x00\x00\x01sRGB\x00\xae\xce\x1c\xe9\x00\x00\x02\xfdPLTE\x00\x01\x00\x01\x04\x00\x02\x05\x01\n\x03\x01\x05\b\x03\t\f\b\t\x0f\x11\x0e\x10\f\x10\x12\x0f\x13\x15\x12\x15\x16\x14\x0f\x17&\x19\x18\x11\x1a\x1a\x13\x1a\x1c\x19\x1c\x1c\x16\x13\x1e7 \x1f\x19!# $$\x1d#$\"$%#'(&)(\"+)\x1e\x14+N++$*,)/-\"-.,.2402/63(241:7+685;9-:;9?<0=?=C@4AB@CEBGE8KH<MI8HIG\x00f\x00\x00i\x01JLI\x00j\x02SN=MOL\x05m\x051S\x96WRAQSP\fo\t\x0fq\vUVT\fr\x175[\xa4XZW,`\xae7]\xad\x15w\x1cb]K\\^[9a\xab\x19y\x1e;c\xad=d\xae`b_)z!?f\xb0)|*Bh\xb3egdLi\xafDl\xb0qjRikh/\x82/Ho\xb3/\x859Jq\xb6mol;\x86:Ut\xb4Xv\xb6?\x8a>|u]tvsB\x8c@@\x8dG\\z\xbby{x]~\xb7e|\xb8\x84|dK\x90J_\x80\xba}\u007f|O\x93Nb\x83\xbd\x8b\x81cN\x95Ud\x85\xbf\x81\x83\x80W\x95Vl\x87\xbc\x8f\x86hZ\x98Yo\x89\xbe\\\x9a[\x87\x89\x86\x93\x89k^\x9d]\\\x9dds\x8dË\x8d\x8a\x96\x8doz\x8e\xbfe\x9ef\x8d\x8f\x8c|\x90\xc1\x9b\x91s\x90\x92\x8fi\xa2i~\x93\xc4x\x95Ā\x94œ\x94\x91{\x98\xc7s\xa4l\xa0\x96xq\xa5s\x97\x99\x96\x83\x9bţ\x99{\x99\x9b\x98u\xaaw\xa7\x9d~\x87\x9fɜ\x9e\x9b\u007f\xabz\x89\xa1˫\xa0\x82\x9f\xa1\x9e\x8f\xa2ǡ\xa3\xa0\xa2\xa4\xa1\x92\xa5ʂ\xb1\x85\xa5\xa7\xa4\x94\xa8ͳ\xa7\x82\x8b\xb3\x89\xa7\xa9\xa6\x96\xaa϶\xa9\x84\x8e\xb6\x8c\x9d\xac̪\xac\xa9\x8d\xb8\x93\xba\xad\x88\x9f\xafέ\xaf\xac\xa1\xb1ѯ\xb1\xae\x97\xbb\x97\xc0\xb3\x8e\xa5\xb4Ԛ\xbe\x9a\xb3\xb5\xb2\xab\xb7ѵ\xb7\xb4\xa3\xbf\x9d\xa2\xc0\xa4Ÿ\x93\xb7\xb9\xb6\xae\xbaԹ\xbb\xb8\xb0\xbc֦Ũ\xbb\xbd\xba\xb2\xbdض\xbeӽ\xbf\xbc\xa8ǫ\xafƫ\xcd\xc0\x9a\xb9\xc0տ\xc1\xbe\xba\xc2ײɮ\xc2\xc4\xc1\xbc\xc4ٲ̷\xd2Š\xc4\xc6\xc3\xd5ƚ\xc0\xc8ݻ\xca\xde\xc7\xc9ƻκ\xd8ɝ\xc0\xcc\xda\xc7\xcb\xdb\xca\xccɿҾ\xc9\xcd\xdd\xd7ϡ\xcd\xcf\xcc\xc4\xd0\xde\xdfϣ\xc8\xd3\xc1\xcc\xd0\xe0\xcf\xd1\xce\xe1Ҧ\xc9\xd7\xcb\xd2\xd4\xd1\xd2\xd3\xdd\xdf֨\xcd\xd6\xde\xcc\xda\xce\xe6֪\xd6\xd8\xd5\xd0\xd9\xe1\xd8\xd9\xe3\xd5\xdc\xd1\xd3\xdc\xe4\xda\xdc\xd9\xe6ݯ\xecܰ\xd5\xdf\xda\xdc\xdc\xe7\xdc\xde\xdb\xda\xdf\xe2\xd7\xe1\xdc\xe0\xde\xe2\xde\xe0\xdd\xf0\xe0\xb3\xdf\xe1\xde\xdd\xe3\xe5\xe1\xe3\xdf\xe3\xe5\xe2\xe1\xe6\xe9\xe8\xe5\xea\xe5\xe7\xe4\xe4\xe9\xeb\xe7\xe9\xe6\xf1\xf3\xf0\xfa\xfc\xf9\xfe\xff\xfcd\x82\x05\xe8\x00\x00 \x00IDATx^\xed\x9d\x0fT\x14\xd7\xdd\xf7\x1fZ\xf3\xc6\xe6M\xda\xd7Q\xf6\xe9S\xe2K\xa9%F\xdbd\x95x\xdeJ\xa0fN\\@\x13\x90*\x82Ę*M\xa2\xb4Q⟜h0\xc4\x1c\xff\xb4.\xc1@\f\th\"I\xa4\xc1\x83A\xa4V\xadx\fA\x03\x96'\xc1D\x92\x87\xa4\xa6nj$QL#\t\x1c\x16\x02\xb7\xf5\xbc\xf7ޙ\x9d\xb93;\xb3\xb3\xc0\xee\x0e\f\xbf\xcf\xd1ݻw\u007f\xf7\xcfܹ\u07fd\u007ff\x98\xdf\u007f\\\x1b<\b\x00\x80\xe1\xc6\u007f\x18\xe9\xd6\aFy\x03\x00\x10r@\xd2\x00`)@\xd2\x00`)@\xd2\x00`)@\xd2\x00\x10`\xfa\x8c\f\x82\nH\x1a\x00\x02\x89+c\x127\xc7\xc8(\x98X^\xd2e3یL̤}f\x99\x91\xc9Hd\x14\xb7\xfaԩ\xce\xcaO\x8c\x8c\x82\x89\x89\x92n\xdeWTrB\f79\xcb}\xda~\xb3y^bN\xbfO\x13m\x9e\xe4\xd6\x19\x99\x04\x8as9I\xa9\xb9\xa7R\xbfR\xc7\u007f\xee\xe0\xefӲ\x17xr\xc2\x06\xaf\xb8\"\x0e\x135\xfb\xa4\x869Ck87\xd5_[?!\x99\xadC\xeb\xf0k\x81\x0f+\xa1`_\x04\xbeիxLr\xce\xfbFv~\xa2\xd5ꁡ\x81\xdbgd\x12dL\x93\xb4\xbb\xd2y\xb4\xf5\xa4\xb3\x85~h/8\\\xec\xd3\xfa\x91Ԋ\xbc\xa4\x0e\x9f&\x9al\x9dPdd\x12(\xea\x93~Sqp)\xcf\u007f\xa4\xfe\xa2\xff\x9d\xcd\x0e\xad\x04\"\xe5\xe1[\xd5QW\x8b\xb8\r\xd5E3\xb9j-{\x99\xa3\x196\xbfm}S-\xfe\"\x90\xcc\xdaPۓ\\\xd1U_\xe6\xb4`\x1f\x04\xa1ջ\xab\xf8\x97NUe\xddu\xca\xc8\xd0\x17\xa7\xceJA\x8dV\x0f\f\xb5\\\x8d\x91I\x901Mҕ\x05.\x84ڜ\xcd\xf4Cy\xa5˧\xa4;\xf8\n\xd4\xdf\xed\xcbB\x9bV\xdbr\xdf\x06mq\x81\x9a v$\xaf\xe9\xc5=/\xd3[\xd2\b\x95\xfa\x924Zis\xa9\xa3\x9a\xe8O\xfd\xcc)\x1a\xd6,\xebl\xfe\xdb\xfadF\x8a\x18\x102\xab\xe6\x9a|Y\x8b\x05\xeb\x12\x94V?\xc7\xd7\xe3_\xc7\xecL#;_d\xad\x97\xc3\x1a\xad\x1e\x10j\xb9\xa3F&A\xc6,I\xbb\x9c\r\xe4M\x18\f\x9a\x8aܾ%}\x81?\xee\xebk]2&u\xfa6h2\xea\xbc~S\x98t\x99\xbc\xed\xe5?\xf5\xfeη\xa4;'e\xa8\xa3\x04em\xe5\fj\xcfH\xda\xd0\xd6'\xd3\x03*頴:\x954\xaa\xe0\a\xf1\xc3.\xb1\x94\x91\xb4F\xab\a\x84\xd1+\xe9\xa3\x05=R\xf8jA\v\xf2!\xe9\xdey<%\x1f\xa1m<\u007fP\\\x9bn\xe3\x1d\x15\xf9\x99I9_P\x9b\v\xeb\xe79RŰ\x8c{\xa24\\\xb4\xa4D\x85O\x9a\xad\xfca\xde:\xa5\xbc\x99k.\x9f\xe2\xc4\xe1ƜtǼ\x9ct\xb2\\\xef\xaf\xcaJ\xca\xcc\xc7]\xe7C\a\xcf0\x97\x9e\x98\xf3\xedA\\~)*\xe5I\xf9\x9a\x06(s\vͳc/\x1e\xab\xfb+\xb2\x92\x96VХ\xff\x17\xb9i\xc9녉\xb7\x94\f\xa9\xea\xbb2\u008d\x94\bʚ\x1fM?\x14ό\x98\xb2\x8c\x88\xe4j\xca$[\xf4\x1c\xfaS\x88\\\xf3'E\xa6dȒVۢ\xce\xe5S'\xc6\x1d\x8dއ\x96p\x13\x8a\xf1\xc0).\u007fe\x83\x9aY\xd1\xe1Q\xb3q\xb2rN`:RIڠ`٠!\x9c\xe3V\xb6̟\x1c1\x9b\x9cTO\xab+c%\xe4Vg\x9a\x8f\x9c\xcd-i\xc9k.P\x13\xad\xb3)H:7\x8d\x84\x99\x96\xec.\xbc/)\xfb\x9d\xb4z\xb6k(\f\xa4\x13{\\\xe8E|\x96\x98\xa1w\xabk\x1e\x90\xf2(\x9c\xd3#\xa6\x93\xee\xa2sl\x88\xb4\xddh\x95tYy\xf3ng\xf1aڪ\xe5\x95ȗ\xa4\xd1G\x8d\a\xf9\xd2\xc6F<\n~\xd1\xe8(\x15צ\xe7\x0e:\xf8\xd4\xd2W\x92\xe9\x0f賓\xacW\xeaK\xf9\xbd\xaa\x84'\xa5\x15f\xf5\xc4\xe9OV\xae\xe36)\xbev\xcd\xe7\xa6r\xb7s)X\xe8\xefߕw\xa4\xbeb\x1e\xff-\x8e\xde\xc2\xe7\xd7W\xa4.\xedG\xbd\a\x0f\xa6gޓ\x96\x9f{\xd7\xe7ݍ\xc9/|\x85\xbez!\xb9\xb1[۠\x97-<ϱ\xb3~\xa7#\x0f\x87.$gV\x1d\xcfᩤ\xa5d\xea\xfa\x1e\xf6\xea\x05M\\\xb9\xbby9G\xb7p2&,)\xdf\x1a5\xbd\x8fh/\xa3\xbad΄Z\x1c\xd92qJQ\xd9,Φk\xdb>9\xea\xc9\xf2%\x1c\xe7D\xae\x9a\xf0u\xd2\xf2W6\xa8\xe5\xe6\xef\xaetFq=\xa8\xf3p͔\xb8\x9a\x9a\x9af13\xb7{\x1f\x95\xb4Q\xc1\xb2\x81\xbb\xa48z\xca\xc4\xe8e\xf39\xb2\xd5\xebiue\xac\x84\xdc\xeaL\U000d1cd9^Z\x9a\x9et\x0e\xe9\x9cM,\xe9\xeeO\v\xf1\xef*b[\xb2#=yo=Vs\x05\xdb5X\x03\xf9\xc4v76ff766zfQޭ\xaey@\x8a\xa3Ȱ\xad,_i\x9b\xaf{l=m\xd53\"\x872]\n\x04fI\xba\xc4Y\xdc\xe0j..\xc1\x9an.\xea\xf4-iv\xe2\xed \xe7T\x98\xc8:\x92\xf1\xefx^*\x0e\xf5\xa6\xe7\u0c71\xf7\xa0z\xff\xac\x9ck\x15\x02\xee\xe8\xd9nr\x1e\xdaU\x06\xfb¹p\xbaAY\x91J\xc4\\\x91\x8c;\xc1q\xbe\n\aϒ\xe1\x18O\xd5\xf8G\xba\x85U\xfc\x96\\\xfc\x92K\x86bM\x83\xcf\xf9\xbfH\xb9\xd6\xd3\x01\x85\xbefg\xe2\xb4\xfdK\x1d\xcad\xaa\xfa\xba\xb8\xddHI\x13\x1d6\xe7\x93`9G\xb6\x9aj\xb9\x17I\xfdIo\xb9\x9d\\\xf4\x9c9\x19\a\xfb\xa6\xdbtm\xe7G\x92\x19\xc92\x8e\f)6\xb2\xfdL\xe7ʌ\x813\x8a\x8c/[#iy\xcc\xc4[\xa0ɏ\x82\x19\x03\x9c\x037몸\x8e\x92Z]\x11\xcb \xb5:۾\x8e\xf4n\xa2\xd0,\xbd\xb3y\x8e\x0e\xb1y\xe4\a\x91i\xc9<\xd2\aP>\x964\xdb5\x18\x03\xe6\xc4*'\xde\x1a\xad\xaew@Rp\x1f\x9d\xc3\b\xaf\x9a\xc76\a7\x9d\xefK7!\xc0,I\x97\x17\x90\xc6\xe8,\xaaE\x9d\x05\xcd}}}\x9f\x14\xfb\xba\xe5F[\xd2y\x9e`\xbd֞\x14\xa6\xccӹʹ\x06\x8d\xafۗ٢\xb9I\xb6eX\xe8\x97\xd3\xd2\xf3+>\xea\xc7]\t\xe5\xa6\xf7~\x8bI\xa3\x13饎\xcfE\xe3S\x89ݨ;锞A\xafC\x1eT\xb6\b\u05ec\xee\xdbL\xb7\xf50;\x1d\xcad\xaa\xfa\xba\x84N\xc4\xd0\xc4m:Z>3\x82\xd4>e\xb2\xbb\a\x13MV~m\xceٓ'r\xb7\xe3\x9aS\xa9\xa2\x956]\xdb\bz\x15\xa9Y%i\xc6\xc05i\xf2\x12g\x03\x12&\x9f\x8c\xa47\xd5\xd6\xd6n\"\x926,\x985@\xd3m\xd2pU\xc6HZ\x8e\x95`Z\x9dm_G!y\xad\xe0;t\xce\xe69\xfe\x95\xb3dz\x12\x89\xb9ܒ\xfdI\xa5\xc2wJI3M͜X/I\xab[]\uf024`\xc6\xed\xf4m\xaa\xda@\xe2\x93}Ω\xa3v\x94\xae\x16~\"\xab\xcbP\xabӃ\xfe\x16\xa4\xb6\xa4\xa5\xe0^\xbeW3\xd9Q\xcf\xdcj+\xe7\xbdnB\xe8\xc9('^\xd5m\x8d\"s֎\x8a\xf5\x99\xfc\xbc\x97\xfa\xc9\xc0!\xb0\x86\x98,\xf5\xac\xbcз\xc9GБy\xe4\xc7^\xdb@\\K\xf7\xe2\xa1\xf9a\xfa\r\xca\xc9\xc2\x03E#\t\xd1J2\xc9T\xf5\xad\xe5\x0e#%tI\xdb>\x81\xc8g\xba8n\xe2!\xb2vR\xf4\xf2\xdd5q\xb8_\x9d\x10\xae\x94\xc8\xdbcj[q\b\xba\xaa\x924\x93\x19jw\xa6L增\xa4\xe5im\x8f\x19\x16\xccf\x86\xa6ϐ*\u007fT\x9e\xd12\xb1\x12l\xab3\xedK\xcf&j\xe4\xcf\xea\x9cM\xba\x96\x16~\"\xe5\x96\xfc\x82?B\xbe\xebVI\x9a=C\xf2\x89UIڻ\xd5\xf5\x0eH\nΜM\xdff\xcfP\x19\xb0\xd4p\xb5\x9a\xf1\xa1\xc3,I\x9f,\xa2\xa3r%\x9e\xa6\xb4\x11\x9a\x8a\xda|\\\xd8PIz\xa7Jҧ\xf8\x0f5\x93u\xda\xc4;\x1e*9\xcd[1\xdct\uf568\xfdl!Y\x98\x1dL\xac ?\xf1g)t\xde\xc7t\x82\xfc5h}>\th\x1b\x14&\xd2\xcf\a\xf9\xaf\xd0\x16a\x97-=\x0f}#\x8c\xd2y\x0ee2U}\xd7\xd9\xd4SSAY\x13I\xed\xe7O>I\xc1\xad3u&\xa9j\x8a<X2\xdbc*\xdb>a\x94n\x92%M\aV&\xb3\x13d\x0f\xeb\xea\x8b\x114#*\xe9\x82O\x14\x926,\x981`~\x14\x98VW\xc4\xcaȭζ\xaf\x83\xb6-\xd9\xd1\xd6>\x9b\xc2\xf6X29\xe7rK\x8a\xa3\xf4G\xb2\xa4w\xaa\x9a\x9a9\xb1biU\xe2\xbc\xc0\xbb\xd5\xf5\x0eH\nfL\xa6o\x933T\x06,\xa3wǻ\x9d^ĺZ\xe0\xb9}\xccߵt\x12\x9e\x9f\xf5\xffF%\xe9\xee\xd4l\xf2Þ\x9f\xafN\x972E\x98\xcewN\x8a#]h\xc92\xb5\x81+R\x98\x1a\x94\xd2\x0e\x83\xb27\x93Y1]$\x17\xbeD^\x19I\xbf\x9bx9\xf1]\x12\xd06\xe8H^O\xf6\xba\xb3\xd3=\x06\aI\x96Y\xe9\xb8[}\x9a\xe8P&Sַo\xeal\xa4BP֤e\r\xeb\xf0ʭ\x84ĬăZ4\xe9D}\xd3\xc9\xecoF4\x9e\xb7\xb6\xd8l\xba\xb6)Q\xa4cΧ\n\x8c\xc0\xea\xed\x9bAl\x19\x83u\u008a0n\t}\x8dÿ\xac\xe4;F҆\x053\x06\xca\x0e\xeeiu\xddn\xefiu\x85\xa4\xe7\xe1\xb5twz\xb6\xbauZ7\b\xd3xAҩ\xf9\xe7Jٖ\\?\x0f\xb7o\u007f\x1e\x95\xb4\xdc5\x18\x03\xe6\xc4\xe2W\x9c\xfbW\xc2wZ\xad\xaew@R\xb0\x9c\xce\xd5_\x14\x96\xcb i5'\nN\xb8\x9a\x8aw\xf7\xd0\x0f}\xae\xa6\"\x97z\xefJB\xd8\xf1~\x87Ν\x1eN}\xa94\x8bwT\x9d\xbb\xdc\xe8\xd8\xfcN\xff\xfb\x9b\x1dd'\xfcT\xe2}\x15\xf5\xc2&\x89\x82\x96\t\xe2\x1ew\xb5m\xaa\xb3|\x89\xfem\x8e\xa5|R\xe9\xf1#[x\xb2V.\xbc+\xf7\xc8_\xb6\xe03\xff\xed\xbbt\x8fT\xfcU\xefO\xcbI\xa3U\xd01\xa8Oz\xb8\xeax\x8e\x83̴s\xf9\xc2\xe3\x85<\xd9O;\x97\x94V\xba3\x99ԗI\xa6\xaa\xef&\xef)\x84pWa\xdcl\xb2x[Υ\x94\x94ep\xc5D\x85)\xce\r\xd3\xf1d\xf9(j\x8a\x88^\xb72rBxQ\xb3\x8e\xadkR\xb4s\xf7\x1c\x1b\x95\xf4̨\r\x1bfr\xc4V\x91\xd9\xc4u\xe5\xbb3\x84\xdd\xe9u\xb6Me\xb3\"\\ʻnj\n\x96\rz\x8e\xd2=s\xcf\x12ZluU\xac7\x8a\xe6s\xf0Y\a+2\x93\xc9~\xb4\xa2u\xe6p\x82\xf4\x04Ig\xe7l^ʶ\xe4\xe5\xd4\xf4\x8a#k\x12\xa9\xad\xd45X\x03\xf6\xc4\xe2\xdf\xff\xbdG\x1e\x11\xee\x1f\xd0ju\xcd\x03R\x1c\xc5\xfc\t\xcb˗O\x98\xef\xeb\xd8Nx\xcd\xe7C\x8di\x92F-eE\xbbO\b\x8aF.\xb2\x94\xd6\x1b\xa7{\x93\xe9\xc2\xc8A\xaf>\\\xc8N\xbc'g'\xcfo\xdbF\xa2>J¯\xdbp\xf4\xa7\xeb\xd3\xee\xc9:\xe2\x9dv\xa5Ml\xe0\x96\x94\xe8\x893\xd4[\x9c2U٥\xe9\x8e\xd4l\xe1v\xc3\xfa\xecy\xc9ٸ\x03}(\xac\xc8rD\x9b\xbd\xd2\x0e\x98\xb6\xc1\xb9\x9c\xa4yk\xe8\xceN\u007f\xc5R\xcfu\xe9\vk\x92\xd3\v\xab\x1c\xb4\x92\x9edHQߚ\b\xaf\xb9C\t^\xd0\xe1EnÔ(2\x1e싋\x8a\x9cId۷i\x8a-*\xa5h\x8a-\x0e\x1fϜ\xc8\xc9ˊ¹%:\xb6\xa8-#:b\xd6\t*閸\x88\x89\xb3\x96s\xdc\x12֠8n]t\xf8\xa48\xf1zӒȈ\xb8Z\xf6\x1eo\xa7a\xc1\x8cA\xc3\x04\xba\x06\x95\x86=\xa1\xd5ձ^(\x9aϑ\xbf%9-O\x90\x1b{6\x8b\xa2\xe8T\x9f\xdc\x18\xf0\nn\xe3\xccyd\xbe&\xb7dǖ\xf4\xc4G\xceRIK]\x835P\x9c\xd8\xde\xfc\xe4\xc4l\xe1\xa6P\x8dVG\x9a\a\xa4<\x8a\xad\xb7Gܾ\xd5+\x96\xa5-<\xa5\xa1\xcdԿ\xae4Oҡa\x99\xad\xc4\xc8\xc4\\^\xb4e\xf4\x18\xd9\f\x9aNa\xe9\x1br\x06\xd1\xea\xc2\xf6\xd8\xe0\xe8\xf6\x9e\x9f\x19\x10\xc4V/\x9b\xca\xc1\x1fW\x06\x95M\xd1\x03\xbf\x9f8\x84\xb4O\n֟\x04\x11̒\xf4 Z=\xa4\x92\x0en\xab\xb75\x04\xe7\xf6q?\xb1\xbc\xa4G5\xa6Iz\xe0\x84TҖ\x06$maZ\xf6q\xcb\xcc\xde\u007f\xf5\x8f/\xe8f\xa7\x91\x95\x0e\x17\xea\xf9\xfcw\a\x9b\xd8z\x80\xa4-\xccL\x8e\xe3\xc2[\x8c\xac\x86\x03t\xb3\xf3s48\xb2I\xe2\vFV\xa3\x06\x904\x00X\n\x904\x00X\n\x904\x00X\n\x904\x00X\n\x904\x00X\n\x904\x00X\n\x904\x00X\n\x904\x00X\n\x90\xb4i\x1c\xcf\xfa*\xb8\xae\\\x80Q\x89\x89\x92\xf68\xd0q\x17\xd1\xc7\x14\x15i=K\xc8¼ė\x92\x9b\x18\x83\xe7\xca\x05\x18\x9d\x98&iفN\xbb\xb3\xc1\x85\x19\xe8\x9f\xee\x8c<\x18\xff-\xe4\x91<UB h\xae\\\x80щi\x92\x96\x1d\xe8\xb4;\xbd\x1f\xb5hIX\xff-\x17\x84'b\x12\x82\xe5\xca\x05\x18\x9d\x98%iƁΨ\x914\xfb\x80\xca-\xa9\x92'\x98`\xb9r\x01F'fI\x9aq\xa0c\xa2\xa45<\xb5\xb0Nq4=\xb5\xf8a\xab\xe5\x8dG\u9fe5\xf7\x1ei\x90\xd6v\xe5\x02\x00\x83\xc4,I3\x0etڝ\x958XcB\xb7\xd6\xf2\xd4\xc2xu\xd1\xf6\xd4bl\xab\xe9\x8dG\xe9\xbf\xe5}\xe1\x01\xdf\x02\x1a\xae\\\x00`\xb0\x98%iƁ\xceU\x1a,y1\xe4\x9a\xd6\xf3\xbb#yu\xd1\xf1\xd4bd\xab\xeb\x8dG\x9ex׳\x0e.\xbd]\xb9\x00\xc0\xa01KҲ\x03\x1d\x84\x9a\x88\x98\xddE!\x1f\xaa\xf4\xfc\xeeH^]t<\xb5\x18\xd8\xea{\xe3\x91%}\x84g\xfe\xde\xdfە\v\x00\f\x1a\xb3$-;\xd0\xf1P\x13\xf2\xa1J\xcf\xef\x8e\xe4\xd5E\xc7S\x8b\x81\xad\xbe7\x1eY\xd2\xef\xf0\xef\xc8yx\xbbr\x01\x80Ac\x96\xa4\x19\a:\x95\x82\xaf\xbf\xear\x9f\t\x82\x80\x9e\xdf\x1dIz:\x9eZ\fl}{\xe3\x11\xfc\xb7t\xb3O\xcf\xf3v\xe5\x02\x00\x83\xc6,I3\x0et\xca\xe9\xf0\xdc^\xd4`\x90$\xe0h{jad\xaa\xe3\xa9\xc5\xc8V\xcf\x1b\x0f\xeb\xbfe}\xa6\xf4\xfc;\rW.\x000h̒4\xe3@\xc7\xe5\xdc\xd7\xf2ɉ\x82\x90\x0f\xd2ڞZ\x14^]\xb4=\xb5\x18\xd9jz\xe3AJ\xff-\x9f\x12\xdf\x11\x02Z\xae\\\x00`\xb0\x98&iƁN[eqQy\x93\x91}0\xd0\xf0Ԣt\x8a\xa3\xe9\xa9\xc5\xc8V\xd3\x1b\x0fR\xf8oA\xe8\x85D\xf12\x96\xb6+\x17\x00\x18$\xe6Iz$\x12\xc0g\xc0\xf7\xe7;\xe8\xd0\x1dDW.\xc0\xa8\x04$=\x10\x02(iԿ7\xad#خ\\\x80Q\bHz \x04R\xd2\x00\x10\x14@\xd2\x03\x00<\xb5\x00\xc3\x1f\x90\xf4\x00\x00O-\xc0\xf0\a$\r\x00\x96\x02$\r\x00\x96\x02$\r\x00\x96\x02$\r\x00\x96\x02$\r\x00\x96\x02$\r\x00\x96\x02$\rX\x95>#\x03k\x02\x92\x06,\x89+c\x127\xc7\xc8Ȓ\x80\xa4G\x1f\xd4s\xcf\xd0\x19\u07be\u007f\xa6NuV\x9a\xf6\xe4YS1Q\xd2\x1e\a:\xca`h\xa9\x8c\x92\xfeL\xbb}IT\xc4lS\xe6j\x9f;\xf8\xfb\x8cl\x10y\xae\x12\xe6\xae\xcc\n\xbf\xefH\xd5\xc9W\xf4\xdc\xd3>+\xf2I\x8do\a@\x80}\xff\x94G\xfa\xff'\xf3\x9e\xf3\x96\xc1q\\D\x8b\x86A\x03\xb7O#vT`\x9a\xa4e\a:l0ԔGHO<\x9b5ə\x11\xd1\xee\xcb8X\xf4\xbf\xb3\xd9ad\x83\xe9x\x89\xafj\xac\xcf\xe5_02\xf4\xa0\x9d\xaf\xc7sϲ\xc9ON\x18\xa2Ӣ\xc0\xfa\xfeY\xce-72\x91\xf0\x9c7WM\xcdV\xcdG&\xd7r5\x1a\xb1\xa3\x02\xd3$-;\xd0a\x83\xe6\xd1\xce\xe1\xee\xd9id\x15$J\xfd\x914\xaa\xe7\xcfa\x9dnc\x9f\x17l\x80F\xbe\x92\xe7\x9e\x19\x1bP\xc4P\xbb}@}\xff\xac\xe4V\x1a\x99hQ\xab#\xe9\x90?pv\xb8`\x96\xa4\x19\a:L\xd0DZ8\xff\xa7}\x01g\x00\x92F\xbd\xc9ی\f%4\xf2\x95<\xf7\xdc^\xe4\xe2\x86:1\n\xa8\xef\x9fu\xdc:#\x13-@\xd2*̒4\xe3@\x87\t\x86\x96\xf6\b\x8e\x9bPLB\xee(\x8e\xe2\xf5Ƞ\xe2\x99\x11S\x96ᱻ!\x9c\xe3V\xb6̟\x1c1\xbb\x87\t\xaa\x8c\xc5\xc7\x17\xb9&\n\x99q\x13UC\x98\x86\xbb\x1e\x84\xbe\xc8MK^/L\x90\x19\x17<\x9a\xb6\x82\xa4Ѷy\xba\xb6\xfd\x15YIK\x85ŶN\xbe\xb2\xe7\x9e\xd9+\xe7\u070e\x8f%\xbcY\xbb4\xff\x1c\tɾ\u007făW %c2S\xe4\xab\xe0I\x8e\xae\xed\xb5\x9bo\t\x17\xee\\6%b\x16\x89\x93\xcf\x1bA[\xbc\xd5 \xe9\xc1`\x94\xb7/\x18\a:L0Ĝ\xa8\xa9\xb1\t#CC͋ܺ\x9a\x1a\xf542c\u0092\xf2\xadQ\xd3\xfb\x90\xbb\xa48z\xca\xc4\xe8e\xf3\xb9O\x98\xa0\xcaZ|Ƞ\xbbh\xab\x80\xcac\xb6\x96\xbb\x1et!9\xb3\xeax\x0eO\xa5'\xbb\xe0Ѷ\x15%]\xc1w\xeb\xd9\xe69v\xd6\xeft\xe4\xe9\xe7\xcbx\xeeY7\xd1v\xa2gv\xdcQ\x9d\xd2\xfcs$$\xfb\xfe\x11\x0f^\x81\x94\x8c\xc9L\x91\xaf\x82\xad\x1c]\x99k7_sq8\x17\xb5n\xd3Dz]J>oHS\xd2=m\xd53\"\xcdZD\x99\x8eY\x92f\x1c\xe80\xc1\xd0\x13\xe1\xe9\x1aZ\x13\xefr\xae\b\x91>C\x9daL\xe7f]\x15\x97\aL\x90\xc5\xf3(\xe0\xb6V\x01\xe5擶\xbb\x9e\xecL\xac\xcf\xfe\xa5Dz\x8c\xb3\x1dm[Q\xd2\xc4\xf9\x8e\xb6m=}\xda0}\xd5Η\xf5ܳ\x81s\xa2\xab\x11䠇\xe0HH\xf6\xfd#?\aYB\xe9=ȓ\x99\"\xc8\xe2\xe4\x84q^\xbb\xf9\x90-\x12\xff\xe0Ώ\x12?E\xf8\x92\xf4\x1c<ƛ\xb8\x8c2\x19\xb3$\xcd8\xd0a}\xe9\x84\x1c\x9f\x92N\x99\xec\xee\xc1D\xd3\x05\xe3t\x9b4*3A\rZ9\x0f\x8aN\xae鮧C\xd0\xc6N\"=\xc6َ\xb6k\x1fQ\xd2U|\x87\x8e\xed\x16\xe1\x9a\xd5}\x9b\xf5\xf2e<\xf7\x94p\x91\xcbЦI=hH\x8e\x84|\xfa\xfeQz\x0frH\xa32\x13d)\xa2?\xa0z͇l\xe4,\xac\xb3\x89\x9f|J\xfa\x93}Ω0J\x0f\x06\xa3\xbc}\xc18\xd0\xf1\xf6\xa5\x13B|Jz\xbaط\xe8lo\xfa\f9^\x0ejQS.\xa0\xdcO\xd6t\xd7sV\x98\a\xd3m,\xc6َ\xb6k\x1fQ҅\xc9z\xb6\x0fS?=('K/_\xd9sO[IJj[\xebdz\xf4Cp$\xe4\xd3\xf7\x8f\xd2{\x90'3E\x90\xe5p\xa4\xa0M\xed\xe6Ct\xaaퟤ15\x9c)#\xc4p\xc0,I3\x0et\x98`\xe8\xf1)\xe9\xf9\x93OR\xe8\x14pz\x8a\x14\xcf\x04\xfdG\xd3]\xcf7\x826\xf2\x84\xd1Tr\xb6\xa3\xed\xdaG\xdc\xf1N]\xafg\xbbEpi\x9d\x9e\xa7\x97\xaf칧\f\x8f\x81s&O\xa4\xd7\xe1\x87\xe0Hȧ\xef\x1fo\xefA\x02Lp\x00\fLҰ\xe3=(\x8c\xf2\xf6\x05\xe3@\x87\t\x86\x1e\x9f\x92\xdeǕ\x90\xb7\x95\xf4&)cIk,'\x19\xb4\xdd\xf5d\xa5\xe3\x0e\xffi\"\x91\x1e\xe3lG\xdbV\x90t!\x11\xa0\xb6\xad\x10{\x90\xac\xa5\xb5\xf3E\x92\xe7\x9e\xdd\\\vj\xe0RP_t\xeb\x10\x1c\t1\xbe\u007fZ\xd7y]\x11S\x14\f\x92\x0e\x15fI\x9aq\xa0\xc3\x06C\x8a\xfbhM\x8d-\xa3\xa6\xe6\xaag\xc7۫\x17,\xe7RJ\xca2\xb8b\xd4s\xb4fJ\\M\r\xe9\xecLP\x85֦/\x83\x96\xbb\x1et.)\xadtg2\xef\xa8:\xa7p\xb6\xa3e+\xdc=\x96\xc7\xd3qR\xdb6\x97/<^\xc8\xe7\xea\xe7+y\xeei\x8bH\xd9\x1d=ŶdCx\xdb\x10\x1c\t1\xbe\u007f\xe6p3\x91\x1a)\x19\x93\x99\"_\x05\xe5\x13}\xcc\xd3\\5\xe1\x19G\xd1Ɍ\xf0\x1a\x17{\xde\xe8\xddc[kj\xbc\xf66N\x8c^o\xa0\xa6I\x9aq\xa0\xc3\x06CI\xed\x04a\xa9\xecD\xeeH\x1a\b\xf7\xba\x81m_\\T\xe4\xcc}X\xf2\x82)\xe9\xecLP\x85֥Y\x16\rw=\b]X\x93\x9c^X\xe5\xe0\xc9\xfd#\x8c\xb3\x1d\r[z\x8f7\x9f.Ny5m\xfb+\x96z\xaeK\xeb\xe4+y\uea5c\x12\xb5\xa4\xb3rJ\xa4S\xa74\u007f\x1c\t\xb1\xbe\u007f\xb6ڢ\x90\x17\x9edLf\xca|Y\xf6E\xf9\xb8-{\t9=M\x11\xf8u\ts\xde\xe8=\xde\x04\xafiS[xJC\x9b)w웎y\x92\x06\x82B_\xfbU\xdfW\x03=\x9e{\x86\x82\xb0=\xa6\xf4\xfd3'N\xcf\xda\x14ʦr\xf0Ǖ\x03\xc6(o \xf4\xb8&\x8d\x193\xc5\xe5SԂ\xe7\x9e!A%\xad\xf4\xfd\xb3a\xd8]\tnk\b\xe0\r\xe8#\b\x90\xf4\x88\x81\xf7\x83_\xfe\xd7\xff*.\x18\xf3_\xbf\xd4\xfe֨\x04\xbf\xf1v$\xe4\x8aڪi\t\x84\x1c\x90\xf4\x88A[\xa6J~\xf9\xbf\xe7\\\xbb\xf6\u007f\xff\xcf\xff\xd3\xfe֨\x04\u007f\x01GB\xc3\x19\x90\xb4\xa5\xe8\x8cL\xb9v-\xf2\xf6\x96\xe0\xde\\\v\x8e\x84\x863 iKA%=\xf1\xf6\xe6\xe0J\x1a\x18\u0380\xa4-\x85 i[ܬ&\x10\xf5h\x05$m)\x04I\x8f\x8d\xfc\xfe\r\r\xbb\xcb\xdbC\u007f\xa9\x1f0\x1f\x90\xb4\xa5\xa0\x92\x9e\xd4~\xad\xe7;aaa\xb6\xa3\xaeNP\xf5\xa8\x03$m%\xfa\xae\x12I\xcf\xc6\xe7\xe6\xfbs\xdc-c\xc3¾\xef\xec\x1c\x9d\xb7P\x8db@\xd2\x16\xa2u\xe6\xf4뱤\xb7\xe2s3\xab\xf9ڵ\x8ce\x87g\x86ŵ\x83\xa6G\x17 i\xeb\xe0\x9e\xf8\xfd\x19\xd7aI\xd7\xe2s\xb3\xfc_X\xdamxĎ\b\xf2\x05-`\xb8\x01\x92\xb6\x0e\raG\xafE`I#|nN\xe0\xffG\xf1\xff\x14[è}\xbc\xc7(\x05$m\x19\xfa6\x85\xfd\xeb\x1aYK\x13\xfe-\xfe\aI\x8f:L\x94\xb4\xe85\xa7\xa7\xd8)P\x8c\x80\xa1г\xe4\xfb\u05eeMJ\xb9\xd6\xe7\xfe\xf7\xb5\x1e\xfcߍ\xff\x13I\x87\x01\xc3\x17\xa3\x93:\bL\x93\xb4\xe45\xc7\xed<\xe9\u009c\x10\x1e\xd0oe\xaaO\xa2`\xe2\x9eo\xbbvm\xfa\x92\u007f\xff\xeb\xda\xc9\u007f\xfd\xfbZCߵk͂\xa4\xbb\x80እ$-{͡7:\xb9\x8b\xad\xff\x14\x8a\x19\x83yd\x99\xff\xb8\xe7D\xd2Ӳ\xf5I\u05f5M\x1b\xae^۰\x01\x81\xa4\x879V\x92\xb4\xdakNy\xe8\x9fS\x14r\x06\xf5\x14B\xffqϊ\xfe\xb7\x17 \xe9a\x8d\x95$\xad\xf2\x9a\xd3\xec\x1c\xa2\x13\xc5a\x84\xd2Î\xc7\x05O\xb9\xf8H\x9d\xe9\xe4\xa1;\x13\x8aQ\xab\x8d\x9b\xaa\xb0e]İ\xf8\xed\x85\xc6=sʿ\xbc\x98\x03\x92\x1e\xceXI\xd2*\xaf9%\x95>\xadG\x14\n\x0f;\x92\v\x9e\xce\xc3\xf4)\x845\xcd\xf4\xd1x\xeb\xf0\x8fZ\x86Ma\xabp\x11\xc3\xe0\xb7\x17\x1a\xf7\xccIȋ\xe8(\"\xe9gn4\xd4\xf5\xfd\xb7\x1aYx\x13F\xff\xe9\u007f\x190\xbc\xf2\xba\xf5~-3\xdf(2Q\x1d\xaeAe\x8d\xda\xef\x89\x1f|\x87\xbe\x87\xdd\xf8\x18y\xf3\xbfvV\x92\xb4\xd2kN\xab\xd3Zϔ\x91<\xec(]\xf0H\x13o\xf6\x01\xb6\xb27\x1e\xa5\x8b\x18\x11\xff\xbdи\x97\x8f\xa9\xb9\xaabwXJ\x13\xee\x8d\xe3^7\xea[\x17ǾE\xbb\x98\x91\x9d\x02}I\xbf>\xde8\xab\xb0\xb0\xb017\xdd\xf6\x94\x91\x19\xc1+\xaf\xb7\xc6^\x14\xbf\x19\\&\xe2\xe1j~\xa7Qq\xa3\xf6\xbb\xe1\xf9/\xe9\xfb\x97\xcf\xdfHޤ\xda\x19b%I+\xbd\xe6T\x96\xf8\xb6\x1eiH\x1ev\x94.x\xb4%-y\xe3Q\xba\x88\x11\xf1\xdf\vM_\xb3-\xec\xfa\x1bn\xb8\xe1{\xdf\xfb\xdeرc\xaf\xc7\\w]\x98\xad\xa4\xd5\xe7X\xea\u125fuu\xdd\xf1\xdb+aW~{\x87\x91\xa9\x8c~\xb6\xbf\xfa\x95\xeeW\x128\xf5\x95\xbf\xfe\xe1Ƿ^12\xd4*\xe8֧\xa4o\x06\x93\t9\\=4\x8eʨ\xfd¾\x14\x03_\n\x96\xb7\xfa\xf5\x1b\xd3e-I+\xbd\xe6\x14\x99\xf2X\xfe\xe0!y\xd8Q\xba\xe0і\xb4\xe4\x8dG\xf9\xf0y\x91\x01x\xa1q7\xad\x9c3+n\x96\xcc\xec\xd9K\xca\x1b\xda\xc3\xc8P\x16&vK\xa2\xef\xa7n\x1e3\xf6\x17\x1f\xe3\x0f\xcf\xde<\xe6\xa6DŽ\xbeu\xdb\x13X\x1b\x8f\xde\x12vˣX\x1c\xcf\xfeh̸\xfb\xbfԲ|t\xdcw\xc7\xd1\x14\x8f\xe1\xc0\xa3a\xaa\xfc\x1e\xfd\x81\x10\x89\x87\xb5?\x93o\u07bam옛\x9fb\x92ɦ]\x1e\x9d|y\v\x99\xa5zJ\xd4/H\xaeԃd\x16\xfc\xc4\x1dC\xca\x04\x1f\xee\xc7t(\xbd8\xf6c1\x1bO\xdd\xe8\xe5beq4\xe6\xadۮ\xbf\xee6\xb6-\xa4\xe2X\xc9\v!O픕\x16j.\xb5\x05\x8d\xf2:\x89C\xc7,I+\xbc\xe6\xb4;}\xb9\xa9\x18\x81H\xe2\xf5v\xc1S@\xc6d*ޕ6\xa5\xad\xb6\xa4\a\xe2\x85\xc6\xdd\xd6ڬ\xa0\xa5\xd5\xd5\xd9'\x8eҲ\xa4ǿ|\xf1\xbd;p\xa7{\xfe\x86g/\xbe\xf5\v\xa1\xef\x8d{K\x96\xf4\xeb?|\xfd\xe2[d=\xe8e\xf9̍/\xff\xe3\xe5\x1b\x9f\xc5\x11?x\xf5\xe2\xab7\x85)\xf3{\xd6\x13\xd9\xf5\xc6x\xfa\xcd\xcd\x0f\xfe\xfd\xca\xeb?g\x92I\xa6\x8c\x0e^\xff\xcf.\xb9D\xfd\x82\xe4J\xfd\xf4\xbfq\xaa\xb7\xc6\r)\x13r\xb8?#?6O\xfd̫Yh\x96\xca\xe2H\xd4\x0f_\xbe\xf8\x8f\xbb\xef\x96s\x97,\xf0\uf0b0\x92&|\x87N\xb9=\xb5S\xe5B^䶠Q\xde'qȘ%i\x85לVg\xbb\x81\xf9\bC\x92\xa9\xc2\x05O\\\x1cBm4\"b9\x9e'\xcf\xf0K\xd2\x03\xf3B\xd3\xe3V҃\u007f8\xbd$\xfd\x06~\xff\x9f\xb1]]?\xfe\x83\xd4\x13\xbb\xc6\\\x94'\u07b7\x10\x83\xf7\xc6iX\xfe\xf8\x19\xfc\xf2̏\xbb\xba~\xf2,\t\x84)\xf3\xa3\x91ϒrȼ\x1b\xbf_\xf7\x9e*\x99d*V\x85pqL\x97\\\xa2~Ar\xa5\xfe\xecI5\x84L\xc8\xe1\xfe\xe1\x16\xfc\xe1\x96?x\xb2\x91\xeaF\xb3T\x16\xe7\x19\x85\xffq\xa3\x9c\xbbd\xd1u\xe5\xb1\xf1]\x1e\xc6?F\x96\x00\x9eکr!/r[\xd0(\xad\x938D̒\xb4\xc2kN\xb3\xd3J\u007f-\xa4\xf0\xb0#\xb9\xe0AD\xad\x9b\xcafE\x90\x8d\xc0\x99Q\x1b6\xcc\xe4\u008b\x9a\x19[\xd6E\f\xcb\xc0\xbc\xd0h\xe0%iO`\xcc\xc7RO\xa4}\xdcc46L\x9c|zY^\xffw\xfc\xf2\xf7\xeb=\x810e~R$\x99w\x93\x88_\x8d\xbd\xfb\x89\xf7\xd8d\x92)\xf3F\xba\xbfT\xa2~Ar\xa5\xaexR\r!\x13r\xb8Wƾ\xd7\xf5\xde\xd8+\x9el\x94\xed\xa3,\x8eD\xfd\xf7\xcf\xc7*r\x97,\xf0T]\xfem\xfc\x03\x8d\xf1\xd4N\x95\xcb\x15\xb6RB\x94\xd1\xc9\x1b\x04\xa6I\x9a\xf5\x9a\xd3\xea\xf1;n\t\x94\x1ev<.x0\xee%\x91\x11qt?\xb0%.b\xe2\xac\xe5\x1c\xb7\x84\xb1e]\xc4(\x18\x90\x17\x1a\r\xc2\xf4$}=#\xe9q\xcc\x0e\xf0\x18qp\xf5\xb6\xf4S\xd2\u007f\x1e'&\xfe\xf3\x83\xb7]\xff\xa0\x81\xa4ɜY*Q\xbf U\xa54&\xde\x03Ʉ\x1e\xee\xdd\xf7w\xdd\u007f\xb7\x94\x8d\xb2}\x94ő\x97\x9f\xfc\xea\xbd//2m!Yt]\xf9-3J\xff\x96(\xd5S;\xef\\Tma-I\x03!B\xec\xa5c\xff\a\xbf\xbc\xc1\xf6ݟ0\x13o\xb2=\xe6\xe1Ǐ\x8a\x01/K퉷d\xe5\x99x\xd3\xfdnQl\u007f\xbd\x8e\x9dl2يo_\x92\xa5\xa6T\xa2~A\xaaJ\xa9\xb6\xc7\x06\x9a\t=\xdc\xd7\xc7w\x8d\u007f]\xcaF\xaa\xdbwȖ\x97\xb28\xf2r\x1d\x1e\xd8_e\xdb\xc2c\xa1\xb1\x96\xf6\xd4\xce;\x17U[\x80\xa4\x81A v\xd7;\xeex\xef\xe2\xcb\xe3پ\xfb\xea\x8d\xcfK\xdbc\xecU\x9d\x97\xaf\u007f\xe2\xe3\x8b/ߪa\xf9\xccMd\x9fI\xbd=\xe6\xb1zv\x1c\x8e\x1c\x87\x03\xe3\xdf\x10\"n}\xfe\xe2\xc5Gof\x92ɒ\x16\xd2]yO\xb8\xfe$\x95\xa8_\x90\xaaR\xf42\xd1\xe03\x11\x0ew\xfc\x83\x9e\xe1\x95=\x8cq\xcf{\xb5\x01y\xb9\xf9\xc1\x8bo\x8cg\xdaB\xb2\xe8\xf2\xa4\x95C\x9e\x8bX\u07b9\xa8\xda\x02$\r\f\x02\xb1\xbb~\xfc\x8b\xb1c~\xf4\x14\xdbw\xbb\x9e\xf9ј\x1f\x88\x17\xb1\x14\xf7^\xbc\xfa\xd3\xeb\xc6\xfc\xf4e-\xcbG\xc7}G\xbc,\xf4\x03\xf9\"\x96d\xf5\xe8M\xdf\x1d\xf7\xe0\x18a\xdeM\"\x9e\xffɘ\xb1?\xff+\x93L)ir\x97\xc8ϞR\x94\xa8_\x90\xb2R\xc2\xcd\x1c\x83\xcfD8\xdc\xfb\xbf\xeb\xb9͋=\x8cgƑկ\xa28\xf2\xf2\xc6\xcdcn\xfa-\xdb\x16Rq]\xea\xeb\xd2\xf2\xad&^\xb9\xa8\xda\x02$\r\f\x82\xb0.\u007f\x18\xcc\r\xa1Z\xe0\xd9,\x9dw\u007f9\xc6\xc8r(\xf8\u007f˥\x0e\x81:\\\x81\x9b\xa4\xbb\xc7n\"o\xfe\xd7\x0e$\r\f\x02\xff$\x1d\b~\xf1狯\xff\xf0Aa\x81\xfa\xfa\xcdF\xd6\x16≛\xc4{\xbcox\xcc\xc0R\x05H\x1a\x18\x04\xa1\x93\xf4\x13\xff9f\xfc\x83B0l\xfc\xab\xbem\x01\x02H\x1a\x18\x04\xa1\x9340P@\xd2\xc0 \x00I\x0f_@\xd2\xc0 \b\x03\x86/F'o\x10\x80\xa4\x01\xc0R\x80\xa4\x01\xc0R\x80\xa4\x01\xc0R\x8cfI\xa7pQ\U000db34c\x00`d1\x9a%\xed\xaa.\x9a\x1a\x05\xeee\x00ka\xa2\xa4E\a:\bu\x1e\xde]\xb0\xfb\xb0)ڪ\xe6,\xef\xe3\x03\x18e\x98&iɁ\x0ej/\xde\xdd\xecj\xde]lƓMj\xb9\xa3F&\x000\xa20MҲ\x03\x9d\x9a\x12\xf2 \x84\x9e\x92\x1a\xa3$A\x00$\rX\r\xb3$\xcd8Щ\x14\x9e\x12Zf\xc6\xd3\xf9AҀ\xd50KҌ\x03\x9d\xf6\xe2\xeavw{\x8d)\x13\xef\x06\xae\xda\xc8\x04\x00F\x14fI\x9au\xa0\x83\x97\xd5N\xe7>S\x9e(莚q\xd8\xd5gd\x05\x00#\a\xb3$\xcd8\xd0qW\x964\xbb\x9aK*Mq]\xb9O~\xf0\x1f\x00X\x01\xb3$\xcd8Щ\xa1\x8e\xb1\xdc%f8\x98\ue31a\xbc\xb5\xdab~\x01\x80эY\x92f\x1c\xe8\x14\b\x97\x86\x1b\n|\xd9\a\x89ZΌM9\x00\b\x1efI\x9aq\xa0#J\xfa\xa49\x92\x86\x1do\xc0Z\x98%iƁN\xb58\xf16c\xef\x19$\rX\r\xb3$\xcd8\xd0q\xbfX\xd2\xe4j*yь-\xef\xa3 i\xc0b\x98&iƁ\x8e\xbbvw\xd1\xee\xda\xd0+\xda\xed:\x99b\xb3\x96\xafz\x000O\xd2\xe63\x87\xe3\xa2ˌ\x8c\x00`d1\x9a%\xed:\tC4`9F\xb3\xa4\x01\xc0\x82\x80\xa4\x01\xc0R\x80\xa4\x01\xc0R\x80\xa4\x01\xc0R\x80\xa4\x01\xc0R\x80\xa4\x01\xc0R\x80\xa4\x01\xc0R\x80\xa4\x01\xc0R\x80\xa4\x01\xc0R\x80\xa4\x01\xc0R\x80\xa4\x01\xc0R\x80\xa4\x01\xc0R\x98(iɁN_CY\xc1\xee\xe1\xe3o\xee\\Nrr\xf6\xa9\xa5\x8dFv\x02\xf5\xa9\xc7\xf5\xbf,\xe5\x1d\xe4\xdb\xfa$\xbeT\xdb`\x1b\xcf\x1f\xd4\xfe\x06}\xee\xe0\xef\xd3\xf9*\xb0\x8c\x88J\x02~c\x9a\xa4e\a:\xa8\xbc\xe8d뉂\x13F)B\xc4Yǚ#\a\xd7\xeb\xf7b\x15Ǔ\x8e\xe8\u007fّ\x9b\xf4\b~{$1\xb7C\xf9ũ\xb3\xc2\xfb\x17\x8d\x0e\x1d\x1d\xa1\xfew6;t\xbe\n,#\xa2\x92\x80ߘ&iفNC\x01y(\u007fK\x81)~\xee\xbc\xc9\xc9\xee\xc7]u\xb3\xbf\x92F\xfd\xbe\xbe,\xccI\xea@\x1d\x899\x85\xaa\xf8\xac\xf5\x9e\x90\xaeZ\xf0\xf0\x19\"\xb5\x8c\x88J\x02\xfeb\x96\xa4\x19\a:\xe5\xfbhL\xf10\x19\xa6\xd3i\xcf>\xc7\xfb\x18|\"\x05\xd7\xcf\x00\x00\r\xafIDAT\xfd\xa70\xf7\x91\x83\xa8*'W\xad\x96\xa5\xc3I-#\xa2\x92\x80\xbf\x98%iƁ\xcen\xc1\xbf]Y\xb9\xaeqp\xf8\xd0\xc1\xf3;/\xe4\xa5'\xe6|\xcbF禞ï\xfd\xf5\xdd\xe4\xb5*+)3\xbf[a{\x90\xe7\U00062cd4'S\xf3\x8e$^\x9e\xa1_X?ϑ\x9a\xf3\x05\x9b\f\xab\xa5b=ʩ\xa0j\x91b\x8f\xf3\x02Y$\x95\xa30?3\x89\xa6B\xfd\x15YIK+\xe8\xa8\xffEnZ\xf2z՜\xd65\x91\x13\x98\xa8zr\x83\\\xb0\x84\xe2\xd8\xe4\xea\xa0\xee\xc2\xfb\x92\xb2\xdfI\xabW\xa4\x0fd%\x01\xd31KҌ\x03\x9d\xc3\xc5\xf4\t\xa1E\xbb\x8d\xd2\x04\x98ރ\a\xd33\xefI\xcbϽ\xebs6\xfa\xf3t>\xa7\xf4\xdd^\x1a\xde\xc2\xe7\xd7W\xa4.\xedgm\xbb\x1b\x93_\xf8\n}\xf5Br#\xee\xf8g\x1b\x1b\x13\xc5\x11\xecTR\xd6+\xf5\xa5\xfc^6\x19V\xcb\x17I\xdf$^\xa6j\x91b\xbb\x1b\x1b3\xb3\x1b\x1b\x1b?%\xc9\x1c|\xe6\xc1\xe3\xf3\xe8x\x98\xe7\xd8Y\xbfӑ\x87C\x17\x923\xab\x8e\xe7\xf0J\xb5\xb8\x8b\xb6\n\x14)\x1f\xd3\xc6\x14,\xa186\xb9:\x1d\xe9\xc9{\xeb\xb7\xf1|\x85\"\x83@V\x120\x1d\xb3$\xcd8\xd0\xe9,*os\xbbʜ%Fi\x02\xcfR\xfe\x91n\xd4߭\x8c\xec(\xfd\x8d\x83O&c\xefq\xbe\n\xbf\x9e\x15\xc6a\xd9vK.~\xc9\xdd\"\x9a\x8b\x92\xeeM\xcf\xe9%R\xeaP$+\xccEK7g!\xa2\x16ef\xf2\x9c6\xf5\x1b\x9cc*\x0e\xd5\xf3\xf5\x9e\xd7\xecL\\N\xffR\x95Z\xdaZ\x05\xda\x14\xb1L\xc1\n\xa4\xfa2\x05\xe7%\x93\x916\xdfK\xd2\x01\xac$`6fI\x9aq\xa0\x83\xda˝N\xe7\xd1r\x13\x9e\xec\xb7ԡ\x18\xa0%zO\xe5\x90N\x9b\x9b\xde\xfb-&m\x8b\xd2\xf6Tb7\xeaN:%~\x12%]\xcf\u007f\xe4I\xcd$\xc3jy\x85\u007f\x89\xaaE\x99\x99\xac\x16\xf2\x99.H\xb7\b\x97\x83\xeeی:\x04\xcd\xedT\xaa\xa5\x95\xf3\xa0\xf0\xf8\xc3\x14\xac@\xaa\xaf\\p\u007f\x12\xad\xeb9oI\a\xac\x92\x80\xe9\x98%iƁ\x0e\xc6\xddއ\x8aM\xf0\x89\xb54\xcb;\ueb30d|x\r\x19\xe8\x04\xd6(m\xbfM>\x82\x8e\xcc\xf3\xect\x8b\x92\xde\xcb\xf7z\xbeg\x92a\xb5t\x14~Eբ\xccL\xb9\xf3D\xd5\xf20\xfd\x06\xe5d\xe1Q\x92^\x14W\xef<Ք\v\xd4(b\x99\x82\x15H\xf5\x95\v\xfeB\xd8\xf3\xeb\xf6\x96t\xe0*\t\x98\x8dY\x92f\x1c\xe8 \xbaQ\xd6\xe24\xe1q\x9dr\xa7\x95Iͧo\x85\x99d\xcc:K\xe9P\xd9\xe6\xafA\xeb\xf3=\x1fDI\x9f\xe2?\xf4\xc40\xc9\ns\x85\x98B\xad̪\xc80*\xabeK:\xf9\x95\xe8O\xcfC\xdf\b\x9a\xcb\xf3K-L\xc1\n\xa4\xfa\xca\x05\x8b\xa3\xf4Gޒ\xa6vA\xac$\x10:̒4\xe3@\xa7ى\x17\x87W\x8b\xcd\xf0\x9f\xc3J\xbau\x830\x9f\x9d\x97F\xfas?\xf9\xaa^XS\x16\xbe\xa4\xb2}7\xf1r⻞\x0f\xa2\xa4\xbbS\xb3\xc9h\x99\x9f\xafHƨE\x91Yv6B_\xd1\bY-\x82\xc1A2\xe3\xcfJ\xc7u\xf84\xd1/\xb50\x05#\xf9(\x98\xfa2\x05\xaf\x9f\x87\xf3\xed\xcf\x13%\xed\xb1\rA%\x81\xd0a\x96\xa4\x19\a:-\xceZWCqyȽm|\xfb.\xdd\xd3\xf5\xac\x90\xe7\x88~\xa6\xe7\xf1\xa9\xa5\xf5G\x1eI\"[\xbd\x85w\xe5\x1e\xf9\xcb\x16܋\x95\xb6\xfdi9it\xde\xdd\xfbNcc\xe2\xe6F\xb2\xf7\x8dW\xd8\xf7U\xd4\v;OR\xb2or\xb3/\xe3ϗ\xb3s\xbfab\x11\x91\xc7^\\\xc4et\xb9ѱ\xf9\x9d\xfe\xf77;\x1a\xb1]._x\xbc\x90'\xfa:\x97\x94V\xba3\x99wT\x9dC\xc60\x05KG\xa1\xa8\xaf\\\xf0\xe5\xd4\xf4\x8a#k\x12\x95\xb6!\xa9$\x102L\x934\xe3@\xe7dIQ\xf9I#\xf3\xc0\xf3\xa1\xb0l\xcc\x11?\x16E9\xe9\xfbo*\n\xefKJ]C/ޠ\xfa\xecy\xc9\xd9\xf5^\xb6{\x1d\xc2%\xa3\xf7ť'\x95ȧ\xeb\xd3\xee\xc9:\xa2HV\xca\xf3dci3Oo\x9f\xf6\xc4bz\xf3\x93\x13\xb3\xcf\xd2ۧy\xc7G\xe4\xea\xf66r\xc9w\xa9\xe7\x92\xef\x855\xc9\xe9\x85U\x0e\x12k\fS\xb0\xe7(\x94\xf5\x95\v\xeeؒ\x9e\xf8\xc8YQҢmh*\t\x84\n\xf3$\r\x98\x85z{\f\xb0\x14 \xe9\xd1\aH\xdaҀ\xa4G\x1f iK\x03\x92\x1eu\\\xa8\xe7\xf3\xdf\xf5\xf9\xf7c\xc0H\x06$=\xea\xc8&\xbb]\x17\x8c\xac\x80\x91\nH\x1a\x00,\x05H\x1a\x00,\x05H\x1a\x00,\x05H\x1a\x00,\x05H\x1a\x00,\x05H\x1a\x00,\x05H\x1a\x00,\x05H\x1a\x00,\x05H\x1a\x00,\x85I\x92\xee)v\n\x14\x93O\xae\xb2\xa2}&<\xd3\x04\x00,\x88I\x92v;O\xba0'\xe8\xb3M\\\x055-5\x05\xa0i\x00\b\x00&I\x1a5\xd1gw\xd3G\b\xf6\xd1\xd7\xc3\xc5}\x06I\x00\x000\xc6,IS\xca\xc9s\x8aPs\x01\x95w\xc1\xf0\xf1]\t\x00#\x173%M\x9f#\x88P\xa5\xe0\x13\xab܌\xe7\t\x02\x80\xd50S\xd2%\x95\xf4m\xb7\xf0\x00\xef\xc3&<\x9a\x1f\x00,\x87\x89\x92n\x15\x9f\xdc]\\K\xdfj\x8b}\x19\x03\x00\xe0\x17&J\xbaRt\x82%z\xae\xac\x0e\xb5\x9b;\x00\xb0\"&J\xbaHt(])x\xa1-\x83\xb54\x00\f\x1d\xf3$\xdd\xee\x14\xfdB4;\x89ǻ\xabN\xd8\xf1\x06\x80\xa1c\x9e\xa4[\x9d\xedB\xa0\x8f\xfaΩ\x86\xeb\xd2\x00\x10\x00̓t\xb3\xd3\xe32\xc7UP\xddZ\rw\x8f\x01@ 0Oҭ\xf2v\x98k_A\x19(\x1a\x00\x02\x81y\x92\x06\x00 \b\x80\xa4\x01\xc0R\x80\xa4\x01\xc0R\x80\xa4\x01\xc0R\x80\xa4\x01\xc0R\x80\xa4\x01\xc0R\x80\xa4\x01\xc0R\x80\xa4\x01\xc0R\x80\xa4\x01\xc0R\x80\xa4\x01\xc0R\x80\xa4\x01\xc0R\x80\xa4\x01\xc0R\x80\xa4\x01\xc0R\x80\xa4\xd1ڵZA\x00\x18\x99\x98$i\xa5\x03\x1d\x84\xaa\xcd{\xa4\xc9\xdf\xecOk\x04=\x1c\xb0c\x12p\xe0\x83_\xc7\xc7.:\xb6\xe0m\x1c\xdc>\xf7\xceiw\xce݁P\x9dݾ\b\xa1\xfd\xd8\xe2\x98:]\x908\x16\xff')|~\x9a\xfd^\x1f\xa6\xbeYk\xb7\xef7\xb2\x19\x10\x81k\xa8\xd5\xd8,漑\x15\xa0\x87I\x92V8\xd0A\xa8\xcdYk\x90 x\xac\x8a\xb9\xa4\x11\xf4\xe0~\xbb.v\xc5\a\b\x9d\x99\xf6Ё\xfd+\xa8\x0e\x8e\xd9\u007f\xbd\xe7\xd0k\x0f\xd9\xeb\x90\xfb\x98=\x06\xbf\xee\xb7\x1fs\xa3\x00s\xec\x8cf\xf4\xa1\x18F\x88\xa7W\xc7h\x1a\xf9å\xbai;\x8cl\x06D\xe0\x1a곺\xba=\xf6\xb7\x8d\xac\x00=L\x924\xeb@\a!W\x89y\x92>oߨ\x11d\x89'C\xf7\xe2\xc5$\xb8\x9a\xf4ԍ\xb1\xb4\xee\xb1\xd8\xd8m_\xb5\x9a\xa4\xf3\xa3\xa3\x0e\x90\x05+\x8c,0;\x06/i\x84b\x02+i\x14Ȇ:\r\x92\x1e<fI\x9a\"8\xd0A\xd5\xce\xea\x02\xd3$\xbdZ\x1e\x99W{\x0f\xd2\x04\xdaS\x13\xb6\x93\xe0\a\xf6\x03\xb8\xd3.\xa4\xd1\v\x17\x93\x9ez\fw[\xbf{\xea\x00\x18\xb1\x92\x0eHC\x81\xa4\x87\x80\x99\x92\x16\x1d\xe8 \xb7\xdb\xf3x\xfe\xd0s~\xdaF\x8d\xa0\x02\xdaSW\xc4\u007f@\u0087p\x9f\\$\xa8m\xc5\"\xd2S\xcf/د\xee\xa9g\xa6\xd9\xed\xdbϯJ\x88y\x80< q\xff\xa2\x98\xb9\x1b\xe9\xf7\xee\xa7\xef\x8d]\xf4v\xc2!\xf48\x99\x96J+a٠nq´\xf8_\xe3\xf5\xe8\x9f\xec\x02\v\x90\x82\xafc\xec\xd2\n\xf8Ҫ\xf8\xd8\x15\xde\x13\xef\xf3+\xe2q\x16\xf8\x97\xa9\x13\a\x12\x1e\"\xb3\xf7\xc7\xed\xd3\xf6l\x9c\x1b\xb3\xf83\x95i\xccƵ\xf1w>$\xacY\xe5:\xc8h\xe6p\b\xd7\xe0\xf7h\x87]s%>І\"k\xeb\x1dbfri\x04Q\xd2z\r\x85\xd0k\xf1{\x10\xa0\x8d\x99\x92\x16\x1d\xe8\x10L\x93\xf4\xdai\x9fi\x04\x15О\xfaY\x82\xfd\x81\x1d\xa7\xe9\xa4b\xc1\xefh\xf4\xef\x16О\xba\xeb\xd7\xea\x9e\xea\u07bf?anl\xc2\xc6U\xf6\xcf\xc8\ft\xe3\xa1]\xf1\v\xb0\xb8\xbfN\x88\xdfuh\xadݾG\\NJ+a\xd9\xe0\x8c}\xd5\xfec{\xe2\xed}d]:wQ]]\x9dz\x8f\xe8L]\x9d8\xb6\x9e\x8f\x9d\xfbڟ\x16\xdbՒ~3v\xc1s\xc7v\xd8w\x11\xed\xad}s\xffC\xf6\xd3\b\xfdm\xff4{\xfc\x8e]\xb1\xeaa?ƾ`\xff\xfe\x051D\x80r\x1d\x184sp\xbf\x9d\xb0\xf6\x12\xba\xb4=\xb6Nc\xbc\x1dpC\xd5\xc5n\xf7d&\x97F\x10%\xad\xd3P\x98\x15\xf6\a\x10\xa0\x8d\x89\x92\xf68\xd0!\x98%\xe9Ϧ\xad\xd5\b*\xa1=\x15}\xfd\xdc\xc2i\xf6X26ݻ\x8aF\xaf\xba\x97\xf6\xd4K1\x97\xbc\xe7\x93\v\xec\x8b;\xf18Gt\xf1GDz(N\xb7*\x96L\xeb7\xda\xc9\xf0B\x85I\xa7͌\xc1\x9ex\xd2]\xf7\xc4\n9\xe8L\xbcEI/\x9a\x8b\x8b\xec[\xa0\x92\xb4;\xe1\x01\x1cݳ\xffk\xf2\xbbB\xea$\xe4\x12\x13\x8b\u007f[Vūs\xba\x17[\xb8\xe7.Tԁ\xcdL;\x87\x1dd\xea@\x16\xc6\xde\f\xbc\xa1V\x93\xdc\u007fGڝ-\x8d\x99xk6\x14\xe6\xfcs\xb0%\xae\x87\x89\x92\xf68\xd0!\x98%\xe9ǧ\x9d\xd7\b*\x89\xf7\\\xd9r\x1f{\xc0~H\x1a|V\b\x83\x0f\xfa\xf5.\rILj\x03\xfe\x8a\x84\x9e>L\x02\x96@\f]d\xfeM%i\xc6\xe0\xb3\xf8\x84\xc7\xf7\x9cA=B\x0e>%\xfd5\xcd\x05mWI\xfa\x90]\xde'\xff\xe7\x9e\a\x12b\x85\xa9{\f\x11\xa0\u05fa;\xe6\xf7\xe4u\x8f\xfdk\xb6\x0e,\xda9|f\xff\x00\xb9c5\xafE\r\xbc\xa1ތq#wL\x1d\t2\xa5iJZ\xa7\x92\x80\x17&J\xda\xe3@\x87`\x92\xa4/Ŭ\xd5\b\xaa\xa0=\xf5\xb4\xb0s\xb6\xe8!\xe1?\xe6!a\x89\x88\xf6/А\xb4g\x15\xbc@\\\x15\xaf\xc0R8@\"\xdc*I\xcb\x06X\xa8{V\xdck\x8f\u007fNH\xe8S\xd2g\xecT\x06j\x99\xee\x92+r:>\xe1\xe9\x03u\x8b\x17Hi\xbc%Ms\xaaÿ\x02l\x1dd\xf4rx\xe0it,\xb6\ai0\xf0\x86\xea\x8b?\x80\x0e\xd0\xc9\t[\x9a\xa6\xa4\xb5+\txc\x9e\xa4%\a:\x04\x93$\xbd\xd1~^#(\xd1G\xa3hO\x8d\u007f\x9c\xc6l\x9f\x8b\x90\xd8\xef\x16,\x16z\xaa;昷\xa4=\x1doU\xc2\x19\xca?Q\x9f \xa1\x0fdI\xd31V6@gH9_\xef\x8f\xd9#\xe5\xf0\x9a\xf7\xe2^\xc8\xe5\x9f\xc2(\xad\xde\x1e;&\x8f\xd2\xf7.$uZ\xe1K\xd2\x1b\xc9\xebk\xf6N\xb6\x0e\fz9\xfc)\xbeg\xb5z\xa8\x1ctCm\\\x81Vl$\x01\xb64\xb5\xa4\xd5\r\x05\xf8\xc4<IK\x0et\b\xe6H\xfaR\xccj\x8d\xa0\xcc\x1e2\x18\xfe\x93\xec6\xa1\xf8\x84\xafI\fQ\x9ax\xb9\x95\x8cꤧ\xa2տӗ\xf41a\xed\xb7\xfd9\xb2\x15Lz\xe3*AҸ\xf3\xf7-\x8cQ\x1a\xec\x10n\xadZDg\v\x8b\xf0\xd0vIc[Y\\K/$\xd59\x1f\xa3\x92\xa9;~\x11\x19>7nD(\x81Ԡo\x81/I'\x90u\xf7\xbd\x8b\x14u`\xd0ˡ'\xfeOw\xaa\xe7݃n\xa8\xd31\x97b\xe8\x96\x18[\x1a+i\xad\x86\u009c\xdf\x01ki=̓\xb4\xec@\xc7\xedr\x15U\xbb\xda|Z\a\x85\xa7\xe5\x91\xf9i\x8dA\x9a\xdc\xfe\xb4\xff\x8f\v\xe3\xc9X\x19o\x8f\xdf~\xec\xc0br\xa3\xe21\xfb\x03\a\xea\x0e,\xc6\x13i7\xeegnT\x17\xa3\xec\xa9}\xa7\xe9~\xf5y1\xdf\xdf\xed?@o\xbc\xb8\x14\x9f\xb0\xe7\xc0\x8a\x18*\xe9E\xf1\xcf=\xb7\xd0>\xed\x8f\x1f\xb0\x06;\xec\xb1\xdb\x0f\xe1\xe0\x9b$ݎ\x98]\xb84\xe5(\xdd\xf3v]]\xcc꺺N<\xd8\xc7$\xec\xd8~\xa7\x90\x03ñ\x98{\xf7\x1c\xdah\u007f\x8dd\xb6b\xcfs\v\xf04\xfe\xf4\xa5\xbai\xabO\xa33\xab\xa7\xd5)\xaf\xba\xc7\xd8\x1f8}lQ,\xa9\xa6\\\a\x06\xdd\x1c\x9eN\x88U\xbb/\x1b\\C\x11\xe2\x17\v\xdbvri\xc2\xddc\xbb\xea\xeaHn\x9a\r\x85y\x88\xdc`\nhb\x9e\xa4e\a:'\x84۽\xaf\xfa\xb2\x0e\x06\x97bVi\x04Y\x0e,\x88\x89}\x88\xaaf\xe1k\xdb\uf349\x17.\xe3n\x9f\x1bk\x8f%\xb7.\xbfI/\xa9\xf6-\x8cWt\xf13¢OXH\xa2c\x8b\xe3c\x17\x1d\"\xa1\u007f\xaeN\x88Y|\x86J\xfa\xfc\xa2\x98\xd8ſ\xb7\xdbײ\x06\xfb\x17\xedH\x98\x16\xbf\x88*\x1a\xb97\xde\x19\xb3\xe84R f,\xe4\xf0Н\tO\xffq\x1á\xe1\xfc\x8a\x84\u0605d\xd1\u07b7knL\xfc\x8a\xd7\xe6N[\xb4\x16\xa7\x98\xf6\x01\xb9\xa4\xad\xb4\xbdwNJ\xd8\xf8U\x82\xcc\xe5J\xca\xe8\xe6p^](\x1adC\x11v\xc5\xec\xa2\xefri\xf4\x1eoϪY\xb3\xa1h2\xf5\x06>\xe0\xc1<I\x9b\xcf\xef\xed\u007f\xd3\b\x06\x17a{lD\xe3\x8ey\xd3\xc8$\xf8<\xb4\xd8\xc8b\xd42\x9a%m\xc6_UZ@\xd2\xfb\xbd\xc7ڐ\xf3\x9c]5\xa7\x00$F\xb3\xa4\xcd`\xa4KzǛh\xf1v#\xa3\xa0\xf3Y\xfc.#\x93\xd1\vH:\xa4\x9c?fߨZ!\x8f(\xdc\xf6\x05\x8f\xc7\u007fmd\x05\x98\tH:\xa4,\";M#\xf9\xfa\xcb\xf6\xd8\xc5#\xb9\xfa\xa3\x01\x904\x00X\n\x904\x00X\n\x904\x00X\x8a\xff\x0f\xb8\x98\xba\xeaw\xacpV\x00\x00\x00\x00IEND\xaeB`\x82",
+
+ "analysis/ipcg-func.png": "\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x02\xaa\x00\x00\x01\xb1\b\x03\x00\x00\x00\x9d\xa2d\x9d\x00\x00\x00\x01sRGB\x00\xae\xce\x1c\xe9\x00\x00\x02\xfdPLTE\x02\x04\x00\a\t\x05\n\f\b\x0e\x10\r\x13\x15\x12!# '(&+-*2319:8?@>QSPVXU,`\xae7]\xadZ\\Z8^\xae8a\xaa:b\xab;b\xac^`]<c\xad=d\xae?e\xaf@f\xb0Ag\xb2Bh\xb3Ci\xb4fgeCk\xafEj\xb5Lj\xafMk\xb0Fm\xb2Ol\xb2Ho\xb4Ip\xb5Jq\xb6molKr\xb7Ms\xb8Nt\xb9Ou\xbaPv\xbbrtqWv\xb6Xw\xb7Yx\xb8[y\xb9wyv\\{\xbbV~\xbd^|\xbdX\x80\xbf`~\xbeZ\x81\xc0`\x81\xbbb\x80\xc0}\u007f|b\x83\xbd\x80\x81\u007fc\x84\xbed\x85\xbfe\x86\xc0\x82\x84\x81f\x87\xc1\x84\x86\x83h\x88\u0085\x87\x84i\x89Æ\x88\x85j\x8a\xc4k\x8bƈ\x89\x86q\x8b\xc1r\x8d\u008a\x8c\x89s\x8e\xc3t\x8f\xc4v\x90ō\x8f\x8cw\x91Ə\x91\x8ex\x92\xc8q\x94\xc9y\x93\xc9z\x94\xcas\x96ˀ\x94Ł\x95\xc6z\x97Ǔ\x95\x92\x82\x96ǃ\x97Ȗ\x98\x95\x84\x99\xca~\x9b\xca\u007f\x9c̆\x9b̀\x9d́\x9eΈ\x9d\u0382\x9fϛ\x9d\x9a\x88\xa0˄\xa1ѝ\x9f\x9c\x8a\xa2̌\xa4\u038d\xa5Ў\xa6ѣ\xa5\xa1\x8f\xa7Ґ\xa8Ӧ\xa8\xa5\x91\xaaԘ\xabє\xac֙\xacҪ\xac\xa9\x9a\xadӛ\xaeԭ\xaf\xac\x9d\xb0֘\xb4ذ\xb2\xae\x9f\xb3ر\xb3\xb0\xa0\xb4٢\xb5۳\xb5\xb2\xb4\xb6\xb3\xa3\xb7ݝ\xb9ݨ\xb8ض\xb8\xb5\xaa\xb9ٷ\xb9\xb6\xa4\xbcڬ\xbb۹\xbb\xb8\xad\xbcܮ\xbdݯ\xbeߩ\xc0߰\xbfཿ\xbc\xab\xc2\xe1\xb1\xc1\xe1\xb6\xc1\xdc\xc0¾\xad\xc4\xe3\xb7\xc2\xdd\xc1\xc3\xc0\xb8\xc3\u07b2\xc5\u07b9\xc4\xdf\xc3\xc5º\xc5\xe0\xb4\xc7\xe1\xbb\xc7\xe2\xb6\xc9\xe3\xc6\xc8ż\xc8\xe3\xb8\xcb\xe5\xbe\xca\xe5\xc9\xcb\xc8\xc0\xcb\xe6\xba\xce\xe7\xc2\xcd\xe8\xbf\xcf\xe2\xcc\xceʼ\xd0\xe9\xc3\xce\xe9\xc7\xcf\xe4\xc8\xd0\xe6\xc3\xd3\xe6\xca\xd2\xe7\xd1\xd3\xd0\xcc\xd4\xe9\xc6\xd6\xea\xd4\xd6\xd2\xce\xd6\xeb\xcf\xd7\xec\xca\xd9\xed\xd0\xd8\xed\xcb\xdb\xee\xd7\xda\xd6\xd4\xd9\xe9\xcc\xdc\xf0\xd6\xda\xea\xd7\xdb\xeb\xda\xdc\xd9\xd2\xde\xec\xdb\xde\xda\xd9\xdd\xed\xd4\xe0\xee\xdb\xdf\xef\xde\xe0\xdd\xdc\xe0\xf0\xd6\xe2\xf0\xdd\xe1\xf2\xd7\xe3\xf2\xe1\xe3\xe0\xdf\xe3\xf3\xe3\xe5\xe2\xda\xe6\xf4\xe1\xe5\xf5\xde\xe7\xef\xe5\xe7\xe4\xdc\xe8\xf6\xe6\xe8\xe5\xdd\xe9\xf7\xe6\xe7\xf1\xe0\xe9\xf1\xe1\xea\xf2\xe8\xea\xe6\xe2\xeb\xf3\xe9\xeb\xe8\xe3\xec\xf4\xea\xec\xe9\xe5\xee\xf6\xec\xec\xf7\xec\xee\xeb\xed\xed\xf8\xe7\xef\xf8\xe8\xf0\xf9\xee\xf0\xed\xe9\xf1\xfa\xef\xf1\xee\xf0\xf0\xfb\xee\xf3\xf6\xf1\xf3\xf0\xf4\xf2\xf6\xef\xf5\xf7\xf2\xf5\xf1\xf0\xf6\xf8\xf4\xf7\xf3\xf2\xf7\xf9\xf3\xf8\xfb\xf6\xf8\xf4\xf4\xf9\xfc\xf7\xf9\xf6\xf5\xfa\xfd\xf8\xfa\xf7\xf6\xfb\xfe\xf9\xfb\xf8\xfa\xfc\xf9\xfd\xfb\xff\xf7\xfd\xff\xfb\xfd\xfa\xf8\xfe\xff\xf9\xff\xff\xfc\xff\xfb\xfe\xff\xfc\x1d\xe0k\xdb\x00\x00 \x00IDATx^\xed\x9d\tp\x14\u05f9\xef}\x93\xdc\xfb\xde]t2\xaa\xbe3\x12\xd2\x13TI\"b\xb9PzFU\xc0Ř\xb5j\"\x95)!\x97\x8b\x87\x1d+U\x02\xa2\xd8O@L \x18\xa1g\f\x97\xa4,,\x16\x13H\xbc@t\xcbv\n\xd9\xd8V\x99'{\xd8\\Pl\x97\xe0`\x85\xb2͢\xc8\x06\x83\x1fKر@\bMթw\x96\x99\x9e\xd33=\xea\x99Ѩ՟\xfa\xfbE\x91z\xce|}\xba\xc7\xfa\xe9\xcc鞦\xff\x0fQ\x04\x01\xc1CV\x05\b\xe2\fPU\x04\b\xa8*\x02\x04T\x15\x01\x02\xaa\x8a\x00\x01UE\x80`\xa1j\x1b\x828\x04T\x15\x01\x02\xaa\x8a\x00\x01UE\x80\x80\xaa\"@@U\x11 \xa0\xaa\b\x10PU\x04\b\xa8*\x02\x84$Tm\x988X\xcb\x1d\xf3\\\xbc\x9e\x12c\n!\xa4\xdc\xd02\x8c\xb5l\x89S\xfd\xe9\xfbq\x9e\x88\xc3H\xd6\x17\xf9ȪJ\xe2g\xa5\xb5r\xf1ͪ\xe2<\xcdW0m\xe9\xe1\x1e\xd7@\xfa\x95\xc4U}\x96\b\xfcq\xbbJ\x88dT=\xbdj\xc8\"\xd3'\xe2\xf1\x8e\xd8\xc3j\xab2\x89\xae\xea\x81i$L\xd6*\x8b\x95\x90\xfe#aU\x0fg\xc8\xdf\xe6\xc2\xf8}%B\x12\xaa\xbe_BHr\xaa>%\xf6p\xc8\xe7Vu\x82\xb0\xaa\x9f\x16\x13\x85eV\xab!\xfdEªna\xbfnj\x15\u007f\\\xbf+~_\x89\x10\xab광#G\xfeѬt\x06IR\xd5\xd6AR\xb7\x97\xad\n\x05aU\xe7\xf3U|\x13ʧ\xe4\xf1\x05-\xc1\xe9\x03b;\t\xab\xfa2\xfb=\x16\xc7\xef'QbU\x8dKҪ\xbe\x1c\x1a\x19'Y\x15\nª\x0ef?\xffן\xd8\xc2\xe7\v\xf9\xcas-VC\xfa\x8b\x84U\xfd\r\xfb5\x8e\x8d\xdfO\xa2\xf4\xa5\xaa\x13\xf9.\xf2\xc1\u007f\x8fU%'\xa4\xea\x01\xee\xe7\x9fdSIz\xfe\x1c\x91>!AU\xcbC\x03\x16\x19\xd9֖\xcd~\xc8#\xf3!l\x89\xbfw\x17\xb0wж\xd6ec\x06\xf9\x8a\x17|\x1aZ\xe3\xf3U~vT]\xf4ě\xc6\xed\xf50W\xdd3\u007fL\x8e\xa6\r\x9e\xb0H\x8837\xbc\xc5M\xfcсg\x8b\xb3\xbc\x85\xe5\xe19\xad\xd9\x06\xdbv\xf1\xd9\xf4G|\x90\\\x10n2\xab\xdbU5ԛ3\xe5U\x83\xaa\xafȧ^\xad\xaa\xaa\x9a/\x17\x8d\x1b\xfc\\8\xbcl\xa8\x967\x83\xff\x97(\x93\xad{\xf8\x06w\xc5V#}B\xdaT\xdd5R\x16\x14\xca\xc9\xecG#\xc3k<\xf5\xa5\xba\xbd\xf8\xaan\xca\n\xaf\x91\xc7\xe7\x8b\x06Uׇ\x9f\xf3K\xe1L6\xd8ֶ\x80=\x18#\xd6+<\x1dj2\xa9{\xd9+\x1fV\x86T=ͧ\xa8ު\xa8\xb3bQ\x1b\x14\xaa\xf2\xfeɣ|\xce\xee\x95{\xb1\x88-N4\xa9F\xfa\x84t\xa9\xaa\r\rW\x88\xb3Y{\x06\x13\x9dy\xea\xf6⪺K($O3\xe4\xb7\x1aUݔ\xa1w6AX\x18\xbbA\xe6\\!\xe1\xee\xbdϛ^\r\xf5\x1d[\xb7E\xef*\x93ȹ\xeas\xf2a^\xc5\xca\xc8\x11c\xf4\x06\xb9\xaa\x83DۊӼ?yN\x8b\xff\rԛT#}B\x82\xaa~\xb8\x85\x9fV-\u07b2\xe5\x9d8\xaa\x12R\xb0\xe2\x9dz\xbe\x90\xc9G\x16n\xa4\xb7zS\xfd\x04\xf6\xd3\U000e1cbd\xb8\xaaV\xb3\x1fU\xbbN\xb7n\xe2\x9d.c[\xdc4\x9e-<\xb1iӁ\xb6Os\xd9Ҙ\x86?\xfe\x8a\x1f\xe1\u05f6\x99nP\x9e\xa2\xc8< \x05\xfaq\xa8\xef\x98:!\x9a6\xff\x9d-O\b\xb3xg\xadcI\x98⥲\xab\x98\r~.\x9e\xce\x1c3\xccs@\x8c\xa5\x13x\x15\xff\xa3\x18\xd4jR\x8d\xf4\t\t\xaa\xaa\x1eV\x99\xab\x9aÏe\xc49xf\xf3\x87\xfc'\u007fW\xffr\f1\x9e\x93\x8f\xab*\u007f?\x16\xf3\xdaM?\x9e\xbf^\x1c\x17\xe9\x87U˸E\xfcd\xe9\x1f\xd9\xf05\xbc\xcdl\x83\x8c\n\"\x8f\xfd\xb9J\xda\x01\xd9wL\x1d\xf7\x99\xac\xe7OU\x91\xb0X\x9f\xf25C\x14l1ݠP\xd5\xc7\xd6\xdf\xce楙\xa1\x037>\xeeW\x99\xee\x1e\xd2\x17\xa4M\xd5gE\v\x1fX\xd8o{1\xe1\xd3FΖ\xe7^1\x9c\x89\x8d\xab*\xf7\xc5W\xf1\xf2\x81\xc8\x13\xba\xaa\xfc\xc8~\x85h\xe2\xe2\xf3\x89l\xcc\x06\x99p>\xb6\xf4\x1b\xb6\xb0\x87k\xb5Dv\x11S\xf7\xac\xbec\x875\xa2\x8f\x81\xef?\x95\x13vU{\xd3l\x83Bէd\xb1\xf8\xa3Z\xcc\xfe\n\a\x87\xfe;\xc4\xee\x1e\xd2\x17\xa4MUy\u07bd\x88\x88\xc9%\x9f\xdaVEoJ\x10W\xd5M!W\x86=\xb5\xa9U>\xa1\xab\xca=*\x9b\xcb\x19\x1e\xdaP\xcc\x06\xdb\xda\xfe\x0f[\xf0\x89\xf7o\xfe\x86>Bv\x11S\xf7c\xa2\x0f\xf2\xfcC\xaa\xda\xf0N\x9c~gѣ>\xb1\xfd\xa1\xa7M6(T\r\u007f\xb2\xc0\xf7\xb4\xb8\xad\xedU\x12:\xb3\x15\xbb{H_\xd0+U\xf9$-\xac\xaa<Q3R\x1a1\x89\xfd\x98\x1f\xbd)A\xfc3\x00\xe2\x1dY\x90/Ǩ\xb0\xaa_\x12\x03\xb5m&\x1b\x94#Zn9g4\xaf\x92\xe7\xc8b\xea\xf8\xdcy\xb1\xdc\xee$\x125\xb3lm\xe0\xbb\xc2\xeac7(T}'T\xf7%?g\xf0\xa1x\x1b\xe0\xeb\x9b\xec\x1e\xd2\x17\xf4JU~\x8e&\xac\xaat\x83\x0fU!U\x9f\x8dޔ\xa0\x87\xf3\xaa\x9b&z¿oq\xf9VX\xd5V\xa3\v\xbc)f\x83rv\xacP!\x9e\x8d\xa9\x9bH\xf4\x8f\x15B\xaa\xbe\xbc\xa8jF\xf8\x84\xc1\x01>\xb0.3٠PU\u007fk\xe7\x1f\xc5\xceoe\xb5\xde?\x99\xef\x1e\xd2\x17\xa4\xa0*\x9f\xf6\x89\xdf\xff\x97\xfc$\x8d\xa9\xaa|\xc4yB4\xb4~d8\xad\xda\xf3\xe5*\a^~B\fl\xc4\xcb\xe7\x00\xfa\x04\xc0\x17\xa9\b\x11\xabj\xb5Q\x98\xd0\\ \xa6\x8e\xf7\x19\x9as\x8e&B\xd5\x12u\x87\xf8\xd8\xfb\xac\xc9\x06\x85\xaa\xfag`\xfc\xb3\x86\x91\xaf\xe8\xeb\xc5\xee\x1e\xd2\x17\xa4\xa0\xea\xe0\x90\x1dr$3U\x95\x1fV\x15\x88S\x8c\xbf&\xdeb\xf5c\xf5\xf8\xaa\xb6n\x97\x9fK\xf1uŨ͵\x12\xc3+\u007fo\x97\xc7I[B\xba\xc4l\xf0\xcb|\x12\xc5\n\xd3:~\x12u\xa4h\xd8Ç\xf0Z\xe9\xb8\x16:\x9d\xb6\x8b\x1fj-3٠QնG\x89\xfc\x04W\n\x1a\xbb{H_\x90\x82\xaa|\xe8\x11\xf6\x89\x93<\xa6\xaa\n\x89\u007f\xc5\x1e\u007f\xce\x1b\u0087Μx\xaa\xee\xe2}D\xa6\x15\x1f\x86\xba\x17\xb3\x88\x85la0\x1f%\xdf!${\xec\x01\xb3\r\x8a\x832\xfd\x13'~\xf2\xf4\xe16\xb3:qҊ[|\xba\x8c/Նv\xb5@|\xb2\xfa\xfe\b\"7\x1d\xb3A\xa1j\xe4\xe4D躘Їb\xb1\xbb\x87\xf4\x05)\xa8\xca\x15\xf2,|\u007f\x8b_\xfc\xbeLUm\x9bƟ\xf2\xd7.*\x0e\xfd\xf2u\xb8\xaa\x85\xe5:[\xf4Q\xb5X\x18s\xb8\xf5C~r>\x8fK\xc0\xaf>͙\xff\xd4\u007f\xca)d\xf1\xab\xbb^\xe1\xdb\x11g\xdfc6\xc8ŋ\x9c\xd2\xe4\xf2\x90\xed\xa6;Ƈ@\xf2D\xc3o\xe4y\xffڶ\xf0\aq\xf9c'ɹ\a?5\x1b\xb3\xc1(U?\xcf\x15\xa5\xa1Kwcw\x0f\xe9\vRP\xf5U\x12\"\x93\x8fB檪\x1f\xac\x1a\xaeʟB\f\xd4ꪾ\xefS\x9a\xf9Ǖm\xb5z\xc9\xca\xc83Y\xc2\xfb\xe8\r\x8a\x93\xa4\x91\x8b\xbeŅ+\x95\xa6;\xf6\xa1\xbe\x99a\xb2\xef\xb6\xc3\xfa\xd5\n\x9c\"!d\xf4\x06\xa3Tm\x9b\xc7\x1f\xeb\x17p\xc5\xec\x1e\xd2\x17\xa4\xa0j\xf8\xe3\xf9\xac\xfaY$\x9e\xaam\x1f\x8d\b\xff\xf6\xaa\f\x1f\x8b\xc7U\xb5\xedͼp\xa3W\x9e\xac:,\xcf\xcbs\xd3\xeb\u0082\xe5ɋ\xb0\xa37\xc8?0\"\xcaG\r\xfc\x9cTN\xab鎽\x19\xba\xfezn\x1d\t\xff\x83\x952\xa23)\xd4I\xd4\x06\xa3U\x15\xb3\x86\xc8e\xb1ѻ\x87\xf4\x05\xa9\xa8\xda\xf6ʣ\xb9\xdea\xf3\xf6\xb4\xf5\xa0j\xdb\xe7+\xa7\f\xd6|ß\n\x9f\x8d\f\x11_ն\xd6\x15S\xf2\xbcZ\xee\x98g\xc3\xce}T>X\x1b<It\xb7g~qn\xe6\xa01\x8bBW.Eo\x90\u007f\x1f\xa3l\x85\xef,?\x19o\xb6c\a\xe6\x16y\x87\x94\xbd٦\xab\xcaF\xf4\xb9c\x06k\u07bc1\xf3\xfeS\xef\xc1\xb8\xc1hU\xdb\xf8\xf5\t\xf5\x91\x87Q\xbb\x87\xf4\x05\t\xab\x8a \xfd\v\xaa\x8a\x00\x01UE\x80\x80\xaa\"@@U\x11 \xa0\xaa\b\x10PU\x04\b\xa8*\x02\x04T\x15\x01\x02\xaa\x8a\x00\x01UE\x80`\xa1*\x828\x05T\x15\x01\x02\xaa\x8a\x00\x01UE\x80\x80\xaa\"@@U\x11 \xa0\xaa\b\x10PU\x04\b\xa8*\x02\x04T\x15\x01\x02\xaa\x8a\x00\x01UE\x80\x80\xaa\"@@U\x11 \xa0\xaa\b\x10PU\x04\b\xa8*\x02\x04T\x15\x01\x02\xaa\x8a\x00\x01UE\x80\x80\xaa\"@@U\x11 \xa4]ՉdIlc\xfb\xbd\xd86+V\x90\xa7\xadJBE\tU\x9a\xd3@ʭJ\x10\x87`\x87\xaa\xc1\x95\xbe\xebf\xa5=\x93\x90\x80\xa8\xaa{\xb0C\xd5\x0eBPU\xa4\xb7\xa0\xaaV%\x88C@U\xadJ\x10\x87\xd0\x1bU?~O\xe7\xff\xea\x8dR\xd5\x06Rw\xa9\xba@+\x9a\u007f\x89\xd2\x1a\x11\xfbs\x84\xb5\xb6W\x17i\xb9e;xY=Y\xb5c\xb8o\xec)\xb5\x90\xb1\xbd\xa2@\xf3\x8d^p\x81F\vx\xe2\x99aZ\xee\x8cݦE\xc6ʝe\xf9\xbe\xf1M\x87Ȥ\xc8F\f\xab4\x90\xda\xe3\xe59\xd9\xe3_\v\x8a\a\xe5\x17\xf8\xe6\x17\xa6\xf0\xb7\x84\xd8KoT}\xe4\xefu\xfeMo\f\xabZ]@\xb2s\t\x19\xddA7W\x10R^\xd1N\xe9\x8e,\xe2}\xb8\x88\x90Ŕ[T\xed%$\xabC-\xa4\xb4\x8a\x90\x82\x92<\xf6\xedr\x94\x80M>\x92]\x92OH\x93Y\x91\xa1\xb2\x81\x90\xfc\x12\x8dTHU\xe5F\f\xab0;\xb35\xff\xa3\x1eR\x19\xe4\x0f\x1e\xce#\xf9l\xf3\xc5\x1d\x14q6\xbdQ\xf5\xcc?\xe8\xaa\x1e\xd4\x1bê\x92Ql\bl\xd2\xc8\x06}\x02ОMj\xeePڒK\x1a\xb9E\x9e\xe1M\xcd\x1b\x8c\x85\xcd\xc4LJ\xdc@6Yi\x14\xf0\xebl\xb2\xa0\x83\x06k\x89\xf7\x92I\x91Zy\xd4C\xea\x83\xf4\xf2\f\"U\x95\x1b1\xac¶8\xfc$\xa5\ar\xc9F\xf1`\xd8>J?\xd0\xc8f\x8a8\x9bި\x1a\x19V#\x83jDտ\xf0GU\xa4JW\xb5\x86\x94\x89\x8a7\xc8(n\x119F\xa3\vk2\x16\x89\x8a\x1a2\xc7(\xe0\"\xe2\x0fu\xbeޤH\xad\x9cEj\xf8\x8f\x8eaRU\xb9\x11\xc3*l\x8bG\xf9\x837H\x91x\xd0\xca\x1f\x88\xcd#\x8e\xa6W\xaa\xea\xc3jdP\xd5U-\x16\x8fV\xf1Ö\x90\xaa\x85\xe4m\xd1\xd6\xe1!\xa7\x98EE\u2061\x90ޓo\xc3\xcbȓF\x01\x8bC\xab\xb6\xb7\aM\x8a\x94ʮl)'k\x13\xaaʍ\x18Vi \x13d\x9b\x97\x1c\xd77_\x8f\x87W\x8e\xa7W\xaa\xd2\u007f\x8f\x19TuU\xe5\b\xba\x9e\xcc\b\xabz\x8bM\b\xc7\v4\xd2\xccܐ㤡\x90\x95\xeeް\xb8b(!\xb3\x8d\xaajr\xec\v\x11]\xa4T\xb6\x93̠Xh\x96\xaa\xfacWi\x90\xe3.\xf7\u007f;{ +6ꕈS靪_\xfcC\xf4\xa0\xaa\xab*G\xa9\xf5\xdcD\xa9\xeay%\x05\xb8\x91YT!\n\f\x85\xc1U\xecȉd\x94L\x88R\xf5\x0e!\xed\xfa\x06b\x8b\x94\xcaC$K.|\"U\xad\x88]\xa5\x81,\x95%\xe3\xc8\x1b\xfa\xe6QU\xe7\xd3;U\xe5\xb0\xfa#\xb5%\xae\xaa\xd7\t9\x11)3U\xb5\x96dTn\xde\u007f\x8b\xd6E\xa9\x1a$\xec\xbd:Ll\x91Ry\x82d\x18FՊ\xd8U\x1a\xc8\x02Y;\x9a\r\xee\xa8*\x1cz\xa9\xaa\x18V\xd5A5\xbe\xaat\b?\xf2紜\xec2U\xf5A6;j\xe2TGO\x00\x86\x8b\xb3T\x94\xbe=m\x95I\x91R\xf9\xc0\x1b\x9a\xab\xaeTT5\xae\x12~Ͽ\xa3\xb1\xa1\x1aU\x85C/U\xe5êaP5S\xf5\x1e!\u007f\xa3\xfc(\xbbD\x8cx\xdb\xf9)'3U/\x84\x06\xcf[\x05\xfcIU\xd5\x1a9\x93\xa5e\xa4֤H\xad\xac\x90cfW\xb1\xa2\xaaq\x95\x06\xa2\xb5\xcb-\x97PT\x15\x10\xbdU\x95\r\xab\x86A\xd5LUvT\xd4x\xa7\x8b\x1e\xf7\x9297\xd9,2\x97T\x9bO\x00\xba\x06\x91\x1a&\xf3Y?\xe1k\xa9\x02\x9e\xf6\x91e\x0fh\xb0\x8ed\x9d7)R+\x0fgx\xd6\a\xe9\xcd'\x89\xa2\xaaq\x95\x06BJ\x98\xab\xdb}\xec\xfd\x1fU\x05DoU\xa5\xffn\x1cTMU-a\a5\xcd\xe2<\xbf\xb7d8\x93\xa8#\xce\\\xb5\x9e\x90\xa1\xfe\xb1\x9e\x9cE\xe4\xe1\xe8O\xab4\x92S\x92K\xb4&\xb3\"Ce=\xff\xb4\xcaG\xc6q\xf7\xc2\x1b1\xac\xd2@\x86y3K\x86\x11RKQUH\xf4Z\xd5/\x8c\x83\xaa\xa9\xaa\xc7'zs\xde`?O\xfc\xacH\xf3\x95\xac\xe2\xd7Y\x9b\xaaJ\x9b'\r\xf1\x8e^t首\xd1n\x14\x90\x1e\xaf,\xc8\x1cR\xc1/$\x88-2V6\xfb\ay'47\xf0)Cx#\x86U\xd8\x16\x8f\x94e疵\xa8\x9bGU\x9dO\xafUu(+ȼ8\xcf\xe0\xc5T@\x19h\xaa\x96\x95\x04\xc4ωd]\x9c\nT\x15(\x03M\xd5\xf9☩c1ɽ\x1c\xa7\x02U\x05\xca@S\xf5B\x11\xc9\x1cU\xec#Y\xcd\xf1*PU\xa0\f4U\xe9͕%\xb9\xbe\x115'\xe3\x16\xa0\xaa@\x19p\xaa\"\x03\x15T\x15\x01\x02\xaa\x8a\x00\x01UE\x80\x80\xaa\"@@U\x11 \xa0\xaa\b\x10PU\x04\b\xa8*\x02\x04T\x15\x01\x02\xaa\x8a\x00\x01UE\x80\x80\xaa\"@@U\x11 \xa0\xaa\b\x10PU\x04\b\xa8*\x02\x04T\x15\x01\x02\xaa\x8a\x00\x01UE\x80\x80\xaa\"@@U\x11 ؤ\xea\xc5o/^\xb9ml\xba}\xe5\xe2\xb5k\xdd\xe6\xe5\b\x12\x83M\xaaF\xf8x\xed\x15\x8a\x82\"\xc9c\xaf\xaa\xf7)]\xfd\xd8_\xf9\x0f\x04I\x12{U\xa5\xfc}\x1f\xc7T$\x15\xecT\xf5\xfe\xfd\xce\xfb\xf7\x0fn\xbb\xc6~t\xa3\xafH\x92ة\xaa`u\xe99\xab\x12\x041\xc1vU\xbb\xafXU \x88\x19v\xa9\xca\xde\xf0\xbf\xd8\xf6۵kּ\xbe\x8d}[\xfb\xd6{\xdfY\xad\x81 \x06\xecR\x95\x1d\xf4\xaf}\xbct\xfa\xe4ɓ\x1fa\xff\x9f\xfe8\x9b\x06\xe0y\x00$\x19lT\xf5\x85\xc9\x1f\u007f\xf6\xe7\xcf\xfe\xcc\xf8\xec\xb3_N>\x83\xaa\"Ia\xa3\xaa/\x96\xde\xd5\x1f\xae)=C;)ڊ$\x8e\x9d\xaaN\xffB\u007f\xf4\xc2\xf43=U#H\fv\xaa:UW\x95.GU\x91$\xb1Q\xd5\xe5\x8f\xdd\xd8\xf6\xa3\x1f\xfd\x1b\xfb_\xe9\xfd\xdfN\xbf\xb8wm\xe7\xc15\xca\xf5\x00G<\x84\x90\xb9\xfa\n;\xf2\x9aL;\xb2\xa0\xde\xfbk\xb3\xe6v\x8d\x14\xf3\x9fGg\xe4\xe7Lk)\xd9mV\x838\x1b\x1bU}~&\xfd\xe5\xf7\xfe\xee\xfb\u007f\xf7\xfd\xef\xfd\xf7\xcemSo\xbf\xfe\xd8\xed?\x94*\aW]\x9f\x8c-\t\x9c\xd7W\xf8 \xfb\xed\xd8^Z\x0eŶ\x19)\xd1J̚\x83\xfb\xaa4\xf6\xe3\x90V\xde\xf4F\x05\tGh#\x90\xb0Q\xd5\x17J\xbf=\xb7m\xdb{\xec\u007f\x1fӗ\xa6\x9e\xbb\xf2Y\xf7\x95/:\xd5\x1a\xbf!<2Hc\x99\xf0\xa4I\xa3\xca\x1dO\xa5\xe7\x96\xe93u\\\xd52?\xeb5X\x85\xaaB\xc4FU\x95\xb9j\xb7\xe9\\\xd5o\x99s:~\xb6EA\v9DZL\x9f\x11\xaa\x0e\xe7\xf9\xaf\xf4(Iin\x81\xf4/v\xaaZzN\xceLٷ\xff\x98z\x86ލ>Y\x15Q\xf5\xba\x8f\x10\xcfV\xb9\xbc\xb3\xacH˟1,H\x9b\x88d\x1co\r\xbe\xf6hv\xf1\xc2\x0eJ\x9f!\xda\xc6\x05\xc5YegEq\xddPZ\xc8\x13\xa9\r\xad\xdfT\x16\xe6\xce\x12\x13\x80'\v\x8e\xf1u\xb7\xdfR{8\x92I\xc8\xd2S\x95\xc3}e]\x8d\xac\xfb:ZG\xc4\x14A/@\x1c\x81\xad\xaa\xde\xd0\x1f\xae)5\xf9\b@\x19U\x0f\x05\x02\xde:\xb1t \xa3\xf2\xed\x1d\x1b\xf3I\x17\xbd\xb3;0zZ \x108\xc1\x9b\xe7yj\xb67\xe4\x8d\x0fҿl\xcd$yu\xbfΑ\x19\xd5\xfeYt6\xefEm=\x95S\xbc\xb9\xa9\x8cpUۋ<eu{\x1ePC\x0f\x1d\x8d[\x87\x8d\x1eT\xb4\xa02\xe3\xeb[;s\x96]\xa2\x97jsw\xdeR\n\x10G`\xa7\xaa3\x9f\u007f\xe9\xc5Ռ\x17W\xbf\xf4\x93GL.\xb06N\x00|R\xd5uy]\xfc{\xae0F\x9f\x00\xbcK~Ǿ\xef'|\xe4\xd5r\xcfRZ\x99Ǜ\x83\xd9\xf5\xb4>[\x94FZ\xa7\x8cb#c\xb0\x84\xabJ\xaf\xae\x98\xa0\x91\xdcƨ\x1e\xe8x\xe2\xbfI\x837\xd9\xd2<>\x1b\xae\xfcYt\x01\xd2\xffب\xea[?}\xact\xaa\xa4\xf4\xa7?\xbf\x98\xa0\xaa\xe7\v\x87\xd7l<\x1c\x94#\xa1\xae\xea\x93#\x1et1\x86\xf2\x93[\xda\x1c\x1a\x9a\x8a\xd2#dw\xc7nr\x84\xaa\xad\xd7\xc9F\xfex\xa9\x16Z\xf5ގ2\xb2\xdd\xd8\x03\x1d\xaf}\x1dz\xb6\xc5\xd7A;\xb2Z\xa26\x818\x00\xbbTe\xdc8w\xe6\x8b0\xe7\xbe5\xb9\xb6\xdaTUz}\xc3\xecb\x92\xbf\xca8\xaa\x96\x84\xe6\xad\xfc\r^\xe3\x85R\xd5\x06\xd1\xd8@\xd5\xd6CDĮ\x8b\x82\xfd\xdf\xf0\xc5\xe0\xa4rc\x0ft\xfc\xb8\xf0V\xbb\xf2\x9bhS~0j\x13\x88\x03\xb0QUK\xa4\xaa\xb7\x96]\x15\x8fB\xaa\x1eZ̼\xb9\xbeշ\x8e?\x10\xaanf#`\xe5\x88C\x02\x9e\xa4\xae\xa8:k\xdc\xfe\xfd\xfb\xc7͢j\xeb߈Xu\x0e/(\xa8\x11}.\x19e쁎\x9f\x15\xde\aZSA+D\x95\xa1\x00\xe9\u007f\xecT\xb5\xbb\xfb~\x98n\xb3\vU\xa4\xaa\x87\xc9N\xf1(\xa4j\x1d\x11q\xe9\xfe\xeap\xc5%~t\xde,O\x8d.YI\r\xaa\x16.d\xdf\x16\x14RC\xeb\xc4\"\xe6\xfeI/_\xcc/\xe4\u007f\x06An\xa6ڃz\x12l\x8f\xf7\x82w\x0f_0\x14 \xfd\x8f\x9d\xaa\xf6Lמ\xb1%\xec\xf8>\xb0\x81\xbda?\xf8$\x10\xf0V\x05v\xde\xe4\xaaf\xd7~\xd04W\x9e-\xad\xd3\xea\x9b\xfc\xd9\xfc#\xad\xc5\x19O\xbf\xcdZߠ\x17\x02Zվ\xe0\xe1*-p\xa1\xa3\x99,\xb9C\xef\xfc\x8a4\xdfSZ鱬\xa2\xba\xa5\x83=\x99\xbf;N\xf3IAms\x93\xdfwR\xed\xa1k\x8f8\xb3\xd0.w#XXV(\x0f\xfa\xf5\x02\xc4\x118Gգ\x9e\xd0\xe4\xd0w\x82\x1e\b-o\xa0\xf4\xb5iuEZ\x81_\x9e\u05ffW3\xd87m\xbfXl\xf6\x0fɝ\xd2\xccϠ\x12\xa2\xb5f\xb3\xef\xcf\xec\xc8\xe0\xe7C\x9b\b\xc9ء\xb4Rz\xaa|\xf0\xf0\xe7~\x97\xc9\x16'l^R\x9c\x9dWq\xd2\xd0\xc3\x11\xb9\xb1\xf2\xd0~\xd4k\xf5\xa1\xa5p\x01\xe2\b\x9c\xa3*\x82\xf4\b\xaa\x8a\x00\x01UE\x80\x80\xaa\"@@U\x11 \xa0\xaa\b\x10PU\x04\b\xa8*\x02\x04T\x15\x01\x02\xaa\x8a\x00\x01UE\x80\x80\xaa\"@@U\x11 \xf4\xb3\xaa\x18\x12\x84$J?\xab\x1a\x01C\x82\x90\x9eq\x86\xaa\x18\x12\x84X\xe2\fU)\x86\x04!V8AU\f\tB\x12\xc0\t\xaa\n0$\b\xe9\x19Ǩ\x8a!AH\xcf\xf4\xb7\xaa\x18\x12\x84$H\u007f\xab\x8a!AH\x828@U\f\tB\x12\xc1\x01\xaabH\x10\x92\bNP5\xa1\x90\xa0\xa6G/\xc5y&U\xaeN\u009bWC\xc2\t\xaa&\x12\x12\xb4\x8a\xd4Eݓ\xb7\xd7a)\xc1U\x9e\xd8\xfbQa\u038bcq\x80\xaa\x16!A\x82\x06\xcfkQ+\xa6#,e{fCt\x13\xe6\xbc8\x16\a\xa8j\x11\x12\xc4i\xd3\x16\x87\x17/\xfb\xe5]$\xd3\x12\x96\xb2L;\x1bӆ9/\x0e\xc5\x01\xaaZ\x86\x04Q:\xb7@O\x8f8F\x8e\x89\x9fi\tK\xb9S\x10{Oj\xccyq(\x0eP\xd52$\x88>\x18\xb4H.4\x8c~\xf7\x049\xb1}\xf4\xfaT\xc3R\x94\x02\xd1\xe12_L\x82\n\xe6\xbc8\x14'\xa8j\x15\x12D\x0f\xcb{\xa4\xf3_7y\x98\x94\x90Y\xe7S\rKQ\nĚ\xbb\xc9\x1e\x1a\x05\xe6\xbc8\x14G\xa8j\x11\x12D\xb7\x93\x93\xe1\xc5f\x8dh\U000969e9\x86\xa5D\n\x18gI\xcca\x13\xe6\xbc8\x14'\xa8j\x15\x12\xc4\xdetC\xb7\x94\xbe\xba@+$\x85\xde\xe7\xfe&\x1f\xa6\x14\x96\x12)\xa0\\\xd5F\x1a\x05\xe6\xbc8\x14\a\xa8j\x19\x12D\xf7\x91O\xe4ª\xfc\r\xc7\xc9_\x1a\xf2W\xf6\",%R@\xf9p\x15sr\x13s^\x1cJ\u007f\xabJ\x13\b\t\xa2\x1dZH\x18\xfa\x80\x1e#\xc7\xe9\x83`/\xc2R\x94\x02\xaeN\xccI%\xccyq(\x0eP5\x01f\x8d\xd2\x0f+\xce\xe7\xca\x13\xf4)\x87\xa5\xa8\xa7\x9a\x82\xc5\xe1\x04\x00ھ\xb2M.`\u038bCq\x82\xaaV!A\x94\x9e\xf0\xc4|P\x99ZX\x8a\xb1\x80\xd6\x13\xfd\x83\xa7\n2\x83\xff\xc0\x9c\x17\xc7\xe2\x04U\x13`\x997zN\x99ZX\x8a\xb1`\xa7\xef9\xbd\xbf\xcdy\x1b\xf8\x0f\xccyq,@T\r\xce\xd7\x1a\xadj\x92\xa6Q\x9b\xdbeU\x838\x06 \xaa\xd2`\xfd\xd0t\x1fY\\-X\x89'\xd6\x01\x01EU\xc4\xf5\xa0\xaa\b\x10PU\x04\b\xa8*\x02\x04T\x15\x01\x02\xaa\x8a\x00\x01UE\x80\x80\xaa\"@@U\x11 \xa0\xaa\b\x10PU\x04\b\x0eU\x15\x93W\x90h\x1c\xaaj\x04L^A$\xceV\x15\x93W\x10\x1dg\xabJ1y\x05\t\xe3dU1y\x05Qp\xb2\xaa\x02L^A$\x8eW\x15\x93W\x10\x89SU\xc5\xe4\x15$\n\xa7\xaa\x8a\xc9+H\x14\x0eV\x15\x93W\x10\x15\a\xab\x8a\xc9+\x88\x8a\x93UM(y\x05q\vNV5\x91\xe4\x15\f\tr\r\x0eV5\x91\xe4\x15\xdbB\x82\xd2\xd0/\xd2;\x1c\xacj\x02\xc9+\xf6\x85\x04\xa5\xa5_\xa478X\xd5\x04\x92Wl\f\tJK\xbfH/p\xb0\xaa\xd6\xc9+v\x86\x04\xa5\xa5_\xa4\x178YU\xcb\xe4\x15;C\x82R\xeb\x17I\x1f\x8eV\xd5*y\xc5ΐ\xa0\xd4\xfaE҇\x93U\xb5L^\xb15$(\xd5~\x914\xe1`U\xad\x93Wl\r\t\xa2)\xf6\x8b\xa4\t\xa7\xaaJ\x13I^\xb13$(\xe5~\x914\xe1`U\xad\xb13$(\xe5~\x914\xe1dU\xad\x93Wl\f\tJ\xb9_$M8YUk\xec\v\tJ\xb1_$}\xc0Vվ\x90\xa0\x14\xfbE\xd2\apU1$\xc8=\x00W\x15C\x82\xdc\x03tU\x11׀\xaa\"@@U\x11 \xa0\xaa\b\x10PU\x04\b\xa8*\x02\x04T\x15\x01\x02\xaa\x8a\x00\x01UE\x80\x80\xaa\"@@U\x11 \xa0\xaa\b\x10`\xaaڍ!A\xee\x03\xa6\xaa\xf7)}i&\x86\x04\xb9\v\x98\xaa2:\xa3\xc2\x02\x91\x81\x0eLU\xd9;\xff\xde\u05ef\xe1\x04\xc0U\xc0T\x15'\x00.\x04\xa6\xaa\x14'\x00\xee\x03\xa6\xaa8\x01p!0U\xc5\t\x80\v\x81\xa9*\xc5\t\x80\xfb\x80\xa9\xaa\x9c\x00tw\xd2\xee\xfb\xfc\v\x87W7\x00S\xd5\xd0\x04\x00q\x130Uet\xde\xe8y(Ő\xa0\x81\x06LU\xf95\x00o\xdd\xdf\xfbR\xe7\xde\xd5\xec\xeb\xee\xc1\xb51\x15\xb6\x85\x04U\x11B\xb2NŶ\xab\xfc\xad:\xdf7\x03o\x83\xd1K`\xaa\xca\xefi\xfd\x93\xef^\x9fy[|\xdd\xd8\xf6\x93\xe8\x02\xfbB\x82\xce\x06\x02\xeb·y\x8d\x87\xbf`\xc3\x1c\xdf\xf5\x9ek\x10+`\xaaʸ\xfb\x1d\xbd\xf6\xd7\xd0\u05cdsQO\xda\x18\x12D\xf9}\x83{V\xf5*i\xa0\xc1\xe8\xfb\xb5\"\xc9\x02SUq\x06\xe0J\xfc\xe7m\f\t\xa2֪\x9e\xea\xddF\x11\tLU\xc5\x19\x80\xaf\xba\xef\xc69YegH\x10UT\r\xae\x1f\x975v\x9d\x98\x94^\xae\x1c2t\xe1\xc2!ٍ\x0f\x86ț\xad/\x88]\x0fI\n\x98\xaaҞ?\x02\xb03$\x88*\xaa\xceіn_\xaaU\xb1\xa5\a\x0f\x17\xac\xab\xf5\xfa6\x97\xd5\xd3Á\xad\xa4.\x10\xb8\x10\xbb\x1e\x92\x140U\xb5\xb8\x06\xc0\u0590\xa0\x88\xaaͤ9\xfc\xbd\x91\x1c\xa1t\x1d9.\xdaq\x02\x90\x16`\xaajq\r\x80\xcd!AaU畈\x1f\x0f\xb3auq.[8\x19R\x14UM\v0U\xa5=O\x00\xec\f\t\xa2\x11U'\xc9\x1b\xad\x97O\xa4\xb4>\xe32\x1f_\xe5\x11\x1d\xaa\x9a\x16`\xaaj1\x01\xb03$\x88FT\x9d;\x82{\x1e\x1c>\x87ү=e_\x1f\x19=I\x9e\xf6GU\xd3\x02LU\xad.\x02\xb41$\x88FT\xdd.&\xb7[\xf9\x1c\xe3\x10\xc9'\xc4\xff\x8d|\x1eUM\v0U\xa5\x16\x17\x01\xda\x18\x12t\x9e\u007fZU\x1f\b\xf0\tm\xa5g\xf1\xbb\x8b=\x95l\xe9\x90w\xc7\xf6\xc07\xa23y\x06`\x1f~\xae\xda[`\xaaj\xf9\xaf\x00\xec\v\t\x9a\x13\x9a\xd7\xf2\xd3\a\xc1\x86\x92\xac\x12q^u\xb7\xc6۴i\xc7\xe8\xbd\\\xf1t\xe6\t\x8a\xf4\x0e\x98\xaaZM\x00\xfa;$\xe8Rv\xf5\xa5\xae\xae\xeb\a*\x06\xe3'\xffi\x03\xa6\xaa\xd4\xf2_\x01\xf4oHPS\xae\xac\f\xe6c\xccZڀ\xa9\xaa\xe5\x04\xa0\x9f9䑧\xa9\x8ey\x0e[T\"\t\x03SU\xcb\t@?\x13\x9c\xeb\xabnli\xac\xf6U':\x0e#\x96\xc0T\x95ZN\x00\xfa\x99`SY\xa1VX\xf6.\x9a\x9a>`\xaa\xea\xf4\t\x00\xd2\a\xc0T\xd5\xe9\x13\x00\xa4\x0f\x80\xa9*u\xfa\x04\x00I?0U\xc5\t\x80\v\x81\xa9*N\x00\\\bLU)N\x00\xdc\a\xaa\x8a\x00\x01\xa6\xaa8Wu!0UŹ\xaa\v\x81\xa9*\xc5\t\x80\xfb\x00\xa6\xea\xb6\xce+w;\xef\xdfg_{_\xbf\xc2\u007fܧ\xf7\xef\xde\xed\xbck\xb5\x1e\x02\x1f`\xaa\ue95d\xfc\a{\xe7\xff\x8f\xd238\x01p\x15\xc0T\xedԗ\xae\x9c\x89,#n\x00\x98\xaa\xfc\xa0\xff\xe0\x1fV\xbf\xb0|\xf9\xf3\xbf\\\xbe|\xf9\v\xbf\u007f\xeb6\x9e\ap\t\xd0Te\xef\xf9k\x1e/e̔ߧ\x9e\xc3i\x80K\x00\xa8\xea\v\x93\xf7~u\xe6\xab\xef\xe8\xc53_}\xf5\xfcd\x9c\xb1\xba\x05\x80\xaa\xbeX\xfa\x1d[x\xef\x17\xfc\xe1\x9a\xd23\xddw1\xb6\xc2\x15@Tu\xfa\x17l\xe1_\x1e\xda\xcb\x1e-\x9f~\xc6j\rd\x80\x00RU\xae\xe7\xffx\x88\v\x1b_U\x8c\xad\x18h\x00Tu\xf9\xcc\xdb\u007f\xf8\xd7\x1f\xfe\xb7\xef\xfd\xf3\xbf\xfe\xcf\xfb\xafO\xbd\xf2\xf1\x8b\x9d\a_\x8a\xa9\xb3-\xb6\"\x01\x8e\x97e\x17T\xb6\x14\xa4\xfbO\xc7m\x00T\xf5\xf9\x99ݿ\xfc\xc1\xf7\xbf\xf7\xd0\x0f~\xf0\x8f\x9doM\xbd\U00047677\xfb3\xb6\u009a\xe6\xec\t\x1b\xb7\x96\x10\x82\xf7W\xe9\x1d\x00U}\xb1\xf4ܕ\x83\a\u007f\xf8\xfd\xb5\a\xffLWO\xff\xea\xc6W\xf4\xf6\xb7QU\xf6\xc6V\xf4\xcc՜\x8a{\x94\xde\x19\x85\xaa\xf6\x12\x88\xaaN\xfd\x8c-\xfc\xf0!6K\xed^^j:W\xb57\xb6\xa2g\x16\xfb\xfe\x1f\xffQ\x8f\xaa\xf6\x12\x88\xaa\x96^d\v\xa5\xffą]=\xdd\xecd\x95\x8d\xb1\x15\xcf\x10m\xe3\x82⬲\xb3T\xed\xb7\x96u\xb3\x95neߗ\xd1Q?\x13\x85\x97\xeb\xef)\xb9\x16\xcaj\x86\x1e\x90\xf8\x80T\xf5\x9a\xfe\xf0%ӋVl\x8c\xad\xf8\xcb\xd6L\x92W\xf7\xeb\x9c\nC\xbf\x97\x9e~\x94usk\xf7\x94\xca\xcb\xf7<\xe1\xbb\vR%\xd7BY\xcd\xd0\x03\x12\x1f\x88\xaa>\xfe\x8b\xe5\xcf?\xbf\xe6\xf7\xec\xdb\xf2\xc7\x1f1\xbb\xc0\xda\xd6\xd8\n-\xf7,[-ϸ\xdak\xc5\u2e52\xd7h\xbb2\xe5Pr-\x94\xd5\xd4E$>\x00U\xdd\xf6\U000d93d5J\x1e\xfb\xf9/\xae\x98\xa8jkl\x856\x87\xf2\x1b\xaf\x1bW;\xe2\xb9\xd7\xf1\xda\xf5.\xed\b}\x90\x19\x19U\x95\\\ve5u\x11\x89\x0f4U\x19w\xaf\\\xbc\xf8\xed\xb7\xd7\xee\xb2o\xdf^\x89\xcc\x05\x14l\x8d\xad\x10\xb9\x03B4e\xb5{\x99G\xebɲ\x13\x1e6?\r\xcdU\x1f4\x1br-\x94\xd5\xd4E$>\x00U\xa5\xe2R\xc05?\xbd\xe2\x8c؊\x88h\xeaj\xc5[\xfdS\x8a\x9b\xf84`\xb1Ot\xd3H.\xa9\xb9\x16\xa8j\xd2\x00T\xb5\xbb\xb3\xf3Fg\xe7O'\xef\xed\xbcq\xbf\xd3\xfcB\x15;c+\"\xa2\xa9\xab=]\xa35\x93g\xf8\xec\xf7jN\x05;\x98\v\xfa\x87\x1br-Pդ\x01\xa8\xaa\xe4\xf6\x95\x1e.\xa9\xb6/\xb6\xe2B@\xab\xda\x17<\\\xa5\xf1dJ}5JWf\xe5\x04G\xfbV\xf0\x92\xe6\xacI\xbfk*\xcb\xe43\a=\xd7BY\xcd\xd0\x03\x12\x1f\x98\xaavR\xba\xf6\u007f\x9f\xa1\xf1\xffɊm\xb1\x15\xcf\xf0t\x8a\xd6l\xf6\xfd\x19e5J\x0f\xe5\xd6\xd2U\xd9\xfbE\xe9\xf1\xb2\xac\xfc\x8aV\xbe\xa4\xe7Z(\xab\x19{@\xe2\x02Sջ\x94\xb2\t\x00\x8d\xff\x0fU\xfb9\xb6\x02\xe9\x03`\xaaJ-&\x00\xfd\x1d[\x81\xf4\x010U\xc5\x1b\x01\xb9\x10\x98\xaa⍀\\\bLU)\xde\b\xc8}\xc0T\x15'\x00.\x04\xa6\xaa8\x01p!0U\xa58\x01p\x1f0U\xc5\t\x80\v\x81\xa9*N\x00\\\bLU)N\x00\xdc\a\xaa\x8a\x00\x01\xa6\xaa8Wu!0UŹ\xaa\v\x81\xa9*\xc5\t\x80\xfb\x00\xa6*\xc6V\xb8\x17`\xaabl\x85{\x01\xa6*\xc6V\xb8\x17`\xaabl\x85{\x81\xa6*\xc6V\xb8\x16\x80\xaabl\x85;\x01\xa8*\xc6V\xb8\x13\x88\xaabl\x85+\x01\xa9j_\xc7V`@\x85\x13\x01\xa8j\x8a\xb1\x15I\x90r@\x05҇\x00T5\xb5؊\xe4H-\xa0\x02\xe9K\x00\xaa\x9aZlE\x92\xa4\x12P\x81\xf4)\x10UM)\xb6\"IR\t\xa8@\xfa\x14\x88\xaa\xa6\x14[A\xe9\xe9Y\xf9Z\xc1\x8cohb\xe9\x111\x01\x15\x94\xee,+\xd2\xf2g\f\x13\xf7HM8\xf8\x02I\x17 UM%\xb6\x82\xb6d\x8f[\xb5\xa3\x8e\xf0{\xfd%\x92\x1e\x11\x13PA\x0fdT\xbe\xbdcc>\xe1\xb7XK<\xf8\x02I\x17\x10UM)\xb6\xa2\xa3\xa8\xec\x1e\x1bo\x1b\xaf&\x98\x1e\x11\x1bP\xb1.\x8fK\xba.7\x98l\xf0\x05\x92\x16\x00\xaa\x9aZlE39\x1c~:\xa1\xf4\x88\u0600\x8a\xf3\x85\xc3k6\x1e\x0e\xf2<\xa1\xe4\x82/\x90\xb4\x00MU\x9ajlE=\xd1'\x8e\t\xa5G\x98\x04T\\\xdf0\xbb\x98\xe4\xaf\n&\x1b|\x81\xa4\x05\x80\xaaҔb+vD\ue35ePzDl@š\xc5l\xb5\xeb[}\xeb\x92\r\xbe@\xd2\x02@US\x8b\xad\xb8U\xe0\xe7o\xdd5\xf3\x13K\x8f0\t\xa8\xa8\x13\x93[\xea\xafN6\xf8\x02I\v\x00U\x95$\x1b[A[\xbc\x0foh\xae!\x9biB\xe9\x11\xb1\x01\x15L\xd5\xec\xda\x0f\x9a\xe6\x12>\x17M<\xf8\x02I\x170UM!\xb6\x82ғ\xb3\x87\x0e\x9a(\xaeC\xb1N\x8f0\t\xa8\xa0\xafM\xab+\xd2\n\xfc-\xe2A\xc2\xc1\x17H\xba\x80\xa9j_\xc7V`@\x85\x03\x81\xa9*\xed\xdb\xd8\n\f\xa8p\"0U\xc5\x1b\x01\xb9\x10\x98\xaa⍀\\\bLU)\xde\b\xc8}\xc0T\x15'\x00.\x04\xa6\xaa8\x01p!0U\xa58\x01p\x1f0U\xc5\t\x80\v\x81\xa9*N\x00\\\bLU)N\x00\xdc\aXU\x11\xb7\x01SU6I\xfdxm\xfc\xebU\x91\x81\bLUq\xae\xeaB`\xaaJq\xae\xea>`\xaa\x8a'\xab\\\bLUq\x02\xe0B`\xaaJq\x02\xe0>`\xaa\x8a\x13\x00\x17\x02SU\x9c\x00\xb8\x10\x98\xaaR\x9c\x00\xb8\x0f\x98\xaa\xca\t@w'\xed\xbeϿpxu\x030U\rM\x00\x107\x01SUF獞\x87R\x8c\xad\x18h\xc0T\x95_\x03\xf0\xd6\xfd\xbd/u\xee];\xee\x1e\\\x1bS\xd1/\xb1\x15Gg\xe4\xe7Lk)\x89\xbd[\x06\x92\x06`\xaa\xca\xef\xb2\xfa\x93\xef^\x9fy[|\xdd\xe8\xdf؊\x96\xf0-\x83\x0ei\xe5MoT\x10y\xbb*\xbdռ\x16I\x1a\x98\xaa2\xee~G\xaf\xfd5\xf4u\xe3\\ԓ\xb6\xc6VLx2\xb4P\xe6g\x03\xe6\xac֍\x00\x00\aLIDATy\xb0J\xaa\xaa\xb7\x9a\xd7\"I\x03SUq\x06\xe0J\xfc\xe7m\x8d\xad\xd0\xef\x048|\t\xff~\x944\x19Z\xcdk\x91\xa4\x81\xa9\xaa8\x03\xf0U\xf7\xdd8'\xabl\x8c\xadh\n\xdd\xf3\x97\xdf\x0e\xf8\xc9\x02\xfeW\x11\xdc~\xcb\xd0zsv\xa1VT~\x84\x1ak1\xd7\"i`\xaaJ{\xfe\b\xc0\xc6؊;\xbb\xc5M+\x03'Xc{\x91\xa7\xacn\x0f\xbf\x8b\xab\xda\xfa.\xa9ni,\xf7\xec7\xb6b\xaeE\xd2\xc0T\xd5\xe2\x1a\x00\x9bc+\xf47\xf5\xab+&h$\xb7\x91\x1aZ;\x1ao\xb11\xb4\xa4\xc2؊\xb9\x16I\x03SU\x8bk\x00l\x8e\xadP\xe7\x9f\xf7v\x94\x89\xbba+\xad\x97ו\x8d\xc8!r\x9bz+\xe6Z$\rLUi\xcf\x13\x00\x9bc+\xc2\xfa\xed\xe7\xf3`\x1a\x94\xddGZ\v\x8a\x165\x05\xfcQ\xaab\xaeE\xd2\xc0T\xd5b\x02`sl\x05\xd7o\xf3ה\x16\x88\xc4\n\xbad\x94\xa1\xb5x\"\xff\x1b\x99\xa5\xa8\xca[1\xd7\"i`\xaaju\x11\xa0\xad\xb1\x15~?\xa5\x97xC~\xe1U\xbe\xa6L\\\xd1[\x8b\xf8\xc3\xe0X\xa9\xaaފ\xb9\x16I\x03SUjq\x11\xa0}\xb1\x15\xbc]\xabo\xf2g\xb3?\x88|RP\xdb\xdc\xe4\xf7\x9d4\xb4֑\xd9\xebV\x8cg\x13\x87}j+\xe6Z$\rLU-\xff\x15\x80m\xb1\x15\x8c{5\x83}\xd3\xf6\xb3\x85\t\x9b\x97\x14g\xe7U\x9c4\xb6\x06\xebGkyOn\x1e\xa5\xf9\xd5V̵H\x1a\x98\xaaZM\x000\xb6b\x00\x02SUj\xf9\xaf\x000\xb6b\xc0\x01SU\xcb\t\x002\xf0\x80\xa9\xaa\xe5\x04\x00\x19x\xc0T\x95ZN\x00\x90\x01\aLUq\x02\xe0B`\xaa\x8a\x13\x00\x17\x02SU\x8a\x13\x00\xf7\x01SU\x9c\x00\xb8\x10\x98\xaa\xe2\x04\xc0\x85\xc0T\x95\xe2\x04\xc0}\xa0\xaa\b\x10`\xaa\x8asU\x17\x02SU\x9c\xab\xba\x10\x98\xaaR\x9c\x00\xb8\x0f\x98\xaa\xe2\x04\xc0\x85\xc0T\x15'\x00.\x04\xa6\xaa\x14'\x00\xee\x03\xa6\xaa8\x01p!0U\xc5\t\x80\v\x81\xa9*\xc5\t\x80\xfb\x80\xa9*\xc6V\xb8\x10\x98\xaabl\x85\v\x81\xa9*\xed\xdb\xd8\n\x10\xb8.[\x03\xac\xaa\a\xdf\xeb>\xf8\xdbN\xf9\xf5_\xbf\x8fy:\xb1؊\xe6\f\xe2\xd9G?\xf1\x10\xdfu\xabRA\xbdW\u07b5\xa5\x8a\x10\x92u*ܺ#\xaf\ai\x8exXm\xe4~\u007f=\xd6&E\xdcl\x8d\xf0N\x0e4`\xaa\xca\x06\xd4_L\xbe\xb1\x96}=¾\xae\xbd\xfe\xf3\xe8\x02=\xb6\xa2眈\x8e\xb7Ɏ\a\xb4cԄ\x04\xd3$J4y멳\x81\xc0\xba\xf0\xdd\x06)\xfd ;\xfaV\xac\n]\x9f\x8c-\t\x9c\xd7\x1f\x9a֦\x18f\x11'[#\xbc\x93ɑ\xe2>\xd8\bLU\xad\x88\xc4VX\xe4D\xb4\x93[\x94\xd6\x0e\x89\xa8\xd4#w<\x95\x9e\xf0\xfd\x01\xf7GT\xa5=\x8f\xdf\xfc\x96j\x11\xccjS\r\xb30\xcd\xd6Pw2\tR\xdd\a\xfb\x18\x98\xaaFb+,r\"\xb8\xaa͙-=\xd6Dh!\x87H\xb8VU\xb5g\x8c\xaa\x9a\x91j\x98\x85i\xb6\x86\xba\x93I\x90\xea>\xd8ǀT5\x1c[aȉ\xd0c+\x9e!\x99\rՅ\x83\xcb\xf9\\\x93\xa9ڞ\xbbB\xae\xa5\x04I\xe8\x8bj-\xa5uCiamh\x1baU\xaf\xfb\b\xf1\x88ۤ7\xb2-\xd5\xd1:\"\x82\xab\x94\xce\"\xaaFj\x95\f\f\xf30\vC\x8a\x86\xdez$\x93\x90\xa5\xa7*\x87\xfb\xca\xe4-\xb5L\xb25ԝ\x8c\x04u\xa8\x99\x1d&\xaf\xcd\xf8\x1fʡ\fHUñ\x15\x86\x9c\b=\xb6\x82\aT\f[\xb1bX\xd61\xaeꥒA\xf7\xe4ZJ\x90\x84\xbe\xa8\xd62\xe9f\xd1\xd9a\xef\xf4Q\xf5P \xe0\x15w\x1e\xbe\xb53g\xd9%z\xa96w\xe7-Cgʨ\xaa\xd7*\x19\x18\xe6a\x16\x86\x14\r\xbd\xb5\xa3q\xeb\xb0у\x8a\x16Tf|-z\x89\xcd\xd6PwR\t\xeaP\x16\xcd^\x9ba\x1f\x9cʀTU\x89\xad\x88\xa4GDb+\xa86\xfc&\x1b\xe2\x8a&rU\x9f\x1eU\xb0N\x14(A\x12j\xa6D\xa4\x96\x06\xb3\xebi}vh\xb2\xa9N\x00|\xa1\x9bd\xcf\xe3\xf3\xbdʟ\x19;\x8b\x9a\x00\x84j\x95\f\x8c8a\x16\x91\x14\rcH\x06\xf1ߤ\xc1\x9b\xb2>6[C\xd9I\xe5\x15+\x8bq^\x1bN\x00\xfa\a=\xb6B\xf9\r(\xb1\x15T\x1et\xad#W\x99\xaa\xbe㛇\x88_\xbc\x12$\xa1fJDj\xe9\x11\xb2\xbbc79\"\xfb0S\xb5\x85\xbd\x1fwd\xb5\x18;3WU\xc9\xc0\x88\x13f\x11I\xd10\x86dh_G:\x8b\xcd\xd6PvRy\xc5\xcab\x9c׆\xaa\xf6\x0f\xfb\"\x1a\xe9\xbf\x01%\xb6B\xdeJ\x9d\x06\xc8!\xa6\xeaV\xdaU,R\xfc\x94 \t5S\"RK\x1bDc\xe8\x04\x91\x99\xaa]\xf9M\xb4)?h\xec\xcc\\U%\x03#N\x98E\xe4~\xefƐ\fu>i\x92\xad\x11\xd9I\xe5\x15+\x8bq^\x1b\xaa\xda?Db+\"9\x11Jl\x05\xd5\xe6\xf3\xef\x1b\xc9My\xb2\xaa\xd9\xcbOV)A\x12j\xa6D\xa4\x96\xce\x1a\xb7\u007f\xff\xfeq\xb3d\x1ff\xaaҚ\nZ!\xb2+\xd4\x1e\xa4\xaa\xb7\x96]Uk\x95\f\x8c8a\x16\x11U\x8d!\x19\xb3h\x84\xd8l\re'\x95W\xac,\xc6ym\x91}p,\x03RU%\xb6BωPb+\xa8\x96\xcf~\xc3wF\xf8C\xe7U\x83\x93x\x82\x95\x12$\xa1fJDji\xe1B\xf6mA\xa1\xec\xd8T\xd5=\xde\v^q\xa0\xa3\xf6 U=Lv\xaa\xb5J\x06F\x9c0\x8b\x88\xaa\x86\x88\vu\xf43\xc9\xd6PvRy\xc5\xcab\x9c\xd7\x16\xd9\a\xc720U\x8d\xc4VDr\"\x94\xd8\n\x8d\x8ck\xdc<:\xf7$\xedh\xe2\x9fVѷ3\xb6\xdf3\x04I(\x8b\x91\xdaf\xb2\xe4\x0e\xbd\xf3+\xd2|\x8f\x9e\xe7\x9fV\xd5\a\x02l\x10z\xf0\t;\xaa\xaf\n\xec\x14\xf3\xdd`aY\xa1\xfc#\xd1{\xe8\xda3\xb6\x84\x1d[\a6\x90\x80Z\xabf`\x98\x85Y\x18R4\x94\xceđzx&\x1e\x9b\xad\xa1\xee\xa4\xfa\x8a\x95E\xb3\xd7f\xd8\a\xa720U\x8d\xc4V(9\x11\x91\xd8\nm\xe1ܜ\xc2\xca\v|\x88\xe1\xd7\x00\xd0i$\x83\x0f\x91J\x90DdQ\xafݑ\xc1O\x986\x11\x92\xb1\x83\xce\tM\xf8\xd8\x11\xff\x01\x8f\\\x94\xd1\x16\xf5Z}h\x0f\xc2=\x1c\r=O|'\xd4ZC\x06\x86I\x98\x851E#\xdczDv\x10\x1aKM\xb25ԝT_\xb1\xbah\xf2ڌ\xfb\xe0P\x06\xa8\xaa=\xc7VD\xa6\xb2\xd6$Sk/\xbd\xcf\xd6p\xeek3c\x80\xaa\xdaslE2\xbf\xa2djm%\r\xd9\x1a\x8e}m\xa6\fTU{$\x99_Q2\xb5Ѐ\xf5\xda\\\xa8\xea7\xe2\x88ŪJ\x92L-4\xa0\xbd6\x17\xaa*\x8eX\xdaiB$S\v\rh\xafͅ\xaa\"0AU\x11 \xa0\xaa\b\x10PU\x04\b\xa8*\x02\x04T\x15\x01\x02\xaa\x8a\x00\x01UE\x80\x80\xaa\"@@U\x11 \xa0\xaa\b\x10PU\x04\b\xa8*\x02\x04T\x15\x01\x02\xaa\x8a\x00\x01UE\x80\x80\xaa\"@@U\x11 \xa0\xaa\b\x10PU\x04\b\xa8*\x02\x04T\x15\x01\xc2\xff\amu\xa3\x1c\xa2\xebff\x00\x00\x00\x00IEND\xaeB`\x82",
+
+ "analysis/ipcg-pkg.png": "\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x02\xf0\x00\x00\x03\xc6\b\x03\x00\x00\x00\xb2,^L\x00\x00\x00\x01sRGB\x00\xae\xce\x1c\xe9\x00\x00\x02\xfdPLTE\x02\x04\x00\t\v\a\r\x0f\f\x10\x12\x0f\x13\x15\x12\x1b\x1d\x1a !\x1f!#!$%#&(&+-*/1.2416859:8<=;>@=AB@DFCFHEJKIOQNQSPTVSWYV,`\xae7]\xad8^\xae[]Z8a\xaa:b\xab;b\xac_`^<c\xad=d\xae?e\xaf@g\xb1Bh\xb3egdDi\xb4Ck\xafFk\xb6Lj\xafhjgNk\xb1Fn\xb2Ho\xb4Pm\xb2kmjIp\xb5Kr\xb6nomMs\xb8Nt\xb9Ou\xbaPv\xbbrtqXv\xb6Yx\xb8vwuZy\xb9[z\xbaxyw]{\xbbV~\xbd_}\xbeY\x80\xbf`\x81\xbbb\x80\xc0[\x82\xc1~\x80}b\x83\xbdc\x84\xbe\x81\x83\x80e\x85\xc0g\x87\u0084\x86\x83\x85\x87\x84i\x89Æ\x88\x85j\x8aŇ\x89\x86\x88\x8a\x87q\x8c\xc1\x89\x8b\x88s\x8eË\x8d\x8at\x8f\xc4v\x90ō\x8f\x8cw\x91Ǐ\x91\x8eq\x94\xc9y\x93ɑ\x93\x90z\x94ʀ\x94Ł\x95Ɠ\x95\x92{\x98ǂ\x96ǃ\x98ɖ\x98\x95\u007f\x9cˆ\x9a˘\x9a\x97\x80\x9d͈\x9d\u0382\x9fϜ\x9e\x9a\x88\xa0˄\xa1ў\xa0\x9d\x8a\xa2̋\xa3Ρ\xa3\xa0\x8d\xa5ώ\xa6я\xa7Ҥ\xa6\xa3\x90\xa8ӑ\xa9ԧ\xa9\xa5\x92\xabՔ\xac֩\xab\xa8\x98\xacѪ\xac\xa9\x9a\xadӛ\xafԭ\xaf\xab\xae\xb0\xad\x9d\xb1֘\xb4ذ\xb2\xaf\x9f\xb3ء\xb4ڲ\xb4\xb1\xb3\xb5\xb2\xa2\xb6ܣ\xb7ݝ\xb9ݵ\xb7\xb4\xa9\xb8ٶ\xb8\xb5\xa3\xbb٫\xbaڸ\xba\xb7\xac\xbbۦ\xbdܹ\xbb\xb8\xad\xbcܮ\xbdݯ\xbeߩ\xc1\u07fd\xbf\xbb\xb0\xc0\xe0\xab\xc2\xe1\xb2\xc1\xe2\xbf\xc1\xbe\xad\xc4\xe3\xb7\xc2\xdd\xc1ÿ\xb2\xc5\xde\xc2\xc4\xc1\xb9\xc4\xdf\xc3\xc5º\xc5\xe0\xb4\xc7\xe0\xbb\xc7\xe2\xb6\xc9\xe3\xbc\xc8\xe3\xc6\xc9ſ\xca\xe5\xb9\xcd\xe6\xc9\xcc\xc8\xc1\xcc\xe7\xc2\xcd\xe9\xbc\xcf\xe9\xbf\xcf\xe2\xcd\xcf\xcc\xc7\xcf\xe4\xc8\xd0\xe6\xc2\xd2\xe6\xca\xd1\xe7\xcb\xd3\xe9\xc6\xd5\xe9\xd2\xd4\xd1\xce\xd6\xeb\xc9\xd9\xed\xd5\xd8\xd4\xd0\xd8\xed\xcb\xdb\xee\xd4\xd9\xe9\xd8\xda\xd6\xcc\xdc\xf0\xd6\xda\xea\xd7\xdb\xeb\xda\xdc\xd9\xd1\xdd\xeb\xd8\xdc\xec\xd9\xdd\xed\xdc\xdf\xdb\xd4\xe0\xee\xdb\xdf\xef\xde\xe0\xdd\xdd\xe1\xf1\xe0\xe2\xdf\xd7\xe3\xf1\xd9\xe5\xf4\xdf\xe4\xf4\xe3\xe5\xe2\xde\xe6\xef\xe5\xe7\xe4\xdc\xe8\xf6\xdd\xe9\xf7\xe6\xe7\xf1\xe0\xe9\xf1\xe7\xe9\xe6\xe8\xea\xe7\xe2\xeb\xf3\xe9\xeb\xe8\xe3\xec\xf4\xeb\xed\xea\xe5\xee\xf6\xec\xed\xf7\xe7\xef\xf8\xed\xef\xeb\xe8\xf0\xf9\xee\xf0\xed\xf0\xf0\xfb\xf0\xf2\xef\xee\xf3\xf6\xf1\xf3\xf0\xf4\xf2\xf6\xf2\xf4\xf1\xef\xf5\xf7\xf0\xf6\xf8\xf4\xf6\xf3\xf2\xf7\xf9\xf3\xf8\xfb\xf6\xf8\xf4\xf7\xf9\xf6\xf5\xfa\xfd\xf8\xfa\xf7\xf6\xfb\xfe\xf9\xfb\xf8\xfa\xfc\xf9\xfd\xfb\xff\xf7\xfd\xff\xfb\xfd\xfa\xf8\xfe\xff\xf9\xff\xff\xfc\xff\xfb\xfe\xff\xfc\x9fIc\x17\x00\x00 \x00IDATx^\xed\xbd\vlT\xe7\x9d\xff\x9dn\xbb\u007f\x92\xf4\xbe\xffM[\x1e\a\x9d\xe0\x91c\xaf\x16\xd9kհuJ\x9b8\xf0&\u0080\x18\xe3\x80l(\xb7֊X\x87\xb0\x15\x97\x10\x93FXd^BH߄\x05\x8aCK\x92%\x1b\xe3\xd5\xca.V\xc1ZHF@P$\xccE\xa4)I\x1b\xc0\t!\\\x82\x13\b66c\xec\x91~z\xcfs\xce\\\xce̜\xb9ٞ\xe7\xfc\xec\xf9~\x82f\x9e9\xf3\x9ccW\xfd\xcc\xf1\xf7\x9c\x999\xdf;\b\x80,\xe2\x8ed\x13\x00\x18M@x\x90U@x\x90U@x\x90U@x\x90U@x\x90U@x\x90U@x\x90U@x\x90U@x\x90U@x\x90U$\x12\xbe\x03\x80\xd1\x06\x84\aY\x05\x84\aY\x05\x84\aY\x05\x84\aY\x05\x84\aY\x05\x84\aY\x05\x84\aY\x05\x84\aYEj\xc2\xe7\n!\xfe\xdfx\x9b\xf8\xf3\x9f\xe2=\x93\x16%\xfa\xcf\xf8\xafd\x93\"\b\xae\x91\xfe\x9aI\x90\x1b\xfc\xefd\x93\xc0\x88d\xc8\u009f\xd98\xe1i\xfbg\xd2$}m!<H\x9b\xa1\n\xff\xa72! <\x181\fU\xf89\x02\u0083\x11\x04\x84\xb7\x01\u008f^ \xbc\rq\x84?\xfa\xefQ\xe0E1\xf2HO\xf8B!r;\xfeZ\xffP^\xee\x03\xab\xfe\xac?\xae\x15\x01^\x95\xb3\x8e\xfe\xfb\x03\xae\xf1\xc5U\x01\xf7\xfe\xaa/\xfeYG}\xb1V0\xe7L̊:g\xfe\xc3]8>\xc75\xf1\x17\u007f4\x1f\xc7j\xfb\xd7\x17\xdd\x05Zn\xc9/\xfe\xa7#\xf1\x1a\xb1k\x1e\xae-\x19\x9f_\xfej\xc73\xfa3\x9e\xa8_%f3\x9a\x10\x85\x1dG\x97M\xd4\xd7\xf8}x\xc3\xff\xfd7\xcfC\xae\xdc\xc9O\xbfo\xd9\xec\x83\"\x02\xedp\a\x18i\xa4/\xfc\xe1\u007f5\xff\xef.>\x1c%\xfc+\xae\xc0\x03\xb7\xa1\xb4a\xd9*\xf9\xb8<vŎ\x8e??\x1c\x12g\x85\xf13b\xb4}\xeb_\x83\x13~\xf5\xb7\x84kĬ\xf9jn`\xbd:\x11\x16>\xf8\xab\xc4lF\n\xff?\xf9撪\xbf\x067\xbc\xad\xcc\\2\xe9\x84e\xbb\"\x82E\x1d`đ\xb6\xf0Zq\xf0\xffow\xa4\xf0\xaf\x8e\r\x99\xf0\xa8\xbe\x1f5,\xcb3\x96=\x1f\xbbbGG\x95\b\xf3\x9frA\xb4\xb6\x87\xf3\xc3\x13j\x13\xae\x11\xbd\xe6\x1f\xb5\xe0\xb4\t\"$|\xe8W\x89ٌ>;//\xb8dAp\xc3\xc1W\xaf\x98g\xd9\xf2\xcf,\xebb\a?\"I[x}w\xe8\xf9\xe3\x169\x18\xf7玷^\x9d\xaa\x0f~\xf1\xea\xab':\xfe,\xfd|h\xdb\x1f\u007f#\xdd\xd1%3,\xd3'=T\x92s\"vŎ\xff\x95\xf7\xab\xff\xf8\xa7\x8dr\xb5_ɟ\x11\xad\xedt\xfd\xf1\xf8e\xafnyT\xbf\xcfy+\xd1\x1a\xd1k> \xd7\\\xf5\xc7\xff2\xd5\xf6D\xfe*\xb1\x9b1^\x1e\xf9O\xbf\xea1^\x91\xc1\r\x8a\xe2\x8d\u007f\xfa\xddD\xb9%K\xa8\x89\xd8\xc5\xff\xa2\x03\x8c<\xd2\x17>O\xee\xd8\xfe(\xff\x1f\x97ﰆ\x0eZ\xeb\xf5\xc1\x032\x10\xfcQߕN\xec\bX\x96\xab\xcf\xd9k\xb7\xe2\x9f~55\xcfH\x14\x1ea\x04\x8d\x18m\xdf\n\xda\xf7\xb7\x87\xf4\xc1\xb2DkD\xad\xf9?rM#\x8d\xd7ȑ'\xf2W\x89\u074c\x16\xfc\xddNH\xe3݁\r\xe6\x1d\r\xfe\x12\xd67\x92-\xbbx\xec\xe0G$\xe9\v\xff\xefƒ\xbc\x80d!\xe1˅\x11\x18t\xa4\xa0o\x05,\xfbU`\x03\xb1+\xea\xc8\xe0\xd3\xf1\xbc\xfe\xb8L\x0e\xa2\xb4\x95Ǜ\x0f\x19\xa3\xffz\xea\xf7A\xb7\xec\u05c8Zs\xb5\xfep\xb21\xfa\xf3x\x11\x16>\xf8\xab\xc4lF\n\xff\x94\xb1|\xa3>r\x9d17h\xa4\xa8\x8e\t\x91\x9b\xee\xf8\xbd\b\x81\x04?\"I_\xf8\xff0\x96H'\xe4\x91jHx)re\xadD\xe6\x80\xdf\x05,\xfb]`\x03\xb1+\xea\xbc\xff\xdf\xf5s\xfeI\xcez(\xf8\x84ŭ\xaa\x90t\x16\xec\u05c8Z\xb32\xbc\xa6<>\xf5D\xfd*1\x9b\x91\u009b'l\x0e\xcbe\x87\xcd\r\x9a\xbf\xed\xc4\xf0ok2Y\x04\x18\x87\x1d\xfc\x88$}\xe1M\xb5\xfeUD\n\xff7\x11A}\xc0\xb2\xc0\x99?\x9b\x15;~W\x1e:\xb6|X>\x8e\xd2V\xfe\xc5X\xd5\x11A\xbc5l\xd6\f\xbc5\xe0\x16aჿJ\xccf\xe4#\xd3^\xe3\u007fğ\xac/\xca\aD\x94\xf0\xbf\x0f\xae\xfa\x8b\x0e0\x12I_x\xf3ݖ\xa0\tA\xe1\xff*\"x:\xb0\xe4\xad\xc0\x06bV<Si\xcc+\xf9\x85<\xd1\x13O\xf8\u007f\xef\xb0\x10\u007f\x8d\xa85\xe5Q\xeejsh\x15\xfe\xadx\x9b\xd1BO\x1a\xf3\xf6\x9a\x1b\x8c\xfc\x9f\x19&\xb0\x8b\x1f\xf7V\a\x18\x89\f\x97\xf0Ɣ\x88w\x1e\r{\x82\u007f\xf7cV\x94Ǹ\xf9\x1bOtt\xfc\xa7>\xf8\u007f\xe4\x13Q\xda\xce\x13\xc1\xbd\xe8\xfbo\x19\xa7\xe1\xe3\xafa\x13i\x02\x81]\x1ecz\"\u007f\x95\xd8\xcdH\xe1\x8d\xf3\x93\x11\x91&\x9e\xf0\xbf\x17\x06\v:\xc0\x88d8\x847\x8e\xf8\xe4\xa1j\xbd\xf1\xd4\u007f\x9bj%\x16^\xaah\xc4\xe4\xff\xd0\a\x8fʁ\xcdAk\xa1qt\xf9[1\xfe\x81\xdaDkD\xad\xb9J\u007fXl\xacyX\x9e{\x8f\x12>v3Rx\xf3\x05\xf2\xa2>\xca\xefH,\xbc\xb9\x8b\xc7\x0e~\xa42T\xe1\xe7\x89@\xf2\x90\xe7F\xfeI\xbe\xc5\xfaG!\\\x0f\x1f\rXv4\xb0\x81\x98\x15\xf3\x83&UF\xeb\x1b\xe0-\xb9\xfao\xf4\xc1_'\x9bB\xc6_#jM\xe3\xcc\xe73\xfa\xe0}\x19\x8bB\xc2\a~\x95\xd8\xcdH\xe15\x99\xf0\xff,7TՑD\xf8W\xe4\xc6~\xd1\x01F&C\x15\xfeW\xfa}ު_\xfdw\xc7Q9g\xf2\u007f\x1e\xfe}a@\xa4\xc4\xc2˻\u007f}\xab\xe3\xf0/\xe4,\xbb\xb34\xc6\x1bO\xc2\xedyZ\xce\x14\xff\x9bh\x8d\xe85\x8d\x8f\xbc\xcc\xd9Xo~4!J\xf8\xd8\xcd\x18\x87\xb0\xe3\x97m\xab\x97\xdb1\x8em\x13\n\u007f\xe6\x01\xf3\x8d00\"\x19\xaa\xf0\x1e\x11\xb4j\xa3\b\xe1\x92>$\x16\xfe\x19c\xe2xs~\xb1|\"Z[\xebG\v\x96u$Z#z\xcd?\x05&\x89q\x05\"F\xf8\xd8\xcdH\xe1s\x83?\xe9W\xc1\r\xc7\x15^\xa6\xf8_t\x80\x11\xcaP\x85?a~\nE\x1a\xe9\tZS`\x9c\x01L,\xfc_\xa7\x9bssV\xffk`Z\xb4\xb6\x1doM\nlO\xd4\x1a\x9f͉\xbbF̚\xaf\x98\xbf\x89\xf6[\xb9\xca\xf3\x91\xbfJ\xecf\xa4\U0002f598K\x17\x19\xc7lj\x85?\xf3\x00v\xf0#\x97\xa1\n\xdf\xf1VU\xbe\xf6O\xe5\xc6\xf0\xf0\x8a\x9f\xe5\x8f\xcb{\xe8i\xf3\U000ff245\xef8\xe3yȥ\x15\xff\xea-\xe3\x03hu\x1d6\xdav\xfcu\xe3\xf4\u007f\xd2r'\xfe*\xf0\xde~\xdc5b\xd7|\xebW\xc5\xda?\xcd\xfb_#\x16\xfd\u007fQ\xbfJ\xccf\x8cӒ\u007f\xfe\xf7\x12-\u007fz\xc0\xed\xc4\xc2w\xfc\xce\xfay20\xb2HM\xf8\x11\xc5\xdf\xfe\x16\x1a\xcawZ\xff3\xc1T\x83\xf0y\xf8\x149s\xb4\x03\x8cTF\xa1\xf0\u007f\xcc)x\xa8r\x9b\x1c\xfdY此\x1f\x01H[x0\x82\x19\x85\u009f\xc8\x11\xf2\xbd\xa5?\xfd\xe9?\xe4{\x03\x0f$\x9b\x0e\u1ccaQ(\xbc\xf1\xde@\x88\xdf'\x9b\r\u1cca\xd1(\xfc\x9f\xcbC\xba\x8f\xfbM\xb2\xc9\x10>\xbb\x18\x8d\xc2wt\xbc\xfa\x8b\a\xf24-\xff\xa1e\xa9\x88\f\u1cc9\xd1)<\x00q\x80\xf0 \xab\x80\xf0 \xab\x80\xf0 \xab\x80\xf0 \xabH$<\x00\xa3\x0e\b\x0f\xb2\n\b\x0f\xb2\n\b\x0f\xb2\n\b\x0f\xb2\n\b\x0f\xb2\n\b\x0f\xb2\n\b\x0f\xb2\n\b\x0f\xb2\n\b\x0f\xb2\n\b\x0f\xb2\n\b\x0f\xb2\n\b\x0f\xb2\n\b\x0f\xb2\n\b\x0f\xb2\n\b\x0f\xb2\n\b\x0f\xb2\n\b\x0f\xb2\n\b\x0f\xb2\n\b\x0f\xb2\n\b\x0f\xb2\n\b\x0f\xb2\n\b\x0f\xb2\n\b\x0f\xb2\n\b\x0f\xb2\n\b\x0f\xb2\n\b\x0f\xb2\n\b\x0f\xb2\n\b\x0f\xb2\n\b\x0f\xb2\n5\xc2_\xbe\xfcygw\xe4\xa2\xee\xce\xcb_}9`?\x1d\x80L\xa1F\xf80\a\xb7w\x124\a\x8e\xa1T\xf8>\xa2Ms?\x96w\x008\x83R\xe1I&\x19\xec߁\x83(\x14\xbe\xaf\xcf\xd7\xd7w|ϗ\xfa\xdd\x00\xac\aΠPx\x83\x97\x1e\xbb\x98l\n\x00\x99C\xb5\xf0\x03\x9d\xc9f\x00\x90A\x14\t\xafG\x98\xd3{\xfe\xb0}\xeb\xe67\x9b\xb7oݺ\xbdy\xdf\xcddk\x00\x90\t\x14\t\xdfG\xb4}\xfe\xac\x99\xd3fL\x93̜_q\x11\xe7j\x80\x13\xa8\x13~ô\x83\xa7\xdf;\xfd\x9e\xce\xe9\xd3k\xa6\x9d\x83\xf0\xc0\t\x14\n?\xbb7\xf4pk\xc59\xf2\x11\x9c\a\xcaQ(\xfc̳\xa1G\x1bf\x9eK4\x1b\x80L\xa1P\xf8\x19!\xe1i}X~\x00T\xa2N\xf8\xf5s\xbb\xf7\xfc\xf8\xc7?\xd1\xff\xab\xe8{}\xe6\xe7G\xb6\xfb\x8eoU\U0007969f\x8e\x193\xe6\xee\xe3\xc9f\x81,A\x9d\xf0\xeb\xaai\xcd\u05fe\xf6w\xfa\u007f\xdf\xf25\xcf\xe8~cn\xf7\xeeY6\x87\xae\x9d\t\xc2\xce\xee\xb7\xe3?\x17\x97\x0f\x9b\x9bW\x8e\xd9c\f\xcf\xe1M\x80\xacG\x9d\xf0\x1bf_\xbeؼgߞ}\xcd\ai\U000cc2dd\xa7\a:?\xf4E\xcf\x1bX\xfb\xcd\xfb\xec\xd67\xf9\xc1\x8f\xe3?\x97\x88}\x01\xe1\xef\xfb\xe6\xda\xcc\xffE\x01\xacQ'\xfc\v3N\a\x1f\r\xc4\xcb\xf0\a\u007f0\xe6\xfe\x0fm\x9f1\xb8\xe7_\xe2?\x97\x88\xa0\xf0g\xef\x1f\U000c30c9\xa7\x82Q\x8e:\xe17̺h&v\xfdfӌs\xd4\x1bsZ\xb2sƝ\xdf\xddn\x0e\xd7\xfd\xf0\xee\u007f\x98\xd1Mt\xe4\xce1c\xee\xa7\xef\x8d\x19\xf3\xcdޭcL\ue258pP\x9f0\xf7\xf8O\xbew\xf7}\xbeG\xc6ܹv\xda?\xdc}\x9f|\xc5t\xfe\xcbw\xee\xfa\xee\xfd\a\x03\x1b\x0e\nO\xb4\xfd\xbbwNC\xae\xc9f\x14\n?;\xfc\x9d\xa7\xcd\x156\xe9}\xf3w\xee\x9c\xfd\x959\xfc\xf9\x9d\x8fl_\xf9\xed{\xfa\xa8o\xcf\xc2;\xf7к;\xd7\x1d\xa4\xaf\x9a\x9b\xff\xe1G\xcd\xcd\xcd\xc7#&\xdcܰ\xfe{\xff\xf0\xcd\xefM\xfbɝ\xa7\x8f\xac\xbfs̷\x17>\xf9\xcd\u007f֟\xdf>\xe6\xe7\xbb7\xdc\u007f\xe7>ssa\xe1\xe9\xab\xd9w~{S\xf4O\x06كB\xe1\xab\xd7m~a\x93\xce\v\x9b6\xff\xf2\x91د\x81<2枃\x81\xe1\xf61ϒ\xd4\xf49\xf9\xe0\xa7?\xbc\xf8\xbd\xc7\xcd\xe5\xa1H\x131\xe1\x9e1\xf7\xe9;m\xb9\u07fe\xeb\x9b\xfa\xde\xfd'\xdf\xd6G\xdd\x1b\xbe\x94\xcf\xfc\xb39\xdd\"\xbc\xfe7\xe1\x9e1\xd3\bd+\xea\x84o~\xfc\xb1\x8a\x19&\x15\x8f?\xf9y\x8c\xf0\xcf\xde\xf5\xadu\x81\u13ff\xef\x93|\xf7\xa7\xf2\xc1\xcd{\xbe}\u007f`yH\xf8\x88\t\xf7\xdc\x15<8\xb8K>\x9e\u007f\x97\x1c^\\s\xdf\xf7\xbf\x19\x88?\x91¯\xfb\xd6\xddk\td+\x8a\x84\xd7\xe9\xbex6\xc4\xc5\xcb6gK\x8e\xdf7\xe6\x87\a\x8d\xd1=\x81\xb8n\xee\xa07\x8di\x0e\xcc\b\t\x1f1\xe1\x9e\x1f\x04\xb7p\xd7|\xfdf\xa1\x14~߷\xbf;\xeb\xa5\xe6{c\x85?\xf2\xc31\xf7\x87\x0e\x9eA\xf6\xa1N\xf8\x14x\xe9;wΒQ\xe4'\xdf\u007f\xdb\xc0\xf8\xae\xc8\xd9\xef\xcc\xfd\xdee\xf3yC\xf8gOGM\b\x9f\xbb\xb9k!\x05\x84\xff\xbf?\x94\a\f\xff\x12-\xbc\x9e\xe0\x83\x87\xc5 ;Q(\xfc\xc0@_\x90\x818\x1f\x1b\xeb\x9cq\xe7w^'z}\xcc\x06\xf9h\xae\x8c\xee\xbe\x1fV\xd3\xcf\xef3\xe7\xdf{/\xd1\xc7\xf29\xeb\x04[\xe1\xbf+\x97\xf5\xdd\x13%\xfc\x9b\u07fds\xd6W\x04\xb2\x19\x85§\xc4\xc1\x1fIUg\xdf\xf9\xe3\x176\xfft\xccz\xba\xd9\xfcȷ?\xa4\xf7\xbe9\xadY~\xd4r\xfe]On\xbe\xef\xee\xb3\xd6\t\xbe=ƹ\x9b\xf7\xf4eg\x9b\xef\xfc\xe9\x1ez\xfb\xa7w6\x9f\xa5\x85c\xfee\xcd\xe3\xf7\x8c\xf9ֿ\xed\xd1\x177\xaf\x1c\xf3\xeb\xe6f\xfd\x0fÿ\xfc\xe8`\xc2\x1f\x0eF?܄\x0f\xf0\xfa\xbd\xdf\xfa\xe6\x8f\xfe w\xe5c\xc6L\xa3Gƌ\xb9s\xb7\xbe\xb4\xf7\x91o\xdd\xfd\xa3}\x11\x13\xe4y\xf81\xf2\\\xbd<ͣO;r\xb7~\xfb\b\xf5\xfd\xfa\x1f\xee\xfa\xf6\x8f\x9f\xfd\xfe]\xf7\x1a\x9f\xa5\x91\f\xf2]Z0\xba`*<\x00\x99\x01\u0083\xac\x02\u0083\xac\x02\u0083\xac\x02\u0083\xac\x02\u0083\xac\x02\u0083\xac\x02\u0083\xac\x02\u0083\xac\x02\u0083\xac\x02\u0083\xac\x02\u0083\xac\x02\u0083\xac\x82\x8b\xf0\xbe\xa8VK\x002\x02\v\xe1\a\x88\x8e\xbc\xf1\xa5\x82\xcb\ue06c\x87\x85\xf0}D\x9b\xabQg\t\x14\xc0BxB\xa4\x01\x8apV\xf8=\xbe\xce^\x9fQgy\xf0\xcdNy\xd7G}\xbd\xbd\xbeps\x02\x00Ë\xb3\xc2\x1f!\xe3r\xaa\xb2\xa1{6Jp\x80\x02\x9c\x15>|\xf5\xe0\xces1W\x12\x06`\xf8qVxyb\xe6\xf8\xeeM\x1b\x9e[\xff\xec\xda\xf5ϭ\xdf\xf0zs7\xceՀL\xe2\xb0\xf0z\x8aٺp\xf6c\xb3fUϟ=k\xd6c\xd53Pg\t2\x8a\xf3\xc2o\x98v\xe4\xfc\xd9\xf37\xe9\xf2\xd9\xf3\xe7\x9fE\x9d%\xc8,\f\x84\xaf\x90\xad\xdc\xfbVʇ[+\xce\r\xc4^7\x1e\x80a\xc3y\xe1_\x98)\x1b\f~t\xc7A\xfd\xd1s\xa8\xb3\x04\x99\xc5y\xe1\xcd\xfe\xd6\xfb\uf437\xa8\xb3\x04\x19\xc6y\xe1\xd7\xcf\xed\xde}\u07fdw\u007f\xed\a\xf7\xfd\xbc\xef\x8d\x19\x9d\a7\xf8\x8eo\x8e\x9a\xb5e\xfco\xe5\xddr\x91\xd3d\xb3\r\x00R\xc7y\xe1\xd7U\x0f\xac\xfd\xc6\xd7\xff\xee\x8eo|\xe3;\xb2\xcerwu\xf7\x9e_F\xcd*\xd3\xca\xe4\xdd\x05\xaf\xe6\xb1\xd9\x06\x00\xa9\xe3\xbc\xf0\x1b*.v\x1e?~\xef\u05f7\x1f\u007f\x8f^\x9ay\xbe\xfb<u_\x8e\x9cԕS\x93\xd3e\x8c <\x18\"\xce\vo\xd6Y\xde+3\xfc\xc0\xfaYv\x19\xde+\x8e\x89\x03\xc6\b\u0083!\xe2\xbc\xf0\x1bf\xc9\x1d\xfa\xac\xefI\xed7ʹ;-\xe9)\xa6b\xd3tm\xc5\x13\xc5\xf9Ug\xe4\xd0[Y\xa2\x15\xcd)\xf1\x13\x00i\xc0@\xf8\x8a/C\x0fm\xeb,ɽ\x88\x16\xbb\x8d\x91&\xa645\x96\xb9N\x11\x1d\x1d\xbb\xb4e\xff\xce\"q;f6\x00\t` \xfc\xfc5\xeb\x9f]\xb7\xf5\xf5\xe7\x9e]\xb7~\xbeM\x9d%\xf9][\xe8e\x97\xb1+\xd7&\xf7\x10\xf5\x94\x96\x135\x14H\xd5\x1b\xf2\xb1\x87\ai\xe1\xbc\xf0{\x9e\xac\x9e;{vEE\xc5\xec\xd9s\x9f\\\xd9\x19+\xfcIq\xa8\xe7\x908)\x87\xda3\xf2v\x87\xb8F\x9f\x15O\\\xb1\xf3\x84\xbf?z2\x00\tqXx\x9d\xde\xce\xcb:_\xf5~\xae\xdfv\xdaU\x8em\x13\x92mrh\x1e\xb4\xea\a\xb1D\xd7w,\x9e,\x8a6b\x0f\x0f\xd2\xc2y\xe1\xc9\xf8\x90\xf0\xe6\xc7;\xe3}0xє\xf6\xf6\xf6)\x8b\xe4P[%ow\x8a\x1b\xd4^\xa7\xab~\xbd1\xb7\xc1~\x1d\x00\xecq^\xf8\x01\x9f\xaf\xdb\xe7{|\xda\x11_w\x9f\xcf\xeeccū\xf5\x9bU\xc5r\xa8\x15\xdf\"\xea\u007fP?\x82\xf5\x886\xb9\xc0\xbd\xccf\x05\x00\xe2\xe2\xbc\xf0&ݝq\xf6\xef=m\xa2\xbe\x8b\xba~#\xdanɳ4\x95\x87\xf7\x97\xe7\u007f$\x85wշ\xb6\xd4\x06\xce\xcf\x03\x90\",\x84\xf7\x11m\u007f\xf2,\xd9~\xc9o\xffX!\x9a\xa8E\x88\xb1\xfb\x89\x1e\xf4,\xce+\xae\xb9\xa4/\xde5\xddS\xa2\x15\xba\xe1;H\x0f\x16\xc2\xf7\x12鑆p\xb1\x02\x90qX\bO\t\"\r\x00\xc3\t\v\xe1q\xa9=\xa0\n\x16\xc2\xe3R{@\x15,\x84'\\j\x0f(\x82\x85\xf0\x884@\x15,\x84G\xa4\x01\xaa`!<!\xd2\x00E\xb0\x10\x1e\x91\x06\xa8\x82\x85\xf0\x884@\x15,\x84'D\x1a\xa0\b\b\x0f\xb2\n\x16\xc2#\xc3\x03U\xb0\x10\x1e\x19\x1e\xa8\x82\x85\xf0\x84H\x03\x14\xe1\xac\xf0(5\x03\x8aqVx\x94\x9a\x01\xc58+<J̀b\x9c\x15\x1e\xa5f@1\x0e\v\x8fR3\xa0\x16\xe7\x85G\xa9\x19P\b\x03\xe1Qj\x06\xd4\xe1\xbc\xf0(5\x03\nq^x\x94\x9a\x01\x858/|\x92R\xb3F\xe3R\xaa\x13\xe6}\x12o\x13\x00\xa4\x81\xf3\xc2')5\xebj\x15\xbf\xf1zw\x95M\xf8\"\xeeF\x00H\x19\xe7\x85OVjvI4\xea\xb7WsQ\xef\x04\x86\x01\xe7\x85OVjf\nOeKb\x9e\x01 m\x9c\x17>Y\xa9\x99)\xfc\x95\xf1\xcf\x13\xddX\\\xac\x95T\x19] \xd6R3\xff\xaer\xd7\x03\xab{b6\x0e@\f\f\x84ORjvI\xec\xec\xb9\xf1N\xd9\xcfn\x10\xb5\x8ae\a\x9a\xaar\xda)\xb2Ԭ6g\xc5\xdem\x05SQ\x06\x02\x92\xc3@\xf8$\xa5f\x97\x8c\xd34\xa5\x17\xf4aOS\x97\xbe?/\x9bG\x11\xa5f\xadb\x97>l7\x93\x0f\x00\tq^\xf8d\xa5f\x97D}{{\xdb\x13\x13\x8e\xea\xe3\xab\r\x95\x93\xf2\x84졷\x94\x9a-\x99\xd4\u007f[\xa7\xb86v\xf3\x00D\xe1\xb0\xf0\x94\xbc\xd4,pк\xa4\xd4O\xed\x85%O\xb7x\xddRxK\xa9Y\x990\x99\x17\xbb.\x00Q8/<%)5\v\b\xff\x9a\xb8J\x93\xcb\xe5\x91\xe9\")\xbc\xa5Ԭf\xd21\x83\xab\xb6\xab\x03`\xc5yᓕ\x9a\x05\x84_\x9a\xe7\xa7\x12Y\xe5\xe7\u007fX\no)5k\x13MrX\xbf1v]\x00\xa2p^x\x93\xb8\r \xe6;\xad-5\xe2Ei\xf9\xe2\x86秊\xa2\x17ߍ(5\xab\x1b[Ӣ\x0fw\xd9o\x00\x00\v,\x84OTjf~\x96F+۩G\x18\xff\x96R\xad`\xc9k\xa5\x9a;\xb2Ԭ\xcd=!\u007fz\x9b\xdd\xda\x00D\xc2Bx\x94\x9a\x01U\xb0\x10\x9ePj\x06\x14\xc1Bx\\j\x0f\xa8\x82\x85\xf0\xb8\xd4\x1eP\x05\v\xe1\t\x97\xda\x03\x8a`!<\"\rP\x05\v\xe1\x11i\x80*X\bO\x884@\x11,\x84G\xa4\x01\xaa`!<\"\rP\x05\v\xe1\t\x91\x06(\x02\u0083\xac\x82\x85\xf0\xc8\xf0@\x15,\x84G\x86\a\xaa`!<!\xd2\x00E8+<J̀b\x9c\x15\x1e\xa5f@1\xce\n\x8fR3\xa0\x18g\x85G\xa9\x19P\x8c\xc3£\xd4\f\xa8\xc5y\xe1Qj\x06\x14\xc2@x\x94\x9a\x01u8/<J̀B\x9c\x17\x1e\xa5f@!\xce\v\x9f\xa4\xd4L\xe7T\xa5\xab\xb0\xe6@\xe1\x15\xaa\x15B\xb8\xce\xd8o\t\x80Tp^\xf8$\xa5fDm\xaeGw6\x96\t\xf1\x01]\xf0z\x1b\xc4;q6\x05@\n8/|\xb2R\xb3ky\xf3n\x11u\x95\xea\u0093\xec=\x80\xf0`\b8/|\xb2R\xb3\xba\xdcK\xf2n\x8b0\xb2\f\x84\aC\xc2yᓕ\x9a\x95>a\xdc]\xddrKޅ\x84\x0f7\x99\x85\xabΖ\vm\xe7\xaa\a\\\x95\x17\b\x00{\x18\b\x9f\xb8\xd4\xecV\xce\x16\xebÐ\xf0\xe1&\xb3p\xd5\xd9_\x1alj\x02\xcfo\xf3\x16\x10\x00\xf60\x10>q\xa9\xd9'\xa2\xc5\xfa0(\xbc\xa5\xc9\xccRuFZ\xbe\xbew\xaf) \x00\xecq^\xf8$\xa5f\xfd\xe3l\xf7\xf0\xd6&\xb3p\xd5\x19iK\xf5\x1b\x8fF\x00\xd8\xe3\xb0\xf0\x94\xbc\xd4,\x90\xe1\xfb\xcd\u0083\xa0\xf0\x96&3kՙ&\v\xea!<\x88\x8b\xf3\xc2S\x92R\xb3\xba\\\xa3\xad\xacI\\\x91wA\xe1-Mf\x96\xaa3\b\x0f\x92\xe0\xbc\xf0\xc9Jͮ\xe5-\xe8\xd73\xba{\xa2\xf1((\xbc\xa5\xc9\xccRu\x06\xe1A\x12\x9c\x17\xde$A\x03H\x9b\xab|WK\xe5\xb8CD\x9f\xc9wZ\xb7x\xbd\x9f\x92\xb5\xc9,\\uvɫվ\xeb?Q\xaby/\xc5\xdb\x18\xc8rX\b\x9f\xa8Ԍ\x8c\xcf\xd2\x14\xcd{_\x1f,\r\x04\xf7%ri\xa8\xc9,\\u\xb6\\֟\xbd\xef\xd2o\x97\xc7\xd9\x14\xc8vX\b\x8fR3\xa0\n\x16\xc2\x13J̀\"X\b\x8fK\xed\x01U\xb0\x10\x1e\x97\xda\x03\xaa`!<\xe1R{@\x11,\x84G\xa4\x01\xaa`!<\"\rP\x05\v\xe1\t\x91\x06(\x82\x85\xf0\x884@\x15,\x84G\xa4\x01\xaa`!<!\xd2\x00E@x\x90U\xb0\x10\x1e\x19\x1e\xa8\x82\x85\xf0\xc8\xf0@\x15,\x84'D\x1a\xa0\bg\x85G\xa9\x19P\x8c\xb3£\xd4\f(\xc6Y\xe1Qj\x06\x14\xe3\xac\xf0(5\x03\x8aqXx\x94\x9a\x01\xb58/<J̀B\x18\b\x8fR3\xa0\x0e\xe7\x85G\xa9\x19P\x88\xf3£\xd4\f(\xc4yᓔ\x9am\x91W^\x1a[\xba\xd3o>\xdc_\xd0j\xbb!\x00R\xc2yᓔ\x9a]\xdb(^\xf3\xee]\"\xea͇\xad\xae\x88\xcb\xc5\x03\x90\x1e\xce\v\x9f\xacԬM\x9c\"\xf2/7;\xcd\xf4\x91\xddf\x00H\x11\xe7\x85OVjf\bO=y\xb8\\$\x18\x06\x9c\x17>Y\xa9\x99)<-/\"\xba\x9e+DN\xa3|tr\x9c\x10\xf5gj&\xe6Vގ\xdd(\x00qa |\xe2R\xb3\xa0\xf0;D\x17Q\xbb\xd7;^^\x01\x9ez\x9a\x1aKJ\xf3JVՌ\xfd\x94\x00H\x1d\x06\xc2'.5\v\n\xdf\x16\b\xf1\xb9\x9e\xc0\xf2\xa9\xc2}\x83\xfc7\b\x804p^\xf8$\xa5fA\xe1_\x13\u05cc\x87a\xe15\xec\xdcA\xda8,<%/5\v\b\xffT\x9e\xf90,\xfc\x94ع\x00$\xc1y\xe1)I\xa9\x99)|\u007f\xc1\x12\xf3aX\xf8E\xb6\xd3\x01H\x84\xf3\xc2'+53\x85\xaf\x13\xc7̇a\xe1\x17\xc7\xce\x05 \t\xce\vo\x12\xb7\x01\xc4x\xa7\xb5m\xa9\x90\x9e\xf7\xbf\xe3\xf5\x8e\xaf\xf5zo\xd0\xed\xc3\xde\xd2\xe9^\xef'\xf6\xeb\x00\x10\x0f\x16\xc2'*53>K#&\xee\x90\xe3\xa39f\xa9\xd9\x0e:i\x8e\xaa\xec\xd6\x00 >,\x84G\xa9\x19P\x05\v\xe1\t\xa5f@\x11,\x84ǥ\xf6\x80*X\b\x8fK\xed\x01U\xb0\x10\x9ep\xa9=\xa0\b\x16\xc2#\xd2\x00U\xb0\x10\x1e\x91\x06\xa8\x82\x85\xf0\x84H\x03\x14\xc1BxD\x1a\xa0\n\x16\xc2#\xd2\x00U\xb0\x10\x9e\x10i\x80\" <\xc8*X\b\x8f\f\x0fT\xc1Bxdx\xa0\n\x16\xc2\x13\"\rP\x84\xb3£\xd4\f(\xc6Y\xe1Qj\x06\x14\xe3\xac\xf0(5\x03\x8aqVx\x94\x9a\x01\xc58,<J̀Z\x9c\x17\x1e\xa5f@!\f\x84G\xa9\x19P\x87\xf3£\xd4\f(\xc4y\xe1Qj\x06\x14\xe2\xbc\xf0IJ\xcd\xdaƚ\x17_\x12\x05\xfdq\xb6Q\xab?\xe9:c\x8eOΙ\x907\xfd@١8S#\xe6\xda5\xa4\xbd\x12(\\\x00\xa3\x15\xe7\x85ORj\xd6sH\xab\xf5\xeaԉ+q\xb6q\xc1\xebm\x10\xef\x18\xc3cZUˮ\x05B4řj\x9dKv\ri\u05fd\xe5\x1e\x02\xa3\x18\xe7\x85OVjF\x9a\xa1\xe0.q\xd5v\v\x06\xed\x01\x89+\xdd~\"\u007fm|\xe1-s%6\riU\x10~T\xe3\xbc\xf0\xc9J\xcd\x02\u009fY\x95\xa0\xbf/(\xf1\xc4zy{R$\xaa\xb6\xb4\no\x03\x84\x1f\xdd8/|\xb2R\xb3\x80\xf0:Mz\x00\xf7\x90G\xc8\xc8rcq\xb1VRu2\xf0LP\xe2%\x85\xf2\xd2\xda\xfe\xbd]Ԫ\xcfzƘ\xdbX\xa4\xfd\xa6\xb8\xf8\xc0\x8a|wW\xc4\xdcpC\xdar\xa1\xed\\\xf5\x80\xab\xf2\x82|\xa0\v\xbfB_k\xbc\xfe\xf7\xc4[Y\xa2\x15\xcd)AQ\xe6h\x82\x81\xf0IJ\xcdH\xab\xef\xe9Y\xb2Z\x1fty\xf3\xea\xafЕ\xfa|\xaf\x14zف\xa6\xaa\x9cvsJP\xe2OJr*=\x87\xe5\xd1mϡ\x92ern\x9e\xb7\xeb@\x9eX\xe5\x16\x136\x16\xbd\x1c17ܐ\xf6\x97\xc6q\xa2\xc0\xf3ۼ\x05\xf2\x81.\xfc\x85\x9a\x9c-\xfa\x86\x8f\x8e]ڲ\u007fg\x91@O\xe0h\x82\x81\xf0IJ\xcdH\v_\x18\xbbVր\xd4<A\xb2\xc6O\xdf_\xfb\xcb\xe6\x99SB\x12_{\xfeQM\xe4\x1b\x11\xde#+q\x96\xd6\xea7\x855\xb4W\xb4\xd2\xd2e\x91s)ܮ\xa0\xe5\xeb{\xf7\x9a\x029ԅ\u007fY3N\xde4\x14H\xd5\x1b\xf2\xb1\x87\x1fM8/|\xb2R3Җ\xb5\xb7\x97\x99\xc2\x1f\xc8\xed\xa1\x1e\x97W\x0e\xaf6TN\xca\x13e\xe6\x14\xabķ\xf6W\x8a\xbd\xfa\xfd\x85\xb1\xefӭ\xbc\xfd\xfa\xa8\xb0\x91\xde\x15]\xf4tM\xccܐ\xf0K\xf5\x1b\x8f&\x87U\x9eza\x9e\xac\xfc\xacx⊝'\xfc\xf1Ά\x82\x11\x89\xc3\xc2S\xf2R3#÷\xed7\x86\xb7'\xb4PK\x91\xdc\xe5\xb6\x17\x96<\xdd\xe2uG\t\xdfn\xc4p\u007f\xb9\xf1\xf2\xa8\\Mm\xf9R\xd7\xc26j\xd7e\xaeK \xbc\xbc\x0f\b_\x987y\x81\xb9S\xbf\xbec\xf1dQ\xb4\x11{\xf8ф\xf3\xc2S\x92R\xb3\xe0A\xebIyZr\xc5<Z\xb0B>\x9a\\ޣ\xdf.\x8a\x12\xbe\xd0x\x8e\xeaK\xe5m\xeb\x84~#Ѥ)|\xc1\xa9O\xf2\xb6\x18\x13\xebtկ7\xe66\x10\x18=8/|\xb2R\xb3\xa0\xf0\x85u\xfa\xcd\xe1\xf1\x97\xc6\x1f\x96\x8fJd\x87\x9f\xff\xe1(ዊe\x99\xab\xdf,\xf8\xeb/j\xcd7\xfe0\xa4'\xbc\xfc{\xa2Ƀa\x8fh\x93\v\xdc\xcb\b\x8c\x1e\x9c\x17\xde$n\x03H\xf0\x9dVo\x9e<Q\xe3/\xae,6\"\x86G,nx~\xaa(z\xf1]\xfaL\xbe{\xba\xc5\xeb\xfdT\x17^\x14z\xdaZܹ\x1f\x19\xab\xd6Mʗ\x87\x9d\xa7\xf2_\xeei\xd4N\xf6Ը/X\xe7\x86\x1b\xd2.y\xb5\xdaw\xfd'j5\xef\xa5\xeb\xde\xf2\xdaw\xfa\xbb\xaa\n\x0f\\\xd1\u007f\x84\xab\xbe\xb5\xa5V\x1c\xb0\xff\xc5\xc0\x88\x84\x85\xf0\x89J\xcd\xdaD\x10#glь;\xf2o)\xd5\n\x96\xbcV\xaa\xb9ii\xe0\xf9%D\x8f\xee\xac\xff\x99\xab`\x9e\xe9;}$\xe4\xce\xd9_$Dc\x9ep5\t1\xcf:7ܐ\xb6\\\xbf\xd5\xdew\xe9\xb7\xcb_\xd1or\x8e6\xea\xb7\xf5\xb4k\xba\xa7D+t\xc3\xf7Q\x05\v\xe13Tj֥AV\x10\x05\v\xe1)3\xa5fM\x13\xf0\x9e\x11\x88\x82\x85\xf0\x99\xb8Ԟ\xe7\x80\xdf]\x9fl\x12\xc8:X\b\x9f\x81K\xed\xf5\x88)\xcb\v\xaf'\x9b\x05\xb2\x0e\x16\xc2S\x06.\xb5\xe7q\xb9?H6\ad\x1f,\x84\xcfD\xa4\x01\xc0\x0e\x16\xc2g \xd2\x00`\v\v\xe1)\x03\x91\x06\x00;X\b\x8fH\x03T\xc1BxD\x1a\xa0\n\x16\xc2\x13\"\rP\x04\x17\xe1\x01P\x02\v\xe1\xf5\xf0\xfe\xf6\xf6\xb8\x9f\x87\a`\xf8`!<2<P\x05\v\xe1\t\x19\x1e(\x82\x85\xf08-\tT\xc1BxD\x1a\xa0\n\x16\xc2\x13\"\rP\x04\v\xe1\x11i\x80*X\b\x8fH\x03T\xc1BxB\xa4\x01\x8a`!\xbc\x8c4o~5\u08c1>\xf9\x0f\xbbz\x901X\b\x1f\x884\x00d\x1c\x16\u0093\x8c4ح\x03\x05\xb0\x10^\x8f4\aw\xf7\x1d\xd9\xec;\xf2\x92\xfe\xaf\xf7\xf8v\xcbs\xc9K\xcd\x00H\x1d\x16\xc2\xcb⛅7߬\xee6\xff\xa5Vjv\xe0\x18\x01\x90.,\x84\xd7\xe9\xbdI_~\x1c\xf8\xd7}1\xe2\xa98\xa5f\x8f.!\x00҅\x85\xf0\xc6\x1bO\x9d\xf1\x9e\x8dSj6u\xb1\xddd\x00\x12\xc2Bx\xe3,\xcd\xf9\x81^\xfbӒ\xa1R\xb3Sㄨ\xf2\x97\b\x91\u007f\xab5\x10\xec\xa7\xc4n\f\x80\x04\xb0\x10\x9e\x12\xbe\xf1\x14*5\xf3\x1f\xf6\xe4\x1c\xa6]cw\x9d\xa0\xaeC\xde\xd2\xe9z\xb2ǵ\x96@z\xb0\x10>\xf1gi,\xa5f\xfe\xa5\xe5WK6\x9a\x8b\x11i\xc0 `!|\xe2\xcf\xd2XJͨ\xe7ᢪ@\x96\x87\xf0`\x10\xb0\x10\x9e\x12G\x9ap\xa9\x19Q\x8b8\x14\x18Ax0\bX\b\x9f$\xd2XJ\xcd.\x14֗|a.6\x84\xdf\xf9\xa9\xfd:\x00\xd8\xc3B\xf8$\x91&\\j\xd6_^O\xcb\xdcf\xa6q\xbb\x89\xae\x88&\xfbu\x00\xb0\x87\x85\xf0\x94 \xd2XJ\xcdz\x0e-/\xb8@\x1dy+\x0e\xdd\"Y\xba\xb7\xa5\xc5\xed\xfa,\xcej\x00\xd8\xc2B\xf8D\x91\xc6Rj&\x87\xabh\x85\x10cewӭ\x15\xf9\xb9\xd3\xdb\xedV\x01 .,\x84\xc77\x9e\x80*X\bO\xf8\xc6\x13P\x04\v\xe1\xf1%n\xa0\n\x16\xc2#\xd2\x00U\xb0\x10\x9e\x10i\x80\"X\b\x8fH\x03T\xc1BxD\x1a\xa0\n\x16\xc2\x13\"\rP\x04\v\xe1\x11i\x80*X\b\x8fH\x03T\xc1BxB\xa4\x01\x8a\xe0\"<\x00J`!<J̀*X\b\x8f\f\x0fT\xc1BxB\x86\a\x8a`!<NK\x02U\xb0\x10\x1e\x91\x06\xa8\x82\x85\xf0\x84H\x03\x14\xc1BxD\x1a\xa0\n\x16\xc2#\xd2\x00U\xb0\x10\x9e\x10i\x80\"X\b\x8fR3\xa0\n\x16£\xd4\f\xa8\x82\x85\xf0\x84R3\xa0\b\x16\xc2'*5\xf3\x06K\xcdƟ\x8c\xbb~\x98\x93s&\xe4M?Pv\x88\xa8V_\xc5u&\xfe\xcc\xe5\"\a\x97\xe9\xcbBX\b\x9f\xa8\xd4\xec֡\xc29\xf2J{\xbbD[\xdc\xf5C\x1cӪZv-\x10\xf2\x8a\x93\x17\xbc\xde\x06\xf1N\xfc\xa9\x17\xbc\xa1f\x11\x90E\xb0\x10\x9e\x12\x96\x9aM\\&o?JE\xf8Jy\xa1U\u007fm\xe0\x12\xab퉄\xb7T\xe9\x80,\x82\x85\xf0\x89K\xcdL\xe1\xfb\xb7݈7!\xcc\xc4zy{R\xb4\x18\x8f <\x88\x81\x85\xf0\x89K\xcdL\xe1uN\x8e\x13\xa2\xfeL\xcd\xc4\xdc\xca\xdb\xfa~\xfc\x95)\xae\x87\x1b\xfct\xbbH\xfbMq\xf1\x81\x15\xf9\xee.\xa2%\x85\xa7\xf4y\xfe\xbd]\xc6\xfc\xa0\xf07\x16\x17k%U\xe6!\x80\xb7\xb2D+\x9aS\"\xaf\xb8\xad=\xb5\xea\x01W\xe5\x05\x02\xd9\x04\v\xe1)\xe1\x1bO\x13k{z^.\xd7\a=M\x8d%\xa5y%\xabj\xc6~J\xb4T\xab\xdf[\xaf\xd5\x12\x1d\xc8\x13\xab\xdcb\xc2Ƣ\x97\x89>)ɩ\xf4\x1c\x0eVv\a\x85o\x15\xcb\x0e4U\xe5\xc8+\r\x1f\x1d\xbb\xb4e\xff\xce\"\xa1\xbfbH\x13\x93\x1b[\x8a\x16\xc4\xf9\xa9`t\xc2B\xf8ğ\xa5\x99(\xcf\xd1\x14\x9a\xe3\xa9\xc2}\x83\xfc7\xe4U\xb4e\xa47n\vkh\xafh\xa5\xa5\xf2\x0f\xc1\xb5\xe7\x1f\xd5D~\xe0\xf4KP\xf8\x9e&}\x8f\xef/\x9b\xa7\x0f\x1b\n\xa4\xea\r\xf9\xc6\x1e\xbe\xf0\v\xa2ڂ\xd8\x1f\bF1,\x84O\xfcY\x9a\x89U\xed\xedK\x83\xc2k\x9f\x9a\x83\xda2\xe3\xeeA}\x17_\xd8H\xef\x8a.z\xba\xc6|\xe6\xd6\xfeJ\xb1\xd7\x18\x852\xfcՆ\xcaIyB\xae\xf1Y\xf1\xc4\x15;O\xf8\x8d\xbf\x01\x9a|\x85x4\x02\xd9\x04\v\xe1)q\xa4\xd1\xc5<\xb5\xd3\x1cO\r6\x11\x97\x9b\xb5~Uz\xd4)l\xa3v]\xdb:]\xf8v#\x91\xfb\x03O\x06\x85o/,y\xba\xc5\xeb6^\"\xd7w,\x9e,\x8a6\x1a{xy\xd0\n\xe1\xb3\f\x16\xc2'\x894\xcb\xc2㩋\x02\x83\xdaI\xd2Y\xffĥ\x11\xc2\x17\xae0\x9e\xac/5\xee\x82\xc2O.\xef\xd1o\x17I\xe1\xdb\xeb\xf4ծ7\xe66\x10\x84\xcfNX\b\x9f$\xd2X\x85_\x1c\x18\xec\x15\x8d\xfam\xa3\f/\x16ዊ\xaf\xe9K\xfd\x81\x97EP\xf8\x12\xf9\xd0\xff\xb0\x14\xdec\x9e\xcdw\xcbMB\xf8l\x84\x85\xf0\x94 \xd2\xdcz\xa7p\xce!\xf34\xe3\xed\xc3F\xdf\xfc'ƃ\x9a\x9c\xbaֺ\x1c]\xf2S\xf9/\xf74j'{j\xdc\x17\xa8H\x14z\xdaZܹ\x1f\xe9i]\xbeӺ\xc5\xeb\xfdTZ\xbe\xb8\xe1\xf9\xa9\xa2\xe8\xc5w\xf5\xa1\xab\xbe\xb5\xa5V\x1c\xa0K^\xad\xf6]\xff\x89Z\xcd{)\xceO\x06\xa3\x11\x16\xc2'\x8a4\xc6giv\x19Ó9\xc2\xd2B\xbf\xad\xccU\xd6\xe0'\u007f\x91\x10\x8dy\xc2\xd5$\xc4<ztg\xfd\xcf\\\x05\xf3t\xdfii\xe0#8K\xf4\xa9[J\xb5\x82%\xaf\x95jn\xda5\xddS\xa2\x15\xba\x0f\xc8\xcf\xd2\b\xa1\xbd\xef\xd2o\x97\xdb\xfdX0Ja!<\xbe\xf1\x04T\xc1Bx\xc27\x9e\x80\"X\b\x8f/q\x03U\xb0\x10\x1e\x91\x06\xa8\x82\x85\xf0\x84H\x03\x14\xc1BxD\x1a\xa0\n\x16\xc2#\xd2\x00U\xb0\x10\x9e\x10i\x80\"X\b\x8fH\x03T\xc1BxD\x1a\xa0\n\x04\x82U\v\x00\x00 \x00IDAT\x16\xc2\x13\"\rP\x04\x84\aY\x05\v\xe1\x91\xe1\x81*X\b\x8f\f\x0fT\xc1BxB\xa4\x01\x8apV\xf8^=\xc6\f\xf8$\a\xdf\xf8\xdc\xe7\xeb\xeb\x93;y$\x1b\x909\x9c\x15>\x80\xae\xf9\xa6\xd9\xe7\x10i@\xe6a!\xbcN\xe79_\xb2)\x00\f\x1d\x87\x85\xd7\xe3\xcb\xf1\xed\xeb֮]\xa3\xb3v\xcdڭ\xafw#рL\xe2\xb0\xf0\xf2\xfc\xcc¹\xd5sM\xaa\xab\xa7\x9dG\xb0\x01\x99\xc4y\xe17\xcc8\xfe\xe5\xe7_\xea\xe87\xebf Ƀ\x8c\xc2@\xf8\x8a\xf0\x19\xc9ͳ\xce\xc9k\b#\u0383L\xe1\xbc\xf0/\xcc\xf80\xf4h\xfd\xac\xb3\x89f\x030T\x9c\x17~\xc3̰\xe4\xcfʹ\x13\xbe\xe5\xc1\xf1e-S[\xe3\xf46\xa1\xac\t\xa4\x81\xf3¯\xaf\xee\xfd\xc3?\xfe\xe3=\xfa\u007f\xff\xec\xdb=\xa3\xf3\xed\xb5\xbdo\xaf\x8d\x98\xb3MԴ<%Ķ8\xbdM(k\x02i\xe0\xbc\xf0\xeb\xaa\xfb\xd6\xfd\xfd\xdf\xff\x1f\xfd\xbf\xef\xfb\x9agt7/\xbc\xd9\\m\x9d\xf2\xd1\xd8z\xfdv\x95\x14\x9e\xeckl <H\x19\xe7\x85\xdf0\xeb\xfcͳ\x1f\x9f\xff\xf8\xfc\xd9˴i\xe6ǾN\xf2}e\x9dR[pK\xbf\xfd@4\x18\x8f <\x18\x12\xce\v\xff\u008cӡGv\a\xad\xf9O\x1bw\xdb>1\xeeB\xc2\a;\x9et\xb4\x15O\x14\xe7W%\xe8d\x05 \x88\xf3\xc2o\x98\x19\xee\xef{if\xcci\xc9\xeb\xe25\xeb\n!\xe1C\x1dO\xb2\xaciJSc\x99\xeb\x14\x01\x90\f\x06\xc2W|\x1ez\xf8Ҭ\x987\x9e\xde7\xae\xe8\xee\xef\xe9\xb9e<\f\no\xe9x\"mr\x0fQOi9\x01\x90\f\xe7\x85ߴ\xf0\xc95+W\xfe\xfa\xd7+W\xae\\S\xfdH\xcc\xd7@\xcc=|\x8d\x10b\xbf|\x18\x14\xde\xd2\xf1D\xda3r\xb8C\\#\x00\x92\xe0\xb0\xf0\x03D\xfbV\xfer~u\xf5\xc2ǫ\xab\xab\xe7\xaf\\\xdb\x19\xf3\xe1\xb1\t2\xc3_j\x11u\xc6.>(\xbc\xa5\xe3)p\xd0\xea\x15\xc7\b\x80$8,\xbcN_o\xb7\x8eo@\xde\xf6\xf6\xc6>_[$Mo\x89:-i\xe9x\"m\x95\\\xb2S\xa4P\xd5\r\xb2\x1d\xe7\x85'c?\xff\xc2\xc2\xcf\xe3|0\xd88\x0f\xefwG\to\xe9x\"\xadX\u007fI\xf4?\xe8\xb6]\x1d\x00+\xce\v?\xd0\xd7\xd7\xed\xf3\xfd۴#\xben_\x9f\xddG%\xb7\x88'Zk\x8dwZ-\xbdM\xe1\x8e'y\x96\xa6\xf2\xf0\xfe\xf2\xfc\x8fl\xd6\x05 \x12\xe7\x857\xe9M\xf0%\xee\x96ɹ\xe5m%m\x11\xbdM\xa1\x8e'\x9d\a=\x8b\xf3\x8ak\xd0M\x06R\x80\x85\xf0>\xa2M\x8f\x9f%|*\x18d\x1c\x16\xc2뇪z\xa4!\x9b#V\x00\x86\x17\x16\xc2S\xe2H\x03\xc0\xb0\xc1Bx\\j\x0f\xa8\x82\x85\xf0\xb8\xd4\x1eP\x05\v\xe1\t\x97\xda\x03\x8a`!<\"\rP\x05\v\xe1\x11i\x80*X\bO\x884@\x11,\x84G\xa4\x01\xaa`!<\"\rP\x05\v\xe1\t\x91\x06(\x82\x85\xf0\x884@\x15,\x84O\x10i\xb0\xe7\a\xc3\n\v\xe1)\x8e\xd8\xd8\xf3\x83ᆅ\xf0\xf1\xc4\xc6\xc1,\x18nX\b\x8fH\x03T\xc1Bx\x8a/\xf6\x91\xdd\x11\xd7\xdd\x03`h\xb0\x10>&\xd2\xec\xf1u\xf6\xfa\xfa\xfaz\xfb\xfa6T\x9c\x95w}\xd4\xd7\xdb\xeb\xc37D\xc0Pa!|L\xa49\x12\xfa\xba\x1f\xda\xfd\xc0\xb0\xc2Bx\x8a\x8e4\x90\x1cd\b\x16\xc2Ǟ\xa5\x91u\x96\xbb7mxn\xfd\xb3k\xd7?\xb7~\xc3\xebͨ\xb3\x04\xc3\x02\v\xe1c\xcf\xd2\xe8í\vg?6kV\xf5\xfcٳf=V=\xe3\"NN\x82စ\xf0\x14s\x96F^Uxڑ\xf3g\xcfߤ\xcbgϟ\u007fv\x1a\xea,\xc1\xb0\xc0B\xf8\xd8Hc\\F\xfb&\xc9K\xadʇ[+\xe4u\xe3\xe1<\x182,\x84\xb7\x8d4/̔u\x96?\xba\xe3\xa0\xfe蹙\xe7\xe2\xad\v@:\xb0\x10\x9el#\x8dQay\xff\x1d\xf2v=\xea,\xc1\xf0\xc0Bx\xdbH\xb3~n\xf7\xee\xfb\xee\xbd\xfbk?\xb8\xef\xe7}o\xcc\xe8<\xb8\xc1w|s\xc4Z\xa8\xb3\x04\xe9\xc3Bx\xdbH\xb3\xaez`\xed7\xbe\xfeww|\xe3\x1bߑu\x96\xbb\xab\xbb\xf7\xfcҺ\x12\xea,\xc1 `!<\xd9F\x9a\x8a\x8b\x9dǏ\xdf\xfb\xf5\xed\xc7ߣ\x97f\x9e\xef>Oݗ\xadSPg\t\x06\x01\v\xe1m#\x8dYgy\xaf\xcc\xf0\x03\xa8\xb3\x04\xc3\x04\v\xe1m#͆Yr\x87>\xeb{R\xfbM3cNK\xa2\xce\x12\f\x06\x16\u0093}\xa4\xf9R\x1f\x98\x9d\xad\x9b+Pg\t\x86\x05\x16\xc2ۿ\xf14\u007f\xcd\xfag\xd7m\u007f\xe3\xb9g\u05ed\x9f\x8f:K0<\xb0\x10\xde6\xd2\xecy\xb2z\xee\xec\xd9\x15\x15\x15\xb3g\xcf}reg\xcc۬\xa8\xb3\x04\x83\x80\x85\xf0d\xf7\x8d\xa7\xde\xce\xcb\x17/_n^\u007fZ\xbf\xeb\xb4\xf9\xda\x13\xea,\xc1 `!|\x82/q\xaf\x9du>\xceGhPg\t\x06\x01\v\xe1c#\r\xc9\xc3U_\xaf\xcf\xf7\xd2\xfc\xb3\xbe\xde>\x9f\x9d\xf3\xa8\xb3\x04\xe9\xc3Bx\x8a\u007f]\x9a\x83\u007f\x88-\xa3\x0f\x82:K\x906,\x84\x8f\x17i|Dkf\x1e\xc7\x17\xfe\xc0\xf0\xc1Bx\xdbH\x13X>\x1f\x17b\x02\xc3\b\v\xe1ip\x91\x06\x80\xb4a!<.\xb5\aT\xc1B\xf8\x04b\xe3R{`Xa!<\xe1\xea\xc1@\x11,\x84G\xa4\x01\xaa`!<\"\rP\x05\v\xe1\t\x91\x06(\x82\x85\xf0\x884@\x15,\x84G\xa4\x01\xaa`!<\xc5\x17\x1b\u0083a\x85\x85\xf0\xf1\"\r2<\x18nX\b\x9f\xe8\xb34\xc8\xf0`8a!<!\xd2\x00E\xb0\x10>AtA\xa9\x19\x18VX\b\x1f\x13]Pj\x062\x04\v\xe1):\xba\xa0\xd4\fd\b\x16\xc2\xc7D\x1aH\x0e2\x04\v\xe1c\xcf\xc6\f\xa0\xd4\fd\x04\x16\u0093ݥ\xf6Pj\x062\x00\v\xe1\xed/\xb5\x87R30\xfc\xb0\x10>6\xd2\xf4\xa1\xd4\fd\x04\x16\u0093]\xa4A\xa9\x19\xc8\x00,\x84\xb7\x8f4\xc9J\xcdNΙ\x907\xfd@١\x88\x85\x91\xfdf\xfb\vZcV\x03Y\r\v\xe1m#M\xb2R\xb3cZUˮ\x05BDV\xf5E\xf6\x9b\xb5\xbaZ\x02\xa3\x03\xb8\x840\x90\xb0\x10\x9e\xec\"M\xb2R\xb3J\xb7\x9f\xc8_+b\xba)\xaduO\xfe\xe0\xe0\xd1%\xd1\xd3@V\xc2Bx\xfbH\x93\xa4\xd4lb\xbd\xbc=)\x82\xfb\xf0\x10v\xfdf4uq\xec2\x90\x85\xb0\x10\xde6\xd2$+5[R(˛\xfc{\xbbh\xb9\x18\xb7mY\xb8\xbe,(\xfc\xf5\\!r\xe4ų\xa95p\xb1\xd5)1\x1b\x01\xd9\x06\v\xe1ɶ\xe3)q\xa9\x19}R\x92S\xe99ܯ\x8f\xfe\xd28N\x94<\xef)\tԗ\x85\xf6\xf0\xed^\xefx\xa3\x04\xa4됷t\xba\xd7\xeb\xfd\x80@\xb6\xc3B\xf88\x91&a\xa9\x19ѵ\xe7\x1f\xd5D\xbe\x11ᵉ7\xf4=z\x89Y_f\x8d4\xb9\xc1\xaaVD\x1a`\xc0Bx\xfb7\x9e\x12\x97\x9a\x19\xdc\xda_iv}\xd4\xc9G\rf}\x19\x84\a\xf1a!<\xd9E\x9ad\xa5f\xed\x17\xe4\xad\xdfh1\x8b\xa8/\x83\xf0 >,\x84\xb7\xfd\xc6S\xb2R\xb3\xc2\x15\xc6]})E\u0557\xc5\x17~\xe7\xa7\x04\xb2\x1c\x16\xc2\xc7F\x9a\xd0\xf2\xf8\xa5fE\xc52\xc0\xf8\xa7.\xd2o\xb5\xa2.\xfd\xd0t\x92Y_f+\xbc[\u007f\xeeJ\xec9{\x90m\xb0\x10\x9e쾬\x9d\xacԬH\x14z\xdaZܹ\xb2\xb3L\x96\xcc\xef,\x95\xf5e\x96~\xb3\xfew\xbc\xde\xf1\xb5^\xaf\xb1\xdb\xf7h[Zܮ\xcfb7\x03\xb2\v\x16\xc2'\xb8.M\xfc\x06\x90Gw\xd6\xff\xccU0\xcf\xe8\xe8\xd3V\xd7\x06\xea\xcb,\xfdfGs\xcc\xe1\x0e9\xe3֊\xfc\xdc\xe9\xed\xb6\x1b\x02\xd9\x04\v\xe1\xe3E\x9a\x94K\xcd4\x0f\x01\x90\n,\x84\xa78ן\xe9K\xb5\xd4\f\u0083\x14a!\xfc\xa0\"\x8d\x15\b\x0fR\x84\x85\xf0\t\xceҤr\xa9\xbd\v^\xad\xf6]?\x01\x90\x1c\x16\xc2\xd3\xd0.\xb5\xb7\\?2\xd5>I6\v\x00b\"|\x82H\x83\xab\a\x83a\x85\x85\xf0C\x8c4\x00\xa4\f\v\xe1ih\x91\x06\x80\x94a!<\"\rP\x05\v\xe1\x11i\x80*X\bO\x884@\x11,\x84O\x10] <\x18VX\b\x1f/\xba Ãᆅ\xf0\x94\xe0\xb34\xc8\xf0`8a!<\"\rP\x05\v\xe1\x13\xec\xc9Qj\x06\x86\x15\x16\xc2S\xf4\x9e\xbcW\xdfۛ\xdfx\xdaP\xf1\xa1\xef\xa6,5#Dy0\f\xb0\x10>A\xa4A\xa9\x19\x18VX\b\x8f\x83S\xa0\n\x16\xc2S\xcc\xc1\xa9\xbe\xb3?\xbe}\xddڵkt֮Y\xbb\xf5u\x94\x9a\x81a\x81\x85\xf0\xb6\x97\xdaۼpn\xf5\\\x93\xea\xeai\xf1.\xd6\x01@Z\xb0\x10>6\xd2\xe8\xc3\r3\x8e\u007f\xf9\xf9\x97:\xfaͺ\x19(5\x03\xc3\x02\v\xe1\xc9\xf6\xea\xc1\x15\xe1E\x9bgɫ\a\x0f\xe0\xf8\x15\f\x15\x16\xc2\xdbF\x9a\x17f|\x18zdw}x\x00\x06\x01\v\xe1\xed#\x8d\xa5\xc8\xec9\xbbR\xb30\x91Mf\x01\x96\x8b\x1c\\Y\x0fD\xc3Bx\xb2\x8b4\xeb\xab{\xff\xf0\x8f\xffx\x8f\xfe\xdf?\xfbv\xcf\xe8|{m\xef\xdbk\xe3\xac\x1c\xd9d\x16Z\x88\x8bw\x80\x18X\bo\x1bi\xd6U\xf7\xad\xfb\xfb\xbf\xff?\xfa\u007fߗ\xa5f\xcd\vo6W\xc7߄]\xb1\x13\x84\a1\xb0\x10\xde>\xd2\xcc:\u007f\xf3\xec\xc7\xe7?>\u007f\xf62m\x9a\xf9\xb1\xaf\x93|\t>V\x03\xe1AJ\xb0\x10\x9el\x9b\xb8\x8dR3\xf3\x91\xedA\xeb՚\tūWOp\x19I=$\xbc\xff\x95)\xae\x87\x1b\x8c\xcb2i+\x9e\bW\x9d\x01 a!\xbcm\xa4\xd90\xb33\xf4𥙱\xa7%\xfb\x1f,l\xf0\x8c\xcf\xddY\xf9\xb2|\x14\x12~\xa9V\xbf\xb7^\xab\x95Cy\x11\xedƲ@\xd5\x19\x00\x12\x16\xc2\xdbG\x9a\x8a\xcf\xf5\xc1\x80\xb1\xf0\xa5Y\xb1o<5\x89\x93\xb2\xd6)\xa0sP\xf86\xd1\x16\xba\xd5&\xf7\x10\xf5\x94\x96\x13\x00AX\bOv\x91f\xd3\xc2'\u05ec\\\xf9\xeb_\xaf\\\xb9rM\xb5M\xa9Y]\xbe~\xf3Q\xb0\x978(|m\x99q\xf7\xa0\xdc\xc5k\xcf\xc8\xe1\x0e\xb3\xea\f\x00\t\v\xe1c#\x8d>ܷ\xf2\x97\xf3\xab\xab\x17>^]]=\u007f\xe5\xda\xd8k\b\xbf<\xf6\xaaܕG\xedፎ3\xa2*\xb9[\x8f\xa8:\x03@\xc2Bxۏ\a\xf7\xf5v\u007f\xd5ݽgù\xee/\xbb{{cW\xfa4\xa7\xf2ӓ\xa5偫\x06\x87\xf6\xf0\x93\xe4\x02\xffĥ\x14Uu\x06\x80\x84\x85\xf0\x14\xffK\xdckf\xc6\xfb\x9c\xfc1Q$\x84\xfbB\xe0QP\xf8\xbdB\x96\xcd7\x9a\xed\xadŷ䱭\xdbvu\x90\x9d\xb0\x10\xde\xf6\x1bO\x03}}\xbd>\xdf\xf6\xc7\xcf\xfaz}}6\xce\x1f\x1b\xbf\u007f\xaf\xf7\x82\xb1\x83\xb74\x99QMN]k]N\x8d\\\xac\x89\xca\xc3\xfb\xcb\xf3?\x8a]\x17d-,\x84\x8f\xf7\x8d'\xfd\x15p\xf0\xf5xץ9\xa4\xc9\xc62m\xfa\xa9\x88&3\xf2o+s\x95\x99\xe7\xe1\x1f\xf4,\x0eT\x9d\x01\x10\x80\x85\xf0\x14'\xd2\xf8\x88~=#N\xa9\xd9\x15ײ+\xb7o_?\xba \xff\xba\xdd\xd3\x00\xd8\xc2B\xf8x_\xe2\xd6w\xf9\xdb\x1f\x8f\xf3]\xa7\x96|\xf3p\xd5_\xd4f\xf74\x00\xb6\xb0\x10~0\x91\xe6X\x8eyB\xf2T\xce\t\xbb\xa7\x01\xb0\x85\x85\xf04\x88K\xed\xf9ks\x975\x1dhZ\x96\xbb\fuf uX\b?\xa8K\xed\xf9[+\x8b\xb5\xe2\xcaV\xf8\x0eҀ\x85\xf0\t\"\r\xae\x1e\f\x86\x15\x16\xc2\xd3 \"\r\x00\x83\x81\x85\xf0\x83\x8a4\x00\f\x02\x16\xc2#\xd2\x00U\xb0\x10\x9e\x10i\x80\"X\b\x8fH\x03T\xc1BxD\x1a\xa0\n\x16\xc2\x13\"\rP\x04\v\xe1\a\x11i\x10u\xc0\xa0`!|\xba\x91\x06Q\a\f\x16\x16\xc2S\x9a\x91\x06Q\a\f\x16\x16\xc2#\xd2\x00U\xb0\x10>\xe5H\x13h\xf7\xd39\xf8\xc6\xe7>\x1f\xda\xfd@\xba\xb0\x10\x9eҏ4\x9bf\xa3\x13\x04\f\x02\x16\xc2\x0f\"Ҡ\xce\x12\f\n\x16§\x1ci\xe4\x10\xed~`\b\xb0\x10\x9eR\x8e4}h\xf7\x03C\x82\x85\xf0\xa9G\x9a>\xb4\xfb\x81!\xc1B\xf8\xd4#M\x1f\xda\xfd\xc0\x90`!<\xa5\x13i\xd0\xee\a\x86\x00\v\xe1Ӌ4\xc9\xdb\xfdZ\xe4e\xc8&F\u007f\xbb{\u007fA\xab\xddd\x90U\xb0\x10>\xadH\x93B\xbb_\xd7!oޢ\x98\xe2\x8fVWK\xf4\"\x90u\xb0\x10\x9e҉4\xa9\xb5\xfb\x15\xad\x8e]\x86\vz\x00\x1e§\x17iRj\xf7\xb3\x13\x1e\x00\x1e§\x15i\x92\xb6\xfb\x19\x98\u0087+\xfd\xae\xe7\n\x91#/\x1dO˅\xb6s\xd5\x03\xae\xca\xe0\x95\xe5AV\xc1BxJ'\xd2$k\xf731\x85\xb7T\xfa\xb5{\xbd\xe3\x8d\n\x9c\xbf4\x8e\x13\x05\x9e\xdf\xe6-\x88]\t\x8c~X\b\x9f^\xa41\xda\xfdL\xec\xda\xfdL\f᭕~:\xb9\x81\xa2b-_\u07fb\xd7\x14خ\aF9,\x84O+\xd2$k\xf731\x84\xb7V\xfa\x91ExY\x00\xe5\xd1l\xd7\x03\xa3\x1c\x16\xc2Sʑf y\xbb\x9f\x89!\xbc\xb5ҏ,\xc2\xcb{\b\x9f\x9d\xb0\x10>\xf5H\xa3\xd3\xd7ۭ\xe3\x1b\x90\xb7v\xed~\xb7?\x90\a\xa9\x13\x8c=\xbc\xa5ҏ < &§\x1eiB\xcb_X\xf8y\x9c}\xfb+\xc2KtUl\xa3\xc8J?\x82\xf0\x80\x98\bO)G\x1a2\xda\xfd\xba}\xbe\u007f\x9bv\xc4\xd7m\xdb\xeew@\xcci\xd9U>\xe139\x0eW\xfa\xf5\xbf\xe3\xf5\x8e\xaf\xf5zo\xd0%\xafV\xfb\xae\xffD\xad\xe6E\xddY\x16\xc2B\xf8\xb4\"\x8dIo\xfc/q\xb7Lu\xe5W\xbdo\fÕ~Gs̢\xbf\x1d\xb4\\v\xff\xbd\xef\xd2o\x97\xc7\xdd\x04\x18\xb5\xb0\x10>\xddH\xe3#\xda\xf4\xf8Y\xfbv?\x00\x12\xc1BxJ'Ґ\xbcx\x01鑆l\x8eX\x01H\f\v\xe1\x877\xd2\x00\x10\x1f\x16§\x1bi\x12\xbc@\x00H\b\v\xe1)\xcdH\x13o9\x00\xc9`!\xfc \"\r.\xb5\a\x06\x05\v\xe1\x11i\x80*X\bO\x884@\x11,\x84G\xa4\x01\xaa`!<\"\rP\x05\v\xe1\t\x91\x06(\x82\x85\xf0\x884@\x15,\x84G\xa4\x01\xaa`!<\r5\xd2\\\xbe\xfcyg\xd4\x06\xba;/\u007f\xf5%^\x12 \n\x16\xc2\x0fc\xa49\xb8=ޗ\xfe\x00 &\xc2\x0fW\xa4\xd17\xb0i.\x0efA\x02X\bOC\x8d4a\xba;\xb1\u007f\a\t`!\xfc\xf0D\x9a\xbe>__\xdf\xf1=_\xeaw\x03\xb0\x1e\xd8\xc3B\xf8\xe1\x8a4:/=v\xd1f)\x00\x01X\bO\xc3\x17i\x06\xc2\xd7\xe1\x03 \x16\x16\xc2\x0f=\xd2諞\xde\xf3\x87\xed[7\xbfټ}\xeb\xd6\xed\xcd\xfbnگ\x06\xb2\x1d\x16\xc2\x0f=\xd2\xe8\xabn\x9f?k\xe6\xb4\x19\xd3$3\xe7W\\Ĺ\x1a`\a\v\xe1iȑF\x1fn\x98v\xf0\xf4{\xa7\xdf\xd39}z\xcd4\xb4\xfb\x01[X\b?\xf4H#\x85\x9f\x1d\xbe\x8a\xc1֊s\xf2\"\x1ep\x1eD\xc3B\xf8a\x894\x96\xb2\xb3\xbe\r3\xcfE\xaf\x03\x80\x84\x85\xf04,\x91fFHxZo\xdf\xee\a\x00\v\xe1\x87%Ҭ\x9f۽\xe7\xc7?\xfe\x89\xfe_E\xdf\xeb3??\xb2\xddw|k\xe4\xe7jNU\xba\nk\x0e\x14^\xa1Z!\x84\xeb\f\x81,\x84\x85\xf0\xc3\x12i\xd6UӚ\xaf}\xed\xef\xf4\xff\xbe%\xdb\xfdޘ۽;\xb2\x1f\xa4\xcd\xf5\xe8\xce\xc62!>\xa0\v^o\x83x'z\xab \x1b`!<\rK\xa4\x99}\xf9b\xf3\x9e}{\xf65\x1f\xa4\xcd3.v\x9e\x1e\xe8\xfc\xd0z\xf5\xc9ky\xf3n\x11u\x95\xea\xc2\xeb\xb4C\xf8섅\xf0\xc3\x12i,\xed~\x03v\x19\xbe.\u05f8<\xf6\x16ad\x19\b\x9f\xa5\xb0\x10~X\"͆Y\x17\xcd%\xfaͦ\x19\xe7\xe4\xa5V#6X\xfa\x84qwu\xcb-y\x17\x12\u07bf\xab\xdc\xf5\xc0\xea\x1e}tcq\xb1VRu\x92\xd0l9\x9aa!<\rO\xa4\tobsE\xcc\x1bO\xb7r\xb6X\x1f\x86\x84\xaf\xcdY\xb1w[\xc1T?Q\xabXv\xa0\xa9*\xa7\x1d͖\xa3\x19\x16\xc2\x0fK\xa4\xd9P\xbdn\xf3\v\x9bt^ش\xf9\x97\xb1\xed~\x9f\x88\x16\xebà\xf0\xadb\x97\U00068468\xa7\xa9K\xdf\xe1\x97͓\x8b\xd1l9Za!\xfc\xb0D\x9a\xe6\xc7\x1f\xab\x98aR\xf1\xf8\x93\x9fGo\xad\u007f\x9c\xed\x1e~ɤ\xfe\xdb:Ų\xd9\xf2jC\xe5\xa4<aT]\xa2\xd9r\xb4\xc2Bx\x1ar\xa4\xd1\xe9\xbex6\xc4\xc5˱\u007f-\x02\x19\xbe\xdfl)\x0e\n_f6\xe1\b}\xbf\xde^X\xf2t\x8b\xd7m\n\x8f\u07b3Q\n\v\xe1\x87\x1eiR\xa0.\xf7\xaa\xbck\x12W\xe4]P\xf8\x9aI\xc7\f\xf4\xe7&\x97\xcbC\xd7E\x10~T\xc3B\xf8\xa1G\x1ac\xe9@_\x90\x81\x98M\xc9\xf3\xf0\v\xfa\xf5\x8c\xee\x9eh<\n\n\xdf&\x9a\xe4]\xfdF\xa2\x92E\xfa\xc0\xff0\x84\x1fհ\x10\x9e\x86#\xd2$\xa5\xcdU\xbe\xab\xa5r\xdc!\xa2\xcf\xe4;\xad[\xbc\xdeO\xf5\xa5uckZZj填G,nx~\xaa(z\xf1]4[\x8e^X\b\xaf$\xd2\x18\x9f\xa5)\x9a\xf7\xbe>X\x1a\b\xeeK\xe4\xd26\xf7\x84\xfc\xe92\xd8\xfb\xb7\x94j\x05K^+\xd5\xdch\xb6\x1c\xbd\xb0\x10~x\"\r\x00\xc9a!<)\x894\x000\x11^Q\xa4\x01\x80\x87\xf0\x884@\x15,\x84'D\x1a\xa0\b\x16\xc2#\xd2\x00U\xb0\x10\x1e\x91\x06\xa8\x82\x85\xf0\x84H\x03\x14\xc1BxD\x1a\xa0\n\x16\xc2#\xd2\x00U\xb0\x10\x9e\x10i\x80\"X\b\x8fH\x03T\xc1BxD\x1a\xa0\n\x16\xc2\x13\"\rP\x04\v\xe13\x1di\xf4\r\xbf\x8d:K a!|\xa6#\r\xfe\"\x80 ,\x84\xa7\xccG\x9a\xb4\xfe\"\x80\xd1\v\v\xe1\x15D\x9a\xb4\xfe\"\x80\xd1\v\v\xe1\x11i\x80*X\bO\x884@\x11,\x84G\xa4\x01\xaa`!<\"\rP\x05\v\xe1\t\x91\x06(\x82\x85\xf0*\"͛_\r\xf8h\xa0O\xfeK\xeb\x95\x02F\x17,\x84W\x14i\x00\xe0!<\xa9\x884\x89g\xb7\x94_I\xf8\xfc\x90\xb8V\x1eqmz\xe0 ,\x84W\x10i\x0e\xee\xee;\xb2\xd9w\xe4%\xfd_\xef\xf1\xed136\n\x8f?bA\x1a͖\xcbEN\x93\xfd3_,+ʝ\xa3o\xd7\xffb\xceF\xfb\x19\x83\xe4\x13MLN6\a\xd8\xc2Bx\x05\x91慅7߬\xee6\xff\xed\xf9e\xf4\x84m9\xbb\xa2\x96\xa4\xd1ly\xc1k\\k\xd8\x06wᎥ\xb9\xd7\xe5h\xef\xb8m\xf6S\x06\x87\xff\xddZ\\\xd9xp\xb0\x10\x9e2\x1fizoҗ\x1f\a\xfeu_\x8cz\xb2C\xab\v\x0e\xaf\xba\xaf\x06\x87\xa9\x17\xfd\xc5\x11\xfe\x9a\xd8F\xfe.s\\\xaf\roC\x1a.\xe5=HX\b\xaf \xd2\x1cy\xa33\xfe\xf3\xb5\x85=\xc1\xe1)q*8\x1c\xb2\xf0gDkh\xdcUXk;g\xb0@\xf8A\xc2Bx\x05\x91fs\xf5\xf9\x81\xde8\xa7%\xfb\xf3\x9e6\a\xdbJ[?\x10\x1f\xec-}\xc5x\x14\x14>\\gI\x93\x03\xd7ٞN\xad\xfa\xed3\xe4\xd1o\xf5\xfc\xae\xadx\xa28\xbf\xea\x8c\x11\xe7w\x05\x02v\xff\x04s\xea\xaa\xc0\x0f\xa9\xcf\r\xbd\xa8\x02Xk2\xc7m[\x16\xdcBhh\xa9Ԍ\xe8ѼPS\x9c\xbf\b\x91f\x90\xb0\x10\x9e2\x1fi\x12\xfdE8!\xbc\xe6\xe0B\x8dxP\x94\x89E\x9f\x19\x8f\xc2E\u007f\xc1:K\xd2j\xbd:\xe5b#\xf5\x1c*Yv\x85\xae\xd4\xe7y\xf5̢\x89)M\x8de\xaeSf\x9c\x0f\x04\xec\x13\xdeF\xe1\xf1\x86*\x15\x0e\x89\xc3Q?6\xb2&\xb3\xe4yO\x89\xbe\x05\xcb\xd0R\xa9i\xed\xd1<\x93\xf7\xc0k-\x95\x02\xc2\x0f\x0e\x16\xc2+\x894\xf1\xff\"\xec\x15\x1f\x05\x87m\x9a\xd0\xda\x02\xe3\xa0\xf0\x96:K\xcf1}T+\x8c\x03P\xcf\x14\xfdf\xa9\x11T\xb4\xc9\xfa^\xb8\xa7\xb4\x9c\"\xbbr\xac\x91\x86.\x88\xe8S\x93\x115\x99\x13o\x10]/)\x8f\x18Z*5-=\x9a\xd3K{\xe4j\x10~p\xb0\x10^I\xa4\x89\xff\x17\xa1E|b\x0e\xae\xadҊE\xf1\xf8\xa7\xbe0\x1e\x852\xbc\xa5\xceR\x8f*\x8bǚgt.\x8c}\x9fn\xe5\xed\x97C\xed\x19y\xbbC\\K(|̹KkM\xa6q\xd4\xdc`l!4\xb4Vj\x86z4\xaf\x8b\x9d\xf2\xf9z\b?8X\bO\xceF\x9aw\x83fo\x9c\xb0\xe3\x94\xf8˶\"\xf3\xa4yPxk\x9d%\xf5\xccт{\xea\xca\xd5Ԗ\xdf/G\xe6A\xabW\x1cK |\xbb8D\x91\xc4\xd4dZ\xb6`\f-\x95\x9a\xe1\xed\xb6\x9b\xf9\v\a\xad\x83\x84\x85\xf0\x0eG\x9a\x9e\xd0Y\x96~\xe3,M\xbf\xf9\x1eTPxk\x9de\xd7\xf4\xf1\xc1\xc4C\xad\x13\xfa\xcdDC\x9aqd\xbaS\xdc\b\x88Yo#\xbcG\xeb\xa2H\"j2-[\b\r-\x95\x9aa\xe1\xbf\x10\r\xf2\xf9\xa5\x10~p\xb0\x10\xde\xe1HC\x8bJCo\xb3~\x96\xffYp\x18\x14\xdeRgym\x8aK\xee_[\xddry\u007fQk\xbe\x91hH+\xbe\xa5?|P.u=\xad\xcf}4Vx\xff\xe4\xaa\xe0\xf0\x93\x8d\x1d\xd1\xdb%\xadH\u007f9tMrG\f-\x95\x9a\x96\xbf\x1c\xe5%z\xee\xf9h<\x84\x1f\x1c,\x84'g#\r\x9d\xc9\xf9m\xf4\"K\xb3e\xb8\xce\xf2z\x99\xd8(O\xd3<a\xdaV7)\xff\xb61\xd0D\xe5\xe1\xfd\xe5\xf9\xf2з\xbc`\xe3\xf3\xe5bܮS\x81\xb34\xef\x06^J[dZ1\x99'\xe6\x18\xf7\xe1\xed\x9a\xe7yv\x96\x1a[\xb0\fC\x95\x9a\xd6\x1e\xcdS\xae\x12O}~\x8e\xfc\x11 }X\b\xefp\xa4\xd1w\xa2\xe3\xa3\x03\xb6\xa5\xd92\\gyb\\`i\x891\xe7#\xb1̜\xfc\xa0gq^q\x8dq\x02\xf2\x8c;7\xaf\xf2\x19!\x96\xdf\xca7f\x8e\xfb\xc0\x98\xe1\xcd}*\xb4\xe9\xd7\nv\x18\xf7\xe1\xedꖯ\xae\rn\xc12\fUjF\xf4h\x9e\xa9ʟ\xf8Ԯq\xa8\xd4\x1c\x14,\x84w:Ґ\u007f\x85\x16\xe7\xf3_\x89\xe8\xd2\x0e$\x9b\x12\xa0I\xab\xbd\x9dp\x82\xe5\xbd\xdax\x1f\xcc\x01\xc3\x02\v\xe1\xc9\xe1H#\xf7\xb6\xc5W)]\x9a&$\xb68ĵ\u008d\x91\x9fŌ\x01«\x82\x85\xf0\x8eG\x9aA\xe09\xe0w\xd7'\x9b\x942\x10^\x15,\x84w<ҤO\x8f\x98\xb2\xbc\xf0z\xb2Y)r\xc18&\x8d\x1e\x82L\xc0Bxr<Ҥ\x8f\xc7\xe5\xfe ٜT1\x8eI?\x89\x1e\x82L\xc0B\xf8\x91\x18i\xc0Ȅ\x85\xf0#0Ҁ\x11\n\v\xe1i\x04F\x1a02a!<\"\rP\x05\v\xe1\x11i\x80*X\bO\x884@\x11,\x84\xcft\xa4\x01 \b\v\xe13\x1di\x06Pj\x06\x02\xb0\x10\x9e2\x1ciҝ\x0fF/,\x84W\x10iҝ\x0fF),\x84W\x10iҚ\x0fF/,\x84'D\x1a\xa0\b\x16\xc2#\xd2\x00U\xb0\x10\x1e\x91\x06\xa8\x82\x85\xf0\x84H\x03\x14\xc1BxD\x1a\xa0\n\x16«\x884(5\x03\x12\x16\u0093\x9aH\x03\x00\x0f\xe1\x95D\x9a\xc4/\x0f\x94\x9ae\t,\x84W\x10ix\x96\x9a\xed/\xb0\\}2\f:\xcb2\a\v\xe1)\xf3\x91\x86g\xa9Y\xab\xcbv\u05cfβ\xcc\xc1Bx\x05\x91\x86i\xa9Y\xbc\vr\xe0jؙ\x82\x85\xf0\n\"\xcd\b+5\x83\U00019085\xf0\x94\xf9Hð\xd4\xecz\xae\x109\xb2\xce&ngY\xa8\xd4\xec\xd48!\xaa\xfc%B\xe4\xdf\"0$X\b\xaf \xd2$\x9a\xefP\xa9\x19\xb5{\xbd㍿\r\xf1:\xcbB\xa5f\xfeÞ\x9côk\xec\xae\x13\xd1\xdb\x00i\xc2Bx%\x91&\xfe|\x87J\xcd$\xb9\x810d\xdbYf-5\xf3/-\xbfZ2\xbc\xfd\xf5\xd9\t\v\xe1IE\xa4\x89?ߩR3\xb2\bo\xd7Yf-5\xa3\x9e\x87\x8b\xaap\xcdɡ\xc3Bx\x87#\x8dC\xa5f\x92\x90\xf0v\x9de\xd6R3\xf9\xb2\xb4\xdb\x00H\x13\x16\xc2;\x1ci\x1c*5\x93\xc4\bo\xed,\xb3\x96\x9aх\xc2\xfa\x92/l\xb6\x00҃\x85\xf0\xe4l\xa4q\xa8\xd4L\x12#\xbc\xb5\xb3\xccZj\xd6_^O\xcb\xdc\xc84C\x86\x85\xf0\x0eG\x1a\x87J\xcd\xfa\xdf\xf1z\xc7\xd7z\xbd7\xe2v\x96\x85J\xcdz\x0e-/\xb8@\x1dy+\x0e\xe1\xb4\xe4\x10a!\xbcÑơR\xb3\xa39\xe6\xc6v\xc4\xef,\v\x96\x9a\xb5\x19'\xf4W\b16\xd5V)\x10\a\x16\u0093Ñ\xc6\xf9R3\xa0\n\x16\xc2;\x1di\x9c/5\x03\xaa`!\xbc\xe3\x91f\x10\fo\xa9\x19P\x05\v\xe1\xc9\xe9H\x93>\xc3Zj\x06\xd4\xc1Bx\xe7#M\xfa\fg\xa9\x19P\a\v\xe1Gb\xa4\x01#\x13\x16\xc2\xd3ȋ4`\x84\xc2B\xf8\x91\x18i\xc0Ȅ\x85\xf0\x884@\x15,\x84'D\x1a\xa0\b\x16\xc2#\xd2\x00U\xb0\x10>ӑ\x06\x80 ,\x84\xa7\fG\x9a\x01\x94\x9a\x81\x00,\x84\xcft\xa4I\xf7\x05\x02F/,\x84W\x10i\xd2z\x81\x80\xd1\v\v\xe1)\xf3\x91&\xdd\x17\b\x18\xa5\xb0\x10\x1e\x91\x06\xa8\x82\x85\xf0\x884@\x15,\x84'D\x1a\xa0\b\x16\xc2#\xd2\x00U\xb0\x10\x1e\x91\x06\xa8\x82\x85\xf0\xa4 Ҡ\xd4\fHX\b\xaf(\xd2\x00\xc0Cx%\x91&\xf1n\x1d\xa5fY\x02\v\xe1)\xf3\x91\x86g\xa9YRⴞ\x81A\xc3Bx\x05\x91\x86g\xa9Y\x98\x03\xc7Ȏ8\xadg`а\x10^A\xa4aZj\x16\xe2\xd1%\xf6\xcbq\x01\xa7a\x86\x85\xf0\x94\xf9Hý\xd4l\xea\xe2\x84O\x83ႅ\xf0\n\"\r\xc3R3\xf2V\x96hEsJ\xfc\xc6\xc6$S\x88N\x8e\x13\xa2\xfeL\xcd\xc4\xdc\xca\xdb\xf1ZϮ\xd6L(^\xbdz\x82k\x10W\xc3\x04<\x84W\x10i\x12\xbd@\x1c*5;:vi\xcb\xfe\x9dE\xe26u\x1d\xf2\x96N\xd77\xfc\x81,\x94j,)\xcd+YU3\xf6\xd38\xadg\xfd\x0f\x166x\xc6\xe7\xee\xac|\x99@\xfa\xb0\x10\x9eTD\x9a\xf8/\x10\x87J\xcd\x1a\n\xe4\xb5X\x1b\xf2\x8d\x98n\x894S\x85\xfb\x06\xf9o\x98\x0fb[Ϛ\x84\xfeǦ!\x9c\xbc@Z\xb0\x10^I\xa4\x89\xff\x02q\xa8\xd4\xec\xb3\xe2\x89+v\x9e\xf0\x1b-Q\x11\xc2k\x9f\x86'Ŵ\x9eQ]>\xc9K\xd3\xe3\xec\xcd\xe0`!\xbcÑƩR\xb3\xeb;\x16O\x16E\x1bc\xf6\xf0S,sb;q^\x1e{U6$`\x0f?8X\bO\xceF\x1a\x87J\xcd\xda\xeb\xf4\x9fs\xbd1\xb7A>0\x84\xdfi\xecڧ.\xb2L\x8a\x15\xfeӜ\xcaOO\x96\x96\xe3|\xe5\xe0`!\xbcÑơR3\x8f0^;n\xa37ǭ\xaf|\xc5L=\x11g(c\x85?&\x8a\x84p'>\xab\x0f\xe2\xc2Bx\x87#\x8dC\xa5f\x1e\xe1\xaaom\xa9\x15Fo\x8eG\xdb\xd2\xe2v}F\xb7\x0f\x1b'l>\x91\xcb\xec[ώ\x8d\u07ff\xd7{\x01;\xf8A\xc2Bxr6\xd28Tj\xb6k\xba\xa7D+t\x9b=Q\xb7V\xe4\xe7No':i6\x9d\x19\u007f\x0e\xec[\xcf\x0eir\x996\x1d!~P\xb0\x10\xde\xe9H3\x92Jͮ\xb8\x96]\xb9}\xfb\xfa\xd1\x05\xf9\xe8\x1f\x19\f,\x84w:Ҍ\xa4R\xb3\x16\xf3\xbc=\xf9\x8bBG\xcf \rX\bONG\x9aA\xe0T\xa9ٱ\x1c3˜\xca9\x91d&\xb0\x83\x85\xf0\x8eG\x9a\xf4q\xac\xd4\xcc_\x9b\xbb\xac\xe9@Ӳ\xdce\xc3\xf6G#\xab`!\xbc\xf3\x91&}\x1c+5\xf3\xb7V\x16kŕ\xad\xf0}P\xb0\x10\x9eF`\xa4\x01#\x13\x16\u008f\xc0H\x03F(,\x84\x1f\x89\x91\x06\x8cLX\bO\x884@\x11,\x84G\xa4\x01\xaa`!<\"\rP\x05\v\xe1)Ñ\x06\x80 ,\x84\xcft\xa4\x19@\xa9\x19\b\xc0B\xf8LG\x1a\xfcE\x00AX\bO\x99\x8f4i\xfdE\x00\xa3\x17\x16\xc2+\x884i\xfdE\x00\xa3\x17\x16\xc2#\xd2\x00U\xb0\x10\x9e\x10i\x80\"X\b\x8fH\x03T\xc1BxD\x1a\xa0\n\x16\xc2\x13\"\rP\x04\v\xe1UD\x1a\x94\x9a\x01\t\v\xe1\x15E\x1a\x00x\bO*\"M:\xb3\xc1\xa8\x85\x85\xf0\n\"M\xdcR3\xef\xd8\xc0ŕƟ\x8c\xbb~\x98\x93s&\xe4M?Pv(y\xebY\xfc\xaa3\xe0$,\x84W\x10i▚\xdd:T8G^>o\x97H\xe1:/Ǵ\xaa\x96]\v\x8c֏d\xadg\xf1\xab\u0380\x93\xb0\x10\x9e2\x1fi\x12\x94\x9aM4.\x98\xf7Q*\xc2W\xba\xfdF#\x82\xb9\xefNR\x02\x05\xe19\xc2Bx\x05\x91&A\xa9\x99)|\xff\xb6\x1b\xf1&\x84\x99h\\z\xe9d\xa0\x8d\x00\u008f@X\b\xaf \xd2$(5\x9b\x18\xb8$jD\xa1\x18\xf9_\x99\xe2z\xb8\xc1O\xb7\x8b\xb4\xdf\x14\x17\x1fX\x91\xef\xee\"ZR(/\xfb\xe5\xdfk^\xeaݦ\xf5,\\T\xa6\v\xffT\xa8\x87\f\xb0\x81\x85\xf0\x94\xf9H\x93\xe0/\xc2\xc4ڞ\x9e\x97e?SD\xa1\xd8R\xad~o\xbdVKt O\xacr\x8b\t\x1b\x8b^&\xfa\xa4$\xa7\xd2s\xb8?\xb0\xa2M\xebY\xb8\xa8L^D{rcKт8?\x158\x03\v\xe1\x95D\x9a\xb8\u007f\x11&\xcas4\x85\xe68T(\xd6fDz㶰\x86\xf6\x8aVZ*\xff\x10\\{\xfeQM\xe4\aN\xbfش\x9eY\x8bʴ\xc2/\x88j\vb\u007f p\x10\x16\xc2+\x894q\xff\"L\xacjo_\x1a\x14>X(VkV:=\xa8\xef\xe2\v\x1b\xe9]\xd1EOט\xcf\xdc\xda_)\xf6\x1a#\x9b\xd63kQ\x99&_!\x81\xba'\xc0\x05\x16\u0093\xb3\x91F\x17\xf3\xd4Ns\x1c*\x14+7\x1bj\xaa\xf4\xa8S\xd8F\xed\xba\xb6u\xba\xf0\xedF\"\xf7\a\x9e\xb4k=\xb3\x14\x95Y\xfb\xcd\x00\x17X\b\xefp\xa4Y\x16\x1e\x87\n\xc5j'Ig\xfd\x13\x97F\b_\xb8\xc2x\xb2\xbeԸ\xb3i=\xb3\x16\x95Ax\x8e\xb0\x10\xde\xe1Hc\x15~q`\xb0W\xc8\xce\xf7F\x19^,\xc2\x17\x15_ӗ\xfa\x03/\v\x9b\xd63kQ\x19\x84\xe7\b\v\xe1\xc9\xc1Hs\xeb\x9d\xc29\x87\xccӌ\xd6B1\xaaɩk\xad\xcb\xd1%?\x95\xffrO\xa3v\xb2\xa7\xc6}\x81\x8aD\xa1\xa7\xadŝ\xfbQ\x9c\xd63KQ\x99\xb5\x87\f\xf0\x81\x85\xf0NF\x1a\xe3\xb34f\xb7\xb6\xb5P\x8c\xfc\xdb\xca\\e\r~\xf2\x17\tј'\\MḄGw\xd6\xff\xccU0O\xd6\xf5ٶ\x9eY\x8aʬ=d\x80\x0f,\x84w6Ҁl\x82\x85\xf0\xe4`\xa4\x01\xd9\x05\vᝌ4 \xbb`!<\"\rP\x05\v\xe1\t\x91\x06(\x82\x85\xf0\x884@\x15,\x84G\xa4\x01\xaa`!<!\xd2\x00E\xb0\x10\x1e\x91\x06\xa8\x82\x85\xf0\x884@\x15,\x84'D\x1a\xa0\b\x16\xc2g:\xd2P\xfa\xf3\xc1(\x85\x85\xf0\x99\x8e4\xe9\xce\a\xa3\x17\x16\xc2S\x86#M\xba\xf3\xc1腅\xf0\x884@\x15,\x84G\xa4\x01\xaa`!<!\xd2\x00E\xb0\x10\x1e\x91\x06\xa8\x82\x85\xf0\x884@\x15,\x84'D\x1a\xa0\b\x16\xc2#\xd2\x00U\xb0\x10^E\xa4A\xa9\x19\x90\xb0\x10\x9e\x14D\x9a\xb9(5\x03\xc4Dx%\x91&\xe5\x97\a\x18Ͱ\x10>ӑF\xe7\xf8\xbe\x81\xe3\u007f\xf0\x05\xfe\xbd\x9elv\xf2\xce2\vޱ\xa2\xdcO-B\x8cݟl\xaay\xad\xa7\xdad\xb3@\xe6`!<e>Ҭ\x99ֽ=\xf0\xef\xab7\x9eL\xb6B\xf2\xce2\v=\xfbE\xae\x97\xbaZ\xc4\xfe\x9edS\xe9\xf6;\x0f\x97y?K6\vd\x0e\x16\xc2+\x88\xc7O\xf3\xe3\x00\x00\x0e\xfdIDAT4\x83 I\x85S\x98.Q\xa3\xef\xb4?\x11]\xc9&J\xdc\xeed3@&a!\xbc\x82H3\b\xd2\x10~\xbf\xab\a\u008f\fX\bO\x19\x8e4\x89h\xd2C\xb5\x87<\xc2(_\r6\x99\x19\x04\x84_.rv\xd1'\x9a\x98\x1c\xd9oF\xfe]\xe5\xae\aV\xcb\x14\xd3%>\x99\xdab\n\x1f\xea7\x8b7\xd7*|h\xe9r\xa1\xedD\x01\x9a\x1aX\b\xefd\xa4\xe9\xf2\xe6\xd5_\xa1+\xf5\xf9\xde.K\x93\x99$ \xbc\xd10\xec\u007f\xb7V\x8b\xec7\xa3ڜ\x15{\xb7\x15L\xf5\x1b\xc2o\x9bc\n\x1f\xee7\x8b3\xd7*|h\xe9_\x1alj\x02\xcfo\xf3P\x80\x96yX\b\xefl\xa4\xa9]\xa2\xdf\xd4<A\x11Mfd\x894\xe1f\x03K\xbfY\xabq\x8d\xedvٛ\xa0\v\u007fu\xfcUCxK\xbf\x99\xfd\\\x8b\xf0֥Z\xbe\xbew\xafA\x01Z\xe6a!<9\x18i\xf4}qn\x0f\xf5\xb8\xbc\x14\xd1dF\xf6\u0087\xfb͖L꿭S\\k\bOs\xb6\x98\x19>\xdcof?\xd7\"\xbcu\xa9\xb6\x94\xd0\x16\xa2\x04\x16\xc2;\x19i\xf4\xb8=\xa1\x85Z\x8adܰ4\x99\x91\xbd\xf0\xe1\xf6\x9b\xb2@!\xc2<S\xf8\x96\x87\r\xe1-\xfdf\xf6s-\xc2[\x97\xa2\x1eG\x15,\x84w6\xd2Њy\xb4\xc0h+\xb34\x99Q\xb4\xf0\xf5Q\xc2\xd7L:fp\xd5\x14\xbeǵ_\no\xe97\xb3\x9f\x1b\x10\xbe\xab\xfeZ\xc4R\b\xaf\n\x16\u0093\xa3\x91\x86\x0e\x8f\xbf4\xfe\xb0\x1cX\x9a\xcc\xc8\"\xbc\xebi\xfdU\xf0h\x94\xf0m¨'\xae\xdfh\nOKk\xa4\xf0\x96~3\xfb\xb9\x01\xe1O\bo\xc4R\b\xaf\n\x16\xc2;\x1bi\xc8_\\Yl\x9e\x8a\f5\x99Y;˨\xbc`\xe3\xf3\xe5bܮS\xd6~3\xaa\x1b[\xd3\xd2R\xab\x1fx\xf6\xec\x17-]\xe4͕\u0087\xfb\xcd\xec\xe7\xde>\xfcp\x99Wg\x87.|x)\n\xd0\xd4\xc1Bx\x87#\rmѶ\x98\x83`\x93YDg\x19\x9dq\xe7\xe6U>#\xc42k\xbf\x99\xbe\xdfvOȟަ\x1f\xf4\x8e\x95\xe7\xf0\xfd\xe5\x85~K\xbf\xd9t\xfb\xb9\x81\xde4!r?\xb0,E\x01\x9a:X\bO\xceF\x1a\x90E\xb0\x10\xde\xe1H\x03\xb2\b\x16\xc2;\x1di@\xf6\xc0BxB\xa4\x01\x8a`!<\"\rP\x05\v\xe1\x11i\x80*X\bO\x884@\x11,\x84G\xa4\x01\xaa`!<\"\rP\x05\v\xe1\t\x91\x06(\x82\x85\xf0\x884@\x15,\x84G\xa4\x01\xaa`!<!\xd2\x00E\xb0\x10\x1e\x91\x06\xa8\x82\x85\xf0\x884@\x15,\x84'D\x1a\xa0\b\x16\xc2#\xd2\x00U\xb0\x10\x1e\x91\x06\xa8\x82\x85\xf0\x84H\x03\x14\xc1BxD\x1a\xa0\n\x16§\x1ci\x8e\x9f\xfd\xf0|g\xe4\x9cΏϞ?\x8b}=H\x11\x16\xc2S\xaa\x91\xc6\x17\x1a\x1d߇]<\x18\x04,\x84O9\xd2\x04\xe6\xe87\x1bf\x9eC\x86\a\xe9\xc3B\xf8\x94#Mx|\xf1\xbd\xf0\xde\x1e\x80\x94a!<\xa5\x1ai:\xa5\xf0\x03\x92s\xc7o\xca;\x9b\x95\x00H\x00\v\xe1Ӎ4}\x884`\x90\xb0\x10>\xe5H\x13\x8e1_\x9e\x8e\x9e\f@\n\xb0\x10\x9eR\x8d4\x92\x8bG\xf6\xed۷砼\xddw\xf08\x92<H\v\x16§\x1ci\xa4\xfb\u007fxlƴG\x1e\x996M\xdeTW_F\xb0\x01\xe9\xc0B\xf8\x94#\x8d\x91\xde+v\xbf\xbd\xef\xed\xf7\xce\x1f\xdc\xf7\xf6ۿ~\x04I\x1e\xa4\x05\v\xe1)\xe5H#\x85\x9f-cL\xe7A\xf9p{\xc59\x99\xebq\xb2\x06\xa4\n\v\xe1ӊ4\xf2\xfc\f\xd1}_;H8W\x03҆\x85\xf0iE\x9a\x17f|\xa8\x0f\xee\xbf\xe3\xa2~\xbb~\xe6\xd9\xe8u\x00H\x04\v\xe1)\x9dH\xf3\xdcc\x9dG\x1e\xff\xe5\xf7\xbf>\xed\xf1\xb5\x03\xdbg\\>\xbd\xa7\xef\xf4\x1e\xcb\xca\x1e\xa1\xb5\xe8w{]\xc2\x13\xb3\xbdh\x96\x8b\x9c\xa6ds\xc0肅\xf0iE\x9auմ\xe6\x8e;\xbe\xa6\xffw\xb7\xafyF\xf7\xeb\x15\xddoL;\x1b~Q\\\xadq\xc9\xda0wn\xcd\xd5\xc8-\x1d8F\xd1\x18%\xdb \xab`!|Z\x91\xe6\xb9\xc7>?\xfe\xec\xda\xff\xfb\xf5\xeag7\x0fl\x9fy\xf1\xdc\xc1\xbes\aoZV\xaa\x9b\xe3\xbaN\xd7r\xe7\xd4Em\xec\xd1%\x14\v\x84\xcf6X\bO\xe9D\x9a\x17f\xc87Y\uf2db\xe1\xebj\xdcM\xb4\xab\xb2&Z\xf8\xa9\x8bc\xa6B\xf8샅\xf0iE\x9a\r3?\xd6\a\xff\xfc\x8d\x83d\x9e\xa5\x89~\xaf\xb5\xae\xa6a\x01\xcd\xd9!\x85\xbf\xb1\xb8X+\xa9:\xa9/l\r\x94\xe7M1\xa6\x9cYT\xa4\x15ι\xa0\x8f\xb4\xa7V=઼@ [`!|Z\x91f\xc3\xec^}\xe03>K\x138\x0f\x1fA]\xcd\x05\xd7\x17\xe3/I\xe1[Ų\x03MU9\xedD]\x87\xbc\xa5ӽ^\xaf,\x8b\xa4\x03\xae)/\xee\xf7\bYU\xa9\x89ɍ-E\v\bd\v,\x84\xa7t\"͆Ƕ7\xefn>rz\xdf\xee\xe6\xe6'm\xdei\xad\xab\xa1\xb2e\x8f\x92\x14\xbe\xa7\xa9\x8b\xc8_6\xcfX\x1e\x8a4=%\x95\xb7\x88\xfa\x9b\xae\xe9c\xad\xf0\v\xa2\xda\x02\x02\xd9\x02\v\xe1ӊ4o̝9\xed\x11\x93i\xd5\vc?K\xa3\v\xff\xa2\xd8h\bOW\x1b*'\xe5\x892cyH\xf86q\"4Y[F\xa8|\xcf*X\b\x9fz\xa4ѹ|\xfc\xa0\xce\xdbo\xcb\xdb\xe36\xdf{҅\xbf\xfa\xd4\x15C\xf8\xf6\u0092\xa7[\xbc\xee(᷈\x9e\xd0d\xe3\xa0\x15\xc2g\x11,\x84\xa7\x94#M\n\xe8\xc2K\xa4\xf0\x93˥ڋ,\xc2\xef\xfc\x94h\xbf\b\x9f\x91\x87\xf0\xd9\x06\v\xe1S\x8f4)`\x11\xbed\x91>\xf0?l\n\xefv\x13]\x11M\xfa\x01l\xa1\xbb_\u007f\xbcb\x15A\xf8샅\xf0iE\x9a$|Q㾤\xdf]r\xd7|A\x1e\xb1\xb8\xe1\xf9\xa9\xa2\xe8\xc5wIj\xbd\xa5\xc5\xed\xfaL\x1f\x1d\x18\xff\xe0\x8e\xb6\x15b']\xf2j\xb5\xef\xfaO\xd4j\xdeKI\xb6\nF\v,\x84\xa7a\x8c4\x1e!\x9e\xd0\xef\x96\t\xe1!\xff\x96R\xad`\xc9k\xa5\x9a\xfc\xb0\xc1\xad\x15\xf9\xb9\xd3ۍ9\x1f-.\xce+o\x91\x9f\xa5\x11B{ߥ\xdf.O\xb8M0z`!\xfc\xb0F\x1a\x00\x12\xc0B\xf8\x94#\r\xec\aC\x84\x85\xf0\x94j\xa4\xe9L/\xcf\x03\x10\r\v\xe1S\x8e4i\x1e\xc0\x02\x10\r\v\xe1S\x8e4\x10\x1e\f\x11\x16\xc2S\xaa\x91\x06\u0083!\xc2B\xf8\x94#M7\x84\aC\x83\x85\xf0)G\x1a\x00\x86\b\v\xe1)\xd5H\x03\xc0\x10a!|ʑ\x06\x80!\xc2BxD\x1a\xa0\n\x16\xc2\x13\"\rP\x04\v\xe1\x11i\x80*X\b\x8fH\x03T\xc1BxB\xa4\x01\x8a`!<\"\rP\x05\v\xe1\x11i\x80*X\bO\x884@\x11,\x84G\xa4\x01\xaa`!<\"\rP\x05\v\xe1\t\x91\x06(\x82\x85\xf0\x884@\x15,\x84G\xa4\x01\xaa`!<!\xd2\x00E\xb0\x10\x1e\x91\x06\xa8\x82\x85\xf0\x89\"͛_\r\xf8h\xa0O\xfeî\x1e\f\x19\x16\xc2S\x82H3\xf7c\x9b'\x00\x18$,\x84O\x18i\xb0[\a\xc3\b\v\xe1\x13\x1c\x9c\x1e\xdf7p\xfc\x0f\xbe\xc0\xbf\xd7-O$-\x15N\xa7\xa1\x18d\r,\x84\xa7\xf8\x91fʹ\xee\xed\x81\u007f_\xbd\xf1\xa4幤\xa5\xc2\xe94\x14\x83\xac\x81\x85\xf0\x83;ߞ\xacc5\xad\x86b\x90%\xb0\x10~p\xe7ۓ\n\x9fNC1\xc8\x12X\bO\x83:\xdf\x1e.\x15\x0e\x17\x10\x13y+K\xb4\xa29%\xfe\x88\x86b\xf2\xef*w=\xb0\xba'\xb2\xa1غ\x1a\xc8\x12X\b?\xc8H\x13*\x15\x0e\x17\x10\xd3ѱK[\xf6\xef,\x12\xb7#\x1a\x8a\xa96g\xc5\xdem\x05S\xfd\x11\rŖ\xd5@\xb6\xc0B\xf8AF\x9aP\xa9\xb0\xa5\x80\xb8\xa1\u0dbc\xcd\xf7G4\x14\xb7\x8a]\xfa\xd2v\xd1(\xd7\v7\x14[{\x8bAv\xc0Bx\x1a\\\xa4\t\x97\n\x87\v\x88?+\x9e\xb8b\xe7\t\xbf\xac\xe9\xb34\x14/\x99\xd4\u007f[\xa7\xb8VN\x0egxko1\xc8\x0eX\b?\xc8H\x13\xaa\x9c\xb4\x16\x10_߱x\xb2(\xda\xe8\x8fh(.\v$wcg\x1e\x12>\xa2\xb7\x18d\a,\x84\x1fd\xa4\t\to) n\xaf\xd3U\xbfޘ\xdb\x10Q\xd8Z3阁qF>\xd4P\x1c\xd1[\f\xb2\x03\x16\xc2\xd3\xe0\"MHxK\x01\xb1G\xb4\xc9\xe7\xdc\xcb\"\x84o\x13ƻ\xb2\xf5\x1b\x8d\xe7\x82\r\xc5\x11\xbd\xc5 ;`!\xfc`\"\x8d\xb5T\xd8R@\xec\x11\xae\xfa֖Zq \xa2\xa1\x98\xea\xc6ִ\xe8K\xe5\xa1k\xb8\xa18\xa2\xb7\x18d\a,\x84\x1fL\xa4\xb1\x96\n[\n\x88wM\xf7\x94h\x85\xee\x03\x91\r\xc5\xfa>\xde=!\u007f\xba\xb1\xf3\x0f7\x14G\xf4\x16\x83쀅\xf04\xa8H\x03@\xfa\xb0\x10~0\x91\x06\x80\xc1\xc0B\xf8\xc1D\x1a\x00\x06\x03\v\xe1\t\x91\x06(\x82\x85\xf0\x884@\x15,\x84G\xa4\x01\xaa`!<!\xd2\x00E\xb0\x10\x1e\x91\x06\xa8\x82\x85\xf0\x884@\x15,\x84'D\x1a\xa0\b\x16\xc2#\xd2\x00U\xb0\x10\x1e\x91\x06\xa8\x82\x85\xf0\x84H\x03\x14\xc1BxD\x1a\xa0\n\x16\xc2#\xd2\x00U\xb0\x10\x9e\x10i\x80\"\xb8\b\x0f\x80\x12X\b\xaf\x87\xf7\xb7\xb7w\"Ã\xcc\xc3Bxdx\xa0\n\x16\xc2\x132<P\x04\v\xe1qZ\x12\xa8\x82\x85\xf0\x884@\x15,\x84'D\x1a\xa0\b\x16\xc2#\xd2\x00U\xb0\x10\x1e\x91\x06\xa8\x82\x85\xf0\x84H\x03\x14\xc1Bx4n\x03U\xb0\x10>\x10i\x00\xc88,\x84'4n\x03E\xb0\x10^\x8f4\aw\xf7\x1d\xd9\xec;\xf2\x92\xfe\xaf\xf7\xf8v\xeb\x93\xc7r\x8c\xf2\x8e\xd8\xee\xb1-\xe3\u007f+\xef\x92Vr\x03\x10\x86\x85\xf0\xfa\xce\xfd\x85\x857߬\xee6\xff\xed\xf9\xa5\xf5\xc9\xdb\xefx\x1b\xc4\x16\xef;\xfd\xd1k\x95iF\x95A\xd2Jn\x00°\x10^\xa7\xf7&}\xf9q\xe0_\xf7Ũ'\xdb\xc5;\xb1kt\xe5\xd4\xe4t\x19#\b\x0fR\x86\x85\xf0\xc6\x1bO\x9d\xf1\x9f\xb7\x15\xde+\x8e\x89\x03\xc6\b\u0083\x94a!\xbcq\x96\xe6\xfc@o\xbcӒ!\xe1\xc35\xdbD\x9eb*6M\xd7V<Q\x9c_u&z\x02\x00\xb1\xb0\x10\x9e\x92\xbc\xf1\x14\x14\xdeR\xb3M\xe4^D\x8bͮ\x1aMLij,s\x9d\x8a\x9a\x00@,,\x84O\xf6Y\x9a\xa0\xf0\x96\x9am\xf2\xbb\xb6\xd0\xcb.cW\xaeM\xee!\xea)-\x8f\x9c\x00\x80\r,\x84O\xf6Y\x9a\xa0\xf0\x96\x9am:)\x0e\xf5\x1c\x12'\xe5P{F\xde\xee\x10\xd7\"&\x00`\x03\v\xe1)\xc5Hc\xa9٦m\xc6\xd9\xf9mr\xa9yЪ\x1f\xc4FL\x00\xc0\x06\x16§\x1ai,5۴hJ{{\xfb\x14Y-L\xda*y\xbbS܈\x98\x00\x80\r,\x84O5\xd2Xj\xb6\xa9x\xb5~\xb3\xaaX>֊o\x11\xf5?莜\x00\x80\r,\x84\xa7D\x91&\xf0N\xeb\xe1~\xb2\xd4l\xf7\xb4\x89\xfa.\xea\xfa\x8dh\xbb%\xcf\xd2T\x1e\xde_\x9e\xff\x91u\x02\x00\xb6\xb0\x10>a\xa49\x11\xfe,M\xb8f{\xffX!\x9a\xa8E\x88\xb1\xfb\x89\x1e\xf4,\xce+\xae\x91=\xf3\xe1\t\x00\xd8\xc2B\xf8d\x91\x06\x80ႅ\xf0\x84o<\x01E\xb0\x10>\xd9Y\x1a\x00\x86\v\x16\xc2#\xd2\x00U\xb0\x10\x9e\x10i\x80\"X\b\x8fH\x03T\xc1BxD\x1a\xa0\n\x16\xc2\x13\"\rP\x04\v\xe1\x11i\x80*X\b\x8fH\x03T\xc1BxB\xa4\x01\x8a\x80\xf0 \xab`!<2<P\x05\v\xe1\x91\xe1\x81*X\bO\x884@\x11\xce\n\xbf\xc7\xd7\xd9\xeb\xeb\xeb\xd3\xff\x1d|\xb3S\xde\xf5Q_o\xaf\xaf7\xd9z\x00\f\x12g\x85?B>y\xa7g\x99M\xb3\xcf!Ҁ\xcc\xe3\xac\xf0\xbeШ\xf3\\x\f@\xc6pVxyb\xe6\xf8\xeeM\x1b\x9e[\xff\xec\xda\xf5ϭ\xdf\xf0zs7\xceՀL\xe2\xb0\xf0z\x8aٺp\xf6c\xb3fUϟ=k\xd6c\xd53.\"\u0600L\xe2\xbc\xf0\x1b\xa6\x1d9\u007f\xf6\xfcM\xba|\xf6\xfc\xf9g\xa7!Ƀ\x8c\xc2@\xf8\x8a\x9b\xfa`\xdfJ\xf9pkŹ\x81^\x94\x9a\x81\xcc\xe1\xbc\xf0/\xcc\xfcP\x1f\xfc莃\xfa\xa3\xe7f\x9eK\xb6\x06\x00C\xc1y\xe17\xcc<\xab\x0f\xee\xbfCޮ7\xc6\x00d\f\xe7\x85_?\xb7{\xf7}\xf7\xde\xfd\xb5\x1f\xdc\xf7\xf3\xbe7ft\x1e\xdc\xe0;\xbe9jV\x8b\xbc\x12\xd3\xc4\xe8+\xa4\xee/h%\x00\xd2\xc3y\xe1\xd7U\x0f\xac\xfd\xc6\xd7\xff\xee\x8eo|\xe3;\xbe\xe6\x19ݻ\xa3K\xcdt\xba\x0ey\xf3\x16\x9d\x8a^\xb7\xd5\xd5\x12\xbd\b\x80$8/\xfc\x86\x8a\x8b\x9dǏ\xdf\xfb\xf5\xed\xc7ߣ\x97f\x9e\xef>Oݗc'\x16\xad\x8e]\x86\x8bb\x83\xb4q^\xf8\x17f\x9c\xd6\a\xf7\xca\f?\xb0~V\xbc\fo'<\x00i\xe3\xbc\xf0\x1bf\xc9\x1d\xfa\xac\xefI\xed7͌wZ\xd2\x14\xde\xff\xca\x14\xd7\xc3\rr\xcf~=W\x88\x9cF\xb9l\xb9\xd0v\xaez\xc0Uy!v%\x00\xa2a |ŗ\xa1\x87\x9b+\xe2\xbd\xf1d\n\xbfT\xab\xdf[\xaf\xd5\xcaa\xbb\xd7;\xdeh\xfe\xf8K\xe38Q\xe0\xf9m\xde\x02\xdb\xf5\x00\x88\x80\x81\xf0\xf3\u05ec\u007fv\xdd\xd6ן{v\xdd\xfa\xf9\x8f\xc4\xfb\x1a\x88!|\x9b\xd1w`\xde\xea\xe4\x06\xfaY\xb5|}\xef^S`\xbb\x1e\x00\x118/\xfc\x9e'\xab\xe7Ξ]QQ1{\xf6\xdc'Wv&\x12\xbe\xd6蚧\ak\xcde!\xe1\x97\xea7\x1e\xcdv=\x00\"pXx\x9d\xde\xce\xcb:_\xf5~\xae\xdfv~\x15o\x96!|y\x951\xae*7\x97\x85\x84\x97\xf7\x10\x1e\xa4\x82\xf3\u0093\xf1!\xe1͏w\xc6\xf9`\xf0\xed\x0f\xe4A\xea\x04c\x0f?\xc9hh\x9d\xb8\xd4|\x06\u0083\xb4q^\xf8\x01\x9f\xaf\xdb\xe7{|\xda\x11_w\x9f\xcf&ϼ\"\xbcDW\x8d\x82ʽB\x9e\x97i\x14{\xcdg <H\x1b\xe7\x857\xe9\xee\x8c\xf7ŏ\x03bNˮ\xf2\t\x9f\xc9qMN]k]N\x8d>\xea\u007f\xc7\xeb\x1d_\xeb\xf5ޠK^\xad\xf6]\xff\x89Z\xcd{)\xce\x16\x00\b\xc1Bx\x1f\xd1\xf6'\xcfR\x9c/\xf9\xb5Lu\xe5W\xbdo\f\xfd\xdb\xca\\e\xc6y\xf8\xa3fՙ\xd8A\xcb\xf5[\xed}\x97~\xbb\xdc~}\x00°\x10\xbe\x97H\x8f4\x84\x8b\x15\x80\x8c\xc3BxJ\x14i\x00\x18FX\b\x8fK\xed\x01U\xb0\x10\x1e\x97\xda\x03\xaa`!<\xe1R{@\x11,\x84G\xa4\x01\xaa`!<\"\rP\x05\v\xe1\t\x91\x06(\x82\x85\xf0\x884@\x15,\x84G\xa4\x01\xaa`!<!\xd2\x00E@x\x90U\xb0\x10\x1e\x19\x1e\xa8\x82\x85\xf0\xc8\xf0@\x15,\x84'D\x1a\xa0\bg\x85G\xa9\x19P\xcc\xff\x0f\x19\x026\x1d6\x9ff\xc5\x00\x00\x00\x00IEND\xaeB`\x82",
+
+ "analysis/typeinfo-pkg.png": "\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x042\x00\x00\x03\xa2\b\x03\x00\x00\x00\xb5\xb6\a\xdf\x00\x00\x00\x01sRGB\x00\xae\xce\x1c\xe9\x00\x00\x03\x00PLTE!# #$\"$%#&(%()'*,),.,/0.231463685;<:>@=BDAGHF\x00f\x00JLI\x00j\x02\x03l\x04OQN\rp\nSUR\fr\x17VXU,`\xae7]\xad8^\xae\x16w\x1d[]Z8a\xaa:b\xab;b\xac<c\xad`a_=d\xae?e\xaf@f\xb0*{!bdaAg\xb2)}*Bh\xb3Ci\xb4egdEj\xb5higMj\xb0Fm\xb2/\x82/Ol\xb1Ho\xb4Pm\xb2Ip\xb5/\x858Jq\xb6molKr\xb7Ms\xb8Nt\xb9pro=\x87<Ou\xbaXv\xb6tvs@\x8b?Yx\xb8Zy\xb9@\x8dG]{\xbbxzwI\x8dH_}\xbdX\x80\xbf`~\xbeZ\x81\xc1|~{`\x81\xbbb\x80\xc0N\x92Mb\x83\xbdM\x95U\x80\x82\u007fd\x84\xbfW\x95Vf\x86\xc1h\x88\xc2Z\x98Y\x85\x87\x84i\x89\xc3j\x8a\xc4q\x8b\xc1^\x9d]\\\x9dc\x8a\x8c\x89s\x8e\xc3d\x9deu\x8fŎ\x90\x8dw\x91\xc7h\xa1hy\x93\xc9z\x94ʀ\x94Œ\x94\x91z\x97Ɓ\x95Ƃ\x96\xc7q\xa5r\x83\x97Ȗ\x98\x95\x84\x99\xca\u007f\x9cˆ\x9b̀\x9d͙\x9b\x98u\xaaw\x81\x9eΈ\x9d\u0383\xa0ψ\xa0\xcb\u007f\xabz\x9d\x9f\x9c\x8a\xa2̠\xa2\x9f\x8c\xa4\u0380\xb0\x84\x8d\xa5Ў\xa6ѣ\xa5\xa2\x82\xb2\x86\x8f\xa7Ҥ\xa6\xa3\x91\xa9Ԍ\xb4\x89\x98\xabє\xac֩\xab\xa8\x99\xacҚ\xadӍ\xb8\x93\x9b\xafԮ\xb0\xad\x9d\xb1֗\xba\x97\x9f\xb3ؠ\xb4٢\xb5ۛ\xbe\x9b\xb3\xb5\xb2\xa3\xb7ݣ\xbf\x9d\xa9\xb8٢\xc1\xa4\xaa\xbaڸ\xba\xb7\xa5\xbd۬\xbbۭ\xbcܦĨ\xae\xbdݯ\xbfߨǪ\xbd\xbf\xbc\xb1\xc0\xe1\xab\xc3\xe1\xb0Ǭ\xb2\xc1\xe2\xb6\xc1\xdc\xc0¿\xb7\xc2ݸ\xc3\u07b2\xc5\u07b9\xc4߳\xc7\xe0\xba\xc5\xe0\xb2ͷ\xc5\xc7Ļ\xc7\xe2\xbc\xc8\xe3\xb7\xca\xe3\xbbκ\xbe\xca\xe5\xb9\xcc\xe6\xc9\xcb\xc8\xc0\xcb\xe6\xc1\xcc\xe7\xc2\xcd\xe9\xbf\xcf\xe2\xc0ӿ\xbc\xd0\xe9\xcd\xcf\xcc\xc7\xcf\xe4\xc8\xd3\xc1\xc8\xd0\xe6\xca\xd1\xe7\xd1\xd3\xd0\xc8\xd7\xca\xcb\xd3\xe9\xc5\xd5\xe8\xce\xd5\xeb\xcc\xda\xce\xd5\xd7\xd4\xcf\xd7\xec\xd0\xd8\xed\xcb\xda\xee\xd5\xdb\xd0\xd4\xd9\xe9\xd6\xda\xea\xd9\xdb\xd8\xd7\xdb\xeb\xd2\xde\xec\xdc\xde\xda\xd9\xdd\xed\xd6\xe0\xdb\xd4\xe0\xee\xdb\xdf\xef\xde\xe0\xdd\xd5\xe1\xf0\xe0\xe2\xdf\xdd\xe1\xf2\xdf\xe3\xf3\xe3\xe5\xe1\xda\xe6\xf5\xe1\xe5\xf5\xde\xe7\xef\xe5\xe7\xe4\xe6\xe7\xf1\xe0\xe9\xf1\xe7\xe9\xe6\xe1\xea\xf2\xe2\xeb\xf3\xe3\xec\xf4\xe5\xee\xf6\xec\xec\xf7\xeb\xee\xea\xed\xed\xf8\xe7\xef\xf8\xe8\xf0\xf9\xf0\xf0\xfb\xed\xf2\xf5\xf0\xf2\xef\xee\xf3\xf6\xf4\xf2\xf6\xf2\xf4\xf1\xef\xf5\xf7\xf0\xf6\xf8\xf2\xf7\xf9\xf3\xf8\xfb\xf7\xf9\xf6\xf5\xfa\xfd\xfa\xfc\xf8\xfd\xfb\xff\xf7\xfd\xff\xf8\xfe\xff\xf9\xff\xff\xfe\xff\xfc\x8c\xab\xeb\xca\x00\x00 \x00IDATx^\xec\xbd\x0fpT\xd5\xdd\xff\u007fu\x8d\x80\x80\x80\x88r\x02\x99\x8d!\x85\x87\x80~ML%\xa0\x86\xca\x17j\x11\xed\xfc\x8c\xa8\x93<\x0fc\xa4\xa2\x8fm\x9c\xaf\xd16T\xa0\xea\x83X\x91g\x88\x98\x87>t(\x14\n\xa2և\xa1\x8c\xed<\x86\xe1\xa9y\x06\xa4)jU\bJ\xad\x04\x19\x89ЂR\xadB\x88$s~\xf7ܿ\xe7\xde=w\xef\x9eݻٽ\xbb\xef\x97#\xb9{\xf7s\xce\xf9\x9c\xb3{\xde{\xef\xb9w\xf7\xadP\x00\x00H\x18\xc5/\x00\x00\x00l \x19\x00\x00\t \x19\x00\x00\t \x19\x00\x00\t \x19\x00\x00\t \x19\x00\x00\t \x19\x00\x00\t \x19\x00\x00\t \x19\x00\x00\t \x19\x00\x00\t \x19\x00\x00\t \x19\x00\x00\t \x19\x00\x00\t|$\xe3\x18\x00\x00p@2\x00\x00\x12@2\x00\x00\x12@2\x00\x00\x12@2\x00\x00\x12@2\x00\x00\x12@2\x00\x00\x12@2\x00\x00\x12@2\x00\x00\x12\xc8H\xc6\a\xbf\xf7\xa8D\x8a\xdf6\xce\xf8?ђ\x8a;\x9ey\xdf/\x12\x00\x90u$.\x19\x9f\xb4\\\xb5Գ\x9a\x84\xd9\u007f\a1\x19\xd7\xe2\x17\f\x00\xc86\x12\x96\x8c\xdf\xcf$$u\xc9\xf8`\x06\xe1X\xe1\x17\x0e\x00\xc82\x12\x96\x8cz\x12\x84d,aJQRS?\xb7\x82mD\xff\xe0\x17\x0f\x00\xc8.\xfaY2&\xab\xb5,\xf8@\xdd8\xfc8ӌF\xbfx\x00@vѿ\x92\xb1\x9f\xe9\xc4\a\xfa\xf6lusF\xfcp\x00@\xb6\x91\xa0d4\x9a\xcb\x0f\xcf/P\xff\xb9Y\xdf\xf9[u\xb3X\x15\x80(!\x15\xc7\xf67M+.\x9b\xfb\xbcY`\u007fӍ\xe3\x8a+\xeb\xff\xcbٚ&\x19F\xcc\U000cd34dKD\xc1\x875-Yqm\xb4\xa2\x9e\xe9T\x9d\xbe\xf7\xad\xd1\xea\xf6[q\xa3?9\x06\x00H3Ғ\xc1tb\xf4~kg\xfd1]2~;Y\u007f\xbe\xfe\xb0\xf6ԆqF|\xeda\xbe\xb5O\xd8\x12Fq\xa3\xebb\xad+X\x13\x81\xc7\xd8\xe3\x9a\xff\"\xba(\xa9,e\x8f\xe3G\x1f\x03\x00\xa4\x1bi\xc98VE\xccK\x1d\x15D?dP%c\xc2D3\xe0^\xf6\xcc\xf3\xa3͇\xa4\xc6\xf1ٿT\xdfY1\xff\xb9\xb7\xac}\xee`&\x02\x13\xb4}\xab>\xb9V\xfdW\xbf\x16{\x83\xba\xb5&~\xf41\x00@\xbaIP2\xfe\xf0\xfc\xadꤼ\xf7\xf9\xe7\xf7k\xb3^;3\xf9ou\xe3*\xf6I\x1fe\x13\xb6l\xe9\xf3͕lC=a\xf8\xa0L\xfd\xfb\x9du\xbf}z\x82\xfa\xb7\x99o\xee\xf0\xcdք\xbf\xf1\x19\xfd\xf0!&\xf8\xb0\xf6t\xd1w\xa6\x16\uedcf-~ϔ\xe1\xb0O4\x00 \xdd$(\x19\xdc\xf2'[T\x18͎\x11\x9a\x88qɃI\xc6D\xb6g?ӌ\xdac\xc7V0E`b\xf2[5v\x9a\xa3\xbd\x0f\xe6[\x9aA*\xb4刘`M\x04Jԓ\x97\x9dj\x8dEFc\xec0\xe7\xff\xf9E\x03\x00ҍ\xbcd\x1c\xab!\xfa\x99\t;i\xd0V%\xa2\xd6S-\xeaV\xe9'Z\x84~\x9a\xf0\x1du\xeb\x0f\x8e\x06\x8f\xfd\xfe_\xad\x93\x98\xe8o\x8d\xea\x1c\xc1\x9a\b\xfc\xab\x11]\xabn?\xad\xee\x9bl4\x16?\x1a\x00\x90f\x92\x90\x8c_\xa8[\xb3\xf5S\x85\x1b\xb4\x1dL2\xfe[\xdbz\x8b\xcd߷\x8e1M\xa8kdLS\xb7~\xe1n\xf3\x93\xff^ZS\xa2iƵ\x9f\x1c\x8b\r\xd6D\xc0,\xf4<\xd1.\xc5\x1a\u007f\xfc\xa2\x01\x00i&\t\xc98<AӅ&kG\x94\x18\x97?\xf5\xf9\xfb{}y\xc1Bx[\xf8\xe1uS\xd9s\xffu,6X\xdb\xf3\xdff\x1c[c\xfdñ\xf9F=>\xd1\x00\x804\x93\x84d\x1c\xfbWm\xb2N3V\x19t\xc9\xf8\x83\xb6\xa5\xcdߝ\xaey\xcd\xdd\x00\xf6\x8b\xa5\x8d\xf5\xe6\xad\x1b\xfbK\xb4jb\x83\xb5=\u007f0\x8b\xb0[̗\x1c.1.\xb6\xfaE\x03\x00\xd2K2\x92\xc1.\x95\xdc\xfc\ab\xdd\t\xc1$C\x17\x02\xe3Ą\x89\x81\xeb&.\x1dv\xc7g\xbd\xf9\x80]6m:\x16\x1b|X\xafĀ\xad\xb6\xde\xf0\xbcU\xce'\x1a\x00\x90^\x92\x91\fv\x80Aء\x86\xf1\xedu&\x19\xffO\xdbb˟e\xfa\xca\xe4O\xb5\x1d\xff\xe5\x9c\xcc\xecd\xc6\xfc.\xda[\xac\xd8\nA\xb0K\x04\u0602\xe7͖P\xf8E\x03\x00\xd2J\u00921_?&\xd00n\xc8*1\xee\xecds?ʖ\x13>\x98\xaa\x1f\r\xb0\xaf\x9cMf\xe7\x11\xea\xf1H\xe9\xcd\xdc\xfd\x12\xecЄThG$\xbfg\a\x19d\xa7 X\x13\x01\xbb\xd0/\xf4\xc6*\xf5[\xc2\xfc\xa2\x01\x00i%a\xc9`G\x15\x13\x97\xfc+\xbb,z\xec\xadBm\x16\xcf7\x9e\xd2n\xe5*nZ\xb7\x82\xdd\x18J~k,S\xccx\xfe\xad\xe7\xd9ڥ\xe3>\xeez\xad`\xf9\xcds\xa7j\x1bs\x8f\t\x82]\"p\xb8L\v}\\\u007f\xe4\x17\r\x00H+\tKF\xb36q\x8d{9\xe7j\xdb\xe6\x9a\x02\x93\f\xfd\xa2)1\xceP\x9e#\x16\xe3\xfe\xc07\xf7\xfe\r\x84\xa3j\xbf(\xd8-\x02?d\x8fG\x9b\xe7\x1e~\xd1\x00\x80t\x92\xb0d\xbc\xaf߀\xa5\x9f\x9bh'\v\xe5\xe6\xb7G\xb4\xe5\xcf*}\x1a/\xd0OV\x9aM\t\xf9?\xbfu\xb6\xb7\xbfΞ\xf2s\r\x19p\x05\xbbE@;\x9b\x99k=\xf4\x89\x06\x00\xa4\x93\x84%\xe3\xd8\x1f\xea'G'\x1b\xdfng\x17=\xc9\x0f\xcdg\xb4\x8b\xac\x1f4M\x8dr_~\u007fkɌ\xb2\xa2\t7/\xfd\xe0\x98\x9b\xdf7~gr\xb4\xb8\xe2;?\xb4\xc5\xc4\x19\x1c#\x02\xec\xeb-\xeb\xec\x87>\xd1\x00\x804\x92\xb8d\xf0\xecd\xf3\xd4\xfa\n\xbb}_\x06\x00 \xc7IJ2>ak\x19\xf6\xd7\xcd \x19\x00\xe4\r\xf2\x92\xf1\x8b_<\xc7n\x95\xe0\xee\x03\x87d\x00\x907\xc8KF\xad\xbe\xf8Xa\xff\xdc\x16$\x03\x80\xbcA^2\xfeUS\x8cq\xdc7\xc1 \x19\x00\xe4\r\xf2\x92\xd129Z<\xad\x81\xbfE\x1b\x92\x01@\xde /\x19\x00\x80<\x06\x92\x01\x00\x90\x00\x92\x01\x00\x90\x00\x92\x01\x00\x90\x00\x92\x01\x00\x90\xc0G2\x00\x00\x80\a\x92\x01\x00\x90\x00\x92\x01\x00\x90\x00\x92\x01\x00\x90\x00\x92\x01\x00\x90\x00\x92\x01\x00\x90\x00\x92\x01\x00\x90\x00\x92\x01\x00\x90\x00\x92\x01\x00\x90\x00\x92\x01\x00\x90\x00\x92\x01\x00\x90\x00\x92\x01\x00\x90\x00\x92\x01\x00\x90\x00\x92\x01\x00\x90\x00\x92\x01\x00\x90\x00\x92\x01\x00\x90\x00\x92\x01\x00\x90\x00\x92\x01\x00\x90\x00\x92\x01\x00\x90\x00\x92\x01\x00\x90\x00\x92\x01\x00\x90\x00\x92\x01\x00\x90\x00\x92\x01\x00\x90\x00\x92\x01\x00\x90\x00\x92\x01\x00\x90\x00\x92\x01\x00\x90\x00\x92\x01\x00\x90\x00\x92\x01\x00\x90\x00\x92\x01\x00\x90\x00\x92\x01\x00\x90 e\xc9\xf8\xfcD\x17\x00 oHQ2\xbe\xf4\xab\x1f\x00\x90S\xa4&\x19P\f\x00\xf2\x8c\xd4$ïv\x00@\x8e\x91\x92d|\xeeW;\x00 \xc7HI2\xb0\xf2\t@\xbe\x91\x92d\xf8U\x0e\x00\xc85 \x19\x00\x00\t \x19\x00\x00\t \x19\x00\x00\t \x19\x00\x00\t \x19\x00\x00\t \x19\x00\x00\t \x19\x00\x00\t \x19\x00\x00\t \x19\x00\x00\t \x19\x00\x00\t \x19\x00\x00\t \x19\x00\x00\t \x19\t\xd0\xe9\x17\x00@\xde\x00\xc9\xf0c\xef\x94A\xcax\xbf \x00\xf2\x05H\x86\x1fC\x87>\xbcr\xb7_\x10\x00\xf9BVH\xc6\xf6\xb1\x03\a\x8cZ}\xf1Z\xbf\xb8L\xb0]Y\xe9\x17\x02@\x1e\x11\xb0d\xac\xde\x14\xbbϗM\x91+\x9e\\<^Q\x9e\xf0\v\x94F&\x1d\x8f\xd8MJV*\x19\x00\x19\"`\xc9\x189)v\x9f/c/g\xffNI\x83dȤ\xe3\x11\v\xc9\x00\x80'`\xc9\x18.1G-\x86\xdc\xc6\xfeݮ<\xe9\x17(\x8dL:\x1e\xb1\x90\f\x00x\x82\x94\x8c\xe5\x8a\xcep}\xf3\xb6\xaey\xea\xbfOLWο\xff\xba\xc1\x03\xafxU\x8bytd\xc1\xd0Y\x1d\xcer\x93.ڮ\x15\xef\xe0\x03^:_\xad\xe1\xd5+\x87\x14\x8c\xed|B\xadf\x9e^\x998\xc0Q\xdbڱ\x83#\x03\xc7\x0ev\xa4\xc3\xc5NW\xce[\xdc\xf5ZD\x19\xaa\x05\xbf6~`d\xd0\xd8\xdd|\xac\x8bՐ\f\x008\x82\x94\x8c\x8e\xb5\xab\x87\x8eZ\xbdz\xf5\xabls\xf0u{\xbb\xf6\xde5`m\xc7\xf6\xc5\xe7+\x83\xe7\xcd\x1b\\\xc0ta\xcayӗ\xdf?p\xb8s\x92\xef\x1e|\xde\xd8yk\xf5}V\xc0_\x9eX<x腃g]\xa9\xec\xeeX;\xe06\xa32q\x00_\xd9&eʓ+\x1f\x1e\xa8t\xf2\xe9p\xb1\xbbWG\xeeRueJ\x84\x05\xaf.\x18~\xcfʻ\x94{\xf8X\x9eν\xabG\x0ep\t\x1c\x00yM\x90\x92\xd1\xc5\x1f\xdd\xdf\xc5>\xb0\xa7La\x9b\x91!\xea\xac\xeb\x18<\x92}\xf0?\xda\xc5f\xf5bg\xa9\x8ey##\xca\x00v\b\xe1\b\x18\xae\\\xce\n\xb2zX\xb5WN\xf1\x0e\xb0yp Ӟ\xfb\ah\x0f\xb8\x93\r;\x96IF\xd7]L2\xfe2\x98\x1d\xa1t>\xd1ኵ\x18\xaf\x1ex,\x8f\xdd\r@\xfe\x926\xc9حl\xef\xea\xbcP\xbb@\x19\xd1\xd6*\xeeW:\xba&\r\xe9d\f\x9e\x12S\xb0s\xe5X69\x1d\x01\xc3#\xe6\xf1\xc3ꂎ\xae?\x17\xac\xee\xf2\f\xb0\xd9}ѐ\xe9\x0f\xbfdܰ\xc9K\x86\x15kK\xc6r\xe5%\xbb\xa0H2v\xaf|p\xe8@\x1ce\x00`\x936\xc9\xe8\x1a;\xabk\xe5\x00m\xe6js\xb4k\xb5\xb2I\xfd\xa8\xd7q\xdeM\xb9I\x9f\xcc#\xaf\xe8r\x06\f\xb7V\x16:\a>ٵ\\;|\xf0\b\xe0\xe8xp\xd2Pe\xd0=\xda6/\x19V\xac-\x19\xf7+\u007f\xb1\xcby,\u007f\xb2\xb4\x01\x00&鐌\x875\tP\xa7\xb8~^\xd2\x15\x99\xc5\xfe}X=ʸr\xc8&\x8dw\x1d\x85.\x9a\xae\xfd\xb9mH\x973`\xb8\xad,\xd3\xc7w\x8dע\xbc\x02,6\xcdQ\xff\xe9X\\\xf0\xa0\x16`\xa7c\xc7j\x92q\x1b\x93\x8c\x951G\x19\x0f\xc7\x1c\xb6\xe0\x8a\t\x00<\x01KƨQ]]{\xf5\x1b,:\a.\x1f\xb8Z\xdb\x19\x19\xc4V\x11\x86\x8cbsT{\xea\xb6y\x8eB\x03\a\xeb\x8b\t\xe3]\x01\xdc\xe7\xfe\xda\xc8\xee\x886u\xbd\x02,\xee\xd2\xef\xd6\x1cu\x9d\xf6\xaf\x9d\x8e\x1d[\xa0\x8aJ\xe7H&\x19\x1d\x17\x8dbG.\xd3g\xb9by \x19\x00\xf0\x04,\x19wE\xeeY~y\x81\xfeQ=g\x88~^\xd2\x15Q\x86?\xf1\xf0\x90\x01\xaf\xb1}ʤ'\x96Oq-\u007f\x0eT.\xbak哗\x17\xbc\xca\at\xea\xd70^3b.\x1a{\x91\xbe\xe1\x15`r\x97Rp\xd7\xf2'\xa7(\x9aZ\x99\xe98bG\r\x9c7o\xa4r\xfe\xa3\xdbճ\x8e\v.~p\xf9t\xe5a>\xd6\x05$\x03\x00\x9e\x80%\xa3s\xfa\xc0\x82Q\xc6\xc9\xff\xab\xcau\xfaFd֔\x01\x17]\xa9Oƕ\x97\x0f\x1c0\xca\xf5\xad\x8d\x91\x0f\xdf6\xb4\xc0\xbcq\xc3\fx\xe9<m\xcdb\xac\x11s\u007f\xe4\x1ec\xcb#\xc0\xe4\xd1Q\xf3\x06G.\x1a\xa5\x1fߘ\xe98b_\x1dUp\xe1\xd8\xdb\x14\x85\x9d\xe8\xbc:i\xf0\x85#\x9ftĺ\xd8{\xfe\xa4\x97\xf6\xe2\xdb\xef\x00\x18\x04,\x19<\x1d\x11}\xde\x1a˟ae\xf9P\xf7r-\x00yL\x1a%㉁Ƈs\xb8%C=\xd0xi\xaf_\b\x00\xf9B\xba$c\xde\xea\xae\xcbM\xa5\b\xbbd\x00\x00,\xd2$\x19\u007fV\x86O\xbfH\xbf\aj\xf7\xea\xc8\x14\xac \x02\x90#\xa4I2\xba\xee*\xb8\xdc\xf8\xbe\xc6tEQ\"\xee\xeb\x1a\x00\x80p\x92.\xc9\x00\x00\xe4$\x90\f\x00\x80\x04\x90\f\x00\x80\x04\x90\f\x00\x80\x04\x90\f\x00\x80\x04\x90\f\x00\x80\x04\x90\f\x00\x80\x04\x90\f\x00\x80\x04\x99\x96\x8c;\xef\x14m\x02\x00\xb2\x94\fK\xc6\xff\x0e\xfb\x9e`3E~y\xd9\u007f\xfa\x85X\xbc\xf7ϗ\x8d\xf8\xbf\xfa\xd7\xe7\xccbw\x0e\x1b6\xec\x92\xd7\xe3\x94\xf1\xe6\xf5\x11\xc3\xfe\xc9/&3\b3\x13t\x9e\xc35\x0e\xd9\xdb7ЯdX2n\x1f\xf1'\xc1f\xa2\xfc\xeaw\xc2\xdd?\xbf\xe4Y\xe1~\x11ߺ\xec\xa9;/yO\xdb4\x8b\xfdq˖\xa7\x86m1\x9e\xf7h\u008b\xdf\xdc9\xc2/$\xbdx\xe6+\xcaL\xd0y\x0e\xc78teA\xdf@V\x90Y\xc9x}\xd8݂̈́\xb9\xfa\xbb~\x11~\xbc7\xecߺ\xba\xb8\xdf\f6\xf8\x8d5Ud\x9bx$\xc3\xd3\xca;\xdf\xd8\xcc<:\xcf\xf1\x1b^22\xde7\x90\x15dV2\ued0f,\xee\x94?Ȑ\x9eϱ\xbc>Lx\x0e\x93\x1f\x92\xe1\xd1y\x0eH\x06\x88!\xa3\x92\xf1\xfa\x88\xbb\x05\x9b\xf6\xd3\u07fdl\xc4e\xffWS\x92\xa7\xae\xbe\xe4\xea\xa7Կ\xff2l\xc4Sw\u007f\xe3\x92o\xfd\xb1\xab\xeb?\x87\xe9\\\xad\xee\xee\xf8\xee\x98\x11c\xbe\xad\x1d\x93\xbfw\x89\xbaO;\xc8\xe6b\xbb\xba\xb6|k\x8cZ\xd7\x18G\xfd\x9d\x97\xe95\xdc\xed(\xc60\xa6\n\xdfDW׳\xd7_\xf2\x8d\xef\xa9\x1fʿ\x1b1l\xd8\x0f^\xbf}̈our{\xbb\xba\xfet\xfb\x98K\xbf\x1b{\xf0n\xa6\xee,f\xf2/\xacU}\x99\xc0\x91\xafU\xef\xff\xa8ž\xdd5fذK;Հ\u007f\xbbs̥\xdf~ݫ^q\xbe\xe2\xcc<;o\x17\xe3$\x83\xabA4\x92 \x8fȨd\xdc9⏂M\x93_]r\xf5\x8f\u007f\xf9Ȱ\x9fh\xcf\xfe\xe0\xe7?\x18q{W\xd7\xff>;b\xd8e\x8f\xfc\xe4\x12\xf5\xb3\xf4\xcf[\xb6|\xe3\xfa-[\xb6\xbc\xae>\xff\xf3aw\xfe\xea\xd9o\x0f\xfb\r+\xf6\xbb-[F<\xc26\xb8خ\xdf\r\xbb\xfd\xd9_>u\xd90\xe7\x8fx\xfen˳\xc3\x1eٲ\xe5O\x8eb\fc\xaa\xf0Mt\xdd9\xec\xee\x9f\xff\xdbeWwvu>\xfb\xec\x98o\\2\xe6\xeeۇ\xfd\x91\xdb\xdb\xf5\xfa\xa5\xdfx\xea?\xbf5\xcc-\x19V\xea\x8eb\x16\u007f\xd2ZՖ\t\xf8|\xb9\xd6~\xf3\x88گ\u007f\x1f\xf6\xecﴀ1?~d\xcc%\xff\xe3Q\xaf8_\x8f\xcc<:o\x17\xeb\xb2%\x83\xabA<\x92 \u007fȤd\xfcq\xc4?\v6M:ǰ\x8f\xe3\xceg\xdf\xeb\xea\xfa\xe5\xb0_v\xb1\u007f\u007f\xae\xfe;\xe2Ru\xc6\xdd~\x99\x16b\x1d\x85\xff\xe5ٿ\xf0\x0fͷ\xbf\x1d\xfb\xd4e\xec-\xfeԥ].\x1c\xc7\xe61\x92\xd1\xc5\xd5\xf9\xf3a\xff\xae=\xa1}\x18_=\xec[\xba[#\xb7\xf7\xfao\xa89t^횘|\xeav1\x1e\xadU\xfd\x98\xdf\xce\xd7\xd1ڝ\xdf|ȍ\xf5\xd81j\xe1\xf7\xc6|ӻ^Q\xbe\xe2\xccĝw4l\x8d\x03W\x83\xd7H\x82|!\x93\x92\xf1/#^\x17l\x9a\xfc|\x98\xb5\xf8\u007f\xa7~u\xef\x9f؍\x1b#\xd8?\xc6Y\xb5}\xe2\xfe\xdeS\xdf\x1as\xa9q@\xceI\x86\x15\xfb\xc71c\xfe\xe5\xa9\xdfu\xc5|4&.\x19\xdf\x1d\xa39;\x8e\xd1n\x1e\xb9\xda<&\xb2\xf7\xbe7\x8c\x9d%t\xfd\xc051\xf9\xd4\xedb<\xbcdX\xf9:Z\xeb\xbc\xfa\xb2o\x1b\xb1\xdau视\xbd\xe7Y\xaf _\x8f\xccĝw4l\x8e\x03_\x83\xd7H\x82|!\x83\x92\xf1\xa7\x11w\n6-~b\x1f\xfb^\xafϘo\xab\x9f\xae\xfc\f\xb3\xe7\xc7o.\x1b\xf3\xbd\xff\xd8r}\x8cdر\xef=\xf5\xdd\u007f\x1avُ\xbb\\$.\x19W\x1b\xeb\x04\xda㫯\x8e\xd9\xfb;\xbd\x88{\x89\x90O\xdd.\xc6\xc3K\x86\xb5\xe9h\xad\xebY3\x1d=\xc3-\xaa\x98z\xd5+\xc8\xd7#3q\xe7\x9d\r\x1b\xe3\xe0\xa8\xc1c$A\xbe\x90Aɸ{\xd8\xeb\x82M\x8b_qG\x19\xfab\x9b\xf6\xd1\x17#\x19O\xa9\x9f\xb0\xff\xf4Mvb\xf2]o\xc9\xf8\x1d\xfbx~\xef\xd9\x11Ou9IL2X\x13\xb7\x8f\xf9\x9d\xc6{\xd6^\x86\xbd\xd7\xf8$v/\u007f\xf2\xa9\x8b/gh\xad\xfe\xc0%\x19\x8e\xd6\xfet\xd9\x0f\xc6\xe8wO\xe8k\xc4O\r\xeb\xf0\xacW\x90\xafGf\xe2\xce;\x1av\x1de\xdc\x19o$A\xbe\x909\xc9\xf09\xc8\xe8\xfa\xcbe׳Ì\xbb\xeff\xe7(\xec\xd4\xfaY}-\x83\x93\x8c\xeb\xafW˲\xe7ư\x89\xd2y\xb5\xb7d<\xa2\x9d\xfaw]\xef^1\xf1\x95\f\xab\x89_\xea\xa7\xf7?\xd0>^\xad9\xca\xed\xfd&\x9b֯\x8fpML>u\xb1d\\\xa2\xce\xc1\xceo\xba$\x83o\xad\xf3\x9b?\xe8\xbaS\xbf\xcc2\xe22U\x1a\xff<\xe6z\xefzE\xf9\x8a3\x13w\xde\xd1Mk\x1c\xb8\x1a\xbcF\x12\xe4\v\x99\x93\x8c\xef\xd9G\x16\xdc&ǯF\xfc\xd3S?\xbf[\xfb\x80\xbb}\xd8\xf7~\xfe\xbda\xb7k\x17\x18\xee\xfcM\xd7\xef\xee\x1c\xa1\xad\xf4?2\xe2'\xff\xf1\xadK\xfe\xc8\xde\xc7\xdf}\xea\xc7W\xab\x87˿\xe9\xeaܲE\x8dٲ\xa5\xc3\x11\xfbȰK\x1e\xf9\xf9\u007f\xdc9\xecW\x8e\x16\xf4\x8b\x06\xdau\x16\xbb\x98~\xd7\xe3O\xb6l\xd1\xd6\a\xac&\xd4$\xff\xbfg\xd5\x1a\x9e\xed\xea\xfc\x8dv]\xe2u\xad\nko\xd7\xff\\2\xe6\x91\x1f\\:lĿ\xff\x8f\xa3\r+uG1\x8e\xeb/\xfb\xf1\x8f\xbfɊ9\xfaf\xb7\xb6\xe5\x9f/\xfbc\xd7\xeb\x97\u07bdE\x15\x8d\x11î~\xf6\xa9o\\\xfa\xbaw\xbd\x82|=2\x13w\x9e+ƍ\x03W\x83x$A\xfe\x901\xc9\xf8\xd3%\xb7\v6\x1d\xbc\xfe\xdd1\x97|\xf3?\xb4\xcd\u007f3nB\xf8g\xf54{\xc4\xff\xb0\xdb\bا\\\xe7ݗ\x8e\xb8\x9e\xbd\xe9;\u007f\xf2\x8d\x11\x97}\xf7\xa9o\x8c\xb8^=\xef\xd6y\xca\x11\xfb\xec\xf5\x8f\x8c\x19q\xd9\xf5\xce\xf7y\xe7\xa5Z\xa4\xb6\xf2j\x17Ӿ[a\x9d\xce[M\xa8\x1f\xc0\xd7_v\xe9\xf5?\xb7B\x8d\x15Is\xaf\x9a\xee\xb7/\x1d\xf3\xbd\u007f\x1f1\xcc\xf5\xf9k\xa6\xee,f\xf3\xfa\xf5#.\xf9\xd6\x0f\xd4$\x9d}3\xeb\xfd\xe50v\xef\xc4\xdd꿿b˟w^:\xe6\xf6?ũW\x90\xaf83\x8f\xces\xc5\xf8q\xb0k\x10\x8e$\xc8#2&\x19?\x18\xf6\xbf\x82M\x10\x17\xfb\xd4\t\x80\f\x911\xc9\xc0\xb7ޓ\x00\x92\x012N\xc6$\x03$\x01$\x03d\x1cHFx\xd0\xd7G\x01\xc8(\x90\x8c\xf0\xf0\xcf\xe6r%\x00\x99\x03\x92\x01\x00\x90\x00\x92\x01\x00\x90\x00\x92\x01\x00\x90\x00\x92\x01\x00\x90\x00\x92\x01\x00\x90\x00\x92\x01\x00\x90\x00\x92\x01\x00\x90 Pɘ\xa4\f\x9c\xb2]\xd4\n\x00 G\bT2v\xaf~t\xe8\xc0\x0eQ3\x00\x80\xdc P\xc9PY\xad\xbc$\xd8\v\x00\xc8\x11\x82\x96\x8cM\xcaZ\xc1^\x00@\x8e\x00\xc9\x00\x00H\x00\xc9\x00\x00H\x10\xb4dlWV\v\xf6\x02\x00r\x84\xa0%\xa3s\xe0ȵ\xbb\xe1\x8b\x03@\xae\x12\xb4dt\xadT\x14\xe5\n\xd1\x13\x00\x80\x1c h\xc9\xe8\x188\xe4\xfeկ\t\x9e\x00\x00\xe4\x02AK\xc6&e\xa5`/\x00 G\b^2p\xc5\x04\x80\x1c\x06\x92\x01\x00\x90 h\xc9X\v\xc9\x00 \x97\tT2:wo\x9a\x14\xd9-j\x06\x00\x90\x1b\x04*\x19\xe3\x15e\xf0rQ+\x00\x80\x1c!P\xc9\xd8\xfb\x12\x0e1\x00\xc8m\x02\x95\f\x00@\xae\x03\xc9\x00\x00H\x00\xc9\x00\x00H\x00\xc9\x00\x00H\x00\xc9\x00\x00H\x00\xc9\x00\x00H\x00\xc9\x00\x00H\x00\xc9\x00\x00H\x00\xc9\x00\x00H\x00\xc9\x00\x00H\x00\xc9\x00\x00H\x00\xc9\x00\x00H\x00\xc9\x00\x00H\x00\xc9\x00\x00H\x90\x92d\x9c\xf0\xab\x1d\x00\x90c\xa4$\x19\x9f\xfb\xd5\x0e\x00\xc81R\x92\f\x9c\x99\x00\x90o\xa4&\x19_\xfaU\x0f\x00\xc8-R\x93\fh\x06\x00yF\x8a\x92A\xe9\xe7X\x03\x05 \x8fHY2\x00\x00\xf9\x04$\x03\x00 \x01$\x03\x00 \x01$\x03\x00 \x01$\x03\x00 \x01$\x03\x00 \x01$\x03\x00 \x01$\x03\x00 \x01$\x03\x00 \x01$\x03\x00 \x01$\x03\x00 \x01$\x03\x00 \x01$\x03\x00 \x01$\x03\x00 \x01$\x03\x00 \x01$\x03\x00 \x01$\x03\x00 \x01$\x03\x00 \x01$\x03\x00 \x01$\x03\x00 \x01$\x03\x00 \x01$\x03\x00 \x01$\x03\x00 \x01$\x03\x00 \x01$\x03\x00 \x01$\x03\x00 \x01$\x03\x00 \x01$\x03\x00 \x01$\x03\x00 \x01$\x03\x00 \x01$\x03\x00 \x01$\x03\x00 \x01$\x03\x00 Aʒ\xb1\xf6\xca\xc1\x91\x01\x17߶\xd7/.\xe3t\x9e\xf5\x8b\xf0\xa0S1\xb8`Ȕ\xddlG\x87\xf182\xf8\xcaMVм\xe1\x05\x91\x8bƯu\x95\r\xcd\xe8\x00\x90 )J\xc6\xd9\xf1\xc6\xf49\xff~\xbf\xd0\f\xf3`\xc1\xe7~!\x1e\xa8\x92Q0@\xe5B\xd6\xcf\xd5Ԗ\f\xc6<=\xe6ш\xf1x,\xdfJxF\a\x80DIQ2\xe6(\x05\x0f\xbe\xfby\xe7K\xea\xdcX\xe9\x17\x9bQ\xce*J\n\x92ѡm|\xbd}\xa8\u0084G\x95\x8c\xbd\x9f\xabt\xbd:VQ^e\xcf\xccR\x94\xf1/u}\xb9\xf7\xae\x882\xeak\xbbdhF\a\x80\x84IM2>\x8f(ơ\xf8\x14eH\xfc\xd0\f\x13\x84d\xa8b\x11Q\x9e\xd0$\xa3S\u007f|v\x882E\xfd\xb3ZQ\x16\xeb;^R\x94G\xad\x82\xe1\x19\x1d\x00\x12&5\xc9xM\x89\x18\x1f\xaa{\xadi\x94\x9d\x04#\x19t\xa4r\x1b/\x19\xf4\x1ee\xb0Z\xf7 e\xba\x190\x9d\x13\x87\xf0\x8c\x0e\x00\t\x93\x9ad\xec\xb5g\xd3\xea\xed_\xb2?\x9d\xb3\x86D\x06\x8e\u007f\x89m>\xaa<\xfcҐ\x82\x91s\x94\xf1z\xc4u\xca]\xc2\x00\xb3\x06\xfb!\x17\xb3X\xb9\xe7\xdd\xf1\x03.\x1c\xb9\xdc3\x82vL\x1f\x1c\x190\xeaQ}u\xd3Q\xf4\xfe\x13\xb3\x06G\x86\xdcv\x82\x9d\"0v\xbb\x82\r\xd6N\xba(R0\xf4\xb6.W\x19\x13^2\x86+s\x1c\x92\xf1\x84r\xa1Z^Q\xfeb\x06t\xdc\xff\xaaU0\xd0\xd1\x01 ;HM2\xe8\x10e\xe8Z\xee䝾T\xa0D\x86\x0f\xd1W\x05\x1fU\xe6\\\xa0(\x05\xef*\x11\xed\xf3\xfd\xec\x85\xca^a\x809}\xad\x87|\xccbeRAd\xec\xa8\xf3\x94\xeb\xbc\"\xf6^\xa8\f\x18>TQƺ\xdb_\xac̺H\xb9p\xa0\xa2\f=K\x97OR\x94\xf1Wv:\x83\r\xa6+\xcaE\xc3\a\xa9\xff\x9cp\x961\xe1$c\xb7\xa2,wH\xc6]\xcaPJoc\xff\x88\brt\x00\xc8\x0eR\x94\x8c\xed\x11E\x190\xfe\xd1\xdd\xc6\xc3\xce\v\x959\xea\xc7\xe9\xf6\x01l\xb9\xefQ\xe5\xbc!\xab7=\xa9\x1e\xcck\x87\b\xab\x95\xe1\x1e\x01\x06\xe6CG\xccbE\x19\xf2g\xf5\x18\u007f\x00\xabD\x181^\xb9M\x9d\x96\xbb\a\xb0u\x03wѡ\xdb\xd5c\x80\x88\xf2\xa4ub\xc2\a\x1blR\nا\xfa\xf6\x02\xe5AW\x19\xb3S\x86d\x9c\xed\\>H\x19r\x96\x97\x8c\x13\x83\x94Y\x94^\xa1-h\b\brt\x00\xc8\x0eR\x94\f\xda1V;\xe4\x1f4\x87\x1d֫\xc7\xffWh{W\xb2\xcf\xddG\x15E\xbb\x1f\xe1\t\xfd3\xfdJ\xe5a\x8f\x00\x03\xf3\xa1#f\xb1\xb1s%[#\x10F\fV\xb4)\xf9\xf0\x95kc\x8bjS}:[i0$\x83\x0f6\x98\xa3\x9d\x11\xb0\xbf\xd3]e\f\xac\xfb2T\x86\xb0gU\xc9\xd8}B\xa5c\xe5\xc5J\xe4]\xb6\xc01\x87\x8a\tpt\x00\xc8\x0eR\x95\fuF=q\xa5z \xaf\\\xc8\xeej\x1a\xacݷ\xa0N\xd0\xf3ԙ\xf7\xa8\xb1\x12x\"r\xde\tv\xf9\xe0\xbc.\x8f\x00\x03\xf3\xa1#f\xb12J\u007f\x10Q\xde\x15G\x8cUFn7\x8f\xfe]E/\xd6\x1e<\xacL\xb2$\x83\x0f69\xab\x1f\xfb\xdfÎ\x15\x1ce\f,\xc98\u007f\xd2r-\x94\xbb/\xe3\xbc\xe5Z\xa5^\x92\x11\xe0\xe8\x00\x90\x1d\xa4.\x19\x8c\xbd\xf3\x06(\x05\x9d\xf4sE\xb9x\xa4FD٤\xbe\xe7\x8d\x15\x83I\xec\x12\xe4r\xf6\xc8#@\xc7x\xe8\x8cY\xcc.Q0.V\xcf%\x84\x11\xaf\xb2\xa3\xff+\x97\x9f\x10\x14\xd5?\xb3\x9f`+\x8c\x86dp\xc16g\xb7?9o\xd2`E\x97\f\xae\x8c\x81*\x19\xef~\xfd\xf5\x97\x9b\x86*c\xf5r\xa6d\\x\xf1,\xed8`\x8ar%\x8dG \xa3\x03@v\x90\xa2d|m~dw^\xa4̣]\xf6ǯz6\xfe\xa89\x93ֲ#\x85\xb1\xec\xfc\xdc#@\xc7x\xe8\x8cYl\xde_9\xd2.\xe0\x8c\xa0{\xa7\x14\xa8\x1b\xe7O\xff2\xa6\xa8~\xa4\xc0K\x06\x17l\xf1\xf0 \x16?|\x94.\x19\\\x19\x03s-\xe3\xc4`e\xb8V\xac\xc3u\xc9\xf4\x1e~\xf9\xf3%\xeeZn\x90\xa3\x03@v\x90\x9ad\x8c4\x8e\xa4U橓\xecs\xeer$\xb5\xdf\xf3g\a(\x9d'\xce+\xf8\x92z\x058\x1e:c\xac\xa3\x8c\xa1\xda\a\xaf \x82\xb2Äy\x17+\xcau1E\x05\x92a\a\x9bܣ(ӗ\xbf\xf6\xa5yb\xe2-\x19t\xbb\xa2\xafp\xb8%c7\xf7\xb8C9Ϻ\xca\x1a\xe8\xe8\x00\x90\x1d\xa4&\x19\xe3\xedk\x05\xf3\xd8\xe6@\xf3\xc6\xe8\xed\x1d_s\xef\xf9Y\xca\xe2'\xf4H\x8f\x00\r\xf3\xa1#f\xb1qx\xfeeD\x9d\x96\u0088?o7J\x9f\xff\xb5\xbbh\xacd\xf0\xc1:_\x17\xb0\x1b:)[{\xf4\x93\fvw\a\xbb\xb8\xe2\x96\f:\x98]71C\x06Z\x97E\x03\x1d\x1d\x00\xb2\x83\xd4$c\xb5\xf5\xe5\x89\xceA\xecb\xe1te\xb86\x15\xd7*\x91\x13\xdc{\xfeUe\xecXm\xb2y\x05h\x98\x0f\x1d1\x8b\x95\x886=\x17\xb3\x8b\x90\xa2\b\xf5h^\xbb\x1c\xf1\xaer\xdeYwQ\xa7d\x9c\xd0\x0e\xfd\xed`\x9d.\xe3\xc2\xc4\xe7\x17\xb1\xca\xe3K\xc6\xe7\ue2ec\x06O*\xfa\x95R\xed\xae\xae\a\xad݁\x8e\x0e\x00\xd9Aj\x92\xa1\x9e\x83+\xe3Wwt\xed~p\x90r\xb1:\x99ލ(\xd3\xd5\x0f\xf3W\a\xb2k\b\xdc{~H$2H\x9b\f^\x01\f\xf3\xa1#f\xb1\xa2\fW\xe7\xe7\xda\x02\xf5\xbcD\x1c1V\x19\xab\xca\xc0\xe7\x93\xd8ራ(?\xfd#\xca\xca/\xbfv\x04\xeb|=@\xbb\xdeѩ\xf6\xe4\n?ɠ+\x15\xe5\x1e\x81d\xa8\xc7\x13ʔ\xed\x9f\u007f\xbd\xf76\xc5\xf1\xb5\xb4`Fg\xf9\xc3\xdb)\x00\xd9B\x8a\x92\xf1\xb9\xf9\xf5nmb\xab\x1f\xac\x11傑C\x14\xe5\xf2\xb3\x8eIq\x8fb.Ix\x040\xac\x87|\xccbe\xc8\x05\xe7\xb3\x1b\"\xef\xf1\x8a\xf8\xcb@%r\xf1\xf0\x02ePGLQ~\xfa\x8fTs\xdc\xe4\f\xd6yXQ\x06_1\xf2\xbc\x01w\xb1\xeb\xab>\x92\xa1\x8a@\xa4C \x19g\xa7\x98\xc3p\x05\xffM\x96`Fgx\x9ck\xb8\x00\xf47)J\x06\xa5/\xcd\x1a: r\xd1\x15ˍ\x0f\u05ceYC\"\x05#\x1ff\x87\xfdܤ\xe8P\x14\xf3\x16Hq\x00u<\xe4b\xd49\xbc\xfb\x8a\x82\x81Wl\xf7\x8c\xa0\x9ds\x86D.\x18z\xd7\tAQm\x97>\xfd\xdf\x1du\xc1\x80\x95\xae`\x9dM\x97\x0f\x8c\xa8{>g\xab%~\x92\xd1\x11Q\x8fOb%\x83\xd2\xedӇ^\x10\xb9h\x92\xfb'v\x82\x18\x1dH\x06\xc8&R\x96\x8c4c\xcea\x00@V\x00\xc9\x00\x00H\x00\xc9\x00\x00H\x00\xc9\x00\x00H\x00\xc9\x00\x00H\x90\xed\x92\x01\x00\xc8* \x19\x00\x00\t \x19\x00\x00\t \x19\x00\x00\t \x19\x00\x00\t \x19\x00\x00\t \x19\x00\x00\t \x19\x00\x00\t \x19\x00\x00\t \x19\x00\x00\t \x19\x00\x00\t \x19\x00\x00\t \x19\x00\x00\t \x19\x00\x00\t \x19\x00\x00\t \x19\x00\x00\t \x19\x00\x00\t \x19\x00\x00\t \x19\x00\x00\t \x19\x00\x00\t \x19\x00\x00\t \x19\x00\x00\t \x19\x00\x00\t \x19\x00\x00\t \x19\x00\x00\t \x19\x00\x00\t \x19\x00\x00\t \x19\x00\x00\t \x19\x00\x00\t \x19\x00\x00\t \x19\x00\x00\t \x19\x00\x00\t \x19\x00\x00\t \x19\x00\x00\t \x19\x00\x00\t\x82\x97\x8c\x1a\xf2S\xbf\x10\xc6*\xf2}\xbf\x10\x1f\x8e\xf7\xfaE\x00\x00\x82&\xb4\x92\xd1\xf7\\\xc9i\xbf\x18\x00@ЄV2z\b\x81d\x00\xd0\xef@2\x00\x00\x12@2\x00\x00\x12\xa4$\x19\xbb_\xb3\xd8m\xed\xd4%c\x1dY\xf5\xd7\xc6\xf2\xe2\x99\xdbhߺ\x19ъ\xa6\xd3ھ\x15\x87\xea'\x96\xde\xfa\xeb>jI\xc6\xf1\xa6\xaahY\xdd.\xeaQ\xc4\x15\xd0|\xaa\xa9\"Z\xb5\xe4\x14\xa5\x8b\b\xe3 \xa5G\x1a*\xa3\x13k\xd6`)\x14\x80~!%ɸM\xb1\x98n\xed4%\xa3q2)\x8f\x12\xb2\xad\x81\x14\x97\x13R\xa3\xed\xab/\x8d\xd6\xd6\x14\x92\x86>S2v\x8d#\xc53\xab\bY\xe6Q\xc4\x15\xd0TAJ\xcb\b\xa9\ue85b\xe7\x13R?\xff8\xfd\xb0\x94\x94\xddTM\xc8\x1d}\x82\xfc\x00\x00A\x93\x92dtEL\xc58\xaf\xc3\xdaiJ\x06\xa9\xfe\x90\xf6\xce'\xc5\xc5/\xf4\xd1W\bٯ\xed\x9b\xf61\xa5\xfb\xcb\xc8FC2\x8e\x97\x92Eݔ\xee)#\xdb\xc4Eb\x02ޤ\xb45J6X'&\xf5d\x89z\x80q`\x02i\xf5J\x12\x00\x10 )I\x86}\x98q\x9d\xbdϒ\x8cC\xea\x9f\x0f\tif;oa\xb3|\x9dv&A\xe9ˤʐ\x8cE\xa4\x8e\xea{\xaa\xc5E\xdc\x01\x1f\xb1\a\x8d\xa4ђ\x8ck\xf5*\xd7ܻ\x93\x02\x00\xd2Oj\x92a\x1efp\a\x19\x96dLc\x0f\xba\t\xf9\x80\xfd\x9dOZ\xd8>\xed\\\x83\xf6\x16\xabڠIF%yE\xdb\xd3SH\x8e\n\x8b\xb8\x02n\xd4\x1e\xb4\x90zK2\xee 5o\x9e\xa3\x00\x80~\"5ɠsb\x0e2,ɨe\x0f\xce\x11r\x92\xfd\xbdO\x97\x8cEz\xc8\f\xb2S\x93\fU\x1dfܪ\x11%m\xa2\"\xee\x00\xfd\x90c\x03'\x19oF\t\x990\u007f\xf3\xdf)\x00\xa0?HQ2\xf4\xc3\f\xfe Ò\x8cz\xf6@\x9d\xff\x9f\xb1\xbf\x86d<c\x86\xbc\xacIƧ\xc4f\x9b\xa8\x880@\x95\x8c:\xfb\"\xeb\x87\vJ\xd4'\x8b\x1a\xbb)\x00 \xfd\xa4(\x19\xfaa\x06\u007f\x90\x11W2\x1e\xd3C\xaa\xd5C\x06&\x19\xa7\t9b\x17\x14\x14\x11\x068%C=\xcfi\u007fz&!\r\x14\x00\x90~R\x95\fv\x98\xe18Ȉ+\x19ڙ\a펒\xe3\xfaZ\xc6U\xecB\bc\xcf\xc7\xe7\x84ED\x01\xbcd\xf4}\xfc\x86\xb6k\r)\u008a\x06\x00\xfd@\xaa\x92\xc1\x0e3\xa68vē\x8c\xe8q\xaa=w\x93qŤ\x91ܤ\xddO\xb1\x93\x14\x9f\x12\x16\x11\x05\xe8\x92\xd1K\xc8?(=IFk\xc1\x87H!n\xe6\x02\xa0\x1fHY2:#\x8a\xe3 #\xaed\x90\x9bT\xcd\xd8Y\xa2\x9e\x97\xe8\x92q\xa8\x98<t\x86ҷ\xcbH\x93\xb8\x88(@\x97\f\x1a%ۺ\xcf\xd1;\xc8\x1dj\xf4\xe9\xf9\xc6\x01\f\x00 \xbd\xa4,\x19t\x8e\xf3 #\xaedL-.\xbai*!+\xa8y\xf7gk\x94\x14ϞF\xc8\xdc\x1eq\x11Q\x80!\x19\xb3\tQ\xa5\xe7X\x19\x89\xde8\xb3\x84\x94\x1f\xa5\x00\x80\xf4\x93\xbadt:\x0f2\xe2JF\xfd\xc1\xbaҲ\xba=l\x8f\xf1\x1d\x93#?\xaa\x8a\x96\xccn\xe9\xf5(\"\n0$\xe3PM\xf1ė\xd9wP\xa6E\x8b\xab\x97\xe2*+\x00\xfdB꒑8\xe6\x94\a\x00\x84\x16H\x06\x00@\x02H\x06\x00@\x02H\x06\x00@\x02H\x06\x00@\x82\xfe\x94\f\x00@\xe8\x81d\x00\x00$\x80d\x00\x00$\x80d\x00\x00$\x80d\x00\x00$\x80d\x00\x00$\x80d\x00\x00$\x80d\x00\x00$\x80d\x00\x00$\x80d\x00\x00$\x80d\x00\x00$\x80d\x00\x00$\x80d\x00\x00$\x80d\x00\x00$\x80d\x00\x00$\x80d\x00\x00$\x80d\x00\x00$\x80d\x00\x00$\x80d\x00\x00$\x80d\x00\x00$\x80d\x00\x00$\x80d\x00\x00$\x80d\x00\x00$\x80d\x00\x00$\x80d\x00\x00$\x80d\x00\x00$\x80d\x00\x00$\x80d\x00\x00$\x80d\x00\x00$\x80d\x00\x00$\x80d\x00\x00$\x80d\x00\x00$\x80d\x00\x00$\x80d\x00\x00$\x80d\x00\x00$\x80dP\xfa\x842\xde/D\xe5Ae\x8a_\x88\x0f\x9dg\xfd\"L\xd0Y\xe9\x00\x00 \x00IDAT\x00\xc8z \x19\xfd&\x19\x0f\x16|\xee\x17\x02@\xd6\x03ɠt\xf7\x83\xab\xfdBh\xea\x92qVQ \x19 \xfc@2\x12\x05\x92\x01\x00\x85d$N\xe6%\xa3\xa9\xc9/\x02\x80\xb4\x13f\xc9\xd8;~Ѐ\xb1ۇo\xf7\x8b\xf3C[\xcbX\xac<\xd89}\xd0\x05\xc3W\xaa\x9b\x17G\x06\xcdb\xd3{\xb1rϻ\xe3\a\\8r9\x8b2$\xa3s\u0590\xc8\xc0\xf1/Q*.\xe2\n\xb8\xffĬ\xc1\x91!\xb7\x9d\xa0t\x8e\xc2\xd8Mi\xc7\xf4\xc1\x91\x01\xa3\x1e\x95_\n=B\x96х\xa4p\x9b_\x9c\x80\x17\b!ʹY\xfdws\x9c\xa8\xe3Q2C\xfdӨ\x86\x8d;\x1a'\x0e\xe45!\x96\x8cݑI\xabW^\xa9(+\xfd\x02\xfd0$c\xfa@ePD\xad\xee:\xe5\x82A\x8a2\x8a\xb2}\x93\n\"cG\x9d\xa7\\GM\xc9x\xa9@\x89\f\x1f\xa2(\U000e8e08+`\xd6Eʅ\x03\x15e\xe8Y\xba|\x92\xa2\x8c\xbf\xb2\x93\xee\xbdP\x190|\xa8\xa2\x8c\x8d\x93\x90\xc1\x9e\x03\x8e\x87\rŧ\xe8\xc9\xf6h\xb30\xc0\x15\xeb\xe2̋\xe4\xb9S\xf4T\vy\xf1L\x9c\xa8\xbew\x1a\xa3ꟿ\xb5\xb7\xaf'olj\x03yM\b%\xe3\xc4\xd8\x13\xda\xdf+\xb4Y7=0\xc9P\x86\xee\xa5g\xafT\"\x17,\xff\x9a\xaeV\x94״}C\xfeL\xe9k\x03\x94\xe5\x86dt^\xa8\xcc\xf9\x92\xd2\xed\x03X\xab\xa2\"1\x01\xea1\xd0ڈ\xf2\xa4ub2^\xb9\xedkU\xee\x06(k\xfdҢ5\x0f\xf0\x8f\x8e\x8e~\x8c\xfd\xe1%\x83\vp\xc6\xc6p\x88\xb4\xa9\xff\xee!\x87\xe2F\xd1\xe6\xa8\xfew\x1f$\x03x\x11B\xc9ث\xec\xd5\xfe\x0e\x99\xa7?J\xe4rG\\L\xc9`\xd5\xeeU\x94{ؾ\x91l\x96\x1b\xfb\xe8Je\x88!\x19s\x94+\xa8\xbeg\xa8\xb8\x88;\xa0\x83=\x98\xaeL\xb7$c0;9\xa1\xf4\xe1+\xfd%\xe3\xd6\xfb\xf8G\x0fE?c\u007fx\xc9\xe0\x02\x9c\xb11@2@P\x84M2\x16\x0f]ۡt\xac\x1d\xfa\x04\xa5S\x06k\xf3y\xed\x97\xec\xdf\xe5\xa3\n.\xbeK\xdd\xda}\xbezN\xd0qݐ\x82\xf1_\xafT\x14\xe5~z\xbf\xa2\x9f\xba\b\x02\xcc:\r\xc9\x18¶\xbfT\xf4)}\xa5\xf20ۧ\x9dkг\x11\xe5]]2\x06\x1b\x02u\xf6<U\fDE\\\x01\x17k\x0f\x1eV&Y\x921V\x19\xb9\xddjYc!\x89n|\xec\xc6qu\u007fc\x0f\xfa~]Sz\xe3\xe3=\x94\xee :\xb7\x18QNj\x16i\u007f\xa3K\x8dX.\x80\xdb\\H\x8a\xd65UN\xaew\xadEp\x92q\xe6\xbe\xcahU\xfdAw\xc3'\x1b*\xcb\x16h'&\x94\x93\f+\x9d\x83E\x84<s\xb4aZI\xdd9\n\xf2\x9a\xb0IF\xd7u\xcap\xf5\xbf)]\xea9\xc0\x90\xf3\xc6\xdf\xff\xaa>\xfdf\x9d7g\xed\xe2A#\xbf\xa6gW\xae\x1c2t\xc0\x90ۮS:\xbf\xdc>\xe0\x9e\x13\xf4\xc4=\x03\xb6\u007f)\x0e0\xeb4$C;\xcf\xf9ZQ\xba\xd8\xdf)\xbadܦG\\\xac\x9eF0\xc9\xf8\\Q.\x1e\xa9\x11Q6\x89\x8a\xb8\x03\xae\xb0\x1b0$\xe3Ո\xa2\f\xb8r\xf9\t\xabG\xf4\xa3\xadE\xa4\xa2\xf9g\x13\xefe\x0f~X\xb8h纊[\xfbh\xf7\x9b\xed\xd5w\xb4\xb7\xb7\x1f1\xa2\x9a\xa2\xda̦Q2ck\xeb5j,\x17\xc0m\xb2ʦ\xaej\x9e:\xeeC\xcas\x88\xec\xec\xe9\xe9ic\x92\xb1\x834\xed\xd9V_\xb8\xcf\xd9\xf0щ7\xbe\xd0ZG\xa2z\xb8%\x19V:=۶N\xad\x9eP\xf5X\xc3\xe8\xbfR\x90ׄM2(\xdd\x14Q\"\x9b\xb4\xad\xcf\xef\x1f\x15Q\x06\xb2C\x88\xb5l\xb1\x81\xbe\xa6/k\x8cT\xaeP\xe7&\x9b\x9e\xb3\u0602\xe5u\xb3\xbc\x03t\fɘĶ]\x921O\x8f\x18\xa9\x16d\x92ѥج\x14\x15\x11\x068$\x83\xee\x9dR\xa0>y\xfe\xf4/\xad\xf6i\xb4L\x95\x83\x86\n\xca\xe6\xf3\x8b\x94\xcdحl7\u007f\xb2q<\xbaЈ\xad\xf8\x87:\x93+\xa8+\xc0ތN;C\xe9\xe9\xaa\x1a\xcas\xc88\x0eQ%\xa3g[\xb7z\xf4p\xd3|-\xd6jxn\xb5z(\xd17;\xaa\x87\x9b\x92\xe1L\x87Ԟ\xa1}\xf1\xd6OA>\x106\xc9\xf8\xfc\xb6\xc8`ep\xe4.\xe3S\xfa\xecK\xe3\xd9:┡_3\x06Og\xfbFF\xcc\xe3\x87\xed\x05_ҳ\x05\xec\"\xacG\x80N\x1c\xc90\x8e2\x86\xaa\x87\f\xc6QF\x87]NPD\x18\xe0\x94\fuk\xfb\xbc\x8b\x15\xed*\x8cA\xf4!j\xac#<pC\xef9\x95k\x1b\xd9n^2\x16F\x8f\x1b\xb1M\xd4Zs\x10K\xc62\xf6\xefz\xf2\x15\xe58D~\xb6o\u07fe5\xdaZ\xc6\x17\xeb\xebn\x98Hfk\xb1fç\xc9F\xf6\xf8\x99\xa8\x1enJ\x863\x9d(\x0e0@\xf8$\xe3\xe1AO\xbe\xabt,\x1e\xf4\xa0z̠MTz\xf9$v\x14\xa0s%\xdb1r\xa4\x19\xfc\xf5\xa0\xd5t\xed v\xea\xe2\x11\xa0\x13G2\xf4K\xa1_FԳ\x18m-c\xa0y}f{\xc7\xd7\xc2\"\xa2\x00\x87d\xfcY\xbf\x8d\xe4Q\xe5|{EC[\xd2\xd4d`\xb6q4\xa0\x1d\x03p\x8ap2\xfa\xa3\x98X/\xc9\xd0\xd6Gۉ\xe3\xaa+\xb7\x96\xb1\xaf\xa2jik{\xedl+\x96Uv\x80\xb4S\x1a\xbb\xfc\xe9L\xc7y\xe0\x02\xf2\x94\xb0I\x06\xfdZ\xbbb¦\xdbEs\xb4\x1d\xf3\x86\xaa'\x1fCwkh\xc7\x1e#\xed\xbb4\xe7\\I\xafԢ\xbc\x024\xe2H\x86~<\xb2X\x19n\\1\x99\xae\f\xd7f\xfaZ%rBXD\x14`I\x86\xdaz\x97\x11\xfc\xaer\x9e}3\x97-\x03\r7\x1c\xd0\xf8\x82\xed\xd6d`\xb3\xf6Ѿ\xa4\xf0XL\xac#\xc0ތ.a\x8f7\x12\xc7\x19\x04'\x193j\xd4S\x10\xba\xc0)\x19\xff \xeb\xd9\xe3\x87\xf4z-\xc9p\xa6\xb3\x80\x02\x10>\xc9Pg\xdd@\xfd\xf0b\xd0`\xed@\x9f\t\xc0&\xfd\xb3}ރ\xe6\x0e\x83W#]\x91WنW\x80F\x1c\xc9P\x86\xab\x9a\xb1\xb6@=/\xd1%\xe3݈2]m\xf5Ձ\xca\x1cq\x11Q\x80\xf1Uو\xb2\xf2˯\xe9Xe\xac\x1a\xfd\xf9$\xfe^.[\x06ڈvs\xe7O\x9fc\xff\xd6\xd6RzJ\xdb\xf1Y\xf1C\xb1\xb1|\x00\xb7\x19\xbd\xa6\x9b\xd2\xee\x1bj\xb5\x88\xe3\xcf\xe9R\xc3IF\x15\x9b\xf9}7;%\x83\xd6T\xa9'2\x1f\x17\xeb\xf5Z\x92\xe1H\xc7\xe7:.\xc8\x13B(\x19&\x83\x94\x8b\xeeٴ\xfa\x8a\x02\xb6x0O\x99\xb2z-\xbb\xab\xeb\xebW\xb7\x0f\x1d\xbb}\xbb\xb9X1\xf8\x8a\xc1\xfa\x86W\x00#\x8ed\f\xb9\xe0|v+'\xbb\xefB\xbf\xfbsuD\xb9`\xa4\xba\xe7\xf2\xb3\xe2\"\xa2\x00C2\xd8\xc9\xd1&\xfa\x97\x81J\xe4\xe2\xe1\x05\xca k\xcd\xe3\xb3\xf6h\xe3;}\xef7F\xdb?\xa3t\xd9\xe8\xef\xbf\xd2\xdaH^fO4G״֖~\xaan=>\xfa\xa8 \x96\v\xe06\xa3\xe4\x96m\x9b\xab\xcb>\xd6\xe2\xe7\x93z\xf6\x87\xbf\xfb\xb3\x99ܷ~խ\xa4\xbc\xe5\x1d\xbe\xb2\x0f\xc7U5?3\xb9\xb0\xe8\xc5C\xf4Sv\xf7\xe7\xba\xf6vv\xc8b\xa5s\xee-\xed\xa2\xccq\n\xf2\x9d\x10Kƨ\xe5\xf3..\x184I\x9fz\x9b\xc6\x0e\x1cx\xb9z,\xb0\xfb<m\xcdb\xbc\x11\xb38\xf2\xa8\xb1\xe5\x11\xc0\x88#\x19\x93v_Q0\xf0\nm\xf9\xc1\xf8\x8eIǬ!\x91\x82\x91\x0f\xb3\xb3\n\xa1d\b\x02\f\xc9xw\xd4\x05\x03\xd4c\x9d\xce9C\"\x17\f\xbd˾ʺ\x90\x10\x12=\\\xaa\xfe\xcb.\x8a\xb4\xd5^U6\xb7M{\xa2w\xd1\xe4\x92;\xf6\xa9\x1b\u007f/i\x10\xc6Z\x01\xfcf\xf4\xf1Ɖ\x95\r\x9f\xe9\xf1/Tl\xd0\xfe\x10\xf3;&\x1biߚ\xeah\xc5\x03/TGk\x1d\x95\x1d\xad\x9f<m\xe9\x8bE\xea\xe6C\xc6\x02\x86v?\xa9\x99\xce\xc1Bm_=\x05\xf9N\x88%#\xfd\x98S>\xd3<M\x8eЄ\xe1o\x0f\x05 p \x19q\xc8\x16\xc9\xf8\x91̷\xde!\x19 \xad@2\xe2\x90-\x92!\x05$\x03\xa4\x15HF\x1cB(\x19'\xb5%M\xbf(\x00\x92\x06\x92\x11\x87\x10J\x86\xb6\xa4\x89\xeb\x1a }@2\x00\x00\x12@2\x00\x00\x12@2\x00\x00\x12@2\x00\x00\x12@2\x00\x00\x12@2\x00\x00\x12@2\x00\x00\x12@2\x00\x00\x12@2\x00\x00\x12@2\x00\x00\x12@2\x00\x00\x12@2\x00\x00\x12@2\x00\x00\x12@2\x00\x00\x12@2\x00\x00\x12@2\x00\x00\x12@2\x00\x00\x12@2\x00\x00\x12@2\x00\x00\x12@2\x00\x00\x12@2\x00\x00\x12@2\x00\x00\x12@2\x00\x00\x12@2\x00\x00\x12@2\x00\x00\x12@2\x00\x00\x12@2\x00\x00\x12@2\x00\x00\x12@2\x00\x00\x12@2\x00\x00\x12@2\x00\x00\x12@2\x00\x00\x12@2\x00\x00\x12@2\x00\x00\x12@2\x00\x00\x12\x04.\x19\xfb\b![\xcd\a\xa7\xa3\x84\x1c\x8a\t9ޫ\xfe\xb3\x8e\xd4\xc7<ᤙ4\xfaDhh\xb5\x01\x00\xfa\x87\xb4H\xc6|\xf3\xc1\xafI\xacd\xf4=Wr\x9a\x06&\x19Fm\x00\x80\xfe!\r\x921ztI\x8f\xf1\xa0^ \x19=\x84\x04(\x19Fm\x00\x80\xfe!\r\x92\x11\xad!\xad\xfa\xf6\x99\xe8LH\x06\x009E:$c\riз\xb7\x92fH\x06\x009EJ\x92\xb1\xfb5\x8b\xdd\xe6>U2\x8e\x93\x89\xfa\x92d=9bH\xc6\xf1\xa6\xaahY\xdd.uk\x11a\x1cd\x92\xf1YSE\xb4\xeaq}\xc6\u007f\xd8X\xa9\x06\xb4\xe9u쩛\\Z\xbb\xcf!\x19G\x1a*\xa3\x13k\xd6\xe8\xf5\xc6\xd6\x06\x00\xe8\x1fR\x92\x8c\xdb\x14\x8b\xe9\xe6>U2\xe8̈́Mg\xda]|\xd39]2v\x8d#\xc53\xab\bYF\xe9\xe6\xf9\x84\xd4\xcf?\xaeJ\xc6\xcc\nR^F\xc8\f\xb6\xf0\xf1b\x94\x94\xdeTN\xc8BV\xae\x85\x90\x8a\x99Ѣ\x1aN2>,%e7U\x13rG\x9f\xb86\x00@\xff\x90\x92dtEL\xc58\xaf\xc3\xdc\xc7$\xe39\xd2\xc46\xb7\x91U\xbad\x1c/%\x8b\xbaՃ\x872\xb2\x8d;1!SߡtG\x94l\xa6\xf4@!y\xba\x87\xf6m-&k\xd4\ad\xf4\xfa>z\xaa\x96p\x92QO\x96\xa8\a\x18\a&\xb0U\x12Qm\x00\x80\xfe!%ɰ\x0f3\xae\xb3v1\xc98J*\xd8\xd1\xc0|rT\x97\x8cE\xa4N{\xeeeR\xcdK\xc6a\xb6\xaf\x91\tC=y@\vXO&\xf7\xd2{\xc9\"\xb6}\xfa*N2\xae\xd5O>\xd6ܻS\\\x1b\x00\xa0\u007fHM2\xcc\xc3\f\xfb C\x93\f:\x93\xa8\a\x10\xdd%3\xa9.\x19\x95\xe4\x15\xed\xb9\x9eBrԖ\x8c\x19ھ5\xa4\x9e\xf6\x96\xb0x\x95\xdeR\xf2f\xdf\x04\xb2_{\xb0\x88\x93\x8c;H͛\xe7\x8cmQm\x00\x80\xfe!5ɠs\xdc\a\x19\xbad4\x93\xc7)m%ͺdt\x132\xe3V\x8d(i\xb3%\xa3V\x8bߨ\xfe\xfd\x98\x10\xe3N\x8e\x1a\xb2\xf1\x14!\xdd\xc63\xb6d\xbc\x19%d\xc2\xfc\xcd\u007fW7\x85\xb5\x01\x00\xfa\x87\x14%C?\xcc\xe0\x0e2t\xc98L\xa6R\xba\x80\x1c\xd1%\xe3Sb\xb3\xcd}\x91\x95I\xc6ARd\x94\xae%k\x8e\x10\xa2o\xb7\xf2WL>\\P\xa2\x96.j\xec\x16\xd7\x06\x00\xe8\x1fR\x94\f\xfd0\x83;\xc8\xd0%\x83V\x93\x83=\xeay\x89.\x19\xa7\x89*\x1e\x16\x02\xc9\xf8\x84?\xca\xf8\xbby\x94\xf1\xb2\xf3\xbe\x8c\xde\xf6\xa7g\x12\xd2 \xae\r\x00\xd0?\xa4*\x19\xec0\x83?\xc80$\xe3i\xb2b\x87z^b\xace\\Ům0\xf6||N$\x19\xbd\xc5\xf6ZF{_\x19yK{\xb0̖\x8c\xbe\x8f\xdf\xd0\xfe\xae!E焵\x01\x00\xfa\x87T%\x83\x1dfL\xe1\x1f\xeb\x92q\x80\xccld\a\x03\xbad4\x92\x9b\xd8\x15\x14\xba\x93\x14\x9f\xa2\xbd\x84\xfc\x83:%\x83\xd6\x1b\xf7\x8bn$\x13zh\x83\xfe\xa0\xa7ʖ\x8c\x93d\xf4g\xec\xef!R\xd8+\xac\r\x00\xd0?\xa4,\x19\x9d\x11\x85?\xc80$\x83V\x91q슈.\x19\x87\x8a\xc9Cg(}\xbbL\xbb_#J\xb6u\x9fsJ\xc6\xfe\"\xb2\xa2\x97\xd2\xd6\x12\xd2B\xe9\x91(Y\xd5G\xcf\xcc'\x8e+&w\xa8\x9aqz>\v\x16\xd5\x06\x00\xe8\x1fR\x96\f:\xc7q\x90aJ\xc6ㄝ\x97\x18\x92A[\xa3\xa4x\xf64B\xe6\xb2%\x8bل\x906\xa7d\xd0\xcdEd\xe2\xcd\x15\x844\xb1\xe3\x87mQR~s\t\xa9\xe7$\xe3X\x19\x89\xde8\xb3\x84\x94\x1f\x15\xd7\x06\x00\xe8\x1fR\x97\x8cN\xc7A\x86)\x19\xef\xe8ZaH\x06=\xf2\xa3\xaah\xc9\xec\x16\xed+\"\x87j\x8a'\xbe\xec\x92\fz\xb0\xa1\"zM}\x9b^\xc7\xfb\xf3\xcbKnm\xdb\xc6/\u007f\x1eo\x9a\x16-\xae^\xfaw*\xae\r\x00\xd0?\xa4.\x19\x00\x80<\x02\x92\x01\x00\x90\x00\x92\x01\x00\x90\x00\x92\x01\x00\x90\x00\x92\x01\x00\x90\x00\x92\x01\x00\x90\x00\x92\x01\x00\x90\x00\x92\x01\x00\x90\x00\x92\x01\x00\x90\x00\x92\x01\x00\x90\x00\x92\x01\x00\x90\x00\x92\x01\x00\x90\x00\x92\x01\x00\x90\x00\x92\x01\x00\x90\x00\x92\x01\x00\x90\x00\x92\x01\x00\x90\x00\x92\x01\x00\x90\x00\x92\x01\x00\x90\x00\x92\x01\x00\x90\x00\x92\x01\x00\x90\x00\x92\x01\x00\x90\x00\x92\x01\x00\x90\x00\x92\x01\x00\x90\x00\x92\x01\x00\x90\x00\x92\x01\x00\x90\x00\x92\x01\x00\x90\x00\x92\x01\x00\x90\x00\x92\x01\x00\x90\x00\x92\x01\x00\x90\x00\x92\x01\x00\x90\x00\x92\x01\x00\x90\x00\x92\x01\x00\x90\x00\x92\x01\x00\x90\x00\x92\x01\x00\x90\x00\x92\x01\x00\x90\x00\x92\x01\x00\x90\x00\x92\x01\x00\x90\x00\x92\x01\x00\x90\x00\x92\x01\x00\x90\x00\x92\x01\x00\x90\x00\x92\x01\x00\x90\x00\x92\x01\x00\x90\x00\x92\x01\x00\x90\x00\x92\x01\x00\x90\x00\x92A[kN\xf9\x85H\xf2\xd5\xdcV\xbf\x90\x14\b>\xdf~ \xbdC\x02\xfa\x91\\\x93\x8c\x85\xa4p\x9b\xc7Sǣd\x86`w\vi\xees\xee9X_>\xf1\x8e=7\xbd)\bN\x8c\xbe\x96\xc2\xe7\x84O\xac)\xfe\x99p\xbf\fz\xbe\x8d\x84\x90qG\xcd}\xbb*v\xc4+\x928\a\v\xd5z\x1b\xad\x87\x81\xd5\xeb=$ l\xe4\x8ad\xec9\xa0\xff=\xd9\x1em\xf6\b\xe9{\xa71\x1a\xbbw]\xe1\xaf]{\x0eD\xeb[_\xbe\x97\x10/\xe9I\x84\x9dE\xebD\xbbgGo\x12\xed\xf6\xc1웆\x91\xef\xdf\xda\xdbד\xb7͝;J_\x89)口^\x9dso\xdf|S\xfb\xa7\xd6Ca\xbd\x82b\x89\xe01$ l\xe4\x8ad\xd4<`nyJ\x06\xa5\xcdј]Ǣ\xcb\xcc\xcd/j\xbf\xd0\xfe\xd6ժ\x9f\xe2}\x8d)I\x06]\x11\xfd[\xec\xce\xee\u0086\xc2\xee\xd8\xdd~\xd8}s\xe4\xbbϖ\f\xea:NJ\f\xbe^\x8b\xdaZ\xfe\x91\xa8^a\xb1\x04\x10\x0e\t\b\x1d\xb9\"\x19\xb7\xdegn\xc9IFcE\x8f\xb9\xf9!\xf9P\xfb;\xed\xa7\xec߃$\xa5\x93\xef\xee\n\xfb\xf0ޢ\x9d\x1c {bw\xfba\xf7͑//\x19I\xc1\xd7k\xe1\x94\f\x11\xc2b\t \x1c\x12\x10:\xc2%\x19箉>}m\xe5\x9eEe\xb5\xecú\xef\xd75\xa57>\xaeN\xa1\x1dD\xe7\x16\x16\x13]\xfa؍\xe3\xea\xb4\x0f\xb4\xbe\r\xb7\x8c\xbby\xbd\xf6Iy\xb2\xa1\xb2lA\xec\x89I\uf125\xfaƺ\xea\x1dGȑ\x9d\xd5\x1b(}\xa0\x82IG\xdfNG\x13\a\x8b\by\xe6hô\x92\xbas\xdbԖ\x9ai3\xd1N]D\x01Z\x85+J\xac\xb9m\xd1|-\xad4\x04\xed\x93\x05\xe5ъ\xfa\x93\xceM\xab\xb2\x85\xa4h]S\xe5\xe4\xfa\xa3\xae\xbe\xd9\xf9R[2N\x97\x10R\xb8U\xdf\xf7F]U\xb4\xbc~\xaa\xe3\xe0`!\x89n\xb4\x87D8f\x1c\xb6d\b\xebu\x14\xe3\xf2\x155\x91Ȑ\x80\xd0\x11.ɠ{&\x92\xc7j\xc9U\xcf]\xb3F}\xf0\xc3\xc2E;\xd7U\xdc\xdaG\xbb\xdfl\xaf\xbe\xa3\xbd\xbd\xfd\b\v\x89\x92\x19[[\xaf\xb9\x97m>\x14}f\xe73Q\xf6\xd9vt\xe2\x8d/\xb4֑\xa8\xbb\xbe\xf7I\xbb\xbeq\xb2\x81\xccT\xff[\xa0\x9e\xc7\x1f\xaf*\xack~\xabW\xdbm5ѳm\xeb\xd4\xea\tU\x8f5\x8c\xfek\xf7\x1b\x13W\x9c\xa2\xa7V\x94\xbd\xd1-\x0e\xd0J\xbeI\xder7Fk\x17\xd0\xfb\xf4\x19\xb9\xa7\xf4\x96\x96]\xcdd\x8dsӪ죭Ed\xea\xaa\xe6\xa9\xe3>t\xf6\xcdΗrG\x19\a\xdaۋu%\xda?\xba\xe1\x95]\x1b\xcb\xc99\xbeUVYE\xf3\xcf&jC\"\x1e3\x0e\xee(CT\xaf\xa3\x98#\xdf\xd8&\x12\x19\x12\x10:B&\x19\xb4\xa2\x81\xee$;\xe8CM\xecs\xf2E\xca&\x8e\xf6Aȝ\x98T\xfcC}\xdbV\xa8[m\xa4\xcd\xfcwn\xb5\xfa\x01\xd77;\xea\xaen'\xf9\xd8\xdcl\x8b\x92h\x9b\xb6\xf5ժ\x9a()cK\x19\xce&H\xed\x19\xdawF\xdd\xfa!;\x9bo\xf8\x91w\x80\xca\xdfH\xcc\xcaa_\xe9\x1a\xba\xa6\x94\x1d\x01\xf4Tթ\x92Ի\xed+\xc7&_Yt\x9aZ\xcf\xe9\xaa\x1a\xad^\xfbL\x80\xcb\xd7qbR\xa2O\xed\xf5\x15L,֗\xb9\x96 \xa2e\xea\xc7\u007f\x03\x1b\x12\x8f1\xe3p\x9e\x98\x88굊9\xf2\xf5h\xc2gH@\xf8\b\x9ddl\xa5\xef\x90n\xba\xf4\xfb\xea\t\xc4\r\xbd\xe7T\xae\xd5ΐ9\xc9P\xd5D_\xb5\xf8\xe1Lm\xc7\xccFz\x9ald[\xcfD\xddյ\x92\xe3\xfa\xc6W\x8fE+Ie\xf1\xd2\u007f\xe8\x0f{wՑ\x9d\xee&\xa2\u007f5J\xedQ\x8f\xb0{Ʊ\xcf{\x8f\x00\xca\xe6G\xcc\xf2\xe9A\xf2fϛ\xe4 e2\xf6\x81\xb9\x93\xdb\xe4+\xd3W9\xd7\x13UI\xf8\xa9m\xe5K\x85\x92\xf1i\xe5\xb4E\x1b?\xe8\xeb\xa5N\xa2\x0fQcH<ƌC(\x19\x8ez\xadb\x8e|=\x9a\xf0\x19\x12\x10>B'\x19mt_\x94\xd2e\xaad\xcc6N\xab\xe7\xb3\xfd\xae\xe5O\xed\xcd;\xb7^\xdbQ_C\x0f\xe8\xc7\xf3\xb1˟\xef\x98Ӯ\xa5|\xc3!\xf2Ѻ\xf2\xe7ԩ\xa8\xad0\xf4\xb1\xd2\xce&j\xccR\xe7\xca[ik9\xfb\xc8\xf5\b\xa0lB\xc7\xdcױN\v]\xa7m\xf5\xd8;\xadM\xbe2}\x11\xb7\x9d\xb0\v\x9a\xdc\xd4~\x87\x93\t\x81d\xd0\xd3\x1b\xee\x9bA\xaeiq\x1feXC\xe21f\x1cB\xc9p\xd4k\x15\x8b\xc9WЄϐ\x80\xf0\x11b\xc9h\xb8ဆviT{\x1fof\x1fi\xf6\x9b\xb7\xf1\x06\xf6\x16\xef\x9b\xf6\x10\xfd\aYς\x1e\x8a\xba\xab뱮\xaf\xf4\xd2\x0f\xc9!ګ\x96\xa8X\xa4\xed\xf8i\xb5\xbb\x89\x05V\xb1E\xf3\xe9\xbdZ\x94W\x00\xcb \xe6r\xea\x82[\xf6\xed\xdbw\v\v\xdaE\xac{\x1b\xb8M\xbe\xb2\xe8\x12\xb6g#a\xc7\xf4v߸|\x85\x92q`\x99\x9a\xff\xe9\xad%\xeb\xa9\x03{H<ƌC\x97\x8c\xee\x15_i\x8fD\xf5Z\xc5\x1c\xf9z4\xe13$ |\x84X2\xda\xf4\xe3ܟjw\x15\xb2w\xfa)m\x87\xfd\xe6ݩ\x9dOoeg\x185U\xea\x14\xf8\xb88\x1aS߂j\xeb\x13\xf9\xd32\xfd\x1e\xa6\xf2J6]\xfaػ\xdd\xd1\x04\xf7\xa1\xfcV\xf1g\xc5\xdaR\x9eW\x00\xed\x9bQO\xddT>\xae\xfe\xf3X%e\xd7\x1bk\xd9A\xfe\xa2%\x8eM\xbe\xb2\xe85\xea\xf4\xea\xbeA\x9b\xbfv\xdf\x1c\xf9\n$\xa3Y[\xbd\xa1\xb5Mԁ=$\x1ecF\xe9\xf1\xe7\x8e鱺d\xbcO\xde\xd0\x1e\x89굊9\xf2\x157\xe17$ |\x84L2\x0eM^ӳ5z\xb0\xa7\xa1\xf6o\xaan\x8c\xfe\xfe+\xad\x8d\xe4e\xf6DstMkm\xe9\xa7\xf4\xb3\xf6h\xe3;}\xef7F\xdb?S?\xf0\n\x97\xedXVؠ>\xfdḪ\xe6g&\x17\x16\xbdx\xc8U\xe1\x91\u0098[\xb8\xcbIEs[km\t[h\xb4\x9a8\xf7\x96v\xa5\xc0XI諬\xabԧ\xaeG\x00]c\x1f<\x18\xf4\xb4\x91\x9fv\xd3\xee\xa7I\x9b*\x11{\x8agnh[D6S\xc7&ס(\xb9e\xdb\xe6\xea2m\xb1\xd3\xec\x1b\xc3\xcc\xf7Sv\xf7\xe7\xba\xf6v\xf5þ\xf7\xed\xf6\xf6\xe2\xc6\xf67ΰ\xa9]\xbab\x87Z\x83\xe3\xe6\x0fǐ\x88ƌ1\x9fh\xf3\xf9\xdc[7\xdfԮ\xb2A=\x93\xf3\xaa\xd7.fU&n\xc2wH@\x18\t\x97d\xf4]C\xc8\xd6\t\xa4t\x9b~\xaa\xdcV{U\xd9\xdc6\xed\x99\xdeE\x93K\xee\xd8\xc7\xee\x10 $z\xb8T\xfdw\xa1\x1a\xben\xf6\xb8\xd9\xfa}\x19G\xeb'O[\xfab\x11\xdb\xebdE\xb1\xfb\x04\xbbf\xf3Og\x94V\xcc\xd7/M\x98Mh_\xbe \xc4\xfc\x9c\\\x17]cl\x89\x03\xde(\xb1\xef\x9f0\xd85\x9a\xdd\xc8\xd1J\xc8\xe8]꣏\xef\xbbvB\x8d~\xb3\x18\xb7iw(\xfax\xe3\xc4ʆϴ\xbdf\xdf4\x8c|\x1f2V\f\x1e\xa0t\xbf\xde2\xd9@\xe9\xaf\xefh\xae\x8aV\xd4:o\x17s\f\x89h\xcc\x18/Tl`\u007f\x8c^\x10Rrij^\xae\x98Y\x99\xb8\t\xdf!\x01a$\\\x92\x91\x06\xfa\x96D\xb7\xf9\xc5H\xb3-\xda\xe8\xb85B\x1e\xefoʤ#\xdf~ \xf5!\x01\xd9A\xdeK\x06\xed[s\xed\xdf\xfdb$\xf9\xaa\u2e64\xbe\xf4\xc1\xe1}\xdb{\x1a\xf2\xed\a\x02\x18\x12\x90\x1d@2\xb2\x938ߔ\x01 \x93@2\xb2\x91\x93\xdar\xa2_\x14\x00\x19\x00\x92\x91\x8dhˉ\xf6}\x9e\x00d\x0f\x90\f\x00\x80\x04\x90\f\x00\x80\x04\x90\f\x00\x80\x04\x90\f\x00\x80\x04\x90\f\x00\x80\x04\x90\f\x00\x80\x04\x90\f\x00\x80\x04\x90\f\x00\x80\x04\x90\f\x00\x80\x04\x90\x8c4x\x9cf\x8f\x01i\xf0}\x031d\xcf\xcb\xdd/\xe4\x9add\xaf'\xeb\vĴ?\xd9,(bb$\xe9\xb4\\5\xe0jh-2~ע\xa8\x95\xdbl\x1b\xcd\xfeN\xae?b\x96\x88훈\x98bn\xe2\f\xaa\x1fɺ\xbaƼX\xbe9d\xae\x17y\xe67\x9b+\x92\x91\xfd\x9e\xacg^$ϝ\xa2\xa7ZȋgD%\f\x8c$\x9d\x96\xab\x06\\\r-\xc4\xf8U\xae\xd1-\xdcfϛ\xd1\xc6\xf6=\xeb\xaaK>\xd2\v\xc4\xf6M\x88\xbb\x98E\x02\x83j\xe1\xe1Ԛ\x9c[\xac\xe0\xc5\xf2\xcd!\x93\xbd\xc8+\xbf\xd9\\\x91\x8c\x10x\xb2\x1e\xd2~@s\x0fq\xff\x96\xa0\v3I\x81\u007f\xa2]ú\xa8\x11P\xb2\x8e\xdb4:\xdf]Y\xa7\x85s}\xf3\xc1Q\xcc&\xa1A5\xf0rjM\xe0(GL̋\xe5\x9bC\x06{\x91O~\xb3\xb9\"\x19!\xf0d\rR2z?1\x02>\xe9\xe56\xcd\xce7\x97hoq\xaeo>8\x8a\xd9$4\xa8\x06\xc9:\xb5z\x92\xa4dd\xa6\x17\xf9\xe47\x1b.\xc9\b\xb5'+'\x19g\ueaccV\xd53\x13$\x87\x9b\xa9#IK2\xac&\\\xa2\xc3i\x8a\xb5\xa9O\x8a\x96\"\xf6\xa3\xe5f߸\xcc8\xafWʛ\xc1\xda\xc5\xec̼\x06\x95C\xe4\xd4ʏ\x83\xed\xea\xea\xe8\xe6\x17\rW]\xfb\xf8\xe3W\x95z\x1e\xc6q\xe3`w\x9eF\x17\xfdHO}!)|\xd9Z\xec\xe0*\xcbd/\xf2\xc8o6\\\x92\x11jO\xd6CdgOOO\x1b\x9b\xf0;HӞm\xf5\x85\xfb\x9c\x86\xa9\xce$-\x19\xb0\x9a\xe0k\xa0q$\xa3\xef\x96\xd9l\xdb\xec\x1b\x97\x19\xe7\xf5\xea0\x83\xb5\x8bٙy\r\xaa\x8dЩ\xd51\x0e\x96\xab+\xdf\xcdޙ\x15뛋K6י\xbf\xb8\xec\x86\x1f\a\xbb\xf3ڏ\xaeo\x9d\xad\xa6\xae-J\x18\x8b\x1d|e\x99\xecE\x1e\xf9͆L2\xc2\xec\xc9z\xc8\xf8\x10;\xc4ޑ\xaa\xda\xf4ݤ\x19\x8a\xd9n\xa6\xce$M\x19\xe0\x9a\xe0j\xa0\x1e\x92\xb1\xa2\xa7\xe7ང\xfd\x869\xdf7;3\xdb\xeb\x953\x83\xe5\x8a\xf1\x99\t\a\x95C\xec\xd4\xea\x1a\a\xd3o\xcd\xee\xe66\xe61\xb9>\xce\xf9\x197\x0e\x0e\xdb\xd7\x19\xea\xee\x9ej\xe6\xbff\xbb\xa6\xf0\x95e\xb2\x17y\xe47\x1b:\xc9\b\xaf'\xeb!\xf2\xb3}\xfb\xf6\xad\xd1\xdee_\xac\xaf\xbba\"\xd1\x0e\x06,7SW\x92\xa6\fpM\xf05xH\x06S\x94r}\x15\x86\xf3o\xb53\xb3\xbd^93X\xbe\x18\x97\x99pP9\xc4N\xad\xaeq\xb0&\x9beں\xacL\xfd\xe7c\xef\xa5\"~\x1c\x1c\xb6\xafO\xb3\xdd\x1b\x98M\xad-\x19|e\x99\xecE\x1e\xf9͆N2\xc2\xeb\xc9ʭD쫨Z\xda\xda^\xabK\x86\x99\xaf+IS\x06\xb8&\x12X\xcbhڷ\xef\x13c\xf9\x8f\xf3o\xb53\xd3\xcf\xf7\x99\xd7+g\x06\xcb\x15\xe33\x13\x0e*\x8fЩ\xd55\x0e\xd6d\xb3jX3\xfa\vv\xec\xf7!\xf5\x80\x1f\a\x0f\x9bZqe\x99\xecE\x1e\xf9͆X2\xc2\xe6\xc9\xcaM\xf8\x195l\xba.pJ\x86+IS\x06\xb8&\x12\x90\f\xb3;\xd4\xe1\xdfjgf{\xbdrf\xb0\\1>3\xe1\xa0r\x88\x9dZ]\xe3\x10;\xd9\xfeZX\xf7׃\xd5s=\xaf[\xf2\xe3\x10kS\xbb\x99\xd9\xd4j\x95=\xe3\xae,\x93\xbd\xc8#\xbf\xd9\x10KF\xd8<Y\xb9\t_\xc5ގ}7;%Õ\xa4)\x03\\\x13r\x92\xc1\xf5\x8d\xfb\xa0\xb5\xbc^93X\xae\x18\x9f\x99pP9\xc4N\xad\xceq\x10L\xb6\x03\xe4\x1aBjO\x1a\xcf\x1fo\x8e\xb9{\x8a\x1b\a\x87\xed\xeb\xb5l\xede&\xf3\x8c\x1d\xb7TM\xb2\xc6]Y\x06{\x91O~\xb3!\x93\x8c\x10{\xb2\xf2w\u007f6\x93\xfb֯\xba\x95\x94\xb7\xbc\xc3\xe7\xcb%\xc9Y\xae\xdaM8\xef\x1f}_\r0\xda07\xd9\r\x90\xdc\xfd\xd2F\xdf\x1c\x99q^\xaf\x96\x19,_\xccΌz\f\xaa\x8dЩ\x95o\xcdvu\xe5k8P\xbckg\xfbIS\xcd\xeaI\xe9i\xea\x84\u007f\xb1\x1c6\xb5uo\xed\xaa\xd1R\x9f[Ѳ\xaa\x86\xb0\x00\xbb\xb2\x8c\xf6\"\x9f\xfcf\xc3%\x19a\xf6d\xb5\xbf!\xb2\x91\xf6\xad\xa9\x8eV<\xf0Bu\xb4֑\xaf\x9d$g\xb9j7\xc1\xd7@{X\x99\x12mA\xdf\xdalS\xff\xce\xe4\x9a\xd4\xfb\xe6Ȍ\xf7z5\xcd`\xf9bvf\xd4cPm\x84N\xad|k\xb6\xab+_Û\xda2e\xf4\x0e}\x19`s)\xd9G]\xf0/\x96\xfd\x1a\xcfl\xbeo\x82\x91\xfa\xd1ڒ\tuO;+\xcbd/\xf2\xcao6\\\x92\x91\x06\xd2\xe2q\x9a%\x06\xa4\x82\xbe9\xce\\2©ҦS\xe7Ν\xde\u007f\xefd\xfd袕\xb8\x8f2$pW\xd6o8\x1aΒ\x97\xbb\x9f\xc8{\xc9H\x87\xc7i\xd6\x18\x90\xc6\xf6-\xf3\x92Ѫ\xdf\x01A\xfb\xca\xdbؿ/\x965\xc5\r\x8f\x8f\xb3\xb2~\x84o8k^\xee\xfe\x01\x92\x91_d^2\x0e\x14\xeag$\x1f\x16\xb2\xfbBN\x96/\xe9\x8d\x1f\x1f\x17ge\xfdH\xc6\x1a\xce<\x90\x8c|\"\x1b\xbc^\xfb\x1aK\x9a\xb6\xed\xd9\xd6T\xd2\x14@\"\x81V&C\xc6\x1a\xce<\x90\x8c|\"+\xbc^\xfbv\xd4UF+\xebv\x042\xd7\x02\xadL\x86\x8c5\x9cq \x19\x00\x00\t \x19\x00\x00\t \x19\x00\x00\t \x19\x00\x00\t \x19\x00\x00\t \x19\x00\x00\t \x19\x00\x00\t \x19\xa0\x1f\xe9\xeb\xd3\xff\a\xe1\x05\x92\x01\xfa\x8b\xcf\x1a+Ƚ\x94>@\xca\x1b\xbd\u007f\xf8\x13d;\x90\x8c4\xf8\x96f¤3\xf8^\x04Mߌ\x19\x1bw\x1dW\x95\xa3\xfd\x85\x19W\xe9?\"\x98\x89\x81\x02)\x92k\x92\x91ݞ\xac\xa4\xbc\xee}A\xbcM\xb2\x16\xa6\t\xba\xafz\x93d\xc3\xffh\xba\xa6\xa4>\xc1\x86\x0f\xea?\u007f\xc5\xd8\xc3~\x9e\x9bz\f\x14\xc8nrE2\x120\xde\xcc\x02O\xd6\xf6\x17jF\xef\x11ś\b\xcd?=\x8cBy\x12t_\xf5&Ɇk+6<T\x92\xe0OU\xec'o\x98\x9b\xf6o\x10敛in\x90+\x92\x91\x90\xf1f̏K\xf7\xbf'k\xdf\xdcjA\xb4\x8d\xe8\x13\xdb\xcb(\xd4&q\xf7UO\x92j\xf8+\xb2\x8e\xf6%\xfa;\xb9\xa2\xdf*\xcd/7\xd3\xdc W$#!\xe3M\x81d\xf4\xbb'+\xef\x05\x90 \xfeF\xa1\x89\xbb\xafJ\xe1\xdb\xf0Q\"q:#\x96\x8c|r3\xcd\r\xc2%\x199\xe0\xc9\xdaPI\xf9zyoO\xdb\xfcSl\x14\xeaٚ\xc0}\x95ږ\xab\\\xbe\xee$\r\x84\xae\xa3\xbe\r\xf7^\xa5\a<Fy\x93Y\xca{\xbdr\xddd\v\x18\xef\x98\r\x1e$\xf6\xe9\x99\xc0\xcdTԚ#u\xeb\x85\xf5\xe8\x10H#ᒌ\xd0{\xb2\x1eYJV9\xeaux{Z\xe6\x9fb\xa3P\xcf\xd6\x04\ueadc\xe5*\x97\xaf;I\x13\x91\xeb\xa8\u007f\xc3\x1f\xb4o%\xcd\xed\xda\xefu\xdb&\xa8\x0e\xafW\xbb\x9b\xe7\xfe\xbe\xa7\xa6\xcc҆ޫj\xde\xfc\xd48\x15\x12\xb8\x99\x8aZs\xa4n\xbd\xb0^\x1d\x02\xe9#d\x92\x11~Oֆ>g1\x97\xb7\xa7a\x98!6\n\xf5jM\xe4\xbe\xca[\xae\xda\xf9\xba\x92\xe4\x88u\x1dM\xa0a\xebĄ3A\xe5\x1a\xe6\x8a\xcdW\xbbΝİ\x9f\x037~\x8c=v\xa0\xbcZ\xb36\xb9\x17ֻC M\x84N2B\xed\xc9\xfaΎ\x9a\x92\xe3\xceb.oOc抍B\xbdZ\x13\xb9\xaf\xf2\x96\xabv\xbe\xae$9b]G\x13h\xd8^˰MP\xb9\x86\xb9b\u007fm\xdb0c\xb2\xb5P\xda]1m\xdd.#\xe7\u0601\xf2j\xcdڴ_X\xea\xdd!\x90&B'\x19!\xf7d=]\xb8\xc1Y\xcc\xe5\xedi\xce\\\xa1Q\xa8Wk\"\xf7U~\x99\xd5\xceו$G\xac\x1fX\x02\r[\x92\xc1\x99\xa0r\r;\x8a\xd1v۰d\x9f\xeeMol\xbb\aʫ5k\xd3~a\xa9w\x87@\x9a\b\xb1d\x84ӓu\xe2\ng1\x97\xb7\xa71s\xc5F\xa1^\xad\x89\xdcWy\xcbU;_W\x92\x1c\x9e\x92\x11\xafaK28\x13T\xaeaG1\x8f+&\x82\x81\xf2j\xcdڴ_X\xea\xdd!\x90&B,\x19\xe1\xf4d\xadXrp\x15_\xcc\xe9\xedi\xce\\\xb1Q\xa8gk\x02\xf7U\xder\xd5\xce\xd7Y\x8cG$\x19\xbe\r[\x92\xc1\x99\xa0r\r;\x8ayH\x86`\xa0\xbcZ\xb36\xb9\x17ֻC M\x84L2B\xec\xc9j\xdc0][\xdfx\x13\x9f:\xe7\xedi\x9b\u007f\x8a\x8dB\xbd[\x13\xb9\xafZ\x96\xab\xd4\xce\xd7U\xccD\xec:\xea۰~\xc5D39\xe0MP\xb9\x86\xf9WH\x15G\xeb\f\xe4\x1d\xfbz\xab\xc8\xcdTԚ#u\xeb\x85\xf5\xe8\x10H#ᒌ0{\xb2\xb2\xdb#ZԸ\xea\xf2\x1d\\1\xde\xdb\xd36\xff\x14\x1b\x85z\xb6&t_\xb5,W\x19F\xbe\xeeb\x06b\xd7Q\xbf\x86{˴\xcd\"v\x15\xd6a\x82\xca5̽B\xf4\xefE\xf7\x1d\xfc\x8c]V\xfe\xec\xfd\x05Q\xd3IY\xecf*h͑\xba\xf5\xc2zt\b\xa4\x91pIF\x1aȰ'k@\xa6\xa2i\xe9Eд\xceԔ~>!S\xcd\vD\x89\x0f\x14\xc8\x16\xf2^22\xec\xc9\x1a\x94\xa9h\x1az\x91\x06N\x1dT\x8f.>;\xf0\xa9\xf9Xb\xa0@\xb6\x00\xc9\xc8,y\xec\xed\t\xc2\t$#\xb3䱷'\b'\x90\x8c\f\x93\xbfޞ \x9c@2\x00\x00\x12@2\x00\x00\x12@2\x00\x00\x12@2\x00\x00\x12@2\x00\x00\x12@2\x00\x00\x12@2\x00\x00\x12@2\x00H\x04\xd8\xc9\x1a@2\x00\xf0\x05v\xb26\x90\x8c4\xb8\x99f\xbb\xd5h\xf0=\xceq`'ˑk\x92\x91\u007f\x9e\xac\xed\xa3\xc9\xdc>\xfa\n!\xa3\xed\xdfӌO\xaa\xfe\xad\xbe$ы\x14H\xb25\xd8\xc9&I\xaeHF\xfez\xb2\xf6\xec\"%\xed\xb4\xfb\x15\xb2+\xc6BHL\xca\xfe\xad6\x1e\x99\t{\x916\x92\x183\x06\xecd\x93$W$#\x8f=Y\xbbIC\xa3z\fE\x12\xf4F\r\xc0\xbf\xd5\xc2+\xb3\x04?\xbc\x03\"\x891\x83\x9dl\xf2\xe4\x8ad\xe4\xb1'k7\xd9\xf7\xbad\xee\x00\x00 \x00IDATUړ\xb8d\x04\xe9ߚ\xbd?\xd5\xeb\x9b\x19\xecd\x93%\\\x92\x01OVAk\xdd\xe4\xf8\xad\xaf\xe8\x92aY\xa3z\f\x14\xb5{̹\xaf&R\xccF\x94\x19\x9f\x8e\xd0\xe0\x95\xef\xa6\x10\xd8Ɇ\x86pI\x06<Y\x05\xad\xa9\x92\xb1\xae^\x97\f\xdb\x1aU<P\xd4\xee1羚H1\vaf\x8e\u038b\f^\x1d\xdd\x14\x01;\xd9\xd0\x102ɀ'klk\xaad\xfc\xbd\xf8\xef\x9adp֨^\x03e\xf7\xd8v_M\xa0\x98\x8583W\xe7c\r^]\xdd\x14\x01;\xd9p\x10:ɀ'\xab\xbb5U2h\xfd:}-öF\xf5\x1a(ۿ\x95s_\xf5/f!\xce\xcc\xd5\xf9X\x83WW7E\xc0N6\x1c\x84N2\xe0\xc9\xean\x8dI\xc6+7k\x92\xc1Y\xa3z\r\x94\xed\xdfj\x0fT\x02\xc5l\x84\x99\xb9:\x1fk\xbd\xe6\xea\xa6\b\xd8Ɇ\x83\x10K\x06<Yu\x98d\xf4\x94\xeeb\x92\xc1Y\xa3z\r\x94\xddc{\xa0\x12(f!\xce\xcc\xd5\xf9\xd8I\xec\xea\xa6\b\xd8Ɇ\x83\x10K\x06<Yu\x98dЇ\x1a\x98dp֨^\x03e\xf7\xd8\x1e\xa8D\x8a\x99\x883sv^0\x89\x9d\xdd<\xde,\xb8\xd3\nv\xb2\xe1 d\x92\x01O֘\xd6zv\x91W\xbai{\t\x93\f\xdb\x1a\xd5s\xa0\xcc\x1e\xf3\x03\x95H1\x13af|\xe7\xc5\x06\xaf\\7U\xeaI\xa9\xeb\xbeK\xd8Ɇ\x86pI\x06<Yc[\xdb3\x9a\xdd \xd2WS\xa1\xf6ӲF\x9d\xeb9Pf\x8f\xf9\x81J\xa8\x98\x8103\xbe\xf3b\x83W\xae\x9b*\x9bK\xed\xc5\x01\x1d\xd8Ɇ\x86pIF\x1aH\x8b\x9bi\xe2V\xa3\x01y\xb2ʐ\x96\x1e\xfb\xe0\xeef+\xe9\xb7\xee\x06\x02\xecdm\xf2^2\xd2\xe1f*a5\x1a\x94'\xab\fi\xe8\xb1\x1f\xcen\xf6\xbdX\xd6\x147<\v\x81\x9d\xac\t$#\xb3\xe4\x89'\xab\xb3\x9b'˗\xf4Ə\a\xd9\v$#\xb3\xe4\x89'k\x9et3/\x80dd\x98<\xf1d͓n\xe6\x03\x90\f\x00\x80\x04\x90\f\x00\x80\x04\x90\f\x00\x80\x04\x90\f\x00\x80\x04\x90\f\x00\x80\x04\x90\f\x00\x80\x04\x90\f\x00\x80\x04\x90\f\x00\x80\x04\x90\f\x00\x80\x04\x90\x8c48\x94f\x8f_g\xf0}\xeb_\xb2g$\x81I\xaeIF\xf6z\xb2&_\uf87aҊ\x86=\x151\x93ߣC\x1c~\xee\xab\xfe5\x18$\x9b:GR\xbd\xc8_\xe7\xd3\xec%W$#\xfb=Y\x93\xae\xb7\xad\xb4f\xe3\xd6ل\x1cq?!\xee\x10\x87\xaf\xfb\xaao\r\x06ɦΑl/\xf2\xd5\xf94{\xc9\x15\xc9\b\x81'k\x92\xf5~5q~/\xa5\xddձ\x93M\xd8!\x8eD\xdcW\xe3\xd7`\x92d\xea\x1c\xc9\xf7\"O\x9dO\xb3\x97\\\x91\x8c\x10x\xb2&Y\xef\xb2\x12\xed\x97\xe3\xd6\xc8O\xb6D\xdcW\x13\x93\x8c$S\xe7H\xbe\x17y\xea|\x9a\xbd\x84K2B\xedɚ\\\xbd\xb4Z\xb7\n\xfbbM\xafW\x87x\xfbP\xdbT\xd4\xee\x9b\xc3jT\xa6\x06\x8b\xe4R\xe7\x87$\xe9^\b\x9dOA\x06\t\x97d\x84ړ5\xb9z{\v\xb9syq\x878\xefT\xceT\xd4\xee\x1b\xbfW\xaa\x06\x8b\xe4R\xe7\x02\x92\xef\x85\xd0\xf9\x14d\x90\x90IF\x98=Y\x93\xab\xf78w6 \xee\x10W\x19\xeffj\xf7\x8d\xdb+W\x83MR\xa9s\x01\xc9\xf7B8\x92 \x83\x84N2\xc2\xeb\xc9ʐ\xaf\xb7\xb7\xc8\xfe\xc0\x17w\x88\xab\x8cw3\xb5\xfb\xc6핫\xc1\x81|\xea\\@\xf2\xbd\xf0\x1aI\x90)B'\x19\xe1\xf5dM\xb2^c\x15\xa0\xb7ͫC\\,\xeffj\xf7\x8d\xdb+W\x83E\x92\xa9s\x01I\xf7B4\x92 \x93\x84X2\xc2\xe6ɚd\xbd\xcbJ4\a\x81m\xe4\x94G\x87\xb8X\x87\x9b\xa9\xd57n\xaf\\\r\x16I\xa6\xce\x05$\xdd\v\xd1H\x82L\x12b\xc9\b\x9b'k\x92\xf5~5\xf1^v\x95\xa1v\x9aW\x87\xb8X\x87\x9b\xa9\xd57n\xafd\r&I\xa6\xce\x05$\xdf\v\xc1H\x82L\x122\xc9\b\xb3'kr\xf5\xaa\x93i\xdc\xdc\x17[\xeb\x8a\xd8ѹ\xb8C\\,\xeffj\xf7\x8d\xdb+W\x83Ir\xa9;\x02\x92\xee\x85\xc8\xf9\x14d\x90pIF\x98=Y\x93\xac\x97\xb2og\x8c\xbbf\xfea\xb6\xe5\xd1!.\x96w3\xb5\xfbf\uf56c\xc1 \xb9ԝ\x01I\xf6B\xec|\n2G\xb8$#\r\xa4š4K\xfc:\xd3ҷ\xfe%KF\x12\xd8\xe4\xbdd\xa4á4k\xfc:\xd3з\xfe%kF\x12X@2\x00\x00\x12@2\x00\x00\x12@2\x00\x00\x12@2\x00\x00\x12@2\x00\x00\x12@2\x00\x00\x12@2\x00\x00\x12@2\x00\x00\x12@2\x00\x00\x12@2\x00\x00\x12@2\x00\x00\x12@2\x00\x00\x12@2\xd2\xe0[\x9aa'\xd1\xe0;\x1462\xfc\x02\xe46\xb9&\x19\xf9\xe4\xc9ꁟ\x11\xab\x1f\xbb*vx?\xf9\x02\xfb\x05\x8c\xf2\xba\xf7\xbd#\x18\xfaP7\x11\xcdW`\r!M\xae\xe7\xe36A\xb9\x1e7\xaa\xad\x8d;\x1a7V\x04\xac\\\xd3H\xaeHF>z\xb2\x8a\xf15b\xf5cGi\x1c\x13\x803/\x92\xe7\xda_\xa8\x19\xbd\xc7;\x84\x9aC\xfdii\v\xfb\xfd\xbf\xafZ&|\xeaz\xdenb\x8f\xe8'\xb7\xec\x1e\xff\xad\xbd}\xbd\xf9\xab\xc7R\xc0\xca5m\xe4\x8ad\xe4\xa7'\xab\x80D\x8cX}\x88{\x8cr\x88\xf9\x8f\xf4ͭ\x8e\x17C\x8d\xa1\xbeI\xff)\xbeͳc\x9e\xb6\x9a\xb0_7\x1bg\x8f\xf7%%\x19\xb0rM\x1b\xb9\"\x19\xf9\xe9\xc9* \x11#\xd6T\xd0$\xc3û\x80C\x1b\xea{\x9fѶ\u007fz\xafw\x1c\xff\x13\xcb&\xce\x1e')\x19\xb0rM\x17\xe1\x92\fx\xb2\x1a\x1dZH\xa2\x1b\x8dnr\x9b|\x87\x84F\xac\x9e\xc5,N\x97\x10R\xb8U\xdf\xe6\x86\xcfF\x97\x8c\x86J-\xc0J\xf2\xcc}\x95Ѫ\xfa\x83Z\x84=\xd4\xcb\xf4C\x88\a\x969F\xc7n\xc2\xf1\xba\x89{\xccI\x06\x97\xce\x1buU\xd1\xf2\xfa\xa9}T<\x92Z8\xac\\\xd3D\xb8$\x03\x9e\xacF\x87>\xdaZD*\x9a\u007f6\xf1^\xc7&\xf53b\xf5,fs\xa0\xbd\xbd\xb8\xd9\xd5\x1a\xcf!\xb2\xb3\xe7\xc8R\xb2\x8am\xdb6\xaa;HӞm\xf5\x85\xfb\xa8c\xa87\xd7\xd0w\xaaަ\xb7nt\x8e\x8eՄ\xe3u\x13\xf7\x98\x93\f;\x9d\xfd\xa3\x1b^ٵ\xb1\x9c\x9c\xa3R/\x00\b\x84\x90I\x06<Y\xcd\u007f\xa3e\xea\xf1A\x03\xeb&\xbf\xe9g\xc4\xeaU\xccA\x89.\x19|1\x9bC\xdaqA\x03\xfb\x80\xe7mT\xb7\xa92\xd7w\x13\xfb\xd9wn\xa8\xdb\xcb\xe9\xd2\xe8RZ\xae\xa9\x98ctJ̳G\xebu\x13\xf7\x98ڒ\xc1\xa5\xb3\xbe\x82\x89\xc5\xfa\xb2>\xc9\x17\x00\x04A\xe8$\x03\x9e\xac\xacCj7\x1f\xa2\xe6\xe2\f\xb7\xe9c\xc4\xeaÝ1\x9f\xf9b6\x87\xc8\xcf\xde\xd9QS\xc2Z\xe1{\xf1\xc5\xfa\xba\x1b&\x92\xd9\xd41\xd4\u007f%=w4\xcc\xed\xd6Sr\x8cN\xacd\x88{Lm\xc9\xe0\xd2\xf9\xb4rڢ\x8d\x1f\xf4\xf5R\xf9\x17\x00\xa4L\xe8$\x03\x9e\xac\xacC|7\xf9M\x1f#V\xcfb\x0e\x8c\xf9\xcc\x17\xb3\xd1\xd62N\x17n\xa0\x8e$\xf7UT-mm\xafU%\x83\x1f\xea\xbe臥\aJ?\x8cj\xeb\x0f\x8eщ\x95\fq\x8f\xa9-\x19|:\xa77\xdc7\x83\\\xd3\xd2'\xf7\x02\x80@\b\xb1d\xe4\xb3'\xab\xe7\u070fo\xc4*%\x19|1\x1b}\xf9s\xe2\n\xeaHrF\r\x13\xa8\x05\xaad8\x86\xba\xba\xa5\x92V\xae\xd1/\xc8:F\xc7)\x19\xecu\x13\xf7\x98ڒ\xc1\xa5s`\x99\xbayzk\xc9z\xb9\x17\x00\x04B\x88%#\xaf=Y=\xe7~|#V\x19\xc9\xe0\x8bQz\xfc\xb9c\xda_]2*\x96\x1c\\\xc5'Y\xc5&k\xdfͪd8\x86\xba\xae\xe6^z\xef\xdc:\xad\xa0\xe3r\xaa%\x19\xd6\xeb&\xee1\xb5%\x83K\xa7Y__\xa9m\x92{\x01@ \x84L2\xe0ɪw\x88릣\xc7>F\xac\xde\xc5Lz\xdfno/nl\u007f\xe3\f_\x8c1\xdf0J<\xa8M\xd7\xda\xfaƛ\xf8$\x9b\xc9}\xebW\xddJ\xca[\xdeq\f\xf5\x92\xd1-\xb4e\xb4z\xdc\xc4w\x93o\xc2z\xdd<z\xfc)\xbb\xfbs]{\xfb_\x1d\xe94\x93\xd2\x15;\xd4\xd8=T\xea\x05\x00\x81\x10.ɀ'\xab\xd1!\xae\x9b\x8e\x1e\xd3\xf8F\xacq\x8a\x19\xec\xd7\xf3!\x1b\xa8c\xf8(}\xa1\x82\xed\xa2\xec\xe6\x91\x165\xed\xear\xf6-\x11+ɾ5\xd5ъ\a^\xa8\x8e\xd6:\x86z縃\xf4Pi\xab\xb3\x9b|\x13\xd6\xebF\xc5=~H\x0f%\x0f8\xd2\xf9\xf5\x1d\xcdUъ\xda=\x8eb\xfe/\x00\b\x84pIF\x1aH\x8boi&\x9dD\xd3ҡ\xb0\x91\xc9\x17 \xd7\xc9{\xc9H\x87oif\x9dD\xd3С\xb0\x91\xd9\x17 ǁd\x00\x00$\x80d\x00\x00$\x80d\x00\x00$\x80d\x00\x00$\x80d\x00\x00$\x80d\x00\x00$\x80d\x00\x00$\x80d\x00\x00$\x80d\x00\x00$\x80d\x00\x00$\x80d\x00\x00$\x80d\x00\x00$\x80d\xa4\xc1\xc24Ö\xa0\x01t\xa8\xc9m\x89\b\x92$[F2\xb8\xf7d\xaeIF\xcey\xb22\x13T\xdd\xdddsk\x91\xf1\xeb\x11E\xad\xdcf\xdbh\xf6wr\xfd\x11\xb3D\xaa\x9e\xac*GȲx#\x19\x8f\xc4L[\xe5I\xde\xe05\xa3d\xcdH\x06gS\x9b+\x92\x91\xb3\x9e\xac\xcc\x04\xf5\x14=\xd5B^<\xd3B\x8cߨ\x1a\xdd\xc2m\xf6\xbc\x19ml߳\xae\xba\xe4#\xbd@R\x9e\xac.kԆ\xe2S\xae\x91\xe4\x02\x846\xaa\x16\x89\x99\xb6ʓ\xb4\xc1k?\x93e#\xc95\x11\x94Mm\xaeHF\xeez\xb2\xea?\xb6\xb9\x87\x1c\xa2\xeb\xa2\xc6/a\x96\xac\xe36\x8d\x1ewW\xea?\xb1\x99\x9c'\xab\xd3\x1a\xf5\xe8\xe8\xc7\xd8\x1f~$\xb9\x00\x91\x8d*G\x82\xa6\xad\xd2$i\xf0\x1a4\xe6\xbbċ,\x1bI\xbe\x89\x80ljsE2rדՖ\x8c\xdeO\f\x9d\xf8\xa4\x97\xdb4{\xdc\\\xa2M\x9d\xe4<Y\x9d֨\x0fE\xb5\xdf\x03\xe5G\x92\v\x10٨r$h\xda*M\x92\x06\xafAc\xbeK\xbcȲ\x91\xe4\x9b\bȦ6\\\x92\x91\x8f\x9e\xac\xb6d08SckS\u007fC\xb6\x14\xb1_\x147;\xb4B\xadf+ݪ\xfe\xbb\xc2\xce\xc0i\xc4*\x1e>\x95\xe3E\xba}\x825\x92\\\x00\xb7\xb9\x90\x14\xadk\xaa\x9c\\\u007f\x94:\x10\x9b\xb6\xda6\xaa\x8eb\"\xb7X\xb1\xe5j\x92\x06\xaf\xee\x97%\x06G\x00\x97o\xf7\xd2\x19\xa5w\xbc}m\x9b#\xd8~\x97dp$\xad\xcc\x16\x92\u0097\xad\x15:\xd1P\xbb\xd3\tƦ6\\\x92\x91\x87\x9e\xac\x9a\tjOO\x9b\x9fd\xf4ݢ\x1d\xb1\x9b\x1d:\xf5\xfd\x1a\xb5\x9a\xee7\xe76\xf0?\xea\xe70b\x15\x0f\x9fJ\x93q\x00k\x8d$\x17\xc0m\xb2ʦ\xaej\x9e:\xce\xf9\xb1+6m\xb5mT\x1d\xc5Dn\xb1b\xcb\xd5$\r^\xdd/K\f\x8e\x00\xbb\xb5\xd37\x94\xafi[h\xfc\xa6\xb1\x85\xfd.\xc9\xdcHڙik$\xe6\n\x9dh\xa8\xdd\xe9\x04cS\x1b2\xc9\xc8?OV\xc3\x04\x95ē\x8c\x15==\a\xef%\xbbضա_\xebW\x87f\xba\xd6Bm#V\x8f\xe1cW\x96\x8c\xdf\x1c\xb7G\xd2\xe3p::M\xcd\xfat\x95\xdbN\x8d\xe16m\xe5lT\xb9bb\xb7X\xb1\xe5jr\x06\xaf\xeeX\x11V\x00W\xac\xb1\x8cy\xdb-qI\x06\xff.\xc9\xd4H\xf2\x99\xd9V4\x1eC\xed<\xf7\tƦ6t\x92\x91o\x9e\xac\xcc\x04u\u07fe}k\xe2I\x06{g\x95\xebK$V\x87\x0e\x16\xf6\xf6\xfc\xfa\xf4\xb9\xe8A\xea\xc06b\xf5\x18>\xf509jTa\x8f\xa4\xd7\x1b][i]O\xbe\xa2\x1cb\xd3V\xceF\x95+&v\x8b\x15[\xae&g\xf0\xea\x8e\x15a\x05\xd8\xc5\xfa\xc6iu~\xe4\x92\f\xfe]\x92\xa1\x91tdfK\x86\xc7P\xbb%C\xf4\x9e\x94%t\x92іo\x9e\xac\t\xace4\xed\xdb\xf7\x89q\xd9\xc0\xeaPo\xd1\xc15dő\xc2^\xea\xc0\x1e\x1d\x8f\xe1\xa3'\xa3?\x8a\x89\xf5z\xa3k\xef\xdev\xa7ɐش\x95\xb3Q\xe5\x8ay\xb8\xc5\n-W\x934xuŊ\xb0\x02\xecb\u007f\xd3\x17\xa9\xbb]\x92\xc1\xbdK25\x92\x8e\xcc\xc49pC플`ljC,\x19y\xe2ɚ\x80d\x98}\xa0|\x87fl\xad\x9d;\xa3\xd5}\xf3\x9a=:\x1e\xc3G\x97\x14\x1e\x8b\x89u\x04pC\xbd\x84=\xdeH\x1c\a\xfdb\xd3V\xceF\x95+&v\x8b\xf5\xb0\\M\xce\xe0\xd5\x15+\xc2\n\xb0\x8b\xf5\xe9u\x1ev\x9f\x98\xd8\xef\x92L\x8d\xa4#3\xad\xdeg\xa2\xd4s\xa8\xf9\xd6D\xef\xc9d\b\xb1d\xe4\x89'\xab\x9cd\xd8\x1d\xfa\xfe\xa2h\x1bY\xf8\x00ub\x8f\x8e\xc7\xf0}Vl\xd96\xf3ot;\x80\x1f\xeakԷ`\xf7\r\xb5ZD|\xd3V\xceF\x95+&v\x8b\xf5\xb0\\M\xce\xe0\xd5\x19{\xbcYp\xf7\x94\x15\xc0\x15[P\xaeN\xbe\xbe\x86\x98\xb5\f\xeb]\x92\xb1\x91\xe43\x1b\xb7Tݬa\xf5z\f5\xdfZP6\xb5!\x93\x8c\xfc\xf3d\xe5\xee\xfeTw\xbf\xbf\x9e\xac3*67\xd9ݟ\xd6\xcd\xe2\\\x87\x9e\x1b7\xb1\xaf\xbad\x15\xe5q\x8c\x8eh\xf8(}|\xf4QA,\x17\xc0mF\xc9-\xdb6W\x97\xe9\v\xae~\xa6\xad\xb6\x8d*WL\xe4\x16+\xb6\\M\xd2\xe0\xd5\xf5\xb2ԓ\xd2\xd3ԁ#\xc0n\xed\xb3\x8a\xaa\xf5\xad\xf3\x8bc%\xc3 s#\xc9g6\xb7\xa2eU\r\xd1\xde\xd5\xe2\xa1\xe6[\vʦ6\\\x92\x91\x87\x9e\xac\xf6wL6\xaa\xf2\xc0:V\xa2M\x0fk\xb3M\xfd;\x93k\xc6\xecЁ\xb2\x15\xb4\xa5t\x1f\xe5q\x1a\xb1\n\x86\x8f\xfe\xbd\xa4A\x18\xcby\xa7ڛ\xd1\xc7\x1b'V6\x186\xd0\xf1M[y\x1bU\xae\x98\xc8-Vl\xb9\x9a\xa4\xc1\xabk|7\x97\x12爸\x02\xec־h\xac*\xa9=\xe0)\x19\x99\x1bI>\xb3\xa3\xb5%\x13\xea\x9ev\xe5\xe0\x18>\xae\xb5\xa0lj\xc3%\x19i -\x16\xa6\x99\xb4\x04M\xadCO\x13\xee\x88\xc5\x0f\xc7\x19Q\xe2$Y,\x10Z\x89\xeb(#.\xee\xe5O\x19\xd2;\x92\xf2\x99\x05\xf6\x9e\xcc{\xc9H\x87\x85if-AS\xeaЏ\x9a\xfc\"8\xa4\xdf\xe8:I\x16\v\x80\xbe\x17\xcbd\xfa\x97\xc4ĴI\xefHJg\x16\xdc{\x12\x92\x01\x92F\xfa\x8d\xae\x93d\xb1\x008Y\xbe\xc4u\xd19>\xd2\x133Y\xa4\x87\xa4\xdf2\x8b\x05\x92\x01\x92䤶\xaa\xe7\x17\x15C\x92\xc52\xc1\xd16\xf2\xd8[\xfd\x90\xaa\xfc\x90\xf4Wf\" \x19 I\xb4U\xbd\xe3T\x96$\x8be\x82\xb9j\xaaE\xae\uf2a5\x03\xf9!\xe9\xaf\xccD@2\x00\x00\x12@2\x00\x00\x12@2\x00\x00\x12@2\x00\x00\x12@2\x00\x00\x12@2\x00\x00\x12@2\x00\x00\x12@2\x00\x00\x12@2\x00\x00\x12@2\x82\xb00u\x11\x9c\xffez\b\xbe\xc7\xfdK\xb6\x8fon\x93k\x92\x91\x93\x9e\xac\xc19sj\xf8\x99\xb6z\fT,Iu\xc8ɡ\xbaҊ\x86=\x151\x12\x167\x87\xe0\xfcE\x81<\xb9\"\x199\xed\xc9\x1a\xa43g\x02\xa6\xad⁊%\xb9\x0e9h+\xadٸu6\x89\xfdi\t\x9f\x1c\x82\xf2\x17\x05\xf2\xe4\x8ad\xe4\xb8'k\x80Μ\x89\x98\xb6\n\x06J@\x92\x1d\xe2\xf8j\xe2\xfc^J\xbb\xabE\xbfF\x13?\x87\x80\xfcE\x81<\xb9\"\x19\xee\xdfw\x17\"x\x17\x86œ58g\xceDL[\x13\x93\x8c$;ı\xacD\xfb\xed\xba5\xf2\x92\x11\x90\xbf(\x90'\\\x92\x91\xbf\x9e\xac\x819sZ=\xa6\xf4\x93\x05\xe5ъz\xe6\xae\"\x1e(\xae2.\xd6&\xb9\x0e\xf1\x03U\xad\x1b}|\xb1\xa6W:\a\x81\xbf\xa8\xa8\t\xa7\xe5\xaaل\xafS+\xf0&\\\x92\x91\xaf\x9e\xac\x01:sZ=\xa6{Joi\xd9\xd5L\xd8H\x8a\aʮ\x8c\x8f\xb5I\xaeC\\@o!\xb7\"!\x99\x83\xc0_TԄ\xe3e\xb1\x9a\xf0uj\x05ބL2\xf2֓50gN\xab\xc7=Uu\xeal\xef\xdd\xf6\x95\xd7@q\x95q\xb1<\xc9u\xc8\x0e8Ν\xd3\xc8\xe6\x10;\xbe^\xaf\x85\xb5\xc9;\xc0\xfa;\xb5\x02\x0fB'\x19\xf9\xe8\xc9\x1a\xa43\xa7\xd5\xe36\xf2\x81\xb9O<P\\e\\\xac\x8b$:d\a\xf4\x16ه-\xb29Ď\xaf\xd7kam\xf2\x0e\xb0\xfeN\xad\xc0\x83\xd0IF~z\xb2\x06\xe7\xcci\xf5\x98[P\x15\x0f\x14W\x99x\xf15\xc9\x0eq\x01\xc6ZFo\x9b|\x0e\xb1\xe3\xeb\xf5ZX\x9b\xbc\x03\xac\xbfS+\xf0 Ē\x91W\x9e\xac\x819sZ=\xdee{g\x89\a\x8a\xabl\x97\xd0g+\xc9\x0eq\x01\xcbJ4\xfb\x84m\xe4\x94t\x0e\xb1\xe3땃\xb5\xc9;\xc0\xfa;\xb5\x02\x0fB,\x19y\xe5\xc9\x1a\x9c3\xa7\xd9\xe3\xee\x8aZvֲh\x89\xd7@q\x95q\xb1\x1cIv\x88\v\xf8j\xe2\xbd\xecZI\xed4\xe9\x1c\x04\xe3땃\xb5\xc9;\xc0:]]\x81\x04!\x93\x8c\xfc\xf3d\rܙ\xd3\xea\xf1\x9e\xe2\x99\x1b\xda\x16\x91\xcd\xd4k\xa0\xb8\xf1\xe5bm\x92\xeb\x90#\xa0m\xdc\xdc\x17[\xeb\x8aޔ\xceA\xe4/*j\xc2њՄ\xeb\xc5\x022\x84K2\xf2Г5hgN\xae\xc7\x1f\xdfw\xed\x84\x1amM\xc4c\xa0\xb8\xf1\xb5cm\x92\xeb\x903\xe0Pݸk\xe6\x1ff[R9\x88\xfdE\x05M8Z\xb3\x9ap%\td\b\x97d\xa4\x81\xd4,L=\b\xcc\xff҇\xa4<\xb3\xd2\xd2\xe3\xfe\xa5\xbf\xc6\x17\b\xc8{\xc9H\xcd\xc2TLp\xfe\x97>$%\x19\xe9\xe8q\xff\xd2o\xe3\v\x04@2\xc2Lr\x92\x01@\n@2BL&\x9d9A\xbe\x02\xc9\b1\x99t\xe6\x04\xf9\n$\x03\x00 \x01$\x03\x00 \x01$\x03\x00 \x01$\x03\x00 \x01$\x03\x00 \x01$\x03\x00 \x01$\x03\x00 \x01$\x03\x00 \x01$\x03\x00 \x01$#\r\x0e\xa5Y\xe9\x19\x1a|7\x93$+G\a$L\xaeIF6{\xb2R\xfa\x8f\xa6kJ\xea\x13\xf8RH\x06\x8cX\xe3\x11l:pT\r7\xb9\"\x19!\xf0dU\xa9\xad\xd8\xf0P\xc9i\xd13N2`\xc4\x1a\x8f\xa0Ӂ\xa3j\x98\xc9\x15\xc9\b\x81'\xabzHN\xd6\xd1>\xf7\xaf\xdc\nɄ\x11\xab\x00sH\x82N\a\x8e\xaa!&W$#\x04\x9e\xac\x94\x1e%;bw\nɄ\x11\xab\x00sH\x82N\a\x8e\xaa!&\\\x92\x11fO\xd6ޫ\xf4$\x1fs\xc5r\xae\xa3i7b\xf5jت\x97\x87\x1b\x92\x80\xd3\x11:\xaa\x82\x90\x10.\xc9\b\xb5'\xeb\a\xed[Is;\xfb\xe5sG,\xe7:\x9av#V\x8f\x86\xedzy\xb8!\t8\x1d\xa1\xa3*\b\t!\x93\x8cP{\xb2\xf2'&V,WC?\x18\xb1\x8a\x1b\xe6\xeb屆$\xe0tģ\x03\xc2A\xe8$#̞\xac\xbcd\x98\xb1\\\r\xfd`\xc4*l\xd8Q\xaf\r7$\x01\xa7\xe3\xe5X\v\xc2@\xe8$#\xbc\x9e\xacN\xc90c\xb9\x1a\xfa\xc1\x88Uذ\xa3^\x1bnH\x02NG<: \x1c\x84X2\xc2\xe6\xc9\xea\x94\f3\x96\xab\xa1\x1f\x8cX\x85\r;\xea將$\xe0tģ\x03\xc2A\x88%#l\x9e\xacN\xc90c\xb9\x1a\xfa\xc1\x88U\xdc0_\xaf\x03sH\x82NG8: \x1c\x84L2\xc2\xecɪ_1y\xa7\xcfe\t\xca\xf5\"\xedF\xac\x1e\r\xf3\xf5\n\t:\x1d\x91\xa3*\b\tᒌ0{\xb2\xf6\x96i\x01EGܱ\\/\xd2m\xc4\xea\xd50W\xaf\x88\xa0\xd3\x11;\xaa\x82p\x10.\xc9H\x03iq(M\xabghR\x16i\tt3\xa9z\x93)\x96\xd6\xd1\x01\xe9&\xef%#\x1d\x0e\xa5\xe9\xf5\f\x95\x9f\xa3\f\xffn&W\xaf|\xb1\xf4\x8e\x0eH7\x90\x8c\xd0!=G\x13$\xc9z\x93,\x06\xc2\n$#l\xa4ˈ5\xc9z\x93,\x06B\v$#l\xa4ˈ5\xc9z\x93,\x06B\v$\x03\x00 \x01$\x03\x00 \x01$\x03\x00 \x01$\x03\x00 \x01$\x03\x00 \x01$\x03\x00 \x01$\x03\x00 \x01$\x03\x00 \x01$\x03\x00 \x01$#\rf\xa5\xd9\xee:\x1a|\x8f\x03%ۇ/\xcf\xc95ɀ'\xab?\xa9سr\xa4-I\x98\xb6f5\xb9\"\x19\xf0dM\x98\x94\xecY9Ҙ$L[\xb3\x98\\\x91\fx\xb2&J\x92\xf6\xac\x1cA:\xb5z\x00\xd3\xd6\xec%W$\x03\x9e\xac\x89\x92\xa4=+G\x90N\xad\x1e\xc0\xb45{\t\x97d\xe4\xbb'\xab\xe5q\xba\x90\x14\xadk\xaa\x9c\\\xaf}\xeb\xdc\xea\xe6B\x12\xddhuފu\xd4\xe0k\xcf*n\xc2\xc6ߩ5\x80$aښńK2\xf2ܓ\xd5\xf68\xfdhk\x11\x99\xba\xaay\xea8\xa6nV7\xd9ފ\xe6\x9fMd\x9d\xb7c\x1dM\xf8ٳz4a\xe3\xeb\xd4\x1aD\x920m\xcdbB&\x19\xf9\xed\xc9\xca{\x9cF\xa7\xa9\x85OW\xd58\xbaI\xa3e\xea\x87w\x03\xeb<\x17\xebH\xd2ǞU܄\x03\x1f\xa7\xd6 \x92\x84ik\x16\x13:\xc9\xc8cOV\x87ǩ\xbe\x88\xb9\x9e|\xc5uS\xdd\xfb\x105:\xcf\xc5:\x92\x8co\xcf\xea\xd1\x04\x87\x9fSk I´5\x8b\t\x9dd\xe4\xb1'\xab\xc3\xe3T_\xe5m'\a\xb8n\xf2\x9d\xe7b\x1dIƷg\xf5h\x82\xc3ϩ5\x90$aښńX2\xf2Γ\xd5\xe1q\x1a]\xc2Jo$g\xb8n\xf2\x9d\xe7b\x1dIƷg\xf5h\x82\xc7ǩ5\x90$aښńX2\xf2ϓ\x95\xf78\x8d^\xa3Ω\xee\x1bj\x1d\xdd\xe4:\xcf\xc5:\x92\xf4\xb1g\x157\xe1$\xbeSk I´5{\t\x99d\xe4\xb7'+\xefq\x1a%\xb7l\xdb\\]ƒ\xb4\xba\xc9w\x9e\x8f\xe5\a\xcaǞգ\t!iL\x12\xa6\xad\xd9K\xb8$#\xcf=Yy\x8f\xd3\xe8\xe3\x8d\x13+\x1b>c\x9bV7\xf9\xce;\xfcP\xb9&|\xecY=\x9a\x10\x91\xc6$aښńK2\xd2@\x02f\xa5\xf2\xf4\x83\xebh\x9c\x9b\\}H\xb8\xc7\xc97a\x92d\r\xfd0| i\xf2^2\x120+\x95\xa6?\\G\x93\x9c\x8d\x8cD{\x9cB\x13\x06\xc9\xd5\xd0\x1f\xc3\a\x92\x06\x92\x11R\x92\x9b\x8dR\xa4\xdeD\xea5\x80\xac\x03\x92\x11JNjk\x88~Q)\x91z\x13\xa9\xd7\x00\xb2\x10HF(\xd1\xd6\x10\x8f\xd3t\x92z\x13\xa9\xd7\x00\xb2\x10H\x06\x00@\x02H\x06\x00@\x02H\x06\x00@\x02H\x06\x00@\x02H\x06\x00@\x02H\x06\x00@\x02H\x06\x00@\x02H\x06\x00@\x02H\x06\x00@\x02HF\x1a\x1cJ\xb3\xc7TT\xeb[\xf6\xa4\x03r\x80\\\x93\x8c\xec\xf6d\x8dK\x1a<N\xf5\xbe\xf9\xa5\x93\x86\x86A\xee\x92+\x92\x11\x0eOV!f\xea\x81x\x9c\xee\xe1\u007f\xcd\xca\xea[\xfct\x82o\x18\xe40\xb9\"\x19\xa1\xf0d\x15c\xa5\x1e\x84ǩ=\x0e\x8e\xbe\x89\xd3\t\xd2\\\x95o\x18\xe42\xb9\"\x19\xa1\xf0d\x15c\xa5\x1e\x84\xc7)\xff\x93\xc5\\\xdf\xc4\xe9\x04i\xae\xca7\fr\x99pIF\x98=Y\xd5\x0f\xf5\x86\xab\xae}\xfc\xf1\xabJ\xb7y\xa4\xee\xe1qڽtF\xe9\x1do_\xdb\xc6\xd6i^\xb6VdD&\xa8\x8eq\xb0\xfbƈM\xc7\xdf\\5نAN\x13.\xc9\b\xb5'k\xef̊\xf5\xcd\xc5%\x9b\xeb\xd6x\xa4.\xf68=}C\xf9\x9a\xb6\x85\x84l\xd0\xd7i\xcc\x15\x19\x91\t\xaac\x1c쾉\xd3\xf15WM\xbaa\x90ӄL2\xc2\xecɺ\x8d\x1cdf\x83\x87b\x8a\xd9'&\f\xb7\xc7ic\x19so[\xa2\xce\\\xde\x01\xc4\xc3\x04\x95??\xe0\xfa&\xf68\xf51WM\xbaa\x90ӄN2\xc2\xebɺ\xacL\xfd\xe7cm\x89D\x9c\xba\xd0\xe3\xb4o\x9c\xb66\xf3\x91k\xe6z\x98\xa0\xf23\x97s_\x15\xa5\xe3g\xae\x9a|\xc3 \xa7\t\x9dd\x84דu\xcd\xe8/\xd81χ1\xc5\x1c˟n\x8fӿ\xe9˰ݮ\x99\xeba\x82\xca\xcf\\\xce}U\x94\x8e\x9f\xb9j\xf2\r\x83\x9c&Ē\x116Oֿ\x16\xd6\xfd\xf5`\xf5ܾ\x98bf\xeaB\x8fӾ\x12-\xc3\xc3\xf6\xccՎ\x95<LP\xb9q\xe0\xddW\x85\x1e\xa7>\xe6\xaa\xc97\fr\x9a\x10KF\xd8<Y\x0f\x90k\b\xa9=\x19S\xccJ]\xecq\xba\xa0\\\x9d\x9d}\r\xda\xcc\x1d\xb7Tݬ\x89:k\xe0MP\xb9qp\xf4M\xecq\x1a\xdf\\5\xf9\x86A.\x132\xc9\b\xb3'\xeb\x81\xe2];\xdbO\xba\x8aQ;u\x0f\x8f\xd3\xcf*\xaaַ\xce/\xd6f\xee܊\x96U5D\xeb\x85\xd8\x04ծ\x8c:\xfa\x16\xdf\xe34\xe8\x86A.\x13.\xc9\b\xb3'+}3\xca\x02\xa2w|\xc8\x17\xa3v\xea\x1e\x1e\xa7\xf4\x8bƪ\x92\xda\x03\xda\xcc=Z[2\xa1\xeei\xadob\x13T\xab2\r\xabo\xf1=N\x83o\x18\xe40ᒌ4\x90\xb0C\xa9\f\"S\xd1S\xa5M\xa7Ν;\xbd\xff\xdeɧEE|\xd0W!%1\xfb\x96\x8a\xc7iR\r\x83\x1c&\xef%#a\x87R\t\x84\xa6\xa2\xad\xfa\xfd\v\xb4\xaf\xbc-\xe69\u007f\x92\x9b\xb9z\xdfR\xf28M\xaea\x90\xbb@2\xfa\x8b\x03\x85\xfa\x17:>,\xfc\xc0'RD\xc6fn\xc6\x1a\x06Y\n$\xa3\xbf\xe8k,iڶg[SIS\x12\x1f\xf9G\xdb\xc8co%Q.e2\xd60\xc8V \x19\xfdFߎ\xba\xcaheݎd&\xe0\\BH\xd1Q\xbf\xa84\x90\xb1\x86A\xb6\x02\xc9\x00\x00H\x00\xc9\x00\x00H\x00\xc9\x00\x00H\x00\xc9\x00\x00H\x00\xc9\x00\x00H\x00\xc9\x00\x00H\x00\xc9\x00\x00H\x00\xc9\x00\x00H\x00\xc9\x00\x00H\x00\xc9\xc8iOV\x0eس\x82@\xc85ɀ'\xab\a\xb0g\x05\xc1\x90+\x92\x01O\xd6\xf8\xf4\xa7=+\xc8irE2\xe0\xc9\x1a\x97~\xb5g\x059M\xaeH\x06<Y\xe3ү\xf6\xac \xa7\t\x97d\xe4\xa5'\xab\xe5|\xba\x90\x14\xadk\xaa\x9c\\\xaf}\x17\xdd\xea\xdbB\x12\xddh\xf5؊uԐ\xba=k\x009\x80\x1c!\\\x92\x91\x8f\x9e\xac\xb6\xf3\xe9G[\x8b\xc8\xd4U\xcdS\xc71I\xb3\xfa\xc6\xf6V4\xffl\"\xeb\xb1\x1d\xcbא\xba=k\x109\x80\x1c!d\x92\x91\x87\x9e\xac\xbc\xf3it\x9aZ\xfb\xe9\xaa\x1aG\xdfh\xb4L\xfdto`=\xe6b\x1dM\xa4j\xcf\x1aD\x0e G\b\x9dd\xe4\x9b'\xab\xc3\xf9T_\xc4\\O\xbe\xe2\xfa\xa6\xee}\x88\x1a=\xe6b\x1dM\xa4h\xcf\x1aH\x0e G\b\x9dd\xe4\x9b'\xab\xc3\xf9T_\xdam'\a\xb8\xbe\xf1=\xe6b\x1dM\xa4h\xcf\x1aH\x0e G\b\xb1d\xe4\x87'\xab\xc3\xf94\xba\x84\x15\xd8H\xcep}\xe3{\xcc\xc5:\x9aHў5\x90\x1c@\x8e\x10b\xc9\xc8\x13OV\xde\xf94z\x8d:ۻo\xa8u\xf4\x8d\xeb1\x17\xebh\"U{\xd6@r\x00\xb9A\xc8$#\x0f=Yy\xe7\xd3(\xb9e\xdb\xe6\xea2\x96\x99\xd57\xbe\xc7|,\xdfD\xaa\xf6\xac\x81\xe4\x00r\x83pIF>z\xb2\xf2Χ\xd1\xc7\x1b'V6|\xc66\xad\xbe\xf1=v\xb8\xa4rM\xa4j\xcf\x1aL\x0e '\b\x97d\xa4\x81\x90x\xb2\xeaĹ\xb3Շ \xecYu\x92\xcf\x01\xe4\x04y/\x19!\xf1d\xd5Ia\xba\x06`Ϫ\x93B\x0e \x17\x80d\xf4\x17\xa9y\xb2\xead\xc3t͆\x1c@\x06\x81d\xf4\x17)y\xb2j\x9c\xd4\x16\x19\xfd\xa2\xd2K6\xe4\x002\n$\xa3\xdfHœUC[d\xe4n\xe3\xcc\x04ِ\x03\xc8(\x90\f\x00\x80\x04\x90\f\x00\x80\x04\x90\f\x00\x80\x04\x90\f\x00\x80\x04\x90\f\x00\x80\x04\x90\f\x00\x80\x04\x90\f\x00\x80\x04\x90\f\x00\x80\x04\x90\f\x00\x80\x04\x90\x8c\xbc\xf2d\r1\xf1\x065\xec}\v\x15\xb9&\x19!\xf6d\xd5ГL\x835jl7\x9dx\x8cN,)\x8f\x0e\xa5\x87\xeaJ+\x1a\xf6T\xc4L\xf3\xb89\xc4\x19T\xbf\xbe\t\xd9U\xb1\xc3/$U\xfa\xa1\x89\xd4\xf0\x9d-\xadE\xc6Ϸ\x16\xd9z\x9d+\x92\x11bOV\az\x92\x81X\xa3\xee\xe1\u007f}+\xb6\x9b.ģ\x13K\x00\xa3\xd3VZ\xb3q\xeblB\x8e\xb8\x9f\xf0\xc9\xc1kP}\xfb&dGi\xac7C\xc0\xa4\xdcĞx?\xa0\x96\x02\tϖ\x16\xd2\u07be\x9e\xacko\x1f\xddb=\x93+\x92\x11bOV\x17Z\x92AX\xa3\xdaC\xe2\xe8\xa6'\x82\xd1\x11\x90\xfa\xe8|5q~/\xa5\xddձ\x92ᗃxP\x13\xe9\x9b\b\x89\x03\x13\xf3\xad!\x8bD\x13B\xf8\x97P\x06\xbf|\x13\x9e-\xeb\xa2\xec\x17\xe9ߦ\xb4\xc4V\xeb\\\x91\x8c\x10{\xb2\xba\xb0%#EkT\xfe\u05cb\xb9nz\x92\x98d\xa4>:\xcbJ\xb4_\x01\\#/\x19\xe2AM\xa4o)b\xbe5\xfa\x1b\xfe%\x94\xc1/߄gK\xef'\x86d|\xd2k\xed\x0f\x97d\x84ٓ\xd5\x11`\x9b\x95\x9e\xb9\xaf2ZU\u007fP\v\xb1\x93\xf4\xb0F\xed^:\xa3\U0010edefmc'\xa1/[\xa7\xfe\"\xefTǐ\U0001eb1f,(\x8fVԳ\xdf9\x17\x8f\x0eo\xa3j\xc7ڤ>:\xd5?\xd2*\xfabM\xaft\x0e\x02\xa3[\xaeo\"3X\x8f\xccN\x97\x10Rh\x9a\xb8qC\"\xf2\x90\xe5\xde\x1a\xe9j\u0082\u007f\x83s/!\xdb|Z\xaf\xd7i\x8a\x1b7߀f\xcb>\xdd\x04\xc7\xca!\\\x92\x11fOVG\x80mV\xba\x834\xed\xd9V_\xb8\x8f:\x92\x14[\xa3\x9e\xbe\xa1|M\xdbBB6\xe8'\xa1橿\xc8;\xd51$\x9c'\xeb\x9e\xd2[Zv5\x136|\xe2\xd1\xe1lT\xb9X\x9b\x94G\xa7\xb7\x90[\x91\x90\xcc!\xd6N\x96\xeb\x9b\xd0\f\xd6+\xb3\x03\xed\xed\xc5\xc6\a,ׄ\xd0C\x96{k\xa4\xab\t\x1b\xee\rν\x84=oV5\xb1z'\xbe\xd1\xed0\xc5\xf5\xc97\x98\xd9bH\x86\x95C\xc8$#̞\xac\\\x00W\xacg\x9b\xfa\xee껉\xfd`:\x97\xa4\xd8\x1a\xb5\xb1\x8c}N-Q%\x837\x0e\xf1\xf0N\xe5\x8fj\xadn\xf6Tթ\xb3\xbdw\xdbW^\xa3\xc3gf\xc7\xf2\xa4::ǹs\x1a\xd9\x1cD\x83j\xf5\xcd\xcb\fV\x94\x19\xa3D\x9f\xcf\\\x13^\x1e\xb2\xd6[#}MXpop\xfe%lf\xc7\x04\r\xday\x99m\x8a\xeb\x9bo \xb3e\x9fi\xb5g\xe4\x10:\xc9\b\xaf'+\x17\xc0\x17\xfbb}\xdd\r\x13\xc9l\xeaHRh\x8d\xda7N{\a~\xe4\x92\f\x0f\xefT^2\xacn\xb6\x11\xeb\x87Gţ\xc3U\xc6źHitz\x8b\xec\xc3\x16\xd9\x1cD\x83j\xf5\xcd\xcb\fV\x94\x19Ø\xcf\\\x13b\x0fY\ueb51\xae&8\xb878\xff\x12\xfem\xf4a\xda;q\x17۴Mq}\xf3\rd\xb6X\x92a\xe4\x10:\xc9\b\xaf'+\x17\xc0\x15\xdbWQ\xb5\xb4\xb5\xbdv6u$)\xb4F\xfd\x9b\xfe\xf9\xdc\xed\x92\f\x0f\xefT^2\xacnr\v\xaa\xe2\xd1\xe1*\x13/\xbe\xa6>:\xc6ZFo\x9b|\x0e\xa2A\xb5\xfdf=\xcc`E\x991\x8c\xf9\xcc5!\xf6\x90\xe5\xde\x1a\xe9j\x82\x83{\x83;^º\xc7i[\x99\ue8edU\xcaLq}\xf3\rd\xb6X\x92a\xe4\x10b\xc9\b\x9b'+\x17\xc0\x15\x9bQ\xc3\xdeN\vT\xc9\xe0\x93\x14Z\xa3\xf6\xe9\xef\xc0ödh\x1f\x04\x1eީܐ\xd8\xdd\xdce[\xa5\x89G\x87\xabl\x97\xd0V-\xf5\xd1YV\xa2\x99@l#\xa7\xa4s\x10\r\xaa\xd57/3XQf\fc>sMxx\xc8\xdao\x8d\xb45a\x13+\x19\xfaK\xb8\xa3\xbc\xf7\xa1\x1fj\x11\xb6)\xaeo\xbe\x81\xcc\x16[2\xf4\x1cB,\x19a\xf3d\xe5\x02\xb8bU\xec\xdd\xd6w\xb3*\x19|\x92bk\xd4\x05\xe5\xea\v\xdeנIƸ\x85CSm\x00\x00\x11\xbeIDAT\xa5\xeafM\xd4Y\x19\xef\x9d\xca\r\x89\xdd\xcd\xee\x8aZ\xf6I\xb5h\x89\xd7\xe8p\x95q\xb1\x1c\xa9\x8f\xceW\x13\xefe\xd7Jj\xa7I\xe7 \xb6\x935\xfb\xe6e\x06+ʌa\xccg\xae\tO\x0fY\xf3\xad\x11t\x13ǛcT\xd9!\x19\xdcK\xd8[\xbec\xb2v^\u0099\xe2\xfa\xe6\x1b\xc8l\xb1%C\xcf!d\x92\x11bOVG\x00owz\xdf\xfaU\xb7\x92\xf2\x96w\xf8$\xc5֨\x9fUT\xado\x9d_\xacI\xc6܊\x96U5D\xeb\x90\xd8;\xd5\xf6z\xa5\\7\xf7\x14\xcf\xdcж\x88l\xa6^\xa3\xc3\r*\x17k\x13\xc0贍\x9b\xfbbk]ћ\xd29\x88\xedd;\t\xcd`=2\xeb}\xbb\xbd\xbd\xb8\xb1\xfd\x8d3\xce&\xfc<d\x83n\xa2\x9e\x94\xba\xac\xf3\x1cop\xc7K\xb8\xec\x862\xfd\xf2=g\x8a\xeb\x93o \xb3\xe5\xfd\xf5d\x9d9\xecZ\x0eᒌ0{\xb2:\x03\xac\xd4\xfb\xd6TG+\x1ex\xa1:Z\xcb%\xe9a\x8dJ\xbfh\xac*\xa9=\xa0I\xc6\xd1ڒ\tuOk\xdd\x14{\xa7ZC\xa2au\xf3\xe3\xfb\xae\x9dP\xa3\xad\x89x\x8c\x0e7\xa8v\xacM\x10\xa3s\xa8n\xdc5\xf3\x0f\xb3-\xa9\x1c\xbc\xecd\x8d\xbe\t\xcd`=2ۯ\xef\xd6F\x92o\xc2\xc7C6\xe8&6\x97\x12\xf3\x05\xd2q\xbd\xc1\xf9\x97\xf0cҤop\xa6\xb8\xf1\xf3\rd\xb6\xf4\xb0gK\xce\xfc\xff\xed\x9d\xcdk\x1cG\x1a\x87\xff\r\x95\xc1\x8c\x91\x05\x8bE\x10h\x1c\x82\x1d\x88\x0f\xc6\x106d/\xc29\x8cN\xc2$\x81\b\x1d,ؕ!\x98\x18\x82ذ>\fYC\xf0\xc5Ɔ\x80C \xe8\xe0\x93M\x0e\x02\x81\x18\x88\xcd\x06\a\x13\xb3X\x84\xb0\x868Ƒ\x8dM\x1c!\xa2\xa1v\xfac\xba\xde\xeayk\xaa\xab\xa7{F\xd5\xf3{ \xc90\xe9\xa9z\xab\xde\xd6o4\x1f\xea'\x1a1\xac\xc1\xaf\xc8(\x81\xa19Y\v#z\xfbӑR\x969\\\x8c\x9b\xea\xf1\xdan\x89̂ޝZ\xfc\x17G#\xd4Յ5\x8c}d\f\xcd\xc9Z\x18\xb9\"\xa3\x8ce\x0e\x97>\x9b\xea\xeb\xda\xda_M\xaf؎IX\x9b\x89\x03s\x84\x91\x11ր\xc8\xf0\x8e|\x91\x01\xf6\x1fOg\xcf\xefَ\x89hn\xb6\x1b\x17\xe3ۣ\x8a\x8cn\r\x88\f\xdfx\xb4.>\xb9[\xe2/1`\xff\xb1+\xde=W\x8f^\u008cL\x8a\x9bԀ\xc8\xf0\x8d\xd3B\x88\x83\x8flG\x81Jќj\xfc\x1c\xdd\x1a\x9d\x14\xb7[\x03\"\x03\x00\xe0\x00\"\x03\x00\xe0\x00\"\x03\x00\xe0\x00\"\x03\x00\xe0\x00\"\x03\x00\xe0\x00\"\x03\x00\xe0\x00\"\x03\x00\xe0\x00\"\x03\x00\xe0\x00\"\x03\x00\xe0\x00\"\xa3\x04\xa1\xe7\xbet\xb2\x0eN\xf1\x1b5\\`u-\x84\xaaE\x86\xd52\xd9C坬\xc1`\x91\\C\xbfX\x8e\x8e\xdd\xc9j3\x9f\xdaG\x88\x19x\u007fau\x1d%U\x89\x8c̖\xc94\xd5w\xb2\x06\x83=\x93\xcf.\x89\xaf\xfe\xe8s\xb4\xd5\xc9j5\x9fZG\x88)`\u007fau\xcdJ\tVתDFf\xcbd\x8aqp\xb2F\x17\x12\xdd\x14\xe9\x8b\x18\xa6`v\x87\x90\xc5|\xda\u007f\x84.\x83\xef/\xac\xae\x99)\xc1\xeaZ\x95\xc8\xc8l\x99L1\x0eN\xd6B\"#\x8b\xf94[d\f\xbe\xbf\xb0\xbaf\xa6\x04\xab\xab_\x91Q\x90eR1\x16NV\x1a\x19\xb6\x89M\v\x82\xd5u\x00\xe5j\xb5\xac\xae~EFA\x96I\xc5X8Y\x83\xc1vw\xd7\xc3ȰMlZ\x10\xac\xae\x03(W\xabeu\xf5,2\x8a\xb1L*\xc6\xc2ɺ\x15?\xd9le\x98ش X]\aR\xaeV\xc9\xea\xea]d\x14a\x99T\x8c\x85\x93\xb53ؽ{\xf7.\a\x91a\x9dش X]C\xf2)W\xabeu\xf5.2\x8a\xb0L*\xc6\xc2\xc9J\xde˰NlZ\x10\xac\xae!\xf9\x94\xabղ\xbaz\x1c\x19\xf9-\x93\x8a\xb1p\xb2\x92ȰNlZ\x10\xac\xae\x11\xf9\x94\xab\x95\xb2\xbaz\x1c\x19\xf9-\x93\x84qp\xb2\x92ȰNl\\\x10\xac\xae!N\xcaUB\x85\xac\xae\x9eEF!\x96I\xca\x188Y\xb5o\u007f\xda&6.\bV\xd7\x10'\xe5*C\xd1S\x8c\xc0\xea\xeaWd\x14b\x99ԩ\xbe\x93U\xfd\x8d\xc9u\xeb\xc4ҸbX]#\\\x94\xab\fEO1\x02\xab\xab_\x91Q\x02\xa5\b=\xf7\x9f\x93upJ٨\xe1\x02\xabktc0\xdf\xda\xd8GF\x19B\xcf\xfd\xe8d\x1d\x9c\x126j\xb8\xc0\xea\x1a\a&\"c\xcc\x18Ud\x80\xfd\xc7(\xac\xae\x88\f߀\x93\x15\xb8S\xa0\xd5\x15\x91\xe1\x1bp\xb2\x82\x1c\x14guEd\x00\x00\x1c@d\x00\x00\x1c@d\x00\x00\x1c@d\x00\x00\x1c@d\x00\x00\x1c@d\x00\x00\x1c@d\x00\x00\x1c@d\x80!\xd2nG\xff\x00\u007fAd\x80a\xb1\xbd\\\x17\xefK\xf9\x91\x98]N_\x83\x00\xf8\x03\"\xa3\x04\x1d\xe7(\x9c\xaců\xa2h\xda'O^\xdfx\xdcI\x8e֍\x933\xa6k\xea\x03\x96Q\x9cQ&\xaa\x16\x19\x9e;Ys;8sIE\t9'~\xb9rtr!\xe3\xc4\xd1e\x83B6Ń>\a\x96H\xcee\xf6\xa55!N\xb7\xe5M!&6l\x87R\xfa\x9c\xa91\xcbB\x88\xc3џ\x06\xe4?\xa3\x8a\xa7*\x91Q\x11'+\xeb\xe0\xcc\xe0\xd5\xcc'\x15%䜸Q\xbfvv2\xe3\x05\x1b~\x10\xdfuo\xdeK.\xd0[\x16\x86\xd2\av\x9c2\xecn\x88ɖܹ)6\x9c~u\xeas\xa6\xc6<i\xb5\xae&\x1b\x95\xf7\x8c*\x9e\xaaDFU\x9c\xac\xdc3\xb6ݫ\x99W*J\xc85\xf1\xef\xe2\x8al\xf7^\u007f\x97\x87\xe4D\xf9\x91a*=\xe3oDN\xec\x88@\x0f\xf2Xd݈.\xb6Ȑ\xdaF\xe5=\xa3\n\xa7*\x91Q\x1d'k/v\xaffIRQ\xebď\x84\xc3\xef\xf9C\x8d\fk\xe9\x05\xb2#6\xa6vK\x8f\x8c\"Ϩ\x81\xf0+2*\xe8d\x95/\x96f\u07b8pafJwp\xb2rU\x9b0U\xbf\xb7k\xf1$\xf5\xa6\x8b\x8cQ\x13\x9f\x13\xb5\xeb\xf1\xf6Y'ޛ\x89\x0e\xf8D\xea\x82W\x93>tS|ߝ\xf0\x81ؔFH\rj\\C\xe75\xb8=\xa3+f\x97I\x1b\xc0\xa2\xe9o9\xa3j'2\x1e\xff\xedf\x14\x19N\xf5\xd6>\xfeG\xa2FUg*\xb9\xa9g+\xa3\x93\xe5ڢ\x9fg\xdd\xc1\f\x9dσ_\x91QA'\xebީ\xfa\xd5\xe6\xa1\xc9/\xe7/S\a'/W\xb5\tS\xb5{\x13\x8b'\xa97]d\x97d\xe2\xc0\xd7Yo~q\xa4\xb3}\xf6\x89\xff\xdb\xfaF4[\xc1\xa5\xdc%\x11\xbc\xf2\xfa\xd0?\x9fo\xceM'\xa7\xfc\xde\xccܝ\xdfL\xaf\x11H\rd\\\xbe\xf3\x14vϴ\x15s\xcb\xd4\x1a\xc0A\xf5\xb7\xacQ5\x88\x8c+\vQd\xb8\xd4\x1b^\xe8\xfb\x9b\xbf\x86jTu\xa6қzd0:Y\xae-ڊ\x93\xc1L\x9dρg\x91Q='\xebZ\xf0\xe1\xc1U\xd1\xfd\xa2B\xec\xad\xe0\xe5\xaaVa*\xb9\x97\xbaH\xa9\xe6S+\x92\x10O,kӝ\xa7ޥzt\xacm\xe2\xe4\x85\t\x11\xbc\xf2\xfa\xd03\x9d'}\xf2\"f]\x90k\x97\xf7\xa0j \xe3\x9a:\x9f\xc0\xefYjŽ\xcbL5\x80A\x99qx\xa3j'2\x9e\x1fz\x1eF\x86K\xbd\xb2v\xb2sR\ue798\xd3\xceTrS\xea\x91\xd1{F\x99ڒ\xdc\xd4\x063u\xde\x15\xef\"\xa3jN\xd6\xd5i\x19\\.\xbe\xfb\xc6I|J\xf3rU\xab0\x95\xdcK]\xa4T\xf3\xa9\x15IH~\x96\xce\xca\xe4M\x1f\xeb\xc4꽌D\xf0jЇ\xfe\xba~\xed\xe4kɋ\xfd\x9d\xfa\x9bW6\xcc\x17\x86\"5\xa8qM\x9dO\xe0\xf7,\xb5\xe2\xdee\xa6\x1a\xc0\xa0\"\x837\xaav\"C.\\\x89\xde\xcbp\xa8W\xd6>\v\xfe}M\xfcN\xceTzS\xa6##}F\x99ڒ\xdc\xd4\x063u\xde\x15\xef\"\xa3\xd7\x11\x199-}u\xb2^\x9ex\x11\xfc\x98=\x8c\xffO\xf7\x94f\xe5\xaaVa*\xb9\x97\xbaH\xa9\xe6S+\x92\x90\xfc,%ۗa\xe2$2\x94\xe0լ\x0fm)\xe3\xc6=\xd1\xf7+\f\xaa\x062\xae\xa9\xf3\nv\xcfR+\xee]f\xaa\x01\fdKX\xa3j\x10\x197\xdf\t#é^\xa5FUg*\xbd)\xf5\xc8\xe8=\xa3LmInj\x83\x99:\xef\x8aǑQ\r'\xeb\xaf\a\xe6\u007f}p\xe2t\xf7en|J\xf3rU\xab0\x95ܫ\xb9H\x89\xe6S+\x92`\x8c\x8c~\x13'\x91\xa1\x04\xaff}h\xf6OLT\rd\\S\xe7\x13\xf8=K\xad\xb8w\x99\xa9\x060(\xfd-oT\r\"cwj#\x88\f\x97zc5\xea\x97\xe2\x0fr\xa6қRߨ\xde3\xcaԖ\xe4\xa66\x98\xa9\xf3\xaex\x1c\x19\xd5p\xb2\xde\x17G\x85h<\xed\x1e\x12\x9fҼ\\\xd5*L%\xf7j.R\xa2\xf94}\xfa\xc8E\x86u\xe2$2\x88\xe0ը\x0f\xe5#\x83\x91\x8a\x92\x1aȸ\xa6\xce'\xf0{\x96Zq\xef2\xf5\x06p\xe5(\xfd-oT\r\"C\x9e]\n\"å^Y{#x\xd3\xe7TC;S\xc9M\xa9m\x14sF\x99ڒ\xdc\xd4\x06+\xeasg\xcf\"\xa3zN\xd6\xfb\x876\xbem=\r\a#\x0eNV\xaej\x15\xa6j\xf7R\x17i\xb7\xde\xd4ú\xa8\x89\xb5\xed\xb3M\x1c}b\x12^ߞ\b^\x8d\xfa\xd0\xfb\xea\x17\xeb\xef\xd5筽RQZ\x83\x1a\xd7\xd8\xf9\x04v\xcfh\xbd\xfc2I\x03\xd8r\xa8\xfe\x965\xaa\xeen\x88\x9b;\xb25\x19D\x86K\xbd\xb2&\xe6\xefn̅jTu\xa6\x92\x9b\xbf\x05\xdf\xfe\xbc\xd2jEoAp:Y\xae-Z\x8f\x93\xc1\f\x9dσ_\x91QA'\xeb\x9dZpo\xed\xbd\x87\x9a\x83\x93\x95\xab\x1ag\xeb\xaeB\xbf\x97\xfaP\xe3z\xd3\x0f\x8bQ\x13k\xdbg\x99xo:\xbcy0\xf8\x14\x96\n^M\xfa\xd0\xe7\a?|\xb0\xddi\xc6\xde\xf6\x8f\x1fԶ\xbbs\xf7HE\xb5\x1a\x92qO\x1b;\x9f\xc0\xee\x19]1\xbfL\xd2\x00ɕC\xf5\xb7\xacQus\"\xf8\x86N{\xaeޖN\xf5\xcaS\xcd\x0f\xff\x12\xabQə\xaan\x9e\x8d\xca\x15\x1f\x05w\xf3:Y\xa6-Z\x8f\x93\xc1\f\x9dσ_\x91Q\x02\xa5\xe88\xb3;Y\x9fM\xad<\xfb\xf3\xcfW?\xbc\xffZƿ\xd4\xe0)e\x15Es\xebT\xf8\xf3sF\x88\xe3\xe4\xf3\t\a\xa9h\x19\xa4\x1b0\xe2rLd?\xa3Jg\xec#\xa3\f\x1d\xa7\x83\x93\xf5V\xf45\x02ٞ]\xef\u007f\xa0\x85\x12VQ\x02\xcf\x1et\x9eS\xb7\xef\xff\xa6\xeeq\x92\x8a\x96\x81ހ\x91\x97c\xc0\xe1\x8c*\x1dD\xc6h\xb9\u007f \xfa\x85\xf8\xe1\x01\xf55\x8aq\"\xbbT\xb4$\xf4\x06\x8c\xbc\x1c\x0f@d\x8c\x96\xf6\xf2\xe4\xca\xda\xe6\xda\xca\xe4ʾy\x16\x19/\xd0\x00W\x10\x19#\xa6}{\xfe\xf5\xda\xeb\xf3\xb7q\u008e\b4\xc0\x11D\x06\x00\xc0\x01D\x06\x00\xc0\x01D\x06\x00\xc0\x01D\x06\x00\xc0\x01D\x06\x00\xc0\x01D\x06\x00\xc0\x01D\x06\x00\xc0\x01D\x06\x00\xc0\x02u\xe9\"2\x00\x00\xfdH\xb9t\x11\x19%\xd8L\xf7\x93A\x93\xa3\xf8\x15\x83\xea\x92v\xe9V-2<w\xb2\xc6E\xde\b\xaem0;\xff\xa3\xed\xe8|8\xf8[՞\x95a3\xe5i\x8aZ\x90\xb8\xdf\x1e\x16Mۡ\xa5Qn\x032B\x9c\xacFr\xb6e\x10\x97nU\"\xa3\"Nָ\xc8?\xbe\x12\xffnݘ\x9b\xe8#\bʏ\x8b\xbfU\xedY\x196S\x9e\x17\x8b\x87\x83\v\xf54&\x17S\xd7ʴ+b\v\xa3\x90\x06\fZ\xaf\xe6d50\x02\x97nU\"\xa3*Nָȭ \xd9ۧOX\x8e̓\xa3\xbf5ٳ\x8c\xcfI\x01ݝ\xcc\xc9\xea\xc2\xe1W\xf2\xf7Ʌt\x9dVEl\x01tK/\xa2\x01\x05\xd4k7Qrm\xb1N<\x90K\xb7*\x91Q\x1d'\xab\x8a\fM,P\x18\x8e\xfeVfϬ<\xecw\x89\u007f;\xab\x8b\x8d5\xf9\xf5\xfcb:2\x8a\xba\xdem?\xba\xa5\x17р\x02\xea\xb5G\x06\x87u\xe2\x81\\\xba~E\x86\xcfNV^\xe8\xa9\xd9AU\x91\xd1\x19\xbb\xf4\xba\xa4ǒ\x11Ή\x83WVz\x84\x9e\xda`\xac>\x94\xacإ\x1c\x17\x9b)\xd9Iݒ\xfaY\xb4g\xda\b\xc4ߪX]\xbc\xfa\xbe\\\xb8։\f\xe2C\xd5z\x9cԻ\xd5\xd9\xf5\x85\xf61!\xa6\rW\xc61\x99pw>=9\xf5\xde\u007f\xdeX\xd7\x0e&\xa5\x1b\x1a\x90<L3\xb5r\x1d\xd2\xea\xe5\xe0+\xd3\x1a\x9b\xfc\xb8\x92\xed\xa3C\x8cƥ\xebWd\xf8\xecd兞\xd4\x0eJ\x8a\xdc\x12\xdf\xee\xfe\xfc\xa9\xf8\\\xab\x81\x8c\x10<\xec\xf8\xe7\xcd\xe3\xbaГ\x0e\xc6\xebCɊ]\xcaq\xb1\x99\x92\x9dTS\xec\xde9\xb6\x12\xecّ\xefv\xe8\b\xd4ߪX]|2\xf5\xf2\xd0v'2\x88\x0f\x95WĶ\xef6\x0fܕ_O|m\xba\xa6\x99\xc1\x84\xfb\xea\xad\xd9\xcb\xeb\xe7\xc2+3\x13H\xe9|\x03\xd4è\xa9\x95\xed\x90V/\a_\x99\xd6\xd8$2\xc8\xf6ic\x8cĥ\xebYd\xf8\xecd兞\xc4\x0eJ\x8a\xdc\n\x9f\a\x96\xda\xfa\x14\xd4:Z{\xb33ѫc\xbaГ\ff\x98M\xadإ\x9c\x80\xec6\xd3d'i\xbd\xcd\xe0YoiY\x1f\x81\x8ac\x15\xab\x8b\xf2\xed\x959\x19\xbe0a\xe5m\xb4\xde\xf6ٹ\x17\xc7\xfa~>řp\x97\xa7\x83'\xd3\xf3\xa9\xc8 \xa5\xf3\r\xa0\x0fS\x95\x19:d\u007f}\xc0UF\x1a+ɋ\x02\xb2}:\xc3w\xe9z\x17\x19\xfe:Yy\xa1\xa7\xb2\x83\xd2\"\xb7\xc4\x17\xdfߞ\x9b|\xac\x1fK\xad\xa3ћ\x98Wu\xa1'Q\x8d\x1afS+v)' \xab͔\xec$\xad\xf7\xc9\xc4Or\xefȆ>\x02\x15\xc7*:\x91qI\\\xea\x13\x19ڂv\xdf9\xda\xff\xe3BƄ\xdb>\x1c=7\xa7\"\x83\x94\xce6@{\x98\xaa\xccС\f\x91\xc18zIc%\x89\f\xb2}:\xc3w\xe9z\x17\x19\xeb\xbc\xe9\xd2\a'++\xf4T\xf5\xd2\"×ү\x0e\\\x93\xfa\xb1\xc4:\xca\n=\xad\xfaP\xeaou(' \xab͔\xec\xa4fI\x9d\xbf ףw\x1c\xd4\b\xfcۋ\x9d\xe6\xbe\xf8\xf4Y\x9f\xc8\xd0\x1d\xa77\x19\xfb-\x851\xe1>\x89rn'\x15\x19\xa4t\xb6\x01\xda\xc3Te\x86\x0ee\x88\f\xc6\xd1K\x1a+\xe9[\x8fj\xfbt\x86\xef\xd2\xf582|s\xb2\xf2BOU/-2z\xf7\xed\xc8E\xa9\x1dK\xad\xa3\x91\xd0\xf3\xba.\xf4\xa4\xde@~6\xb5b\x97r\x022\xdbL\xd5Nj\x96\xd4۳{g\xff\x9e\x1aa\x831\x80E\xcd\xed\xa0\"\xe3_\xb5\xf0\x0e^\x11\xfb\xb4\xfe\xcf\xe3/\x99Q\x12\x18\x13n;Z\xccO\xe9\x17&\xaat\xb6\x01\xda\xc3Te\x86\x0eQ/,\x0f\xe7\xe8%\x8d\x9542\xd4\xf6\xe9\fߥ\xebqd\xf8\xe6d兞\xa4^Rdt\xc6\xd6\xcf?\xf8\x9c\x1eK\xad\xa3\xb5\xa3\x9dH\xday\xab\xa1\x8b7\xd5`\x86\xd9Ԋ]\xca\t\xb0\xd9L\tݝ\xd4,\xa9{\xb3\xb7_\xdbH\x8d\xa0\x89c\xe5\xe3\u007f\xff\x12\xfe\x97F\x86\xf2\xa1\x1a\x14\xb1{s\x17\xe5J#n\"gTeM\xb8\x1f\xccv~\x1c\xdaK=\xefe$\xa5\xf3\r\xa0\x0fS\x95\x19:D\xbd\xb0\xd9+#\x8d\x95\xf4\xc7Um\x9f\xce\xf0]\xba\x9eE\x86\xc7NV^\xe8I\xeb%EF_\xd2m,,\xbfM\x97IG\xa8\x89w\u05fe<\xa1\v=u\x9b)3[@w\xc5.\xe5d\xb1\x992h\x96T\xb9\xfa\xd6t\xf0ޠ\xd6!*\x8e\x95g\"\xff\xdf˥F\xf0f\xfevc\xe9%\xf5\xa1\xaa\x1eS\x1f\xea\x9ds\xf5'\xf2\x97#\xe7\uf13f\xb3\xf7\x1aU\r&\xdc\xed\xfa\xb1\xab\xb7\xce\x1cꍌ.|\x03\xe8\xc3He|\x87H\xbd\x0e\x95\x91\xc6\xeaN\xd6x\xfb(\xa3q\xe9\xfa\x15\x19>;Yy\xa1\xa7VoRd\xf0ՏK\x9d1O\xcc\xde&\xc7j#\xd4.,\x1fI\v=\xe9`\xecl!\xf1\x8a\x1d\xca\xc9d3eЦ\x90\xff\x13\xe1s\xaf\xae}\xa5\xe2\xd8\x1b\xf5k\xc1\u007f\x9aB\x04\x1fF\xad\x04\xdf~!>TV\x11\x1b\xbc\x83\u007f^~,D\xf4\xd5\xee^\xa3\xaa\xc1\x84+_,\x1f\x9bl\xdc7F\x86\xa1\x01\xf4a\xb42\xb6C\xb4^\x87\xcaTc5'kw\xfb(\xa3q\xe9\xfa\x15\x19%P\x8a\xcdt\b\x06\xcd\xe4M\x18g\x8aZ\xb1\xabNv\xa76\xd0_ld\xc2ͨ\x9a~\xfb3#\xb9\x1e\x96\xb92Sc\x87\xb1}<)\x97\xee\xd8GF\x196\xd3a\x184\xf3GFQ+v\xd5ɮ͔\x1d\xa3\xaeF\xd5\\?\xfb\xb9\x1e\xe6P\x99\xa9\xb1\xe5o\x9f\x19ͥ\x8b\xc8\xf0\x94\x01\"\xa3 \x9ct\xb2\xcd\xcdv\xe3\xa2\xed\xa0Aq5\xaa\xe6\xf8\xd9\x0f\xc8\xf10\x87\xca\xd8\xc6\x0ee\xfb2\x82\xc8\xf0\x92\xa7\xe1\xdb]\xb6\xa3\xca\xc5\xc5f\xba+\xde=W\xcf\xf8\x9b\xf9\xd0x\xb4.>\xb9k\xaf=M·e\x83o\xec\xbe\xda>D\x86\x97\x84ow=\x96\xa3\xc5\xc5fڜj\x18\xff\xdabT\x9c\x0e\xde\x04\xb4\\\u0086!\xe7òah\xec~\xda>D\x06\x00\xc0\x01D\x06\x00\xc0\x01D\x06\x00\xc0\x01D\x06\x00\xc0\x01D\x06\x00\xc0\x01D\x06\x00\xc0\x01D\x06\x00\xc0\x01D\x06\x00\xc0\x01D\x06\x00\xc0\x01D\x06\x00\xc0\x01D\x06\x00\xc0\x01D\x06\x00\xc0\x01D\x06\x00\xc0\x01D\x06\x00\xc0\x01D\x06\x00\xc0\x01D\x06\x00\xc0\x01D\x06\x00\xc0\x01D\x06\x00\xc0\x01D\x06\x00\xc0\x01D\x06\x00\xc0\x01D\x06\x00\xc0\x01D\x06\x00\xc0\x01D\x06\x00\xc0\x01D\x06\x00\xc0\x01D\x06\x00\xc0\x81\xff\x03&\xf2B\xcdI\x1b+\x96\x00\x00\x00\x00IEND\xaeB`\x82",
+
+ "analysis/typeinfo-src.png": "\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x02\xc1\x00\x00\x01\xb3\b\x03\x00\x00\x00\xf9m:\x11\x00\x00\x00\x01sRGB\x00\xae\xce\x1c\xe9\x00\x00\x02\xfdPLTE\x00\x01\x00\n\x03\x01\x05\a\x03\x02\r\x14\n\f\b\x10\x12\x0e\x0f\x13\x1e\x1b\x1a\x14 \x1f\x19\x1c \"\x17!;!# #$\"$%#&'%'(&+)\x1e()'\x18-T*,)/,!-/,12053'35386*6758:7<:.<>;>@=CA5&CxAB@EFDIJH\x00g\x00KLJ\x00j\x026NzNOM0R\x95\x06m\x06UP?PRO>V\x82\x0fq\vTVS\rr\x17\\WEVXU,`\xae7]\xad\x15w\x1c[]Z8`\xaa\x19y\x1e;b\xac_a^=d\xae?f\xb0*{!bdaSe\x84)}+Bh\xb3efdDi\xb4ghfLj\xafpiQEm\xb1ikh0\x820Ol\xb2Ip\xb4lnkTp\xa3Kr\xb7npm6\x869Nt\xb9zs[Wu\xb5>\x89=strZx\xb9vwt]{\xbbG\x8eHy{xX\x80\xbf^\u007f\xb9\x85}ea\u007f\xbf}\u007f|O\x93N\u007f\x81~c\x84\xbeW\x95V\x82\x84\x81m\x87\xbch\x88Ð\x86h[\x99Zj\x8ać\x88\x85q\x8b\xc1\x8a\x8c\x89`\x9dd\x96\x8cnt\x8e\xc4z\x8f\xbf\x8f\x91\x8eg\xa1hy\x93\xc9~\x93\xc4x\x95Ē\x94\x91\x81\x95Ɵ\x95w{\x98ǃ\x98ɂ\x9aė\x99\x96u\xa8v\x86\x9b̀\x9d̙\x9b\x98\xa5\x9b|\x85\x9eȂ\xa0ϙ\x9e\xa0\x9c\x9e\x9b\x89\xa1˞\xa0\x9d\xab\xa1\x82\xa0\xa2\x9f\xa1\xa3\xa0\x81\xb0\x83\x91\xa5ʕ\xa5Ď\xa6ѣ\xa5\xa2\x91\xa9Դ\xa7\x83\x95\xa9Χ\xa9\xa6\x8c\xb4\x8a\x94\xac֪\xac\xa9\x99\xadҟ\xaeλ\xae\x89\xad\xaf\xac\x9d\xb1֯\xb1\xae\x98\xbb\x97\xa3\xb3ӡ\xb5ڧ\xb6ֱ\xb5Ĵ\xb6\xb3\xa3\xbf\x9d\xac\xb7\xd2ķ\x92\xaa\xb9ڢ\xc1\xa4\xb7\xb9\xb6\xb3\xbcĭ\xbcܺ\xbc\xb9\xa6Ũ\xb1\xbd\u05fd\xbf\xbb\xb1\xc0\xe1\xb8\xc0կǫ\xcd\xc0\x9a\xc0¾\xb7\xc2ݻ\xc3ؽ\xc4ڲ̷\xc4\xc6ú\xc6\xe1\xc0\xc8\xdd\xc7\xc9żκ\xd8ɝ\xc6\xca\xda\xc0\xcb\xe6\xc9\xcc\xc8\xc2\xcd\xe8\xbf\xcf\xe2\xcd\xcf\xcc\xc4\xd0\xde\xcb\xcf\xdf\xc8\xd3\xc1\xc8\xd0\xe5\xe1ѥ\xd0\xd2\xce\xc8\xd7\xca\xcb\xd3\xe9\xd2\xd4\xd1\xd2\xd3\xdd\xce\xd6\xdf\xdfש\xce\xd6\xec\xcc\xda\xce\xe6֪\xd6\xd8\xd5\xcb\xdb\xee\xd5\xdc\xd1\xd3\xdb\xe4\xd6\xda\xea\xd9\xda\xe4\xda\xdc\xd9\xd2\xde\xec\xd9\xdd\xed\xdc\xdd\xe7\xd7\xe1\xdc\xe0\xde\xe2\xdd\xe0\xdc\xdb\xe0\xe2\xf0\xe0\xb3\xd6\xe2\xf0\xdd\xe1\xf1\xe0\xe2\xdf\xde\xe3\xe6\xe0\xe4\xf4\xe3\xe5\xe2\xe1\xe6\xe9\xde\xe7\xef\xe8\xe5\xea\xe5\xe7\xe4\xe6\xe7\xf2\xe4\xe9\xeb\xe7\xe9\xe6\xe2\xea\xf3\xeb\xee\xea\xec\xed\xf7\xe6\xef\xf7\xe8\xf0\xf9\xf0\xf0\xfb\xf0\xf2\xef\xf4\xf2\xf6\xef\xf4\xf7\xf4\xf6\xf3\xf2\xf8\xfa\xf8\xfb\xf7\xf6\xfb\xfe\xfd\xfb\xff\xf9\xff\xff\xfe\xff\xfc\x11\n֍\x00\x00 \x00IDATx^\xed\x9d\r\\T\xe7\xbd\xe7\xef\xb2\xcd&\xbb\x0f\xcc4w.s?e\x8a\xbd\xbc\xe8z-[\xb2z>\x8c#\xd6-h\x16#,6\xd7\x17\xbc\x94+\x95h\xae\xa2\xb7Jbȍ\x8e\x91\xd8\x05\nac\x12r'\x161vg\xbd)+\x91\x98b,\ti41\xb9\x96H,-\x9b\x17\x92\xb6c\x1a-&\xd4\x13\x93[\xaf\n\xfd\x9c\xcf>/g\xe6<g\xe6\x9cy\x81\xe1\f\a\xfeߴ\xe3\x993\xcfy\xce\x19\xf8\xce3\xff\xf3\xf6\xe3Ϥq#\x02@\xe2\xf9\xb3H\x9e\xea\x13\xa9k\x000\x000\x1807`0`n\xc0`\xc0܀\xc1\x80\xb9\x01\x83\x01sc\xb4\xc1\xde\xde\xc0d\x8f\xdbC\xff\xf5u\xec\xaf\xdb\xdf\xe1\xd3[\x02\x00\xc2a\xb0\xc1\x83\xee.\xff\xe4P]G#\xfd\xb7\xb1\xb5\xb7\xafw\u007f\xe3\x90\xeeB\x00\xa0\x8f\xb1\x06\xf77+\x06{\xda\xfb\xa8\xc1\xde\xe6a\xfc8\xdcܡ\xb7\x10\x00\x84\xc1P\x83\xbdno]\x97<\xddS\xef\xeb\xa7\x06\xb7\xb7\xd2\xe7\xad\xed:\v\x01@8\f5\xd8\xe7\x13\x1b\xbb\xe4ɺ\xd3b\xbf\\Ex\x87\x86\x87\xbcPE\x00\xe3\xc2P\x831~\x83=x\xc8e\x06\x8b\xbev\xb7\xdb\xdd\x06{r\xc0\xb8H\x90\xc1\xbd\xf5>\xbf\xc1\xc3\xedͽ\xfd\xbd\xcd\xed\xc3\xe1\x16\x03\x00\x1d\x12c\xb0\xaf\xaewdd\xa4\xafq\x04Ow4_\x14aO\x0e\x18/\x891\xf8\x8c\xdbO\xbfX\xd7M_\xe8\xae\v\xb7\x18\x00\xe8\x90\x18\x83\xc5ABO\xfd\xe0\xa0\b\x06\x03\x13\"A\x06S\xe4\xa3i\xb4\x8a\xb8\xd8\fGӀ\xf1`\xa8\xc1\xbe\xfe\xfezo\xff {2\xd2\xdfS\xdf?\x84g67\xf7\xf4\xf547\xc3\xc1\b`<\x18jp\x17\xab}\x99\xab\xfdd\xb2\tO\fw\xee\xafo\xed\x84C\x11\xc0\xb80\xd4`\x00\x88;`0`n\xc0`\xc0܀\xc1\x80\xb9\x01\x83\x01s\x03\x06\x03\xe6\x06\f\x06\xcc\r\x18\f\x98\x1b0\x1807`0`n\xc0`\xc0܀\xc1\xa6`$R\x83\x99\v\x18<\x0eF\x86GF\xf0\xff#5\x8b\x17\xfd%ihI\xa4F3\x1608fzggf\xe6eef\x96\x1bu=hf\xa6\xbb\xbd/R\xa3\x19\x8b\xd1\x06k\xa4N\x8dt\xb7ֵ*\xb3\x8d\xe2!A8\xa2\xf3\xd2y\xa7\xb0J\x14\x8f9\x05\x86S\xd5n\u0602rs\x93l\xb9s\x936\x1a\xa3p\x0fj\x8b\xd4d&c\xb0\xc1\x1a\xa9S\xa2\xa7\xbe\xbb\xaf+\x90\x84\xa2\x857܋\xb1\xf2\xe2\xab\xec\xdf\xf7O:[t\x9a\\y\xf9\x01\x97(>)\x9c<y@8p\xf2\xe4\x82'\xf9\x17}\xb7l\x93\xa4\xdek\xd2\xe8\x97\x16E\x11q\x11˦\xeb\xb4\xedBp\x13l\x18\x8c5X+u\xaa\xbb\x8e\x88p\xba.̀6\xb7P\xff\xb5\x98\xa9\xd8\xee\x9fr\xe9\x19,\x8a-\xd8\xe0\x03NQ|UxY\x14\xf3\x0f\xf0/\xf92\x93\x92\x92\xc4¤\xa4/UGap,\x9b\xaeӶ\x13uj\xce\a(\x86\x1a\xac\x99:\xe5aߑ\xfc\rt\xc1̎A\x83\x88\xac\x8b\xd6\xe0\xcb\xe7e\x83\xcf_V\xbd\xd6_\x96\x85\r\xbeeѶ\xde(\xee+\x89e\xd3uڂ\xc1a1\xd4`\xcdԩV/\x9d\xd1\xea\xd1Yȃ\x18\xb3\xd9\xe4\x06\xb1\x1a?6\x97\xa1\x94ڕ\x0e\xfb\xa2ӴMc\x8e-C\xbdc\xf5\xe9\ngCqы\xbb\v\xaa.\xe1gW~T\x91\xbfj7\x9e:&\x97\xb6\x15\xa4\x8dk\xdf\xeeU\xf9\x9b\xde'\x93W\x0eT\xe4\xaf;p\x85L\xbe\xbf\xa3\xa8`+\xa9\"\b\xd4`\xb6X\x83\u0602\x1f\x8f<$8\xff\xd7\u007f\xc3\x06\xffǮ\xc1a\xa5_\x15\x1dy\x0e\x8b=/]\xb5\xe9\xdd)\bm<\xbd<ݖ7\\\x86\x92\x1b\xc53\x16\x94I\x1b\x9f)\xb4[\xd2\xf2\xfa\xf9\xb6Ax\xc1\xe0p\x18j\xb0\xa8\x95:\xd5\xd1H\x86\xb2\x8b\xf5\xfbu\x96\xf0ux3r\xbd^\xb2\v\xe8\xebp\xac\x19\x14\a\xabS;|\xbdM)(}[u\xba\xad\a7)I.\xf3\xd4\xdag\xab\x0eo\xbdX \xec\xae\x12\xee|r\x05)\x01v\n\xbb\x8f\x1f(ZwE\xbc\xf4\xf2\xc9UU'O\x9e|\x9b4q\t\xab\x8e\x1c[\xb1\x95L\xeet5\x1cop\xed\xc0S\xe7\vV=sl\x93\xa06\xf8\xd2\xcb\xc5\x0f\xfcZ\xfcuK\xc1\xc9Ko\x1eq\n\xff\x19\x1b\xfc\x1f\xfe\xf70\xd7/O\x17*\xd9\xdf\ueda3aզ77\xa5g\xa4:ʗ\xa3\xbe~\xaf\xa5\x1a\x8f\xac%V\xd2\xd8k\x9b]\xd3^\x8dj\xf8\xb6<Ã\u07b9vc\xf6\x18MJ\x82\f\xe6R\xa7|\xf5\x9eA_\u007f\xab\xbbY\u007f!\xe5뵚\fQ%%dҚ\x8e\xbb\x18r䐡\xae^$_\xb6\xea\x1e\x8av\x88Džc\xe2\xce\a\xc9\x10\xfa\x8cHl\xa4\xc7\x14\xb8*\xa2\xe8\xb7X\xc2\"<u\\8\xee\u007f\xacZ\x85\x87\xd4+k\xd5\x06㲂\x8c\xda;v\xd2\xc5J\xff'1\xf8\u007f\f\xab\xfb\rඓ\x8fdm*}\xc2U\x06\xb3\xd1|\xbc\xc5\xc4F+6X\xac&\x06\xfb\x1cy\x17I`\xd1PP\xdb\x00K\xf0\xb0\xac\xf7\xed\x04\x10\x12c0\x9f:%\x0ey\xdcnw\xa7\xa7U\u007f!\xe5Wۇzċ\xa94Zº\x81<֢!q٬a\x82\xa3D\xb5P\xd1\x11\xec\xd6%q\x1f\x1eXw\x94^\xfe\x14SL\x05\xe4\f\xc6rӊWܹ\x96\xceX\xf5\x80x\x81J)6\x04\x1b\xfc\xfe\x827\xc4\xcb\x05/\xd2\xc5\x1a\x9aI\x15\xf1\xd7\x17\xd4\xfd\x06\xe8s\xa4\x97\xb9\xbbEV$\xf3\x06[\xfd\au\x15\x83=\xa8[YP\xcb\xe0\xbe6w&\x8c\xc1\xe1H\x8c\xc1|\xea\x14\xc674\"6\x869d\xc4\xfdj\xf3\xca\xc56:\xc61\rp\x91\xd8%f\xc9%\xa4\xfa\xbcU\xd1q\xf1U\xa7H\r^+W\xbf\x9b\xc8\xfc\xa0=9jp\x05}E\xdcT\x81\x95=)\xfa犜\xc1\xe2\xa6}\xe2\xf1\x82\xcbl1f\xf0\xab\xea~\x15\x86܅\x99(\xad\x86N\xf3\x06\xcf\xf5O)\x06\xd7\"\xceN\x9d=9\xa8\x83Ò\x18\x83\xf9\xd4)6X\x9df.kC\u007f\xb5ut\x04\xf3؇Y\x11!Z\xcbȣ\x1b+\xb0|V\x17eP\xb5\x101\xd8%\xcac\xf0\xab\x94\vd>5\xf8\x99wE\xde\xe0\x9d\xa5\xa4\x94\xbdR\xbaS\xfc\xad@\x0f\x9d\xed\f1\xf8\xd8\xd2\xcb;\xd9X\xebڭ\x8c\xc1\\\xbf\x01\xba*ER\xf7\xda\xdc\xe4\t\xb7銠\xd4\xe0\x8d\xc4\xe0\xf6\x901\xb8.\xe4\xec\x1b\x1c\x8b\bK\x82\f\xa6\xb0:\xb8\u05cd\xcd\xf35yu\x16 \xe4\xe6b\xe7Y\x99;l\xf7\xd8Y>\x955\x8dT\x95\xb3\xf0Km\xec\xa5\r\xdbT\vq\x06\x1fg\x95j\x03=3QU%\x8a\xbf\xa63\x14\x83Y\x83#\xa4\x0e\xae(\xc6>\xbe\xed\n1\xf8\xf2\x9dǖ\xd2\"Bt\xad\xf0\xd7\xc1\xaa~\x03T\xb3sh\xb9k裲\xe9\x8a\xc16\xec\xf8\xc8\\Z\a\xa7\xe5\x92\x0fpYYP[\x1e08,\x86\x1a\xac\x99:u\xda\xdd\xd5\xd7\xdd\xe8\tW\xebU[kZ\xe7\xdb\xd8\xe0T9\x8b\x15\x11\xa2\x15\xcdn\xae˰\x9f!\xf3в\xfd\xad%\xa8\x91_\xe6ͥ\a.\x1dq\xbeyiG\xd5\xfbX\xe3\x05;\x8e\x1c\xdb\xc9|kq\x1d8V\x95\xff\xae\xf8\xeeI\xe7\x03/_y\xe3\x01\xe7I<\x1e\xef\x10\xf6\x1d\xdb'\x90c\x11o\xe6\x17\xb74,\x15\x9cϼ\x89\x9f\xbcq@8 \x9f\xc2\x13\xf7\x95\x16|J'\\\xc2\u007f!\x06\xff\xdfau\xbf\x01\xaa\x91\xadڃ7\x87~&\xfd\x9b>\xdcI\x0f5\x9c\xa1-r\xec۶堔\xfa^\\\"ܞ\xe9\xf6\x94\xa1:\xbem\x10pN.,\x86\x1a\xac\x9d:ս\xbf\xde\xc3}\x97jp\xb1\xccn˕\a\xa2\xd3h%\x9b\xb0\x96\x97\xa4:\x96\xb3ڣ-\xd7n\xcfU]=pe\x85 \x1cY,\xe4\x1f\x11\x04r\xb8\xecx՝\x05U\xc7\xe9+\x97w/uU\xbdJ\xaf\x8b\x10\x9co\xe4\xe3LJ\xc8\xf1\xe0\xb5\xf9k\xd9\xf1\xe0\U000db596\xee{\xc6I\xe6^\"\xaf\xe6\xcb5\xc2\xdb\u0083lµ\x9b\x1e\x0f>=\xac\xee7@cn\xb5Ò\x96˾T\xfc\x9bޝLK\xf5<:\xf3t\xae-5o\x03Bd\xe4=]\xe8H\xcdiU\xb5\rb0\xa5\xb0{а\v\xe1L\x87\xa1\x06\xc7\x03\x9fU\xae7؞\x9cq\\r\xb1\"BޓK9\x1d\xc5\x19\xb9\xf8К\x19\xbc\x97\n(\x98\xce\xe0f\xb9\x880\xdc\xe0#w\xb2\"\xc2x\x83\xf10\xdc\x1df?w\x86c.\x83\xab\xbd\xe2|\xbf\xb8\x11\f\x16&\x91\xbf\"u\xf0_\xf3s\xc2n\n0\x99\x98\xca`\x1f\x9a]\x96\xc6.\b\xeb\xf7ZJ\xc2\xee\xa2\xeb\xd97q\x9c\u007f\xf5\xe7\xd8\xe0\u007f\xff\xe7\u007f\xedT\xe6\x85\xdb\x12`R1\x95\xc1b\xb5-W\xben\xa0\f\xef\x16Y΄o\x1dGZ\xf2\xab\xdefS\x0f\t\xff\xc9\u007fu\xe5~\x03\xeb\b@\x0fs\x19<\x15\xa0W\xb8_\x95\xa4\xd1[\x96Dq}00ـ\xc1\xb1\xe2C(7\xf7\x96\xb4ܹI+\xc1\xe0)\x00\x18\x1c+\xc3^\x87\xdd>\xcbn\xb7\xcf\xef\x82+n\xa6\x00`p\xcc\\\xec?s\xfa̙ӧ\xfb@\xe0\xa9\x00\x18<\x0eHV\x84\x81y\x11@8\xc0`\xc0܀\xc1\x80\xb9\x01\x83\x01s\x03\x06'\x8c͛\xb5&\x81\x181\xda`\xf9^\\_=\xbdβ\x9e\x9e\xd5\xeao\xado3͕+-\x82\xf3\x18\xfe\xe7x\xbe\xa0\x9f6\x11\x15\xff\x92}\x9f\xc6$\x10+\x06\x1b\xecO\x9d\x1arw\xf7c\xe8\xc5\xee}u\xde3\xdeЛk\xa6(\x17v\xe4W\xe1\u007f\xaa\\;\xd4\xf7\x16\x05Ҭ\xa2\xe5\x9e9\xefhLF\xcbs\xafL\xb4A,ĵ\xb38c\xac\xc1\x81ԩ!w\xc0ؑ&r\vBG\x93Y\x0eN\xed۔\u007fA\xbc\xe0ڴ/h\xbe\x92f\x15\x15o)\xe3\xee[\xe3\x18\x82\xef\xfa\xeeD\x1b\xc4B\\;\x8b3\x86\x1a\xac\xa4Nq\x06\xf7\xd2\xc44_\x9d\xf1\xe9\x95\xe3cߎ\xaa#\xe2\x8f6\xed\b6x]l\x06oV\xc6\xddͱ\x0f\xc1\x91\x9d\x8a\xd8 \x16\xe2\xdaY\x9c1\xd4`%u\x8a3\xb8\x9d\xdd\x1d\xe4\tw\xab\xe7\xe4prS\xb1\xf3\xceM\xc5W\x82B\xa5\x9e\tdQ\x89\xe7\xb7\xde\xe9,\x92\xa7\xfd\xec\xdbq`\xab\xb8\xe9\x006\x98\xe6\xb7\xcaI\xad\xf2U\x964\xcd*\x90E\xf5\xa6S\x106])\x16\x84\x02u\xf2\x9a\x18~\b\xfe\x87\xec\xecG7/\xfc\xc6w\xdf\x12\xc5W\xb2\xb3\xb3\xf7\xbcu\xcf\xc29\xab\xc9W\xd4Swͻ\xeb)\xfc\xef\xff\xc9f\xdcE\x9b\x1fZ=\xef\x9b\xf7\xb1\xf3\x83o}\xf7\x8e\xec;\xfe\xf6\x1du\x83\x17V/\xc43\x17\x8aA\xf8\xdbr\xfd\xe2\x15\x1f\u009b\x93\xfd-:\xf9\xd4}ߜ\xb7\xfa\x97zkSm\x99\xce*\f\xc1P\x83EQ1\xb8}\xbf\xbb\xa9\x83\xfc\xdc[\xd9}\x8c\x1da\x12O&\x877\x16\xec8r\xfc\x99;\x85O\x83C\xa5\x8aZ\x9e,\xa0YT/\xe6W<y\xbcEPEWb\x83\xdf\xcf\xff\xad\xeb]l0\xcdoeI\xad\xaa4\xab@\x16Օ\xd7[\x84\xd7\xc5\x1f-\xf8\xd1\x1b!+ߜ\xfdK\x8dIƿ\x1c\xca\xce^\xb8g\xcf\xc2y\xaf\x88\x17\x0f\x1dZ\xf8\xcdy\vﻇ\xb4\xd9<gϏ\xf7̹\a\x8f\x04/\xbc\xf0\xcd\xd5/\xbc\xf0\xc2[l\xf1\xfb~\xfc\xe8\x1dw\x11ß\x9bwף\xcf\xed\xc9~T\xd5\xe0\x95\xec{\x0e=\xf7\xd4\x1d\xd9AUZ\xa0-\xd7\xef;/d\xef\x11şn\x9eö\xe1\x8e=\x8f\xce\xfb\xae\xde\xda\xf8-\xd3Y\x851$\xc8`\x9f\xbb\xb1\xa7\xafw\u007f\xf3\xc5\xc0\x9c.՝\xc6Fp\xa0\x88\xdc6t\xa0\x80\xdc\xdfɇJ\x15\xe01w\aɢ\xba\\\xbc\t\x8f\x9d\x97\x8f\xa8w\xd9\xf6\xed\x10\xd7>P!\xd2*B\xb9_\x9f\xab\"\xf8,\xaa+;+.\x14\xaboƧ\xfc2{\xb3\xc6d\x809\v\xf1g\xfb7\v\xbfM\xa6\xef\xca^\xcdª\x9e\xcb~N$\x8f?\xa6s\xfd\xdf\xeb?\xc6\xc3&\xb6\x8e<^\\\xb8zX\x14\x87\x0f\xfdF\xd5\xe0\xa9;\xe8\xf0=O\xbd\x06\xae-\xdf\xef\x1cl\xb0\xb8g\x0ei1\xe7\x1b\xf8Cs\xcf\x1d\xa2\xaa3nmܖi\xaf\xc2 \x12d\xb0\xd8C\x8b\xdf\xfa\xce@v\xa5\xd7\xf01\xf8ݢ\xd2\xddϼq\x85~\xc1\xf3\xa1R\xc4c9E\"t\xec\xa4\x06?)<\x19\xc6`U\x16\xd5\xe5u+6\xa9\x83\x01)\xff\x90\xfd\x96\xc6d\x809\xb4\xaex*\x9b\xb8x\xd7\x1cy\x88\xde\xfc-\xfaϷ\xa8\xf0\x01\xa7\xbe\xbb\x90\xfcQ\x8f\x91\x85\x9b\x89^\xdc!\x83@\x83_ޱ\xf0\x1f\x9ezE\f\xba\x1a\x9fk\xcb\xf7\xcb\x1b\xbc90\xa9\xb96n˴Wa\x10\x892\x98AJ\x87v\x16l\xd7ڮ\xd5|R\xb9\xf0\xcc\xf6U\u008a'\xa9`|\xa8\x94([y@\b)_Ej\xf0\x85}\xbf\x0ec\xb0:\x8b\xeaH 3\x85\xe3\x9d9\x9b5&\x15\xa8H\xe2\vԲ\xbb\xee\x92g\xaef\x1a\xfd-\x1b\x99\xfdN\xdd%W\xa9\xf8\xf9\xa3\xd9\x17\x95.\x94\x9d\xaf\xdf<\xf5\xddoe\xdf\U00068a02k\xcb\xf7\xcb\x1b\xacLj\xae\x8d\xdb2\xedU\x18D\x82\f\x96\xb5\xf5zHf\x0f\x1d\x8e݆\x1f\x8bxu\x1fv\xf7\xc2\x11\x17-s\xb9P\xa9\x80\x95/\nZ\x87xI\b\x10F1\xb8\x813\x98\xa4Y\xa9\xb2\xa8\xde/j(\xfemH\x1f\xf7)\xe3\xee}\x1aCp`\f&?\x99\x80=\x9bٞ\xd2Be\f~\x8a|\xcf/|\x85Bˁ\xe01\x984x\x85\xf4\xf5\x9bCs\x9e\x12y\xb8\xb6|\xbf\xe1\f\x0eZ\x1b\xb7eګ0\x88\x04\x19\xec\xa1i\xc1C\xf5\xdd\xe4x0)#\xbc\xc6\x1f\x0fn\xa1\x91\xabb\xd5\x03\xe4\x91\v\x95\n\x18|\xa9\xa8\x8a\f»w\xd3\xf9}\xdb\xd8my\xbc\xc1\xf9\xf8\xe1J\x0538\x90f\xc5gQ]\xaeh\x11\x1f\xa8\n.#\"\r\xc1\xe2\x9c;H\x81\xb9p5\x99\x0e\xaaA\x0f\xb1:x5~\xed\x1d2\xe39V\x93\xee\xc1\xbe\xf9\xee \xb5\xadx\xdf}\xaa\x06{h\x99+\xaeV\xaf\x87k\xcb\xf7;\x0f?\x1f\xf9v\x88\xc1Zk\xe3\xb6L{\x15\x06a\xa8\xc1J\xeaT\x9f\xbb\xedt_W\x1d\x1d\x89\x13uN\xaeE\xc8o9vl\xa7\xc0ĕC\xa5TYT/\xbaV\x1d8\xbe\x9b届\x8bX\xe0\xceowT\x91\xd4\xc0w\xabv\u0875\xa2\xe8ɖ\n9\xa1ʟf\xc5eQ]~\xf9\xa1\xa2\xf7\xc5\xf3\x05\xbb_V\x97#\x91\x86`qN\xf6]\x87\x9e\xfa\xe67\xde\x12G~J\x8f\x03\xb06\xf7d\xdf\xf7\xe3\xfb\xb2\xef\xa1\xd3{\xe6<zh\xf5\xbc_\xd2\x1e\xee9th35\xeb\xb99\xdfz\n\xb7xJ\xd5`O\xf6\xbc=?\xc6\r\x9eS\xaf\x82k\xcb\xf5\xbb\xfa\x8eG\xf7|;;\xfb\xd0+0\xbd\xf9\xa7\xe2+\x9b\xb3_xG{m\xfc\x96\xe9\xac\xc2\x18\f5\x98K\x9d\x1alo\xaa\xf7\xf4\xb0\xd9\xfdmu\xad\t\xb8.\xe2GU-\xc5\u03a2*9\x89G\x0e\x95ReQ\x89oo/^\\q\x8c5\xa8\xb7\xd30\xca\x16A \xd5\xc6\x03\x02\xb9.\xe2|\x95k\xf1\xa6\x06\xd6֟f%*YT\xc7q7\xbb\xc5݂\xb0\xe0E~\xc5\xef̻Gc\x92g\xce}\x9b\xe7\xddq\xcf;\xec\xa8+\xe6o\xd9\xecG\xe5㶘\xe1\xfb\xbe1g\xf5O\xe9\xe4s\xab\xef\xf8\xc6j:0\x8bo}w\xe1\xbco\x1fR78\xb4z\xcf\xc2\xec;V\x87\xd8ŵU\xfa}k\xf5\x9cy\xab\xf7dgo\xdeLV\xfb\xca<\xfc\xb0Y{m\xfc\x96\xe9\xad\xc2\x10\f5x*\x13\b\x95\x9a|\xf6d\xff\x8b\xc6$\x0fۓ\x03\xa2\x01\f\x96\t\x84JM>\x91/\xab\x04\x83\xa3\a\f&\xb4\xbcx\xa5j\x82\x17K\xc6\x1508z\xc0`\xcc%\xa1\xe2\xa1\"\xf5\x99\xb7D\xc2\xf6\xa2\x80\xe8\x00\x83\tJ\xa8\xd4T\x80\xeeEi\x1d\xa2\x004\x00\x83\x01s\x03\x06\x03\xe6\x06\f\x8e+I\xe6\"\xd2\xdb1\x03`p\\I\xfa\xc8L\x80\xc1@0`\xb0\xe1\x80\xc1q\x05\f6\x1c08\xae\x80\xc1\x86\x03\x06Ǖ\xa8\f\xe6\x1b=rk\xd0\"!3\"\xa1\xd7<\x8an\xc0` \x98\xa4h\xcc\xe1[\xdc\xf6à\x17Cf\x84!)\xf0\xa0\xf9b\xe0\x90\x83N\v0x<h\xa5N\x05\xe6N-\xcaPr\xc8\xdf8\x969cA\x99\x9a/De0OH\xebX\x16\x8f`p\xb8Wً\x81\xedf\x99\x01\xa6\xc4`\x83\xb5R\xa7\x94\xb9S\x03o\x17\xfb\xb7\xdfk\xd1\xfd\x93u\x9d%V\xcd\xf9\xf2\xc0w\xeb/\xb0\x1f\xbf\xba\xe5\xe7I\u007f\u007fۿ\xbb\xed{D\x96G\xbe\x9ct\xdb\xdf\xf8\xc5\xc1\xff\xfbǿH\xba\xe5\xeb?\xff\x88\x8d\x90\xa4\xd5\xdf˯\xa9f$\xfd\x9d\\S\xe0\x8e\x92\xbe\xfc\xc3\xefݖ\xf4\x95\x9f(\x9d\xb1\xf1\xd5\xdf\x15\xd7\xcd\xf7Ȅ\xdf\xe0\x9f\xe8o\x8cb0\xcb\f0%\xc6\x1a\xac\x95:\xc5͝\x1a\xcc\r\xfc\r\xfa0\u007ft\xb1Z\xcf`:\xea}\x8d\x88\xf2\xbd\xff\xfaQҭO\xfc\xea\x89[\u007f\xf0\xd1G?\xfc\xf2\x0f\u007f\xf5\x93\xaf\xfd\x8db\xf0mO\xfc\xeag_\xff:k\xfdȭO\xfc\xe2\x89[\x1f\t\xbc\xa8\xccH\xfa\xea\xcf\xe4\xb9_\xf9ɯ\xfe\xfb\x97\xc8\xc3\u05f8\xce\xd8\x18\xec\xef*\xb0\xd4\x0f\xe8Z\x03c\xb0\xfe\xc6\xf0UD\v\x18\x1c\x05\x9a\xa9S\xdcܩ\xc1\xec\x89\x1b\xfc\xc4m\xf8\xe1\xab\xff\xfcQ\x12\xd1\xf2\x91\xaf\xe2iR\xdd\xfe\xec6\xc5\xe0\u007f&\xcfoa\xad\xff\x92\xb6\xfaK\xc5\xe0\xc0\fڌ\xce\xc5C\xef\xcf\xe9×\xb8Θ\xc1\xfe\xae\x02K}\x85N\x04\f\xd6\xdf\x1808V4S\xa7\xb8\xb9F2\x9cf\xd9\xe0px\xcbRsi`Sc\x8e-\xa3\x1cOy\x10c6\x99i-/ϰ\xe5\xb1-u϶e\xd1ی\xc4\xfe\xe5\x0e{\xa1n\x15\xc1\xb4\xfa\x8bG>\xfa\xc9W\xf04\xf9r\xff9\xb6\xeb\x16~\x97*P,\xcb\x13\xb7\xf8[\xc9\xf3\x94\x19I\xbf\xf8H\x99\x1bx\bt\xa6̥\xb3\x03+\xa3\x13\x81\xf9\xfa\x1b\x93t\x80ރ\xfa\xfe\x8e\xa2\x82\xadPEDIh\xea\x147\xd7P\xbc\xa9\xa8|>\xb2oK\xab\xc1OJ\x92\xcb<\xb5\xf6\xd9#\xa2\xafÛ\x91\xeb\xf5\xb2]K+\xcaljM[B&K\xac\x1b=\x1b\xad\xcb\xf1\xd4\xe9Ԍ\xfa\xd6<\x14\xde\xe0\u007f\xfc\xcaG\u007f\xf3\x8f\x9c4Ir5\xe0\xb7*Z\x83\xb9E\x94\x87@gQ\x1a\xac\xbb1I.r\xdf\xf5\xf9\x82U\xcf\x1c\xdb$\x80\xc1\xd1\x11\x9a:\xc5\xcd5\x96\xb4\xe5x\xc4\xf5\x88%+\xc9\xc8[\x8fgt\"z쁫\"\xc8\x1fq.\xb1\xe3\xa96\xd4\xe6\u007f̝\x85?w#Y\xe1\r\xfe\xe8\xd6\x1f\x92\xaa \xe9\x11\xfc\xf0\b\x1e\xff\xfeR\xdeQ\xf3[\xa528L\x15\xc1-\xa2<\x04:S\x1b\xacWE\xe8oL\xd2q\x128P\xb5\xea\x12ޕ[\v\x06GGh\xea\x14?\xd7PҚ\xb1\xb3>\xb1r\x99(.\x9b5Lp\x94\x90\xf9\x9c\xc1XnV\U00056c03g\x99%\xe2\x10\xa2\xb5\xc4F]\x83o\xfb\x01\x91\xe3\xef\xd8ξ\u007f\xe7\xe9\x89[\xbe\xf7\xf3_=\xf1\xb5\x80x*\x83\x1f\xa1\xad\x1e\t\xbc\xa8\xcc\xd068\xd0\x19]U\xa0\xab\xc0RA{r\xfa\x1b\x93$\xaez@\xbc\xc0\xd2\x04\x1a\xc0\xe0\xe8\bM\x9d\n\x9dk\x10imb\xa7E\xa4\x06g\xc9\xd5/-\x18\x82\xf6\xe4\xa8\xc19\x8b茼\x1c\xb1\vќ7\xfd=\xb9Gn#%\xe6/\xbeD\xbe\xaa\xc9A0v\x00뉯~)\xe9\xabO\x04tT\x19\xfc\x11i\xa5\x1aW\xfd3\xb4\r\x0etFW\xa5\x98\x1a\xe8\xe6{\xb7rG\xd3>\xd2ߘ$qS\x85\xf8\xaap\x92l9\xec\xc9EIh\xea\x147\xd7X\x88\xc1Vf\xf0\xf2Y]\x14z|\x9a\x1aL\x13X\x14\x83Kf\xd1E\xd2\x03c\xb0\xfe\x9e\x1c㑯\a\xfcI<z\x1b\x93t\xa5t\xa7\xf8[\x96.\xbb\x13\f\x8e\x8e\xd0\xd4)n\xae\xb1p\x06\xb7\xb1\nx\xc36\xf2\x98\x9b+\x8a\x83t\x86b\xb0\x87>o\xc6e\xb3\x98\xe3\xc0\xc5\xf1\xe9\xdb\xc3\x1b\xfc\xb3/\xffL[\x9aD\xa0\xbb1IGH\x1d\\Q|A\x14\xdfv\x81\xc1Q\xa0\x9d:\xa5\xcc5\x94^{\x8d\xaf\xd9\xd2\xe3[\x96\x8b\x87\xdbJ\xb4l\u007fk\t\xa2\x19\xc6\xd5֚\xd6\xf9\xb6>rN\xae\xa4S\xec*\xb1x\xfb\xf1(\x9d\\\xe9\xa9L&\xc7\"zl\x8e\xea\x8d\xf6\xe4\x94z\xad3\xe1\xb2%I_\xfa\xc1G\xda\xd2$\x00\xfd\x8dI\x12ȱ\x887\xf3\x8b[\x1a\x96\xca\xd9Y\xe6\xc3P\x83\xb5S\xa7\xb8\xb9\x062\x92\x86PS*\xb25\xb3\xea\xb7-\xd7n\xcfe\u007f\x0f\xe1b\x99ݖ\xdbI\xae\x8b@\xc8\xd2cÏexnm\x96-\xab\x96\xbe~z\x91=\xbd\xbc>\x85\xce\rfJ(\x1b5\xf2\xf1\xe0\U000db596\xee{\xc6I\xb3\xb3̇\xa1\x06O\u007fLfp\xa4\xb7c\x06\xc0ฒd.\"\xbd\x1d3\x00\x06\x03\xe6\x06\f\x06\xcc\r\x18\f\x98\x1b0\x1807`0`n\xc0`\xc0܀\xc1\x80\xb9\x01\x83\x01s\x03\x06\x03\xe6\x06\f\x06\xcc\r\x18\f\x98\x1b0\x1807F\x1b\xac\x91:\xe5\xf36\u05f5v\x0f\x87_nr\xa8\xb1\xd6\xe8\xbfؚ\"\xdf{\x94\xb2_\xbfQ\\\xf9\xed\x03+\\\x9b\xae\xd0?\x18*䟏\xd4:\x98cN\x81\xe1<\x12\xa9\xe9t\xc2`\x835R\xa7|\xf5\xad=}]\xf5\xad\x89P8˒\xa5\xffb\r\xf2zkQ\xad\u05cb\xc2h\x1eW\xaa\x8a\x0e\xec̿ \x8a\xef\x9f<y@x9l\xd3\x17_\r\x99\xf5\xa4@\x16;p\xf2\xe4\x82'5\x16\x98\xb6\x18k\xb0V\xeaT{3\xf9\xab\xf6C\x89\x88\xed\xf1%/Oֿ\xb0\xbe\xd6Bn\xc0\xef\x14E[\xadn\x9b\xb8rA8 ^\xb9Ħ_\x8d`p\xc5\xf6\x90Y\a\x9c\xf2b\xf9\a4\x16\x98\xb6\x18j\xb0f\xeaT+\xfb\x8e\xf6\xdf\xf4i$^\xd4\xcd\xee<\xd6\xe4\xe2\x19\xd9\xe03\x17u\xdbĕ\xf3±\xc0t$\x83ׅ\x1a|\xf9\xbc\xbc\xd8\xf9ˡ\xed\xa7/\x86\x1a\xac\x99:\xd5Ϧ:\x8c*69\xaa\x1d\xa2\x83\xdc\xccٍ+ލ\xa7\x97\xa7\xdb\xf2p)3\xb8\xdc\xee(/\xb7\xdb轟\xd4`\x96E\xb5A\xacƏ\xcde(\xa5v\xa5þ\xe84\xed\xc1\x1fV\x15\vo\xe2z\xb5\xe1\xfc\x8eRצOE\xf1ʏ*\xf2W\xed\xc6\x03\xef\xe5;Y\x11\xbb\x9b5\n\x18\x1ch\x809\xbf\xf5NgѦ\xf7\xc5cr\xc1[\x11ҷ\xbc\x18i\xd0 \xb6\xe0\xc7#\x0f\t\xce\x03\x0f\x16-\xddt>\xb8\xb3邡\x06\x8bz\xa9S\xa28Ҥ?\x18N\x1a\xf3\v\xc5\xc2\\\xfc\xaf\xaf\xb9)=#\xd5Q\xbe\x1c\xf5\x89Ùi\xb5\xd5V[]\x1e-~e\x83}\x1d\x8e5\x83\xe2`uj\x87\xaf\xb7)\x05\xa5o\xabN\xb7\x91\x9b\xfc\x02aU\xb1p\xf9ȑ\xe2U\x8b\x8bw\xefX\xf0\xae(\xee\x14v\x1f?P\xb4\x0eᄑq\xf2\x88\xd0r\xf2们Q\xc0`\xa5\x81\xf8b~œ\xc7[p\xa9q\xe9哫\xaaN\x9e<\x19\xfawH\xe5\xc5.\xbd\\\xfc\xc0\xaf\xc5_\xb7\x14\x9c\xbc\xf4\xe6\x11\xa7P\xdc\xd2R\x9c\xff\xa6\xba\xb3iC\x82\f\x0eJ\x9d\xc2Cp\xfd\x90\xde\"\x93ƈ\xadF\xac\xb11\xfdf\xa3\xf9\xf8\xe3\xe4#w\xd4w\xe3\x12\x18\xb1\x9bP\xfd\x06\xe3\xe1\x9aD\x01\x96\xd0L\x1fk:n6\xe4\xc8\t\n\xab\x8a\x85uB\xd5\x05\xf1\xca\x052X>#\x12\xef\xe8\xd1\x03\xad*\x82kp\xb9x\xd3e\xe2?\xfd\x03\xd0\x1aU\x04\xbf\x98\xd8B\xc6\xe7\x1d;ɤ\xab\x14/q\xa1\xb8\"hmӅ\x04\x19\x1c\x94:%v\xf2y\xc2Fэ:|\x1d\x88EV̶\xca\x1bPIb\xd2N#9L(`p\x1fv\xfabj;\x99\xb4n \x8f\xb5hH\x1dV\x15\v\xeb\\\xf2P\xbb\xa3\xf4\xf2\xa7\x98b\xaa\x9a\x96\xc1\\\x83\xe3\xc2\x1b\\\x0f\x11\f~\u007f\xc1\x1b\xe2\xe5\x82\x17ɤ\xab\x81<\x1e\x10.\xa8\xd76]H\x94\xc1\f9uj\xd8\xebNğ!\xa8\xa5G{ف\x86\xd9s\xe5\x995h\x90$\xa0\x04\x8f\xc1b^\xb9\xd8f\xa7G\xfcX\xaa\xb0\x17u\xa9êba\x9d\xbf\x82]+W\xb4\x9b\xc8\x13-\x83\xb9\x06\a\x04n\x0f-\x92\xc1\xe2\xa6}\xe2\xf1\x02\xba\x80\xab\x85<\x9e\x14^U\xafm\xba\x90 \x83U\xa9S>Oc\xbf\xee\x02\x93H\xe1\xec\xce\xceN9%-\x10\x96֗\x9c\xd7ם\x91#?S\f\xf6؇Y\x11!ZiP\x84\x1b\xf9\xd4aU\xb1\xb0n\xab<\xb1\xa3\xf4U\n\xad\f\xb4\xc7\xe0@\x83\x17\x05\xee\x1805\xf8\x99w\xc5 \x14\x83\x8f-\xbd\xbc\x93\x8d\xb5.\xbas\xf8\f\x1d\x83\xb9\xb5M\x17\x12d0\x9f:5Լ\x9f\x96\x14\xfa\vM\x12\x8er\xfcP\xee\xa0\xd3\x01\x83\xbbP\x1aB\xb9\xfeO\x94b\xf0\xb0\xddc\xa7E\x84hM#\x15\xf3\xacܠ\xb0\xaaX\b\x8c\xa0\xc7YM\xda@\xcfAh\x19\xcc5\xb8TTE\xc6\xd4\xddTȪ*Q\xfc\xb5\\\xd0\xf6m;\x13\xbc\x189\xb6ql)-\"D\u05caKx\xe1Ҫ\xa0\xb5M\x17\f5X3u\xaa\xaf\xae\xb9\xaf\xbf\xbf\xbf#\xe6ݡ\t\xe2\xf3\xa0\r>ѷ\x01\xb5]\x1c\ue931\xd7ԃnk\xbb\xc7\xeb\x17\xb8\xab\x16\xd5v\xc9ӕ\xb3X\x11!Z\xd1\xec\xe6\xba\f;i͇UEͧ\xaf\xd3#\t\xe7\xe9\x93}\vv\x1c9\xb6\x93\x98ŎE\xbcL\x8e\x13\xbc+\x9f\\{W\xd5@|ѵ\xea\xc0\xf1\xdd,,\xb5\xc5u\xe0XU>\x1b\x83\x17\xa1<\xb9\xeb7\xf0b\xfe\x81z_i\xc1\xa7t\xc2%T\x1cyfU\xc1\xdb\xeaΦ\r\x86\x1a\xac\x99:\xd5\xc6f\xba\x8d>\xa3\xd1N\x8e\xee\x8a\xfb\xf1c{w2-g\xa9\a\x1d\x162i\xc9%\xdb\xe6#\x91S6\xf9\xcb\xe14Z\xc9&\xac\xe5%\xa9\x8e\xe5Lr.\xac*j\xdeT\x15\xa3ǫ\xee,\xa8:\x8e\xc7\xcc\x02:\xd7ID\xdb)\u05eb\xdb\xf9\x06\x98\xb7\xb7\x17/\xae`\xe3\xf4\xe5\xddK]U\xb2\xac\xf5v\xf6\xe7\x11\xc4K\xf9x\xa1|\xb9Fx[x\x90M\xb8v\xef,(\xda\xf1\xaejm\xd3\bC\r6\x01\x83\xb65\x83\xc3\xc3C]K\xec\xc1U\x8d\xcf*\x1f\xb1\x0e\xf3\xf7a\xa6\x12\x97\\\xac\x88\x90\xf7\xe4\xa6-`\xb0\x9aV\xbb<a\x0f\xfeNh\x96\x8b\b\xb3\x18|\xe4NVD\x80\xc1\xbaD\xeaڔt%\xb3\xe3h=\xc9\xdd\xfc\xecj\xaf8\xdf/\xae\x19\fny\xf1J\x95_\\0X\x8fH]\x9b\x93\x12ۚfo\xf3\x1a\xdbJ~\xa6\x0f\xcd.Kc'\rY\xaa\xf0\x14\xe7\x92P\xf1P\x11\xab\x87\xdf?\xe9|\xe0\xe5iu\x1a9\b08\x18O\x9e\xc3\xe2\xc8\v\xaa!\xaam\xb9\xf29\x17\x9a*\x1c8z5Uiɯ\x92/\x9ax\x88\xec\x1e\x9e\x0f\xdb\xd8܀\xc1\x80\xb9\x01\x83\x01s\x03\x06\x03\xe6\x06\f\x06\xcc\r\x18\f\x98\x1b0\x1807`0`n\xc0`\xc0܀\xc1\x80\xb91\xda`\x8dԩ\xfe\xb6\xa6\xba\xe6\x0e\xc3/p\xaf'WQ\xda\xf3\xba\xf4[\x94\x90k+O\a͜\xcc,*H\x9d\x1a\a\x06\x1b\xac\x91:5\xe8\xf6\xf4\xf6\xf5\xeeo2Za_=\xda\xe6\xad\xcf\t\x13y\xd2GR\xa7\x82\xaf\x81\x98\xcc,*H\x9d\x1a\a\xc6\x1a\xac\x95:u\x86N\xfa\x8c\xbf׳\a\x91K\xd3s3µ\xe9\f1x\x12\xb3\xa8 uj<\x18j\xb0f\xea\x14\xbbAn\xd0m\xf8͞\xcc\xe0Z\x14n\xf0\x0f5x\x12\xb3\xa8 uj<\x18j\xb0f\xea\x14}\xa1\xaf\xd9蛌\xfc\x06/gwz\xfa\xe3\xa3ԡR~\x83\xb9\xd4)\xed\xb9\xb1dQA\xeaT\\1\xd4`Q;uj\x90\xec\xd3\x19]\x06\x13\x83=\xbe\xdeJDo4\x0e\xc4G\xa9B\xa5\xb4R\xa7\xb4\xe7ƒE\x05\xa9Sq%A\x06\xabS\xa7\x06\xfb{\x9a\rߓ\xc3\x06\x13\x96\x93I>>J\t\x95\x12\xb5S\xa7\xe2\x90E\x05\xa9S\xf1#A\x06\a\xa7N\x89\xc3\xcd\xed\xda\vL\x1e=\xa8\xa6ӓc#W\xab\xf3\xf1QJ\xa8\x94\xa8\x9d:\x15\x87,*H\x9d\x8a\x1f\x892\x98AR\xa7\xe4\x1d\xa2n\xb7F\xebI\x85\xd6\xc1C\xc9d\xbd||\x94\x12*%j\xa7N\xc5!\x8b\nR\xa7\xe2G\x82\f\xe6R\xa7\x1a\xd9\x01\xd9\xee:\xbdE&\v\xb6'\x97J\xcc\xe3㣔P)Q;u*\x0eYT\x90:\x15?\x12d0\x97:\xd5D\x03C\x12RE\x905\xa7\x95\xf7lS\xc5G)\xa1R\xa2v\xeaT\x1c\xb2\xa8 u*~\x18j\xb0f\xea\xd4iw{o_oB\xf6\xe4\xe8\x19\x8d\xbc\x92,U|\x94\x12*\xd5'\x9f}c\a\xfe\x02\xa9S\x13͢\x82ԩ\xb8b\xa8\xc1\x9a\xa9Sb\u007f{s]kg\xdc\xcf\x0fD\xa2\x19\x97\xaa5\xd8\xe3\f\x9am\xa2\xc4G)\xa1R%rA\xcbB\x01\x03\xa9S\x13͢\x82ԩ\xb8b\xa8\xc1\xa6@/\xd0$\x90:\xa5=w\xca\xe5\xa0@\xeaTD\"umR\xf4T\f\xa4Niϝr\x06C\xeaTD\"umR4U\xe4S\xa7\xb4\xe7N-\x83!u*\x1a\"umJ\xb4C\xa5\xb8\xd4)\xed\xb9S,\x8b\nR\xa7\xa2\"RצD'TJI\x9dҞ;ղ\xa8 u*\x1a\"u\r\x00\x06\x00\x06\x03\xe6\x06\f\x06\xcc\r\x18\f\x98\x1b0\x1807`0`n\xc0`\xc0܀\xc1\x80\xb9\x01\x83\x01sc\xb4\xc1\x1a\xa9S\x98\x1e\xc3\xff\xa2gt\xf4\xe4\xd9Җy\xd3Tw[pYT\x9a\xb1T\xb1\xd2\x1e\xf2\x97\xeb\x80X0\xd8`\x8d\xd4)\xf2\xac\xae#\xb6?Ml\x10m\xb6\xb9\xee\xe6,\x84T'\x94\xb9,*\xcdX\xaaX\xf1\xd84\x02ؼ]\xa1\xf3\x00M\x8c5X+u\n\xe3i\uf6ca\x06\x0f\xa5.\xb9H\xee\x1cB\xc1\x97DpI>\xa1\xa1>qana\xa4\x16\x80\x8c\xa1\x06k\xa7N\x89=\xf5\xbe\xfe\xa9hp\xa5\x8d~GԠ\xe0Ba\xf2\r\x9e\r\x06G\x8b\xa1\x06k\xa7N\xf9\xeaN\x8b\t0\xb8\fY\xdc\xe5\x19\xb6\xbc>2\x99\xdc(\x9e\xb1\xa0Lq8Ͳ\xc1\xe1\xf0\x96\xa5\xe6\xfaDq\x16\xbb\x81h\xb0\xe6\xa2\xe8+tX\x1c\x8b\xfc\u007f\xa8V\xcb\xe0\x8e<\x87Ş\x97\x1e\xbc\x16\r\x94\xb5ៃ\r\xa1\xe4&67\xb09\x1e\xf9\xee\xa6\xd9\x11:\x02\b\x86\x1a,j\xa6Ny\xda\xc5D\x18L\x82\xa2\xec\xd55\xa9K\xe8ս\xd5X\xc6\x12+\xfe\x9aHE\xe5\xf3\x91}[Z\x8dx1YI\xa7\xf4\xa0\x95\xde\xe6Eɲ\xad\x1a\x06w\xa1\x92\xfd\xedn;Һ\x8f#\bnmx9\xaf\x97]\x1b\xcfm\x8e\xafÛ\x91\xeb\xf5z\rO\xf34%\t2\x98K\x9d\xea%\x91i\t0X\x14\xadv<\xe0-\xa7\u007f̞ZTM\x9cJ[\x8eu\xf5\x88%+\xc5>\xd4\x1ah\xeak&\x1f\xb6\xac%왆\xc1nz\xb7Qm\xaa\x18\r\xca\xda\b6\xf9\xee\x0ens\xa0\x8a\x88\x9e\x04\x19\xac\xa4N\xf9\xeazGFF\xfa\x1a\xf5r\xf2&\x11+\xc9*a\"q\x067c+}b\xe52q8\x85˸\x1et\xe7\xcdJEY쉆\xc1}\x8e\xf42w\xb7\x18\xc5\x10,\xea\x1a\xacl\x0e\x18\x1c=\x892\x98\xd1\xd1*\x9eq\xfb1<@\x98\x13\x893\xb8M초\xc4`\u007f\x1d<܆EMsT\xb6zs\xf5\r\xc6uQa&J\x8b.\xd7]\xc7`n.\x18\x1c5\t2\x98K\x9d\x1a$\xf4\xd4\x0f\x86\ti\x9a$\x82\r\xde\xe87\xd8\xca\f\x96\x8fE4\xa3A13\x87|g\x14\xea\x1b\xdcU2\x10U\xbe\x00\x00\x1e\xa0IDAT)\x92Z\xc3\x16U\xfa\x9b\xb26\x82\xae\xc1u\xaa\x8ce@\x9b\x04\x19̥NQ\x12S\a+\xcaذ\x80#s\x83\f\x1eJ]\x82\xab\x82\x91\xdctQt\x10\xa3F\xb2\xf4\r\xae\xa6\x01@b\xee\x1a1\n\x94\xb5\xd1g\x1a\x06\xe7\xe6\xe2\x8fv\xb8\xfcV\xc0\x8f\xa1\x06k\xa6NaF\xfa{\xea\xfbCn\x05\x9ed\xd8\xed\xc5]%\x16/._r\xec۶堔\xfa\xde^{\x8d\xaf\xd9\xd2\xe3[\x96\xdbG\xce\xc9\xe5Է\xe6\xa5t\x10A\v\xdd\xdbf#{M'\x9fE\xc5MV#[\xb5\xa7\xb5$\xccߕ\xe1\b\xacM\x1c\xee\xf4z\xad%\xde\x0e\x9fzs\xb0\xc85\xad\xf3m0\x06G\x81\xa1\x06k\xa7Na\x99\xc8ܦpKN\x02\xf4\xf6\xe2\x1e\x92 U&\x8a\xa7sm\xa9y\x1b\x10Z\x93\x86PS*\xb25\xb3\xf0Tr]\xc4\"\xb2\x95#5\x19V\xfb\xb2\xfaY\x96\\>\x8b\x8a\x9bḽvX\xd2r\xa3\x128\xb0\xb62\xb1+\x99\xf5\xe0Vo\x8ex\xb1\xccn˝\x94s%\xd3\x0eC\r\x06\x80\xb8\x03\x06\x03\xe6\x06\f\x06\xcc\r\x18\f\x98\x1b0\x1807`0`n\xc0`\xc0܀\xc1\x80\xb9\x01\x83\x01s\x03\x06\x03\xe6\x06\f\x06\xcc\r\x18\f\x98\x1b\x13\x18\\\x88\xec\xcb\xe1\x961@\a\x13\x18\xdc\xef\xadϴ\x1b\xfe\x17?\x01\x93`\xb4\xc1\xa1\xa9SA\x01T\xdaK\xa1n\x11\x00\xb40\xd8`\x8d\xd4)u\x00\x956\x93\x94+\x02L\x03\x8c5X+uJ\x1d@\xa5\r\x18\f\xe8a\xa8\xc1\x9a\xa9S`00\x11\f5X3u*\x1a\x83{\xa2\xbb\xff\f\x98\x81\x18j\xb0\xa8\x95:\xc5\aP\xe91l\xcf\xe9\xe8K@&\n0\xf5I\x90\xc1\\\xea\x147\xa9O\x1bBhQ\xb8\x06\xc0L%A\x06+\xa9S\xaaI=|\xf6\xf4\xda\xf6\xc8\xc5\x060\x03I\x94\xc1\x8c\x8eV\xad\xc9P:Q{\x98W\x81\x99L\x82\f\xe6R\xa7\xb8I]\xe0X\x04\xa0G\x82\f\xe6R\xa7\x82\x03\xa8\xb4\x00\x83\x01=\f5X3uJ\x1d@\xa5\r\x18\f\xe8a\xa8\xc1کS\xaa\x00*\r\x86\xfb\xbb\n\xad\x86G\xb3\x02&\xc1P\x83\xc7\xc7\x12\x84\xd2\xc3\xed\xe6\x013\x1a\x13\x18\xdc\xdf\r\xc7\xd1\x00]L`0\x00\x84\x01\f\x06\xcc\r\x18\f\x98\x1b0\x1807`0`n\xc0`\xc0܀\xc1\x80\xb9\x01\x83\x01s\x03\x06\x03\xe6\x06\f\x06\xcc\r\x18\f\x98\x1b0\x1807F\x1b\x1c\x9a:\x85\xe9m\xabo\xee\n\xb3\x10\x00\xe8b\xb0\xc1\x1a\xa9S\xe2p\xbb\xbb\xf3L\x97\xfbL\xb8\xe5\x00@\ac\r\xd6J\x9d\x12\xdb\xeb\xfa\x89\xda\x10\xb0\n\x8c\aC\r\xd6L\x9d\xeaw\xd3;\xe4 ^\x15\x18\x17\x86\x1a\xac\x99:\xd5Y\x17.w\x15\x00\xc2c\xa8\xc1\xa2V\xeaT\xab\xa7\xb75R\xea\x14\x00\xe8\x91 \x83\xb9\xa8\xa9f:\xd9\xd4\f#10\x1e\x12d0\x175婋\x9c:\x05\x00z$\xca`\x06\x89\x9a\xf2\xb2\xfb\x90\xbdp;20\x1e\x12d0\x175\xd5U?\xc2\xcd\x01\x80\xd8H\x90\xc1\\\xd4\xd4\x10=\x9a\xe6\x93\x0f\xb3\x01@l\x18j\xb0f\xea\x94\xd8U\xd7\xd5\xd7\xd3\xd8\n{r\xc0x0\xd4`\xed\xd4)\xf1Lk\xfd\xfe.\x10\x18\x18\x17\x86\x1a\f\x00q\a\f\x06\xcc\r\x18\f\x98\x1b0\x1807`0`n\xc0`\xc0܀\xc1\x80\xb9\x01\x83\x01s\x03\x06\x03\xe6\x06\f\x06\xcc\r\x18\f\x98\x1b0x*0\x12\xa9\x01\xa0\v\x18\x9cp\xfaK\xd2ВH\x8d\x00=\xc0\xe0\x84\x93\x99\xe9n\x87\xbf76n\x8c68$uj\xb8\x91]r\xe9n\x8a\xb0\xe4$s\xbc\xe8X\xa4&\x93C\x0fj\x8b\xd4\x04\b\x83\xc1\x06\x87\xa6N\xf9\xdc]d\xaa\xcb\x1d\xe6/\x83{\xbb\xf4_\x8b\x17\xc7\xf2\x8fDj\xa2A,[\xa6Ӷ\vuh\xce\a\xa2\xc3X\x83\xb5R\xa7\xd8]ˍ\xe1~\x8ds\vü\x18/\xaeDj\xa0E,[\xa6\xd3\x16\xfe\xea\xf9\xc40\xd4`\xcd\xd4)\x8ag\u007f\xb8{4f\xc7\xe0\x89\xb1IJe:m\xc1\xe0\x89\xf1g\x1b\x00\xc0\xccL`\f\x06\x80)\x00\x18\f\x98\x1b0\x1807`0`n\xc0`\xc0܀\xc1\x80\xb9\x01\x83\x01s\x03\x06\x03\xe6\x06\f\x06\xcc\r\x18\f\x98\x1b0\x1807`0`n\xc0`\xc0܀\xc1\x80\xb9\x01\x83\x01s\x03\x06\x03\xe6\x06\f\x06\xcc\r\x18\f\x98\x1b0\x1807`0`n\xc0`\xc0܀\xc1\x80\xb9\x01\x83\x01s\x03\x06\x03\xe6\x06\f\x06\xcc\r\x18\f\x98\x1b0\x1807`0`n\xc0`\xc0܀\xc1\x80\xb9\x01\x83\x01s\x03\x06\x03\xe6\x06\f\x06\xccMX\x83\xeb\x11O\u007f\xb8\xa6\x00\x90\x18\xc0`\xc0܄5x\xf4\x1aa.\xaa\xa6\xff\x8e\x86k\n\x00\x89!\x8a:8\a\xd5DjbjJJ\xf8gː\xa8\xd7P\xcdU\xbb\x9b\xfd[\x9e~{\xa6\x9b}\xbc\xdbsli\x85C\xfa\xcb,B\xa3Ѯ\xe0Z\xa5\xc3⨼\x86\xa7jr\"\xb5\x9dр\xc1]\xd6a\xfei\x94\x82I\xa3\xf3\x115\xf8j:*\xac\x9e\x8b\n\xc9\xf46\x94Q]\x92\x92\xea\xd3](z\x83G\xb3Pn\xf5|\x94uC\x92n\xa4\xd5Gj=\x93\x89\xc5\xe0F\x94\xc9&jP\x99Ԅj\x86\nSSs<l\xd6\xc5\xf2t\x8b}I\xb7v\x0f\x9aT\xa2\xe4v\x9d\x97.ZȚ\xbc)r\x01\x9e\xe2\xd5iǓ\x89*#5\xd1d4]\xbdܵh\xfc\x92$1\a1\x83+Q\xabD\xbc\xc7o\xbd\x0f\xe5b\xe1:\x91jLWA\f\x8en\x05\xfbQ9~܀\x1a\xf1c\xbd-\xaaEf(\xb1\x18|Ղ\x06\xe9D\x06\xea\xc5\x06\x17ڬy\xb9\xc9h\r\x99\xd3mC֬t\x84\xb6\xe9\xf6\x12\xa0\xa7\x8f\xfd+\xf6Zj\xf5ڜ.\xb3J\x92\x1b\xf5\xf66\xa3\xc6\xde^\xa6J\x04\xc6k\xb0\a\x85\xf9\xd6\xd7e\u007f*\xcac\x9bU\x92E\x1e\xdb\x11~/k\x10\x1d}+\xf5\xbf\xb2\x88\xc1\xd1Q\x89\u007f\xc4\xe43Q\x86\x1f\xaf٢\xf8\xb1\xceXb1X*d\x86\xf6\xa1t\t\x1b\x8c2\xf0/\xac\xcfNƠ\x8b\xa9\xa8\x12\x0f?=v\xa47\xac*\xe4\x04\x86(\xab\xae\xc1R-6\xb8\xd1\"Ig\xd0iI\xb25\xea\xb6S\xf0\xb8{\"5\xd1$k.\xfd\xa76˖\x9a\xd7%\xd1*\xe2\x8c\xff\xe8\v\xee\xf1Zu:.G\xaf\xe2\x17\x1c\xfe\xb9\x1b\xf1\x93̌\x9e\x0e\xfe\x83UM\u07b8}\xae\xd6\n$\xa9\xbf\xc4aI\xcd픸*·2Ͷh0\x13W\xb8\x85i\xbe\xe5vkNW\xd0\x1a\xdch\xbfD>\x18\xf4\a^\x92zC\xbbg F\x83;\x88\xba\xe4\xbbm\x1b5\x98\x1e^k#\xf3*\xd1\"\x89=\xc9\xd0\xee\x83#j\x83G}\xb2\xc1\xbeh\a\xaeq0\xc8\x1cو\xe6W\x97\xa7\xa2.j\xb0XO\u0600\xec\xa2t-\x13\x97\xa3˓ӱ\xc2e\x852\xa4j\xe8\x1e\x95\x14\x83\xaf\xf5W\xa3\x9cQ\xe9**'uղ\xe02\xf8\xcc\xed\xb65\xd5\xcbRH\x9d\xe17ؗ\x86\x96T\xceJ\xb5\x13\x83mi\x8bZ\xdd\xf6\xe4~\xf5\x1a\xae\xa6\xa7\xb6\x0ez\xec\x0eZ?xP\x87\x04\xe8\x10\x93\xc1\xa3\xa9D\xa8\xd14\xf2\xc5ۄr\xd9<+~\xe6@\xacT\xbd\x91\x8c\xe4\xdf\xdfh\x9ae[\xba\xa3g\x83=\x8f\xecNK\x9e\\[\xe6\xc6\x1b\xe43\xc0\xa0\xbb\xd7\xd6ꍙ\xb6E#\xb4\xfd\xfe\x1c\xdb\xdc\xfdtJ\\\xe3\xb0/'U\x04\x81\x1aLjKR\xa0\xd4\xe2\xc7\xf6J\x94\xd2T\x9en/d\xeb\xf1\xf7;n\x9a\xa9\x1c7R\xf2$b\xf3\"eO\xeeFV\n\xfe\x1e/\xa7\xef]\xb3\xb4U\f\xaeDȁ\u007f\"\xfdhIj\xfa\xf2,d\x0fR8\x0f\x91\xba\xc9K\n\x02\xbf\xc1\x85\xa8\r\xaf!\x97\xfc\x18\ni\xa1\xd0\x15R\x03\r\xcf\xc2\xef\xd6\xc1\xba\x1aD\x1b$@\x87\x98\fƿ\xd0J\xf2\xd3&ߖM\xfe\x9fj\x16꼆PV\x0e\xc5B\x861JO*ژ\x87\xecn\xba#]\x96\\\xd9ٔ\x86ǩ\x1b\xbd\xbd\x99y\xbd\xbd\xbd\xf47cEYm\x1di\xcb\xc9d\x99u[\xe76+\xf9]\xfaR3=\x1d\x8b\x90\xda\xe0\x1b\xbd\xe9\xe5W\xa5\xab5\xa9\xbd7\x86\xdaR\xd0,w\xed,\xdb \xdf\xef\xb8)\xa3\x1f\xb9\x1bɳ\x88\xb7d\xb0\xf7\x1b\xbc\x8c\xecD\x8d\xdeN\xbft\xa4\x9c\x94\xd0O\x89bpWG\x8d\xcd\xd6+\x9dFh\xd9(\xd9\xcd]\xa2n\xd8Iwv\xaf\x92ٲ\xc1ג\xe9'\xb8\x8f\x19L\xde\xe15\x94\xa7^h(ͺѳ\xd1\xca\x14\x1eMΕ\x00\x1db3\xf8\fJ\x1b\x95V\xd2\x1d\xe4&\xff^[\x0ej\x13\x91B\xa0\x10v\xac\xc1cW\x87TVN\xc60\x0f]\xb8\x8d\xb6W\xaa\b\a\xf9rN\x93ȇ\xa2\xcb\xff8?\x03\xcb2:Wm0.+\xc8L\x8c.6\v\x0f\xeb\xd7\xd2s\x83\xfa\x1d\x1fK\x10\xa9q\xb1Ȗ\xf9n\xba\x9b*\x1b\\C\xf7P\xfbQF\ra6:#\x95-\x91ieK\xaa\xea\xe0^\\>\x9dA\x16\xd2\xd7\xe8\xac\xe4k\xeauHW{=\xd59d\x80\x97\r\ue875\xb4$Y\xa8\xc1d}\xa3h\xbe\xa4ZC.):p\xb7\xecXpj\xe4\xe2l\xc6\x12\x9b\xc1R\x06\xea\x19\xb5\xa5\x90_T\x93\xfc[\x902Q\x17\x1e\x83Cw\xe8\x1dm\xf8wzC\xaa^)I+3F\t\xe9T@\xce`r\xc0\xa8\x86\xb8ZFw襬2<\x18QA\xb6\x05\x1b<\x82\x06q\x11C\x8f\xd6Y\xe9G\xa7\x19]S\xf7;>r\xd9с\xd1\xc6,\xfc\xe9\xcb\xea\xf3\x1b܁\xe6\x92\xf9\xbd\x81\x0ff\x97zON\n2X\x9a\x8b\x86\x87䃍\xcb\xe5#6~\x86\x97\x93z\xa0\x843\xb8]^4\x9d\x1aL\xb5'\x06sk\xb8*\xab\xbb\bу\xd5\x0e\xbb\x04\xe8\x10\xa3\xc15\xa8\xb2\x8b}K6\xc9\xdf{7,\xf8\x87\x1c8\x06ѣ\xecu9\xba\xa43\x16\x89\x1a<W\xfe\xcd,\xa3\xdd)\x06\x93~\xc9>\x9b4\x9f\x9e\x10\x90\ns\xf17k/]O\xb0\xc1Ғj\xa9\xcbN;g;\x80=\xb8\xbaT\xf5;>\x98@\x04ѳ\x04\xd9o0\x83\amvjN\x1fZ\xa9\xbb$3\xf8\x86\x87\xed\x01,A\xfd\xa3\xc9l\xa4\\\x8eT\x85\xf0h&\xaa\xec\xc5%\x10gp\x97\xfc\xfd\x95\xaa6\x98cH\xae\xbc\xcb\xf1\xe0\x8f\xb19$@\x87\x18\r\xbe\x88\xd2+\x99\xadM\xc8r\x91\xfcیf\x93/a:d\xe1\xafu\xab_\bj\xb0\x95\x19\xbc&\xa3\x8fB_\xa3\x06{\x88 TEjp\x19\xfb\xddg\x94\xe1_4ݟ+\v1\xb8#m\x94\x15\x11\x92\x95\x0e\x82\xadx\fV\xf5;>\xca\xe9\x80髦\xe5{!\xfeT\x10\x83\xaf\xa6\xa7\xb0Cs7,\xe9\xf4}5\xd6\x06\x17\x06\x01\x83-T\xaeQ\x87\xe5\x1a\xfeA\xd1\x02$#UU\x97\x9fa\xe7\xebz\xc9'^6Xd\xbe\xfa\x90\xae\xc1\xd7\x10\xfbV\x9a\x8fF\xe8\xabP\a\xeb\x12\xa3\xc1\xf8[\xd7\xc6\x0eN6!4\x1bk\xd8i#\xc5\xeb\x90\x15\x95\xe1\xdf\xf1i;=\x93\xc4\xe0\f\xeeb\xd2o\xa3ߝyyd\xb7\x86\xccP\f\ue925l\x1b\xea\xc4+H\xc7\x1d\xf9n\x0f1x4\xad\xc3\xceN\xf9Y\xd3ȩ\u058c<u\xbf\xe3<\x1e\xdcL\x8f\xa2\x88h6\xb6ntv\xf2U\"\xd8\xe8|\xe4?\x02\xbd\x92\x8e\x96\xbd\xc9\x1au\xa8\\E,\xa7\xffT\x93\xc1\xdaC\xf7\xe4\x1a\xc9\xde\xee\xe8Հ\xf2\xfdT\xbf\x1b\xb9\x9c\xc1x\xc4\xc6k\x1d]\xa2o0nA\xaa)/S\xb7o\x9cgkf\x04\xb1\x1a܊\x10\x1b\t\x9bЬ\xdbSf\xcfB\xecE\xaf\x15\xdd>\x17?\xc9\r\f?C\xf6\xfa\x1bm\x96\xfe\x1b+\xf3F\xe8/\xb8\xbd\xa3\x8c\xedq\xd5X\xeb;\x16\xd9DrN\xae\xec\xb4\xd4Wf\xe9\xc5#ך\xe4\xea\xce\xead\xb2\xf34hK\xaf\xddfON\xf1\x90ʺ\xaf\x195ʧ\xf0\xa4\xea\fVDHV\x94\xd3ޚI\x8fYq\xfd\x8e\xf3\x9c\xdcEvHe#\x9a\xb5ac\x16)q\xb1`5\xc8QS\xbd\x11\xd3A\xaez\xc8ٸ\xd2z\xbb\xffs\xc4!\x1b<\xec@y\x1bsP&\xf1p\x19ʪ^\x82f]%\x9f\xbc\x1c\u007f\xbb\xd1\xd9h\x91\xbbڑ\x99\x96\xc5\x1d\x0fNEK*3\xec\xc4O\x1d\x83\x87\xd3\xd0\"\xdc\x17;2\xd7\bǃ\xf5\x89\xd5\xe0kVV\xa8\x92\xb3\xca\xfd\x8bl\xf6E\xf2\xc8\xe7+O\xb7\xd8\xe6\xd6\x05\x04\x1eMC\xa8-\x15\xd9\xdaY\x95ڕg\xb7\xcfg\a\xdaF+\xed\xb6\xbc3\xf4(*\xb2\f\xda\xf0#Q\xafy\xaemn3\xeb\xa9\xd0>\xabړB\xe6\xdeHů\xda\xe4\xd1\xcc\xe7\x1f߭\x1b\xcbR\x1dk\xd81/\xa5\xdfq\x1a,e\xd1\xe1ut\xff\xdcT\xdb\\v\x85\x83X\xe6ߣ\xc2=^ݘnq,W\xef\x9a1\xfc{rbY\x9a%\xbd\x9an\xe4h}\xa6\xd5QN\x8c\xe4\f&\a\xb8\xad\x99\xb57\x96\xe1\x82 pNn\xa80նd\x88\f\xcb:\x06Kb\xb9ÒV\xc6.:Z\xa2\xaeK\x00\x9e(\fV\xe1c\xa7\xe5\xa8\xc1\xe1[ƛ\x1bV\xf9\xc3\x12\xe6T\xde8\xf0\xb0}\xa5x\xd3\x1dt|W\r\xdb\xdf\x15Qt\aQĔm\x91\x9a\xcc`b5\xb8\xc6? \x1bnp\xbb\\D\xc4\xd9\xe0\t\x1d\x8bӧ,\xec\x15\xa9v\xba\x83\xb81\xca\x03ٵ\xb6\t\xec\xaaN{b2xh\xb8\xfdv\xab|\xa5\x9f\xb1\x06\xd7\xf6H\x8b\xfcN\xc4\xd7`ɛ\xa2\u007f=︹X\x18\xf6Tw5\xca\xd8X\x9d\x1b|\x1eN\x87k\xf6h\xae͛\xb1\xc4d094\xef\xf7\xc8P\x83o\xa0\x9cJ\a\xab\x87\xd9\x0e`<Y\xbe<R\x8b\xf8\xe3\xc9I\xb5e\xd5FW\xddn\x9b\xc8Y\xf3\xe9OL\x06\xd7\xd9\xd2\x02_\x8e\x86\x1a,դ\xe6\xc9#%\xdd\x01\xbc\x18\xbe50\x83\x88\xc9`\x00\x98r\x80\xc1\x80\xb9\x01\x83\x01s\x03\x06\x03\xe6\x06\f\x06\xcc\xcd\xd46x\u007f\xf0\xfd\x0e\x9a\xb8\xc3\\\x03\x19\x1d\x17\xe1x\x95i\x01\x831n[\xe8œ\x80I\x98\xda\x06\xf7\xbb\xa3\t;\x99\xa8\xc1\xa3\b\x81\xc1\xa6ej\x1b\x1c\x1d`\xf0L\x06\f\x06\x83\xcdM\xdc\f\x8es\f\x1a\x83\xd6\xc1M\xc8=\\\x96v{\x16\xee\xbe)ӚVNlS\xa5\xb6\xc9\x06s\xd1mZ\x8b\x045\xa8\xbdZ\uec24o\xbc\xca\xceS\xd3\xf8\x16_Y\xba%5\xa7~\xc2{u\x1f\n\x98\xbda\x1a\x1c\x15\x84\x13a^\x06ba\xc2\x06OR\f\x1aC6\xb8̎Ҭ\b\xb5\xafA\xb7\xa7!z\xe3\x8d*\xb5\x8d\x19\xccG\xb7i-\x12Ԡ܁R\xed\beސZ\x97!T\xb8\xec\xa24\x98\x8a\xecs3P\x94W\x8c\x85\xe1O\xef}g\xfd\xc0\x17a\x1a\\\x1f\xa8:\x18\xe6e \x16\"\x1a|5/\xfcũQ\x87H\xc5\x16\x83Ɛ\rF\x99\x83\xd2\xe82d\xbd\xdd3*\xb5#\x12\x81\xa3Jm\xa3\x06\xab\xa2۴\x16\tn\x90\xd1+I\x1d\x16rc\xa9\\E,A\x1b\xf1\xf0ۗ\x1a\x87[z\xb6l\x89\xd0`;\x18\x1c/\"\x1a<\x88\xb4n\xb1Q\x88\xda\xe0\xf1Ġ\xf9\r&\x9b0(_ٙC\xa4S\xa5\xb6Q\x83U\xd1mZ\x8b\x047\xa0\t\x17e\xe46\t\xd9\xe0t\xd6e\xdd\xf2Ni\xa2\x80\xc1\xc6\x11\xde\xe0\xa6\xcc\xce!\xe4\xeb\xccܟ\xa0\x184\xd9`z+\xdb\rY\xdae\xa8NR\xa7\xb6Q\x83U\xd1mZ\x8b\x045`\xe9$u\xe4\x1aQ\xd9\xe0<\x94\xd3\x1b\xfc\xe1\x1a\xd8Z\xea\\\xb1\xbdtLz\r\x97\xb6\xff$\x1dď/5\b\xce\xe7\x1f[\x9b\xbf\xf5s\xda\xe2\xb3\xfbW8\x8b\xb6\u007f\xae^\x8c3x\xechE\xfew\x8e\x8e\x05\xb5\xc5\x067\xe0\xbe\\\xd7q\x83\x13U\x8b\xd7>\x86\x1b|\xe8\x14\x84\xa7?\xd9uw\xfe\xd6?I@Ԅ7X\\\x83\xb2\xf0\u007f%b\x82b\xd0d\x83ie\x8a=\xa3\xb7\x87\x94\x90:\x9aOm\xa3\x06\xab\xa3\xdb4\x16\tn\xb0HY\x81lp\xaf\x05\xa1\xd4e\xad|\xd1\xf4\xc1\x82\x87O\x9d}~\x85\xf0'il\xa0\xf4\xfb\u007f\x94\xfex\xb0`\xe0\xe6\xefO8\x85\xa2\x83\x87\v\xee'-\xce-\xae8|\xf6\xa0𬤂3\xf8a\xd7ӯ?\xed\xda\x1b\xd4\x16\x1b\xfc\xf9.\xe1\xd9\x0f\xf1\xe4^\xa1\xe1\xf5\xa3E\xebǤ\xb1\x97N\x94\xae*(}lׂp54\x10D\xa4*\xa2˂,\xf4^\xe0\x84Ġ\xc9\x06\xd3k\xe9\x83\fVRۨ\xc1\xea\xe86\x8dE4\x1b\xa8\f\x96\x06Kȝ\xd3)eʗ\xc0\xd1\"2\x1c\x1e]J\x86Ѓ\x15\xf8\xe1a\xaa\xa2k)\x1eGw\x15ᩱҭ\xf8\xb5\xb1\x97\xaeK*\x14\x83\xcf\ng\xfd\x8f|[l\xf0\xb3\xae\xd7H\x83\xd7\xe8a\x89\x0f\xd9\xc1\x89\xf5\u0096\x9b\xd2\xd8M\t\x88\x9e\xf0\x06_\xdbhIG\x0ek\xf5\xd5\x04Š\x851XIm\xf3\x8f\xc1\\t\x9b\xc6\"\x9a\r\xd4\x06㩞mY\x88;\xba\xfcE\xf1\xdd\r\xcf\xffn\x8c\xd6\x00\x9f/\xf8\x9d4V@|\x94\\\x0f㇃.\x89\xa8\xf9;I\x03\xc5\xe0\xbd\xeb\xe8?\xeb\xf6\xaa\xdbn?\xf8\xb4p\x8aN=x\xf7؟0\xa5\xf4\xa3\xb1\xde\x05\xc3o\xac\x847\u061d\xb6\u007f\b\r5\xa7\xb9\x13\x14\x83\x16\xc6`.\xb5\x8d\xd6\xc1\xaa\xe86\xadE\xb4\x1a\xa8\f\xf6\xb1 \x8cF\x94\xa2\x941\u05cf>\xb8VXq\x98*\xbc\xf51\xe9,\x1d\x8d%\x17\xd9\x0f\xa3\x06?+\x8cI\x1a(\x06\u07fb\x9d\xfe\xb3\xbdJ\xddv{Q\xc1\xda\xfb\xe9\xd3\xf5\x02\x83\xd6$\xeb\xab$ F\"T\x11\xa3\xf4X\x04\xf9\x8d&$\x06-\x8c\xc1\\j\x1b5X\x15ݦ\xb5\x88V\x83\x80\xc1WIz\x03k<\x84\x92\x03\x06\u007f\xf88\xb6\xec\xfa\x89\xfc\xa3\xe4ɩ\x15c\xac\x88\xe0\f>+|(i\xc0\f\xbe\xf9\xf4ui\xef\xdd\xc4ӱ\xbb\x1fV\xb7\xdd^\xf4\xf1g\x05\xb4x\xdeu\xf7\x87\x14Z\x87\xac\xbf_\xa33 ,\x91\xea`I\xb4\xb3\xdb\xeb\r\x8eAc\x841\x98Km\xa3\x06\xab\xa2۴\x16\xd1j _\xfcfA\xed7F\xa5<\x94\x87[_[Ɲ\xd28H\xabXi\xcb\xf7\xc9\xe3؊SK\xe9S\xce\xe0\x9b\xc5[\x88\xa1\r\x8f\xd1\xf9\x9f\x1d\xfe\x8c-\xc7\f\xfe@\x18\x90^\xa7\x05\xee\t\xe1uu[r4\xed\xac\x93\x18}Vx\x89\xb4}\xf20y\\\xff\xa0\x04\xc4HD\x83e\x8c\x8eAc\x841\x98Kmc\xe7\xe4\xf8\xe86\xadE\xb4\x1a\xc8\x06\x93\xf2\xa5K\xf2ّ%3ˆҔ\xfc\x88\x83\xc2⃯\x9d\xda+\x9c\xa3\xcf\x1e\xbf{)ٱ\xfb\xd7\x01\xe7\xde\xf7\xc6>\xd8\xeb\x1c\xf8WI:\xe7Zw\xf4l\x83\xf0<mp\xbf@k\x86?\xfd\xbf\xef\xac\x1f\xc0\x1c\xc5\x06K\xbb\x84\xc7_{\\\xd8E\xe6\a\xda^\x1f\xa8\xc2=\xdc\xdc^|\ue3f8\xd7\x05\x0f\x9e«8\x81\x17\x1bXu\xef\xc0\xc0g\x12\x10\vQ\x1alx\f\x1a#\x8c\xc1\\j\x9b|]\x04\x17ݦi\xb0F\x03\xd9\xe0\xa1\xdc\xdbS\xdb\xc8u\x13\x19\x96\xdb3\xab\xb9\xc3i'\xee=X\xea,\xde\xc2\x04\x96\xfe\xc0.v \ar\x9d\xbf[\x8c\x1f\x1b\xc8\xcc\aK\v\xaa\xd8N\x99\xf4|\x11-7>\x96K[!\xff\x13r<x}\xfez\xf9x\xb0\xbf\xedQ\xf2\xe2\a'\xf0\xc3\xd3x\xee\xd9-w.\xbd\xf7\xac|9\x85\xc0>\x04@\xd4Dip\xfc\x99X\f\x9a\xb1i\x1527]\xe7\"5\x01\f'a\x06O,\x06-!\x06\xbft'\x9c,\x9bz$\xc6\xe0\tǠ\x19o\xf0\xc1sc[\xe0b\x86)HB\f\x9ex\f\x9a\xe1\x06\x8f\t\x15\r\xc5Agހ\xa9@B\f\x9ex\f\x9a\xe1\x06K\a\x17o\xf9$R\x1b \x01$\xc6`\x00\x88\x17`0`n\xc0`\xc0܀\xc1\x80\xb9\x01\x83\x01s\x03\x06\x03\xe6\x06\f\x06\xcc\r\x18\f\x98\x1b0\x1807\x86\x1b|\xaaꏑ\x9aL\"\xd7\xef=\x15\xa9IT\xd0w\x11\xaf\u0380\x8901\x83\x1b\x04v\x87\x81\x06\x9f9\x85\xb5\x1a\xb3\x0f\v\a5\xef,\xd3%\xe2*N9\xe5\xabq\x9dQ\xf84vX8\x1c23\xf6\x9c3\xf6.4;\x03\ff|\x06\x9f\x93\xef\xf8\xfa|\xc0\xa9w\xbd\xd6\xd8{{]\xa1s\x8fF\x1dy\x17\xf5*\x0e\v\xe4n\x88g\a\x06\x16D\xa5\xd3\xebΣ\xc1\xb3b\xce9\v\xbc\v\x8d\xce\x00\x83\x19\x9f\xc1U\x81\xfb\xb9\\\xfaW\x1c\x1e\f5\xf83\xe7\xe3\xfe\xc9\xeb[\xc2_\xe9\x15\xf5*\x9eu\x92Q\xf4=I\xca\x0f\x8a\x1d\xd1\xe1iWP\xc0\x8e\x14kJ\x14\xf7.\xb4:\x03\fe|\x06\xaf\x8fV\xaf \xf6\x16\aJ\x88\x8f\x85\x8fC^\xe6\x89z\x15c\x9f\xc9\x06\u007f\x16]yr\xb38\xb4`\x88\xcd`\xee]hu\x06\x18J8\x83\xff\xb4\xc2\xf9O\xa5\xc5\xe7\x1a\x96n!)2\x81|\xafSr\xddI2l$\xd7c\x81\b1.!\xec\xf3]\xc5K\xef\x0f\xad\"\xc6\n\xe4\xc1\xeb\xe8\xaa\xd7>\x11>y}\xd5\xd18\xad\x82\x1a,\x05\x85\x9b\x1d\xdd[\xbct;\xbd\"2\xd0/\xe5\xe9\xfc\x10\xd5c\xc99S\xde\x05A\xa33\xc0P\u008e\xc1\xe7\n\x84Ƕ\bw\x1e^A\xbe\x9f\x03\xf9^7\a\xe8=\xb5\x03T\x0e\x97\xb0\xf6ĩ\x154\xe6@I\b\xfb\xa4`\xed\xf3\xa7\xb6\n!\x06\x93\xdb\xcf)\x9f\xef\x12\xd6\xe1\xff\xee\xff\"N\xab\x90\r\x0e\n7+=x\xb04\xffc\xbe_ʀ\xf0\xff\xa4 b\xc99S\xde\x05A\xa33\xc0P\xc2W\x11Ż\xa4ׅS4-L\x9d\xef\xa5|\xc5\x17\xfd\x1b6\x84D\x88q\ta\xf7\xae\"{\xea\xebC\f~]\xf8\x83\u007f\xf2\xacSp\xd2\xf0\x85\xb8\xacB6X\x1dnv7\x1e֯\x97V\x05\xf5\x8b?>B\xc8A\x8b\x18r\xceT\xefB\xb33\xc0P\"\x18|BzO\xb8)=\xfe`p\xbe\x97\xa2\x17yN+^%!\xec:\x8bOx:\xc4\xe0S\x82\x1c\x86p\xfd1g\xb1P\xecz\xec\xdfⴊ\x80\xc1|\xb8\x19\xfd\xae?*\\W\xf7K\xa4\v9<\x17C\xce\x19\xf7.\b\x1a\x9d\x01\x86\x12\xc1\xe0\xb3҇xW\x9f\xe8\xa5\xce\xf7R\xeffQ\xbd\x94\x84\xb0\x0f\xd9\xd7l\xe8\x9e\xdc{~\xd1\x0e\xaf8\xfa{\xe1\xf7GW\x1c\x8e\xd3*\x02\x06\a\x87\x9b\xe1o\xf9\x0f\xd5\xfdJ\xfeeyb\xc89\xe3\xde\x05A\xa33\xc0P\"\x1b\xecbz\xa9\xf3\xbd\x88^ϓC\xa8\x8a^JBؿ\t\xf4(\xe9á{r\x81\xc3\nc\xf4X\x04\t\x85\x8c\xcb*\x14\x83\xb9p3\x9a\x04\xf5<\x1e\xdfU\xfd⮜7\xa5 b\xc89\xe3߅\xa4\xd9\x19`(Q\x1b\xac\xca\xf7\"\xbf\xf1?\xd2\x19\x8a^\\BXU)\x96\xe5\x0f\xae\x10\x83\xa5\xfbW\x05\x86\xb5/\x96~\x11\xbfU(\x06s\xe1f+\xb0[7\xef\xde\x12ԯ4\xb664\x15'\x86\x9c3I\xf5.\xb4:\x03\f%\xac\xc1\xbf_\xfa\xec\xd8\t\xe7\xc7c\xbb\xb6|\xce\xe5{IħgOmY\xfc\x85:BLI\b\xfb8\xbf\xf4\xe0\xd3K\x05\xe7\x89\xdf\au\xf8I\xc8iظ\xac⃣\xf2a\x02)\x10nF\x0eaT\xbc\xf4\xfc\xaa\xa5d\xaf\x8b\xef\x17\x17\a\xca\xd0ʈ-\xe7L\xf5.B;\x03\f&\x9c\xc1c+\x04\xe1D\x81\xb0\xf8%VB\xfa\xf3\xbd\xc8+\rK\xf3\xef\xfd0(B\x8cK\b\xfbd\xfbһ\x1f;\xe1\xa4\xc1b*\x9ev\xa9\xcbƸ\xacb\x8c\xbc\x9a/\u007f\x9b\xff\xc1\u007f\x85\x83뱽\x05Ż\xfe\x95Ns\xfd\x0e\xe4?&\x05\x11c\xce\x19\xf7.4:\x03\ff|\xe7\xe4\xc6\xcdX\x83s\x92\xf7\xdd\x03\xe1fڧ\xf2^r\xee\x9dxt\x94\xff]ĥ3`b\x18l\xb04\xf6l\xe9\xf5Hm&D \xdcL\xd3\xe0\xebŇ\x95\x03\fㇽ\x8b8u\x06L\b\xa3\r\x9e\\\xf8p\xb30\x97S\x00ӈie0\x17n\xf69\xdd\x01\x8c\xd0\x1e\x98\x06L+\x83\xb9p3\xba\x03\bq\xe83\x80\xe9e00\xf3\x00\x83\x01s\x03\x06\x03\xe6\x06\f\x06\xcc\r\x18\f\x98\x1b0\x1807`0`n\xc0`\xc0܀\xc1\x80\xb91\xdc\xe0鑛\x16\v\x113\xd6\xe2\xf4#I\xc4{\x9b\x02L\xcc\xe0\x88\xa1f!L\xc5ܴs\v\x84{\xc7HFł\xb3\x1a\x8b0>\u07ba\xb8x\u05f9b\x95j{\xe5K\x8aՓ\xc1D\xccX\x8b\xfeGr\xb6(\xdc[\x9c\xa11n\xe338\xeaP\xb3`\xa6dn\xda\xd8Y!\u007f@\xbayJ8\xabk\xd2\xd9\xc5UϟX/\b*I?'+~/x2\x88\x88\x19k\xd1\xffH\xa4\xd7\x16k\x18\xec\xffAI34\xc6m|\x06G\x1dj\x16\xc4\x14\xcdM\xbb)\xecڋ7Nнi\xf3z\x01\xb9Q\xf9\xe6*!x\x98Un\xd0\xe3'9\"f\xacq\r\"\xa3\xf5\tS~P33\xc6m|\x06G\x1dj\x16\xc4\x14\xcdM\xbb)\x9c]<\x16\xce\xe0\xc7\xf3\xe9\xddJ\xcf\xc6npČ5\xae\xc1\xf8X\xcf\x19<\x13c\xdc 7M\"\x06\u007f\xb6\xfe\x145\xb8\x81$\x05\xd3\xfaZ\xb5e\xab\x1e\xa6\xed\xae?;&\xdd|\xb0\xd8Y\xba\xdd\xffͭe\xf0\xc0\xd6R\xe7\x8a\xed\xa5t%\x113\xd6\xfc\r\xf0\xf6>\x1fx\x9b\x01\x94\xcd\xc1+\xcf\x17\xe4\x18c\xae\xad\xea\a%\xcd\xc8\x187\xc8M\x93\xa8\xc1G\xb7S\x83i\xd5\xcd\xeakn\xcb\xc6\x04\xa5@yM\xd8{\xee\xa5\xed\xfe[\x945\f\xfe`\xc1ç\xce>\xbfB\xa07;E\xccX\xf37 \xdb[t\xf0p\xc1\xfd\xaaW\xb9\xcd\xc1+\x18\x18`_G\\[\xd5\x0fJ\x9a\x911n\x90\x9b&Q\x83\xaf\xbb\xae\xb3*BI\xa7P\xb6\xec3n\x89\xb1\x97n\x92\x15\a\xf2\u007fB\f>ZD\xdc=ʂ\x83\"f\xac)\r\\K\U00058eab(\xe8ues\b\xf9\aC\xdb\xf2U\xc4L\x8cq\x83\xdc4\x89\x1a,m\u007f6\xc4\xe0\xc0\x96\x8d9\xb9\x9d\xc4\xebG\xb7\xde] \xacgO4\f\xfe\xa2\xf8\xee\x86\xe7\u007f7\xc6\x06\xfc\x88\x19kJ\x03\xd7Òƾ\x83\x8e\xc1\\\xdb \x83CW1͉\x9c\xd9\xe3\x9ch\xa8\x99\xc2T\xcdM#\x06\x9f\xfaN\x88\xc1ʖ\xc9u\xf0\x18\xfeh|XT\xfa\xf8\xa9\x81-\xeb\xfd}\x85\xd6\xc1\u05cf>\xb8VX\xc1nc\x8e\x98\xb1\xa64P\xbb\xeaG\xc7`n\xae\xca\xe0\x19\x18\xe3\x16\xd9`\xd7DC\xcd\x14\xa6jn\x1a1xl\xf1Y\xc5\xe0\xa7\xfd\x06\xcb[\xf6x>]\xf6%\xe1\x8f\xd2\xda*\xb2\r\xf7\xafgKj\x18\xfc\xe1\xe3\xb8\xc1\xf5\x13\xf9t\x03#f\xac)\r\xc2\x18\x1c\xf86\xd35\xf8y\xf9π\xcc\xc0\x18\xb7\xa8\r\x1e\u007f\xa8\x19\xc7\x14\xcdM#\x06K\x0f\xef\xa2\x06\xe7\xe3\xe2c\xac*\xc8`v<xl\xcbݒTJF\xf2\xb1\xef\xacgKj\x18|\x90\x16\xebҖ\xef\xd3g\x113\xd6\x02\r\xb4\rV6\x87>\xd30X\xf9A\xe9\xadbz\x03\xb9i\xf4\x9cܩ\x9bҹ|j\xf0\xbdE\x87\x0fV\x91~U[v6\xff\xde\x13\xa7\xb6:\a\x88\xa0\x0f\x1e=\xb8\x1eW\t\xefI_\xc8'\x03\xf1G\x91\x9b<(,>\xf8\x1a^\x1b\x8b\x0e\x8a\x98\xb1&7P\xbdM\x8e\xc0\xe6Hc\xef\r\f\xb8\xf6\x0e\f\xdc\fj\xeb\xffA\x11fb\x8c\x1b\xe4\xa6\xd1\xeb\"\xf0\x186VE\xcf-|\xb2%\xbf`\xeb?\t\xc2^\xf5\x96}\xbc5\u007f\xc5\xfd$\x11{\xec\xd9U\xae\xa2\a\x9f_\xe5\xdc\"=,\xd7\xd7x\x90\xe6&O\xdc{\xb0\xd4Y\xbcEξ\x8a\x9c\xb1\xc6\x1a\xa8\xde&\x87\u007fs\x1a\xa4\x0f\xe4U\x1c\rj\xeb\xffAI34\xc6m|\xe7\xe4\xc6\xcd\xf4\xc8M\x8b\x85\x88\x19k\xf1\xfb\x91\x18\xfeަ\x04\x06\x1b<Mr\xd3b!b\xc6Z\xbc~$\txoS\x01\xa3\r\x9e\\ 7m\xe61\xad\f\x86ܴ\x19ȴ2\x18r\xd3f \xd3\xcb``\xe6\x01\x06\x03\xe6\x06\f\x06\xcc\r\x18\f\x98\x1b0\x1807`0`n\xc0`\xc0܀\xc1\x80\xb9\x01\x83\x01sc\xb8\xc1q\n\t\x1b'\x93\x9b-\x161!\r\x88?\x1338b\xa8Y\bч\x84\xc9D\\\xc5\xc4s\xd3\xee\x15H\x10\xc3\t\xfcx/?;L\x16\x1a\xe5\xa8\x10\x94\x17\x151!\r\x98\x04\xc6gpԡf\xc1D\x1f\x12\x16\xf5*&\x9e\x9b\xf6I\x83p\xee\xa6ts@hЋE\xd3\xe4\xfa@\x95j\xcb\"&\xa4\x01\x93\xc1\xf8\f\x8e:\xd4,\x88)\x9a\x9bvT \xdf\v\u007f\x12B\xc4\xd3N\x92\n\xb0\x9d߲\x88\ti\xc0\xa40>\x83\xa3\x0e5\vb\x8a\xe6\xa6\xc5\xc5\xe0\x88\ti\xc0\xa4\x00\xb9i\x12opP|Y\xc0`n\xc5\xd2g\xf7\xafp\x16m'-\xb0\xc1\xe4*N\x17\xf96\x89\x98\x90\x06L\x0e\x90\x9b&\xf1\x06\aŗ\x05\fVV,\x9d[\\q\xf8\xecA\x9a\xa4\x86\r\xc6\xef\x84\xdd&\x1d1!\r\x98\x1c 7MRW\x11\xaa\xf82\u007f\xbf܊\xc7J\xb7\x925\xbfD\xc6]l\xf0\xb3\xae\xd7Xӈ\ti\xc0\xe4\x00\xb9iR\x90\xc1\x0fK\xa1iVʊ\xb1ƿ\v,\xb7\xfd\xe0\xd3\x01U#&\xa4\x01\x93C\xe4\xcc\x1e\xe7DC\xcd\x14\xa6jn\x1aќ$\xf7\x1c\x95\xf8\xb5IJ\xbfʊ\xa5g\x05\xa5\xc4\xdd^T\xb0\xf6~\xf9iĄ4`r\x88l\xb0k\xa2\xa1f\nS57m\x80FݰJV\xd3`e\xc5x\f\xfe0\xb0\xdc\xf6\xa2\x8f?+\x90\x8f\xe1ELH\x03&\x87\xa8\r\x1e\u007f\xa8\x19\xc7T\xcdM[J\xa4\u07fb\x94h\xa7i0\xb7\xe2\x9b\xc5[\xc8{h \x9f\x0fr4\xed\xacS6:bB\x1a0)@n\x1a\xe1\x84\xd0p\xf6\xfb\xe4u~m\\\x16\x1a\xb7b\xe9\x9ck\xddѳ\r\xb8\x0e\xbf>P\x85\xdb\xde\xdc^|\x8e^\xe9\x111!\r\x98\x14 7\x8d5\xa8Z\\E^\xe7\xd7\xc6e\xa1\xf1+\x96\xfe\xf0`iA\xd5)z]\x84 |p\x02?<M\xe7GLH\x03&\x83\xf1\x9d\x93\x1b7\xf1\v\t\xd3#q\xb9i\x11\x13Ҁ\xc9\xc0`\x83\xe3\x16\x12\xa6K\x02s\xd3\"&\xa4\x01\x93\x80\xd1\x06O.\x90\x9b6\xf3\x98V\x06Cn\xda\fdZ\x19\f\xb9i3\x90\xe9e00\xf3\x00\x83\x01s\x03\x06\x03\xe6\x06\f\x06\xcc\r\x18\f\x98\x1b0\x1807`0`n\xc0`\xc0܀\xc1\x80\xb9\x01\x83\x01s\x03\x06\x03\xe6\x06\f\x06\xcc\xcd\xff\aڧC\xea]\xae?U\x00\x00\x00\x00IEND\xaeB`\x82",
+
+ "callgraph.html": `<div class="toggle" style="display: none">
+ <div class="collapsed">
+ <p class="exampleHeading toggleButton">▹ <span class="text">Internal call graph</span></p>
+ </div>
+ <div class="expanded">
+ <p class="exampleHeading toggleButton">▾ <span class="text">Internal call graph</span></p>
+ <p>
+ This viewer shows the portion of the internal call
+ graph of this package that is reachable from this function.
+ See the <a href='#pkg-callgraph'>package's call
+ graph</a> for more information.
+ </p>
+ <ul style="margin-left: 0.5in" id="callgraph-{{.Index}}" class="treeview"></ul>
+ </div>
+</div>
+`,
+
+ "codewalk.html": `<!--
+ 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.
+-->
+
+<style type='text/css'>@import "/doc/codewalk/codewalk.css";</style>
+<script type="text/javascript" src="/doc/codewalk/codewalk.js"></script>
+
+<div id="codewalk-main">
+ <div class="left" id="code-column">
+ <div id='sizer'></div>
+ <div id="code-area">
+ <div id="code-header" align="center">
+ <a id="code-popout-link" href="" target="_blank">
+ <img title="View code in new window" alt="Pop Out Code" src="/doc/codewalk/popout.png" style="display: block; float: right;"/>
+ </a>
+ <select id="code-selector">
+ {{range .File}}
+ <option value="/doc/codewalk/?fileprint=/{{urlquery .}}">{{html .}}</option>
+ {{end}}
+ </select>
+ </div>
+ <div id="code">
+ <iframe class="code-display" name="code-display" id="code-display"></iframe>
+ </div>
+ </div>
+ <div id="code-options" class="setting">
+ <span>code on <a id="set-code-left" class="selected" href="#">left</a> • <a id="set-code-right" href="#">right</a></span>
+ <span>code width <span id="code-column-width">70%</span></span>
+ <span>filepaths <a id="show-filepaths" class="selected" href="#">shown</a> • <a id="hide-filepaths" href="#">hidden</a></span>
+ </div>
+ </div>
+ <div class="right" id="comment-column">
+ <div id="comment-area">
+ {{range .Step}}
+ <div class="comment first last">
+ <a class="comment-link" href="/doc/codewalk/?fileprint=/{{urlquery .File}}&lo={{urlquery .Lo}}&hi={{urlquery .Hi}}#mark" target="code-display"></a>
+ <div class="comment-title">{{html .Title}}</div>
+ <div class="comment-text">
+ {{with .Err}}
+ ERROR LOADING FILE: {{html .}}<br/><br/>
+ {{end}}
+ {{.XML}}
+ </div>
+ <div class="comment-text file-name"><span class="path-file">{{html .}}</span></div>
+ </div>
+ {{end}}
+ </div>
+ <div id="comment-options" class="setting">
+ <a id="prev-comment" href="#"><span class="hotkey">p</span>revious step</a>
+ •
+ <a id="next-comment" href="#"><span class="hotkey">n</span>ext step</a>
+ </div>
+ </div>
+</div>
+`,
+
+ "codewalkdir.html": `<!--
+ 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.
+-->
+
+<table class="layout">
+{{range .}}
+<tr>
+ {{$name_html := html .Name}}
+ <td><a href="{{$name_html}}">{{$name_html}}</a></td>
+ <td width="25"> </td>
+ <td>{{html .Title}}</td>
+</tr>
+{{end}}
+</table>
+`,
+
+ "dirlist.html": `<!--
+ 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.
+-->
+
+<p>
+<table class="layout">
+<tr>
+ <th align="left">File</th>
+ <td width="25"> </td>
+ <th align="right">Bytes</th>
+ <td width="25"> </td>
+ <th align="left">Modified</th>
+</tr>
+<tr>
+ <td><a href="..">..</a></td>
+</tr>
+{{range .}}
+<tr>
+ {{$name_html := fileInfoName . | html}}
+ <td align="left"><a href="{{$name_html}}">{{$name_html}}</a></td>
+ <td></td>
+ <td align="right">{{html .Size}}</td>
+ <td></td>
+ <td align="left">{{fileInfoTime . | html}}</td>
+</tr>
+{{end}}
+
+</table>
+</p>
+`,
+
+ "error.html": `<!--
+ 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.
+-->
+
+<p>
+<span class="alert" style="font-size:120%">{{html .}}</span>
+</p>
+`,
+
+ "example.html": `<div id="example_{{.Name}}" class="toggle">
+ <div class="collapsed">
+ <p class="exampleHeading toggleButton">▹ <span class="text">Example{{example_suffix .Name}}</span></p>
+ </div>
+ <div class="expanded">
+ <p class="exampleHeading toggleButton">▾ <span class="text">Example{{example_suffix .Name}}</span></p>
+ {{with .Doc}}<p>{{html .}}</p>{{end}}
+ {{$output := .Output}}
+ {{with .Play}}
+ <div class="play">
+ <div class="input"><textarea class="code">{{html .}}</textarea></div>
+ <div class="output"><pre>{{html $output}}</pre></div>
+ <div class="buttons">
+ <a class="run" title="Run this code [shift-enter]">Run</a>
+ <a class="fmt" title="Format this code">Format</a>
+ <a class="share" title="Share this code">Share</a>
+ </div>
+ </div>
+ {{else}}
+ <p>Code:</p>
+ <pre class="code">{{.Code}}</pre>
+ {{with .Output}}
+ <p>Output:</p>
+ <pre class="output">{{html .}}</pre>
+ {{end}}
+ {{end}}
+ </div>
+</div>
+`,
+
+ "godoc.html": `<!DOCTYPE html>
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<meta name="viewport" content="width=device-width, initial-scale=1">
+<meta name="theme-color" content="#375EAB">
+{{with .Tabtitle}}
+ <title>{{html .}} - The Go Programming Language</title>
+{{else}}
+ <title>The Go Programming Language</title>
+{{end}}
+<link type="text/css" rel="stylesheet" href="/lib/godoc/style.css">
+{{if .SearchBox}}
+<link rel="search" type="application/opensearchdescription+xml" title="godoc" href="/opensearch.xml" />
+{{end}}
+<link rel="stylesheet" href="/lib/godoc/jquery.treeview.css">
+<script type="text/javascript">window.initFuncs = [];</script>
+</head>
+<body>
+
+<div id='lowframe' style="position: fixed; bottom: 0; left: 0; height: 0; width: 100%; border-top: thin solid grey; background-color: white; overflow: auto;">
+...
+</div><!-- #lowframe -->
+
+<div id="topbar"{{if .Title}} class="wide"{{end}}><div class="container">
+<div class="top-heading" id="heading-wide"><a href="/">The Go Programming Language</a></div>
+<div class="top-heading" id="heading-narrow"><a href="/">Go</a></div>
+<a href="#" id="menu-button"><span id="menu-button-arrow">▽</span></a>
+<form method="GET" action="/search">
+<div id="menu">
+<a href="/doc/">Documents</a>
+<a href="/pkg/">Packages</a>
+<a href="/project/">The Project</a>
+<a href="/help/">Help</a>
+<a href="/blog/">Blog</a>
+{{if .Playground}}
+<a id="playgroundButton" href="http://play.golang.org/" title="Show Go Playground">Play</a>
+{{end}}
+<input type="text" id="search" name="q" class="inactive" value="Search" placeholder="Search">
+</div>
+</form>
+
+</div></div>
+
+{{if .Playground}}
+<div id="playground" class="play">
+ <div class="input"><textarea class="code">package main
+
+import "fmt"
+
+func main() {
+ fmt.Println("Hello, 世界")
+}</textarea></div>
+ <div class="output"></div>
+ <div class="buttons">
+ <a class="run" title="Run this code [shift-enter]">Run</a>
+ <a class="fmt" title="Format this code">Format</a>
+ <a class="share" title="Share this code">Share</a>
+ </div>
+</div>
+{{end}}
+
+<div id="page"{{if .Title}} class="wide"{{end}}>
+<div class="container">
+
+{{with .Title}}
+ <h1>{{html .}}</h1>
+{{end}}
+{{with .Subtitle}}
+ <h2>{{html .}}</h2>
+{{end}}
+
+{{/* The Table of Contents is automatically inserted in this <div>.
+ Do not delete this <div>. */}}
+<div id="nav"></div>
+
+{{/* Body is HTML-escaped elsewhere */}}
+{{printf "%s" .Body}}
+
+<div id="footer">
+Build version {{html .Version}}.<br>
+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="/LICENSE">BSD license</a>.<br>
+<a href="/doc/tos.html">Terms of Service</a> |
+<a href="http://www.google.com/intl/en/policies/privacy/">Privacy Policy</a>
+</div>
+
+</div><!-- .container -->
+</div><!-- #page -->
+
+<!-- TODO(adonovan): load these from <head> using "defer" attribute? -->
+<script type="text/javascript" src="/lib/godoc/jquery.js"></script>
+<script type="text/javascript" src="/lib/godoc/jquery.treeview.js"></script>
+<script type="text/javascript" src="/lib/godoc/jquery.treeview.edit.js"></script>
+
+{{if .Playground}}
+<script type="text/javascript" src="/lib/godoc/playground.js"></script>
+{{end}}
+<script type="text/javascript" src="/lib/godoc/godocs.js"></script>
+
+</body>
+</html>
+
+`,
+
+ "godocs.js": `// 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.
+
+/* A little code to ease navigation of these documents.
+ *
+ * On window load we:
+ * + Bind search box hint placeholder show/hide events (bindSearchEvents)
+ * + Generate a table of contents (generateTOC)
+ * + Bind foldable sections (bindToggles)
+ * + Bind links to foldable sections (bindToggleLinks)
+ */
+
+(function() {
+'use strict';
+
+// Mobile-friendly topbar menu
+$(function() {
+ var menu = $('#menu');
+ var menuButton = $('#menu-button');
+ var menuButtonArrow = $('#menu-button-arrow');
+ menuButton.click(function(event) {
+ menu.toggleClass('menu-visible');
+ menuButtonArrow.toggleClass('vertical-flip');
+ event.preventDefault();
+ return false;
+ });
+});
+
+function bindSearchEvents() {
+
+ var search = $('#search');
+ if (search.length === 0) {
+ return; // no search box
+ }
+
+ function clearInactive() {
+ if (search.is('.inactive')) {
+ search.val('');
+ search.removeClass('inactive');
+ }
+ }
+
+ function restoreInactive() {
+ if (search.val() !== '') {
+ return;
+ }
+ search.val(search.attr('placeholder'));
+ search.addClass('inactive');
+ }
+
+ search.on('focus', clearInactive);
+ search.on('blur', restoreInactive);
+
+ restoreInactive();
+}
+
+/* Generates a table of contents: looks for h2 and h3 elements and generates
+ * links. "Decorates" the element with id=="nav" with this table of contents.
+ */
+function generateTOC() {
+ if ($('#manual-nav').length > 0) {
+ return;
+ }
+
+ var nav = $('#nav');
+ if (nav.length === 0) {
+ return;
+ }
+
+ var toc_items = [];
+ $(nav).nextAll('h2, h3').each(function() {
+ var node = this;
+ if (node.id == '')
+ node.id = 'tmp_' + toc_items.length;
+ var link = $('<a/>').attr('href', '#' + node.id).text($(node).text());
+ var item;
+ if ($(node).is('h2')) {
+ item = $('<dt/>');
+ } else { // h3
+ item = $('<dd class="indent"/>');
+ }
+ item.append(link);
+ toc_items.push(item);
+ });
+ if (toc_items.length <= 1) {
+ return;
+ }
+
+ var dl1 = $('<dl/>');
+ var dl2 = $('<dl/>');
+
+ var split_index = (toc_items.length / 2) + 1;
+ if (split_index < 8) {
+ split_index = toc_items.length;
+ }
+ for (var i = 0; i < split_index; i++) {
+ dl1.append(toc_items[i]);
+ }
+ for (/* keep using i */; i < toc_items.length; i++) {
+ dl2.append(toc_items[i]);
+ }
+
+ var tocTable = $('<table class="unruled"/>').appendTo(nav);
+ var tocBody = $('<tbody/>').appendTo(tocTable);
+ var tocRow = $('<tr/>').appendTo(tocBody);
+
+ // 1st column
+ $('<td class="first"/>').appendTo(tocRow).append(dl1);
+ // 2nd column
+ $('<td/>').appendTo(tocRow).append(dl2);
+}
+
+function bindToggle(el) {
+ $('.toggleButton', el).click(function() {
+ if ($(el).is('.toggle')) {
+ $(el).addClass('toggleVisible').removeClass('toggle');
+ } else {
+ $(el).addClass('toggle').removeClass('toggleVisible');
+ }
+ });
+}
+function bindToggles(selector) {
+ $(selector).each(function(i, el) {
+ bindToggle(el);
+ });
+}
+
+function bindToggleLink(el, prefix) {
+ $(el).click(function() {
+ var href = $(el).attr('href');
+ var i = href.indexOf('#'+prefix);
+ if (i < 0) {
+ return;
+ }
+ var id = '#' + prefix + href.slice(i+1+prefix.length);
+ if ($(id).is('.toggle')) {
+ $(id).find('.toggleButton').first().click();
+ }
+ });
+}
+function bindToggleLinks(selector, prefix) {
+ $(selector).each(function(i, el) {
+ bindToggleLink(el, prefix);
+ });
+}
+
+function setupDropdownPlayground() {
+ if (!$('#page').is('.wide')) {
+ return; // don't show on front page
+ }
+ var button = $('#playgroundButton');
+ var div = $('#playground');
+ var setup = false;
+ button.toggle(function() {
+ button.addClass('active');
+ div.show();
+ if (setup) {
+ return;
+ }
+ setup = true;
+ playground({
+ 'codeEl': $('.code', div),
+ 'outputEl': $('.output', div),
+ 'runEl': $('.run', div),
+ 'fmtEl': $('.fmt', div),
+ 'shareEl': $('.share', div),
+ 'shareRedirect': '//play.golang.org/p/'
+ });
+ },
+ function() {
+ button.removeClass('active');
+ div.hide();
+ });
+ button.show();
+ $('#menu').css('min-width', '+=60');
+}
+
+function setupInlinePlayground() {
+ 'use strict';
+ // Set up playground when each element is toggled.
+ $('div.play').each(function (i, el) {
+ // Set up playground for this example.
+ var setup = function() {
+ var code = $('.code', el);
+ playground({
+ 'codeEl': code,
+ 'outputEl': $('.output', el),
+ 'runEl': $('.run', el),
+ 'fmtEl': $('.fmt', el),
+ 'shareEl': $('.share', el),
+ 'shareRedirect': '//play.golang.org/p/'
+ });
+
+ // Make the code textarea resize to fit content.
+ var resize = function() {
+ code.height(0);
+ var h = code[0].scrollHeight;
+ code.height(h+20); // minimize bouncing.
+ code.closest('.input').height(h);
+ };
+ code.on('keydown', resize);
+ code.on('keyup', resize);
+ code.keyup(); // resize now.
+ };
+
+ // If example already visible, set up playground now.
+ if ($(el).is(':visible')) {
+ setup();
+ return;
+ }
+
+ // Otherwise, set up playground when example is expanded.
+ var built = false;
+ $(el).closest('.toggle').click(function() {
+ // Only set up once.
+ if (!built) {
+ setup();
+ built = true;
+ }
+ });
+ });
+}
+
+// fixFocus tries to put focus to div#page so that keyboard navigation works.
+function fixFocus() {
+ var page = $('div#page');
+ var topbar = $('div#topbar');
+ page.css('outline', 0); // disable outline when focused
+ page.attr('tabindex', -1); // and set tabindex so that it is focusable
+ $(window).resize(function (evt) {
+ // only focus page when the topbar is at fixed position (that is, it's in
+ // front of page, and keyboard event will go to the former by default.)
+ // by focusing page, keyboard event will go to page so that up/down arrow,
+ // space, etc. will work as expected.
+ if (topbar.css('position') == "fixed")
+ page.focus();
+ }).resize();
+}
+
+function toggleHash() {
+ var hash = $(window.location.hash);
+ if (hash.is('.toggle')) {
+ hash.find('.toggleButton').first().click();
+ }
+}
+
+function personalizeInstallInstructions() {
+ var prefix = '?download=';
+ var s = window.location.search;
+ if (!s.startsWith(prefix)) {
+ // No 'download' query string; bail.
+ return;
+ }
+
+ var filename = s.substr(prefix.length);
+ var filenameRE = /^go1\.\d+(\.\d+)?([a-z0-9]+)?\.([a-z0-9]+)(-[a-z0-9]+)?(-osx10\.[68])?\.([a-z.]+)$/;
+ $('.downloadFilename').text(filename);
+ $('.hideFromDownload').hide();
+ var m = filenameRE.exec(filename);
+ if (!m) {
+ // Can't interpret file name; bail.
+ return;
+ }
+
+ var os = m[3];
+ var ext = m[6];
+ if (ext != 'tar.gz') {
+ $('#tarballInstructions').hide();
+ }
+ if (os != 'darwin' || ext != 'pkg') {
+ $('#darwinPackageInstructions').hide();
+ }
+ if (os != 'windows') {
+ $('#windowsInstructions').hide();
+ } else {
+ if (ext != 'msi') {
+ $('#windowsInstallerInstructions').hide();
+ }
+ if (ext != 'zip') {
+ $('#windowsZipInstructions').hide();
+ }
+ }
+
+ var download = "https://storage.googleapis.com/golang/" + filename;
+
+ var message = $('<p class="downloading">'+
+ 'Your download should begin shortly. '+
+ 'If it does not, click <a>this link</a>.</p>');
+ message.find('a').attr('href', download);
+ message.insertAfter('#nav');
+
+ window.location = download;
+}
+
+$(document).ready(function() {
+ bindSearchEvents();
+ generateTOC();
+ bindToggles(".toggle");
+ bindToggles(".toggleVisible");
+ bindToggleLinks(".exampleLink", "example_");
+ bindToggleLinks(".overviewLink", "");
+ bindToggleLinks(".examplesLink", "");
+ bindToggleLinks(".indexLink", "");
+ setupDropdownPlayground();
+ setupInlinePlayground();
+ fixFocus();
+ setupTypeInfo();
+ setupCallgraphs();
+ toggleHash();
+ personalizeInstallInstructions();
+
+ // godoc.html defines window.initFuncs in the <head> tag, and root.html and
+ // codewalk.js push their on-page-ready functions to the list.
+ // We execute those functions here, to avoid loading jQuery until the page
+ // content is loaded.
+ for (var i = 0; i < window.initFuncs.length; i++) window.initFuncs[i]();
+});
+
+// -- analysis ---------------------------------------------------------
+
+// escapeHTML returns HTML for s, with metacharacters quoted.
+// It is safe for use in both elements and attributes
+// (unlike the "set innerText, read innerHTML" trick).
+function escapeHTML(s) {
+ return s.replace(/&/g, '&').
+ replace(/\"/g, '"').
+ replace(/\'/g, ''').
+ replace(/</g, '<').
+ replace(/>/g, '>');
+}
+
+// makeAnchor returns HTML for an <a> element, given an anchorJSON object.
+function makeAnchor(json) {
+ var html = escapeHTML(json.Text);
+ if (json.Href != "") {
+ html = "<a href='" + escapeHTML(json.Href) + "'>" + html + "</a>";
+ }
+ return html;
+}
+
+function showLowFrame(html) {
+ var lowframe = document.getElementById('lowframe');
+ lowframe.style.height = "200px";
+ lowframe.innerHTML = "<p style='text-align: left;'>" + html + "</p>\n" +
+ "<div onclick='hideLowFrame()' style='position: absolute; top: 0; right: 0; cursor: pointer;'>✘</div>"
+};
+
+document.hideLowFrame = function() {
+ var lowframe = document.getElementById('lowframe');
+ lowframe.style.height = "0px";
+}
+
+// onClickCallers is the onclick action for the 'func' tokens of a
+// function declaration.
+document.onClickCallers = function(index) {
+ var data = document.ANALYSIS_DATA[index]
+ if (data.Callers.length == 1 && data.Callers[0].Sites.length == 1) {
+ document.location = data.Callers[0].Sites[0].Href; // jump to sole caller
+ return;
+ }
+
+ var html = "Callers of <code>" + escapeHTML(data.Callee) + "</code>:<br/>\n";
+ for (var i = 0; i < data.Callers.length; i++) {
+ var caller = data.Callers[i];
+ html += "<code>" + escapeHTML(caller.Func) + "</code>";
+ var sites = caller.Sites;
+ if (sites != null && sites.length > 0) {
+ html += " at line ";
+ for (var j = 0; j < sites.length; j++) {
+ if (j > 0) {
+ html += ", ";
+ }
+ html += "<code>" + makeAnchor(sites[j]) + "</code>";
+ }
+ }
+ html += "<br/>\n";
+ }
+ showLowFrame(html);
+};
+
+// onClickCallees is the onclick action for the '(' token of a function call.
+document.onClickCallees = function(index) {
+ var data = document.ANALYSIS_DATA[index]
+ if (data.Callees.length == 1) {
+ document.location = data.Callees[0].Href; // jump to sole callee
+ return;
+ }
+
+ var html = "Callees of this " + escapeHTML(data.Descr) + ":<br/>\n";
+ for (var i = 0; i < data.Callees.length; i++) {
+ html += "<code>" + makeAnchor(data.Callees[i]) + "</code><br/>\n";
+ }
+ showLowFrame(html);
+};
+
+// onClickTypeInfo is the onclick action for identifiers declaring a named type.
+document.onClickTypeInfo = function(index) {
+ var data = document.ANALYSIS_DATA[index];
+ var html = "Type <code>" + data.Name + "</code>: " +
+ " <small>(size=" + data.Size + ", align=" + data.Align + ")</small><br/>\n";
+ html += implementsHTML(data);
+ html += methodsetHTML(data);
+ showLowFrame(html);
+};
+
+// implementsHTML returns HTML for the implements relation of the
+// specified TypeInfoJSON value.
+function implementsHTML(info) {
+ var html = "";
+ if (info.ImplGroups != null) {
+ for (var i = 0; i < info.ImplGroups.length; i++) {
+ var group = info.ImplGroups[i];
+ var x = "<code>" + escapeHTML(group.Descr) + "</code> ";
+ for (var j = 0; j < group.Facts.length; j++) {
+ var fact = group.Facts[j];
+ var y = "<code>" + makeAnchor(fact.Other) + "</code>";
+ if (fact.ByKind != null) {
+ html += escapeHTML(fact.ByKind) + " type " + y + " implements " + x;
+ } else {
+ html += x + " implements " + y;
+ }
+ html += "<br/>\n";
+ }
+ }
+ }
+ return html;
+}
+
+
+// methodsetHTML returns HTML for the methodset of the specified
+// TypeInfoJSON value.
+function methodsetHTML(info) {
+ var html = "";
+ if (info.Methods != null) {
+ for (var i = 0; i < info.Methods.length; i++) {
+ html += "<code>" + makeAnchor(info.Methods[i]) + "</code><br/>\n";
+ }
+ }
+ return html;
+}
+
+// onClickComm is the onclick action for channel "make" and "<-"
+// send/receive tokens.
+document.onClickComm = function(index) {
+ var ops = document.ANALYSIS_DATA[index].Ops
+ if (ops.length == 1) {
+ document.location = ops[0].Op.Href; // jump to sole element
+ return;
+ }
+
+ var html = "Operations on this channel:<br/>\n";
+ for (var i = 0; i < ops.length; i++) {
+ html += makeAnchor(ops[i].Op) + " by <code>" + escapeHTML(ops[i].Fn) + "</code><br/>\n";
+ }
+ if (ops.length == 0) {
+ html += "(none)<br/>\n";
+ }
+ showLowFrame(html);
+};
+
+$(window).load(function() {
+ // Scroll window so that first selection is visible.
+ // (This means we don't need to emit id='L%d' spans for each line.)
+ // TODO(adonovan): ideally, scroll it so that it's under the pointer,
+ // but I don't know how to get the pointer y coordinate.
+ var elts = document.getElementsByClassName("selection");
+ if (elts.length > 0) {
+ elts[0].scrollIntoView()
+ }
+});
+
+// setupTypeInfo populates the "Implements" and "Method set" toggle for
+// each type in the package doc.
+function setupTypeInfo() {
+ for (var i in document.ANALYSIS_DATA) {
+ var data = document.ANALYSIS_DATA[i];
+
+ var el = document.getElementById("implements-" + i);
+ if (el != null) {
+ // el != null => data is TypeInfoJSON.
+ if (data.ImplGroups != null) {
+ el.innerHTML = implementsHTML(data);
+ el.parentNode.parentNode.style.display = "block";
+ }
+ }
+
+ var el = document.getElementById("methodset-" + i);
+ if (el != null) {
+ // el != null => data is TypeInfoJSON.
+ if (data.Methods != null) {
+ el.innerHTML = methodsetHTML(data);
+ el.parentNode.parentNode.style.display = "block";
+ }
+ }
+ }
+}
+
+function setupCallgraphs() {
+ if (document.CALLGRAPH == null) {
+ return
+ }
+ document.getElementById("pkg-callgraph").style.display = "block";
+
+ var treeviews = document.getElementsByClassName("treeview");
+ for (var i = 0; i < treeviews.length; i++) {
+ var tree = treeviews[i];
+ if (tree.id == null || tree.id.indexOf("callgraph-") != 0) {
+ continue;
+ }
+ var id = tree.id.substring("callgraph-".length);
+ $(tree).treeview({collapsed: true, animated: "fast"});
+ document.cgAddChildren(tree, tree, [id]);
+ tree.parentNode.parentNode.style.display = "block";
+ }
+}
+
+document.cgAddChildren = function(tree, ul, indices) {
+ if (indices != null) {
+ for (var i = 0; i < indices.length; i++) {
+ var li = cgAddChild(tree, ul, document.CALLGRAPH[indices[i]]);
+ if (i == indices.length - 1) {
+ $(li).addClass("last");
+ }
+ }
+ }
+ $(tree).treeview({animated: "fast", add: ul});
+}
+
+// cgAddChild adds an <li> element for document.CALLGRAPH node cgn to
+// the parent <ul> element ul. tree is the tree's root <ul> element.
+function cgAddChild(tree, ul, cgn) {
+ var li = document.createElement("li");
+ ul.appendChild(li);
+ li.className = "closed";
+
+ var code = document.createElement("code");
+
+ if (cgn.Callees != null) {
+ $(li).addClass("expandable");
+
+ // Event handlers and innerHTML updates don't play nicely together,
+ // hence all this explicit DOM manipulation.
+ var hitarea = document.createElement("div");
+ hitarea.className = "hitarea expandable-hitarea";
+ li.appendChild(hitarea);
+
+ li.appendChild(code);
+
+ var childUL = document.createElement("ul");
+ li.appendChild(childUL);
+ childUL.setAttribute('style', "display: none;");
+
+ var onClick = function() {
+ document.cgAddChildren(tree, childUL, cgn.Callees);
+ hitarea.removeEventListener('click', onClick)
+ };
+ hitarea.addEventListener('click', onClick);
+
+ } else {
+ li.appendChild(code);
+ }
+ code.innerHTML += " " + makeAnchor(cgn.Func);
+ return li
+}
+
+})();
+`,
+
+ "images/minus.gif": "GIF89a\t\x00\t\x00\xf7\x00\x00\x00\x00\x00\x80\x80\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00!\xf9\x04\x01\x00\x00\xff\x00,\x00\x00\x00\x00\t\x00\t\x00\x00\b\"\x00\x03\b\x1cH\xf0\x9f\xc1\x83\xff\x04\"<\xa8pa\xc2\x00\xff\x00H\x94\xf8\xd0aE\x87\r\x17\x12\xdc\x18 \x00;",
+
+ "images/plus.gif": "GIF89a\t\x00\t\x00\xf7\x00\x00\x00\x00\x00\x80\x80\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00!\xf9\x04\x01\x00\x00\xff\x00,\x00\x00\x00\x00\t\x00\t\x00\x00\b&\x00\x03\b\x1cH\xf0\x9f\xc1\x83\xff\x04\x1e\x04pP\xa1A\x86\x06\x15\x02\x9881a\x80\x85\r/>̈0#A\x82\x01\x01\x00;",
+
+ "images/treeview-black-line.gif": "GIF89a\x10\x00\xf0\x06\xf7\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00!\xf9\x04\x01\x00\x00\xff\x00,\x00\x00\x00\x00\x10\x00\xf0\x06\x00\b\xff\x00\xff\t\x1c\xf8\x0f\x00\xc1\x83\b\r\"\\X\x90\xe1B\x85\x0e\tB\x8c(p\"E\x8b\x111:\xd4\xc8\x10\x80Ǐ\x1f\x1fR\x948r G\x91%\x1b\xa6<\x990\xa5ʒ,\x0f\xc6$\xb9\xd2\xe5L\x936s\xd6\xdc\tSgO\x9e#oV\xf4\x19\x94\xe8E\xa3\x19\x91nTڑ)ʟP\x8b\x02=:5iեW\x9bf}*5*U\xafV\xc1b\x15\xab\x95,\u05ef]Ӣ]\x1bVm[\xb6c\xddƅ[Vn]\xbag\xdfꝻ\xf7n\u07fc|\x03\xfb\x15\fx\xb0\xe1\u0088[nUl\x96\xb1\xdd\xc42\x9d:\xc6;\xf9oe\u0097\x0fg\x86L\xb3q\xe4ş=w~\xbc\xb9thҧ)\xa7\xb6\xbc\x1askͯ9\xe3\x04=Zumַ]熽[\xf6PڳE\aG\xdd\xdbt\xf1\xd8Ƈ\xdbV\x8e\x9b\xb9n缡\xfb~Iܥ\xf5\xebسk\xdfν{\xf4\xdf\xc2\xc1W\xff\x17\xbf\x9c|s\xf3\xcf\xd1\u007f\xa7^\x9e\xfdy\xf7\xe9\xe1\xaf\x17*\u007f:\xfd\xfb\x92\x91\xeb?\xce_zr\xf5\xf6\xe5\xd7\x1f\x80\xff\xd5W ~\xc0\x11\xb8\x9f\u007f\v*8\xa0\x81\rB\xf8 \x82\xe1I\xc8\xe0\x84\x02^\xa8\xa1\x83\x1bZ\xc8\xe1\x87\x1e\x86H\xe1x\"f\b\xe2\x88\xed\xa1\xf8\x9e\x8a\xf1\xb18\x9f\x89%&\x18c\x85.\x06(c\x8d\a\u0088c\x84;bx\xa3\x8e@\xfe($\x8dA\x129$\x89=v\x98\xe4\x89E\"\xd9d\x8aO\xae\x18e\x8bS\xbex$\x94WJ\x99%\x95[Zi\xe4\x97Nvi#\x98X\x92\xa9\xa5\x99\\\xa2\xe9e\x98j\x8e\xc9\xe6\x9be\xc2y\xa6\x9ciҹf\x9cxΙg\x9d{ީ\xe7\x9f|\x02\xeag\xa0\x84\x0ej\xa8\x9b}\"*\xa8\xa2\x852zh\x8ebBڦ\xa4v:j)\xa5\x89b\xba\xa8\xa6\x8dr\xfa(\x8fU^\nj\xa4\xa3NZj\xa5\x9e\x8a꣩\xab\xa2zj\xa6\xafn\xff\x1ak\xa7\xb3~\xda*\xac\xb7ʚ+\xad\xbbڪd\xa8\xa9\x06[\xab\xaa\xbf\x92\xda+\xb1L\x1a[,\xab˺z\xac\xb0\xcf\x0e\vm\xb3\xb8R\xab\xab\xb5\xbcb\xebk\xb2\xccr묶\xc8\xce\xf8\xad\xb7Ւ{\xad\xb9٢\xbb\xad\xb8\xe5\xb2{\xae\xbb\xe9»\xee\x92\xf2\x86K\xef\xbd\xc0J\xabo\xb4\xfc\x82;\xad\xba\xf6\xe6\xdb/\xc0\xff\xd6[0\xbe\xca\x12\xbc\xaf\xbf\v+<\xb0\xc1\rC\xfc0\xc2\xddJ\xcc\xf0\xc4\x02_\xac\xb1\xc3\x1b[\xcc\xf1\xc7\x1e\x87L\xf1\xb8\"g\f\xf2\xc8\xed\xa2\xfc\xae\xca\xf1\xb2<\xaf\xc9%'\x1cs\xc5.\a,s\xcd\aÌs\xc4;c|\xb3\xce@\xff,4\xcdA\x13=4\xc9=w\x9c\xf4\xc9E#\xddt\xcaO\xaf\x1cu\xcbS\xbf|4\xd4WK\x9d5\xd5[[m\xf4\xd7Nwm3\xd8X\x93\xad\xb5\xd9\\\xa3\xedu\xd8j\x8f\xcd\xf6\xdbe\xc3}\xb6\xdciӽv\xdcxϝw\xdd{\xdf\xff\xad\xf7\xdf|\x03\xeew\xe0\x84\x0fn\xb8\xdb}#.\xb8\xe2\x853~x\xcebC\u07b6\xe4v;n9\xe5\x89c\xbe\xb8\xe6\x8ds\xfe8\xcfU_\x0ez\xe4\xa3O^z型\xee\xb3髣~z\xe6\xafo\x1e{\xe7\xb3\u007f\xde:\xec\xb7˞;\xed\xbbۮt\xe8\xa9\a_\xbb꿓\xde;\xf1L\x1b_<\xeb˻~\xbc\xf0\xcf\x0f\x0f}\xf3\xb8S\xaf\xbb\xf5\xbcc\xef{\xf2\xccs\xef\xbc\xf6\xc8\xcf\xfc\xbd\xf7Փ\u007f\xbd\xf9٣\xbf\xbd\xf8\xe5\xb3\u007f\xbe\xfb\xe9ÿ\xfe\xd2\xf2\x87O\xff\xfd\xc0K\xaf\u007f\xf4\xfc\x83?\xbd\xfa\xf6\xcb_\xff\x00\xf8\xbf\xfa\x15\x10\u007f\xca#\xe0\xfe\xfc\xb7@\x05\x0eЀ\r\x84\xe0\x03\x11\xd8=\t2p\x82\x02\xbc\xa0\x06\x1d\xb8A\vr\xf0\x83\x1e\f!\x05\xc7'\xc2\f\x82p\x84\xedC\xe1\xfbT\x18?\x16\xceτ%L`\f+\xe8\xc2\x00ʰ\x86\a\x84!\x0e#\xb8C\f\xdeP\x87@\xfc\xa1\x102i\x18D\"\x0e\x91\x84=\xec`\x12OXD$61\x85O\\a\x14[8\xc5\x17\x1e\x11\x8aW\x94b\x16\xa9\xb8E+\x1a\xf1\x8bN\xec\xa2\ri\b\x12\x90\x04\x04\x00;",
+
+ "images/treeview-black.gif": "GIF89a`\x00\x85\x00\xa1\x01\x00\x00\x00\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff!\xf9\x04\x01\x00\x00\x02\x00,\x00\x00\x00\x00`\x00\x85\x00\x00\x02\xfe\x94\x8f\xa9\xcb\xed\x0fE\x98\xc1ш\xb3ި\xf2\x0f\x86\x9a'\x96\xa6I\x9e\xeaʶ\xee\nIJ\xfc\xd6&\xb0\xe0\xf6\xfe\xe9\x82\xef\xe3\t#\xc0Cp\x88d\xe0f\xcbY\xf2\x89(\x1a\x8eP\xa8\xf4W\xcdNs\xda,\xd3\xd9\xedR\xc3^\xb2yl~\xa2\xd3\xc85[\xe8~\xabRF9\x8f\xbe\xb5o.\x96\tW?R\x12\a\x98\x80Gx\x88\x98\b\xf8E\xa3\xa826\xe8\x88\x01)yBY)\xf8\xe3Ą\xd9\xf3\xd7\tr\t\xea\xa9\x109\x9a\xc3hzڠ\xba\xfa\xd0\xea\xca\x1a{3\x9bY\x1b\x02\xebj\x98\xbb\xba\x1b\xcb\xd7\x00\x1c\xf5k\xdb{{\x8c\x9c\xac\x8cʸ\xac\xf4\xe9<\x9c\x87\x15\x9dp\xc5{\xdaD\xc3Y}]m]7\xfdM\r>>\x95j\x9e\xae\xbe\xceގd\xb8\x0e\xff+\xac@\u007f뛎o\xae?\xce\xef\x8e\x1d+\x15@P\xa2\xc6yKwМ\xb6\x18\x9a\x1aEKh0\x1c\xb9\x88\xa5\xd4\tt\x871\xa3\xc6d\x8d\x06\xe4\xe5\xdb豗\x9f>!O\x95\xfcv\xb2ZJ\x8e,\r\xa2C\b\xed[A\x991\xbb5d\xc8\xedaM\x9d\x15a\xf6T\xf8\xb2\xa5СDG\xadtvtY\xd2J\xf6:\x8cT\xb8q`-\xa9\xb3\xa8\x06\xfc\x17\x94b9\xa8?\xb5J\x83\xca)\xa7\xb3\x996\xbb\xd24\xdb-kѵlۺ}\v7.\x82\x02\x00;",
+
+ "images/treeview-default-line.gif": "GIF89a\x10\x00\xf0\x06\xf7\x00\x00\x00\x00\x00\x80\x80\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00!\xf9\x04\x01\x00\x00\xff\x00,\x00\x00\x00\x00\x10\x00\xf0\x06\x00\b\xff\x00\xff\t\x1cH\xb0\xa0A\x81\x01\x0e*\\x0!Ç\v\x1dB\x9cHP\"E\x8a\t3\xfe\xd3x\xb1aNj\x16?2\f)R!ɒ\x06O\xa2\xac\xb8rdˈ/M\xc6\xf48\xb3\xa0ʗ7[\xe6\\\xb9\x13eϒ?E\x06\xfd8\xb4cQ\x905m&e\xb9\x14aS\xa7O\x8fb|\xba\x91\xaaԉW!f}\xb8\xd5eT\xab`\xbf\x8am\xda\x15\xe6إee\x9eM\x9a\x96&ٰo\xd7\xd6l\x9b\x12.Z\xbbl\xf1\xce\xd5;\x93\xaeR\xb9}\xf9\xc6\xf4\xcb4\xaeỀ\a\vƹXgc\x9e\x8f}F\x06:Yhe\xa2\x97\xa9j\xde̹3\xd7\xccH\x133\x16\xed\x984dӒQSVm\x995f\xd7FAO\x85\x1d\xfap^ڳm\xefōUvo\xdeZ}\a\a\xfe\x99\xb8W݁\x8d\x9bE\xaeX\xb9Z棡\x97\x96~\x9azj뫱\xb7\xd6\xfe\x9a{l\xe7n\x11{\xff\xaf-\xbe\xfc\xed\xf1\xb9\xcd\xefF\xff\x9b\xfdp\xf7\xc5\xe1\x1fW\x9f\\\xfer\xfa\xcd\xed?\xc7\x1f\x9d\xfft\xff\xd5\x01x\x9d\x80\xd9\x11\xb8\x9d\x81\xdd!\xf8\x9d~ᝧ y\x0eF\xb8ރ\xe9IX\x1f\x85\xeda\xf8\x9e\x86\xf1q8\x9f\x85\xf9yx\x1f\x88\xfd\x91\xf8\x9f\x89\x01\xa28\xa0\x8a\x05\xb2x\xa0\x8b\t¸\xa0\x88\xfb\xc9\b\xe1\x846V\x88\xe3\x8e\x17昡\x8f\x1b\x02١\x90\x1f\xf2\x18\"\x91#\x1aY\xa2\x92'2\x99\xa2\x93+B٢\x94/R\x19\xa3\x953\"Y#\x967\xf6ȥ\x8e^\x86y\xe4\x97?\x92\x19\xa4\x99C\xa2Y\xa4\x98K\xb2٤\x9bO\xc2\x19\xa5\x9cS\xd2Y\xa5\x9dW♥\x9aI\xea\xd9\xe5\x98~\x82\t\xe8\xa0m\x12\xfa\xa6\xa1q\":\xa7\xa2u2z\xa7\xa3yB\xbag\xa0eRz\xa6\xa5ib\xba\xa6\xa4\u007f\x16\xea顟&\x1aꢣ6Z꣧F\x9aꤜ\n\xbaj\xa7\xa0\xc6\xff*\xaa\xac\xa4\xd2j\xaa\xad\xa8⪪\xae\xac\xbe\xea*\xaf\xb0\xce*l\xad\xc3\xdeZl\xae\xc7\xee\x9al\xaf\xc0\xfe\xbal\xb0\xc4Fk\xac\xb4\xc8R\xab\xac\xb5\xcc>\xeb,\xb6\xd0N\xebm\xb5\xdf^\x1bn\xb6\xdcn;n\xb7\xe0\xa6+\xae\xba\xe4\x9ek.\xbb\xe8\xae+o\xbb\xf0\xbe;o\xbc\xf4\xdeko\xbe\xfc\xe2\xeb\xef\xbe\xffVڪ\xc0\xbe\x12ܬ\xc1\xda\"\\\xae\xc2\xee2\\\xaf\xc3\xfaB\xdc/\xc0\x14K\x1c\xf0\xa5\x03c\\\xb0\xc6\as\x9c\xb0\xc7\v\x83ܰ\xc8\x0f\x93\x1c\xb1\xc9\x13[\\1\xca\x17g\x9a\xb1\xcb\x1b\xc3ܱ\xcc\x1f\xd3\x1c\xb2\xcd#\xe3\\\xb2\xce'\xf3\x9c2\xcb+\xfb\xdc\xf2\xa61\x13=\xb3\xd15#}\xb3\xd293\xbd\xb3\xd3=C\xfd\xb3\xd0AK=t\x9f/[]5\xd6Es}\xb4\xd7I\x83\xbd\xb4\xd8M\x93\xfd\xb4\xd9Q\xa3=\xb5\xd6*\xb7\r\xb4\xdbT\xc3\xcd\xf6\xdbt\xc7]\xf7\xdcv\xe7\x8d\xf7\xdej_\xff\xbd\xa5\xa6}o\xfdwց\xcb]\xf8݇\xeb\x9d8߃w\xdd\xf8\u05cf\x87\x1d\xf9ؓ\x97]\xf9ٗ\xa7\x9d\xf9ڋw\xbe\xb9\xdf\r\xf2\xf9\xb9\xe0\xa1\x03>\xba\xe1\xa7#\x9e\xba\xe2\xab3^:\xe1\xad{\xfe\xba\xe3\xb3C^\xbb\xe4\xb7S\x9e\xbb\xe5\xbbc\u07bb\xe6\xbfs\x1e\xfb\xf0\xc1\x83^\x17x\xc73\x98<\x8dœ\xbe\xbc\x96ͣ\x1e\xbd\xeaӳ^\xbd\xebϋ~\xbd\xecٛ\xbe=\xf1\xdd\xc3\xfe\xfd\xf8\xe1\xd3^\xbe\xed\xe7㞾\xee\xeb\xf3\u07be\xef\xef\x03\x1f\xbf\xf0\xe4\xff\xa5\xbc\xfd\xcc\xcfo<\xfe\xd0\xeb\xef<\xff\xda\xf3\x9f\xf4\x04H=\x02Zπ\xd8\x03\xa0\xf7\x10\xc8=\x05\x8a\x8f\x81\xe0s\xa0\xf9$\x88>\n\xaaς\xecà\xfb4\b?\x0e\xcaσ\xf4\x83`\xfd\n\x93?\x10\ue3c4\xfd3\xe1\xffP\x18@\x15\x0eЅ\x05\x84\xe1\x01e\x98@\x16.\x90\x86\r\xb4\xe1\x03q\x18A\x1dNЇ\x15\x04\xe2\x05\xa6\x85\x98A\"nЈ\x1dD\xe2\a\x95\x18B\x1e\x8ep \x84\x81\xa2pf\xc8\xc4\x13J\x11yN\x14\xa1\x16\xb3\xc8\xc5*\xae\xf0\x8a\xf7\xf3\xe2\v\xc5\x18C2R\x11\x8c%4c\rјB5損-tc\x0f\xe1xC9>\x11*a\xa4\xe3\x0e\xed\xb8E>vQ\x8f?\x04d\x10\x059DB\x16ѐGDd\x12\x15\xb9DF6я\x90t\xa4\x15\xf1\x98FI~\x91\x92m\xb4\xe4\x185YFN\x9e\x11\x93q\xf4\xe4\x1aAYGQ\xbe\x91\x94{4\xe5\x1cQ\x19HV\x0eҕ\x85\x84\xe5!e\x99HZ.\xd2)\x1a\xc9H@\x00\x00;",
+
+ "images/treeview-default.gif": "GIF89a`\x00\x85\x00\xa1\x03\x00\x00\x00\x00\x80\x80\x80\xbc\xbc\xbc\xff\xff\xff!\xf9\x04\x01\x00\x00\x03\x00,\x00\x00\x00\x00`\x00\x85\x00\x00\x02\xfe\x9c\x8f\xa9\xcb\xed\x0f\a\x98\xc0ш\xb3ި\xf2\x0f\x86\x9a'\x96\xa6I\x9e\xeaʶ\xee\x1aIJ\xfc\xd6f\xb0\xe0\xf6\xfe\xe9\xd2\xe1\xe3\t#>Rp\x88d\xe0(\x93\x01\ue64c\"\x8a@\xa9uz0^\xb7GCw;\x9c\x89\xc1\xe4\xb2\xd9yN\xab\xa5ߵ\xfb}j\xc3M\x82y\xb2\xae\x90\xdb\x13\x82\xfe\xa3\x8f\xb7\xf7\x11\b\xa2'h@x\xa8\xb8\xc8\xc8&F\xd3(\xf2e\x18\xf90Y\x19r\x89\xd9#\xc1\x84\x06\xb5\x89\xa1\x19\xaa1J*\x9asZ\xfa\x18\xa3\xeajE\xf9*\xeb\x12;k\x1bwې\x98\xfb\x97J\n\xf8\xe7w\xbb\xbbQkG̛\xac\xbc\xfc\xc6\xda\xca\xec\xe5\vM\x15\r\x8df\xa0e\xbd\xe4\te\xbcI}=\x9dU\xa5-\xcd\xec\xecm\xad\xbe\xce\xde\ueb81\xac\x1e\xff\v\xac+l;\x0fM\x9c\xfe\xfb~\xb0\xef/ :u\xa6\x96\x81\xe3\x17\xea \xc1N\x17\xba\x19\x1cWM\x1c6r\x12\x13 \xfc\xe6,\xa0\xc6b\x8d\x1c\xf5i\xcc\xc7\f$\xa6z\xf6DV2\x99\f%/\x95\x1d[\xde\x1aX.\xcfB\x991-.dR\xc1\xa1\xb2\x82;\xcd=\xa49-\xa3ˡD\x8b\x1eb9\xec\xe3\xca{\vH\x1a\x9du\xf1i\xa5\xa8R\x0f\xc1\xac\x88\xa5fV\xac\x14\xcf1l\xa23\x19O\xb1>{\x02='\xb4\xaaڵlۺ}˫\x00\x00;",
+
+ "images/treeview-gray-line.gif": "GIF89a\x10\x00\xf0\x06\xf7\x00\x00\x00\x00\x00\x80\x80\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00!\xf9\x04\x01\x00\x00\xff\x00,\x00\x00\x00\x00\x10\x00\xf0\x06\x00\b\xff\x00\xff\t\x1c\xf8/\x00\xc1\x83\b\r\"\\X\x90\xe1B\x85\x0e\tB\x8c(p\"E\x8b\x111:\xd4\xc80\x80Ǐ\x1f\x1fR\x948r G\x91%\x1b\xa6<\x990\xa5ʒ,\x0f\xc6$\xb9\xd2\xe5L\x936s\xd6\xdc\tSgO\x9e#oV\xf4\x19\x94\xe8E\xa3\x19\x91nTڑ)ʟP\x8b\x02=:5iեW\x9bf}*5*U\xafV\xc1b\x15\xab\x95,\u05ef]Ӣ]\x1bVm[\xb6c\xddƅ[Vn]\xbag\xdfꝻ\xf7n\u07fc|\x03\xfb\x15\fx\xb0\xe1\u0088[nUl\x96\xb1\xdd\xc42\x9d:\xc6;\xf9oe\u0097\x0fg\x86L\xb3q\xe4ş=w~\xbc\xb9thҧ)\xa7\xb6\xbc\x1askͯ9\xe3\x04=Zumַ]熽[\xf6PڳE\aG\xdd\xdbt\xf1\xd8Ƈ\xdbV\x8e\x9b\xb9n缡\xfb~Iܥ\xf5\xebسk\xdfν{\xf4\xdf\xc2\xc1W\xff\x17\xbf\x9c|s\xf3\xcf\xd1\u007f\xa7^\x9e\xfdy\xf7\xe9\xe1\xaf\x17*\u007f:\xfd\xfb\x92\x91\xeb?\xce_zr\xf5\xf6\xe5\xd7\x1f\x80\xff\xd5W ~\xc0\x11\xb8\x9f\u007f\v*8\xa0\x81\rB\xf8 \x82\xe1I\xc8\xe0\x84\x02^\xa8\xa1\x83\x1bZ\xc8\xe1\x87\x1e\x86H\xe1x\"f\b\xe2\x88\xed\xa1\xf8\x9e\x8a\xf1\xb18\x9f\x89%&\x18c\x85.\x06(c\x8d\a\u0088c\x84;bx\xa3\x8e@\xfe($\x8dA\x129$\x89=v\x98\xe4\x89E\"\xd9d\x8aO\xae\x18e\x8bS\xbex$\x94WJ\x99%\x95[Zi\xe4\x97Nvi#\x98X\x92\xa9\xa5\x99\\\xa2\xe9e\x98j\x8e\xc9\xe6\x9be\xc2y\xa6\x9ciҹf\x9cxΙg\x9d{ީ\xe7\x9f|\x02\xeag\xa0\x84\x0ej\xa8\x9b}\"*\xa8\xa2\x852zh\x8ebBڦ\xa4v:j)\xa5\x89b\xba\xa8\xa6\x8dr\xfa(\x8fU^\nj\xa4\xa3NZj\xa5\x9e\x8a꣩\xab\xa2zj\xa6\xafn\xff\x1ak\xa7\xb3~\xda*\xac\xb7ʚ+\xad\xbbڪd\xa8\xa9\x06[\xab\xaa\xbf\x92\xda+\xb1L\x1a[,\xab˺z\xac\xb0\xcf\x0e\vm\xb3\xb8R\xab\xab\xb5\xbcb\xebk\xb2\xccr묶\xc8\xce\xf8\xad\xb7Ւ{\xad\xb9٢\xbb\xad\xb8\xe5\xb2{\xae\xbb\xe9»\xee\x92\xf2\x86K\xef\xbd\xc0J\xabo\xb4\xfc\x82;\xad\xba\xf6\xe6\xdb/\xc0\xff\xd6[0\xbe\xca\x12\xbc\xaf\xbf\v+<\xb0\xc1\rC\xfc0\xc2\xddJ\xcc\xf0\xc4\x02_\xac\xb1\xc3\x1b[\xcc\xf1\xc7\x1e\x87L\xf1\xb8\"g\f\xf2\xc8\xed\xa2\xfc\xae\xca\xf1\xb2<\xaf\xc9%'\x1cs\xc5.\a,s\xcd\aÌs\xc4;c|\xb3\xce@\xff,4\xcdA\x13=4\xc9=w\x9c\xf4\xc9E#\xddt\xcaO\xaf\x1cu\xcbS\xbf|4\xd4WK\x9d5\xd5[[m\xf4\xd7Nwm3\xd8X\x93\xad\xb5\xd9\\\xa3\xedu\xd8j\x8f\xcd\xf6\xdbe\xc3}\xb6\xdciӽv\xdcxϝw\xdd{\xdf\xff\xad\xf7\xdf|\x03\xeew\xe0\x84\x0fn\xb8\xdb}#.\xb8\xe2\x853~x\xcebC\u07b6\xe4v;n9\xe5\x89c\xbe\xb8\xe6\x8ds\xfe8\xcfU_\x0ez\xe4\xa3O^z型\xee\xb3髣~z\xe6\xafo\x1e{\xe7\xb3\u007f\xde:\xec\xb7˞;\xed\xbbۮt\xe8\xa9\a_\xbb꿓\xde;\xf1L\x1b_<\xeb˻~\xbc\xf0\xcf\x0f\x0f}\xf3\xb8S\xaf\xbb\xf5\xbcc\xef{\xf2\xccs\xef\xbc\xf6\xc8\xcf\xfc\xbd\xf7Փ\u007f\xbd\xf9٣\xbf\xbd\xf8\xe5\xb3\u007f\xbe\xfb\xe9ÿ\xfe\xd2\xf2\x87O\xff\xfd\xc0K\xaf\u007f\xf4\xfc\x83?\xbd\xfa\xf6\xcb_\xff\x00\xf8\xbf\xfa\x15\x10\u007f\xca#\xe0\xfe\xfc\xb7@\x05\x0eЀ\r\x84\xe0\x03\x11\xd8=\t2p\x82\x02\xbc\xa0\x06\x1d\xb8A\vr\xf0\x83\x1e\f!\x05\xc7'\xc2\f\x82p\x84\xedC\xe1\xfbT\x18?\x16\xceτ%L`\f+\xe8\xc2\x00ʰ\x86\a\x84!\x0e#\xb8C\f\xdeP\x87@\xfc\xa1\x102i\x18D\"\x0e\x91\x84=\xec`\x12OXD$61\x85O\\a\x14[8\xc5\x17\x1e\x11\x8aW\x94b\x16\xa9\xb8E+\x1a\xf1\x8bN\xec\xa2\ri\b\x12\x90\x04\x04\x00;",
+
+ "images/treeview-gray.gif": "GIF89a`\x00\x85\x00\xa1\x03\x00\x00\x00\x00\x80\x80\x80\xbc\xbc\xbc\xff\xff\xff!\xf9\x04\x01\x00\x00\x03\x00,\x00\x00\x00\x00`\x00\x85\x00\x00\x02\xfe\x9c\x8f\xa9\xcb\xed\x0f\x87\x98\xc2ш\xb3ި\xf2\x0f\x86\x9a'\x96\xa6I\x9e\xeaʶ\xee\x1aIJ\xfc\xd6f\xb0\xe0\xf6\xfe\xe9\x03p\xf0\xf1\x86\x11\x1f\xd0 $*\x198\x80\xd39\x98%\x97Kc\x90\x8aUX\x91\xd9.W\xeb\xedJg\xe1\xf2\xb4,F\xab\xcfj*\xbb\xad|Ç\xf2\xb9*u\xb5\xef\xf0_\xfdh\xf2p\x01\xe67RRG\x98\xc0\x87\xb8\xc8\xd8H8F\xe3\xa8rv(\x89Aiy\x82\x99i\xf8\xf3\x04$\xc5ٓ#*\xb2Y::\x88\xca\x01\x19\xb3\xda\xf9\xaa\x19+;\v[\x1bRyې{\xab\xc8[\xeb;+\xd80\x8c\xf0K\xa8\xa8q여\xeb\xfc\f\rݺ\xfcz\x1a\xadz\x14u\xcdt\x90M\xbd\xda\xf4\x19E\xb6\xdd\xe7]\x8e\x9d\x87\xaen\xbcn\xdc\xea\x1e/?O_\xef\xd5,\x8f\xffJ\x81_\xec\x1c\x9c\x8fT@U\xee\x00\xdac7oZB\x81\xf1\xb6h\x93\xe7\xf0\x1b\xaapO\xc6E*\x17q\xa1\x81ms\x10\x19\xbaSx0\xa4ȑ$%\x90\xd4W\xf0\x9a?\x05+{\x9d|Y2fL\x90\r=\xae\xb3v\xd3&:\x8aPB\xedԉ\x11\xe86\x9c;\xe1\xc9<\x8a4\xe9*\x94똢sZ\xaa\xe5\x01\xa9\xd7$\xea\xb2z\vk-\xad\xb3\xb8\x96\xa2\xf9QhU\xb1ш\x06\xfd\x04\x8a\\P\x829\xd9\xfet\x8bѨҹt\xebڽ\x8b7\xaf\x82\x02\x00;",
+
+ "implements.html": `<div class="toggle" style="display: none">
+ <div class="collapsed">
+ <p class="exampleHeading toggleButton">▹ <span class="text">Implements</span></p>
+ </div>
+ <div class="expanded">
+ <p class="exampleHeading toggleButton">▾ <span class="text">Implements</span></p>
+ <div style="margin-left: 1in" id='implements-{{.Index}}'>...</div>
+ </div>
+</div>
+`,
+
+ "jquery.js": `/*! jQuery v1.8.2 jquery.com | jquery.org/license */
+(function(a,b){function G(a){var b=F[a]={};return p.each(a.split(s),function(a,c){b[c]=!0}),b}function J(a,c,d){if(d===b&&a.nodeType===1){var e="data-"+c.replace(I,"-$1").toLowerCase();d=a.getAttribute(e);if(typeof d=="string"){try{d=d==="true"?!0:d==="false"?!1:d==="null"?null:+d+""===d?+d:H.test(d)?p.parseJSON(d):d}catch(f){}p.data(a,c,d)}else d=b}return d}function K(a){var b;for(b in a){if(b==="data"&&p.isEmptyObject(a[b]))continue;if(b!=="toJSON")return!1}return!0}function ba(){return!1}function bb(){return!0}function bh(a){return!a||!a.parentNode||a.parentNode.nodeType===11}function bi(a,b){do a=a[b];while(a&&a.nodeType!==1);return a}function bj(a,b,c){b=b||0;if(p.isFunction(b))return p.grep(a,function(a,d){var e=!!b.call(a,d,a);return e===c});if(b.nodeType)return p.grep(a,function(a,d){return a===b===c});if(typeof b=="string"){var d=p.grep(a,function(a){return a.nodeType===1});if(be.test(b))return p.filter(b,d,!c);b=p.filter(b,d)}return p.grep(a,function(a,d){return p.inArray(a,b)>=0===c})}function bk(a){var b=bl.split("|"),c=a.createDocumentFragment();if(c.createElement)while(b.length)c.createElement(b.pop());return c}function bC(a,b){return a.getElementsByTagName(b)[0]||a.appendChild(a.ownerDocument.createElement(b))}function bD(a,b){if(b.nodeType!==1||!p.hasData(a))return;var c,d,e,f=p._data(a),g=p._data(b,f),h=f.events;if(h){delete g.handle,g.events={};for(c in h)for(d=0,e=h[c].length;d<e;d++)p.event.add(b,c,h[c][d])}g.data&&(g.data=p.extend({},g.data))}function bE(a,b){var c;if(b.nodeType!==1)return;b.clearAttributes&&b.clearAttributes(),b.mergeAttributes&&b.mergeAttributes(a),c=b.nodeName.toLowerCase(),c==="object"?(b.parentNode&&(b.outerHTML=a.outerHTML),p.support.html5Clone&&a.innerHTML&&!p.trim(b.innerHTML)&&(b.innerHTML=a.innerHTML)):c==="input"&&bv.test(a.type)?(b.defaultChecked=b.checked=a.checked,b.value!==a.value&&(b.value=a.value)):c==="option"?b.selected=a.defaultSelected:c==="input"||c==="textarea"?b.defaultValue=a.defaultValue:c==="script"&&b.text!==a.text&&(b.text=a.text),b.removeAttribute(p.expando)}function bF(a){return typeof a.getElementsByTagName!="undefined"?a.getElementsByTagName("*"):typeof a.querySelectorAll!="undefined"?a.querySelectorAll("*"):[]}function bG(a){bv.test(a.type)&&(a.defaultChecked=a.checked)}function bY(a,b){if(b in a)return b;var c=b.charAt(0).toUpperCase()+b.slice(1),d=b,e=bW.length;while(e--){b=bW[e]+c;if(b in a)return b}return d}function bZ(a,b){return a=b||a,p.css(a,"display")==="none"||!p.contains(a.ownerDocument,a)}function b$(a,b){var c,d,e=[],f=0,g=a.length;for(;f<g;f++){c=a[f];if(!c.style)continue;e[f]=p._data(c,"olddisplay"),b?(!e[f]&&c.style.display==="none"&&(c.style.display=""),c.style.display===""&&bZ(c)&&(e[f]=p._data(c,"olddisplay",cc(c.nodeName)))):(d=bH(c,"display"),!e[f]&&d!=="none"&&p._data(c,"olddisplay",d))}for(f=0;f<g;f++){c=a[f];if(!c.style)continue;if(!b||c.style.display==="none"||c.style.display==="")c.style.display=b?e[f]||"":"none"}return a}function b_(a,b,c){var d=bP.exec(b);return d?Math.max(0,d[1]-(c||0))+(d[2]||"px"):b}function ca(a,b,c,d){var e=c===(d?"border":"content")?4:b==="width"?1:0,f=0;for(;e<4;e+=2)c==="margin"&&(f+=p.css(a,c+bV[e],!0)),d?(c==="content"&&(f-=parseFloat(bH(a,"padding"+bV[e]))||0),c!=="margin"&&(f-=parseFloat(bH(a,"border"+bV[e]+"Width"))||0)):(f+=parseFloat(bH(a,"padding"+bV[e]))||0,c!=="padding"&&(f+=parseFloat(bH(a,"border"+bV[e]+"Width"))||0));return f}function cb(a,b,c){var d=b==="width"?a.offsetWidth:a.offsetHeight,e=!0,f=p.support.boxSizing&&p.css(a,"boxSizing")==="border-box";if(d<=0||d==null){d=bH(a,b);if(d<0||d==null)d=a.style[b];if(bQ.test(d))return d;e=f&&(p.support.boxSizingReliable||d===a.style[b]),d=parseFloat(d)||0}return d+ca(a,b,c||(f?"border":"content"),e)+"px"}function cc(a){if(bS[a])return bS[a];var b=p("<"+a+">").appendTo(e.body),c=b.css("display");b.remove();if(c==="none"||c===""){bI=e.body.appendChild(bI||p.extend(e.createElement("iframe"),{frameBorder:0,width:0,height:0}));if(!bJ||!bI.createElement)bJ=(bI.contentWindow||bI.contentDocument).document,bJ.write("<!doctype html><html><body>"),bJ.close();b=bJ.body.appendChild(bJ.createElement(a)),c=bH(b,"display"),e.body.removeChild(bI)}return bS[a]=c,c}function ci(a,b,c,d){var e;if(p.isArray(b))p.each(b,function(b,e){c||ce.test(a)?d(a,e):ci(a+"["+(typeof e=="object"?b:"")+"]",e,c,d)});else if(!c&&p.type(b)==="object")for(e in b)ci(a+"["+e+"]",b[e],c,d);else d(a,b)}function cz(a){return function(b,c){typeof b!="string"&&(c=b,b="*");var d,e,f,g=b.toLowerCase().split(s),h=0,i=g.length;if(p.isFunction(c))for(;h<i;h++)d=g[h],f=/^\+/.test(d),f&&(d=d.substr(1)||"*"),e=a[d]=a[d]||[],e[f?"unshift":"push"](c)}}function cA(a,c,d,e,f,g){f=f||c.dataTypes[0],g=g||{},g[f]=!0;var h,i=a[f],j=0,k=i?i.length:0,l=a===cv;for(;j<k&&(l||!h);j++)h=i[j](c,d,e),typeof h=="string"&&(!l||g[h]?h=b:(c.dataTypes.unshift(h),h=cA(a,c,d,e,h,g)));return(l||!h)&&!g["*"]&&(h=cA(a,c,d,e,"*",g)),h}function cB(a,c){var d,e,f=p.ajaxSettings.flatOptions||{};for(d in c)c[d]!==b&&((f[d]?a:e||(e={}))[d]=c[d]);e&&p.extend(!0,a,e)}function cC(a,c,d){var e,f,g,h,i=a.contents,j=a.dataTypes,k=a.responseFields;for(f in k)f in d&&(c[k[f]]=d[f]);while(j[0]==="*")j.shift(),e===b&&(e=a.mimeType||c.getResponseHeader("content-type"));if(e)for(f in i)if(i[f]&&i[f].test(e)){j.unshift(f);break}if(j[0]in d)g=j[0];else{for(f in d){if(!j[0]||a.converters[f+" "+j[0]]){g=f;break}h||(h=f)}g=g||h}if(g)return g!==j[0]&&j.unshift(g),d[g]}function cD(a,b){var c,d,e,f,g=a.dataTypes.slice(),h=g[0],i={},j=0;a.dataFilter&&(b=a.dataFilter(b,a.dataType));if(g[1])for(c in a.converters)i[c.toLowerCase()]=a.converters[c];for(;e=g[++j];)if(e!=="*"){if(h!=="*"&&h!==e){c=i[h+" "+e]||i["* "+e];if(!c)for(d in i){f=d.split(" ");if(f[1]===e){c=i[h+" "+f[0]]||i["* "+f[0]];if(c){c===!0?c=i[d]:i[d]!==!0&&(e=f[0],g.splice(j--,0,e));break}}}if(c!==!0)if(c&&a["throws"])b=c(b);else try{b=c(b)}catch(k){return{state:"parsererror",error:c?k:"No conversion from "+h+" to "+e}}}h=e}return{state:"success",data:b}}function cL(){try{return new a.XMLHttpRequest}catch(b){}}function cM(){try{return new a.ActiveXObject("Microsoft.XMLHTTP")}catch(b){}}function cU(){return setTimeout(function(){cN=b},0),cN=p.now()}function cV(a,b){p.each(b,function(b,c){var d=(cT[b]||[]).concat(cT["*"]),e=0,f=d.length;for(;e<f;e++)if(d[e].call(a,b,c))return})}function cW(a,b,c){var d,e=0,f=0,g=cS.length,h=p.Deferred().always(function(){delete i.elem}),i=function(){var b=cN||cU(),c=Math.max(0,j.startTime+j.duration-b),d=1-(c/j.duration||0),e=0,f=j.tweens.length;for(;e<f;e++)j.tweens[e].run(d);return h.notifyWith(a,[j,d,c]),d<1&&f?c:(h.resolveWith(a,[j]),!1)},j=h.promise({elem:a,props:p.extend({},b),opts:p.extend(!0,{specialEasing:{}},c),originalProperties:b,originalOptions:c,startTime:cN||cU(),duration:c.duration,tweens:[],createTween:function(b,c,d){var e=p.Tween(a,j.opts,b,c,j.opts.specialEasing[b]||j.opts.easing);return j.tweens.push(e),e},stop:function(b){var c=0,d=b?j.tweens.length:0;for(;c<d;c++)j.tweens[c].run(1);return b?h.resolveWith(a,[j,b]):h.rejectWith(a,[j,b]),this}}),k=j.props;cX(k,j.opts.specialEasing);for(;e<g;e++){d=cS[e].call(j,a,k,j.opts);if(d)return d}return cV(j,k),p.isFunction(j.opts.start)&&j.opts.start.call(a,j),p.fx.timer(p.extend(i,{anim:j,queue:j.opts.queue,elem:a})),j.progress(j.opts.progress).done(j.opts.done,j.opts.complete).fail(j.opts.fail).always(j.opts.always)}function cX(a,b){var c,d,e,f,g;for(c in a){d=p.camelCase(c),e=b[d],f=a[c],p.isArray(f)&&(e=f[1],f=a[c]=f[0]),c!==d&&(a[d]=f,delete a[c]),g=p.cssHooks[d];if(g&&"expand"in g){f=g.expand(f),delete a[d];for(c in f)c in a||(a[c]=f[c],b[c]=e)}else b[d]=e}}function cY(a,b,c){var d,e,f,g,h,i,j,k,l=this,m=a.style,n={},o=[],q=a.nodeType&&bZ(a);c.queue||(j=p._queueHooks(a,"fx"),j.unqueued==null&&(j.unqueued=0,k=j.empty.fire,j.empty.fire=function(){j.unqueued||k()}),j.unqueued++,l.always(function(){l.always(function(){j.unqueued--,p.queue(a,"fx").length||j.empty.fire()})})),a.nodeType===1&&("height"in b||"width"in b)&&(c.overflow=[m.overflow,m.overflowX,m.overflowY],p.css(a,"display")==="inline"&&p.css(a,"float")==="none"&&(!p.support.inlineBlockNeedsLayout||cc(a.nodeName)==="inline"?m.display="inline-block":m.zoom=1)),c.overflow&&(m.overflow="hidden",p.support.shrinkWrapBlocks||l.done(function(){m.overflow=c.overflow[0],m.overflowX=c.overflow[1],m.overflowY=c.overflow[2]}));for(d in b){f=b[d];if(cP.exec(f)){delete b[d];if(f===(q?"hide":"show"))continue;o.push(d)}}g=o.length;if(g){h=p._data(a,"fxshow")||p._data(a,"fxshow",{}),q?p(a).show():l.done(function(){p(a).hide()}),l.done(function(){var b;p.removeData(a,"fxshow",!0);for(b in n)p.style(a,b,n[b])});for(d=0;d<g;d++)e=o[d],i=l.createTween(e,q?h[e]:0),n[e]=h[e]||p.style(a,e),e in h||(h[e]=i.start,q&&(i.end=i.start,i.start=e==="width"||e==="height"?1:0))}}function cZ(a,b,c,d,e){return new cZ.prototype.init(a,b,c,d,e)}function c$(a,b){var c,d={height:a},e=0;b=b?1:0;for(;e<4;e+=2-b)c=bV[e],d["margin"+c]=d["padding"+c]=a;return b&&(d.opacity=d.width=a),d}function da(a){return p.isWindow(a)?a:a.nodeType===9?a.defaultView||a.parentWindow:!1}var c,d,e=a.document,f=a.location,g=a.navigator,h=a.jQuery,i=a.$,j=Array.prototype.push,k=Array.prototype.slice,l=Array.prototype.indexOf,m=Object.prototype.toString,n=Object.prototype.hasOwnProperty,o=String.prototype.trim,p=function(a,b){return new p.fn.init(a,b,c)},q=/[\-+]?(?:\d*\.|)\d+(?:[eE][\-+]?\d+|)/.source,r=/\S/,s=/\s+/,t=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,u=/^(?:[^#<]*(<[\w\W]+>)[^>]*$|#([\w\-]*)$)/,v=/^<(\w+)\s*\/?>(?:<\/\1>|)$/,w=/^[\],:{}\s]*$/,x=/(?:^|:|,)(?:\s*\[)+/g,y=/\\(?:["\\\/bfnrt]|u[\da-fA-F]{4})/g,z=/"[^"\\\r\n]*"|true|false|null|-?(?:\d\d*\.|)\d+(?:[eE][\-+]?\d+|)/g,A=/^-ms-/,B=/-([\da-z])/gi,C=function(a,b){return(b+"").toUpperCase()},D=function(){e.addEventListener?(e.removeEventListener("DOMContentLoaded",D,!1),p.ready()):e.readyState==="complete"&&(e.detachEvent("onreadystatechange",D),p.ready())},E={};p.fn=p.prototype={constructor:p,init:function(a,c,d){var f,g,h,i;if(!a)return this;if(a.nodeType)return this.context=this[0]=a,this.length=1,this;if(typeof a=="string"){a.charAt(0)==="<"&&a.charAt(a.length-1)===">"&&a.length>=3?f=[null,a,null]:f=u.exec(a);if(f&&(f[1]||!c)){if(f[1])return c=c instanceof p?c[0]:c,i=c&&c.nodeType?c.ownerDocument||c:e,a=p.parseHTML(f[1],i,!0),v.test(f[1])&&p.isPlainObject(c)&&this.attr.call(a,c,!0),p.merge(this,a);g=e.getElementById(f[2]);if(g&&g.parentNode){if(g.id!==f[2])return d.find(a);this.length=1,this[0]=g}return this.context=e,this.selector=a,this}return!c||c.jquery?(c||d).find(a):this.constructor(c).find(a)}return p.isFunction(a)?d.ready(a):(a.selector!==b&&(this.selector=a.selector,this.context=a.context),p.makeArray(a,this))},selector:"",jquery:"1.8.2",length:0,size:function(){return this.length},toArray:function(){return k.call(this)},get:function(a){return a==null?this.toArray():a<0?this[this.length+a]:this[a]},pushStack:function(a,b,c){var d=p.merge(this.constructor(),a);return d.prevObject=this,d.context=this.context,b==="find"?d.selector=this.selector+(this.selector?" ":"")+c:b&&(d.selector=this.selector+"."+b+"("+c+")"),d},each:function(a,b){return p.each(this,a,b)},ready:function(a){return p.ready.promise().done(a),this},eq:function(a){return a=+a,a===-1?this.slice(a):this.slice(a,a+1)},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},slice:function(){return this.pushStack(k.apply(this,arguments),"slice",k.call(arguments).join(","))},map:function(a){return this.pushStack(p.map(this,function(b,c){return a.call(b,c,b)}))},end:function(){return this.prevObject||this.constructor(null)},push:j,sort:[].sort,splice:[].splice},p.fn.init.prototype=p.fn,p.extend=p.fn.extend=function(){var a,c,d,e,f,g,h=arguments[0]||{},i=1,j=arguments.length,k=!1;typeof h=="boolean"&&(k=h,h=arguments[1]||{},i=2),typeof h!="object"&&!p.isFunction(h)&&(h={}),j===i&&(h=this,--i);for(;i<j;i++)if((a=arguments[i])!=null)for(c in a){d=h[c],e=a[c];if(h===e)continue;k&&e&&(p.isPlainObject(e)||(f=p.isArray(e)))?(f?(f=!1,g=d&&p.isArray(d)?d:[]):g=d&&p.isPlainObject(d)?d:{},h[c]=p.extend(k,g,e)):e!==b&&(h[c]=e)}return h},p.extend({noConflict:function(b){return a.$===p&&(a.$=i),b&&a.jQuery===p&&(a.jQuery=h),p},isReady:!1,readyWait:1,holdReady:function(a){a?p.readyWait++:p.ready(!0)},ready:function(a){if(a===!0?--p.readyWait:p.isReady)return;if(!e.body)return setTimeout(p.ready,1);p.isReady=!0;if(a!==!0&&--p.readyWait>0)return;d.resolveWith(e,[p]),p.fn.trigger&&p(e).trigger("ready").off("ready")},isFunction:function(a){return p.type(a)==="function"},isArray:Array.isArray||function(a){return p.type(a)==="array"},isWindow:function(a){return a!=null&&a==a.window},isNumeric:function(a){return!isNaN(parseFloat(a))&&isFinite(a)},type:function(a){return a==null?String(a):E[m.call(a)]||"object"},isPlainObject:function(a){if(!a||p.type(a)!=="object"||a.nodeType||p.isWindow(a))return!1;try{if(a.constructor&&!n.call(a,"constructor")&&!n.call(a.constructor.prototype,"isPrototypeOf"))return!1}catch(c){return!1}var d;for(d in a);return d===b||n.call(a,d)},isEmptyObject:function(a){var b;for(b in a)return!1;return!0},error:function(a){throw new Error(a)},parseHTML:function(a,b,c){var d;return!a||typeof a!="string"?null:(typeof b=="boolean"&&(c=b,b=0),b=b||e,(d=v.exec(a))?[b.createElement(d[1])]:(d=p.buildFragment([a],b,c?null:[]),p.merge([],(d.cacheable?p.clone(d.fragment):d.fragment).childNodes)))},parseJSON:function(b){if(!b||typeof b!="string")return null;b=p.trim(b);if(a.JSON&&a.JSON.parse)return a.JSON.parse(b);if(w.test(b.replace(y,"@").replace(z,"]").replace(x,"")))return(new Function("return "+b))();p.error("Invalid JSON: "+b)},parseXML:function(c){var d,e;if(!c||typeof c!="string")return null;try{a.DOMParser?(e=new DOMParser,d=e.parseFromString(c,"text/xml")):(d=new ActiveXObject("Microsoft.XMLDOM"),d.async="false",d.loadXML(c))}catch(f){d=b}return(!d||!d.documentElement||d.getElementsByTagName("parsererror").length)&&p.error("Invalid XML: "+c),d},noop:function(){},globalEval:function(b){b&&r.test(b)&&(a.execScript||function(b){a.eval.call(a,b)})(b)},camelCase:function(a){return a.replace(A,"ms-").replace(B,C)},nodeName:function(a,b){return a.nodeName&&a.nodeName.toLowerCase()===b.toLowerCase()},each:function(a,c,d){var e,f=0,g=a.length,h=g===b||p.isFunction(a);if(d){if(h){for(e in a)if(c.apply(a[e],d)===!1)break}else for(;f<g;)if(c.apply(a[f++],d)===!1)break}else if(h){for(e in a)if(c.call(a[e],e,a[e])===!1)break}else for(;f<g;)if(c.call(a[f],f,a[f++])===!1)break;return a},trim:o&&!o.call("` + "\xEF\xBB\xBF" + ` ")?function(a){return a==null?"":o.call(a)}:function(a){return a==null?"":(a+"").replace(t,"")},makeArray:function(a,b){var c,d=b||[];return a!=null&&(c=p.type(a),a.length==null||c==="string"||c==="function"||c==="regexp"||p.isWindow(a)?j.call(d,a):p.merge(d,a)),d},inArray:function(a,b,c){var d;if(b){if(l)return l.call(b,a,c);d=b.length,c=c?c<0?Math.max(0,d+c):c:0;for(;c<d;c++)if(c in b&&b[c]===a)return c}return-1},merge:function(a,c){var d=c.length,e=a.length,f=0;if(typeof d=="number")for(;f<d;f++)a[e++]=c[f];else while(c[f]!==b)a[e++]=c[f++];return a.length=e,a},grep:function(a,b,c){var d,e=[],f=0,g=a.length;c=!!c;for(;f<g;f++)d=!!b(a[f],f),c!==d&&e.push(a[f]);return e},map:function(a,c,d){var e,f,g=[],h=0,i=a.length,j=a instanceof p||i!==b&&typeof i=="number"&&(i>0&&a[0]&&a[i-1]||i===0||p.isArray(a));if(j)for(;h<i;h++)e=c(a[h],h,d),e!=null&&(g[g.length]=e);else for(f in a)e=c(a[f],f,d),e!=null&&(g[g.length]=e);return g.concat.apply([],g)},guid:1,proxy:function(a,c){var d,e,f;return typeof c=="string"&&(d=a[c],c=a,a=d),p.isFunction(a)?(e=k.call(arguments,2),f=function(){return a.apply(c,e.concat(k.call(arguments)))},f.guid=a.guid=a.guid||p.guid++,f):b},access:function(a,c,d,e,f,g,h){var i,j=d==null,k=0,l=a.length;if(d&&typeof d=="object"){for(k in d)p.access(a,c,k,d[k],1,g,e);f=1}else if(e!==b){i=h===b&&p.isFunction(e),j&&(i?(i=c,c=function(a,b,c){return i.call(p(a),c)}):(c.call(a,e),c=null));if(c)for(;k<l;k++)c(a[k],d,i?e.call(a[k],k,c(a[k],d)):e,h);f=1}return f?a:j?c.call(a):l?c(a[0],d):g},now:function(){return(new Date).getTime()}}),p.ready.promise=function(b){if(!d){d=p.Deferred();if(e.readyState==="complete")setTimeout(p.ready,1);else if(e.addEventListener)e.addEventListener("DOMContentLoaded",D,!1),a.addEventListener("load",p.ready,!1);else{e.attachEvent("onreadystatechange",D),a.attachEvent("onload",p.ready);var c=!1;try{c=a.frameElement==null&&e.documentElement}catch(f){}c&&c.doScroll&&function g(){if(!p.isReady){try{c.doScroll("left")}catch(a){return setTimeout(g,50)}p.ready()}}()}}return d.promise(b)},p.each("Boolean Number String Function Array Date RegExp Object".split(" "),function(a,b){E["[object "+b+"]"]=b.toLowerCase()}),c=p(e);var F={};p.Callbacks=function(a){a=typeof a=="string"?F[a]||G(a):p.extend({},a);var c,d,e,f,g,h,i=[],j=!a.once&&[],k=function(b){c=a.memory&&b,d=!0,h=f||0,f=0,g=i.length,e=!0;for(;i&&h<g;h++)if(i[h].apply(b[0],b[1])===!1&&a.stopOnFalse){c=!1;break}e=!1,i&&(j?j.length&&k(j.shift()):c?i=[]:l.disable())},l={add:function(){if(i){var b=i.length;(function d(b){p.each(b,function(b,c){var e=p.type(c);e==="function"&&(!a.unique||!l.has(c))?i.push(c):c&&c.length&&e!=="string"&&d(c)})})(arguments),e?g=i.length:c&&(f=b,k(c))}return this},remove:function(){return i&&p.each(arguments,function(a,b){var c;while((c=p.inArray(b,i,c))>-1)i.splice(c,1),e&&(c<=g&&g--,c<=h&&h--)}),this},has:function(a){return p.inArray(a,i)>-1},empty:function(){return i=[],this},disable:function(){return i=j=c=b,this},disabled:function(){return!i},lock:function(){return j=b,c||l.disable(),this},locked:function(){return!j},fireWith:function(a,b){return b=b||[],b=[a,b.slice?b.slice():b],i&&(!d||j)&&(e?j.push(b):k(b)),this},fire:function(){return l.fireWith(this,arguments),this},fired:function(){return!!d}};return l},p.extend({Deferred:function(a){var b=[["resolve","done",p.Callbacks("once memory"),"resolved"],["reject","fail",p.Callbacks("once memory"),"rejected"],["notify","progress",p.Callbacks("memory")]],c="pending",d={state:function(){return c},always:function(){return e.done(arguments).fail(arguments),this},then:function(){var a=arguments;return p.Deferred(function(c){p.each(b,function(b,d){var f=d[0],g=a[b];e[d[1]](p.isFunction(g)?function(){var a=g.apply(this,arguments);a&&p.isFunction(a.promise)?a.promise().done(c.resolve).fail(c.reject).progress(c.notify):c[f+"With"](this===e?c:this,[a])}:c[f])}),a=null}).promise()},promise:function(a){return a!=null?p.extend(a,d):d}},e={};return d.pipe=d.then,p.each(b,function(a,f){var g=f[2],h=f[3];d[f[1]]=g.add,h&&g.add(function(){c=h},b[a^1][2].disable,b[2][2].lock),e[f[0]]=g.fire,e[f[0]+"With"]=g.fireWith}),d.promise(e),a&&a.call(e,e),e},when:function(a){var b=0,c=k.call(arguments),d=c.length,e=d!==1||a&&p.isFunction(a.promise)?d:0,f=e===1?a:p.Deferred(),g=function(a,b,c){return function(d){b[a]=this,c[a]=arguments.length>1?k.call(arguments):d,c===h?f.notifyWith(b,c):--e||f.resolveWith(b,c)}},h,i,j;if(d>1){h=new Array(d),i=new Array(d),j=new Array(d);for(;b<d;b++)c[b]&&p.isFunction(c[b].promise)?c[b].promise().done(g(b,j,c)).fail(f.reject).progress(g(b,i,h)):--e}return e||f.resolveWith(j,c),f.promise()}}),p.support=function(){var b,c,d,f,g,h,i,j,k,l,m,n=e.createElement("div");n.setAttribute("className","t"),n.innerHTML=" <link/><table></table><a href='/a'>a</a><input type='checkbox'/>",c=n.getElementsByTagName("*"),d=n.getElementsByTagName("a")[0],d.style.cssText="top:1px;float:left;opacity:.5";if(!c||!c.length)return{};f=e.createElement("select"),g=f.appendChild(e.createElement("option")),h=n.getElementsByTagName("input")[0],b={leadingWhitespace:n.firstChild.nodeType===3,tbody:!n.getElementsByTagName("tbody").length,htmlSerialize:!!n.getElementsByTagName("link").length,style:/top/.test(d.getAttribute("style")),hrefNormalized:d.getAttribute("href")==="/a",opacity:/^0.5/.test(d.style.opacity),cssFloat:!!d.style.cssFloat,checkOn:h.value==="on",optSelected:g.selected,getSetAttribute:n.className!=="t",enctype:!!e.createElement("form").enctype,html5Clone:e.createElement("nav").cloneNode(!0).outerHTML!=="<:nav></:nav>",boxModel:e.compatMode==="CSS1Compat",submitBubbles:!0,changeBubbles:!0,focusinBubbles:!1,deleteExpando:!0,noCloneEvent:!0,inlineBlockNeedsLayout:!1,shrinkWrapBlocks:!1,reliableMarginRight:!0,boxSizingReliable:!0,pixelPosition:!1},h.checked=!0,b.noCloneChecked=h.cloneNode(!0).checked,f.disabled=!0,b.optDisabled=!g.disabled;try{delete n.test}catch(o){b.deleteExpando=!1}!n.addEventListener&&n.attachEvent&&n.fireEvent&&(n.attachEvent("onclick",m=function(){b.noCloneEvent=!1}),n.cloneNode(!0).fireEvent("onclick"),n.detachEvent("onclick",m)),h=e.createElement("input"),h.value="t",h.setAttribute("type","radio"),b.radioValue=h.value==="t",h.setAttribute("checked","checked"),h.setAttribute("name","t"),n.appendChild(h),i=e.createDocumentFragment(),i.appendChild(n.lastChild),b.checkClone=i.cloneNode(!0).cloneNode(!0).lastChild.checked,b.appendChecked=h.checked,i.removeChild(h),i.appendChild(n);if(n.attachEvent)for(k in{submit:!0,change:!0,focusin:!0})j="on"+k,l=j in n,l||(n.setAttribute(j,"return;"),l=typeof n[j]=="function"),b[k+"Bubbles"]=l;return p(function(){var c,d,f,g,h="padding:0;margin:0;border:0;display:block;overflow:hidden;",i=e.getElementsByTagName("body")[0];if(!i)return;c=e.createElement("div"),c.style.cssText="visibility:hidden;border:0;width:0;height:0;position:static;top:0;margin-top:1px",i.insertBefore(c,i.firstChild),d=e.createElement("div"),c.appendChild(d),d.innerHTML="<table><tr><td></td><td>t</td></tr></table>",f=d.getElementsByTagName("td"),f[0].style.cssText="padding:0;margin:0;border:0;display:none",l=f[0].offsetHeight===0,f[0].style.display="",f[1].style.display="none",b.reliableHiddenOffsets=l&&f[0].offsetHeight===0,d.innerHTML="",d.style.cssText="box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;padding:1px;border:1px;display:block;width:4px;margin-top:1%;position:absolute;top:1%;",b.boxSizing=d.offsetWidth===4,b.doesNotIncludeMarginInBodyOffset=i.offsetTop!==1,a.getComputedStyle&&(b.pixelPosition=(a.getComputedStyle(d,null)||{}).top!=="1%",b.boxSizingReliable=(a.getComputedStyle(d,null)||{width:"4px"}).width==="4px",g=e.createElement("div"),g.style.cssText=d.style.cssText=h,g.style.marginRight=g.style.width="0",d.style.width="1px",d.appendChild(g),b.reliableMarginRight=!parseFloat((a.getComputedStyle(g,null)||{}).marginRight)),typeof d.style.zoom!="undefined"&&(d.innerHTML="",d.style.cssText=h+"width:1px;padding:1px;display:inline;zoom:1",b.inlineBlockNeedsLayout=d.offsetWidth===3,d.style.display="block",d.style.overflow="visible",d.innerHTML="<div></div>",d.firstChild.style.width="5px",b.shrinkWrapBlocks=d.offsetWidth!==3,c.style.zoom=1),i.removeChild(c),c=d=f=g=null}),i.removeChild(n),c=d=f=g=h=i=n=null,b}();var H=/(?:\{[\s\S]*\}|\[[\s\S]*\])$/,I=/([A-Z])/g;p.extend({cache:{},deletedIds:[],uuid:0,expando:"jQuery"+(p.fn.jquery+Math.random()).replace(/\D/g,""),noData:{embed:!0,object:"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000",applet:!0},hasData:function(a){return a=a.nodeType?p.cache[a[p.expando]]:a[p.expando],!!a&&!K(a)},data:function(a,c,d,e){if(!p.acceptData(a))return;var f,g,h=p.expando,i=typeof c=="string",j=a.nodeType,k=j?p.cache:a,l=j?a[h]:a[h]&&h;if((!l||!k[l]||!e&&!k[l].data)&&i&&d===b)return;l||(j?a[h]=l=p.deletedIds.pop()||p.guid++:l=h),k[l]||(k[l]={},j||(k[l].toJSON=p.noop));if(typeof c=="object"||typeof c=="function")e?k[l]=p.extend(k[l],c):k[l].data=p.extend(k[l].data,c);return f=k[l],e||(f.data||(f.data={}),f=f.data),d!==b&&(f[p.camelCase(c)]=d),i?(g=f[c],g==null&&(g=f[p.camelCase(c)])):g=f,g},removeData:function(a,b,c){if(!p.acceptData(a))return;var d,e,f,g=a.nodeType,h=g?p.cache:a,i=g?a[p.expando]:p.expando;if(!h[i])return;if(b){d=c?h[i]:h[i].data;if(d){p.isArray(b)||(b in d?b=[b]:(b=p.camelCase(b),b in d?b=[b]:b=b.split(" ")));for(e=0,f=b.length;e<f;e++)delete d[b[e]];if(!(c?K:p.isEmptyObject)(d))return}}if(!c){delete h[i].data;if(!K(h[i]))return}g?p.cleanData([a],!0):p.support.deleteExpando||h!=h.window?delete h[i]:h[i]=null},_data:function(a,b,c){return p.data(a,b,c,!0)},acceptData:function(a){var b=a.nodeName&&p.noData[a.nodeName.toLowerCase()];return!b||b!==!0&&a.getAttribute("classid")===b}}),p.fn.extend({data:function(a,c){var d,e,f,g,h,i=this[0],j=0,k=null;if(a===b){if(this.length){k=p.data(i);if(i.nodeType===1&&!p._data(i,"parsedAttrs")){f=i.attributes;for(h=f.length;j<h;j++)g=f[j].name,g.indexOf("data-")||(g=p.camelCase(g.substring(5)),J(i,g,k[g]));p._data(i,"parsedAttrs",!0)}}return k}return typeof a=="object"?this.each(function(){p.data(this,a)}):(d=a.split(".",2),d[1]=d[1]?"."+d[1]:"",e=d[1]+"!",p.access(this,function(c){if(c===b)return k=this.triggerHandler("getData"+e,[d[0]]),k===b&&i&&(k=p.data(i,a),k=J(i,a,k)),k===b&&d[1]?this.data(d[0]):k;d[1]=c,this.each(function(){var b=p(this);b.triggerHandler("setData"+e,d),p.data(this,a,c),b.triggerHandler("changeData"+e,d)})},null,c,arguments.length>1,null,!1))},removeData:function(a){return this.each(function(){p.removeData(this,a)})}}),p.extend({queue:function(a,b,c){var d;if(a)return b=(b||"fx")+"queue",d=p._data(a,b),c&&(!d||p.isArray(c)?d=p._data(a,b,p.makeArray(c)):d.push(c)),d||[]},dequeue:function(a,b){b=b||"fx";var c=p.queue(a,b),d=c.length,e=c.shift(),f=p._queueHooks(a,b),g=function(){p.dequeue(a,b)};e==="inprogress"&&(e=c.shift(),d--),e&&(b==="fx"&&c.unshift("inprogress"),delete f.stop,e.call(a,g,f)),!d&&f&&f.empty.fire()},_queueHooks:function(a,b){var c=b+"queueHooks";return p._data(a,c)||p._data(a,c,{empty:p.Callbacks("once memory").add(function(){p.removeData(a,b+"queue",!0),p.removeData(a,c,!0)})})}}),p.fn.extend({queue:function(a,c){var d=2;return typeof a!="string"&&(c=a,a="fx",d--),arguments.length<d?p.queue(this[0],a):c===b?this:this.each(function(){var b=p.queue(this,a,c);p._queueHooks(this,a),a==="fx"&&b[0]!=="inprogress"&&p.dequeue(this,a)})},dequeue:function(a){return this.each(function(){p.dequeue(this,a)})},delay:function(a,b){return a=p.fx?p.fx.speeds[a]||a:a,b=b||"fx",this.queue(b,function(b,c){var d=setTimeout(b,a);c.stop=function(){clearTimeout(d)}})},clearQueue:function(a){return this.queue(a||"fx",[])},promise:function(a,c){var d,e=1,f=p.Deferred(),g=this,h=this.length,i=function(){--e||f.resolveWith(g,[g])};typeof a!="string"&&(c=a,a=b),a=a||"fx";while(h--)d=p._data(g[h],a+"queueHooks"),d&&d.empty&&(e++,d.empty.add(i));return i(),f.promise(c)}});var L,M,N,O=/[\t\r\n]/g,P=/\r/g,Q=/^(?:button|input)$/i,R=/^(?:button|input|object|select|textarea)$/i,S=/^a(?:rea|)$/i,T=/^(?:autofocus|autoplay|async|checked|controls|defer|disabled|hidden|loop|multiple|open|readonly|required|scoped|selected)$/i,U=p.support.getSetAttribute;p.fn.extend({attr:function(a,b){return p.access(this,p.attr,a,b,arguments.length>1)},removeAttr:function(a){return this.each(function(){p.removeAttr(this,a)})},prop:function(a,b){return p.access(this,p.prop,a,b,arguments.length>1)},removeProp:function(a){return a=p.propFix[a]||a,this.each(function(){try{this[a]=b,delete this[a]}catch(c){}})},addClass:function(a){var b,c,d,e,f,g,h;if(p.isFunction(a))return this.each(function(b){p(this).addClass(a.call(this,b,this.className))});if(a&&typeof a=="string"){b=a.split(s);for(c=0,d=this.length;c<d;c++){e=this[c];if(e.nodeType===1)if(!e.className&&b.length===1)e.className=a;else{f=" "+e.className+" ";for(g=0,h=b.length;g<h;g++)f.indexOf(" "+b[g]+" ")<0&&(f+=b[g]+" ");e.className=p.trim(f)}}}return this},removeClass:function(a){var c,d,e,f,g,h,i;if(p.isFunction(a))return this.each(function(b){p(this).removeClass(a.call(this,b,this.className))});if(a&&typeof a=="string"||a===b){c=(a||"").split(s);for(h=0,i=this.length;h<i;h++){e=this[h];if(e.nodeType===1&&e.className){d=(" "+e.className+" ").replace(O," ");for(f=0,g=c.length;f<g;f++)while(d.indexOf(" "+c[f]+" ")>=0)d=d.replace(" "+c[f]+" "," ");e.className=a?p.trim(d):""}}}return this},toggleClass:function(a,b){var c=typeof a,d=typeof b=="boolean";return p.isFunction(a)?this.each(function(c){p(this).toggleClass(a.call(this,c,this.className,b),b)}):this.each(function(){if(c==="string"){var e,f=0,g=p(this),h=b,i=a.split(s);while(e=i[f++])h=d?h:!g.hasClass(e),g[h?"addClass":"removeClass"](e)}else if(c==="undefined"||c==="boolean")this.className&&p._data(this,"__className__",this.className),this.className=this.className||a===!1?"":p._data(this,"__className__")||""})},hasClass:function(a){var b=" "+a+" ",c=0,d=this.length;for(;c<d;c++)if(this[c].nodeType===1&&(" "+this[c].className+" ").replace(O," ").indexOf(b)>=0)return!0;return!1},val:function(a){var c,d,e,f=this[0];if(!arguments.length){if(f)return c=p.valHooks[f.type]||p.valHooks[f.nodeName.toLowerCase()],c&&"get"in c&&(d=c.get(f,"value"))!==b?d:(d=f.value,typeof d=="string"?d.replace(P,""):d==null?"":d);return}return e=p.isFunction(a),this.each(function(d){var f,g=p(this);if(this.nodeType!==1)return;e?f=a.call(this,d,g.val()):f=a,f==null?f="":typeof f=="number"?f+="":p.isArray(f)&&(f=p.map(f,function(a){return a==null?"":a+""})),c=p.valHooks[this.type]||p.valHooks[this.nodeName.toLowerCase()];if(!c||!("set"in c)||c.set(this,f,"value")===b)this.value=f})}}),p.extend({valHooks:{option:{get:function(a){var b=a.attributes.value;return!b||b.specified?a.value:a.text}},select:{get:function(a){var b,c,d,e,f=a.selectedIndex,g=[],h=a.options,i=a.type==="select-one";if(f<0)return null;c=i?f:0,d=i?f+1:h.length;for(;c<d;c++){e=h[c];if(e.selected&&(p.support.optDisabled?!e.disabled:e.getAttribute("disabled")===null)&&(!e.parentNode.disabled||!p.nodeName(e.parentNode,"optgroup"))){b=p(e).val();if(i)return b;g.push(b)}}return i&&!g.length&&h.length?p(h[f]).val():g},set:function(a,b){var c=p.makeArray(b);return p(a).find("option").each(function(){this.selected=p.inArray(p(this).val(),c)>=0}),c.length||(a.selectedIndex=-1),c}}},attrFn:{},attr:function(a,c,d,e){var f,g,h,i=a.nodeType;if(!a||i===3||i===8||i===2)return;if(e&&p.isFunction(p.fn[c]))return p(a)[c](d);if(typeof a.getAttribute=="undefined")return p.prop(a,c,d);h=i!==1||!p.isXMLDoc(a),h&&(c=c.toLowerCase(),g=p.attrHooks[c]||(T.test(c)?M:L));if(d!==b){if(d===null){p.removeAttr(a,c);return}return g&&"set"in g&&h&&(f=g.set(a,d,c))!==b?f:(a.setAttribute(c,d+""),d)}return g&&"get"in g&&h&&(f=g.get(a,c))!==null?f:(f=a.getAttribute(c),f===null?b:f)},removeAttr:function(a,b){var c,d,e,f,g=0;if(b&&a.nodeType===1){d=b.split(s);for(;g<d.length;g++)e=d[g],e&&(c=p.propFix[e]||e,f=T.test(e),f||p.attr(a,e,""),a.removeAttribute(U?e:c),f&&c in a&&(a[c]=!1))}},attrHooks:{type:{set:function(a,b){if(Q.test(a.nodeName)&&a.parentNode)p.error("type property can't be changed");else if(!p.support.radioValue&&b==="radio"&&p.nodeName(a,"input")){var c=a.value;return a.setAttribute("type",b),c&&(a.value=c),b}}},value:{get:function(a,b){return L&&p.nodeName(a,"button")?L.get(a,b):b in a?a.value:null},set:function(a,b,c){if(L&&p.nodeName(a,"button"))return L.set(a,b,c);a.value=b}}},propFix:{tabindex:"tabIndex",readonly:"readOnly","for":"htmlFor","class":"className",maxlength:"maxLength",cellspacing:"cellSpacing",cellpadding:"cellPadding",rowspan:"rowSpan",colspan:"colSpan",usemap:"useMap",frameborder:"frameBorder",contenteditable:"contentEditable"},prop:function(a,c,d){var e,f,g,h=a.nodeType;if(!a||h===3||h===8||h===2)return;return g=h!==1||!p.isXMLDoc(a),g&&(c=p.propFix[c]||c,f=p.propHooks[c]),d!==b?f&&"set"in f&&(e=f.set(a,d,c))!==b?e:a[c]=d:f&&"get"in f&&(e=f.get(a,c))!==null?e:a[c]},propHooks:{tabIndex:{get:function(a){var c=a.getAttributeNode("tabindex");return c&&c.specified?parseInt(c.value,10):R.test(a.nodeName)||S.test(a.nodeName)&&a.href?0:b}}}}),M={get:function(a,c){var d,e=p.prop(a,c);return e===!0||typeof e!="boolean"&&(d=a.getAttributeNode(c))&&d.nodeValue!==!1?c.toLowerCase():b},set:function(a,b,c){var d;return b===!1?p.removeAttr(a,c):(d=p.propFix[c]||c,d in a&&(a[d]=!0),a.setAttribute(c,c.toLowerCase())),c}},U||(N={name:!0,id:!0,coords:!0},L=p.valHooks.button={get:function(a,c){var d;return d=a.getAttributeNode(c),d&&(N[c]?d.value!=="":d.specified)?d.value:b},set:function(a,b,c){var d=a.getAttributeNode(c);return d||(d=e.createAttribute(c),a.setAttributeNode(d)),d.value=b+""}},p.each(["width","height"],function(a,b){p.attrHooks[b]=p.extend(p.attrHooks[b],{set:function(a,c){if(c==="")return a.setAttribute(b,"auto"),c}})}),p.attrHooks.contenteditable={get:L.get,set:function(a,b,c){b===""&&(b="false"),L.set(a,b,c)}}),p.support.hrefNormalized||p.each(["href","src","width","height"],function(a,c){p.attrHooks[c]=p.extend(p.attrHooks[c],{get:function(a){var d=a.getAttribute(c,2);return d===null?b:d}})}),p.support.style||(p.attrHooks.style={get:function(a){return a.style.cssText.toLowerCase()||b},set:function(a,b){return a.style.cssText=b+""}}),p.support.optSelected||(p.propHooks.selected=p.extend(p.propHooks.selected,{get:function(a){var b=a.parentNode;return b&&(b.selectedIndex,b.parentNode&&b.parentNode.selectedIndex),null}})),p.support.enctype||(p.propFix.enctype="encoding"),p.support.checkOn||p.each(["radio","checkbox"],function(){p.valHooks[this]={get:function(a){return a.getAttribute("value")===null?"on":a.value}}}),p.each(["radio","checkbox"],function(){p.valHooks[this]=p.extend(p.valHooks[this],{set:function(a,b){if(p.isArray(b))return a.checked=p.inArray(p(a).val(),b)>=0}})});var V=/^(?:textarea|input|select)$/i,W=/^([^\.]*|)(?:\.(.+)|)$/,X=/(?:^|\s)hover(\.\S+|)\b/,Y=/^key/,Z=/^(?:mouse|contextmenu)|click/,$=/^(?:focusinfocus|focusoutblur)$/,_=function(a){return p.event.special.hover?a:a.replace(X,"mouseenter$1 mouseleave$1")};p.event={add:function(a,c,d,e,f){var g,h,i,j,k,l,m,n,o,q,r;if(a.nodeType===3||a.nodeType===8||!c||!d||!(g=p._data(a)))return;d.handler&&(o=d,d=o.handler,f=o.selector),d.guid||(d.guid=p.guid++),i=g.events,i||(g.events=i={}),h=g.handle,h||(g.handle=h=function(a){return typeof p!="undefined"&&(!a||p.event.triggered!==a.type)?p.event.dispatch.apply(h.elem,arguments):b},h.elem=a),c=p.trim(_(c)).split(" ");for(j=0;j<c.length;j++){k=W.exec(c[j])||[],l=k[1],m=(k[2]||"").split(".").sort(),r=p.event.special[l]||{},l=(f?r.delegateType:r.bindType)||l,r=p.event.special[l]||{},n=p.extend({type:l,origType:k[1],data:e,handler:d,guid:d.guid,selector:f,needsContext:f&&p.expr.match.needsContext.test(f),namespace:m.join(".")},o),q=i[l];if(!q){q=i[l]=[],q.delegateCount=0;if(!r.setup||r.setup.call(a,e,m,h)===!1)a.addEventListener?a.addEventListener(l,h,!1):a.attachEvent&&a.attachEvent("on"+l,h)}r.add&&(r.add.call(a,n),n.handler.guid||(n.handler.guid=d.guid)),f?q.splice(q.delegateCount++,0,n):q.push(n),p.event.global[l]=!0}a=null},global:{},remove:function(a,b,c,d,e){var f,g,h,i,j,k,l,m,n,o,q,r=p.hasData(a)&&p._data(a);if(!r||!(m=r.events))return;b=p.trim(_(b||"")).split(" ");for(f=0;f<b.length;f++){g=W.exec(b[f])||[],h=i=g[1],j=g[2];if(!h){for(h in m)p.event.remove(a,h+b[f],c,d,!0);continue}n=p.event.special[h]||{},h=(d?n.delegateType:n.bindType)||h,o=m[h]||[],k=o.length,j=j?new RegExp("(^|\\.)"+j.split(".").sort().join("\\.(?:.*\\.|)")+"(\\.|$)"):null;for(l=0;l<o.length;l++)q=o[l],(e||i===q.origType)&&(!c||c.guid===q.guid)&&(!j||j.test(q.namespace))&&(!d||d===q.selector||d==="**"&&q.selector)&&(o.splice(l--,1),q.selector&&o.delegateCount--,n.remove&&n.remove.call(a,q));o.length===0&&k!==o.length&&((!n.teardown||n.teardown.call(a,j,r.handle)===!1)&&p.removeEvent(a,h,r.handle),delete m[h])}p.isEmptyObject(m)&&(delete r.handle,p.removeData(a,"events",!0))},customEvent:{getData:!0,setData:!0,changeData:!0},trigger:function(c,d,f,g){if(!f||f.nodeType!==3&&f.nodeType!==8){var h,i,j,k,l,m,n,o,q,r,s=c.type||c,t=[];if($.test(s+p.event.triggered))return;s.indexOf("!")>=0&&(s=s.slice(0,-1),i=!0),s.indexOf(".")>=0&&(t=s.split("."),s=t.shift(),t.sort());if((!f||p.event.customEvent[s])&&!p.event.global[s])return;c=typeof c=="object"?c[p.expando]?c:new p.Event(s,c):new p.Event(s),c.type=s,c.isTrigger=!0,c.exclusive=i,c.namespace=t.join("."),c.namespace_re=c.namespace?new RegExp("(^|\\.)"+t.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,m=s.indexOf(":")<0?"on"+s:"";if(!f){h=p.cache;for(j in h)h[j].events&&h[j].events[s]&&p.event.trigger(c,d,h[j].handle.elem,!0);return}c.result=b,c.target||(c.target=f),d=d!=null?p.makeArray(d):[],d.unshift(c),n=p.event.special[s]||{};if(n.trigger&&n.trigger.apply(f,d)===!1)return;q=[[f,n.bindType||s]];if(!g&&!n.noBubble&&!p.isWindow(f)){r=n.delegateType||s,k=$.test(r+s)?f:f.parentNode;for(l=f;k;k=k.parentNode)q.push([k,r]),l=k;l===(f.ownerDocument||e)&&q.push([l.defaultView||l.parentWindow||a,r])}for(j=0;j<q.length&&!c.isPropagationStopped();j++)k=q[j][0],c.type=q[j][1],o=(p._data(k,"events")||{})[c.type]&&p._data(k,"handle"),o&&o.apply(k,d),o=m&&k[m],o&&p.acceptData(k)&&o.apply&&o.apply(k,d)===!1&&c.preventDefault();return c.type=s,!g&&!c.isDefaultPrevented()&&(!n._default||n._default.apply(f.ownerDocument,d)===!1)&&(s!=="click"||!p.nodeName(f,"a"))&&p.acceptData(f)&&m&&f[s]&&(s!=="focus"&&s!=="blur"||c.target.offsetWidth!==0)&&!p.isWindow(f)&&(l=f[m],l&&(f[m]=null),p.event.triggered=s,f[s](),p.event.triggered=b,l&&(f[m]=l)),c.result}return},dispatch:function(c){c=p.event.fix(c||a.event);var d,e,f,g,h,i,j,l,m,n,o=(p._data(this,"events")||{})[c.type]||[],q=o.delegateCount,r=k.call(arguments),s=!c.exclusive&&!c.namespace,t=p.event.special[c.type]||{},u=[];r[0]=c,c.delegateTarget=this;if(t.preDispatch&&t.preDispatch.call(this,c)===!1)return;if(q&&(!c.button||c.type!=="click"))for(f=c.target;f!=this;f=f.parentNode||this)if(f.disabled!==!0||c.type!=="click"){h={},j=[];for(d=0;d<q;d++)l=o[d],m=l.selector,h[m]===b&&(h[m]=l.needsContext?p(m,this).index(f)>=0:p.find(m,this,null,[f]).length),h[m]&&j.push(l);j.length&&u.push({elem:f,matches:j})}o.length>q&&u.push({elem:this,matches:o.slice(q)});for(d=0;d<u.length&&!c.isPropagationStopped();d++){i=u[d],c.currentTarget=i.elem;for(e=0;e<i.matches.length&&!c.isImmediatePropagationStopped();e++){l=i.matches[e];if(s||!c.namespace&&!l.namespace||c.namespace_re&&c.namespace_re.test(l.namespace))c.data=l.data,c.handleObj=l,g=((p.event.special[l.origType]||{}).handle||l.handler).apply(i.elem,r),g!==b&&(c.result=g,g===!1&&(c.preventDefault(),c.stopPropagation()))}}return t.postDispatch&&t.postDispatch.call(this,c),c.result},props:"attrChange attrName relatedNode srcElement altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "),fixHooks:{},keyHooks:{props:"char charCode key keyCode".split(" "),filter:function(a,b){return a.which==null&&(a.which=b.charCode!=null?b.charCode:b.keyCode),a}},mouseHooks:{props:"button buttons clientX clientY fromElement offsetX offsetY pageX pageY screenX screenY toElement".split(" "),filter:function(a,c){var d,f,g,h=c.button,i=c.fromElement;return a.pageX==null&&c.clientX!=null&&(d=a.target.ownerDocument||e,f=d.documentElement,g=d.body,a.pageX=c.clientX+(f&&f.scrollLeft||g&&g.scrollLeft||0)-(f&&f.clientLeft||g&&g.clientLeft||0),a.pageY=c.clientY+(f&&f.scrollTop||g&&g.scrollTop||0)-(f&&f.clientTop||g&&g.clientTop||0)),!a.relatedTarget&&i&&(a.relatedTarget=i===a.target?c.toElement:i),!a.which&&h!==b&&(a.which=h&1?1:h&2?3:h&4?2:0),a}},fix:function(a){if(a[p.expando])return a;var b,c,d=a,f=p.event.fixHooks[a.type]||{},g=f.props?this.props.concat(f.props):this.props;a=p.Event(d);for(b=g.length;b;)c=g[--b],a[c]=d[c];return a.target||(a.target=d.srcElement||e),a.target.nodeType===3&&(a.target=a.target.parentNode),a.metaKey=!!a.metaKey,f.filter?f.filter(a,d):a},special:{load:{noBubble:!0},focus:{delegateType:"focusin"},blur:{delegateType:"focusout"},beforeunload:{setup:function(a,b,c){p.isWindow(this)&&(this.onbeforeunload=c)},teardown:function(a,b){this.onbeforeunload===b&&(this.onbeforeunload=null)}}},simulate:function(a,b,c,d){var e=p.extend(new p.Event,c,{type:a,isSimulated:!0,originalEvent:{}});d?p.event.trigger(e,null,b):p.event.dispatch.call(b,e),e.isDefaultPrevented()&&c.preventDefault()}},p.event.handle=p.event.dispatch,p.removeEvent=e.removeEventListener?function(a,b,c){a.removeEventListener&&a.removeEventListener(b,c,!1)}:function(a,b,c){var d="on"+b;a.detachEvent&&(typeof a[d]=="undefined"&&(a[d]=null),a.detachEvent(d,c))},p.Event=function(a,b){if(this instanceof p.Event)a&&a.type?(this.originalEvent=a,this.type=a.type,this.isDefaultPrevented=a.defaultPrevented||a.returnValue===!1||a.getPreventDefault&&a.getPreventDefault()?bb:ba):this.type=a,b&&p.extend(this,b),this.timeStamp=a&&a.timeStamp||p.now(),this[p.expando]=!0;else return new p.Event(a,b)},p.Event.prototype={preventDefault:function(){this.isDefaultPrevented=bb;var a=this.originalEvent;if(!a)return;a.preventDefault?a.preventDefault():a.returnValue=!1},stopPropagation:function(){this.isPropagationStopped=bb;var a=this.originalEvent;if(!a)return;a.stopPropagation&&a.stopPropagation(),a.cancelBubble=!0},stopImmediatePropagation:function(){this.isImmediatePropagationStopped=bb,this.stopPropagation()},isDefaultPrevented:ba,isPropagationStopped:ba,isImmediatePropagationStopped:ba},p.each({mouseenter:"mouseover",mouseleave:"mouseout"},function(a,b){p.event.special[a]={delegateType:b,bindType:b,handle:function(a){var c,d=this,e=a.relatedTarget,f=a.handleObj,g=f.selector;if(!e||e!==d&&!p.contains(d,e))a.type=f.origType,c=f.handler.apply(this,arguments),a.type=b;return c}}}),p.support.submitBubbles||(p.event.special.submit={setup:function(){if(p.nodeName(this,"form"))return!1;p.event.add(this,"click._submit keypress._submit",function(a){var c=a.target,d=p.nodeName(c,"input")||p.nodeName(c,"button")?c.form:b;d&&!p._data(d,"_submit_attached")&&(p.event.add(d,"submit._submit",function(a){a._submit_bubble=!0}),p._data(d,"_submit_attached",!0))})},postDispatch:function(a){a._submit_bubble&&(delete a._submit_bubble,this.parentNode&&!a.isTrigger&&p.event.simulate("submit",this.parentNode,a,!0))},teardown:function(){if(p.nodeName(this,"form"))return!1;p.event.remove(this,"._submit")}}),p.support.changeBubbles||(p.event.special.change={setup:function(){if(V.test(this.nodeName)){if(this.type==="checkbox"||this.type==="radio")p.event.add(this,"propertychange._change",function(a){a.originalEvent.propertyName==="checked"&&(this._just_changed=!0)}),p.event.add(this,"click._change",function(a){this._just_changed&&!a.isTrigger&&(this._just_changed=!1),p.event.simulate("change",this,a,!0)});return!1}p.event.add(this,"beforeactivate._change",function(a){var b=a.target;V.test(b.nodeName)&&!p._data(b,"_change_attached")&&(p.event.add(b,"change._change",function(a){this.parentNode&&!a.isSimulated&&!a.isTrigger&&p.event.simulate("change",this.parentNode,a,!0)}),p._data(b,"_change_attached",!0))})},handle:function(a){var b=a.target;if(this!==b||a.isSimulated||a.isTrigger||b.type!=="radio"&&b.type!=="checkbox")return a.handleObj.handler.apply(this,arguments)},teardown:function(){return p.event.remove(this,"._change"),!V.test(this.nodeName)}}),p.support.focusinBubbles||p.each({focus:"focusin",blur:"focusout"},function(a,b){var c=0,d=function(a){p.event.simulate(b,a.target,p.event.fix(a),!0)};p.event.special[b]={setup:function(){c++===0&&e.addEventListener(a,d,!0)},teardown:function(){--c===0&&e.removeEventListener(a,d,!0)}}}),p.fn.extend({on:function(a,c,d,e,f){var g,h;if(typeof a=="object"){typeof c!="string"&&(d=d||c,c=b);for(h in a)this.on(h,c,d,a[h],f);return this}d==null&&e==null?(e=c,d=c=b):e==null&&(typeof c=="string"?(e=d,d=b):(e=d,d=c,c=b));if(e===!1)e=ba;else if(!e)return this;return f===1&&(g=e,e=function(a){return p().off(a),g.apply(this,arguments)},e.guid=g.guid||(g.guid=p.guid++)),this.each(function(){p.event.add(this,a,e,d,c)})},one:function(a,b,c,d){return this.on(a,b,c,d,1)},off:function(a,c,d){var e,f;if(a&&a.preventDefault&&a.handleObj)return e=a.handleObj,p(a.delegateTarget).off(e.namespace?e.origType+"."+e.namespace:e.origType,e.selector,e.handler),this;if(typeof a=="object"){for(f in a)this.off(f,c,a[f]);return this}if(c===!1||typeof c=="function")d=c,c=b;return d===!1&&(d=ba),this.each(function(){p.event.remove(this,a,d,c)})},bind:function(a,b,c){return this.on(a,null,b,c)},unbind:function(a,b){return this.off(a,null,b)},live:function(a,b,c){return p(this.context).on(a,this.selector,b,c),this},die:function(a,b){return p(this.context).off(a,this.selector||"**",b),this},delegate:function(a,b,c,d){return this.on(b,a,c,d)},undelegate:function(a,b,c){return arguments.length===1?this.off(a,"**"):this.off(b,a||"**",c)},trigger:function(a,b){return this.each(function(){p.event.trigger(a,b,this)})},triggerHandler:function(a,b){if(this[0])return p.event.trigger(a,b,this[0],!0)},toggle:function(a){var b=arguments,c=a.guid||p.guid++,d=0,e=function(c){var e=(p._data(this,"lastToggle"+a.guid)||0)%d;return p._data(this,"lastToggle"+a.guid,e+1),c.preventDefault(),b[e].apply(this,arguments)||!1};e.guid=c;while(d<b.length)b[d++].guid=c;return this.click(e)},hover:function(a,b){return this.mouseenter(a).mouseleave(b||a)}}),p.each("blur focus focusin focusout load resize scroll unload click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup error contextmenu".split(" "),function(a,b){p.fn[b]=function(a,c){return c==null&&(c=a,a=null),arguments.length>0?this.on(b,null,a,c):this.trigger(b)},Y.test(b)&&(p.event.fixHooks[b]=p.event.keyHooks),Z.test(b)&&(p.event.fixHooks[b]=p.event.mouseHooks)}),function(a,b){function bc(a,b,c,d){c=c||[],b=b||r;var e,f,i,j,k=b.nodeType;if(!a||typeof a!="string")return c;if(k!==1&&k!==9)return[];i=g(b);if(!i&&!d)if(e=P.exec(a))if(j=e[1]){if(k===9){f=b.getElementById(j);if(!f||!f.parentNode)return c;if(f.id===j)return c.push(f),c}else if(b.ownerDocument&&(f=b.ownerDocument.getElementById(j))&&h(b,f)&&f.id===j)return c.push(f),c}else{if(e[2])return w.apply(c,x.call(b.getElementsByTagName(a),0)),c;if((j=e[3])&&_&&b.getElementsByClassName)return w.apply(c,x.call(b.getElementsByClassName(j),0)),c}return bp(a.replace(L,"$1"),b,c,d,i)}function bd(a){return function(b){var c=b.nodeName.toLowerCase();return c==="input"&&b.type===a}}function be(a){return function(b){var c=b.nodeName.toLowerCase();return(c==="input"||c==="button")&&b.type===a}}function bf(a){return z(function(b){return b=+b,z(function(c,d){var e,f=a([],c.length,b),g=f.length;while(g--)c[e=f[g]]&&(c[e]=!(d[e]=c[e]))})})}function bg(a,b,c){if(a===b)return c;var d=a.nextSibling;while(d){if(d===b)return-1;d=d.nextSibling}return 1}function bh(a,b){var c,d,f,g,h,i,j,k=C[o][a];if(k)return b?0:k.slice(0);h=a,i=[],j=e.preFilter;while(h){if(!c||(d=M.exec(h)))d&&(h=h.slice(d[0].length)),i.push(f=[]);c=!1;if(d=N.exec(h))f.push(c=new q(d.shift())),h=h.slice(c.length),c.type=d[0].replace(L," ");for(g in e.filter)(d=W[g].exec(h))&&(!j[g]||(d=j[g](d,r,!0)))&&(f.push(c=new q(d.shift())),h=h.slice(c.length),c.type=g,c.matches=d);if(!c)break}return b?h.length:h?bc.error(a):C(a,i).slice(0)}function bi(a,b,d){var e=b.dir,f=d&&b.dir==="parentNode",g=u++;return b.first?function(b,c,d){while(b=b[e])if(f||b.nodeType===1)return a(b,c,d)}:function(b,d,h){if(!h){var i,j=t+" "+g+" ",k=j+c;while(b=b[e])if(f||b.nodeType===1){if((i=b[o])===k)return b.sizset;if(typeof i=="string"&&i.indexOf(j)===0){if(b.sizset)return b}else{b[o]=k;if(a(b,d,h))return b.sizset=!0,b;b.sizset=!1}}}else while(b=b[e])if(f||b.nodeType===1)if(a(b,d,h))return b}}function bj(a){return a.length>1?function(b,c,d){var e=a.length;while(e--)if(!a[e](b,c,d))return!1;return!0}:a[0]}function bk(a,b,c,d,e){var f,g=[],h=0,i=a.length,j=b!=null;for(;h<i;h++)if(f=a[h])if(!c||c(f,d,e))g.push(f),j&&b.push(h);return g}function bl(a,b,c,d,e,f){return d&&!d[o]&&(d=bl(d)),e&&!e[o]&&(e=bl(e,f)),z(function(f,g,h,i){if(f&&e)return;var j,k,l,m=[],n=[],o=g.length,p=f||bo(b||"*",h.nodeType?[h]:h,[],f),q=a&&(f||!b)?bk(p,m,a,h,i):p,r=c?e||(f?a:o||d)?[]:g:q;c&&c(q,r,h,i);if(d){l=bk(r,n),d(l,[],h,i),j=l.length;while(j--)if(k=l[j])r[n[j]]=!(q[n[j]]=k)}if(f){j=a&&r.length;while(j--)if(k=r[j])f[m[j]]=!(g[m[j]]=k)}else r=bk(r===g?r.splice(o,r.length):r),e?e(null,g,r,i):w.apply(g,r)})}function bm(a){var b,c,d,f=a.length,g=e.relative[a[0].type],h=g||e.relative[" "],i=g?1:0,j=bi(function(a){return a===b},h,!0),k=bi(function(a){return y.call(b,a)>-1},h,!0),m=[function(a,c,d){return!g&&(d||c!==l)||((b=c).nodeType?j(a,c,d):k(a,c,d))}];for(;i<f;i++)if(c=e.relative[a[i].type])m=[bi(bj(m),c)];else{c=e.filter[a[i].type].apply(null,a[i].matches);if(c[o]){d=++i;for(;d<f;d++)if(e.relative[a[d].type])break;return bl(i>1&&bj(m),i>1&&a.slice(0,i-1).join("").replace(L,"$1"),c,i<d&&bm(a.slice(i,d)),d<f&&bm(a=a.slice(d)),d<f&&a.join(""))}m.push(c)}return bj(m)}function bn(a,b){var d=b.length>0,f=a.length>0,g=function(h,i,j,k,m){var n,o,p,q=[],s=0,u="0",x=h&&[],y=m!=null,z=l,A=h||f&&e.find.TAG("*",m&&i.parentNode||i),B=t+=z==null?1:Math.E;y&&(l=i!==r&&i,c=g.el);for(;(n=A[u])!=null;u++){if(f&&n){for(o=0;p=a[o];o++)if(p(n,i,j)){k.push(n);break}y&&(t=B,c=++g.el)}d&&((n=!p&&n)&&s--,h&&x.push(n))}s+=u;if(d&&u!==s){for(o=0;p=b[o];o++)p(x,q,i,j);if(h){if(s>0)while(u--)!x[u]&&!q[u]&&(q[u]=v.call(k));q=bk(q)}w.apply(k,q),y&&!h&&q.length>0&&s+b.length>1&&bc.uniqueSort(k)}return y&&(t=B,l=z),x};return g.el=0,d?z(g):g}function bo(a,b,c,d){var e=0,f=b.length;for(;e<f;e++)bc(a,b[e],c,d);return c}function bp(a,b,c,d,f){var g,h,j,k,l,m=bh(a),n=m.length;if(!d&&m.length===1){h=m[0]=m[0].slice(0);if(h.length>2&&(j=h[0]).type==="ID"&&b.nodeType===9&&!f&&e.relative[h[1].type]){b=e.find.ID(j.matches[0].replace(V,""),b,f)[0];if(!b)return c;a=a.slice(h.shift().length)}for(g=W.POS.test(a)?-1:h.length-1;g>=0;g--){j=h[g];if(e.relative[k=j.type])break;if(l=e.find[k])if(d=l(j.matches[0].replace(V,""),R.test(h[0].type)&&b.parentNode||b,f)){h.splice(g,1),a=d.length&&h.join("");if(!a)return w.apply(c,x.call(d,0)),c;break}}}return i(a,m)(d,b,f,c,R.test(a)),c}function bq(){}var c,d,e,f,g,h,i,j,k,l,m=!0,n="undefined",o=("sizcache"+Math.random()).replace(".",""),q=String,r=a.document,s=r.documentElement,t=0,u=0,v=[].pop,w=[].push,x=[].slice,y=[].indexOf||function(a){var b=0,c=this.length;for(;b<c;b++)if(this[b]===a)return b;return-1},z=function(a,b){return a[o]=b==null||b,a},A=function(){var a={},b=[];return z(function(c,d){return b.push(c)>e.cacheLength&&delete a[b.shift()],a[c]=d},a)},B=A(),C=A(),D=A(),E="[\\x20\\t\\r\\n\\f]",F="(?:\\\\.|[-\\w]|[^\\x00-\\xa0])+",G=F.replace("w","w#"),H="([*^$|!~]?=)",I="\\["+E+"*("+F+")"+E+"*(?:"+H+E+"*(?:(['\"])((?:\\\\.|[^\\\\])*?)\\3|("+G+")|)|)"+E+"*\\]",J=":("+F+")(?:\\((?:(['\"])((?:\\\\.|[^\\\\])*?)\\2|([^()[\\]]*|(?:(?:"+I+")|[^:]|\\\\.)*|.*))\\)|)",K=":(even|odd|eq|gt|lt|nth|first|last)(?:\\("+E+"*((?:-\\d)?\\d*)"+E+"*\\)|)(?=[^-]|$)",L=new RegExp("^"+E+"+|((?:^|[^\\\\])(?:\\\\.)*)"+E+"+$","g"),M=new RegExp("^"+E+"*,"+E+"*"),N=new RegExp("^"+E+"*([\\x20\\t\\r\\n\\f>+~])"+E+"*"),O=new RegExp(J),P=/^(?:#([\w\-]+)|(\w+)|\.([\w\-]+))$/,Q=/^:not/,R=/[\x20\t\r\n\f]*[+~]/,S=/:not\($/,T=/h\d/i,U=/input|select|textarea|button/i,V=/\\(?!\\)/g,W={ID:new RegExp("^#("+F+")"),CLASS:new RegExp("^\\.("+F+")"),NAME:new RegExp("^\\[name=['\"]?("+F+")['\"]?\\]"),TAG:new RegExp("^("+F.replace("w","w*")+")"),ATTR:new RegExp("^"+I),PSEUDO:new RegExp("^"+J),POS:new RegExp(K,"i"),CHILD:new RegExp("^:(only|nth|first|last)-child(?:\\("+E+"*(even|odd|(([+-]|)(\\d*)n|)"+E+"*(?:([+-]|)"+E+"*(\\d+)|))"+E+"*\\)|)","i"),needsContext:new RegExp("^"+E+"*[>+~]|"+K,"i")},X=function(a){var b=r.createElement("div");try{return a(b)}catch(c){return!1}finally{b=null}},Y=X(function(a){return a.appendChild(r.createComment("")),!a.getElementsByTagName("*").length}),Z=X(function(a){return a.innerHTML="<a href='#'></a>",a.firstChild&&typeof a.firstChild.getAttribute!==n&&a.firstChild.getAttribute("href")==="#"}),$=X(function(a){a.innerHTML="<select></select>";var b=typeof a.lastChild.getAttribute("multiple");return b!=="boolean"&&b!=="string"}),_=X(function(a){return a.innerHTML="<div class='hidden e'></div><div class='hidden'></div>",!a.getElementsByClassName||!a.getElementsByClassName("e").length?!1:(a.lastChild.className="e",a.getElementsByClassName("e").length===2)}),ba=X(function(a){a.id=o+0,a.innerHTML="<a name='"+o+"'></a><div name='"+o+"'></div>",s.insertBefore(a,s.firstChild);var b=r.getElementsByName&&r.getElementsByName(o).length===2+r.getElementsByName(o+0).length;return d=!r.getElementById(o),s.removeChild(a),b});try{x.call(s.childNodes,0)[0].nodeType}catch(bb){x=function(a){var b,c=[];for(;b=this[a];a++)c.push(b);return c}}bc.matches=function(a,b){return bc(a,null,null,b)},bc.matchesSelector=function(a,b){return bc(b,null,null,[a]).length>0},f=bc.getText=function(a){var b,c="",d=0,e=a.nodeType;if(e){if(e===1||e===9||e===11){if(typeof a.textContent=="string")return a.textContent;for(a=a.firstChild;a;a=a.nextSibling)c+=f(a)}else if(e===3||e===4)return a.nodeValue}else for(;b=a[d];d++)c+=f(b);return c},g=bc.isXML=function(a){var b=a&&(a.ownerDocument||a).documentElement;return b?b.nodeName!=="HTML":!1},h=bc.contains=s.contains?function(a,b){var c=a.nodeType===9?a.documentElement:a,d=b&&b.parentNode;return a===d||!!(d&&d.nodeType===1&&c.contains&&c.contains(d))}:s.compareDocumentPosition?function(a,b){return b&&!!(a.compareDocumentPosition(b)&16)}:function(a,b){while(b=b.parentNode)if(b===a)return!0;return!1},bc.attr=function(a,b){var c,d=g(a);return d||(b=b.toLowerCase()),(c=e.attrHandle[b])?c(a):d||$?a.getAttribute(b):(c=a.getAttributeNode(b),c?typeof a[b]=="boolean"?a[b]?b:null:c.specified?c.value:null:null)},e=bc.selectors={cacheLength:50,createPseudo:z,match:W,attrHandle:Z?{}:{href:function(a){return a.getAttribute("href",2)},type:function(a){return a.getAttribute("type")}},find:{ID:d?function(a,b,c){if(typeof b.getElementById!==n&&!c){var d=b.getElementById(a);return d&&d.parentNode?[d]:[]}}:function(a,c,d){if(typeof c.getElementById!==n&&!d){var e=c.getElementById(a);return e?e.id===a||typeof e.getAttributeNode!==n&&e.getAttributeNode("id").value===a?[e]:b:[]}},TAG:Y?function(a,b){if(typeof b.getElementsByTagName!==n)return b.getElementsByTagName(a)}:function(a,b){var c=b.getElementsByTagName(a);if(a==="*"){var d,e=[],f=0;for(;d=c[f];f++)d.nodeType===1&&e.push(d);return e}return c},NAME:ba&&function(a,b){if(typeof b.getElementsByName!==n)return b.getElementsByName(name)},CLASS:_&&function(a,b,c){if(typeof b.getElementsByClassName!==n&&!c)return b.getElementsByClassName(a)}},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(a){return a[1]=a[1].replace(V,""),a[3]=(a[4]||a[5]||"").replace(V,""),a[2]==="~="&&(a[3]=" "+a[3]+" "),a.slice(0,4)},CHILD:function(a){return a[1]=a[1].toLowerCase(),a[1]==="nth"?(a[2]||bc.error(a[0]),a[3]=+(a[3]?a[4]+(a[5]||1):2*(a[2]==="even"||a[2]==="odd")),a[4]=+(a[6]+a[7]||a[2]==="odd")):a[2]&&bc.error(a[0]),a},PSEUDO:function(a){var b,c;if(W.CHILD.test(a[0]))return null;if(a[3])a[2]=a[3];else if(b=a[4])O.test(b)&&(c=bh(b,!0))&&(c=b.indexOf(")",b.length-c)-b.length)&&(b=b.slice(0,c),a[0]=a[0].slice(0,c)),a[2]=b;return a.slice(0,3)}},filter:{ID:d?function(a){return a=a.replace(V,""),function(b){return b.getAttribute("id")===a}}:function(a){return a=a.replace(V,""),function(b){var c=typeof b.getAttributeNode!==n&&b.getAttributeNode("id");return c&&c.value===a}},TAG:function(a){return a==="*"?function(){return!0}:(a=a.replace(V,"").toLowerCase(),function(b){return b.nodeName&&b.nodeName.toLowerCase()===a})},CLASS:function(a){var b=B[o][a];return b||(b=B(a,new RegExp("(^|"+E+")"+a+"("+E+"|$)"))),function(a){return b.test(a.className||typeof a.getAttribute!==n&&a.getAttribute("class")||"")}},ATTR:function(a,b,c){return function(d,e){var f=bc.attr(d,a);return f==null?b==="!=":b?(f+="",b==="="?f===c:b==="!="?f!==c:b==="^="?c&&f.indexOf(c)===0:b==="*="?c&&f.indexOf(c)>-1:b==="$="?c&&f.substr(f.length-c.length)===c:b==="~="?(" "+f+" ").indexOf(c)>-1:b==="|="?f===c||f.substr(0,c.length+1)===c+"-":!1):!0}},CHILD:function(a,b,c,d){return a==="nth"?function(a){var b,e,f=a.parentNode;if(c===1&&d===0)return!0;if(f){e=0;for(b=f.firstChild;b;b=b.nextSibling)if(b.nodeType===1){e++;if(a===b)break}}return e-=d,e===c||e%c===0&&e/c>=0}:function(b){var c=b;switch(a){case"only":case"first":while(c=c.previousSibling)if(c.nodeType===1)return!1;if(a==="first")return!0;c=b;case"last":while(c=c.nextSibling)if(c.nodeType===1)return!1;return!0}}},PSEUDO:function(a,b){var c,d=e.pseudos[a]||e.setFilters[a.toLowerCase()]||bc.error("unsupported pseudo: "+a);return d[o]?d(b):d.length>1?(c=[a,a,"",b],e.setFilters.hasOwnProperty(a.toLowerCase())?z(function(a,c){var e,f=d(a,b),g=f.length;while(g--)e=y.call(a,f[g]),a[e]=!(c[e]=f[g])}):function(a){return d(a,0,c)}):d}},pseudos:{not:z(function(a){var b=[],c=[],d=i(a.replace(L,"$1"));return d[o]?z(function(a,b,c,e){var f,g=d(a,null,e,[]),h=a.length;while(h--)if(f=g[h])a[h]=!(b[h]=f)}):function(a,e,f){return b[0]=a,d(b,null,f,c),!c.pop()}}),has:z(function(a){return function(b){return bc(a,b).length>0}}),contains:z(function(a){return function(b){return(b.textContent||b.innerText||f(b)).indexOf(a)>-1}}),enabled:function(a){return a.disabled===!1},disabled:function(a){return a.disabled===!0},checked:function(a){var b=a.nodeName.toLowerCase();return b==="input"&&!!a.checked||b==="option"&&!!a.selected},selected:function(a){return a.parentNode&&a.parentNode.selectedIndex,a.selected===!0},parent:function(a){return!e.pseudos.empty(a)},empty:function(a){var b;a=a.firstChild;while(a){if(a.nodeName>"@"||(b=a.nodeType)===3||b===4)return!1;a=a.nextSibling}return!0},header:function(a){return T.test(a.nodeName)},text:function(a){var b,c;return a.nodeName.toLowerCase()==="input"&&(b=a.type)==="text"&&((c=a.getAttribute("type"))==null||c.toLowerCase()===b)},radio:bd("radio"),checkbox:bd("checkbox"),file:bd("file"),password:bd("password"),image:bd("image"),submit:be("submit"),reset:be("reset"),button:function(a){var b=a.nodeName.toLowerCase();return b==="input"&&a.type==="button"||b==="button"},input:function(a){return U.test(a.nodeName)},focus:function(a){var b=a.ownerDocument;return a===b.activeElement&&(!b.hasFocus||b.hasFocus())&&(!!a.type||!!a.href)},active:function(a){return a===a.ownerDocument.activeElement},first:bf(function(a,b,c){return[0]}),last:bf(function(a,b,c){return[b-1]}),eq:bf(function(a,b,c){return[c<0?c+b:c]}),even:bf(function(a,b,c){for(var d=0;d<b;d+=2)a.push(d);return a}),odd:bf(function(a,b,c){for(var d=1;d<b;d+=2)a.push(d);return a}),lt:bf(function(a,b,c){for(var d=c<0?c+b:c;--d>=0;)a.push(d);return a}),gt:bf(function(a,b,c){for(var d=c<0?c+b:c;++d<b;)a.push(d);return a})}},j=s.compareDocumentPosition?function(a,b){return a===b?(k=!0,0):(!a.compareDocumentPosition||!b.compareDocumentPosition?a.compareDocumentPosition:a.compareDocumentPosition(b)&4)?-1:1}:function(a,b){if(a===b)return k=!0,0;if(a.sourceIndex&&b.sourceIndex)return a.sourceIndex-b.sourceIndex;var c,d,e=[],f=[],g=a.parentNode,h=b.parentNode,i=g;if(g===h)return bg(a,b);if(!g)return-1;if(!h)return 1;while(i)e.unshift(i),i=i.parentNode;i=h;while(i)f.unshift(i),i=i.parentNode;c=e.length,d=f.length;for(var j=0;j<c&&j<d;j++)if(e[j]!==f[j])return bg(e[j],f[j]);return j===c?bg(a,f[j],-1):bg(e[j],b,1)},[0,0].sort(j),m=!k,bc.uniqueSort=function(a){var b,c=1;k=m,a.sort(j);if(k)for(;b=a[c];c++)b===a[c-1]&&a.splice(c--,1);return a},bc.error=function(a){throw new Error("Syntax error, unrecognized expression: "+a)},i=bc.compile=function(a,b){var c,d=[],e=[],f=D[o][a];if(!f){b||(b=bh(a)),c=b.length;while(c--)f=bm(b[c]),f[o]?d.push(f):e.push(f);f=D(a,bn(e,d))}return f},r.querySelectorAll&&function(){var a,b=bp,c=/'|\\/g,d=/\=[\x20\t\r\n\f]*([^'"\]]*)[\x20\t\r\n\f]*\]/g,e=[":focus"],f=[":active",":focus"],h=s.matchesSelector||s.mozMatchesSelector||s.webkitMatchesSelector||s.oMatchesSelector||s.msMatchesSelector;X(function(a){a.innerHTML="<select><option selected=''></option></select>",a.querySelectorAll("[selected]").length||e.push("\\["+E+"*(?:checked|disabled|ismap|multiple|readonly|selected|value)"),a.querySelectorAll(":checked").length||e.push(":checked")}),X(function(a){a.innerHTML="<p test=''></p>",a.querySelectorAll("[test^='']").length&&e.push("[*^$]="+E+"*(?:\"\"|'')"),a.innerHTML="<input type='hidden'/>",a.querySelectorAll(":enabled").length||e.push(":enabled",":disabled")}),e=new RegExp(e.join("|")),bp=function(a,d,f,g,h){if(!g&&!h&&(!e||!e.test(a))){var i,j,k=!0,l=o,m=d,n=d.nodeType===9&&a;if(d.nodeType===1&&d.nodeName.toLowerCase()!=="object"){i=bh(a),(k=d.getAttribute("id"))?l=k.replace(c,"\\$&"):d.setAttribute("id",l),l="[id='"+l+"'] ",j=i.length;while(j--)i[j]=l+i[j].join("");m=R.test(a)&&d.parentNode||d,n=i.join(",")}if(n)try{return w.apply(f,x.call(m.querySelectorAll(n),0)),f}catch(p){}finally{k||d.removeAttribute("id")}}return b(a,d,f,g,h)},h&&(X(function(b){a=h.call(b,"div");try{h.call(b,"[test!='']:sizzle"),f.push("!=",J)}catch(c){}}),f=new RegExp(f.join("|")),bc.matchesSelector=function(b,c){c=c.replace(d,"='$1']");if(!g(b)&&!f.test(c)&&(!e||!e.test(c)))try{var i=h.call(b,c);if(i||a||b.document&&b.document.nodeType!==11)return i}catch(j){}return bc(c,null,null,[b]).length>0})}(),e.pseudos.nth=e.pseudos.eq,e.filters=bq.prototype=e.pseudos,e.setFilters=new bq,bc.attr=p.attr,p.find=bc,p.expr=bc.selectors,p.expr[":"]=p.expr.pseudos,p.unique=bc.uniqueSort,p.text=bc.getText,p.isXMLDoc=bc.isXML,p.contains=bc.contains}(a);var bc=/Until$/,bd=/^(?:parents|prev(?:Until|All))/,be=/^.[^:#\[\.,]*$/,bf=p.expr.match.needsContext,bg={children:!0,contents:!0,next:!0,prev:!0};p.fn.extend({find:function(a){var b,c,d,e,f,g,h=this;if(typeof a!="string")return p(a).filter(function(){for(b=0,c=h.length;b<c;b++)if(p.contains(h[b],this))return!0});g=this.pushStack("","find",a);for(b=0,c=this.length;b<c;b++){d=g.length,p.find(a,this[b],g);if(b>0)for(e=d;e<g.length;e++)for(f=0;f<d;f++)if(g[f]===g[e]){g.splice(e--,1);break}}return g},has:function(a){var b,c=p(a,this),d=c.length;return this.filter(function(){for(b=0;b<d;b++)if(p.contains(this,c[b]))return!0})},not:function(a){return this.pushStack(bj(this,a,!1),"not",a)},filter:function(a){return this.pushStack(bj(this,a,!0),"filter",a)},is:function(a){return!!a&&(typeof a=="string"?bf.test(a)?p(a,this.context).index(this[0])>=0:p.filter(a,this).length>0:this.filter(a).length>0)},closest:function(a,b){var c,d=0,e=this.length,f=[],g=bf.test(a)||typeof a!="string"?p(a,b||this.context):0;for(;d<e;d++){c=this[d];while(c&&c.ownerDocument&&c!==b&&c.nodeType!==11){if(g?g.index(c)>-1:p.find.matchesSelector(c,a)){f.push(c);break}c=c.parentNode}}return f=f.length>1?p.unique(f):f,this.pushStack(f,"closest",a)},index:function(a){return a?typeof a=="string"?p.inArray(this[0],p(a)):p.inArray(a.jquery?a[0]:a,this):this[0]&&this[0].parentNode?this.prevAll().length:-1},add:function(a,b){var c=typeof a=="string"?p(a,b):p.makeArray(a&&a.nodeType?[a]:a),d=p.merge(this.get(),c);return this.pushStack(bh(c[0])||bh(d[0])?d:p.unique(d))},addBack:function(a){return this.add(a==null?this.prevObject:this.prevObject.filter(a))}}),p.fn.andSelf=p.fn.addBack,p.each({parent:function(a){var b=a.parentNode;return b&&b.nodeType!==11?b:null},parents:function(a){return p.dir(a,"parentNode")},parentsUntil:function(a,b,c){return p.dir(a,"parentNode",c)},next:function(a){return bi(a,"nextSibling")},prev:function(a){return bi(a,"previousSibling")},nextAll:function(a){return p.dir(a,"nextSibling")},prevAll:function(a){return p.dir(a,"previousSibling")},nextUntil:function(a,b,c){return p.dir(a,"nextSibling",c)},prevUntil:function(a,b,c){return p.dir(a,"previousSibling",c)},siblings:function(a){return p.sibling((a.parentNode||{}).firstChild,a)},children:function(a){return p.sibling(a.firstChild)},contents:function(a){return p.nodeName(a,"iframe")?a.contentDocument||a.contentWindow.document:p.merge([],a.childNodes)}},function(a,b){p.fn[a]=function(c,d){var e=p.map(this,b,c);return bc.test(a)||(d=c),d&&typeof d=="string"&&(e=p.filter(d,e)),e=this.length>1&&!bg[a]?p.unique(e):e,this.length>1&&bd.test(a)&&(e=e.reverse()),this.pushStack(e,a,k.call(arguments).join(","))}}),p.extend({filter:function(a,b,c){return c&&(a=":not("+a+")"),b.length===1?p.find.matchesSelector(b[0],a)?[b[0]]:[]:p.find.matches(a,b)},dir:function(a,c,d){var e=[],f=a[c];while(f&&f.nodeType!==9&&(d===b||f.nodeType!==1||!p(f).is(d)))f.nodeType===1&&e.push(f),f=f[c];return e},sibling:function(a,b){var c=[];for(;a;a=a.nextSibling)a.nodeType===1&&a!==b&&c.push(a);return c}});var bl="abbr|article|aside|audio|bdi|canvas|data|datalist|details|figcaption|figure|footer|header|hgroup|mark|meter|nav|output|progress|section|summary|time|video",bm=/ jQuery\d+="(?:null|\d+)"/g,bn=/^\s+/,bo=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,bp=/<([\w:]+)/,bq=/<tbody/i,br=/<|&#?\w+;/,bs=/<(?:script|style|link)/i,bt=/<(?:script|object|embed|option|style)/i,bu=new RegExp("<(?:"+bl+")[\\s/>]","i"),bv=/^(?:checkbox|radio)$/,bw=/checked\s*(?:[^=]|=\s*.checked.)/i,bx=/\/(java|ecma)script/i,by=/^\s*<!(?:\[CDATA\[|\-\-)|[\]\-]{2}>\s*$/g,bz={option:[1,"<select multiple='multiple'>","</select>"],legend:[1,"<fieldset>","</fieldset>"],thead:[1,"<table>","</table>"],tr:[2,"<table><tbody>","</tbody></table>"],td:[3,"<table><tbody><tr>","</tr></tbody></table>"],col:[2,"<table><tbody></tbody><colgroup>","</colgroup></table>"],area:[1,"<map>","</map>"],_default:[0,"",""]},bA=bk(e),bB=bA.appendChild(e.createElement("div"));bz.optgroup=bz.option,bz.tbody=bz.tfoot=bz.colgroup=bz.caption=bz.thead,bz.th=bz.td,p.support.htmlSerialize||(bz._default=[1,"X<div>","</div>"]),p.fn.extend({text:function(a){return p.access(this,function(a){return a===b?p.text(this):this.empty().append((this[0]&&this[0].ownerDocument||e).createTextNode(a))},null,a,arguments.length)},wrapAll:function(a){if(p.isFunction(a))return this.each(function(b){p(this).wrapAll(a.call(this,b))});if(this[0]){var b=p(a,this[0].ownerDocument).eq(0).clone(!0);this[0].parentNode&&b.insertBefore(this[0]),b.map(function(){var a=this;while(a.firstChild&&a.firstChild.nodeType===1)a=a.firstChild;return a}).append(this)}return this},wrapInner:function(a){return p.isFunction(a)?this.each(function(b){p(this).wrapInner(a.call(this,b))}):this.each(function(){var b=p(this),c=b.contents();c.length?c.wrapAll(a):b.append(a)})},wrap:function(a){var b=p.isFunction(a);return this.each(function(c){p(this).wrapAll(b?a.call(this,c):a)})},unwrap:function(){return this.parent().each(function(){p.nodeName(this,"body")||p(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,!0,function(a){(this.nodeType===1||this.nodeType===11)&&this.appendChild(a)})},prepend:function(){return this.domManip(arguments,!0,function(a){(this.nodeType===1||this.nodeType===11)&&this.insertBefore(a,this.firstChild)})},before:function(){if(!bh(this[0]))return this.domManip(arguments,!1,function(a){this.parentNode.insertBefore(a,this)});if(arguments.length){var a=p.clean(arguments);return this.pushStack(p.merge(a,this),"before",this.selector)}},after:function(){if(!bh(this[0]))return this.domManip(arguments,!1,function(a){this.parentNode.insertBefore(a,this.nextSibling)});if(arguments.length){var a=p.clean(arguments);return this.pushStack(p.merge(this,a),"after",this.selector)}},remove:function(a,b){var c,d=0;for(;(c=this[d])!=null;d++)if(!a||p.filter(a,[c]).length)!b&&c.nodeType===1&&(p.cleanData(c.getElementsByTagName("*")),p.cleanData([c])),c.parentNode&&c.parentNode.removeChild(c);return this},empty:function(){var a,b=0;for(;(a=this[b])!=null;b++){a.nodeType===1&&p.cleanData(a.getElementsByTagName("*"));while(a.firstChild)a.removeChild(a.firstChild)}return this},clone:function(a,b){return a=a==null?!1:a,b=b==null?a:b,this.map(function(){return p.clone(this,a,b)})},html:function(a){return p.access(this,function(a){var c=this[0]||{},d=0,e=this.length;if(a===b)return c.nodeType===1?c.innerHTML.replace(bm,""):b;if(typeof a=="string"&&!bs.test(a)&&(p.support.htmlSerialize||!bu.test(a))&&(p.support.leadingWhitespace||!bn.test(a))&&!bz[(bp.exec(a)||["",""])[1].toLowerCase()]){a=a.replace(bo,"<$1></$2>");try{for(;d<e;d++)c=this[d]||{},c.nodeType===1&&(p.cleanData(c.getElementsByTagName("*")),c.innerHTML=a);c=0}catch(f){}}c&&this.empty().append(a)},null,a,arguments.length)},replaceWith:function(a){return bh(this[0])?this.length?this.pushStack(p(p.isFunction(a)?a():a),"replaceWith",a):this:p.isFunction(a)?this.each(function(b){var c=p(this),d=c.html();c.replaceWith(a.call(this,b,d))}):(typeof a!="string"&&(a=p(a).detach()),this.each(function(){var b=this.nextSibling,c=this.parentNode;p(this).remove(),b?p(b).before(a):p(c).append(a)}))},detach:function(a){return this.remove(a,!0)},domManip:function(a,c,d){a=[].concat.apply([],a);var e,f,g,h,i=0,j=a[0],k=[],l=this.length;if(!p.support.checkClone&&l>1&&typeof j=="string"&&bw.test(j))return this.each(function(){p(this).domManip(a,c,d)});if(p.isFunction(j))return this.each(function(e){var f=p(this);a[0]=j.call(this,e,c?f.html():b),f.domManip(a,c,d)});if(this[0]){e=p.buildFragment(a,this,k),g=e.fragment,f=g.firstChild,g.childNodes.length===1&&(g=f);if(f){c=c&&p.nodeName(f,"tr");for(h=e.cacheable||l-1;i<l;i++)d.call(c&&p.nodeName(this[i],"table")?bC(this[i],"tbody"):this[i],i===h?g:p.clone(g,!0,!0))}g=f=null,k.length&&p.each(k,function(a,b){b.src?p.ajax?p.ajax({url:b.src,type:"GET",dataType:"script",async:!1,global:!1,"throws":!0}):p.error("no ajax"):p.globalEval((b.text||b.textContent||b.innerHTML||"").replace(by,"")),b.parentNode&&b.parentNode.removeChild(b)})}return this}}),p.buildFragment=function(a,c,d){var f,g,h,i=a[0];return c=c||e,c=!c.nodeType&&c[0]||c,c=c.ownerDocument||c,a.length===1&&typeof i=="string"&&i.length<512&&c===e&&i.charAt(0)==="<"&&!bt.test(i)&&(p.support.checkClone||!bw.test(i))&&(p.support.html5Clone||!bu.test(i))&&(g=!0,f=p.fragments[i],h=f!==b),f||(f=c.createDocumentFragment(),p.clean(a,c,f,d),g&&(p.fragments[i]=h&&f)),{fragment:f,cacheable:g}},p.fragments={},p.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){p.fn[a]=function(c){var d,e=0,f=[],g=p(c),h=g.length,i=this.length===1&&this[0].parentNode;if((i==null||i&&i.nodeType===11&&i.childNodes.length===1)&&h===1)return g[b](this[0]),this;for(;e<h;e++)d=(e>0?this.clone(!0):this).get(),p(g[e])[b](d),f=f.concat(d);return this.pushStack(f,a,g.selector)}}),p.extend({clone:function(a,b,c){var d,e,f,g;p.support.html5Clone||p.isXMLDoc(a)||!bu.test("<"+a.nodeName+">")?g=a.cloneNode(!0):(bB.innerHTML=a.outerHTML,bB.removeChild(g=bB.firstChild));if((!p.support.noCloneEvent||!p.support.noCloneChecked)&&(a.nodeType===1||a.nodeType===11)&&!p.isXMLDoc(a)){bE(a,g),d=bF(a),e=bF(g);for(f=0;d[f];++f)e[f]&&bE(d[f],e[f])}if(b){bD(a,g);if(c){d=bF(a),e=bF(g);for(f=0;d[f];++f)bD(d[f],e[f])}}return d=e=null,g},clean:function(a,b,c,d){var f,g,h,i,j,k,l,m,n,o,q,r,s=b===e&&bA,t=[];if(!b||typeof b.createDocumentFragment=="undefined")b=e;for(f=0;(h=a[f])!=null;f++){typeof h=="number"&&(h+="");if(!h)continue;if(typeof h=="string")if(!br.test(h))h=b.createTextNode(h);else{s=s||bk(b),l=b.createElement("div"),s.appendChild(l),h=h.replace(bo,"<$1></$2>"),i=(bp.exec(h)||["",""])[1].toLowerCase(),j=bz[i]||bz._default,k=j[0],l.innerHTML=j[1]+h+j[2];while(k--)l=l.lastChild;if(!p.support.tbody){m=bq.test(h),n=i==="table"&&!m?l.firstChild&&l.firstChild.childNodes:j[1]==="<table>"&&!m?l.childNodes:[];for(g=n.length-1;g>=0;--g)p.nodeName(n[g],"tbody")&&!n[g].childNodes.length&&n[g].parentNode.removeChild(n[g])}!p.support.leadingWhitespace&&bn.test(h)&&l.insertBefore(b.createTextNode(bn.exec(h)[0]),l.firstChild),h=l.childNodes,l.parentNode.removeChild(l)}h.nodeType?t.push(h):p.merge(t,h)}l&&(h=l=s=null);if(!p.support.appendChecked)for(f=0;(h=t[f])!=null;f++)p.nodeName(h,"input")?bG(h):typeof h.getElementsByTagName!="undefined"&&p.grep(h.getElementsByTagName("input"),bG);if(c){q=function(a){if(!a.type||bx.test(a.type))return d?d.push(a.parentNode?a.parentNode.removeChild(a):a):c.appendChild(a)};for(f=0;(h=t[f])!=null;f++)if(!p.nodeName(h,"script")||!q(h))c.appendChild(h),typeof h.getElementsByTagName!="undefined"&&(r=p.grep(p.merge([],h.getElementsByTagName("script")),q),t.splice.apply(t,[f+1,0].concat(r)),f+=r.length)}return t},cleanData:function(a,b){var c,d,e,f,g=0,h=p.expando,i=p.cache,j=p.support.deleteExpando,k=p.event.special;for(;(e=a[g])!=null;g++)if(b||p.acceptData(e)){d=e[h],c=d&&i[d];if(c){if(c.events)for(f in c.events)k[f]?p.event.remove(e,f):p.removeEvent(e,f,c.handle);i[d]&&(delete i[d],j?delete e[h]:e.removeAttribute?e.removeAttribute(h):e[h]=null,p.deletedIds.push(d))}}}}),function(){var a,b;p.uaMatch=function(a){a=a.toLowerCase();var b=/(chrome)[ \/]([\w.]+)/.exec(a)||/(webkit)[ \/]([\w.]+)/.exec(a)||/(opera)(?:.*version|)[ \/]([\w.]+)/.exec(a)||/(msie) ([\w.]+)/.exec(a)||a.indexOf("compatible")<0&&/(mozilla)(?:.*? rv:([\w.]+)|)/.exec(a)||[];return{browser:b[1]||"",version:b[2]||"0"}},a=p.uaMatch(g.userAgent),b={},a.browser&&(b[a.browser]=!0,b.version=a.version),b.chrome?b.webkit=!0:b.webkit&&(b.safari=!0),p.browser=b,p.sub=function(){function a(b,c){return new a.fn.init(b,c)}p.extend(!0,a,this),a.superclass=this,a.fn=a.prototype=this(),a.fn.constructor=a,a.sub=this.sub,a.fn.init=function c(c,d){return d&&d instanceof p&&!(d instanceof a)&&(d=a(d)),p.fn.init.call(this,c,d,b)},a.fn.init.prototype=a.fn;var b=a(e);return a}}();var bH,bI,bJ,bK=/alpha\([^)]*\)/i,bL=/opacity=([^)]*)/,bM=/^(top|right|bottom|left)$/,bN=/^(none|table(?!-c[ea]).+)/,bO=/^margin/,bP=new RegExp("^("+q+")(.*)$","i"),bQ=new RegExp("^("+q+")(?!px)[a-z%]+$","i"),bR=new RegExp("^([-+])=("+q+")","i"),bS={},bT={position:"absolute",visibility:"hidden",display:"block"},bU={letterSpacing:0,fontWeight:400},bV=["Top","Right","Bottom","Left"],bW=["Webkit","O","Moz","ms"],bX=p.fn.toggle;p.fn.extend({css:function(a,c){return p.access(this,function(a,c,d){return d!==b?p.style(a,c,d):p.css(a,c)},a,c,arguments.length>1)},show:function(){return b$(this,!0)},hide:function(){return b$(this)},toggle:function(a,b){var c=typeof a=="boolean";return p.isFunction(a)&&p.isFunction(b)?bX.apply(this,arguments):this.each(function(){(c?a:bZ(this))?p(this).show():p(this).hide()})}}),p.extend({cssHooks:{opacity:{get:function(a,b){if(b){var c=bH(a,"opacity");return c===""?"1":c}}}},cssNumber:{fillOpacity:!0,fontWeight:!0,lineHeight:!0,opacity:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{"float":p.support.cssFloat?"cssFloat":"styleFloat"},style:function(a,c,d,e){if(!a||a.nodeType===3||a.nodeType===8||!a.style)return;var f,g,h,i=p.camelCase(c),j=a.style;c=p.cssProps[i]||(p.cssProps[i]=bY(j,i)),h=p.cssHooks[c]||p.cssHooks[i];if(d===b)return h&&"get"in h&&(f=h.get(a,!1,e))!==b?f:j[c];g=typeof d,g==="string"&&(f=bR.exec(d))&&(d=(f[1]+1)*f[2]+parseFloat(p.css(a,c)),g="number");if(d==null||g==="number"&&isNaN(d))return;g==="number"&&!p.cssNumber[i]&&(d+="px");if(!h||!("set"in h)||(d=h.set(a,d,e))!==b)try{j[c]=d}catch(k){}},css:function(a,c,d,e){var f,g,h,i=p.camelCase(c);return c=p.cssProps[i]||(p.cssProps[i]=bY(a.style,i)),h=p.cssHooks[c]||p.cssHooks[i],h&&"get"in h&&(f=h.get(a,!0,e)),f===b&&(f=bH(a,c)),f==="normal"&&c in bU&&(f=bU[c]),d||e!==b?(g=parseFloat(f),d||p.isNumeric(g)?g||0:f):f},swap:function(a,b,c){var d,e,f={};for(e in b)f[e]=a.style[e],a.style[e]=b[e];d=c.call(a);for(e in b)a.style[e]=f[e];return d}}),a.getComputedStyle?bH=function(b,c){var d,e,f,g,h=a.getComputedStyle(b,null),i=b.style;return h&&(d=h[c],d===""&&!p.contains(b.ownerDocument,b)&&(d=p.style(b,c)),bQ.test(d)&&bO.test(c)&&(e=i.width,f=i.minWidth,g=i.maxWidth,i.minWidth=i.maxWidth=i.width=d,d=h.width,i.width=e,i.minWidth=f,i.maxWidth=g)),d}:e.documentElement.currentStyle&&(bH=function(a,b){var c,d,e=a.currentStyle&&a.currentStyle[b],f=a.style;return e==null&&f&&f[b]&&(e=f[b]),bQ.test(e)&&!bM.test(b)&&(c=f.left,d=a.runtimeStyle&&a.runtimeStyle.left,d&&(a.runtimeStyle.left=a.currentStyle.left),f.left=b==="fontSize"?"1em":e,e=f.pixelLeft+"px",f.left=c,d&&(a.runtimeStyle.left=d)),e===""?"auto":e}),p.each(["height","width"],function(a,b){p.cssHooks[b]={get:function(a,c,d){if(c)return a.offsetWidth===0&&bN.test(bH(a,"display"))?p.swap(a,bT,function(){return cb(a,b,d)}):cb(a,b,d)},set:function(a,c,d){return b_(a,c,d?ca(a,b,d,p.support.boxSizing&&p.css(a,"boxSizing")==="border-box"):0)}}}),p.support.opacity||(p.cssHooks.opacity={get:function(a,b){return bL.test((b&&a.currentStyle?a.currentStyle.filter:a.style.filter)||"")?.01*parseFloat(RegExp.$1)+"":b?"1":""},set:function(a,b){var c=a.style,d=a.currentStyle,e=p.isNumeric(b)?"alpha(opacity="+b*100+")":"",f=d&&d.filter||c.filter||"";c.zoom=1;if(b>=1&&p.trim(f.replace(bK,""))===""&&c.removeAttribute){c.removeAttribute("filter");if(d&&!d.filter)return}c.filter=bK.test(f)?f.replace(bK,e):f+" "+e}}),p(function(){p.support.reliableMarginRight||(p.cssHooks.marginRight={get:function(a,b){return p.swap(a,{display:"inline-block"},function(){if(b)return bH(a,"marginRight")})}}),!p.support.pixelPosition&&p.fn.position&&p.each(["top","left"],function(a,b){p.cssHooks[b]={get:function(a,c){if(c){var d=bH(a,b);return bQ.test(d)?p(a).position()[b]+"px":d}}}})}),p.expr&&p.expr.filters&&(p.expr.filters.hidden=function(a){return a.offsetWidth===0&&a.offsetHeight===0||!p.support.reliableHiddenOffsets&&(a.style&&a.style.display||bH(a,"display"))==="none"},p.expr.filters.visible=function(a){return!p.expr.filters.hidden(a)}),p.each({margin:"",padding:"",border:"Width"},function(a,b){p.cssHooks[a+b]={expand:function(c){var d,e=typeof c=="string"?c.split(" "):[c],f={};for(d=0;d<4;d++)f[a+bV[d]+b]=e[d]||e[d-2]||e[0];return f}},bO.test(a)||(p.cssHooks[a+b].set=b_)});var cd=/%20/g,ce=/\[\]$/,cf=/\r?\n/g,cg=/^(?:color|date|datetime|datetime-local|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i,ch=/^(?:select|textarea)/i;p.fn.extend({serialize:function(){return p.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?p.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&&(this.checked||ch.test(this.nodeName)||cg.test(this.type))}).map(function(a,b){var c=p(this).val();return c==null?null:p.isArray(c)?p.map(c,function(a,c){return{name:b.name,value:a.replace(cf,"\r\n")}}):{name:b.name,value:c.replace(cf,"\r\n")}}).get()}}),p.param=function(a,c){var d,e=[],f=function(a,b){b=p.isFunction(b)?b():b==null?"":b,e[e.length]=encodeURIComponent(a)+"="+encodeURIComponent(b)};c===b&&(c=p.ajaxSettings&&p.ajaxSettings.traditional);if(p.isArray(a)||a.jquery&&!p.isPlainObject(a))p.each(a,function(){f(this.name,this.value)});else for(d in a)ci(d,a[d],c,f);return e.join("&").replace(cd,"+")};var cj,ck,cl=/#.*$/,cm=/^(.*?):[ \t]*([^\r\n]*)\r?$/mg,cn=/^(?:about|app|app\-storage|.+\-extension|file|res|widget):$/,co=/^(?:GET|HEAD)$/,cp=/^\/\//,cq=/\?/,cr=/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi,cs=/([?&])_=[^&]*/,ct=/^([\w\+\.\-]+:)(?:\/\/([^\/?#:]*)(?::(\d+)|)|)/,cu=p.fn.load,cv={},cw={},cx=["*/"]+["*"];try{ck=f.href}catch(cy){ck=e.createElement("a"),ck.href="",ck=ck.href}cj=ct.exec(ck.toLowerCase())||[],p.fn.load=function(a,c,d){if(typeof a!="string"&&cu)return cu.apply(this,arguments);if(!this.length)return this;var e,f,g,h=this,i=a.indexOf(" ");return i>=0&&(e=a.slice(i,a.length),a=a.slice(0,i)),p.isFunction(c)?(d=c,c=b):c&&typeof c=="object"&&(f="POST"),p.ajax({url:a,type:f,dataType:"html",data:c,complete:function(a,b){d&&h.each(d,g||[a.responseText,b,a])}}).done(function(a){g=arguments,h.html(e?p("<div>").append(a.replace(cr,"")).find(e):a)}),this},p.each("ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split(" "),function(a,b){p.fn[b]=function(a){return this.on(b,a)}}),p.each(["get","post"],function(a,c){p[c]=function(a,d,e,f){return p.isFunction(d)&&(f=f||e,e=d,d=b),p.ajax({type:c,url:a,data:d,success:e,dataType:f})}}),p.extend({getScript:function(a,c){return p.get(a,b,c,"script")},getJSON:function(a,b,c){return p.get(a,b,c,"json")},ajaxSetup:function(a,b){return b?cB(a,p.ajaxSettings):(b=a,a=p.ajaxSettings),cB(a,b),a},ajaxSettings:{url:ck,isLocal:cn.test(cj[1]),global:!0,type:"GET",contentType:"application/x-www-form-urlencoded; charset=UTF-8",processData:!0,async:!0,accepts:{xml:"application/xml, text/xml",html:"text/html",text:"text/plain",json:"application/json, text/javascript","*":cx},contents:{xml:/xml/,html:/html/,json:/json/},responseFields:{xml:"responseXML",text:"responseText"},converters:{"* text":a.String,"text html":!0,"text json":p.parseJSON,"text xml":p.parseXML},flatOptions:{context:!0,url:!0}},ajaxPrefilter:cz(cv),ajaxTransport:cz(cw),ajax:function(a,c){function y(a,c,f,i){var k,s,t,u,w,y=c;if(v===2)return;v=2,h&&clearTimeout(h),g=b,e=i||"",x.readyState=a>0?4:0,f&&(u=cC(l,x,f));if(a>=200&&a<300||a===304)l.ifModified&&(w=x.getResponseHeader("Last-Modified"),w&&(p.lastModified[d]=w),w=x.getResponseHeader("Etag"),w&&(p.etag[d]=w)),a===304?(y="notmodified",k=!0):(k=cD(l,u),y=k.state,s=k.data,t=k.error,k=!t);else{t=y;if(!y||a)y="error",a<0&&(a=0)}x.status=a,x.statusText=(c||y)+"",k?o.resolveWith(m,[s,y,x]):o.rejectWith(m,[x,y,t]),x.statusCode(r),r=b,j&&n.trigger("ajax"+(k?"Success":"Error"),[x,l,k?s:t]),q.fireWith(m,[x,y]),j&&(n.trigger("ajaxComplete",[x,l]),--p.active||p.event.trigger("ajaxStop"))}typeof a=="object"&&(c=a,a=b),c=c||{};var d,e,f,g,h,i,j,k,l=p.ajaxSetup({},c),m=l.context||l,n=m!==l&&(m.nodeType||m instanceof p)?p(m):p.event,o=p.Deferred(),q=p.Callbacks("once memory"),r=l.statusCode||{},t={},u={},v=0,w="canceled",x={readyState:0,setRequestHeader:function(a,b){if(!v){var c=a.toLowerCase();a=u[c]=u[c]||a,t[a]=b}return this},getAllResponseHeaders:function(){return v===2?e:null},getResponseHeader:function(a){var c;if(v===2){if(!f){f={};while(c=cm.exec(e))f[c[1].toLowerCase()]=c[2]}c=f[a.toLowerCase()]}return c===b?null:c},overrideMimeType:function(a){return v||(l.mimeType=a),this},abort:function(a){return a=a||w,g&&g.abort(a),y(0,a),this}};o.promise(x),x.success=x.done,x.error=x.fail,x.complete=q.add,x.statusCode=function(a){if(a){var b;if(v<2)for(b in a)r[b]=[r[b],a[b]];else b=a[x.status],x.always(b)}return this},l.url=((a||l.url)+"").replace(cl,"").replace(cp,cj[1]+"//"),l.dataTypes=p.trim(l.dataType||"*").toLowerCase().split(s),l.crossDomain==null&&(i=ct.exec(l.url.toLowerCase())||!1,l.crossDomain=i&&i.join(":")+(i[3]?"":i[1]==="http:"?80:443)!==cj.join(":")+(cj[3]?"":cj[1]==="http:"?80:443)),l.data&&l.processData&&typeof l.data!="string"&&(l.data=p.param(l.data,l.traditional)),cA(cv,l,c,x);if(v===2)return x;j=l.global,l.type=l.type.toUpperCase(),l.hasContent=!co.test(l.type),j&&p.active++===0&&p.event.trigger("ajaxStart");if(!l.hasContent){l.data&&(l.url+=(cq.test(l.url)?"&":"?")+l.data,delete l.data),d=l.url;if(l.cache===!1){var z=p.now(),A=l.url.replace(cs,"$1_="+z);l.url=A+(A===l.url?(cq.test(l.url)?"&":"?")+"_="+z:"")}}(l.data&&l.hasContent&&l.contentType!==!1||c.contentType)&&x.setRequestHeader("Content-Type",l.contentType),l.ifModified&&(d=d||l.url,p.lastModified[d]&&x.setRequestHeader("If-Modified-Since",p.lastModified[d]),p.etag[d]&&x.setRequestHeader("If-None-Match",p.etag[d])),x.setRequestHeader("Accept",l.dataTypes[0]&&l.accepts[l.dataTypes[0]]?l.accepts[l.dataTypes[0]]+(l.dataTypes[0]!=="*"?", "+cx+"; q=0.01":""):l.accepts["*"]);for(k in l.headers)x.setRequestHeader(k,l.headers[k]);if(!l.beforeSend||l.beforeSend.call(m,x,l)!==!1&&v!==2){w="abort";for(k in{success:1,error:1,complete:1})x[k](l[k]);g=cA(cw,l,c,x);if(!g)y(-1,"No Transport");else{x.readyState=1,j&&n.trigger("ajaxSend",[x,l]),l.async&&l.timeout>0&&(h=setTimeout(function(){x.abort("timeout")},l.timeout));try{v=1,g.send(t,y)}catch(B){if(v<2)y(-1,B);else throw B}}return x}return x.abort()},active:0,lastModified:{},etag:{}});var cE=[],cF=/\?/,cG=/(=)\?(?=&|$)|\?\?/,cH=p.now();p.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var a=cE.pop()||p.expando+"_"+cH++;return this[a]=!0,a}}),p.ajaxPrefilter("json jsonp",function(c,d,e){var f,g,h,i=c.data,j=c.url,k=c.jsonp!==!1,l=k&&cG.test(j),m=k&&!l&&typeof i=="string"&&!(c.contentType||"").indexOf("application/x-www-form-urlencoded")&&cG.test(i);if(c.dataTypes[0]==="jsonp"||l||m)return f=c.jsonpCallback=p.isFunction(c.jsonpCallback)?c.jsonpCallback():c.jsonpCallback,g=a[f],l?c.url=j.replace(cG,"$1"+f):m?c.data=i.replace(cG,"$1"+f):k&&(c.url+=(cF.test(j)?"&":"?")+c.jsonp+"="+f),c.converters["script json"]=function(){return h||p.error(f+" was not called"),h[0]},c.dataTypes[0]="json",a[f]=function(){h=arguments},e.always(function(){a[f]=g,c[f]&&(c.jsonpCallback=d.jsonpCallback,cE.push(f)),h&&p.isFunction(g)&&g(h[0]),h=g=b}),"script"}),p.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/javascript|ecmascript/},converters:{"text script":function(a){return p.globalEval(a),a}}}),p.ajaxPrefilter("script",function(a){a.cache===b&&(a.cache=!1),a.crossDomain&&(a.type="GET",a.global=!1)}),p.ajaxTransport("script",function(a){if(a.crossDomain){var c,d=e.head||e.getElementsByTagName("head")[0]||e.documentElement;return{send:function(f,g){c=e.createElement("script"),c.async="async",a.scriptCharset&&(c.charset=a.scriptCharset),c.src=a.url,c.onload=c.onreadystatechange=function(a,e){if(e||!c.readyState||/loaded|complete/.test(c.readyState))c.onload=c.onreadystatechange=null,d&&c.parentNode&&d.removeChild(c),c=b,e||g(200,"success")},d.insertBefore(c,d.firstChild)},abort:function(){c&&c.onload(0,1)}}}});var cI,cJ=a.ActiveXObject?function(){for(var a in cI)cI[a](0,1)}:!1,cK=0;p.ajaxSettings.xhr=a.ActiveXObject?function(){return!this.isLocal&&cL()||cM()}:cL,function(a){p.extend(p.support,{ajax:!!a,cors:!!a&&"withCredentials"in a})}(p.ajaxSettings.xhr()),p.support.ajax&&p.ajaxTransport(function(c){if(!c.crossDomain||p.support.cors){var d;return{send:function(e,f){var g,h,i=c.xhr();c.username?i.open(c.type,c.url,c.async,c.username,c.password):i.open(c.type,c.url,c.async);if(c.xhrFields)for(h in c.xhrFields)i[h]=c.xhrFields[h];c.mimeType&&i.overrideMimeType&&i.overrideMimeType(c.mimeType),!c.crossDomain&&!e["X-Requested-With"]&&(e["X-Requested-With"]="XMLHttpRequest");try{for(h in e)i.setRequestHeader(h,e[h])}catch(j){}i.send(c.hasContent&&c.data||null),d=function(a,e){var h,j,k,l,m;try{if(d&&(e||i.readyState===4)){d=b,g&&(i.onreadystatechange=p.noop,cJ&&delete cI[g]);if(e)i.readyState!==4&&i.abort();else{h=i.status,k=i.getAllResponseHeaders(),l={},m=i.responseXML,m&&m.documentElement&&(l.xml=m);try{l.text=i.responseText}catch(a){}try{j=i.statusText}catch(n){j=""}!h&&c.isLocal&&!c.crossDomain?h=l.text?200:404:h===1223&&(h=204)}}}catch(o){e||f(-1,o)}l&&f(h,j,l,k)},c.async?i.readyState===4?setTimeout(d,0):(g=++cK,cJ&&(cI||(cI={},p(a).unload(cJ)),cI[g]=d),i.onreadystatechange=d):d()},abort:function(){d&&d(0,1)}}}});var cN,cO,cP=/^(?:toggle|show|hide)$/,cQ=new RegExp("^(?:([-+])=|)("+q+")([a-z%]*)$","i"),cR=/queueHooks$/,cS=[cY],cT={"*":[function(a,b){var c,d,e=this.createTween(a,b),f=cQ.exec(b),g=e.cur(),h=+g||0,i=1,j=20;if(f){c=+f[2],d=f[3]||(p.cssNumber[a]?"":"px");if(d!=="px"&&h){h=p.css(e.elem,a,!0)||c||1;do i=i||".5",h=h/i,p.style(e.elem,a,h+d);while(i!==(i=e.cur()/g)&&i!==1&&--j)}e.unit=d,e.start=h,e.end=f[1]?h+(f[1]+1)*c:c}return e}]};p.Animation=p.extend(cW,{tweener:function(a,b){p.isFunction(a)?(b=a,a=["*"]):a=a.split(" ");var c,d=0,e=a.length;for(;d<e;d++)c=a[d],cT[c]=cT[c]||[],cT[c].unshift(b)},prefilter:function(a,b){b?cS.unshift(a):cS.push(a)}}),p.Tween=cZ,cZ.prototype={constructor:cZ,init:function(a,b,c,d,e,f){this.elem=a,this.prop=c,this.easing=e||"swing",this.options=b,this.start=this.now=this.cur(),this.end=d,this.unit=f||(p.cssNumber[c]?"":"px")},cur:function(){var a=cZ.propHooks[this.prop];return a&&a.get?a.get(this):cZ.propHooks._default.get(this)},run:function(a){var b,c=cZ.propHooks[this.prop];return this.options.duration?this.pos=b=p.easing[this.easing](a,this.options.duration*a,0,1,this.options.duration):this.pos=b=a,this.now=(this.end-this.start)*b+this.start,this.options.step&&this.options.step.call(this.elem,this.now,this),c&&c.set?c.set(this):cZ.propHooks._default.set(this),this}},cZ.prototype.init.prototype=cZ.prototype,cZ.propHooks={_default:{get:function(a){var b;return a.elem[a.prop]==null||!!a.elem.style&&a.elem.style[a.prop]!=null?(b=p.css(a.elem,a.prop,!1,""),!b||b==="auto"?0:b):a.elem[a.prop]},set:function(a){p.fx.step[a.prop]?p.fx.step[a.prop](a):a.elem.style&&(a.elem.style[p.cssProps[a.prop]]!=null||p.cssHooks[a.prop])?p.style(a.elem,a.prop,a.now+a.unit):a.elem[a.prop]=a.now}}},cZ.propHooks.scrollTop=cZ.propHooks.scrollLeft={set:function(a){a.elem.nodeType&&a.elem.parentNode&&(a.elem[a.prop]=a.now)}},p.each(["toggle","show","hide"],function(a,b){var c=p.fn[b];p.fn[b]=function(d,e,f){return d==null||typeof d=="boolean"||!a&&p.isFunction(d)&&p.isFunction(e)?c.apply(this,arguments):this.animate(c$(b,!0),d,e,f)}}),p.fn.extend({fadeTo:function(a,b,c,d){return this.filter(bZ).css("opacity",0).show().end().animate({opacity:b},a,c,d)},animate:function(a,b,c,d){var e=p.isEmptyObject(a),f=p.speed(b,c,d),g=function(){var b=cW(this,p.extend({},a),f);e&&b.stop(!0)};return e||f.queue===!1?this.each(g):this.queue(f.queue,g)},stop:function(a,c,d){var e=function(a){var b=a.stop;delete a.stop,b(d)};return typeof a!="string"&&(d=c,c=a,a=b),c&&a!==!1&&this.queue(a||"fx",[]),this.each(function(){var b=!0,c=a!=null&&a+"queueHooks",f=p.timers,g=p._data(this);if(c)g[c]&&g[c].stop&&e(g[c]);else for(c in g)g[c]&&g[c].stop&&cR.test(c)&&e(g[c]);for(c=f.length;c--;)f[c].elem===this&&(a==null||f[c].queue===a)&&(f[c].anim.stop(d),b=!1,f.splice(c,1));(b||!d)&&p.dequeue(this,a)})}}),p.each({slideDown:c$("show"),slideUp:c$("hide"),slideToggle:c$("toggle"),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"},fadeToggle:{opacity:"toggle"}},function(a,b){p.fn[a]=function(a,c,d){return this.animate(b,a,c,d)}}),p.speed=function(a,b,c){var d=a&&typeof a=="object"?p.extend({},a):{complete:c||!c&&b||p.isFunction(a)&&a,duration:a,easing:c&&b||b&&!p.isFunction(b)&&b};d.duration=p.fx.off?0:typeof d.duration=="number"?d.duration:d.duration in p.fx.speeds?p.fx.speeds[d.duration]:p.fx.speeds._default;if(d.queue==null||d.queue===!0)d.queue="fx";return d.old=d.complete,d.complete=function(){p.isFunction(d.old)&&d.old.call(this),d.queue&&p.dequeue(this,d.queue)},d},p.easing={linear:function(a){return a},swing:function(a){return.5-Math.cos(a*Math.PI)/2}},p.timers=[],p.fx=cZ.prototype.init,p.fx.tick=function(){var a,b=p.timers,c=0;for(;c<b.length;c++)a=b[c],!a()&&b[c]===a&&b.splice(c--,1);b.length||p.fx.stop()},p.fx.timer=function(a){a()&&p.timers.push(a)&&!cO&&(cO=setInterval(p.fx.tick,p.fx.interval))},p.fx.interval=13,p.fx.stop=function(){clearInterval(cO),cO=null},p.fx.speeds={slow:600,fast:200,_default:400},p.fx.step={},p.expr&&p.expr.filters&&(p.expr.filters.animated=function(a){return p.grep(p.timers,function(b){return a===b.elem}).length});var c_=/^(?:body|html)$/i;p.fn.offset=function(a){if(arguments.length)return a===b?this:this.each(function(b){p.offset.setOffset(this,a,b)});var c,d,e,f,g,h,i,j={top:0,left:0},k=this[0],l=k&&k.ownerDocument;if(!l)return;return(d=l.body)===k?p.offset.bodyOffset(k):(c=l.documentElement,p.contains(c,k)?(typeof k.getBoundingClientRect!="undefined"&&(j=k.getBoundingClientRect()),e=da(l),f=c.clientTop||d.clientTop||0,g=c.clientLeft||d.clientLeft||0,h=e.pageYOffset||c.scrollTop,i=e.pageXOffset||c.scrollLeft,{top:j.top+h-f,left:j.left+i-g}):j)},p.offset={bodyOffset:function(a){var b=a.offsetTop,c=a.offsetLeft;return p.support.doesNotIncludeMarginInBodyOffset&&(b+=parseFloat(p.css(a,"marginTop"))||0,c+=parseFloat(p.css(a,"marginLeft"))||0),{top:b,left:c}},setOffset:function(a,b,c){var d=p.css(a,"position");d==="static"&&(a.style.position="relative");var e=p(a),f=e.offset(),g=p.css(a,"top"),h=p.css(a,"left"),i=(d==="absolute"||d==="fixed")&&p.inArray("auto",[g,h])>-1,j={},k={},l,m;i?(k=e.position(),l=k.top,m=k.left):(l=parseFloat(g)||0,m=parseFloat(h)||0),p.isFunction(b)&&(b=b.call(a,c,f)),b.top!=null&&(j.top=b.top-f.top+l),b.left!=null&&(j.left=b.left-f.left+m),"using"in b?b.using.call(a,j):e.css(j)}},p.fn.extend({position:function(){if(!this[0])return;var a=this[0],b=this.offsetParent(),c=this.offset(),d=c_.test(b[0].nodeName)?{top:0,left:0}:b.offset();return c.top-=parseFloat(p.css(a,"marginTop"))||0,c.left-=parseFloat(p.css(a,"marginLeft"))||0,d.top+=parseFloat(p.css(b[0],"borderTopWidth"))||0,d.left+=parseFloat(p.css(b[0],"borderLeftWidth"))||0,{top:c.top-d.top,left:c.left-d.left}},offsetParent:function(){return this.map(function(){var a=this.offsetParent||e.body;while(a&&!c_.test(a.nodeName)&&p.css(a,"position")==="static")a=a.offsetParent;return a||e.body})}}),p.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(a,c){var d=/Y/.test(c);p.fn[a]=function(e){return p.access(this,function(a,e,f){var g=da(a);if(f===b)return g?c in g?g[c]:g.document.documentElement[e]:a[e];g?g.scrollTo(d?p(g).scrollLeft():f,d?f:p(g).scrollTop()):a[e]=f},a,e,arguments.length,null)}}),p.each({Height:"height",Width:"width"},function(a,c){p.each({padding:"inner"+a,content:c,"":"outer"+a},function(d,e){p.fn[e]=function(e,f){var g=arguments.length&&(d||typeof e!="boolean"),h=d||(e===!0||f===!0?"margin":"border");return p.access(this,function(c,d,e){var f;return p.isWindow(c)?c.document.documentElement["client"+a]:c.nodeType===9?(f=c.documentElement,Math.max(c.body["scroll"+a],f["scroll"+a],c.body["offset"+a],f["offset"+a],f["client"+a])):e===b?p.css(c,d,e,h):p.style(c,d,e,h)},c,g?e:b,g,null)}})}),a.jQuery=a.$=p,typeof define=="function"&&define.amd&&define.amd.jQuery&&define("jquery",[],function(){return p})})(window);`,
+
+ "jquery.treeview.css": `/* https://github.com/jzaefferer/jquery-treeview/blob/master/jquery.treeview.css */
+/* License: MIT. */
+.treeview, .treeview ul {
+ padding: 0;
+ margin: 0;
+ list-style: none;
+}
+
+.treeview ul {
+ background-color: white;
+ margin-top: 4px;
+}
+
+.treeview .hitarea {
+ background: url(images/treeview-default.gif) -64px -25px no-repeat;
+ height: 16px;
+ width: 16px;
+ margin-left: -16px;
+ float: left;
+ cursor: pointer;
+}
+/* fix for IE6 */
+* html .hitarea {
+ display: inline;
+ float:none;
+}
+
+.treeview li {
+ margin: 0;
+ padding: 3px 0pt 3px 16px;
+}
+
+.treeview a.selected {
+ background-color: #eee;
+}
+
+#treecontrol { margin: 1em 0; display: none; }
+
+.treeview .hover { color: red; cursor: pointer; }
+
+.treeview li { background: url(images/treeview-default-line.gif) 0 0 no-repeat; }
+.treeview li.collapsable, .treeview li.expandable { background-position: 0 -176px; }
+
+.treeview .expandable-hitarea { background-position: -80px -3px; }
+
+.treeview li.last { background-position: 0 -1766px }
+.treeview li.lastCollapsable, .treeview li.lastExpandable { background-image: url(images/treeview-default.gif); }
+.treeview li.lastCollapsable { background-position: 0 -111px }
+.treeview li.lastExpandable { background-position: -32px -67px }
+
+.treeview div.lastCollapsable-hitarea, .treeview div.lastExpandable-hitarea { background-position: 0; }
+
+.treeview-red li { background-image: url(images/treeview-red-line.gif); }
+.treeview-red .hitarea, .treeview-red li.lastCollapsable, .treeview-red li.lastExpandable { background-image: url(images/treeview-red.gif); }
+
+.treeview-black li { background-image: url(images/treeview-black-line.gif); }
+.treeview-black .hitarea, .treeview-black li.lastCollapsable, .treeview-black li.lastExpandable { background-image: url(images/treeview-black.gif); }
+
+.treeview-gray li { background-image: url(images/treeview-gray-line.gif); }
+.treeview-gray .hitarea, .treeview-gray li.lastCollapsable, .treeview-gray li.lastExpandable { background-image: url(images/treeview-gray.gif); }
+
+.treeview-famfamfam li { background-image: url(images/treeview-famfamfam-line.gif); }
+.treeview-famfamfam .hitarea, .treeview-famfamfam li.lastCollapsable, .treeview-famfamfam li.lastExpandable { background-image: url(images/treeview-famfamfam.gif); }
+
+.treeview .placeholder {
+ background: url(images/ajax-loader.gif) 0 0 no-repeat;
+ height: 16px;
+ width: 16px;
+ display: block;
+}
+
+.filetree li { padding: 3px 0 2px 16px; }
+.filetree span.folder, .filetree span.file { padding: 1px 0 1px 16px; display: block; }
+.filetree span.folder { background: url(images/folder.gif) 0 0 no-repeat; }
+.filetree li.expandable span.folder { background: url(images/folder-closed.gif) 0 0 no-repeat; }
+.filetree span.file { background: url(images/file.gif) 0 0 no-repeat; }
+`,
+
+ "jquery.treeview.edit.js": `/* https://github.com/jzaefferer/jquery-treeview/blob/master/jquery.treeview.edit.js */
+/* License: MIT. */
+(function($) {
+ var CLASSES = $.treeview.classes;
+ var proxied = $.fn.treeview;
+ $.fn.treeview = function(settings) {
+ settings = $.extend({}, settings);
+ if (settings.add) {
+ return this.trigger("add", [settings.add]);
+ }
+ if (settings.remove) {
+ return this.trigger("remove", [settings.remove]);
+ }
+ return proxied.apply(this, arguments).bind("add", function(event, branches) {
+ $(branches).prev()
+ .removeClass(CLASSES.last)
+ .removeClass(CLASSES.lastCollapsable)
+ .removeClass(CLASSES.lastExpandable)
+ .find(">.hitarea")
+ .removeClass(CLASSES.lastCollapsableHitarea)
+ .removeClass(CLASSES.lastExpandableHitarea);
+ $(branches).find("li").andSelf().prepareBranches(settings).applyClasses(settings, $(this).data("toggler"));
+ }).bind("remove", function(event, branches) {
+ var prev = $(branches).prev();
+ var parent = $(branches).parent();
+ $(branches).remove();
+ prev.filter(":last-child").addClass(CLASSES.last)
+ .filter("." + CLASSES.expandable).replaceClass(CLASSES.last, CLASSES.lastExpandable).end()
+ .find(">.hitarea").replaceClass(CLASSES.expandableHitarea, CLASSES.lastExpandableHitarea).end()
+ .filter("." + CLASSES.collapsable).replaceClass(CLASSES.last, CLASSES.lastCollapsable).end()
+ .find(">.hitarea").replaceClass(CLASSES.collapsableHitarea, CLASSES.lastCollapsableHitarea);
+ if (parent.is(":not(:has(>))") && parent[0] != this) {
+ parent.parent().removeClass(CLASSES.collapsable).removeClass(CLASSES.expandable)
+ parent.siblings(".hitarea").andSelf().remove();
+ }
+ });
+ };
+
+})(jQuery);
+`,
+
+ "jquery.treeview.js": `/*
+ * Treeview 1.4.1 - jQuery plugin to hide and show branches of a tree
+ *
+ * http://bassistance.de/jquery-plugins/jquery-plugin-treeview/
+ * http://docs.jquery.com/Plugins/Treeview
+ *
+ * Copyright (c) 2007 Jörn Zaefferer
+ *
+ * Dual licensed under the MIT and GPL licenses:
+ * http://www.opensource.org/licenses/mit-license.php
+ * http://www.gnu.org/licenses/gpl.html
+ *
+ * Revision: $Id: jquery.treeview.js 5759 2008-07-01 07:50:28Z joern.zaefferer $
+ *
+ */
+
+;(function($) {
+
+ // TODO rewrite as a widget, removing all the extra plugins
+ $.extend($.fn, {
+ swapClass: function(c1, c2) {
+ var c1Elements = this.filter('.' + c1);
+ this.filter('.' + c2).removeClass(c2).addClass(c1);
+ c1Elements.removeClass(c1).addClass(c2);
+ return this;
+ },
+ replaceClass: function(c1, c2) {
+ return this.filter('.' + c1).removeClass(c1).addClass(c2).end();
+ },
+ hoverClass: function(className) {
+ className = className || "hover";
+ return this.hover(function() {
+ $(this).addClass(className);
+ }, function() {
+ $(this).removeClass(className);
+ });
+ },
+ heightToggle: function(animated, callback) {
+ animated ?
+ this.animate({ height: "toggle" }, animated, callback) :
+ this.each(function(){
+ jQuery(this)[ jQuery(this).is(":hidden") ? "show" : "hide" ]();
+ if(callback)
+ callback.apply(this, arguments);
+ });
+ },
+ heightHide: function(animated, callback) {
+ if (animated) {
+ this.animate({ height: "hide" }, animated, callback);
+ } else {
+ this.hide();
+ if (callback)
+ this.each(callback);
+ }
+ },
+ prepareBranches: function(settings) {
+ if (!settings.prerendered) {
+ // mark last tree items
+ this.filter(":last-child:not(ul)").addClass(CLASSES.last);
+ // collapse whole tree, or only those marked as closed, anyway except those marked as open
+ this.filter((settings.collapsed ? "" : "." + CLASSES.closed) + ":not(." + CLASSES.open + ")").find(">ul").hide();
+ }
+ // return all items with sublists
+ return this.filter(":has(>ul)");
+ },
+ applyClasses: function(settings, toggler) {
+ // TODO use event delegation
+ this.filter(":has(>ul):not(:has(>a))").find(">span").unbind("click.treeview").bind("click.treeview", function(event) {
+ // don't handle click events on children, eg. checkboxes
+ if ( this == event.target )
+ toggler.apply($(this).next());
+ }).add( $("a", this) ).hoverClass();
+
+ if (!settings.prerendered) {
+ // handle closed ones first
+ this.filter(":has(>ul:hidden)")
+ .addClass(CLASSES.expandable)
+ .replaceClass(CLASSES.last, CLASSES.lastExpandable);
+
+ // handle open ones
+ this.not(":has(>ul:hidden)")
+ .addClass(CLASSES.collapsable)
+ .replaceClass(CLASSES.last, CLASSES.lastCollapsable);
+
+ // create hitarea if not present
+ var hitarea = this.find("div." + CLASSES.hitarea);
+ if (!hitarea.length)
+ hitarea = this.prepend("<div class=\"" + CLASSES.hitarea + "\"/>").find("div." + CLASSES.hitarea);
+ hitarea.removeClass().addClass(CLASSES.hitarea).each(function() {
+ var classes = "";
+ $.each($(this).parent().attr("class").split(" "), function() {
+ classes += this + "-hitarea ";
+ });
+ $(this).addClass( classes );
+ })
+ }
+
+ // apply event to hitarea
+ this.find("div." + CLASSES.hitarea).click( toggler );
+ },
+ treeview: function(settings) {
+
+ settings = $.extend({
+ cookieId: "treeview"
+ }, settings);
+
+ if ( settings.toggle ) {
+ var callback = settings.toggle;
+ settings.toggle = function() {
+ return callback.apply($(this).parent()[0], arguments);
+ };
+ }
+
+ // factory for treecontroller
+ function treeController(tree, control) {
+ // factory for click handlers
+ function handler(filter) {
+ return function() {
+ // reuse toggle event handler, applying the elements to toggle
+ // start searching for all hitareas
+ toggler.apply( $("div." + CLASSES.hitarea, tree).filter(function() {
+ // for plain toggle, no filter is provided, otherwise we need to check the parent element
+ return filter ? $(this).parent("." + filter).length : true;
+ }) );
+ return false;
+ };
+ }
+ // click on first element to collapse tree
+ $("a:eq(0)", control).click( handler(CLASSES.collapsable) );
+ // click on second to expand tree
+ $("a:eq(1)", control).click( handler(CLASSES.expandable) );
+ // click on third to toggle tree
+ $("a:eq(2)", control).click( handler() );
+ }
+
+ // handle toggle event
+ function toggler() {
+ $(this)
+ .parent()
+ // swap classes for hitarea
+ .find(">.hitarea")
+ .swapClass( CLASSES.collapsableHitarea, CLASSES.expandableHitarea )
+ .swapClass( CLASSES.lastCollapsableHitarea, CLASSES.lastExpandableHitarea )
+ .end()
+ // swap classes for parent li
+ .swapClass( CLASSES.collapsable, CLASSES.expandable )
+ .swapClass( CLASSES.lastCollapsable, CLASSES.lastExpandable )
+ // find child lists
+ .find( ">ul" )
+ // toggle them
+ .heightToggle( settings.animated, settings.toggle );
+ if ( settings.unique ) {
+ $(this).parent()
+ .siblings()
+ // swap classes for hitarea
+ .find(">.hitarea")
+ .replaceClass( CLASSES.collapsableHitarea, CLASSES.expandableHitarea )
+ .replaceClass( CLASSES.lastCollapsableHitarea, CLASSES.lastExpandableHitarea )
+ .end()
+ .replaceClass( CLASSES.collapsable, CLASSES.expandable )
+ .replaceClass( CLASSES.lastCollapsable, CLASSES.lastExpandable )
+ .find( ">ul" )
+ .heightHide( settings.animated, settings.toggle );
+ }
+ }
+ this.data("toggler", toggler);
+
+ function serialize() {
+ function binary(arg) {
+ return arg ? 1 : 0;
+ }
+ var data = [];
+ branches.each(function(i, e) {
+ data[i] = $(e).is(":has(>ul:visible)") ? 1 : 0;
+ });
+ $.cookie(settings.cookieId, data.join(""), settings.cookieOptions );
+ }
+
+ function deserialize() {
+ var stored = $.cookie(settings.cookieId);
+ if ( stored ) {
+ var data = stored.split("");
+ branches.each(function(i, e) {
+ $(e).find(">ul")[ parseInt(data[i]) ? "show" : "hide" ]();
+ });
+ }
+ }
+
+ // add treeview class to activate styles
+ this.addClass("treeview");
+
+ // prepare branches and find all tree items with child lists
+ var branches = this.find("li").prepareBranches(settings);
+
+ switch(settings.persist) {
+ case "cookie":
+ var toggleCallback = settings.toggle;
+ settings.toggle = function() {
+ serialize();
+ if (toggleCallback) {
+ toggleCallback.apply(this, arguments);
+ }
+ };
+ deserialize();
+ break;
+ case "location":
+ var current = this.find("a").filter(function() {
+ return this.href.toLowerCase() == location.href.toLowerCase();
+ });
+ if ( current.length ) {
+ // TODO update the open/closed classes
+ var items = current.addClass("selected").parents("ul, li").add( current.next() ).show();
+ if (settings.prerendered) {
+ // if prerendered is on, replicate the basic class swapping
+ items.filter("li")
+ .swapClass( CLASSES.collapsable, CLASSES.expandable )
+ .swapClass( CLASSES.lastCollapsable, CLASSES.lastExpandable )
+ .find(">.hitarea")
+ .swapClass( CLASSES.collapsableHitarea, CLASSES.expandableHitarea )
+ .swapClass( CLASSES.lastCollapsableHitarea, CLASSES.lastExpandableHitarea );
+ }
+ }
+ break;
+ }
+
+ branches.applyClasses(settings, toggler);
+
+ // if control option is set, create the treecontroller and show it
+ if ( settings.control ) {
+ treeController(this, settings.control);
+ $(settings.control).show();
+ }
+
+ return this;
+ }
+ });
+
+ // classes used by the plugin
+ // need to be styled via external stylesheet, see first example
+ $.treeview = {};
+ var CLASSES = ($.treeview.classes = {
+ open: "open",
+ closed: "closed",
+ expandable: "expandable",
+ expandableHitarea: "expandable-hitarea",
+ lastExpandableHitarea: "lastExpandable-hitarea",
+ collapsable: "collapsable",
+ collapsableHitarea: "collapsable-hitarea",
+ lastCollapsableHitarea: "lastCollapsable-hitarea",
+ lastCollapsable: "lastCollapsable",
+ lastExpandable: "lastExpandable",
+ last: "last",
+ hitarea: "hitarea"
+ });
+
+})(jQuery);
+`,
+
+ "methodset.html": `<div class="toggle" style="display: none">
+ <div class="collapsed">
+ <p class="exampleHeading toggleButton">▹ <span class="text">Method set</span></p>
+ </div>
+ <div class="expanded">
+ <p class="exampleHeading toggleButton">▾ <span class="text">Method set</span></p>
+ <div style="margin-left: 1in" id='methodset-{{.Index}}'>...</div>
+ </div>
+</div>
+`,
+
+ "opensearch.xml": `<?xml version="1.0" encoding="UTF-8"?>
+<OpenSearchDescription xmlns="http://a9.com/-/spec/opensearch/1.1/">
+ <ShortName>godoc</ShortName>
+ <Description>The Go Programming Language</Description>
+ <Tags>go golang</Tags>
+ <Contact />
+ <Url type="text/html" template="{{.BaseURL}}/search?q={searchTerms}" />
+ <Image height="15" width="16" type="image/x-icon">/favicon.ico</Image>
+ <OutputEncoding>UTF-8</OutputEncoding>
+ <InputEncoding>UTF-8</InputEncoding>
+</OpenSearchDescription>
+`,
+
+ "package.html": `<!--
+ 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.
+-->
+<!--
+ Note: Static (i.e., not template-generated) href and id
+ attributes start with "pkg-" to make it impossible for
+ them to conflict with generated attributes (some of which
+ correspond to Go identifiers).
+-->
+{{with .PDoc}}
+ <script type='text/javascript'>
+ document.ANALYSIS_DATA = {{$.AnalysisData}};
+ document.CALLGRAPH = {{$.CallGraph}};
+ </script>
+
+ {{if $.IsMain}}
+ {{/* command documentation */}}
+ {{comment_html .Doc}}
+ {{else}}
+ {{/* package documentation */}}
+ <div id="short-nav">
+ <dl>
+ <dd><code>import "{{html .ImportPath}}"</code></dd>
+ </dl>
+ <dl>
+ <dd><a href="#pkg-overview" class="overviewLink">Overview</a></dd>
+ <dd><a href="#pkg-index" class="indexLink">Index</a></dd>
+ {{if $.Examples}}
+ <dd><a href="#pkg-examples" class="examplesLink">Examples</a></dd>
+ {{end}}
+ {{if $.Dirs}}
+ <dd><a href="#pkg-subdirectories">Subdirectories</a></dd>
+ {{end}}
+ </dl>
+ </div>
+ <!-- The package's Name is printed as title by the top-level template -->
+ <div id="pkg-overview" class="toggleVisible">
+ <div class="collapsed">
+ <h2 class="toggleButton" title="Click to show Overview section">Overview ▹</h2>
+ </div>
+ <div class="expanded">
+ <h2 class="toggleButton" title="Click to hide Overview section">Overview ▾</h2>
+ {{comment_html .Doc}}
+ </div>
+ </div>
+ {{example_html $ ""}}
+
+ <div id="pkg-index" class="toggleVisible">
+ <div class="collapsed">
+ <h2 class="toggleButton" title="Click to show Index section">Index ▹</h2>
+ </div>
+ <div class="expanded">
+ <h2 class="toggleButton" title="Click to hide Index section">Index ▾</h2>
+
+ <!-- Table of contents for API; must be named manual-nav to turn off auto nav. -->
+ <div id="manual-nav">
+ <dl>
+ {{if .Consts}}
+ <dd><a href="#pkg-constants">Constants</a></dd>
+ {{end}}
+ {{if .Vars}}
+ <dd><a href="#pkg-variables">Variables</a></dd>
+ {{end}}
+ {{range .Funcs}}
+ {{$name_html := html .Name}}
+ <dd><a href="#{{$name_html}}">{{node_html $ .Decl false | sanitize}}</a></dd>
+ {{end}}
+ {{range .Types}}
+ {{$tname_html := html .Name}}
+ <dd><a href="#{{$tname_html}}">type {{$tname_html}}</a></dd>
+ {{range .Funcs}}
+ {{$name_html := html .Name}}
+ <dd> <a href="#{{$name_html}}">{{node_html $ .Decl false | sanitize}}</a></dd>
+ {{end}}
+ {{range .Methods}}
+ {{$name_html := html .Name}}
+ <dd> <a href="#{{$tname_html}}.{{$name_html}}">{{node_html $ .Decl false | sanitize}}</a></dd>
+ {{end}}
+ {{end}}
+ {{if $.Notes}}
+ {{range $marker, $item := $.Notes}}
+ <dd><a href="#pkg-note-{{$marker}}">{{noteTitle $marker | html}}s</a></dd>
+ {{end}}
+ {{end}}
+ </dl>
+ </div><!-- #manual-nav -->
+
+ {{if $.Examples}}
+ <div id="pkg-examples">
+ <h4>Examples</h4>
+ <dl>
+ {{range $.Examples}}
+ <dd><a class="exampleLink" href="#example_{{.Name}}">{{example_name .Name}}</a></dd>
+ {{end}}
+ </dl>
+ </div>
+ {{end}}
+
+ {{with .Filenames}}
+ <h4>Package files</h4>
+ <p>
+ <span style="font-size:90%">
+ {{range .}}
+ <a href="{{.|srcLink|html}}">{{.|filename|html}}</a>
+ {{end}}
+ </span>
+ </p>
+ {{end}}
+ </div><!-- .expanded -->
+ </div><!-- #pkg-index -->
+
+ <div id="pkg-callgraph" class="toggle" style="display: none">
+ <div class="collapsed">
+ <h2 class="toggleButton" title="Click to show Internal Call Graph section">Internal call graph ▹</h2>
+ </div> <!-- .expanded -->
+ <div class="expanded">
+ <h2 class="toggleButton" title="Click to hide Internal Call Graph section">Internal call graph ▾</h2>
+ <p>
+ In the call graph viewer below, each node
+ is a function belonging to this package
+ and its children are the functions it
+ calls—perhaps dynamically.
+ </p>
+ <p>
+ The root nodes are the entry points of the
+ package: functions that may be called from
+ outside the package.
+ There may be non-exported or anonymous
+ functions among them if they are called
+ dynamically from another package.
+ </p>
+ <p>
+ Click a node to visit that function's source code.
+ From there you can visit its callers by
+ clicking its declaring <code>func</code>
+ token.
+ </p>
+ <p>
+ Functions may be omitted if they were
+ determined to be unreachable in the
+ particular programs or tests that were
+ analyzed.
+ </p>
+ <!-- Zero means show all package entry points. -->
+ <ul style="margin-left: 0.5in" id="callgraph-0" class="treeview"></ul>
+ </div>
+ </div> <!-- #pkg-callgraph -->
+
+ {{with .Consts}}
+ <h2 id="pkg-constants">Constants</h2>
+ {{range .}}
+ <pre>{{node_html $ .Decl true}}</pre>
+ {{comment_html .Doc}}
+ {{end}}
+ {{end}}
+ {{with .Vars}}
+ <h2 id="pkg-variables">Variables</h2>
+ {{range .}}
+ <pre>{{node_html $ .Decl true}}</pre>
+ {{comment_html .Doc}}
+ {{end}}
+ {{end}}
+ {{range .Funcs}}
+ {{/* Name is a string - no need for FSet */}}
+ {{$name_html := html .Name}}
+ <h2 id="{{$name_html}}">func <a href="{{posLink_url $ .Decl}}">{{$name_html}}</a></h2>
+ <pre>{{node_html $ .Decl true}}</pre>
+ {{comment_html .Doc}}
+ {{example_html $ .Name}}
+ {{callgraph_html $ "" .Name}}
+
+ {{end}}
+ {{range .Types}}
+ {{$tname := .Name}}
+ {{$tname_html := html .Name}}
+ <h2 id="{{$tname_html}}">type <a href="{{posLink_url $ .Decl}}">{{$tname_html}}</a></h2>
+ <pre>{{node_html $ .Decl true}}</pre>
+ {{comment_html .Doc}}
+
+ {{range .Consts}}
+ <pre>{{node_html $ .Decl true}}</pre>
+ {{comment_html .Doc}}
+ {{end}}
+
+ {{range .Vars}}
+ <pre>{{node_html $ .Decl true}}</pre>
+ {{comment_html .Doc}}
+ {{end}}
+
+ {{example_html $ $tname}}
+ {{implements_html $ $tname}}
+ {{methodset_html $ $tname}}
+
+ {{range .Funcs}}
+ {{$name_html := html .Name}}
+ <h3 id="{{$name_html}}">func <a href="{{posLink_url $ .Decl}}">{{$name_html}}</a></h3>
+ <pre>{{node_html $ .Decl true}}</pre>
+ {{comment_html .Doc}}
+ {{example_html $ .Name}}
+ {{callgraph_html $ "" .Name}}
+ {{end}}
+
+ {{range .Methods}}
+ {{$name_html := html .Name}}
+ <h3 id="{{$tname_html}}.{{$name_html}}">func ({{html .Recv}}) <a href="{{posLink_url $ .Decl}}">{{$name_html}}</a></h3>
+ <pre>{{node_html $ .Decl true}}</pre>
+ {{comment_html .Doc}}
+ {{$name := printf "%s_%s" $tname .Name}}
+ {{example_html $ $name}}
+ {{callgraph_html $ .Recv .Name}}
+ {{end}}
+ {{end}}
+ {{end}}
+
+ {{with $.Notes}}
+ {{range $marker, $content := .}}
+ <h2 id="pkg-note-{{$marker}}">{{noteTitle $marker | html}}s</h2>
+ <ul style="list-style: none; padding: 0;">
+ {{range .}}
+ <li><a href="{{posLink_url $ .}}">☞</a> {{html .Body}}</li>
+ {{end}}
+ </ul>
+ {{end}}
+ {{end}}
+{{end}}
+
+{{with .PAst}}
+ {{range $filename, $ast := .}}
+ <a href="{{$filename|srcLink|html}}">{{$filename|filename|html}}</a>:<pre>{{node_html $ $ast false}}</pre>
+ {{end}}
+{{end}}
+
+{{with .Dirs}}
+ {{/* DirList entries are numbers and strings - no need for FSet */}}
+ {{if $.PDoc}}
+ <h2 id="pkg-subdirectories">Subdirectories</h2>
+ {{end}}
+ {{if eq $.Dirname "/src"}}
+ <div id="manual-nav">
+ <dl>
+ <dt><a href="#stdlib">Standard library</a></dt>
+ <dt><a href="#other">Other packages</a></dt>
+ <dd><a href="#subrepo">Sub-repositories</a></dd>
+ <dd><a href="#community">Community</a></dd>
+ </dl>
+ </div>
+ <h2 id="stdlib">Standard library</h2>
+ <img class="gopher" src="/doc/gopher/pkg.png"/>
+ {{end}}
+
+
+ <div class="pkg-dir">
+ <table>
+ <tr>
+ <th class="pkg-name">Name</th>
+ <th class="pkg-synopsis">Synopsis</th>
+ </tr>
+
+ {{if not (or (eq $.Dirname "/src") (eq $.Dirname "/src/cmd") $.DirFlat)}}
+ <tr>
+ <td colspan="2"><a href="..">..</a></td>
+ </tr>
+ {{end}}
+
+ {{range .List}}
+ {{if $.DirFlat}}
+ {{if .HasPkg}}
+ <tr>
+ <td class="pkg-name">
+ <a href="{{html .Path}}/">{{html .Path}}</a>
+ </td>
+ <td class="pkg-synopsis">
+ {{html .Synopsis}}
+ </td>
+ </tr>
+ {{end}}
+ {{else}}
+ <tr>
+ <td class="pkg-name" style="padding-left: {{multiply .Depth 20}}px;">
+ <a href="{{html .Path}}/">{{html .Name}}</a>
+ </td>
+ <td class="pkg-synopsis">
+ {{html .Synopsis}}
+ </td>
+ </tr>
+ {{end}}
+ {{end}}
+ </table>
+ </div>
+
+
+ {{if eq $.Dirname "/src"}}
+ <h2 id="other">Other packages</h2>
+
+ <h3 id="subrepo">Sub-repositories</h3>
+ <p>
+ These packages are part of the Go Project but outside the main Go tree.
+ They are developed under looser <a href="/doc/go1compat">compatibility requirements</a> than the Go core.
+ Install them with "<a href="/cmd/go/#hdr-Download_and_install_packages_and_dependencies">go get</a>".
+ </p>
+ <ul>
+ <li><a href="//godoc.org/golang.org/x/benchmarks">benchmarks</a> — benchmarks to measure Go as it is developed.</li>
+ <li><a href="//godoc.org/golang.org/x/blog">blog</a> — <a href="//blog.golang.org">blog.golang.org</a>'s implementation.</li>
+ <li><a href="//godoc.org/golang.org/x/build">build</a> — <a href="//build.golang.org">build.golang.org</a>'s implementation.</li>
+ <li><a href="//godoc.org/golang.org/x/crypto">crypto</a> — additional cryptography packages.</li>
+ <li><a href="//godoc.org/golang.org/x/debug">debug</a> — an experimental debugger for Go.</li>
+ <li><a href="//godoc.org/golang.org/x/image">image</a> — additional imaging packages.</li>
+ <li><a href="//godoc.org/golang.org/x/mobile">mobile</a> — experimental support for Go on mobile platforms.</li>
+ <li><a href="//godoc.org/golang.org/x/net">net</a> — additional networking packages.</li>
+ <li><a href="//godoc.org/golang.org/x/sys">sys</a> — packages for making system calls.</li>
+ <li><a href="//godoc.org/golang.org/x/text">text</a> — packages for working with text.</li>
+ <li><a href="//godoc.org/golang.org/x/tools">tools</a> — godoc, goimports, gorename, and other tools.</li>
+ <li><a href="//godoc.org/golang.org/x/tour">tour</a> — <a href="//tour.golang.org">tour.golang.org</a>'s implementation.</li>
+ <li><a href="//godoc.org/golang.org/x/exp">exp</a> — experimental and deprecated packages (handle with care; may change without warning).</li>
+ </ul>
+
+ <h3 id="community">Community</h3>
+ <p>
+ These services can help you find Open Source packages provided by the community.
+ </p>
+ <ul>
+ <li><a href="//godoc.org">GoDoc</a> - a package index and search engine.</li>
+ <li><a href="http://go-search.org">Go Search</a> - a code search engine.</li>
+ <li><a href="/wiki/Projects">Projects at the Go Wiki</a> - a curated list of Go projects.</li>
+ </ul>
+ {{end}}
+{{end}}
+`,
+
+ "package.txt": `{{$info := .}}{{$filtered := .IsFiltered}}{{/*
+
+---------------------------------------
+
+*/}}{{if $filtered}}{{range .PAst}}{{range .Decls}}{{node $info .}}
+
+{{end}}{{end}}{{else}}{{with .PAst}}{{range $filename, $ast := .}}{{$filename}}:
+{{node $ $ast}}{{end}}{{end}}{{end}}{{/*
+
+---------------------------------------
+
+*/}}{{if and $filtered (not (or .PDoc .PAst))}}No match found.
+{{end}}{{with .PDoc}}{{if $.IsMain}}COMMAND DOCUMENTATION
+
+{{comment_text .Doc " " "\t"}}
+{{else}}{{if not $filtered}}PACKAGE DOCUMENTATION
+
+package {{.Name}}
+ import "{{.ImportPath}}"
+
+{{comment_text .Doc " " "\t"}}
+{{example_text $ "" " "}}{{end}}{{/*
+
+---------------------------------------
+
+*/}}{{with .Consts}}{{if not $filtered}}CONSTANTS
+
+{{end}}{{range .}}{{node $ .Decl}}
+{{comment_text .Doc " " "\t"}}
+{{end}}{{end}}{{/*
+
+---------------------------------------
+
+*/}}{{with .Vars}}{{if not $filtered}}VARIABLES
+
+{{end}}{{range .}}{{node $ .Decl}}
+{{comment_text .Doc " " "\t"}}
+{{end}}{{end}}{{/*
+
+---------------------------------------
+
+*/}}{{with .Funcs}}{{if not $filtered}}FUNCTIONS
+
+{{end}}{{range .}}{{node $ .Decl}}
+{{comment_text .Doc " " "\t"}}
+{{example_text $ .Name " "}}{{end}}{{end}}{{/*
+
+---------------------------------------
+
+*/}}{{with .Types}}{{if not $filtered}}TYPES
+
+{{end}}{{range .}}{{$tname := .Name}}{{node $ .Decl}}
+{{comment_text .Doc " " "\t"}}
+{{/*
+
+---------------------------------------
+
+*/}}{{if .Consts}}{{range .Consts}}{{node $ .Decl}}
+{{comment_text .Doc " " "\t"}}
+{{end}}{{end}}{{/*
+
+---------------------------------------
+
+*/}}{{if .Vars}}{{range .Vars}}{{node $ .Decl}}
+{{comment_text .Doc " " "\t"}}
+{{range $name := .Names}}{{example_text $ $name " "}}{{end}}{{end}}{{end}}{{/*
+
+---------------------------------------
+
+*/}}{{if .Funcs}}{{range .Funcs}}{{node $ .Decl}}
+{{comment_text .Doc " " "\t"}}
+{{example_text $ .Name " "}}{{end}}{{end}}{{/*
+
+---------------------------------------
+
+*/}}{{if .Methods}}{{range .Methods}}{{node $ .Decl}}
+{{comment_text .Doc " " "\t"}}
+{{$name := printf "%s_%s" $tname .Name}}{{example_text $ $name " "}}{{end}}{{end}}{{/*
+
+---------------------------------------
+
+*/}}{{end}}{{end}}{{/*
+
+---------------------------------------
+
+*/}}{{if and $filtered (not (or .Consts (or .Vars (or .Funcs .Types))))}}No match found.
+{{end}}{{/*
+
+---------------------------------------
+
+*/}}{{end}}{{/*
+
+---------------------------------------
+
+*/}}{{with $.Notes}}
+{{range $marker, $content := .}}
+{{$marker}}S
+
+{{range $content}}{{comment_text .Body " " "\t"}}
+{{end}}{{end}}{{end}}{{end}}{{/*
+
+---------------------------------------
+
+*/}}{{if not $filtered}}{{with .Dirs}}SUBDIRECTORIES
+{{if $.DirFlat}}{{range .List}}{{if .HasPkg}}
+ {{.Path}}{{end}}{{end}}
+{{else}}{{range .List}}
+ {{repeat ` + "`" + `. ` + "`" + ` .Depth}}{{.Name}}{{end}}
+{{end}}{{end}}{{/*
+
+---------------------------------------
+
+*/}}{{end}}{{/*
+Make sure there is no newline at the end of this file.
+perl -i -pe 'chomp if eof' package.txt
+*/}}
+`,
+
+ "play.js": `// 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.
+
+function initPlayground(transport) {
+ "use strict";
+
+ function text(node) {
+ var s = "";
+ for (var i = 0; i < node.childNodes.length; i++) {
+ var n = node.childNodes[i];
+ if (n.nodeType === 1) {
+ if (n.tagName === "BUTTON") continue
+ if (n.tagName === "SPAN" && n.className === "number") continue;
+ if (n.tagName === "DIV" || n.tagName == "BR") {
+ s += "\n";
+ }
+ s += text(n);
+ continue;
+ }
+ if (n.nodeType === 3) {
+ s += n.nodeValue;
+ }
+ }
+ return s.replace("\xA0", " "); // replace non-breaking spaces
+ }
+
+ function init(code) {
+ var output = document.createElement('div');
+ var outpre = document.createElement('pre');
+ var running;
+
+ if ($ && $(output).resizable) {
+ $(output).resizable({
+ handles: "n,w,nw",
+ minHeight: 27,
+ minWidth: 135,
+ maxHeight: 608,
+ maxWidth: 990
+ });
+ }
+
+ function onKill() {
+ if (running) running.Kill();
+ }
+
+ function onRun(e) {
+ onKill();
+ output.style.display = "block";
+ outpre.innerHTML = "";
+ run1.style.display = "none";
+ var options = {Race: e.shiftKey};
+ running = transport.Run(text(code), PlaygroundOutput(outpre), options);
+ }
+
+ function onClose() {
+ onKill();
+ output.style.display = "none";
+ run1.style.display = "inline-block";
+ }
+
+ var run1 = document.createElement('button');
+ run1.innerHTML = 'Run';
+ run1.className = 'run';
+ run1.addEventListener("click", onRun, false);
+ var run2 = document.createElement('button');
+ run2.className = 'run';
+ run2.innerHTML = 'Run';
+ run2.addEventListener("click", onRun, false);
+ var kill = document.createElement('button');
+ kill.className = 'kill';
+ kill.innerHTML = 'Kill';
+ kill.addEventListener("click", onKill, false);
+ var close = document.createElement('button');
+ close.className = 'close';
+ close.innerHTML = 'Close';
+ close.addEventListener("click", onClose, false);
+
+ var button = document.createElement('div');
+ button.classList.add('buttons');
+ button.appendChild(run1);
+ // Hack to simulate insertAfter
+ code.parentNode.insertBefore(button, code.nextSibling);
+
+ var buttons = document.createElement('div');
+ buttons.classList.add('buttons');
+ buttons.appendChild(run2);
+ buttons.appendChild(kill);
+ buttons.appendChild(close);
+
+ output.classList.add('output');
+ output.appendChild(buttons);
+ output.appendChild(outpre);
+ output.style.display = "none";
+ code.parentNode.insertBefore(output, button.nextSibling);
+ }
+
+ var play = document.querySelectorAll('div.playground');
+ for (var i = 0; i < play.length; i++) {
+ init(play[i]);
+ }
+}
+
+`,
+
+ "playground.js": `// 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.
+
+/*
+In the absence of any formal way to specify interfaces in JavaScript,
+here's a skeleton implementation of a playground transport.
+
+ function Transport() {
+ // Set up any transport state (eg, make a websocket connection).
+ return {
+ Run: function(body, output, options) {
+ // Compile and run the program 'body' with 'options'.
+ // Call the 'output' callback to display program output.
+ return {
+ Kill: function() {
+ // Kill the running program.
+ }
+ };
+ }
+ };
+ }
+
+ // The output callback is called multiple times, and each time it is
+ // passed an object of this form.
+ var write = {
+ Kind: 'string', // 'start', 'stdout', 'stderr', 'end'
+ Body: 'string' // content of write or end status message
+ }
+
+ // The first call must be of Kind 'start' with no body.
+ // Subsequent calls may be of Kind 'stdout' or 'stderr'
+ // and must have a non-null Body string.
+ // The final call should be of Kind 'end' with an optional
+ // Body string, signifying a failure ("killed", for example).
+
+ // The output callback must be of this form.
+ // See PlaygroundOutput (below) for an implementation.
+ function outputCallback(write) {
+ }
+*/
+
+function HTTPTransport() {
+ 'use strict';
+
+ // TODO(adg): support stderr
+
+ function playback(output, events) {
+ var timeout;
+ output({Kind: 'start'});
+ function next() {
+ if (!events || events.length === 0) {
+ output({Kind: 'end'});
+ return;
+ }
+ var e = events.shift();
+ if (e.Delay === 0) {
+ output({Kind: 'stdout', Body: e.Message});
+ next();
+ return;
+ }
+ timeout = setTimeout(function() {
+ output({Kind: 'stdout', Body: e.Message});
+ next();
+ }, e.Delay / 1000000);
+ }
+ next();
+ return {
+ Stop: function() {
+ clearTimeout(timeout);
+ }
+ }
+ }
+
+ function error(output, msg) {
+ output({Kind: 'start'});
+ output({Kind: 'stderr', Body: msg});
+ output({Kind: 'end'});
+ }
+
+ var seq = 0;
+ return {
+ Run: function(body, output, options) {
+ seq++;
+ var cur = seq;
+ var playing;
+ $.ajax('/compile', {
+ type: 'POST',
+ data: {'version': 2, 'body': body},
+ dataType: 'json',
+ success: function(data) {
+ if (seq != cur) return;
+ if (!data) return;
+ if (playing != null) playing.Stop();
+ if (data.Errors) {
+ error(output, data.Errors);
+ return;
+ }
+ playing = playback(output, data.Events);
+ },
+ error: function() {
+ error(output, 'Error communicating with remote server.');
+ }
+ });
+ return {
+ Kill: function() {
+ if (playing != null) playing.Stop();
+ output({Kind: 'end', Body: 'killed'});
+ }
+ };
+ }
+ };
+}
+
+function SocketTransport() {
+ 'use strict';
+
+ var id = 0;
+ var outputs = {};
+ var started = {};
+ var websocket = new WebSocket('ws://' + window.location.host + '/socket');
+
+ websocket.onclose = function() {
+ console.log('websocket connection closed');
+ }
+
+ websocket.onmessage = function(e) {
+ var m = JSON.parse(e.data);
+ var output = outputs[m.Id];
+ if (output === null)
+ return;
+ if (!started[m.Id]) {
+ output({Kind: 'start'});
+ started[m.Id] = true;
+ }
+ output({Kind: m.Kind, Body: m.Body});
+ }
+
+ function send(m) {
+ websocket.send(JSON.stringify(m));
+ }
+
+ return {
+ Run: function(body, output, options) {
+ var thisID = id+'';
+ id++;
+ outputs[thisID] = output;
+ send({Id: thisID, Kind: 'run', Body: body, Options: options});
+ return {
+ Kill: function() {
+ send({Id: thisID, Kind: 'kill'});
+ }
+ };
+ }
+ };
+}
+
+function PlaygroundOutput(el) {
+ 'use strict';
+
+ return function(write) {
+ if (write.Kind == 'start') {
+ el.innerHTML = '';
+ return;
+ }
+
+ var cl = 'system';
+ if (write.Kind == 'stdout' || write.Kind == 'stderr')
+ cl = write.Kind;
+
+ var m = write.Body;
+ if (write.Kind == 'end')
+ m = '\nProgram exited' + (m?(': '+m):'.');
+
+ if (m.indexOf('IMAGE:') === 0) {
+ // TODO(adg): buffer all writes before creating image
+ var url = 'data:image/png;base64,' + m.substr(6);
+ var img = document.createElement('img');
+ img.src = url;
+ el.appendChild(img);
+ return;
+ }
+
+ // ^L clears the screen.
+ var s = m.split('\x0c');
+ if (s.length > 1) {
+ el.innerHTML = '';
+ m = s.pop();
+ }
+
+ m = m.replace(/&/g, '&');
+ m = m.replace(/</g, '<');
+ m = m.replace(/>/g, '>');
+
+ var needScroll = (el.scrollTop + el.offsetHeight) == el.scrollHeight;
+
+ var span = document.createElement('span');
+ span.className = cl;
+ span.innerHTML = m;
+ el.appendChild(span);
+
+ if (needScroll)
+ el.scrollTop = el.scrollHeight - el.offsetHeight;
+ }
+}
+
+(function() {
+ function lineHighlight(error) {
+ var regex = /prog.go:([0-9]+)/g;
+ var r = regex.exec(error);
+ while (r) {
+ $(".lines div").eq(r[1]-1).addClass("lineerror");
+ r = regex.exec(error);
+ }
+ }
+ function highlightOutput(wrappedOutput) {
+ return function(write) {
+ if (write.Body) lineHighlight(write.Body);
+ wrappedOutput(write);
+ }
+ }
+ function lineClear() {
+ $(".lineerror").removeClass("lineerror");
+ }
+
+ // opts is an object with these keys
+ // codeEl - code editor element
+ // outputEl - program output element
+ // runEl - run button element
+ // fmtEl - fmt button element (optional)
+ // fmtImportEl - fmt "imports" checkbox element (optional)
+ // shareEl - share button element (optional)
+ // shareURLEl - share URL text input element (optional)
+ // shareRedirect - base URL to redirect to on share (optional)
+ // toysEl - toys select element (optional)
+ // enableHistory - enable using HTML5 history API (optional)
+ // transport - playground transport to use (default is HTTPTransport)
+ function playground(opts) {
+ var code = $(opts.codeEl);
+ var transport = opts['transport'] || new HTTPTransport();
+ var running;
+
+ // autoindent helpers.
+ function insertTabs(n) {
+ // find the selection start and end
+ var start = code[0].selectionStart;
+ var end = code[0].selectionEnd;
+ // split the textarea content into two, and insert n tabs
+ var v = code[0].value;
+ var u = v.substr(0, start);
+ for (var i=0; i<n; i++) {
+ u += "\t";
+ }
+ u += v.substr(end);
+ // set revised content
+ code[0].value = u;
+ // reset caret position after inserted tabs
+ code[0].selectionStart = start+n;
+ code[0].selectionEnd = start+n;
+ }
+ function autoindent(el) {
+ var curpos = el.selectionStart;
+ var tabs = 0;
+ while (curpos > 0) {
+ curpos--;
+ if (el.value[curpos] == "\t") {
+ tabs++;
+ } else if (tabs > 0 || el.value[curpos] == "\n") {
+ break;
+ }
+ }
+ setTimeout(function() {
+ insertTabs(tabs);
+ }, 1);
+ }
+
+ function keyHandler(e) {
+ if (e.keyCode == 9 && !e.ctrlKey) { // tab (but not ctrl-tab)
+ insertTabs(1);
+ e.preventDefault();
+ return false;
+ }
+ if (e.keyCode == 13) { // enter
+ if (e.shiftKey) { // +shift
+ run();
+ e.preventDefault();
+ return false;
+ } if (e.ctrlKey) { // +control
+ fmt();
+ e.preventDefault();
+ } else {
+ autoindent(e.target);
+ }
+ }
+ return true;
+ }
+ code.unbind('keydown').bind('keydown', keyHandler);
+ var outdiv = $(opts.outputEl).empty();
+ var output = $('<pre/>').appendTo(outdiv);
+
+ function body() {
+ return $(opts.codeEl).val();
+ }
+ function setBody(text) {
+ $(opts.codeEl).val(text);
+ }
+ function origin(href) {
+ return (""+href).split("/").slice(0, 3).join("/");
+ }
+
+ var pushedEmpty = (window.location.pathname == "/");
+ function inputChanged() {
+ if (pushedEmpty) {
+ return;
+ }
+ pushedEmpty = true;
+ $(opts.shareURLEl).hide();
+ window.history.pushState(null, "", "/");
+ }
+ function popState(e) {
+ if (e === null) {
+ return;
+ }
+ if (e && e.state && e.state.code) {
+ setBody(e.state.code);
+ }
+ }
+ var rewriteHistory = false;
+ if (window.history && window.history.pushState && window.addEventListener && opts.enableHistory) {
+ rewriteHistory = true;
+ code[0].addEventListener('input', inputChanged);
+ window.addEventListener('popstate', popState);
+ }
+
+ function setError(error) {
+ if (running) running.Kill();
+ lineClear();
+ lineHighlight(error);
+ output.empty().addClass("error").text(error);
+ }
+ function loading() {
+ lineClear();
+ if (running) running.Kill();
+ output.removeClass("error").text('Waiting for remote server...');
+ }
+ function run() {
+ loading();
+ running = transport.Run(body(), highlightOutput(PlaygroundOutput(output[0])));
+ }
+
+ function fmt() {
+ loading();
+ var data = {"body": body()};
+ if ($(opts.fmtImportEl).is(":checked")) {
+ data["imports"] = "true";
+ }
+ $.ajax("/fmt", {
+ data: data,
+ type: "POST",
+ dataType: "json",
+ success: function(data) {
+ if (data.Error) {
+ setError(data.Error);
+ } else {
+ setBody(data.Body);
+ setError("");
+ }
+ }
+ });
+ }
+
+ $(opts.runEl).click(run);
+ $(opts.fmtEl).click(fmt);
+
+ if (opts.shareEl !== null && (opts.shareURLEl !== null || opts.shareRedirect !== null)) {
+ var shareURL;
+ if (opts.shareURLEl) {
+ shareURL = $(opts.shareURLEl).hide();
+ }
+ var sharing = false;
+ $(opts.shareEl).click(function() {
+ if (sharing) return;
+ sharing = true;
+ var sharingData = body();
+ $.ajax("/share", {
+ processData: false,
+ data: sharingData,
+ type: "POST",
+ complete: function(xhr) {
+ sharing = false;
+ if (xhr.status != 200) {
+ alert("Server error; try again.");
+ return;
+ }
+ if (opts.shareRedirect) {
+ window.location = opts.shareRedirect + xhr.responseText;
+ }
+ if (shareURL) {
+ var path = "/p/" + xhr.responseText;
+ var url = origin(window.location) + path;
+ shareURL.show().val(url).focus().select();
+
+ if (rewriteHistory) {
+ var historyData = {"code": sharingData};
+ window.history.pushState(historyData, "", path);
+ pushedEmpty = false;
+ }
+ }
+ }
+ });
+ });
+ }
+
+ if (opts.toysEl !== null) {
+ $(opts.toysEl).bind('change', function() {
+ var toy = $(this).val();
+ $.ajax("/doc/play/"+toy, {
+ processData: false,
+ type: "GET",
+ complete: function(xhr) {
+ if (xhr.status != 200) {
+ alert("Server error; try again.");
+ return;
+ }
+ setBody(xhr.responseText);
+ }
+ });
+ });
+ }
+ }
+
+ window.playground = playground;
+})();
+`,
+
+ "search.html": `<!--
+ 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.
+-->
+{{with .Alert}}
+ <p>
+ <span class="alert" style="font-size:120%">{{html .}}</span>
+ </p>
+{{end}}
+{{with .Alt}}
+ <p>
+ <span class="alert" style="font-size:120%">Did you mean: </span>
+ {{range .Alts}}
+ <a href="search?q={{urlquery .}}" style="font-size:120%">{{html .}}</a>
+ {{end}}
+ </p>
+{{end}}
+`,
+
+ "search.txt": `QUERY
+ {{.Query}}
+
+{{with .Alert}}{{.}}
+{{end}}{{/* .Alert */}}{{/*
+
+---------------------------------------
+
+*/}}{{with .Alt}}DID YOU MEAN
+
+{{range .Alts}} {{.}}
+{{end}}
+{{end}}{{/* .Alt */}}{{/*
+
+---------------------------------------
+
+*/}}{{with .Pak}}PACKAGE {{$.Query}}
+
+{{range .}} {{pkgLink .Pak.Path}}
+{{end}}
+{{end}}{{/* .Pak */}}{{/*
+
+---------------------------------------
+
+*/}}{{range $key, $val := .Idents}}{{if $val}}{{$key.Name}}
+{{range $val}} {{.Path}}.{{.Name}}
+{{end}}
+{{end}}{{end}}{{/* .Idents */}}{{/*
+
+---------------------------------------
+
+*/}}{{with .Hit}}{{with .Decls}}PACKAGE-LEVEL DECLARATIONS
+
+{{range .}}package {{.Pak.Name}}
+{{range $file := .Files}}{{range .Groups}}{{range .}} {{srcLink $file.File.Path}}:{{infoLine .}}{{end}}
+{{end}}{{end}}{{/* .Files */}}
+{{end}}{{end}}{{/* .Decls */}}{{/*
+
+---------------------------------------
+
+*/}}{{with .Others}}LOCAL DECLARATIONS AND USES
+
+{{range .}}package {{.Pak.Name}}
+{{range $file := .Files}}{{range .Groups}}{{range .}} {{srcLink $file.File.Path}}:{{infoLine .}}
+{{end}}{{end}}{{end}}{{/* .Files */}}
+{{end}}{{end}}{{/* .Others */}}{{end}}{{/* .Hit */}}{{/*
+
+---------------------------------------
+
+*/}}{{if .Textual}}{{if .Complete}}{{.Found}} TEXTUAL OCCURRENCES{{else}}MORE THAN {{.Found}} TEXTUAL OCCURRENCES{{end}}
+
+{{range .Textual}}{{len .Lines}} {{srcLink .Filename}}
+{{end}}{{if not .Complete}}... ...
+{{end}}{{end}}
+`,
+
+ "searchcode.html": `<!--
+ 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.
+-->
+{{$query_url := urlquery .Query}}
+{{if not .Idents}}
+ {{with .Pak}}
+ <h2 id="Packages">Package {{html $.Query}}</h2>
+ <p>
+ <table class="layout">
+ {{range .}}
+ {{$pkg_html := pkgLink .Pak.Path | html}}
+ <tr><td><a href="/{{$pkg_html}}">{{$pkg_html}}</a></td></tr>
+ {{end}}
+ </table>
+ </p>
+ {{end}}
+{{end}}
+{{with .Hit}}
+ {{with .Decls}}
+ <h2 id="Global">Package-level declarations</h2>
+ {{range .}}
+ {{$pkg_html := pkgLink .Pak.Path | html}}
+ <h3 id="Global_{{$pkg_html}}">package <a href="/{{$pkg_html}}">{{html .Pak.Name}}</a></h3>
+ {{range .Files}}
+ {{$file := .File.Path}}
+ {{range .Groups}}
+ {{range .}}
+ {{$line := infoLine .}}
+ <a href="{{queryLink $file $query_url $line | html}}">{{$file}}:{{$line}}</a>
+ {{infoSnippet_html .}}
+ {{end}}
+ {{end}}
+ {{end}}
+ {{end}}
+ {{end}}
+ {{with .Others}}
+ <h2 id="Local">Local declarations and uses</h2>
+ {{range .}}
+ {{$pkg_html := pkgLink .Pak.Path | html}}
+ <h3 id="Local_{{$pkg_html}}">package <a href="/{{$pkg_html}}">{{html .Pak.Name}}</a></h3>
+ {{range .Files}}
+ {{$file := .File.Path}}
+ <a href="{{queryLink $file $query_url 0 | html}}">{{$file}}</a>
+ <table class="layout">
+ {{range .Groups}}
+ <tr>
+ <td width="25"></td>
+ <th align="left" valign="top">{{index . 0 | infoKind_html}}</th>
+ <td align="left" width="4"></td>
+ <td>
+ {{range .}}
+ {{$line := infoLine .}}
+ <a href="{{queryLink $file $query_url $line | html}}">{{$line}}</a>
+ {{end}}
+ </td>
+ </tr>
+ {{end}}
+ </table>
+ {{end}}
+ {{end}}
+ {{end}}
+{{end}}
+`,
+
+ "searchdoc.html": `<!--
+ 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.
+-->
+{{range $key, $val := .Idents}}
+ {{if $val}}
+ <h2 id="{{$key.Name}}">{{$key.Name}}</h2>
+ {{range $val}}
+ {{$pkg_html := pkgLink .Path | html}}
+ {{if eq "Packages" $key.Name}}
+ <a href="/{{$pkg_html}}">{{html .Path}}</a>
+ {{else}}
+ {{$doc_html := docLink .Path .Name| html}}
+ <a href="/{{$pkg_html}}">{{html .Package}}</a>.<a href="{{$doc_html}}">{{.Name}}</a>
+ {{end}}
+ {{if .Doc}}
+ <p>{{comment_html .Doc}}</p>
+ {{else}}
+ <p><em>No documentation available</em></p>
+ {{end}}
+ {{end}}
+ {{end}}
+{{end}}
+`,
+
+ "searchtxt.html": `<!--
+ 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.
+-->
+{{$query_url := urlquery .Query}}
+{{with .Textual}}
+ {{if $.Complete}}
+ <h2 id="Textual">{{html $.Found}} textual occurrences</h2>
+ {{else}}
+ <h2 id="Textual">More than {{html $.Found}} textual occurrences</h2>
+ <p>
+ <span class="alert" style="font-size:120%">Not all files or lines containing "{{html $.Query}}" are shown.</span>
+ </p>
+ {{end}}
+ <p>
+ <table class="layout">
+ {{range .}}
+ {{$file := .Filename}}
+ <tr>
+ <td align="left" valign="top">
+ <a href="{{queryLink $file $query_url 0}}">{{$file}}</a>:
+ </td>
+ <td align="left" width="4"></td>
+ <th align="left" valign="top">{{len .Lines}}</th>
+ <td align="left" width="4"></td>
+ <td align="left">
+ {{range .Lines}}
+ <a href="{{queryLink $file $query_url .}}">{{html .}}</a>
+ {{end}}
+ {{if not $.Complete}}
+ ...
+ {{end}}
+ </td>
+ </tr>
+ {{end}}
+ {{if not $.Complete}}
+ <tr><td align="left">...</td></tr>
+ {{end}}
+ </table>
+ </p>
+{{end}}
+`,
+
+ "style.css": `body {
+ margin: 0;
+ font-family: Arial, sans-serif;
+ font-size: 16px;
+ background-color: #fff;
+ line-height: 1.3em;
+}
+pre,
+code {
+ font-family: Menlo, monospace;
+ font-size: 14px;
+}
+pre {
+ line-height: 1.4em;
+ overflow-x: auto;
+}
+pre .comment {
+ color: #006600;
+}
+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 {
+ max-width: 800px;
+ word-wrap: break-word;
+}
+p,
+pre,
+ul,
+ol {
+ margin: 20px;
+}
+pre {
+ background: #EFEFEF;
+ padding: 10px;
+
+ -webkit-border-radius: 5px;
+ -moz-border-radius: 5px;
+ border-radius: 5px;
+}
+
+h1,
+h2,
+h3,
+h4,
+.rootHeading {
+ margin: 20px 0 20px;
+ padding: 0;
+ color: #375EAB;
+ font-weight: bold;
+}
+h1 {
+ font-size: 28px;
+ line-height: 1;
+}
+h2 {
+ font-size: 20px;
+ background: #E0EBF5;
+ padding: 8px;
+ line-height: 1.25;
+ font-weight: normal;
+}
+h2 a {
+ font-weight: bold;
+}
+h3 {
+ font-size: 20px;
+}
+h3,
+h4 {
+ margin: 20px 5px;
+}
+h4 {
+ font-size: 16px;
+}
+.rootHeading {
+ font-size: 20px;
+ margin: 0;
+}
+
+dl {
+ margin: 20px;
+}
+dd {
+ margin: 0;
+}
+dd.indent {
+ margin: 0 20px;
+}
+dl,
+dd {
+ font-size: 14px;
+}
+div#nav table td {
+ vertical-align: top;
+}
+
+
+.pkg-dir {
+ padding: 0 10px;
+}
+.pkg-dir table {
+ border-collapse: collapse;
+ border-spacing: 0;
+}
+.pkg-name {
+ padding-right: 10px;
+}
+.alert {
+ color: #AA0000;
+}
+
+.top-heading {
+ float: left;
+ padding: 21px 0;
+ font-size: 20px;
+ font-weight: normal;
+}
+.top-heading a {
+ color: #222;
+ text-decoration: none;
+}
+
+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;
+}
+div#topbar > .container,
+div#page > .container {
+ max-width: 950px;
+}
+div#page.wide > .container,
+div#topbar.wide > .container {
+ max-width: none;
+}
+div#plusone {
+ float: right;
+ clear: right;
+ margin-top: 5px;
+}
+
+div#footer {
+ text-align: center;
+ color: #666;
+ font-size: 14px;
+ margin: 40px 0;
+}
+
+div#menu > a,
+div#menu > input,
+div#learn .buttons a,
+div.play .buttons a,
+div#blog .read a,
+#menu-button {
+ padding: 10px;
+
+ text-decoration: none;
+ font-size: 16px;
+
+ -webkit-border-radius: 5px;
+ -moz-border-radius: 5px;
+ border-radius: 5px;
+}
+div#playground .buttons a,
+div#menu > a,
+div#menu > input,
+#menu-button {
+ border: 1px solid #375EAB;
+}
+div#playground .buttons a,
+div#menu > a,
+#menu-button {
+ color: white;
+ background: #375EAB;
+}
+#playgroundButton.active {
+ background: white;
+ color: #375EAB;
+}
+a#start,
+div#learn .buttons a,
+div.play .buttons a,
+div#blog .read a {
+ color: #222;
+ border: 1px solid #375EAB;
+ background: #E0EBF5;
+}
+.download {
+ width: 150px;
+}
+
+div#menu {
+ text-align: right;
+ padding: 10px;
+ white-space: nowrap;
+ max-height: 0;
+ -moz-transition: max-height .25s linear;
+ transition: max-height .25s linear;
+ width: 100%;
+}
+div#menu.menu-visible {
+ max-height: 500px;
+}
+div#menu > a,
+#menu-button {
+ margin: 10px 2px;
+ padding: 10px;
+}
+div#menu > input {
+ position: relative;
+ top: 1px;
+ width: 140px;
+ background: white;
+ color: #222;
+ box-sizing: border-box;
+}
+div#menu > input.inactive {
+ color: #999;
+}
+
+#menu-button {
+ display: none;
+ position: absolute;
+ right: 5px;
+ top: 0;
+ margin-right: 5px;
+}
+#menu-button-arrow {
+ display: inline-block;
+}
+.vertical-flip {
+ transform: rotate(-180deg);
+}
+
+div.left {
+ float: left;
+ clear: left;
+ margin-right: 2.5%;
+}
+div.right {
+ float: right;
+ clear: right;
+ margin-left: 2.5%;
+}
+div.left,
+div.right {
+ width: 45%;
+}
+
+div#learn,
+div#about {
+ padding-top: 20px;
+}
+div#learn h2,
+div#about {
+ margin: 0;
+}
+div#about {
+ font-size: 20px;
+ margin: 0 auto 30px;
+}
+div#gopher {
+ background: url(/doc/gopher/frontpage.png) no-repeat;
+ background-position: center top;
+ height: 155px;
+}
+a#start {
+ display: block;
+ padding: 10px;
+
+ text-align: center;
+ text-decoration: none;
+
+ -webkit-border-radius: 5px;
+ -moz-border-radius: 5px;
+ border-radius: 5px;
+}
+a#start .big {
+ display: block;
+ font-weight: bold;
+ font-size: 20px;
+}
+a#start .desc {
+ display: block;
+ font-size: 14px;
+ font-weight: normal;
+ margin-top: 5px;
+}
+
+div#learn .popout {
+ float: right;
+ display: block;
+ cursor: pointer;
+ font-size: 12px;
+ background: url(/doc/share.png) no-repeat;
+ background-position: right top;
+ padding: 5px 27px;
+}
+div#learn pre,
+div#learn textarea {
+ padding: 0;
+ margin: 0;
+ font-family: Menlo, monospace;
+ font-size: 14px;
+}
+div#learn .input {
+ padding: 10px;
+ margin-top: 10px;
+ height: 150px;
+
+ -webkit-border-top-left-radius: 5px;
+ -webkit-border-top-right-radius: 5px;
+ -moz-border-radius-topleft: 5px;
+ -moz-border-radius-topright: 5px;
+ border-top-left-radius: 5px;
+ border-top-right-radius: 5px;
+}
+div#learn .input textarea {
+ width: 100%;
+ height: 100%;
+ border: none;
+ outline: none;
+ resize: none;
+}
+div#learn .output {
+ border-top: none !important;
+
+ padding: 10px;
+ height: 59px;
+ overflow: auto;
+
+ -webkit-border-bottom-right-radius: 5px;
+ -webkit-border-bottom-left-radius: 5px;
+ -moz-border-radius-bottomright: 5px;
+ -moz-border-radius-bottomleft: 5px;
+ border-bottom-right-radius: 5px;
+ border-bottom-left-radius: 5px;
+}
+div#learn .output pre {
+ padding: 0;
+
+ -webkit-border-radius: 0;
+ -moz-border-radius: 0;
+ border-radius: 0;
+}
+div#learn .input,
+div#learn .input textarea,
+div#learn .output,
+div#learn .output pre {
+ background: #FFFFD8;
+}
+div#learn .input,
+div#learn .output {
+ border: 1px solid #375EAB;
+}
+div#learn .buttons {
+ float: right;
+ padding: 20px 0 10px 0;
+ text-align: right;
+}
+div#learn .buttons a {
+ height: 16px;
+ margin-left: 5px;
+ padding: 10px;
+}
+div#learn .toys {
+ margin-top: 8px;
+}
+div#learn .toys select {
+ border: 1px solid #375EAB;
+ margin: 0;
+}
+div#learn .output .exit {
+ display: none;
+}
+
+div#video {
+ max-width: 100%;
+}
+div#blog,
+div#video {
+ margin-top: 40px;
+}
+div#blog > a,
+div#blog > div,
+div#blog > h2,
+div#video > a,
+div#video > div,
+div#video > h2 {
+ margin-bottom: 10px;
+}
+div#blog .title,
+div#video .title {
+ display: block;
+ font-size: 20px;
+}
+div#blog .when {
+ color: #666;
+ font-size: 14px;
+}
+div#blog .read {
+ text-align: right;
+}
+
+.toggleButton { cursor: pointer; }
+.toggle .collapsed { display: block; }
+.toggle .expanded { display: none; }
+.toggleVisible .collapsed { display: none; }
+.toggleVisible .expanded { display: block; }
+
+table.codetable { margin-left: auto; margin-right: auto; border-style: none; }
+table.codetable td { padding-right: 10px; }
+hr { border-style: none; border-top: 1px solid black; }
+
+img.gopher {
+ float: right;
+ margin-left: 10px;
+ margin-bottom: 10px;
+ z-index: -1;
+}
+h2 { clear: right; }
+
+/* example and drop-down playground */
+div.play {
+ padding: 0 20px 40px 20px;
+}
+div.play pre,
+div.play textarea,
+div.play .lines {
+ padding: 0;
+ margin: 0;
+ font-family: Menlo, monospace;
+ font-size: 14px;
+}
+div.play .input {
+ padding: 10px;
+ margin-top: 10px;
+
+ -webkit-border-top-left-radius: 5px;
+ -webkit-border-top-right-radius: 5px;
+ -moz-border-radius-topleft: 5px;
+ -moz-border-radius-topright: 5px;
+ border-top-left-radius: 5px;
+ border-top-right-radius: 5px;
+
+ overflow: hidden;
+}
+div.play .input textarea {
+ width: 100%;
+ height: 100%;
+ border: none;
+ outline: none;
+ resize: none;
+
+ overflow: hidden;
+}
+div#playground .input textarea {
+ overflow: auto;
+ resize: auto;
+}
+div.play .output {
+ border-top: none !important;
+
+ padding: 10px;
+ max-height: 200px;
+ overflow: auto;
+
+ -webkit-border-bottom-right-radius: 5px;
+ -webkit-border-bottom-left-radius: 5px;
+ -moz-border-radius-bottomright: 5px;
+ -moz-border-radius-bottomleft: 5px;
+ border-bottom-right-radius: 5px;
+ border-bottom-left-radius: 5px;
+}
+div.play .output pre {
+ padding: 0;
+
+ -webkit-border-radius: 0;
+ -moz-border-radius: 0;
+ border-radius: 0;
+}
+div.play .input,
+div.play .input textarea,
+div.play .output,
+div.play .output pre {
+ background: #FFFFD8;
+}
+div.play .input,
+div.play .output {
+ border: 1px solid #375EAB;
+}
+div.play .buttons {
+ float: right;
+ padding: 20px 0 10px 0;
+ text-align: right;
+}
+div.play .buttons a {
+ height: 16px;
+ margin-left: 5px;
+ padding: 10px;
+ cursor: pointer;
+}
+.output .stderr {
+ color: #933;
+}
+.output .system {
+ color: #999;
+}
+
+/* drop-down playground */
+#playgroundButton,
+div#playground {
+ /* start hidden; revealed by javascript */
+ display: none;
+}
+div#playground {
+ position: absolute;
+ top: 63px;
+ right: 20px;
+ padding: 0 10px 10px 10px;
+ z-index: 1;
+ text-align: left;
+ background: #E0EBF5;
+
+ border: 1px solid #B0BBC5;
+ border-top: none;
+
+ -webkit-border-bottom-left-radius: 5px;
+ -webkit-border-bottom-right-radius: 5px;
+ -moz-border-radius-bottomleft: 5px;
+ -moz-border-radius-bottomright: 5px;
+ border-bottom-left-radius: 5px;
+ border-bottom-right-radius: 5px;
+}
+div#playground .code {
+ width: 520px;
+ height: 200px;
+}
+div#playground .output {
+ height: 100px;
+}
+
+/* Inline runnable snippets (play.js/initPlayground) */
+#content .code pre, #content .playground pre, #content .output pre {
+ margin: 0;
+ padding: 0;
+ background: none;
+ border: none;
+ outline: 0px solid transparent;
+ overflow: auto;
+}
+#content .playground .number, #content .code .number {
+ color: #999;
+}
+#content .code, #content .playground, #content .output {
+ width: auto;
+ margin: 20px;
+ padding: 10px;
+ -webkit-border-radius: 5px;
+ -moz-border-radius: 5px;
+ border-radius: 5px;
+}
+#content .code, #content .playground {
+ background: #e9e9e9;
+}
+#content .output {
+ background: #202020;
+}
+#content .output .stdout, #content .output pre {
+ color: #e6e6e6;
+}
+#content .output .stderr, #content .output .error {
+ color: rgb(244, 74, 63);
+}
+#content .output .system, #content .output .exit {
+ color: rgb(255, 209, 77)
+}
+#content .buttons {
+ position: relative;
+ float: right;
+ top: -50px;
+ right: 30px;
+}
+#content .output .buttons {
+ top: -60px;
+ right: 0;
+ height: 0;
+}
+#content .buttons .kill {
+ display: none;
+ visibility: hidden;
+}
+a.error {
+ font-weight: bold;
+ color: white;
+ background-color: darkred;
+ border-bottom-left-radius: 4px;
+ border-bottom-right-radius: 4px;
+ border-top-left-radius: 4px;
+ border-top-right-radius: 4px;
+ padding: 2px 4px 2px 4px; /* TRBL */
+}
+
+
+#heading-narrow {
+ display: none;
+}
+
+.downloading {
+ background: #F9F9BE;
+ padding: 10px;
+ text-align: center;
+ border-radius: 5px;
+}
+
+@media (max-width: 930px) {
+ #heading-wide {
+ display: none;
+ }
+ #heading-narrow {
+ display: block;
+ }
+}
+
+
+@media (max-width: 760px) {
+ .container .left,
+ .container .right {
+ width: auto;
+ float: none;
+ }
+
+ div#about {
+ max-width: 500px;
+ text-align: center;
+ }
+}
+
+@media (min-width: 700px) and (max-width: 1000px) {
+ div#menu > a {
+ margin: 5px 0;
+ font-size: 14px;
+ }
+
+ div#menu > input {
+ font-size: 14px;
+ }
+}
+
+@media (max-width: 700px) {
+ body {
+ font-size: 15px;
+ }
+
+ pre,
+ code {
+ font-size: 13px;
+ }
+
+ div#page > .container {
+ padding: 0 10px;
+ }
+
+ div#topbar {
+ height: auto;
+ padding: 10px;
+ }
+
+ div#topbar > .container {
+ padding: 0;
+ }
+
+ #heading-wide {
+ display: block;
+ }
+ #heading-narrow {
+ display: none;
+ }
+
+ .top-heading {
+ float: none;
+ display: inline-block;
+ padding: 12px;
+ }
+
+ div#menu {
+ padding: 0;
+ min-width: 0;
+ text-align: left;
+ float: left;
+ }
+
+ div#menu > a,
+ div#menu > input {
+ display: block;
+ margin-left: 0;
+ margin-right: 0;
+ }
+
+ div#menu > input {
+ width: 100%;
+ }
+
+ #menu-button {
+ display: inline-block;
+ }
+
+ p,
+ pre,
+ ul,
+ ol {
+ margin: 10px;
+ }
+
+ .pkg-synopsis {
+ display: none;
+ }
+
+ img.gopher {
+ display: none;
+ }
+}
+
+@media (max-width: 480px) {
+ #heading-wide {
+ display: none;
+ }
+ #heading-narrow {
+ display: block;
+ }
+}
+
+@media print {
+ pre {
+ background: #FFF;
+ border: 1px solid #BBB;
+ white-space: pre-wrap;
+ }
+}
+`,
+}
diff --git a/godoc/static/style.css b/godoc/static/style.css
new file mode 100644
index 0000000..4d2b07a
--- /dev/null
+++ b/godoc/static/style.css
@@ -0,0 +1,776 @@
+body {
+ margin: 0;
+ font-family: Arial, sans-serif;
+ font-size: 16px;
+ background-color: #fff;
+ line-height: 1.3em;
+}
+pre,
+code {
+ font-family: Menlo, monospace;
+ font-size: 14px;
+}
+pre {
+ line-height: 1.4em;
+ overflow-x: auto;
+}
+pre .comment {
+ color: #006600;
+}
+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 {
+ max-width: 800px;
+ word-wrap: break-word;
+}
+p,
+pre,
+ul,
+ol {
+ margin: 20px;
+}
+pre {
+ background: #EFEFEF;
+ padding: 10px;
+
+ -webkit-border-radius: 5px;
+ -moz-border-radius: 5px;
+ border-radius: 5px;
+}
+
+h1,
+h2,
+h3,
+h4,
+.rootHeading {
+ margin: 20px 0 20px;
+ padding: 0;
+ color: #375EAB;
+ font-weight: bold;
+}
+h1 {
+ font-size: 28px;
+ line-height: 1;
+}
+h2 {
+ font-size: 20px;
+ background: #E0EBF5;
+ padding: 8px;
+ line-height: 1.25;
+ font-weight: normal;
+}
+h2 a {
+ font-weight: bold;
+}
+h3 {
+ font-size: 20px;
+}
+h3,
+h4 {
+ margin: 20px 5px;
+}
+h4 {
+ font-size: 16px;
+}
+.rootHeading {
+ font-size: 20px;
+ margin: 0;
+}
+
+dl {
+ margin: 20px;
+}
+dd {
+ margin: 0;
+}
+dd.indent {
+ margin: 0 20px;
+}
+dl,
+dd {
+ font-size: 14px;
+}
+div#nav table td {
+ vertical-align: top;
+}
+
+
+.pkg-dir {
+ padding: 0 10px;
+}
+.pkg-dir table {
+ border-collapse: collapse;
+ border-spacing: 0;
+}
+.pkg-name {
+ padding-right: 10px;
+}
+.alert {
+ color: #AA0000;
+}
+
+.top-heading {
+ float: left;
+ padding: 21px 0;
+ font-size: 20px;
+ font-weight: normal;
+}
+.top-heading a {
+ color: #222;
+ text-decoration: none;
+}
+
+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;
+}
+div#topbar > .container,
+div#page > .container {
+ max-width: 950px;
+}
+div#page.wide > .container,
+div#topbar.wide > .container {
+ max-width: none;
+}
+div#plusone {
+ float: right;
+ clear: right;
+ margin-top: 5px;
+}
+
+div#footer {
+ text-align: center;
+ color: #666;
+ font-size: 14px;
+ margin: 40px 0;
+}
+
+div#menu > a,
+div#menu > input,
+div#learn .buttons a,
+div.play .buttons a,
+div#blog .read a,
+#menu-button {
+ padding: 10px;
+
+ text-decoration: none;
+ font-size: 16px;
+
+ -webkit-border-radius: 5px;
+ -moz-border-radius: 5px;
+ border-radius: 5px;
+}
+div#playground .buttons a,
+div#menu > a,
+div#menu > input,
+#menu-button {
+ border: 1px solid #375EAB;
+}
+div#playground .buttons a,
+div#menu > a,
+#menu-button {
+ color: white;
+ background: #375EAB;
+}
+#playgroundButton.active {
+ background: white;
+ color: #375EAB;
+}
+a#start,
+div#learn .buttons a,
+div.play .buttons a,
+div#blog .read a {
+ color: #222;
+ border: 1px solid #375EAB;
+ background: #E0EBF5;
+}
+.download {
+ width: 150px;
+}
+
+div#menu {
+ text-align: right;
+ padding: 10px;
+ white-space: nowrap;
+ max-height: 0;
+ -moz-transition: max-height .25s linear;
+ transition: max-height .25s linear;
+ width: 100%;
+}
+div#menu.menu-visible {
+ max-height: 500px;
+}
+div#menu > a,
+#menu-button {
+ margin: 10px 2px;
+ padding: 10px;
+}
+div#menu > input {
+ position: relative;
+ top: 1px;
+ width: 140px;
+ background: white;
+ color: #222;
+ box-sizing: border-box;
+}
+div#menu > input.inactive {
+ color: #999;
+}
+
+#menu-button {
+ display: none;
+ position: absolute;
+ right: 5px;
+ top: 0;
+ margin-right: 5px;
+}
+#menu-button-arrow {
+ display: inline-block;
+}
+.vertical-flip {
+ transform: rotate(-180deg);
+}
+
+div.left {
+ float: left;
+ clear: left;
+ margin-right: 2.5%;
+}
+div.right {
+ float: right;
+ clear: right;
+ margin-left: 2.5%;
+}
+div.left,
+div.right {
+ width: 45%;
+}
+
+div#learn,
+div#about {
+ padding-top: 20px;
+}
+div#learn h2,
+div#about {
+ margin: 0;
+}
+div#about {
+ font-size: 20px;
+ margin: 0 auto 30px;
+}
+div#gopher {
+ background: url(/doc/gopher/frontpage.png) no-repeat;
+ background-position: center top;
+ height: 155px;
+}
+a#start {
+ display: block;
+ padding: 10px;
+
+ text-align: center;
+ text-decoration: none;
+
+ -webkit-border-radius: 5px;
+ -moz-border-radius: 5px;
+ border-radius: 5px;
+}
+a#start .big {
+ display: block;
+ font-weight: bold;
+ font-size: 20px;
+}
+a#start .desc {
+ display: block;
+ font-size: 14px;
+ font-weight: normal;
+ margin-top: 5px;
+}
+
+div#learn .popout {
+ float: right;
+ display: block;
+ cursor: pointer;
+ font-size: 12px;
+ background: url(/doc/share.png) no-repeat;
+ background-position: right top;
+ padding: 5px 27px;
+}
+div#learn pre,
+div#learn textarea {
+ padding: 0;
+ margin: 0;
+ font-family: Menlo, monospace;
+ font-size: 14px;
+}
+div#learn .input {
+ padding: 10px;
+ margin-top: 10px;
+ height: 150px;
+
+ -webkit-border-top-left-radius: 5px;
+ -webkit-border-top-right-radius: 5px;
+ -moz-border-radius-topleft: 5px;
+ -moz-border-radius-topright: 5px;
+ border-top-left-radius: 5px;
+ border-top-right-radius: 5px;
+}
+div#learn .input textarea {
+ width: 100%;
+ height: 100%;
+ border: none;
+ outline: none;
+ resize: none;
+}
+div#learn .output {
+ border-top: none !important;
+
+ padding: 10px;
+ height: 59px;
+ overflow: auto;
+
+ -webkit-border-bottom-right-radius: 5px;
+ -webkit-border-bottom-left-radius: 5px;
+ -moz-border-radius-bottomright: 5px;
+ -moz-border-radius-bottomleft: 5px;
+ border-bottom-right-radius: 5px;
+ border-bottom-left-radius: 5px;
+}
+div#learn .output pre {
+ padding: 0;
+
+ -webkit-border-radius: 0;
+ -moz-border-radius: 0;
+ border-radius: 0;
+}
+div#learn .input,
+div#learn .input textarea,
+div#learn .output,
+div#learn .output pre {
+ background: #FFFFD8;
+}
+div#learn .input,
+div#learn .output {
+ border: 1px solid #375EAB;
+}
+div#learn .buttons {
+ float: right;
+ padding: 20px 0 10px 0;
+ text-align: right;
+}
+div#learn .buttons a {
+ height: 16px;
+ margin-left: 5px;
+ padding: 10px;
+}
+div#learn .toys {
+ margin-top: 8px;
+}
+div#learn .toys select {
+ border: 1px solid #375EAB;
+ margin: 0;
+}
+div#learn .output .exit {
+ display: none;
+}
+
+div#video {
+ max-width: 100%;
+}
+div#blog,
+div#video {
+ margin-top: 40px;
+}
+div#blog > a,
+div#blog > div,
+div#blog > h2,
+div#video > a,
+div#video > div,
+div#video > h2 {
+ margin-bottom: 10px;
+}
+div#blog .title,
+div#video .title {
+ display: block;
+ font-size: 20px;
+}
+div#blog .when {
+ color: #666;
+ font-size: 14px;
+}
+div#blog .read {
+ text-align: right;
+}
+
+.toggleButton { cursor: pointer; }
+.toggle .collapsed { display: block; }
+.toggle .expanded { display: none; }
+.toggleVisible .collapsed { display: none; }
+.toggleVisible .expanded { display: block; }
+
+table.codetable { margin-left: auto; margin-right: auto; border-style: none; }
+table.codetable td { padding-right: 10px; }
+hr { border-style: none; border-top: 1px solid black; }
+
+img.gopher {
+ float: right;
+ margin-left: 10px;
+ margin-bottom: 10px;
+ z-index: -1;
+}
+h2 { clear: right; }
+
+/* example and drop-down playground */
+div.play {
+ padding: 0 20px 40px 20px;
+}
+div.play pre,
+div.play textarea,
+div.play .lines {
+ padding: 0;
+ margin: 0;
+ font-family: Menlo, monospace;
+ font-size: 14px;
+}
+div.play .input {
+ padding: 10px;
+ margin-top: 10px;
+
+ -webkit-border-top-left-radius: 5px;
+ -webkit-border-top-right-radius: 5px;
+ -moz-border-radius-topleft: 5px;
+ -moz-border-radius-topright: 5px;
+ border-top-left-radius: 5px;
+ border-top-right-radius: 5px;
+
+ overflow: hidden;
+}
+div.play .input textarea {
+ width: 100%;
+ height: 100%;
+ border: none;
+ outline: none;
+ resize: none;
+
+ overflow: hidden;
+}
+div#playground .input textarea {
+ overflow: auto;
+ resize: auto;
+}
+div.play .output {
+ border-top: none !important;
+
+ padding: 10px;
+ max-height: 200px;
+ overflow: auto;
+
+ -webkit-border-bottom-right-radius: 5px;
+ -webkit-border-bottom-left-radius: 5px;
+ -moz-border-radius-bottomright: 5px;
+ -moz-border-radius-bottomleft: 5px;
+ border-bottom-right-radius: 5px;
+ border-bottom-left-radius: 5px;
+}
+div.play .output pre {
+ padding: 0;
+
+ -webkit-border-radius: 0;
+ -moz-border-radius: 0;
+ border-radius: 0;
+}
+div.play .input,
+div.play .input textarea,
+div.play .output,
+div.play .output pre {
+ background: #FFFFD8;
+}
+div.play .input,
+div.play .output {
+ border: 1px solid #375EAB;
+}
+div.play .buttons {
+ float: right;
+ padding: 20px 0 10px 0;
+ text-align: right;
+}
+div.play .buttons a {
+ height: 16px;
+ margin-left: 5px;
+ padding: 10px;
+ cursor: pointer;
+}
+.output .stderr {
+ color: #933;
+}
+.output .system {
+ color: #999;
+}
+
+/* drop-down playground */
+#playgroundButton,
+div#playground {
+ /* start hidden; revealed by javascript */
+ display: none;
+}
+div#playground {
+ position: absolute;
+ top: 63px;
+ right: 20px;
+ padding: 0 10px 10px 10px;
+ z-index: 1;
+ text-align: left;
+ background: #E0EBF5;
+
+ border: 1px solid #B0BBC5;
+ border-top: none;
+
+ -webkit-border-bottom-left-radius: 5px;
+ -webkit-border-bottom-right-radius: 5px;
+ -moz-border-radius-bottomleft: 5px;
+ -moz-border-radius-bottomright: 5px;
+ border-bottom-left-radius: 5px;
+ border-bottom-right-radius: 5px;
+}
+div#playground .code {
+ width: 520px;
+ height: 200px;
+}
+div#playground .output {
+ height: 100px;
+}
+
+/* Inline runnable snippets (play.js/initPlayground) */
+#content .code pre, #content .playground pre, #content .output pre {
+ margin: 0;
+ padding: 0;
+ background: none;
+ border: none;
+ outline: 0px solid transparent;
+ overflow: auto;
+}
+#content .playground .number, #content .code .number {
+ color: #999;
+}
+#content .code, #content .playground, #content .output {
+ width: auto;
+ margin: 20px;
+ padding: 10px;
+ -webkit-border-radius: 5px;
+ -moz-border-radius: 5px;
+ border-radius: 5px;
+}
+#content .code, #content .playground {
+ background: #e9e9e9;
+}
+#content .output {
+ background: #202020;
+}
+#content .output .stdout, #content .output pre {
+ color: #e6e6e6;
+}
+#content .output .stderr, #content .output .error {
+ color: rgb(244, 74, 63);
+}
+#content .output .system, #content .output .exit {
+ color: rgb(255, 209, 77)
+}
+#content .buttons {
+ position: relative;
+ float: right;
+ top: -50px;
+ right: 30px;
+}
+#content .output .buttons {
+ top: -60px;
+ right: 0;
+ height: 0;
+}
+#content .buttons .kill {
+ display: none;
+ visibility: hidden;
+}
+a.error {
+ font-weight: bold;
+ color: white;
+ background-color: darkred;
+ border-bottom-left-radius: 4px;
+ border-bottom-right-radius: 4px;
+ border-top-left-radius: 4px;
+ border-top-right-radius: 4px;
+ padding: 2px 4px 2px 4px; /* TRBL */
+}
+
+
+#heading-narrow {
+ display: none;
+}
+
+.downloading {
+ background: #F9F9BE;
+ padding: 10px;
+ text-align: center;
+ border-radius: 5px;
+}
+
+@media (max-width: 930px) {
+ #heading-wide {
+ display: none;
+ }
+ #heading-narrow {
+ display: block;
+ }
+}
+
+
+@media (max-width: 760px) {
+ .container .left,
+ .container .right {
+ width: auto;
+ float: none;
+ }
+
+ div#about {
+ max-width: 500px;
+ text-align: center;
+ }
+}
+
+@media (min-width: 700px) and (max-width: 1000px) {
+ div#menu > a {
+ margin: 5px 0;
+ font-size: 14px;
+ }
+
+ div#menu > input {
+ font-size: 14px;
+ }
+}
+
+@media (max-width: 700px) {
+ body {
+ font-size: 15px;
+ }
+
+ pre,
+ code {
+ font-size: 13px;
+ }
+
+ div#page > .container {
+ padding: 0 10px;
+ }
+
+ div#topbar {
+ height: auto;
+ padding: 10px;
+ }
+
+ div#topbar > .container {
+ padding: 0;
+ }
+
+ #heading-wide {
+ display: block;
+ }
+ #heading-narrow {
+ display: none;
+ }
+
+ .top-heading {
+ float: none;
+ display: inline-block;
+ padding: 12px;
+ }
+
+ div#menu {
+ padding: 0;
+ min-width: 0;
+ text-align: left;
+ float: left;
+ }
+
+ div#menu > a,
+ div#menu > input {
+ display: block;
+ margin-left: 0;
+ margin-right: 0;
+ }
+
+ div#menu > input {
+ width: 100%;
+ }
+
+ #menu-button {
+ display: inline-block;
+ }
+
+ p,
+ pre,
+ ul,
+ ol {
+ margin: 10px;
+ }
+
+ .pkg-synopsis {
+ display: none;
+ }
+
+ img.gopher {
+ display: none;
+ }
+}
+
+@media (max-width: 480px) {
+ #heading-wide {
+ display: none;
+ }
+ #heading-narrow {
+ display: block;
+ }
+}
+
+@media print {
+ pre {
+ background: #FFF;
+ border: 1px solid #BBB;
+ white-space: pre-wrap;
+ }
+}
diff --git a/godoc/tab.go b/godoc/tab.go
new file mode 100644
index 0000000..d314ac7
--- /dev/null
+++ b/godoc/tab.go
@@ -0,0 +1,82 @@
+// 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.
+
+// TODO(bradfitz,adg): move to util
+
+package godoc
+
+import "io"
+
+var spaces = []byte(" ") // 32 spaces seems like a good number
+
+const (
+ indenting = iota
+ collecting
+)
+
+// A tconv is an io.Writer filter for converting leading tabs into spaces.
+type tconv struct {
+ output io.Writer
+ state int // indenting or collecting
+ indent int // valid if state == indenting
+ p *Presentation
+}
+
+func (p *tconv) writeIndent() (err error) {
+ i := p.indent
+ for i >= len(spaces) {
+ i -= len(spaces)
+ if _, err = p.output.Write(spaces); err != nil {
+ return
+ }
+ }
+ // i < len(spaces)
+ if i > 0 {
+ _, err = p.output.Write(spaces[0:i])
+ }
+ return
+}
+
+func (p *tconv) Write(data []byte) (n int, err error) {
+ if len(data) == 0 {
+ return
+ }
+ pos := 0 // valid if p.state == collecting
+ var b byte
+ for n, b = range data {
+ switch p.state {
+ case indenting:
+ switch b {
+ case '\t':
+ p.indent += p.p.TabWidth
+ case '\n':
+ p.indent = 0
+ if _, err = p.output.Write(data[n : n+1]); err != nil {
+ return
+ }
+ case ' ':
+ p.indent++
+ default:
+ p.state = collecting
+ pos = n
+ if err = p.writeIndent(); err != nil {
+ return
+ }
+ }
+ case collecting:
+ if b == '\n' {
+ p.state = indenting
+ p.indent = 0
+ if _, err = p.output.Write(data[pos : n+1]); err != nil {
+ return
+ }
+ }
+ }
+ }
+ n = len(data)
+ if pos < n && p.state == collecting {
+ _, err = p.output.Write(data[pos:])
+ }
+ return
+}
diff --git a/godoc/template.go b/godoc/template.go
new file mode 100644
index 0000000..eda5874
--- /dev/null
+++ b/godoc/template.go
@@ -0,0 +1,179 @@
+// 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.
+
+// Template support for writing HTML documents.
+// Documents that include Template: true in their
+// metadata are executed as input to text/template.
+//
+// This file defines functions for those templates to invoke.
+
+// The template uses the function "code" to inject program
+// source into the output by extracting code from files and
+// injecting them as HTML-escaped <pre> blocks.
+//
+// The syntax is simple: 1, 2, or 3 space-separated arguments:
+//
+// Whole file:
+// {{code "foo.go"}}
+// One line (here the signature of main):
+// {{code "foo.go" `/^func.main/`}}
+// Block of text, determined by start and end (here the body of main):
+// {{code "foo.go" `/^func.main/` `/^}/`
+//
+// Patterns can be `/regular expression/`, a decimal number, or "$"
+// to signify the end of the file. In multi-line matches,
+// lines that end with the four characters
+// OMIT
+// are omitted from the output, making it easy to provide marker
+// lines in the input that will not appear in the output but are easy
+// to identify by pattern.
+
+package godoc
+
+import (
+ "bytes"
+ "fmt"
+ "log"
+ "regexp"
+ "strings"
+
+ "golang.org/x/tools/godoc/vfs"
+)
+
+// Functions in this file panic on error, but the panic is recovered
+// to an error by 'code'.
+
+// contents reads and returns the content of the named file
+// (from the virtual file system, so for example /doc refers to $GOROOT/doc).
+func (c *Corpus) contents(name string) string {
+ file, err := vfs.ReadFile(c.fs, name)
+ if err != nil {
+ log.Panic(err)
+ }
+ return string(file)
+}
+
+// stringFor returns a textual representation of the arg, formatted according to its nature.
+func stringFor(arg interface{}) string {
+ switch arg := arg.(type) {
+ case int:
+ return fmt.Sprintf("%d", arg)
+ case string:
+ if len(arg) > 2 && arg[0] == '/' && arg[len(arg)-1] == '/' {
+ return fmt.Sprintf("%#q", arg)
+ }
+ return fmt.Sprintf("%q", arg)
+ default:
+ log.Panicf("unrecognized argument: %v type %T", arg, arg)
+ }
+ return ""
+}
+
+func (p *Presentation) code(file string, arg ...interface{}) (s string, err error) {
+ defer func() {
+ if r := recover(); r != nil {
+ err = fmt.Errorf("%v", r)
+ }
+ }()
+
+ text := p.Corpus.contents(file)
+ var command string
+ switch len(arg) {
+ case 0:
+ // text is already whole file.
+ command = fmt.Sprintf("code %q", file)
+ case 1:
+ command = fmt.Sprintf("code %q %s", file, stringFor(arg[0]))
+ text = p.Corpus.oneLine(file, text, arg[0])
+ case 2:
+ command = fmt.Sprintf("code %q %s %s", file, stringFor(arg[0]), stringFor(arg[1]))
+ text = p.Corpus.multipleLines(file, text, arg[0], arg[1])
+ default:
+ return "", fmt.Errorf("incorrect code invocation: code %q %q", file, arg)
+ }
+ // Trim spaces from output.
+ text = strings.Trim(text, "\n")
+ // Replace tabs by spaces, which work better in HTML.
+ text = strings.Replace(text, "\t", " ", -1)
+ var buf bytes.Buffer
+ // HTML-escape text and syntax-color comments like elsewhere.
+ FormatText(&buf, []byte(text), -1, true, "", nil)
+ // Include the command as a comment.
+ text = fmt.Sprintf("<pre><!--{{%s}}\n-->%s</pre>", command, buf.Bytes())
+ return text, nil
+}
+
+// parseArg returns the integer or string value of the argument and tells which it is.
+func parseArg(arg interface{}, file string, max int) (ival int, sval string, isInt bool) {
+ switch n := arg.(type) {
+ case int:
+ if n <= 0 || n > max {
+ log.Panicf("%q:%d is out of range", file, n)
+ }
+ return n, "", true
+ case string:
+ return 0, n, false
+ }
+ log.Panicf("unrecognized argument %v type %T", arg, arg)
+ return
+}
+
+// oneLine returns the single line generated by a two-argument code invocation.
+func (c *Corpus) oneLine(file, text string, arg interface{}) string {
+ lines := strings.SplitAfter(c.contents(file), "\n")
+ line, pattern, isInt := parseArg(arg, file, len(lines))
+ if isInt {
+ return lines[line-1]
+ }
+ return lines[match(file, 0, lines, pattern)-1]
+}
+
+// multipleLines returns the text generated by a three-argument code invocation.
+func (c *Corpus) multipleLines(file, text string, arg1, arg2 interface{}) string {
+ lines := strings.SplitAfter(c.contents(file), "\n")
+ line1, pattern1, isInt1 := parseArg(arg1, file, len(lines))
+ line2, pattern2, isInt2 := parseArg(arg2, file, len(lines))
+ if !isInt1 {
+ line1 = match(file, 0, lines, pattern1)
+ }
+ if !isInt2 {
+ line2 = match(file, line1, lines, pattern2)
+ } else if line2 < line1 {
+ log.Panicf("lines out of order for %q: %d %d", text, line1, line2)
+ }
+ for k := line1 - 1; k < line2; k++ {
+ if strings.HasSuffix(lines[k], "OMIT\n") {
+ lines[k] = ""
+ }
+ }
+ return strings.Join(lines[line1-1:line2], "")
+}
+
+// match identifies the input line that matches the pattern in a code invocation.
+// If start>0, match lines starting there rather than at the beginning.
+// The return value is 1-indexed.
+func match(file string, start int, lines []string, pattern string) int {
+ // $ matches the end of the file.
+ if pattern == "$" {
+ if len(lines) == 0 {
+ log.Panicf("%q: empty file", file)
+ }
+ return len(lines)
+ }
+ // /regexp/ matches the line that matches the regexp.
+ if len(pattern) > 2 && pattern[0] == '/' && pattern[len(pattern)-1] == '/' {
+ re, err := regexp.Compile(pattern[1 : len(pattern)-1])
+ if err != nil {
+ log.Panic(err)
+ }
+ for i := start; i < len(lines); i++ {
+ if re.MatchString(lines[i]) {
+ return i + 1
+ }
+ }
+ log.Panicf("%s: no match for %#q", file, pattern)
+ }
+ log.Panicf("unrecognized pattern: %q", pattern)
+ return 0
+}
diff --git a/godoc/util/throttle.go b/godoc/util/throttle.go
new file mode 100644
index 0000000..53d9ba6
--- /dev/null
+++ b/godoc/util/throttle.go
@@ -0,0 +1,88 @@
+// 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 util
+
+import "time"
+
+// A Throttle permits throttling of a goroutine by
+// calling the Throttle method repeatedly.
+//
+type Throttle struct {
+ f float64 // f = (1-r)/r for 0 < r < 1
+ dt time.Duration // minimum run time slice; >= 0
+ tr time.Duration // accumulated time running
+ ts time.Duration // accumulated time stopped
+ tt time.Time // earliest throttle time (= time Throttle returned + tm)
+}
+
+// NewThrottle creates a new Throttle with a throttle value r and
+// a minimum allocated run time slice of dt:
+//
+// r == 0: "empty" throttle; the goroutine is always sleeping
+// r == 1: full throttle; the goroutine is never sleeping
+//
+// A value of r == 0.6 throttles a goroutine such that it runs
+// approx. 60% of the time, and sleeps approx. 40% of the time.
+// Values of r < 0 or r > 1 are clamped down to values between 0 and 1.
+// Values of dt < 0 are set to 0.
+//
+func NewThrottle(r float64, dt time.Duration) *Throttle {
+ var f float64
+ switch {
+ case r <= 0:
+ f = -1 // indicates always sleep
+ case r >= 1:
+ f = 0 // assume r == 1 (never sleep)
+ default:
+ // 0 < r < 1
+ f = (1 - r) / r
+ }
+ if dt < 0 {
+ dt = 0
+ }
+ return &Throttle{f: f, dt: dt, tt: time.Now().Add(dt)}
+}
+
+// Throttle calls time.Sleep such that over time the ratio tr/ts between
+// accumulated run (tr) and sleep times (ts) approximates the value 1/(1-r)
+// where r is the throttle value. Throttle returns immediately (w/o sleeping)
+// if less than tm ns have passed since the last call to Throttle.
+//
+func (p *Throttle) Throttle() {
+ if p.f < 0 {
+ select {} // always sleep
+ }
+
+ t0 := time.Now()
+ if t0.Before(p.tt) {
+ return // keep running (minimum time slice not exhausted yet)
+ }
+
+ // accumulate running time
+ p.tr += t0.Sub(p.tt) + p.dt
+
+ // compute sleep time
+ // Over time we want:
+ //
+ // tr/ts = r/(1-r)
+ //
+ // Thus:
+ //
+ // ts = tr*f with f = (1-r)/r
+ //
+ // After some incremental run time δr added to the total run time
+ // tr, the incremental sleep-time δs to get to the same ratio again
+ // after waking up from time.Sleep is:
+ if δs := time.Duration(float64(p.tr)*p.f) - p.ts; δs > 0 {
+ time.Sleep(δs)
+ }
+
+ // accumulate (actual) sleep time
+ t1 := time.Now()
+ p.ts += t1.Sub(t0)
+
+ // set earliest next throttle time
+ p.tt = t1.Add(p.dt)
+}
diff --git a/godoc/util/util.go b/godoc/util/util.go
new file mode 100644
index 0000000..feedb76
--- /dev/null
+++ b/godoc/util/util.go
@@ -0,0 +1,89 @@
+// 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 util contains utility types and functions for godoc.
+package util // import "golang.org/x/tools/godoc/util"
+
+import (
+ pathpkg "path"
+ "sync"
+ "time"
+ "unicode/utf8"
+
+ "golang.org/x/tools/godoc/vfs"
+)
+
+// An RWValue wraps a value and permits mutually exclusive
+// access to it and records the time the value was last set.
+type RWValue struct {
+ mutex sync.RWMutex
+ value interface{}
+ timestamp time.Time // time of last set()
+}
+
+func (v *RWValue) Set(value interface{}) {
+ v.mutex.Lock()
+ v.value = value
+ v.timestamp = time.Now()
+ v.mutex.Unlock()
+}
+
+func (v *RWValue) Get() (interface{}, time.Time) {
+ v.mutex.RLock()
+ defer v.mutex.RUnlock()
+ return v.value, v.timestamp
+}
+
+// IsText reports whether a significant prefix of s looks like correct UTF-8;
+// that is, if it is likely that s is human-readable text.
+func IsText(s []byte) bool {
+ const max = 1024 // at least utf8.UTFMax
+ if len(s) > max {
+ s = s[0:max]
+ }
+ for i, c := range string(s) {
+ if i+utf8.UTFMax > len(s) {
+ // last char may be incomplete - ignore
+ break
+ }
+ if c == 0xFFFD || c < ' ' && c != '\n' && c != '\t' && c != '\f' {
+ // decoding error or control character - not a text file
+ return false
+ }
+ }
+ return true
+}
+
+// textExt[x] is true if the extension x indicates a text file, and false otherwise.
+var textExt = map[string]bool{
+ ".css": false, // must be served raw
+ ".js": false, // must be served raw
+}
+
+// IsTextFile reports whether the file has a known extension indicating
+// a text file, or if a significant chunk of the specified file looks like
+// correct UTF-8; that is, if it is likely that the file contains human-
+// readable text.
+func IsTextFile(fs vfs.Opener, filename string) bool {
+ // if the extension is known, use it for decision making
+ if isText, found := textExt[pathpkg.Ext(filename)]; found {
+ return isText
+ }
+
+ // the extension is not known; read an initial chunk
+ // of the file and check if it looks like text
+ f, err := fs.Open(filename)
+ if err != nil {
+ return false
+ }
+ defer f.Close()
+
+ var buf [1024]byte
+ n, err := f.Read(buf[0:])
+ if err != nil {
+ return false
+ }
+
+ return IsText(buf[0:n])
+}
diff --git a/godoc/vfs/gatefs/gatefs.go b/godoc/vfs/gatefs/gatefs.go
new file mode 100644
index 0000000..7045a5c
--- /dev/null
+++ b/godoc/vfs/gatefs/gatefs.go
@@ -0,0 +1,89 @@
+// 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 gatefs provides an implementation of the FileSystem
+// interface that wraps another FileSystem and limits its concurrency.
+package gatefs // import "golang.org/x/tools/godoc/vfs/gatefs"
+
+import (
+ "fmt"
+ "os"
+
+ "golang.org/x/tools/godoc/vfs"
+)
+
+// New returns a new FileSystem that delegates to fs.
+// If gateCh is non-nil and buffered, it's used as a gate
+// to limit concurrency on calls to fs.
+func New(fs vfs.FileSystem, gateCh chan bool) vfs.FileSystem {
+ if cap(gateCh) == 0 {
+ return fs
+ }
+ return gatefs{fs, gate(gateCh)}
+}
+
+type gate chan bool
+
+func (g gate) enter() { g <- true }
+func (g gate) leave() { <-g }
+
+type gatefs struct {
+ fs vfs.FileSystem
+ gate
+}
+
+func (fs gatefs) String() string {
+ return fmt.Sprintf("gated(%s, %d)", fs.fs.String(), cap(fs.gate))
+}
+
+func (fs gatefs) Open(p string) (vfs.ReadSeekCloser, error) {
+ fs.enter()
+ defer fs.leave()
+ rsc, err := fs.fs.Open(p)
+ if err != nil {
+ return nil, err
+ }
+ return gatef{rsc, fs.gate}, nil
+}
+
+func (fs gatefs) Lstat(p string) (os.FileInfo, error) {
+ fs.enter()
+ defer fs.leave()
+ return fs.fs.Lstat(p)
+}
+
+func (fs gatefs) Stat(p string) (os.FileInfo, error) {
+ fs.enter()
+ defer fs.leave()
+ return fs.fs.Stat(p)
+}
+
+func (fs gatefs) ReadDir(p string) ([]os.FileInfo, error) {
+ fs.enter()
+ defer fs.leave()
+ return fs.fs.ReadDir(p)
+}
+
+type gatef struct {
+ rsc vfs.ReadSeekCloser
+ gate
+}
+
+func (f gatef) Read(p []byte) (n int, err error) {
+ f.enter()
+ defer f.leave()
+ return f.rsc.Read(p)
+}
+
+func (f gatef) Seek(offset int64, whence int) (ret int64, err error) {
+ f.enter()
+ defer f.leave()
+ return f.rsc.Seek(offset, whence)
+}
+
+func (f gatef) Close() error {
+ f.enter()
+ defer f.leave()
+ return f.rsc.Close()
+}
diff --git a/godoc/vfs/httpfs/httpfs.go b/godoc/vfs/httpfs/httpfs.go
new file mode 100644
index 0000000..f232f03
--- /dev/null
+++ b/godoc/vfs/httpfs/httpfs.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.
+
+// Package httpfs implements http.FileSystem using a godoc vfs.FileSystem.
+package httpfs // import "golang.org/x/tools/godoc/vfs/httpfs"
+
+import (
+ "fmt"
+ "io"
+ "net/http"
+ "os"
+
+ "golang.org/x/tools/godoc/vfs"
+)
+
+func New(fs vfs.FileSystem) http.FileSystem {
+ return &httpFS{fs}
+}
+
+type httpFS struct {
+ fs vfs.FileSystem
+}
+
+func (h *httpFS) Open(name string) (http.File, error) {
+ fi, err := h.fs.Stat(name)
+ if err != nil {
+ return nil, err
+ }
+ if fi.IsDir() {
+ return &httpDir{h.fs, name, nil}, nil
+ }
+ f, err := h.fs.Open(name)
+ if err != nil {
+ return nil, err
+ }
+ return &httpFile{h.fs, f, name}, nil
+}
+
+// httpDir implements http.File for a directory in a FileSystem.
+type httpDir struct {
+ fs vfs.FileSystem
+ name string
+ pending []os.FileInfo
+}
+
+func (h *httpDir) Close() error { return nil }
+func (h *httpDir) Stat() (os.FileInfo, error) { return h.fs.Stat(h.name) }
+func (h *httpDir) Read([]byte) (int, error) {
+ return 0, fmt.Errorf("cannot Read from directory %s", h.name)
+}
+
+func (h *httpDir) Seek(offset int64, whence int) (int64, error) {
+ if offset == 0 && whence == 0 {
+ h.pending = nil
+ return 0, nil
+ }
+ return 0, fmt.Errorf("unsupported Seek in directory %s", h.name)
+}
+
+func (h *httpDir) Readdir(count int) ([]os.FileInfo, error) {
+ if h.pending == nil {
+ d, err := h.fs.ReadDir(h.name)
+ if err != nil {
+ return nil, err
+ }
+ if d == nil {
+ d = []os.FileInfo{} // not nil
+ }
+ h.pending = d
+ }
+
+ if len(h.pending) == 0 && count > 0 {
+ return nil, io.EOF
+ }
+ if count <= 0 || count > len(h.pending) {
+ count = len(h.pending)
+ }
+ d := h.pending[:count]
+ h.pending = h.pending[count:]
+ return d, nil
+}
+
+// httpFile implements http.File for a file (not directory) in a FileSystem.
+type httpFile struct {
+ fs vfs.FileSystem
+ vfs.ReadSeekCloser
+ name string
+}
+
+func (h *httpFile) Stat() (os.FileInfo, error) { return h.fs.Stat(h.name) }
+func (h *httpFile) Readdir(int) ([]os.FileInfo, error) {
+ return nil, fmt.Errorf("cannot Readdir from file %s", h.name)
+}
diff --git a/godoc/vfs/mapfs/mapfs.go b/godoc/vfs/mapfs/mapfs.go
new file mode 100644
index 0000000..660b1ca
--- /dev/null
+++ b/godoc/vfs/mapfs/mapfs.go
@@ -0,0 +1,152 @@
+// 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 mapfs file provides an implementation of the FileSystem
+// interface based on the contents of a map[string]string.
+package mapfs // import "golang.org/x/tools/godoc/vfs/mapfs"
+
+import (
+ "io"
+ "os"
+ pathpkg "path"
+ "sort"
+ "strings"
+ "time"
+
+ "golang.org/x/tools/godoc/vfs"
+)
+
+// New returns a new FileSystem from the provided map.
+// Map keys should be forward slash-separated pathnames
+// and not contain a leading slash.
+func New(m map[string]string) vfs.FileSystem {
+ return mapFS(m)
+}
+
+// mapFS is the map based implementation of FileSystem
+type mapFS map[string]string
+
+func (fs mapFS) String() string { return "mapfs" }
+
+func (fs mapFS) Close() error { return nil }
+
+func filename(p string) string {
+ return strings.TrimPrefix(p, "/")
+}
+
+func (fs mapFS) Open(p string) (vfs.ReadSeekCloser, error) {
+ b, ok := fs[filename(p)]
+ if !ok {
+ return nil, os.ErrNotExist
+ }
+ return nopCloser{strings.NewReader(b)}, nil
+}
+
+func fileInfo(name, contents string) os.FileInfo {
+ return mapFI{name: pathpkg.Base(name), size: len(contents)}
+}
+
+func dirInfo(name string) os.FileInfo {
+ return mapFI{name: pathpkg.Base(name), dir: true}
+}
+
+func (fs mapFS) Lstat(p string) (os.FileInfo, error) {
+ b, ok := fs[filename(p)]
+ if ok {
+ return fileInfo(p, b), nil
+ }
+ ents, _ := fs.ReadDir(p)
+ if len(ents) > 0 {
+ return dirInfo(p), nil
+ }
+ return nil, os.ErrNotExist
+}
+
+func (fs mapFS) Stat(p string) (os.FileInfo, error) {
+ return fs.Lstat(p)
+}
+
+// slashdir returns path.Dir(p), but special-cases paths not beginning
+// with a slash to be in the root.
+func slashdir(p string) string {
+ d := pathpkg.Dir(p)
+ if d == "." {
+ return "/"
+ }
+ if strings.HasPrefix(p, "/") {
+ return d
+ }
+ return "/" + d
+}
+
+func (fs mapFS) ReadDir(p string) ([]os.FileInfo, error) {
+ p = pathpkg.Clean(p)
+ var ents []string
+ fim := make(map[string]os.FileInfo) // base -> fi
+ for fn, b := range fs {
+ dir := slashdir(fn)
+ isFile := true
+ var lastBase string
+ for {
+ if dir == p {
+ base := lastBase
+ if isFile {
+ base = pathpkg.Base(fn)
+ }
+ if fim[base] == nil {
+ var fi os.FileInfo
+ if isFile {
+ fi = fileInfo(fn, b)
+ } else {
+ fi = dirInfo(base)
+ }
+ ents = append(ents, base)
+ fim[base] = fi
+ }
+ }
+ if dir == "/" {
+ break
+ } else {
+ isFile = false
+ lastBase = pathpkg.Base(dir)
+ dir = pathpkg.Dir(dir)
+ }
+ }
+ }
+ if len(ents) == 0 {
+ return nil, os.ErrNotExist
+ }
+
+ sort.Strings(ents)
+ var list []os.FileInfo
+ for _, dir := range ents {
+ list = append(list, fim[dir])
+ }
+ return list, nil
+}
+
+// mapFI is the map-based implementation of FileInfo.
+type mapFI struct {
+ name string
+ size int
+ dir bool
+}
+
+func (fi mapFI) IsDir() bool { return fi.dir }
+func (fi mapFI) ModTime() time.Time { return time.Time{} }
+func (fi mapFI) Mode() os.FileMode {
+ if fi.IsDir() {
+ return 0755 | os.ModeDir
+ }
+ return 0444
+}
+func (fi mapFI) Name() string { return pathpkg.Base(fi.name) }
+func (fi mapFI) Size() int64 { return int64(fi.size) }
+func (fi mapFI) Sys() interface{} { return nil }
+
+type nopCloser struct {
+ io.ReadSeeker
+}
+
+func (nc nopCloser) Close() error { return nil }
diff --git a/godoc/vfs/mapfs/mapfs_test.go b/godoc/vfs/mapfs/mapfs_test.go
new file mode 100644
index 0000000..6b7db29
--- /dev/null
+++ b/godoc/vfs/mapfs/mapfs_test.go
@@ -0,0 +1,111 @@
+// 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 mapfs
+
+import (
+ "io/ioutil"
+ "os"
+ "reflect"
+ "testing"
+)
+
+func TestOpenRoot(t *testing.T) {
+ fs := New(map[string]string{
+ "foo/bar/three.txt": "a",
+ "foo/bar.txt": "b",
+ "top.txt": "c",
+ "other-top.txt": "d",
+ })
+ tests := []struct {
+ path string
+ want string
+ }{
+ {"/foo/bar/three.txt", "a"},
+ {"foo/bar/three.txt", "a"},
+ {"foo/bar.txt", "b"},
+ {"top.txt", "c"},
+ {"/top.txt", "c"},
+ {"other-top.txt", "d"},
+ {"/other-top.txt", "d"},
+ }
+ for _, tt := range tests {
+ rsc, err := fs.Open(tt.path)
+ if err != nil {
+ t.Errorf("Open(%q) = %v", tt.path, err)
+ continue
+ }
+ slurp, err := ioutil.ReadAll(rsc)
+ if err != nil {
+ t.Error(err)
+ }
+ if string(slurp) != tt.want {
+ t.Errorf("Read(%q) = %q; want %q", tt.path, tt.want, slurp)
+ }
+ rsc.Close()
+ }
+
+ _, err := fs.Open("/xxxx")
+ if !os.IsNotExist(err) {
+ t.Errorf("ReadDir /xxxx = %v; want os.IsNotExist error", err)
+ }
+}
+
+func TestReaddir(t *testing.T) {
+ fs := New(map[string]string{
+ "foo/bar/three.txt": "333",
+ "foo/bar.txt": "22",
+ "top.txt": "top.txt file",
+ "other-top.txt": "other-top.txt file",
+ })
+ tests := []struct {
+ dir string
+ want []os.FileInfo
+ }{
+ {
+ dir: "/",
+ want: []os.FileInfo{
+ mapFI{name: "foo", dir: true},
+ mapFI{name: "other-top.txt", size: len("other-top.txt file")},
+ mapFI{name: "top.txt", size: len("top.txt file")},
+ },
+ },
+ {
+ dir: "/foo",
+ want: []os.FileInfo{
+ mapFI{name: "bar", dir: true},
+ mapFI{name: "bar.txt", size: 2},
+ },
+ },
+ {
+ dir: "/foo/",
+ want: []os.FileInfo{
+ mapFI{name: "bar", dir: true},
+ mapFI{name: "bar.txt", size: 2},
+ },
+ },
+ {
+ dir: "/foo/bar",
+ want: []os.FileInfo{
+ mapFI{name: "three.txt", size: 3},
+ },
+ },
+ }
+ for _, tt := range tests {
+ fis, err := fs.ReadDir(tt.dir)
+ if err != nil {
+ t.Errorf("ReadDir(%q) = %v", tt.dir, err)
+ continue
+ }
+ if !reflect.DeepEqual(fis, tt.want) {
+ t.Errorf("ReadDir(%q) = %#v; want %#v", tt.dir, fis, tt.want)
+ continue
+ }
+ }
+
+ _, err := fs.ReadDir("/xxxx")
+ if !os.IsNotExist(err) {
+ t.Errorf("ReadDir /xxxx = %v; want os.IsNotExist error", err)
+ }
+}
diff --git a/godoc/vfs/namespace.go b/godoc/vfs/namespace.go
new file mode 100644
index 0000000..dbba20c
--- /dev/null
+++ b/godoc/vfs/namespace.go
@@ -0,0 +1,381 @@
+// 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 vfs
+
+import (
+ "fmt"
+ "io"
+ "os"
+ pathpkg "path"
+ "sort"
+ "strings"
+ "time"
+)
+
+// Setting debugNS = true will enable debugging prints about
+// name space translations.
+const debugNS = false
+
+// A NameSpace is a file system made up of other file systems
+// mounted at specific locations in the name space.
+//
+// The representation is a map from mount point locations
+// to the list of file systems mounted at that location. A traditional
+// Unix mount table would use a single file system per mount point,
+// but we want to be able to mount multiple file systems on a single
+// mount point and have the system behave as if the union of those
+// file systems were present at the mount point.
+// For example, if the OS file system has a Go installation in
+// c:\Go and additional Go path trees in d:\Work1 and d:\Work2, then
+// this name space creates the view we want for the godoc server:
+//
+// NameSpace{
+// "/": {
+// {old: "/", fs: OS(`c:\Go`), new: "/"},
+// },
+// "/src/pkg": {
+// {old: "/src/pkg", fs: OS(`c:\Go`), new: "/src/pkg"},
+// {old: "/src/pkg", fs: OS(`d:\Work1`), new: "/src"},
+// {old: "/src/pkg", fs: OS(`d:\Work2`), new: "/src"},
+// },
+// }
+//
+// This is created by executing:
+//
+// ns := NameSpace{}
+// ns.Bind("/", OS(`c:\Go`), "/", BindReplace)
+// ns.Bind("/src/pkg", OS(`d:\Work1`), "/src", BindAfter)
+// ns.Bind("/src/pkg", OS(`d:\Work2`), "/src", BindAfter)
+//
+// A particular mount point entry is a triple (old, fs, new), meaning that to
+// operate on a path beginning with old, replace that prefix (old) with new
+// and then pass that path to the FileSystem implementation fs.
+//
+// Given this name space, a ReadDir of /src/pkg/code will check each prefix
+// of the path for a mount point (first /src/pkg/code, then /src/pkg, then /src,
+// then /), stopping when it finds one. For the above example, /src/pkg/code
+// will find the mount point at /src/pkg:
+//
+// {old: "/src/pkg", fs: OS(`c:\Go`), new: "/src/pkg"},
+// {old: "/src/pkg", fs: OS(`d:\Work1`), new: "/src"},
+// {old: "/src/pkg", fs: OS(`d:\Work2`), new: "/src"},
+//
+// ReadDir will when execute these three calls and merge the results:
+//
+// OS(`c:\Go`).ReadDir("/src/pkg/code")
+// OS(`d:\Work1').ReadDir("/src/code")
+// OS(`d:\Work2').ReadDir("/src/code")
+//
+// Note that the "/src/pkg" in "/src/pkg/code" has been replaced by
+// just "/src" in the final two calls.
+//
+// OS is itself an implementation of a file system: it implements
+// OS(`c:\Go`).ReadDir("/src/pkg/code") as ioutil.ReadDir(`c:\Go\src\pkg\code`).
+//
+// Because the new path is evaluated by fs (here OS(root)), another way
+// to read the mount table is to mentally combine fs+new, so that this table:
+//
+// {old: "/src/pkg", fs: OS(`c:\Go`), new: "/src/pkg"},
+// {old: "/src/pkg", fs: OS(`d:\Work1`), new: "/src"},
+// {old: "/src/pkg", fs: OS(`d:\Work2`), new: "/src"},
+//
+// reads as:
+//
+// "/src/pkg" -> c:\Go\src\pkg
+// "/src/pkg" -> d:\Work1\src
+// "/src/pkg" -> d:\Work2\src
+//
+// An invariant (a redundancy) of the name space representation is that
+// ns[mtpt][i].old is always equal to mtpt (in the example, ns["/src/pkg"]'s
+// mount table entries always have old == "/src/pkg"). The 'old' field is
+// useful to callers, because they receive just a []mountedFS and not any
+// other indication of which mount point was found.
+//
+type NameSpace map[string][]mountedFS
+
+// A mountedFS handles requests for path by replacing
+// a prefix 'old' with 'new' and then calling the fs methods.
+type mountedFS struct {
+ old string
+ fs FileSystem
+ new string
+}
+
+// hasPathPrefix returns true if x == y or x == y + "/" + more
+func hasPathPrefix(x, y string) bool {
+ return x == y || strings.HasPrefix(x, y) && (strings.HasSuffix(y, "/") || strings.HasPrefix(x[len(y):], "/"))
+}
+
+// translate translates path for use in m, replacing old with new.
+//
+// mountedFS{"/src/pkg", fs, "/src"}.translate("/src/pkg/code") == "/src/code".
+func (m mountedFS) translate(path string) string {
+ path = pathpkg.Clean("/" + path)
+ if !hasPathPrefix(path, m.old) {
+ panic("translate " + path + " but old=" + m.old)
+ }
+ return pathpkg.Join(m.new, path[len(m.old):])
+}
+
+func (NameSpace) String() string {
+ return "ns"
+}
+
+// Fprint writes a text representation of the name space to w.
+func (ns NameSpace) Fprint(w io.Writer) {
+ fmt.Fprint(w, "name space {\n")
+ var all []string
+ for mtpt := range ns {
+ all = append(all, mtpt)
+ }
+ sort.Strings(all)
+ for _, mtpt := range all {
+ fmt.Fprintf(w, "\t%s:\n", mtpt)
+ for _, m := range ns[mtpt] {
+ fmt.Fprintf(w, "\t\t%s %s\n", m.fs, m.new)
+ }
+ }
+ fmt.Fprint(w, "}\n")
+}
+
+// clean returns a cleaned, rooted path for evaluation.
+// It canonicalizes the path so that we can use string operations
+// to analyze it.
+func (NameSpace) clean(path string) string {
+ return pathpkg.Clean("/" + path)
+}
+
+type BindMode int
+
+const (
+ BindReplace BindMode = iota
+ BindBefore
+ BindAfter
+)
+
+// Bind causes references to old to redirect to the path new in newfs.
+// If mode is BindReplace, old redirections are discarded.
+// If mode is BindBefore, this redirection takes priority over existing ones,
+// but earlier ones are still consulted for paths that do not exist in newfs.
+// If mode is BindAfter, this redirection happens only after existing ones
+// have been tried and failed.
+func (ns NameSpace) Bind(old string, newfs FileSystem, new string, mode BindMode) {
+ old = ns.clean(old)
+ new = ns.clean(new)
+ m := mountedFS{old, newfs, new}
+ var mtpt []mountedFS
+ switch mode {
+ case BindReplace:
+ mtpt = append(mtpt, m)
+ case BindAfter:
+ mtpt = append(mtpt, ns.resolve(old)...)
+ mtpt = append(mtpt, m)
+ case BindBefore:
+ mtpt = append(mtpt, m)
+ mtpt = append(mtpt, ns.resolve(old)...)
+ }
+
+ // Extend m.old, m.new in inherited mount point entries.
+ for i := range mtpt {
+ m := &mtpt[i]
+ if m.old != old {
+ if !hasPathPrefix(old, m.old) {
+ // This should not happen. If it does, panic so
+ // that we can see the call trace that led to it.
+ panic(fmt.Sprintf("invalid Bind: old=%q m={%q, %s, %q}", old, m.old, m.fs.String(), m.new))
+ }
+ suffix := old[len(m.old):]
+ m.old = pathpkg.Join(m.old, suffix)
+ m.new = pathpkg.Join(m.new, suffix)
+ }
+ }
+
+ ns[old] = mtpt
+}
+
+// resolve resolves a path to the list of mountedFS to use for path.
+func (ns NameSpace) resolve(path string) []mountedFS {
+ path = ns.clean(path)
+ for {
+ if m := ns[path]; m != nil {
+ if debugNS {
+ fmt.Printf("resolve %s: %v\n", path, m)
+ }
+ return m
+ }
+ if path == "/" {
+ break
+ }
+ path = pathpkg.Dir(path)
+ }
+ return nil
+}
+
+// Open implements the FileSystem Open method.
+func (ns NameSpace) Open(path string) (ReadSeekCloser, error) {
+ var err error
+ for _, m := range ns.resolve(path) {
+ if debugNS {
+ fmt.Printf("tx %s: %v\n", path, m.translate(path))
+ }
+ r, err1 := m.fs.Open(m.translate(path))
+ if err1 == nil {
+ return r, nil
+ }
+ if err == nil {
+ err = err1
+ }
+ }
+ if err == nil {
+ err = &os.PathError{Op: "open", Path: path, Err: os.ErrNotExist}
+ }
+ return nil, err
+}
+
+// stat implements the FileSystem Stat and Lstat methods.
+func (ns NameSpace) stat(path string, f func(FileSystem, string) (os.FileInfo, error)) (os.FileInfo, error) {
+ var err error
+ for _, m := range ns.resolve(path) {
+ fi, err1 := f(m.fs, m.translate(path))
+ if err1 == nil {
+ return fi, nil
+ }
+ if err == nil {
+ err = err1
+ }
+ }
+ if err == nil {
+ err = &os.PathError{Op: "stat", Path: path, Err: os.ErrNotExist}
+ }
+ return nil, err
+}
+
+func (ns NameSpace) Stat(path string) (os.FileInfo, error) {
+ return ns.stat(path, FileSystem.Stat)
+}
+
+func (ns NameSpace) Lstat(path string) (os.FileInfo, error) {
+ return ns.stat(path, FileSystem.Lstat)
+}
+
+// dirInfo is a trivial implementation of os.FileInfo for a directory.
+type dirInfo string
+
+func (d dirInfo) Name() string { return string(d) }
+func (d dirInfo) Size() int64 { return 0 }
+func (d dirInfo) Mode() os.FileMode { return os.ModeDir | 0555 }
+func (d dirInfo) ModTime() time.Time { return startTime }
+func (d dirInfo) IsDir() bool { return true }
+func (d dirInfo) Sys() interface{} { return nil }
+
+var startTime = time.Now()
+
+// ReadDir implements the FileSystem ReadDir method. It's where most of the magic is.
+// (The rest is in resolve.)
+//
+// Logically, ReadDir must return the union of all the directories that are named
+// by path. In order to avoid misinterpreting Go packages, of all the directories
+// that contain Go source code, we only include the files from the first,
+// but we include subdirectories from all.
+//
+// ReadDir must also return directory entries needed to reach mount points.
+// If the name space looks like the example in the type NameSpace comment,
+// but c:\Go does not have a src/pkg subdirectory, we still want to be able
+// to find that subdirectory, because we've mounted d:\Work1 and d:\Work2
+// there. So if we don't see "src" in the directory listing for c:\Go, we add an
+// entry for it before returning.
+//
+func (ns NameSpace) ReadDir(path string) ([]os.FileInfo, error) {
+ path = ns.clean(path)
+
+ var (
+ haveGo = false
+ haveName = map[string]bool{}
+ all []os.FileInfo
+ err error
+ first []os.FileInfo
+ )
+
+ for _, m := range ns.resolve(path) {
+ dir, err1 := m.fs.ReadDir(m.translate(path))
+ if err1 != nil {
+ if err == nil {
+ err = err1
+ }
+ continue
+ }
+
+ if dir == nil {
+ dir = []os.FileInfo{}
+ }
+
+ if first == nil {
+ first = dir
+ }
+
+ // If we don't yet have Go files in 'all' and this directory
+ // has some, add all the files from this directory.
+ // Otherwise, only add subdirectories.
+ useFiles := false
+ if !haveGo {
+ for _, d := range dir {
+ if strings.HasSuffix(d.Name(), ".go") {
+ useFiles = true
+ haveGo = true
+ break
+ }
+ }
+ }
+
+ for _, d := range dir {
+ name := d.Name()
+ if (d.IsDir() || useFiles) && !haveName[name] {
+ haveName[name] = true
+ all = append(all, d)
+ }
+ }
+ }
+
+ // We didn't find any directories containing Go files.
+ // If some directory returned successfully, use that.
+ if !haveGo {
+ for _, d := range first {
+ if !haveName[d.Name()] {
+ haveName[d.Name()] = true
+ all = append(all, d)
+ }
+ }
+ }
+
+ // Built union. Add any missing directories needed to reach mount points.
+ for old := range ns {
+ if hasPathPrefix(old, path) && old != path {
+ // Find next element after path in old.
+ elem := old[len(path):]
+ elem = strings.TrimPrefix(elem, "/")
+ if i := strings.Index(elem, "/"); i >= 0 {
+ elem = elem[:i]
+ }
+ if !haveName[elem] {
+ haveName[elem] = true
+ all = append(all, dirInfo(elem))
+ }
+ }
+ }
+
+ if len(all) == 0 {
+ return nil, err
+ }
+
+ sort.Sort(byName(all))
+ return all, nil
+}
+
+// byName implements sort.Interface.
+type byName []os.FileInfo
+
+func (f byName) Len() int { return len(f) }
+func (f byName) Less(i, j int) bool { return f[i].Name() < f[j].Name() }
+func (f byName) Swap(i, j int) { f[i], f[j] = f[j], f[i] }
diff --git a/godoc/vfs/os.go b/godoc/vfs/os.go
new file mode 100644
index 0000000..fa98142
--- /dev/null
+++ b/godoc/vfs/os.go
@@ -0,0 +1,65 @@
+// 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 vfs
+
+import (
+ "fmt"
+ "io/ioutil"
+ "os"
+ pathpkg "path"
+ "path/filepath"
+)
+
+// OS returns an implementation of FileSystem reading from the
+// tree rooted at root. Recording a root is convenient everywhere
+// but necessary on Windows, because the slash-separated path
+// passed to Open has no way to specify a drive letter. Using a root
+// lets code refer to OS(`c:\`), OS(`d:\`) and so on.
+func OS(root string) FileSystem {
+ return osFS(root)
+}
+
+type osFS string
+
+func (root osFS) String() string { return "os(" + string(root) + ")" }
+
+func (root osFS) resolve(path string) string {
+ // Clean the path so that it cannot possibly begin with ../.
+ // If it did, the result of filepath.Join would be outside the
+ // tree rooted at root. We probably won't ever see a path
+ // with .. in it, but be safe anyway.
+ path = pathpkg.Clean("/" + path)
+
+ return filepath.Join(string(root), path)
+}
+
+func (root osFS) Open(path string) (ReadSeekCloser, error) {
+ f, err := os.Open(root.resolve(path))
+ if err != nil {
+ return nil, err
+ }
+ fi, err := f.Stat()
+ if err != nil {
+ f.Close()
+ return nil, err
+ }
+ if fi.IsDir() {
+ f.Close()
+ return nil, fmt.Errorf("Open: %s is a directory", path)
+ }
+ return f, nil
+}
+
+func (root osFS) Lstat(path string) (os.FileInfo, error) {
+ return os.Lstat(root.resolve(path))
+}
+
+func (root osFS) Stat(path string) (os.FileInfo, error) {
+ return os.Stat(root.resolve(path))
+}
+
+func (root osFS) ReadDir(path string) ([]os.FileInfo, error) {
+ return ioutil.ReadDir(root.resolve(path)) // is sorted
+}
diff --git a/godoc/vfs/vfs.go b/godoc/vfs/vfs.go
new file mode 100644
index 0000000..ad06b1a
--- /dev/null
+++ b/godoc/vfs/vfs.go
@@ -0,0 +1,45 @@
+// 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 vfs defines types for abstract file system access and provides an
+// implementation accessing the file system of the underlying OS.
+package vfs // import "golang.org/x/tools/godoc/vfs"
+
+import (
+ "io"
+ "io/ioutil"
+ "os"
+)
+
+// The FileSystem interface specifies the methods godoc is using
+// to access the file system for which it serves documentation.
+type FileSystem interface {
+ Opener
+ Lstat(path string) (os.FileInfo, error)
+ Stat(path string) (os.FileInfo, error)
+ ReadDir(path string) ([]os.FileInfo, error)
+ String() string
+}
+
+// Opener is a minimal virtual filesystem that can only open regular files.
+type Opener interface {
+ Open(name string) (ReadSeekCloser, error)
+}
+
+// A ReadSeekCloser can Read, Seek, and Close.
+type ReadSeekCloser interface {
+ io.Reader
+ io.Seeker
+ io.Closer
+}
+
+// ReadFile reads the file named by path from fs and returns the contents.
+func ReadFile(fs Opener, path string) ([]byte, error) {
+ rc, err := fs.Open(path)
+ if err != nil {
+ return nil, err
+ }
+ defer rc.Close()
+ return ioutil.ReadAll(rc)
+}
diff --git a/godoc/vfs/zipfs/zipfs.go b/godoc/vfs/zipfs/zipfs.go
new file mode 100644
index 0000000..87eaf8d
--- /dev/null
+++ b/godoc/vfs/zipfs/zipfs.go
@@ -0,0 +1,237 @@
+// 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 zipfs file provides an implementation of the FileSystem
+// interface based on the contents of a .zip file.
+//
+// Assumptions:
+//
+// - The file paths stored in the zip file must use a slash ('/') as path
+// separator; and they must be relative (i.e., they must not start with
+// a '/' - this is usually the case if the file was created w/o special
+// options).
+// - The zip file system treats the file paths found in the zip internally
+// like absolute paths w/o a leading '/'; i.e., the paths are considered
+// relative to the root of the file system.
+// - All path arguments to file system methods must be absolute paths.
+package zipfs // import "golang.org/x/tools/godoc/vfs/zipfs"
+
+import (
+ "archive/zip"
+ "fmt"
+ "io"
+ "os"
+ "path"
+ "sort"
+ "strings"
+ "time"
+
+ "golang.org/x/tools/godoc/vfs"
+)
+
+// zipFI is the zip-file based implementation of FileInfo
+type zipFI struct {
+ name string // directory-local name
+ file *zip.File // nil for a directory
+}
+
+func (fi zipFI) Name() string {
+ return fi.name
+}
+
+func (fi zipFI) Size() int64 {
+ if f := fi.file; f != nil {
+ return int64(f.UncompressedSize)
+ }
+ return 0 // directory
+}
+
+func (fi zipFI) ModTime() time.Time {
+ if f := fi.file; f != nil {
+ return f.ModTime()
+ }
+ return time.Time{} // directory has no modified time entry
+}
+
+func (fi zipFI) Mode() os.FileMode {
+ if fi.file == nil {
+ // Unix directories typically are executable, hence 555.
+ return os.ModeDir | 0555
+ }
+ return 0444
+}
+
+func (fi zipFI) IsDir() bool {
+ return fi.file == nil
+}
+
+func (fi zipFI) Sys() interface{} {
+ return nil
+}
+
+// zipFS is the zip-file based implementation of FileSystem
+type zipFS struct {
+ *zip.ReadCloser
+ list zipList
+ name string
+}
+
+func (fs *zipFS) String() string {
+ return "zip(" + fs.name + ")"
+}
+
+func (fs *zipFS) Close() error {
+ fs.list = nil
+ return fs.ReadCloser.Close()
+}
+
+func zipPath(name string) string {
+ name = path.Clean(name)
+ if !path.IsAbs(name) {
+ panic(fmt.Sprintf("stat: not an absolute path: %s", name))
+ }
+ return name[1:] // strip leading '/'
+}
+
+func (fs *zipFS) stat(abspath string) (int, zipFI, error) {
+ i, exact := fs.list.lookup(abspath)
+ if i < 0 {
+ // abspath has leading '/' stripped - print it explicitly
+ return -1, zipFI{}, fmt.Errorf("file not found: /%s", abspath)
+ }
+ _, name := path.Split(abspath)
+ var file *zip.File
+ if exact {
+ file = fs.list[i] // exact match found - must be a file
+ }
+ return i, zipFI{name, file}, nil
+}
+
+func (fs *zipFS) Open(abspath string) (vfs.ReadSeekCloser, error) {
+ _, fi, err := fs.stat(zipPath(abspath))
+ if err != nil {
+ return nil, err
+ }
+ if fi.IsDir() {
+ return nil, fmt.Errorf("Open: %s is a directory", abspath)
+ }
+ r, err := fi.file.Open()
+ if err != nil {
+ return nil, err
+ }
+ return &zipSeek{fi.file, r}, nil
+}
+
+type zipSeek struct {
+ file *zip.File
+ io.ReadCloser
+}
+
+func (f *zipSeek) Seek(offset int64, whence int) (int64, error) {
+ if whence == 0 && offset == 0 {
+ r, err := f.file.Open()
+ if err != nil {
+ return 0, err
+ }
+ f.Close()
+ f.ReadCloser = r
+ return 0, nil
+ }
+ return 0, fmt.Errorf("unsupported Seek in %s", f.file.Name)
+}
+
+func (fs *zipFS) Lstat(abspath string) (os.FileInfo, error) {
+ _, fi, err := fs.stat(zipPath(abspath))
+ return fi, err
+}
+
+func (fs *zipFS) Stat(abspath string) (os.FileInfo, error) {
+ _, fi, err := fs.stat(zipPath(abspath))
+ return fi, err
+}
+
+func (fs *zipFS) ReadDir(abspath string) ([]os.FileInfo, error) {
+ path := zipPath(abspath)
+ i, fi, err := fs.stat(path)
+ if err != nil {
+ return nil, err
+ }
+ if !fi.IsDir() {
+ return nil, fmt.Errorf("ReadDir: %s is not a directory", abspath)
+ }
+
+ var list []os.FileInfo
+ dirname := path + "/"
+ prevname := ""
+ for _, e := range fs.list[i:] {
+ if !strings.HasPrefix(e.Name, dirname) {
+ break // not in the same directory anymore
+ }
+ name := e.Name[len(dirname):] // local name
+ file := e
+ if i := strings.IndexRune(name, '/'); i >= 0 {
+ // We infer directories from files in subdirectories.
+ // If we have x/y, return a directory entry for x.
+ name = name[0:i] // keep local directory name only
+ file = nil
+ }
+ // If we have x/y and x/z, don't return two directory entries for x.
+ // TODO(gri): It should be possible to do this more efficiently
+ // by determining the (fs.list) range of local directory entries
+ // (via two binary searches).
+ if name != prevname {
+ list = append(list, zipFI{name, file})
+ prevname = name
+ }
+ }
+
+ return list, nil
+}
+
+func New(rc *zip.ReadCloser, name string) vfs.FileSystem {
+ list := make(zipList, len(rc.File))
+ copy(list, rc.File) // sort a copy of rc.File
+ sort.Sort(list)
+ return &zipFS{rc, list, name}
+}
+
+type zipList []*zip.File
+
+// zipList implements sort.Interface
+func (z zipList) Len() int { return len(z) }
+func (z zipList) Less(i, j int) bool { return z[i].Name < z[j].Name }
+func (z zipList) Swap(i, j int) { z[i], z[j] = z[j], z[i] }
+
+// lookup returns the smallest index of an entry with an exact match
+// for name, or an inexact match starting with name/. If there is no
+// such entry, the result is -1, false.
+func (z zipList) lookup(name string) (index int, exact bool) {
+ // look for exact match first (name comes before name/ in z)
+ i := sort.Search(len(z), func(i int) bool {
+ return name <= z[i].Name
+ })
+ if i >= len(z) {
+ return -1, false
+ }
+ // 0 <= i < len(z)
+ if z[i].Name == name {
+ return i, true
+ }
+
+ // look for inexact match (must be in z[i:], if present)
+ z = z[i:]
+ name += "/"
+ j := sort.Search(len(z), func(i int) bool {
+ return name <= z[i].Name
+ })
+ if j >= len(z) {
+ return -1, false
+ }
+ // 0 <= j < len(z)
+ if strings.HasPrefix(z[j].Name, name) {
+ return i + j, false
+ }
+
+ return -1, false
+}
diff --git a/imports/fix.go b/imports/fix.go
new file mode 100644
index 0000000..3ccee0e
--- /dev/null
+++ b/imports/fix.go
@@ -0,0 +1,387 @@
+// 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 imports
+
+import (
+ "fmt"
+ "go/ast"
+ "go/build"
+ "go/parser"
+ "go/token"
+ "os"
+ "path"
+ "path/filepath"
+ "strings"
+ "sync"
+
+ "golang.org/x/tools/go/ast/astutil"
+)
+
+// importToGroup is a list of functions which map from an import path to
+// a group number.
+var importToGroup = []func(importPath string) (num int, ok bool){
+ func(importPath string) (num int, ok bool) {
+ if strings.HasPrefix(importPath, "appengine") {
+ return 2, true
+ }
+ return
+ },
+ func(importPath string) (num int, ok bool) {
+ if strings.Contains(importPath, ".") {
+ return 1, true
+ }
+ return
+ },
+}
+
+func importGroup(importPath string) int {
+ for _, fn := range importToGroup {
+ if n, ok := fn(importPath); ok {
+ return n
+ }
+ }
+ return 0
+}
+
+func fixImports(fset *token.FileSet, f *ast.File) (added []string, err error) {
+ // refs are a set of possible package references currently unsatisfied by imports.
+ // first key: either base package (e.g. "fmt") or renamed package
+ // second key: referenced package symbol (e.g. "Println")
+ refs := make(map[string]map[string]bool)
+
+ // decls are the current package imports. key is base package or renamed package.
+ decls := make(map[string]*ast.ImportSpec)
+
+ // collect potential uses of packages.
+ var visitor visitFn
+ visitor = visitFn(func(node ast.Node) ast.Visitor {
+ if node == nil {
+ return visitor
+ }
+ switch v := node.(type) {
+ case *ast.ImportSpec:
+ if v.Name != nil {
+ decls[v.Name.Name] = v
+ } else {
+ local := importPathToName(strings.Trim(v.Path.Value, `\"`))
+ decls[local] = v
+ }
+ case *ast.SelectorExpr:
+ xident, ok := v.X.(*ast.Ident)
+ if !ok {
+ break
+ }
+ if xident.Obj != nil {
+ // if the parser can resolve it, it's not a package ref
+ break
+ }
+ pkgName := xident.Name
+ if refs[pkgName] == nil {
+ refs[pkgName] = make(map[string]bool)
+ }
+ if decls[pkgName] == nil {
+ refs[pkgName][v.Sel.Name] = true
+ }
+ }
+ return visitor
+ })
+ ast.Walk(visitor, f)
+
+ // Nil out any unused ImportSpecs, to be removed in following passes
+ unusedImport := map[string]bool{}
+ for pkg, is := range decls {
+ if refs[pkg] == nil && pkg != "_" && pkg != "." {
+ unusedImport[strings.Trim(is.Path.Value, `"`)] = true
+ }
+ }
+ for ipath := range unusedImport {
+ if ipath == "C" {
+ // Don't remove cgo stuff.
+ continue
+ }
+ astutil.DeleteImport(fset, f, ipath)
+ }
+
+ // Search for imports matching potential package references.
+ searches := 0
+ type result struct {
+ ipath string
+ name string
+ err error
+ }
+ results := make(chan result)
+ for pkgName, symbols := range refs {
+ if len(symbols) == 0 {
+ continue // skip over packages already imported
+ }
+ go func(pkgName string, symbols map[string]bool) {
+ ipath, rename, err := findImport(pkgName, symbols)
+ r := result{ipath: ipath, err: err}
+ if rename {
+ r.name = pkgName
+ }
+ results <- r
+ }(pkgName, symbols)
+ searches++
+ }
+ for i := 0; i < searches; i++ {
+ result := <-results
+ if result.err != nil {
+ return nil, result.err
+ }
+ if result.ipath != "" {
+ if result.name != "" {
+ astutil.AddNamedImport(fset, f, result.name, result.ipath)
+ } else {
+ astutil.AddImport(fset, f, result.ipath)
+ }
+ added = append(added, result.ipath)
+ }
+ }
+
+ return added, nil
+}
+
+// importPathToName returns the package name for the given import path.
+var importPathToName = importPathToNameGoPath
+
+// importPathToNameBasic assumes the package name is the base of import path.
+func importPathToNameBasic(importPath string) (packageName string) {
+ return path.Base(importPath)
+}
+
+// importPathToNameGoPath finds out the actual package name, as declared in its .go files.
+// If there's a problem, it falls back to using importPathToNameBasic.
+func importPathToNameGoPath(importPath string) (packageName string) {
+ if buildPkg, err := build.Import(importPath, "", 0); err == nil {
+ return buildPkg.Name
+ } else {
+ return importPathToNameBasic(importPath)
+ }
+}
+
+type pkg struct {
+ importpath string // full pkg import path, e.g. "net/http"
+ dir string // absolute file path to pkg directory e.g. "/usr/lib/go/src/fmt"
+}
+
+var pkgIndexOnce sync.Once
+
+var pkgIndex struct {
+ sync.Mutex
+ m map[string][]pkg // shortname => []pkg, e.g "http" => "net/http"
+}
+
+// gate is a semaphore for limiting concurrency.
+type gate chan struct{}
+
+func (g gate) enter() { g <- struct{}{} }
+func (g gate) leave() { <-g }
+
+// fsgate protects the OS & filesystem from too much concurrency.
+// Too much disk I/O -> too many threads -> swapping and bad scheduling.
+var fsgate = make(gate, 8)
+
+func loadPkgIndex() {
+ pkgIndex.Lock()
+ pkgIndex.m = make(map[string][]pkg)
+ pkgIndex.Unlock()
+
+ var wg sync.WaitGroup
+ for _, path := range build.Default.SrcDirs() {
+ fsgate.enter()
+ f, err := os.Open(path)
+ if err != nil {
+ fsgate.leave()
+ fmt.Fprint(os.Stderr, err)
+ continue
+ }
+ children, err := f.Readdir(-1)
+ f.Close()
+ fsgate.leave()
+ if err != nil {
+ fmt.Fprint(os.Stderr, err)
+ continue
+ }
+ for _, child := range children {
+ if child.IsDir() {
+ wg.Add(1)
+ go func(path, name string) {
+ defer wg.Done()
+ loadPkg(&wg, path, name)
+ }(path, child.Name())
+ }
+ }
+ }
+ wg.Wait()
+}
+
+func loadPkg(wg *sync.WaitGroup, root, pkgrelpath string) {
+ importpath := filepath.ToSlash(pkgrelpath)
+ dir := filepath.Join(root, importpath)
+
+ fsgate.enter()
+ defer fsgate.leave()
+ pkgDir, err := os.Open(dir)
+ if err != nil {
+ return
+ }
+ children, err := pkgDir.Readdir(-1)
+ pkgDir.Close()
+ if err != nil {
+ return
+ }
+ // hasGo tracks whether a directory actually appears to be a
+ // Go source code directory. If $GOPATH == $HOME, and
+ // $HOME/src has lots of other large non-Go projects in it,
+ // then the calls to importPathToName below can be expensive.
+ hasGo := false
+ for _, child := range children {
+ // Avoid .foo, _foo, and testdata directory trees.
+ name := child.Name()
+ if name == "" || name[0] == '.' || name[0] == '_' || name == "testdata" {
+ continue
+ }
+ if strings.HasSuffix(name, ".go") {
+ hasGo = true
+ }
+ if child.IsDir() {
+ wg.Add(1)
+ go func(root, name string) {
+ defer wg.Done()
+ loadPkg(wg, root, name)
+ }(root, filepath.Join(importpath, name))
+ }
+ }
+ if hasGo {
+ shortName := importPathToName(importpath)
+ pkgIndex.Lock()
+ pkgIndex.m[shortName] = append(pkgIndex.m[shortName], pkg{
+ importpath: importpath,
+ dir: dir,
+ })
+ pkgIndex.Unlock()
+ }
+
+}
+
+// loadExports returns a list exports for a package.
+var loadExports = loadExportsGoPath
+
+func loadExportsGoPath(dir string) map[string]bool {
+ exports := make(map[string]bool)
+ buildPkg, err := build.ImportDir(dir, 0)
+ if err != nil {
+ if strings.Contains(err.Error(), "no buildable Go source files in") {
+ return nil
+ }
+ fmt.Fprintf(os.Stderr, "could not import %q: %v\n", dir, err)
+ return nil
+ }
+ fset := token.NewFileSet()
+ for _, files := range [...][]string{buildPkg.GoFiles, buildPkg.CgoFiles} {
+ for _, file := range files {
+ f, err := parser.ParseFile(fset, filepath.Join(dir, file), nil, 0)
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "could not parse %q: %v\n", file, err)
+ continue
+ }
+ for name := range f.Scope.Objects {
+ if ast.IsExported(name) {
+ exports[name] = true
+ }
+ }
+ }
+ }
+ return exports
+}
+
+// findImport searches for a package with the given symbols.
+// If no package is found, findImport returns "".
+// Declared as a variable rather than a function so goimports can be easily
+// extended by adding a file with an init function.
+var findImport = findImportGoPath
+
+func findImportGoPath(pkgName string, symbols map[string]bool) (string, bool, error) {
+ // Fast path for the standard library.
+ // In the common case we hopefully never have to scan the GOPATH, which can
+ // be slow with moving disks.
+ if pkg, rename, ok := findImportStdlib(pkgName, symbols); ok {
+ return pkg, rename, nil
+ }
+
+ // TODO(sameer): look at the import lines for other Go files in the
+ // local directory, since the user is likely to import the same packages
+ // in the current Go file. Return rename=true when the other Go files
+ // use a renamed package that's also used in the current file.
+
+ pkgIndexOnce.Do(loadPkgIndex)
+
+ // Collect exports for packages with matching names.
+ var wg sync.WaitGroup
+ var pkgsMu sync.Mutex // guards pkgs
+ // full importpath => exported symbol => True
+ // e.g. "net/http" => "Client" => True
+ pkgs := make(map[string]map[string]bool)
+ pkgIndex.Lock()
+ for _, pkg := range pkgIndex.m[pkgName] {
+ wg.Add(1)
+ go func(importpath, dir string) {
+ defer wg.Done()
+ exports := loadExports(dir)
+ if exports != nil {
+ pkgsMu.Lock()
+ pkgs[importpath] = exports
+ pkgsMu.Unlock()
+ }
+ }(pkg.importpath, pkg.dir)
+ }
+ pkgIndex.Unlock()
+ wg.Wait()
+
+ // Filter out packages missing required exported symbols.
+ for symbol := range symbols {
+ for importpath, exports := range pkgs {
+ if !exports[symbol] {
+ delete(pkgs, importpath)
+ }
+ }
+ }
+ if len(pkgs) == 0 {
+ return "", false, nil
+ }
+
+ // If there are multiple candidate packages, the shortest one wins.
+ // This is a heuristic to prefer the standard library (e.g. "bytes")
+ // over e.g. "github.com/foo/bar/bytes".
+ shortest := ""
+ for importPath := range pkgs {
+ if shortest == "" || len(importPath) < len(shortest) {
+ shortest = importPath
+ }
+ }
+ return shortest, false, nil
+}
+
+type visitFn func(node ast.Node) ast.Visitor
+
+func (fn visitFn) Visit(node ast.Node) ast.Visitor {
+ return fn(node)
+}
+
+func findImportStdlib(shortPkg string, symbols map[string]bool) (importPath string, rename, ok bool) {
+ for symbol := range symbols {
+ path := stdlib[shortPkg+"."+symbol]
+ if path == "" {
+ return "", false, false
+ }
+ if importPath != "" && importPath != path {
+ // Ambiguous. Symbols pointed to different things.
+ return "", false, false
+ }
+ importPath = path
+ }
+ return importPath, false, importPath != ""
+}
diff --git a/imports/fix_test.go b/imports/fix_test.go
new file mode 100644
index 0000000..f087bc7
--- /dev/null
+++ b/imports/fix_test.go
@@ -0,0 +1,862 @@
+// 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 imports
+
+import (
+ "flag"
+ "go/build"
+ "io/ioutil"
+ "os"
+ "path/filepath"
+ "sync"
+ "testing"
+)
+
+var only = flag.String("only", "", "If non-empty, the fix test to run")
+
+var tests = []struct {
+ name string
+ in, out string
+}{
+ // Adding an import to an existing parenthesized import
+ {
+ name: "factored_imports_add",
+ in: `package foo
+import (
+ "fmt"
+)
+func bar() {
+var b bytes.Buffer
+fmt.Println(b.String())
+}
+`,
+ out: `package foo
+
+import (
+ "bytes"
+ "fmt"
+)
+
+func bar() {
+ var b bytes.Buffer
+ fmt.Println(b.String())
+}
+`,
+ },
+
+ // Adding an import to an existing parenthesized import,
+ // verifying it goes into the first section.
+ {
+ name: "factored_imports_add_first_sec",
+ in: `package foo
+import (
+ "fmt"
+
+ "appengine"
+)
+func bar() {
+var b bytes.Buffer
+_ = appengine.IsDevServer
+fmt.Println(b.String())
+}
+`,
+ out: `package foo
+
+import (
+ "bytes"
+ "fmt"
+
+ "appengine"
+)
+
+func bar() {
+ var b bytes.Buffer
+ _ = appengine.IsDevServer
+ fmt.Println(b.String())
+}
+`,
+ },
+
+ // Adding an import to an existing parenthesized import,
+ // verifying it goes into the first section. (test 2)
+ {
+ name: "factored_imports_add_first_sec_2",
+ in: `package foo
+import (
+ "fmt"
+
+ "appengine"
+)
+func bar() {
+_ = math.NaN
+_ = fmt.Sprintf
+_ = appengine.IsDevServer
+}
+`,
+ out: `package foo
+
+import (
+ "fmt"
+ "math"
+
+ "appengine"
+)
+
+func bar() {
+ _ = math.NaN
+ _ = fmt.Sprintf
+ _ = appengine.IsDevServer
+}
+`,
+ },
+
+ // Adding a new import line, without parens
+ {
+ name: "add_import_section",
+ in: `package foo
+func bar() {
+var b bytes.Buffer
+}
+`,
+ out: `package foo
+
+import "bytes"
+
+func bar() {
+ var b bytes.Buffer
+}
+`,
+ },
+
+ // Adding two new imports, which should make a parenthesized import decl.
+ {
+ name: "add_import_paren_section",
+ in: `package foo
+func bar() {
+_, _ := bytes.Buffer, zip.NewReader
+}
+`,
+ out: `package foo
+
+import (
+ "archive/zip"
+ "bytes"
+)
+
+func bar() {
+ _, _ := bytes.Buffer, zip.NewReader
+}
+`,
+ },
+
+ // Make sure we don't add things twice
+ {
+ name: "no_double_add",
+ in: `package foo
+func bar() {
+_, _ := bytes.Buffer, bytes.NewReader
+}
+`,
+ out: `package foo
+
+import "bytes"
+
+func bar() {
+ _, _ := bytes.Buffer, bytes.NewReader
+}
+`,
+ },
+
+ // Remove unused imports, 1 of a factored block
+ {
+ name: "remove_unused_1_of_2",
+ in: `package foo
+import (
+"bytes"
+"fmt"
+)
+
+func bar() {
+_, _ := bytes.Buffer, bytes.NewReader
+}
+`,
+ out: `package foo
+
+import "bytes"
+
+func bar() {
+ _, _ := bytes.Buffer, bytes.NewReader
+}
+`,
+ },
+
+ // Remove unused imports, 2 of 2
+ {
+ name: "remove_unused_2_of_2",
+ in: `package foo
+import (
+"bytes"
+"fmt"
+)
+
+func bar() {
+}
+`,
+ out: `package foo
+
+func bar() {
+}
+`,
+ },
+
+ // Remove unused imports, 1 of 1
+ {
+ name: "remove_unused_1_of_1",
+ in: `package foo
+
+import "fmt"
+
+func bar() {
+}
+`,
+ out: `package foo
+
+func bar() {
+}
+`,
+ },
+
+ // Don't remove empty imports.
+ {
+ name: "dont_remove_empty_imports",
+ in: `package foo
+import (
+_ "image/png"
+_ "image/jpeg"
+)
+`,
+ out: `package foo
+
+import (
+ _ "image/jpeg"
+ _ "image/png"
+)
+`,
+ },
+
+ // Don't remove dot imports.
+ {
+ name: "dont_remove_dot_imports",
+ in: `package foo
+import (
+. "foo"
+. "bar"
+)
+`,
+ out: `package foo
+
+import (
+ . "bar"
+ . "foo"
+)
+`,
+ },
+
+ // Skip refs the parser can resolve.
+ {
+ name: "skip_resolved_refs",
+ in: `package foo
+
+func f() {
+ type t struct{ Println func(string) }
+ fmt := t{Println: func(string) {}}
+ fmt.Println("foo")
+}
+`,
+ out: `package foo
+
+func f() {
+ type t struct{ Println func(string) }
+ fmt := t{Println: func(string) {}}
+ fmt.Println("foo")
+}
+`,
+ },
+
+ // Do not add a package we already have a resolution for.
+ {
+ name: "skip_template",
+ in: `package foo
+
+import "html/template"
+
+func f() { t = template.New("sometemplate") }
+`,
+ out: `package foo
+
+import "html/template"
+
+func f() { t = template.New("sometemplate") }
+`,
+ },
+
+ // Don't touch cgo
+ {
+ name: "cgo",
+ in: `package foo
+
+/*
+#include <foo.h>
+*/
+import "C"
+`,
+ out: `package foo
+
+/*
+#include <foo.h>
+*/
+import "C"
+`,
+ },
+
+ // Put some things in their own section
+ {
+ name: "make_sections",
+ in: `package foo
+
+import (
+"os"
+)
+
+func foo () {
+_, _ = os.Args, fmt.Println
+_, _ = appengine.FooSomething, user.Current
+}
+`,
+ out: `package foo
+
+import (
+ "fmt"
+ "os"
+
+ "appengine"
+ "appengine/user"
+)
+
+func foo() {
+ _, _ = os.Args, fmt.Println
+ _, _ = appengine.FooSomething, user.Current
+}
+`,
+ },
+
+ // Delete existing empty import block
+ {
+ name: "delete_empty_import_block",
+ in: `package foo
+
+import ()
+`,
+ out: `package foo
+`,
+ },
+
+ // Use existing empty import block
+ {
+ name: "use_empty_import_block",
+ in: `package foo
+
+import ()
+
+func f() {
+ _ = fmt.Println
+}
+`,
+ out: `package foo
+
+import "fmt"
+
+func f() {
+ _ = fmt.Println
+}
+`,
+ },
+
+ // Blank line before adding new section.
+ {
+ name: "blank_line_before_new_group",
+ in: `package foo
+
+import (
+ "fmt"
+ "net"
+)
+
+func f() {
+ _ = net.Dial
+ _ = fmt.Printf
+ _ = snappy.Foo
+}
+`,
+ out: `package foo
+
+import (
+ "fmt"
+ "net"
+
+ "code.google.com/p/snappy-go/snappy"
+)
+
+func f() {
+ _ = net.Dial
+ _ = fmt.Printf
+ _ = snappy.Foo
+}
+`,
+ },
+
+ // Blank line between standard library and third-party stuff.
+ {
+ name: "blank_line_separating_std_and_third_party",
+ in: `package foo
+
+import (
+ "code.google.com/p/snappy-go/snappy"
+ "fmt"
+ "net"
+)
+
+func f() {
+ _ = net.Dial
+ _ = fmt.Printf
+ _ = snappy.Foo
+}
+`,
+ out: `package foo
+
+import (
+ "fmt"
+ "net"
+
+ "code.google.com/p/snappy-go/snappy"
+)
+
+func f() {
+ _ = net.Dial
+ _ = fmt.Printf
+ _ = snappy.Foo
+}
+`,
+ },
+
+ // golang.org/issue/6884
+ {
+ name: "issue 6884",
+ in: `package main
+
+// A comment
+func main() {
+ fmt.Println("Hello, world")
+}
+`,
+ out: `package main
+
+import "fmt"
+
+// A comment
+func main() {
+ fmt.Println("Hello, world")
+}
+`,
+ },
+
+ // golang.org/issue/7132
+ {
+ name: "issue 7132",
+ in: `package main
+
+import (
+"fmt"
+
+"gu"
+"github.com/foo/bar"
+)
+
+var (
+a = bar.a
+b = gu.a
+c = fmt.Printf
+)
+`,
+ out: `package main
+
+import (
+ "fmt"
+
+ "gu"
+
+ "github.com/foo/bar"
+)
+
+var (
+ a = bar.a
+ b = gu.a
+ c = fmt.Printf
+)
+`,
+ },
+
+ {
+ name: "renamed package",
+ in: `package main
+
+var _ = str.HasPrefix
+`,
+ out: `package main
+
+import str "strings"
+
+var _ = str.HasPrefix
+`,
+ },
+
+ {
+ name: "fragment with main",
+ in: `func main(){fmt.Println("Hello, world")}`,
+ out: `package main
+
+import "fmt"
+
+func main() { fmt.Println("Hello, world") }
+`,
+ },
+
+ {
+ name: "fragment without main",
+ in: `func notmain(){fmt.Println("Hello, world")}`,
+ out: `import "fmt"
+
+func notmain() { fmt.Println("Hello, world") }`,
+ },
+
+ // Remove first import within in a 2nd/3rd/4th/etc. section.
+ // golang.org/issue/7679
+ {
+ name: "issue 7679",
+ in: `package main
+
+import (
+ "fmt"
+
+ "github.com/foo/bar"
+ "github.com/foo/qux"
+)
+
+func main() {
+ var _ = fmt.Println
+ //var _ = bar.A
+ var _ = qux.B
+}
+`,
+ out: `package main
+
+import (
+ "fmt"
+
+ "github.com/foo/qux"
+)
+
+func main() {
+ var _ = fmt.Println
+ //var _ = bar.A
+ var _ = qux.B
+}
+`,
+ },
+
+ // Blank line can be added before all types of import declarations.
+ // golang.org/issue/7866
+ {
+ name: "issue 7866",
+ in: `package main
+
+import (
+ "fmt"
+ renamed_bar "github.com/foo/bar"
+
+ . "github.com/foo/baz"
+ "io"
+
+ _ "github.com/foo/qux"
+ "strings"
+)
+
+func main() {
+ _, _, _, _, _ = fmt.Errorf, io.Copy, strings.Contains, renamed_bar.A, B
+}
+`,
+ out: `package main
+
+import (
+ "fmt"
+
+ renamed_bar "github.com/foo/bar"
+
+ "io"
+
+ . "github.com/foo/baz"
+
+ "strings"
+
+ _ "github.com/foo/qux"
+)
+
+func main() {
+ _, _, _, _, _ = fmt.Errorf, io.Copy, strings.Contains, renamed_bar.A, B
+}
+`,
+ },
+
+ // Non-idempotent comment formatting
+ // golang.org/issue/8035
+ {
+ name: "issue 8035",
+ in: `package main
+
+import (
+ "fmt" // A
+ "go/ast" // B
+ _ "launchpad.net/gocheck" // C
+)
+
+func main() { _, _ = fmt.Print, ast.Walk }
+`,
+ out: `package main
+
+import (
+ "fmt" // A
+ "go/ast" // B
+
+ _ "launchpad.net/gocheck" // C
+)
+
+func main() { _, _ = fmt.Print, ast.Walk }
+`,
+ },
+
+ // Failure to delete all duplicate imports
+ // golang.org/issue/8459
+ {
+ name: "issue 8459",
+ in: `package main
+
+import (
+ "fmt"
+ "log"
+ "log"
+ "math"
+)
+
+func main() { fmt.Println("pi:", math.Pi) }
+`,
+ out: `package main
+
+import (
+ "fmt"
+ "math"
+)
+
+func main() { fmt.Println("pi:", math.Pi) }
+`,
+ },
+
+ // Too aggressive prefix matching
+ // golang.org/issue/9961
+ {
+ name: "issue 9961",
+ in: `package p
+
+import (
+ "zip"
+
+ "rsc.io/p"
+)
+
+var (
+ _ = fmt.Print
+ _ = zip.Store
+ _ p.P
+ _ = regexp.Compile
+)
+`,
+ out: `package p
+
+import (
+ "fmt"
+ "regexp"
+ "zip"
+
+ "rsc.io/p"
+)
+
+var (
+ _ = fmt.Print
+ _ = zip.Store
+ _ p.P
+ _ = regexp.Compile
+)
+`,
+ },
+
+ // Unused named import is mistaken for unnamed import
+ // golang.org/issue/8149
+ {
+ name: "issue 8149",
+ in: `package main
+
+import foo "fmt"
+
+func main() { fmt.Println() }
+`,
+ out: `package main
+
+import "fmt"
+
+func main() { fmt.Println() }
+`,
+ },
+}
+
+func TestFixImports(t *testing.T) {
+ simplePkgs := map[string]string{
+ "appengine": "appengine",
+ "bytes": "bytes",
+ "fmt": "fmt",
+ "math": "math",
+ "os": "os",
+ "p": "rsc.io/p",
+ "regexp": "regexp",
+ "snappy": "code.google.com/p/snappy-go/snappy",
+ "str": "strings",
+ "user": "appengine/user",
+ "zip": "archive/zip",
+ }
+ findImport = func(pkgName string, symbols map[string]bool) (string, bool, error) {
+ return simplePkgs[pkgName], pkgName == "str", nil
+ }
+
+ options := &Options{
+ TabWidth: 8,
+ TabIndent: true,
+ Comments: true,
+ Fragment: true,
+ }
+
+ for _, tt := range tests {
+ if *only != "" && tt.name != *only {
+ continue
+ }
+ buf, err := Process(tt.name+".go", []byte(tt.in), options)
+ if err != nil {
+ t.Errorf("error on %q: %v", tt.name, err)
+ continue
+ }
+ if got := string(buf); got != tt.out {
+ t.Errorf("results diff on %q\nGOT:\n%s\nWANT:\n%s\n", tt.name, got, tt.out)
+ }
+ }
+}
+
+func TestFindImportGoPath(t *testing.T) {
+ goroot, err := ioutil.TempDir("", "goimports-")
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer os.RemoveAll(goroot)
+
+ pkgIndexOnce = sync.Once{}
+
+ origStdlib := stdlib
+ defer func() {
+ stdlib = origStdlib
+ }()
+ stdlib = nil
+
+ // Test against imaginary bits/bytes package in std lib
+ bytesDir := filepath.Join(goroot, "src", "pkg", "bits", "bytes")
+ for _, tag := range build.Default.ReleaseTags {
+ // Go 1.4 rearranged the GOROOT tree to remove the "pkg" path component.
+ if tag == "go1.4" {
+ bytesDir = filepath.Join(goroot, "src", "bits", "bytes")
+ }
+ }
+ if err := os.MkdirAll(bytesDir, 0755); err != nil {
+ t.Fatal(err)
+ }
+ bytesSrcPath := filepath.Join(bytesDir, "bytes.go")
+ bytesPkgPath := "bits/bytes"
+ bytesSrc := []byte(`package bytes
+
+type Buffer2 struct {}
+`)
+ if err := ioutil.WriteFile(bytesSrcPath, bytesSrc, 0775); err != nil {
+ t.Fatal(err)
+ }
+ oldGOROOT := build.Default.GOROOT
+ oldGOPATH := build.Default.GOPATH
+ build.Default.GOROOT = goroot
+ build.Default.GOPATH = ""
+ defer func() {
+ build.Default.GOROOT = oldGOROOT
+ build.Default.GOPATH = oldGOPATH
+ }()
+
+ got, rename, err := findImportGoPath("bytes", map[string]bool{"Buffer2": true})
+ if err != nil {
+ t.Fatal(err)
+ }
+ if got != bytesPkgPath || rename {
+ t.Errorf(`findImportGoPath("bytes", Buffer2 ...)=%q, %t, want "%s", false`, got, rename, bytesPkgPath)
+ }
+
+ got, rename, err = findImportGoPath("bytes", map[string]bool{"Missing": true})
+ if err != nil {
+ t.Fatal(err)
+ }
+ if got != "" || rename {
+ t.Errorf(`findImportGoPath("bytes", Missing ...)=%q, %t, want "", false`, got, rename)
+ }
+}
+
+func TestFindImportStdlib(t *testing.T) {
+ tests := []struct {
+ pkg string
+ symbols []string
+ want string
+ }{
+ {"http", []string{"Get"}, "net/http"},
+ {"http", []string{"Get", "Post"}, "net/http"},
+ {"http", []string{"Get", "Foo"}, ""},
+ {"bytes", []string{"Buffer"}, "bytes"},
+ {"ioutil", []string{"Discard"}, "io/ioutil"},
+ }
+ for _, tt := range tests {
+ got, rename, ok := findImportStdlib(tt.pkg, strSet(tt.symbols))
+ if (got != "") != ok {
+ t.Error("findImportStdlib return value inconsistent")
+ }
+ if got != tt.want || rename {
+ t.Errorf("findImportStdlib(%q, %q) = %q, %t; want %q, false", tt.pkg, tt.symbols, got, rename, tt.want)
+ }
+ }
+}
+
+func strSet(ss []string) map[string]bool {
+ m := make(map[string]bool)
+ for _, s := range ss {
+ m[s] = true
+ }
+ return m
+}
diff --git a/imports/imports.go b/imports/imports.go
new file mode 100644
index 0000000..e30946b
--- /dev/null
+++ b/imports/imports.go
@@ -0,0 +1,279 @@
+// 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 imports implements a Go pretty-printer (like package "go/format")
+// that also adds or removes import statements as necessary.
+package imports // import "golang.org/x/tools/imports"
+
+import (
+ "bufio"
+ "bytes"
+ "fmt"
+ "go/ast"
+ "go/format"
+ "go/parser"
+ "go/printer"
+ "go/token"
+ "io"
+ "regexp"
+ "strconv"
+ "strings"
+
+ "golang.org/x/tools/go/ast/astutil"
+)
+
+// Options specifies options for processing files.
+type Options struct {
+ Fragment bool // Accept fragment of a source file (no package statement)
+ AllErrors bool // Report all errors (not just the first 10 on different lines)
+
+ Comments bool // Print comments (true if nil *Options provided)
+ TabIndent bool // Use tabs for indent (true if nil *Options provided)
+ TabWidth int // Tab width (8 if nil *Options provided)
+}
+
+// Process formats and adjusts imports for the provided file.
+// If opt is nil the defaults are used.
+func Process(filename string, src []byte, opt *Options) ([]byte, error) {
+ if opt == nil {
+ opt = &Options{Comments: true, TabIndent: true, TabWidth: 8}
+ }
+
+ fileSet := token.NewFileSet()
+ file, adjust, err := parse(fileSet, filename, src, opt)
+ if err != nil {
+ return nil, err
+ }
+
+ _, err = fixImports(fileSet, file)
+ if err != nil {
+ return nil, err
+ }
+
+ sortImports(fileSet, file)
+ imps := astutil.Imports(fileSet, file)
+
+ var spacesBefore []string // import paths we need spaces before
+ for _, impSection := range imps {
+ // Within each block of contiguous imports, see if any
+ // import lines are in different group numbers. If so,
+ // we'll need to put a space between them so it's
+ // compatible with gofmt.
+ lastGroup := -1
+ for _, importSpec := range impSection {
+ importPath, _ := strconv.Unquote(importSpec.Path.Value)
+ groupNum := importGroup(importPath)
+ if groupNum != lastGroup && lastGroup != -1 {
+ spacesBefore = append(spacesBefore, importPath)
+ }
+ lastGroup = groupNum
+ }
+
+ }
+
+ printerMode := printer.UseSpaces
+ if opt.TabIndent {
+ printerMode |= printer.TabIndent
+ }
+ printConfig := &printer.Config{Mode: printerMode, Tabwidth: opt.TabWidth}
+
+ var buf bytes.Buffer
+ err = printConfig.Fprint(&buf, fileSet, file)
+ if err != nil {
+ return nil, err
+ }
+ out := buf.Bytes()
+ if adjust != nil {
+ out = adjust(src, out)
+ }
+ if len(spacesBefore) > 0 {
+ out = addImportSpaces(bytes.NewReader(out), spacesBefore)
+ }
+
+ out, err = format.Source(out)
+ if err != nil {
+ return nil, err
+ }
+ return out, nil
+}
+
+// parse parses src, which was read from filename,
+// as a Go source file or statement list.
+func parse(fset *token.FileSet, filename string, src []byte, opt *Options) (*ast.File, func(orig, src []byte) []byte, error) {
+ parserMode := parser.Mode(0)
+ if opt.Comments {
+ parserMode |= parser.ParseComments
+ }
+ if opt.AllErrors {
+ parserMode |= parser.AllErrors
+ }
+
+ // Try as whole source file.
+ file, err := parser.ParseFile(fset, filename, src, parserMode)
+ if err == nil {
+ return file, nil, nil
+ }
+ // If the error is that the source file didn't begin with a
+ // package line and we accept fragmented input, fall through to
+ // try as a source fragment. Stop and return on any other error.
+ if !opt.Fragment || !strings.Contains(err.Error(), "expected 'package'") {
+ return nil, nil, err
+ }
+
+ // If this is a declaration list, make it a source file
+ // by inserting a package clause.
+ // Insert using a ;, not a newline, so that the line numbers
+ // in psrc match the ones in src.
+ psrc := append([]byte("package main;"), src...)
+ file, err = parser.ParseFile(fset, filename, psrc, parserMode)
+ if err == nil {
+ // If a main function exists, we will assume this is a main
+ // package and leave the file.
+ if containsMainFunc(file) {
+ return file, nil, nil
+ }
+
+ adjust := func(orig, src []byte) []byte {
+ // Remove the package clause.
+ // Gofmt has turned the ; into a \n.
+ src = src[len("package main\n"):]
+ return matchSpace(orig, src)
+ }
+ return file, adjust, nil
+ }
+ // If the error is that the source file didn't begin with a
+ // declaration, fall through to try as a statement list.
+ // Stop and return on any other error.
+ if !strings.Contains(err.Error(), "expected declaration") {
+ return nil, nil, err
+ }
+
+ // If this is a statement list, make it a source file
+ // by inserting a package clause and turning the list
+ // into a function body. This handles expressions too.
+ // Insert using a ;, not a newline, so that the line numbers
+ // in fsrc match the ones in src.
+ fsrc := append(append([]byte("package p; func _() {"), src...), '}')
+ file, err = parser.ParseFile(fset, filename, fsrc, parserMode)
+ if err == nil {
+ adjust := func(orig, src []byte) []byte {
+ // Remove the wrapping.
+ // Gofmt has turned the ; into a \n\n.
+ src = src[len("package p\n\nfunc _() {"):]
+ src = src[:len(src)-len("}\n")]
+ // Gofmt has also indented the function body one level.
+ // Remove that indent.
+ src = bytes.Replace(src, []byte("\n\t"), []byte("\n"), -1)
+ return matchSpace(orig, src)
+ }
+ return file, adjust, nil
+ }
+
+ // Failed, and out of options.
+ return nil, nil, err
+}
+
+// containsMainFunc checks if a file contains a function declaration with the
+// function signature 'func main()'
+func containsMainFunc(file *ast.File) bool {
+ for _, decl := range file.Decls {
+ if f, ok := decl.(*ast.FuncDecl); ok {
+ if f.Name.Name != "main" {
+ continue
+ }
+
+ if len(f.Type.Params.List) != 0 {
+ continue
+ }
+
+ if f.Type.Results != nil && len(f.Type.Results.List) != 0 {
+ continue
+ }
+
+ return true
+ }
+ }
+
+ return false
+}
+
+func cutSpace(b []byte) (before, middle, after []byte) {
+ i := 0
+ for i < len(b) && (b[i] == ' ' || b[i] == '\t' || b[i] == '\n') {
+ i++
+ }
+ j := len(b)
+ for j > 0 && (b[j-1] == ' ' || b[j-1] == '\t' || b[j-1] == '\n') {
+ j--
+ }
+ if i <= j {
+ return b[:i], b[i:j], b[j:]
+ }
+ return nil, nil, b[j:]
+}
+
+// matchSpace reformats src to use the same space context as orig.
+// 1) If orig begins with blank lines, matchSpace inserts them at the beginning of src.
+// 2) matchSpace copies the indentation of the first non-blank line in orig
+// to every non-blank line in src.
+// 3) matchSpace copies the trailing space from orig and uses it in place
+// of src's trailing space.
+func matchSpace(orig []byte, src []byte) []byte {
+ before, _, after := cutSpace(orig)
+ i := bytes.LastIndex(before, []byte{'\n'})
+ before, indent := before[:i+1], before[i+1:]
+
+ _, src, _ = cutSpace(src)
+
+ var b bytes.Buffer
+ b.Write(before)
+ for len(src) > 0 {
+ line := src
+ if i := bytes.IndexByte(line, '\n'); i >= 0 {
+ line, src = line[:i+1], line[i+1:]
+ } else {
+ src = nil
+ }
+ if len(line) > 0 && line[0] != '\n' { // not blank
+ b.Write(indent)
+ }
+ b.Write(line)
+ }
+ b.Write(after)
+ return b.Bytes()
+}
+
+var impLine = regexp.MustCompile(`^\s+(?:[\w\.]+\s+)?"(.+)"`)
+
+func addImportSpaces(r io.Reader, breaks []string) []byte {
+ var out bytes.Buffer
+ sc := bufio.NewScanner(r)
+ inImports := false
+ done := false
+ for sc.Scan() {
+ s := sc.Text()
+
+ if !inImports && !done && strings.HasPrefix(s, "import") {
+ inImports = true
+ }
+ if inImports && (strings.HasPrefix(s, "var") ||
+ strings.HasPrefix(s, "func") ||
+ strings.HasPrefix(s, "const") ||
+ strings.HasPrefix(s, "type")) {
+ done = true
+ inImports = false
+ }
+ if inImports && len(breaks) > 0 {
+ if m := impLine.FindStringSubmatch(s); m != nil {
+ if m[1] == string(breaks[0]) {
+ out.WriteByte('\n')
+ breaks = breaks[1:]
+ }
+ }
+ }
+
+ fmt.Fprintln(&out, s)
+ }
+ return out.Bytes()
+}
diff --git a/imports/mkindex.go b/imports/mkindex.go
new file mode 100644
index 0000000..755e239
--- /dev/null
+++ b/imports/mkindex.go
@@ -0,0 +1,173 @@
+// +build ignore
+
+// 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.
+
+// Command mkindex creates the file "pkgindex.go" containing an index of the Go
+// standard library. The file is intended to be built as part of the imports
+// package, so that the package may be used in environments where a GOROOT is
+// not available (such as App Engine).
+package main
+
+import (
+ "bytes"
+ "fmt"
+ "go/ast"
+ "go/build"
+ "go/format"
+ "go/parser"
+ "go/token"
+ "io/ioutil"
+ "log"
+ "os"
+ "path"
+ "path/filepath"
+ "strings"
+)
+
+var (
+ pkgIndex = make(map[string][]pkg)
+ exports = make(map[string]map[string]bool)
+)
+
+func main() {
+ // Don't use GOPATH.
+ ctx := build.Default
+ ctx.GOPATH = ""
+
+ // Populate pkgIndex global from GOROOT.
+ for _, path := range ctx.SrcDirs() {
+ f, err := os.Open(path)
+ if err != nil {
+ log.Print(err)
+ continue
+ }
+ children, err := f.Readdir(-1)
+ f.Close()
+ if err != nil {
+ log.Print(err)
+ continue
+ }
+ for _, child := range children {
+ if child.IsDir() {
+ loadPkg(path, child.Name())
+ }
+ }
+ }
+ // Populate exports global.
+ for _, ps := range pkgIndex {
+ for _, p := range ps {
+ e := loadExports(p.dir)
+ if e != nil {
+ exports[p.dir] = e
+ }
+ }
+ }
+
+ // Construct source file.
+ var buf bytes.Buffer
+ fmt.Fprint(&buf, pkgIndexHead)
+ fmt.Fprintf(&buf, "var pkgIndexMaster = %#v\n", pkgIndex)
+ fmt.Fprintf(&buf, "var exportsMaster = %#v\n", exports)
+ src := buf.Bytes()
+
+ // Replace main.pkg type name with pkg.
+ src = bytes.Replace(src, []byte("main.pkg"), []byte("pkg"), -1)
+ // Replace actual GOROOT with "/go".
+ src = bytes.Replace(src, []byte(ctx.GOROOT), []byte("/go"), -1)
+ // Add some line wrapping.
+ src = bytes.Replace(src, []byte("}, "), []byte("},\n"), -1)
+ src = bytes.Replace(src, []byte("true, "), []byte("true,\n"), -1)
+
+ var err error
+ src, err = format.Source(src)
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ // Write out source file.
+ err = ioutil.WriteFile("pkgindex.go", src, 0644)
+ if err != nil {
+ log.Fatal(err)
+ }
+}
+
+const pkgIndexHead = `package imports
+
+func init() {
+ pkgIndexOnce.Do(func() {
+ pkgIndex.m = pkgIndexMaster
+ })
+ loadExports = func(dir string) map[string]bool {
+ return exportsMaster[dir]
+ }
+}
+`
+
+type pkg struct {
+ importpath string // full pkg import path, e.g. "net/http"
+ dir string // absolute file path to pkg directory e.g. "/usr/lib/go/src/fmt"
+}
+
+var fset = token.NewFileSet()
+
+func loadPkg(root, importpath string) {
+ shortName := path.Base(importpath)
+ if shortName == "testdata" {
+ return
+ }
+
+ dir := filepath.Join(root, importpath)
+ pkgIndex[shortName] = append(pkgIndex[shortName], pkg{
+ importpath: importpath,
+ dir: dir,
+ })
+
+ pkgDir, err := os.Open(dir)
+ if err != nil {
+ return
+ }
+ children, err := pkgDir.Readdir(-1)
+ pkgDir.Close()
+ if err != nil {
+ return
+ }
+ for _, child := range children {
+ name := child.Name()
+ if name == "" {
+ continue
+ }
+ if c := name[0]; c == '.' || ('0' <= c && c <= '9') {
+ continue
+ }
+ if child.IsDir() {
+ loadPkg(root, filepath.Join(importpath, name))
+ }
+ }
+}
+
+func loadExports(dir string) map[string]bool {
+ exports := make(map[string]bool)
+ buildPkg, err := build.ImportDir(dir, 0)
+ if err != nil {
+ if strings.Contains(err.Error(), "no buildable Go source files in") {
+ return nil
+ }
+ log.Printf("could not import %q: %v", dir, err)
+ return nil
+ }
+ for _, file := range buildPkg.GoFiles {
+ f, err := parser.ParseFile(fset, filepath.Join(dir, file), nil, 0)
+ if err != nil {
+ log.Printf("could not parse %q: %v", file, err)
+ continue
+ }
+ for name := range f.Scope.Objects {
+ if ast.IsExported(name) {
+ exports[name] = true
+ }
+ }
+ }
+ return exports
+}
diff --git a/imports/mkstdlib.go b/imports/mkstdlib.go
new file mode 100644
index 0000000..c43d325
--- /dev/null
+++ b/imports/mkstdlib.go
@@ -0,0 +1,90 @@
+// +build ignore
+
+// mkstdlib generates the zstdlib.go file, containing the Go standard
+// library API symbols. It's baked into the binary to avoid scanning
+// GOPATH in the common case.
+package main
+
+import (
+ "bufio"
+ "bytes"
+ "fmt"
+ "go/format"
+ "io"
+ "log"
+ "os"
+ "path"
+ "path/filepath"
+ "regexp"
+ "sort"
+ "strings"
+)
+
+func mustOpen(name string) io.Reader {
+ f, err := os.Open(name)
+ if err != nil {
+ log.Fatal(err)
+ }
+ return f
+}
+
+func api(base string) string {
+ return filepath.Join(os.Getenv("GOROOT"), "api", base)
+}
+
+var sym = regexp.MustCompile(`^pkg (\S+).*?, (?:var|func|type|const) ([A-Z]\w*)`)
+
+func main() {
+ var buf bytes.Buffer
+ outf := func(format string, args ...interface{}) {
+ fmt.Fprintf(&buf, format, args...)
+ }
+ outf("// AUTO-GENERATED BY mkstdlib.go\n\n")
+ outf("package imports\n")
+ outf("var stdlib = map[string]string{\n")
+ f := io.MultiReader(
+ mustOpen(api("go1.txt")),
+ mustOpen(api("go1.1.txt")),
+ mustOpen(api("go1.2.txt")),
+ )
+ sc := bufio.NewScanner(f)
+ fullImport := map[string]string{} // "zip.NewReader" => "archive/zip"
+ ambiguous := map[string]bool{}
+ var keys []string
+ for sc.Scan() {
+ l := sc.Text()
+ has := func(v string) bool { return strings.Contains(l, v) }
+ if has("struct, ") || has("interface, ") || has(", method (") {
+ continue
+ }
+ if m := sym.FindStringSubmatch(l); m != nil {
+ full := m[1]
+ key := path.Base(full) + "." + m[2]
+ if exist, ok := fullImport[key]; ok {
+ if exist != full {
+ ambiguous[key] = true
+ }
+ } else {
+ fullImport[key] = full
+ keys = append(keys, key)
+ }
+ }
+ }
+ if err := sc.Err(); err != nil {
+ log.Fatal(err)
+ }
+ sort.Strings(keys)
+ for _, key := range keys {
+ if ambiguous[key] {
+ outf("\t// %q is ambiguous\n", key)
+ } else {
+ outf("\t%q: %q,\n", key, fullImport[key])
+ }
+ }
+ outf("}\n")
+ fmtbuf, err := format.Source(buf.Bytes())
+ if err != nil {
+ log.Fatal(err)
+ }
+ os.Stdout.Write(fmtbuf)
+}
diff --git a/imports/sortimports.go b/imports/sortimports.go
new file mode 100644
index 0000000..68b3dc4
--- /dev/null
+++ b/imports/sortimports.go
@@ -0,0 +1,214 @@
+// +build go1.2
+
+// 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.
+
+// Hacked up copy of go/ast/import.go
+
+package imports
+
+import (
+ "go/ast"
+ "go/token"
+ "sort"
+ "strconv"
+)
+
+// sortImports sorts runs of consecutive import lines in import blocks in f.
+// It also removes duplicate imports when it is possible to do so without data loss.
+func sortImports(fset *token.FileSet, f *ast.File) {
+ for i, d := range f.Decls {
+ d, ok := d.(*ast.GenDecl)
+ if !ok || d.Tok != token.IMPORT {
+ // Not an import declaration, so we're done.
+ // Imports are always first.
+ break
+ }
+
+ if len(d.Specs) == 0 {
+ // Empty import block, remove it.
+ f.Decls = append(f.Decls[:i], f.Decls[i+1:]...)
+ }
+
+ if !d.Lparen.IsValid() {
+ // Not a block: sorted by default.
+ continue
+ }
+
+ // Identify and sort runs of specs on successive lines.
+ i := 0
+ specs := d.Specs[:0]
+ for j, s := range d.Specs {
+ if j > i && fset.Position(s.Pos()).Line > 1+fset.Position(d.Specs[j-1].End()).Line {
+ // j begins a new run. End this one.
+ specs = append(specs, sortSpecs(fset, f, d.Specs[i:j])...)
+ i = j
+ }
+ }
+ specs = append(specs, sortSpecs(fset, f, d.Specs[i:])...)
+ d.Specs = specs
+
+ // Deduping can leave a blank line before the rparen; clean that up.
+ if len(d.Specs) > 0 {
+ lastSpec := d.Specs[len(d.Specs)-1]
+ lastLine := fset.Position(lastSpec.Pos()).Line
+ if rParenLine := fset.Position(d.Rparen).Line; rParenLine > lastLine+1 {
+ fset.File(d.Rparen).MergeLine(rParenLine - 1)
+ }
+ }
+ }
+}
+
+func importPath(s ast.Spec) string {
+ t, err := strconv.Unquote(s.(*ast.ImportSpec).Path.Value)
+ if err == nil {
+ return t
+ }
+ return ""
+}
+
+func importName(s ast.Spec) string {
+ n := s.(*ast.ImportSpec).Name
+ if n == nil {
+ return ""
+ }
+ return n.Name
+}
+
+func importComment(s ast.Spec) string {
+ c := s.(*ast.ImportSpec).Comment
+ if c == nil {
+ return ""
+ }
+ return c.Text()
+}
+
+// collapse indicates whether prev may be removed, leaving only next.
+func collapse(prev, next ast.Spec) bool {
+ if importPath(next) != importPath(prev) || importName(next) != importName(prev) {
+ return false
+ }
+ return prev.(*ast.ImportSpec).Comment == nil
+}
+
+type posSpan struct {
+ Start token.Pos
+ End token.Pos
+}
+
+func sortSpecs(fset *token.FileSet, f *ast.File, specs []ast.Spec) []ast.Spec {
+ // Can't short-circuit here even if specs are already sorted,
+ // since they might yet need deduplication.
+ // A lone import, however, may be safely ignored.
+ if len(specs) <= 1 {
+ return specs
+ }
+
+ // Record positions for specs.
+ pos := make([]posSpan, len(specs))
+ for i, s := range specs {
+ pos[i] = posSpan{s.Pos(), s.End()}
+ }
+
+ // Identify comments in this range.
+ // Any comment from pos[0].Start to the final line counts.
+ lastLine := fset.Position(pos[len(pos)-1].End).Line
+ cstart := len(f.Comments)
+ cend := len(f.Comments)
+ for i, g := range f.Comments {
+ if g.Pos() < pos[0].Start {
+ continue
+ }
+ if i < cstart {
+ cstart = i
+ }
+ if fset.Position(g.End()).Line > lastLine {
+ cend = i
+ break
+ }
+ }
+ comments := f.Comments[cstart:cend]
+
+ // Assign each comment to the import spec preceding it.
+ importComment := map[*ast.ImportSpec][]*ast.CommentGroup{}
+ specIndex := 0
+ for _, g := range comments {
+ for specIndex+1 < len(specs) && pos[specIndex+1].Start <= g.Pos() {
+ specIndex++
+ }
+ s := specs[specIndex].(*ast.ImportSpec)
+ importComment[s] = append(importComment[s], g)
+ }
+
+ // Sort the import specs by import path.
+ // Remove duplicates, when possible without data loss.
+ // Reassign the import paths to have the same position sequence.
+ // Reassign each comment to abut the end of its spec.
+ // Sort the comments by new position.
+ sort.Sort(byImportSpec(specs))
+
+ // Dedup. Thanks to our sorting, we can just consider
+ // adjacent pairs of imports.
+ deduped := specs[:0]
+ for i, s := range specs {
+ if i == len(specs)-1 || !collapse(s, specs[i+1]) {
+ deduped = append(deduped, s)
+ } else {
+ p := s.Pos()
+ fset.File(p).MergeLine(fset.Position(p).Line)
+ }
+ }
+ specs = deduped
+
+ // Fix up comment positions
+ for i, s := range specs {
+ s := s.(*ast.ImportSpec)
+ if s.Name != nil {
+ s.Name.NamePos = pos[i].Start
+ }
+ s.Path.ValuePos = pos[i].Start
+ s.EndPos = pos[i].End
+ for _, g := range importComment[s] {
+ for _, c := range g.List {
+ c.Slash = pos[i].End
+ }
+ }
+ }
+
+ sort.Sort(byCommentPos(comments))
+
+ return specs
+}
+
+type byImportSpec []ast.Spec // slice of *ast.ImportSpec
+
+func (x byImportSpec) Len() int { return len(x) }
+func (x byImportSpec) Swap(i, j int) { x[i], x[j] = x[j], x[i] }
+func (x byImportSpec) Less(i, j int) bool {
+ ipath := importPath(x[i])
+ jpath := importPath(x[j])
+
+ igroup := importGroup(ipath)
+ jgroup := importGroup(jpath)
+ if igroup != jgroup {
+ return igroup < jgroup
+ }
+
+ if ipath != jpath {
+ return ipath < jpath
+ }
+ iname := importName(x[i])
+ jname := importName(x[j])
+
+ if iname != jname {
+ return iname < jname
+ }
+ return importComment(x[i]) < importComment(x[j])
+}
+
+type byCommentPos []*ast.CommentGroup
+
+func (x byCommentPos) Len() int { return len(x) }
+func (x byCommentPos) Swap(i, j int) { x[i], x[j] = x[j], x[i] }
+func (x byCommentPos) Less(i, j int) bool { return x[i].Pos() < x[j].Pos() }
diff --git a/imports/sortimports_compat.go b/imports/sortimports_compat.go
new file mode 100644
index 0000000..295f237
--- /dev/null
+++ b/imports/sortimports_compat.go
@@ -0,0 +1,14 @@
+// +build !go1.2
+
+// 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 imports
+
+import "go/ast"
+
+// Go 1.1 users don't get fancy package grouping.
+// But this is still gofmt-compliant:
+
+var sortImports = ast.SortImports
diff --git a/imports/zstdlib.go b/imports/zstdlib.go
new file mode 100644
index 0000000..6cdc033
--- /dev/null
+++ b/imports/zstdlib.go
@@ -0,0 +1,8374 @@
+// AUTO-GENERATED BY mkstdlib.go
+
+package imports
+
+var stdlib = map[string]string{
+ "adler32.Checksum": "hash/adler32",
+ "adler32.New": "hash/adler32",
+ "adler32.Size": "hash/adler32",
+ "aes.BlockSize": "crypto/aes",
+ "aes.KeySizeError": "crypto/aes",
+ "aes.NewCipher": "crypto/aes",
+ "ascii85.CorruptInputError": "encoding/ascii85",
+ "ascii85.Decode": "encoding/ascii85",
+ "ascii85.Encode": "encoding/ascii85",
+ "ascii85.MaxEncodedLen": "encoding/ascii85",
+ "ascii85.NewDecoder": "encoding/ascii85",
+ "ascii85.NewEncoder": "encoding/ascii85",
+ "asn1.BitString": "encoding/asn1",
+ "asn1.Enumerated": "encoding/asn1",
+ "asn1.Flag": "encoding/asn1",
+ "asn1.Marshal": "encoding/asn1",
+ "asn1.ObjectIdentifier": "encoding/asn1",
+ "asn1.RawContent": "encoding/asn1",
+ "asn1.RawValue": "encoding/asn1",
+ "asn1.StructuralError": "encoding/asn1",
+ "asn1.SyntaxError": "encoding/asn1",
+ "asn1.Unmarshal": "encoding/asn1",
+ "asn1.UnmarshalWithParams": "encoding/asn1",
+ "ast.ArrayType": "go/ast",
+ "ast.AssignStmt": "go/ast",
+ "ast.Bad": "go/ast",
+ "ast.BadDecl": "go/ast",
+ "ast.BadExpr": "go/ast",
+ "ast.BadStmt": "go/ast",
+ "ast.BasicLit": "go/ast",
+ "ast.BinaryExpr": "go/ast",
+ "ast.BlockStmt": "go/ast",
+ "ast.BranchStmt": "go/ast",
+ "ast.CallExpr": "go/ast",
+ "ast.CaseClause": "go/ast",
+ "ast.ChanDir": "go/ast",
+ "ast.ChanType": "go/ast",
+ "ast.CommClause": "go/ast",
+ "ast.Comment": "go/ast",
+ "ast.CommentGroup": "go/ast",
+ "ast.CommentMap": "go/ast",
+ "ast.CompositeLit": "go/ast",
+ "ast.Con": "go/ast",
+ "ast.DeclStmt": "go/ast",
+ "ast.DeferStmt": "go/ast",
+ "ast.Ellipsis": "go/ast",
+ "ast.EmptyStmt": "go/ast",
+ "ast.ExprStmt": "go/ast",
+ "ast.Field": "go/ast",
+ "ast.FieldFilter": "go/ast",
+ "ast.FieldList": "go/ast",
+ "ast.File": "go/ast",
+ "ast.FileExports": "go/ast",
+ "ast.Filter": "go/ast",
+ "ast.FilterDecl": "go/ast",
+ "ast.FilterFile": "go/ast",
+ "ast.FilterFuncDuplicates": "go/ast",
+ "ast.FilterImportDuplicates": "go/ast",
+ "ast.FilterPackage": "go/ast",
+ "ast.FilterUnassociatedComments": "go/ast",
+ "ast.ForStmt": "go/ast",
+ "ast.Fprint": "go/ast",
+ "ast.Fun": "go/ast",
+ "ast.FuncDecl": "go/ast",
+ "ast.FuncLit": "go/ast",
+ "ast.FuncType": "go/ast",
+ "ast.GenDecl": "go/ast",
+ "ast.GoStmt": "go/ast",
+ "ast.Ident": "go/ast",
+ "ast.IfStmt": "go/ast",
+ "ast.ImportSpec": "go/ast",
+ "ast.Importer": "go/ast",
+ "ast.IncDecStmt": "go/ast",
+ "ast.IndexExpr": "go/ast",
+ "ast.Inspect": "go/ast",
+ "ast.InterfaceType": "go/ast",
+ "ast.IsExported": "go/ast",
+ "ast.KeyValueExpr": "go/ast",
+ "ast.LabeledStmt": "go/ast",
+ "ast.Lbl": "go/ast",
+ "ast.MapType": "go/ast",
+ "ast.MergeMode": "go/ast",
+ "ast.MergePackageFiles": "go/ast",
+ "ast.NewCommentMap": "go/ast",
+ "ast.NewIdent": "go/ast",
+ "ast.NewObj": "go/ast",
+ "ast.NewPackage": "go/ast",
+ "ast.NewScope": "go/ast",
+ "ast.Node": "go/ast",
+ "ast.NotNilFilter": "go/ast",
+ "ast.ObjKind": "go/ast",
+ "ast.Object": "go/ast",
+ "ast.Package": "go/ast",
+ "ast.PackageExports": "go/ast",
+ "ast.ParenExpr": "go/ast",
+ "ast.Pkg": "go/ast",
+ "ast.Print": "go/ast",
+ "ast.RECV": "go/ast",
+ "ast.RangeStmt": "go/ast",
+ "ast.ReturnStmt": "go/ast",
+ "ast.SEND": "go/ast",
+ "ast.Scope": "go/ast",
+ "ast.SelectStmt": "go/ast",
+ "ast.SelectorExpr": "go/ast",
+ "ast.SendStmt": "go/ast",
+ "ast.SliceExpr": "go/ast",
+ "ast.SortImports": "go/ast",
+ "ast.StarExpr": "go/ast",
+ "ast.StructType": "go/ast",
+ "ast.SwitchStmt": "go/ast",
+ "ast.Typ": "go/ast",
+ "ast.TypeAssertExpr": "go/ast",
+ "ast.TypeSpec": "go/ast",
+ "ast.TypeSwitchStmt": "go/ast",
+ "ast.UnaryExpr": "go/ast",
+ "ast.ValueSpec": "go/ast",
+ "ast.Var": "go/ast",
+ "ast.Visitor": "go/ast",
+ "ast.Walk": "go/ast",
+ "atomic.AddInt32": "sync/atomic",
+ "atomic.AddInt64": "sync/atomic",
+ "atomic.AddUint32": "sync/atomic",
+ "atomic.AddUint64": "sync/atomic",
+ "atomic.AddUintptr": "sync/atomic",
+ "atomic.CompareAndSwapInt32": "sync/atomic",
+ "atomic.CompareAndSwapInt64": "sync/atomic",
+ "atomic.CompareAndSwapPointer": "sync/atomic",
+ "atomic.CompareAndSwapUint32": "sync/atomic",
+ "atomic.CompareAndSwapUint64": "sync/atomic",
+ "atomic.CompareAndSwapUintptr": "sync/atomic",
+ "atomic.LoadInt32": "sync/atomic",
+ "atomic.LoadInt64": "sync/atomic",
+ "atomic.LoadPointer": "sync/atomic",
+ "atomic.LoadUint32": "sync/atomic",
+ "atomic.LoadUint64": "sync/atomic",
+ "atomic.LoadUintptr": "sync/atomic",
+ "atomic.StoreInt32": "sync/atomic",
+ "atomic.StoreInt64": "sync/atomic",
+ "atomic.StorePointer": "sync/atomic",
+ "atomic.StoreUint32": "sync/atomic",
+ "atomic.StoreUint64": "sync/atomic",
+ "atomic.StoreUintptr": "sync/atomic",
+ "atomic.SwapInt32": "sync/atomic",
+ "atomic.SwapInt64": "sync/atomic",
+ "atomic.SwapPointer": "sync/atomic",
+ "atomic.SwapUint32": "sync/atomic",
+ "atomic.SwapUint64": "sync/atomic",
+ "atomic.SwapUintptr": "sync/atomic",
+ "base32.CorruptInputError": "encoding/base32",
+ "base32.Encoding": "encoding/base32",
+ "base32.HexEncoding": "encoding/base32",
+ "base32.NewDecoder": "encoding/base32",
+ "base32.NewEncoder": "encoding/base32",
+ "base32.NewEncoding": "encoding/base32",
+ "base32.StdEncoding": "encoding/base32",
+ "base64.CorruptInputError": "encoding/base64",
+ "base64.Encoding": "encoding/base64",
+ "base64.NewDecoder": "encoding/base64",
+ "base64.NewEncoder": "encoding/base64",
+ "base64.NewEncoding": "encoding/base64",
+ "base64.StdEncoding": "encoding/base64",
+ "base64.URLEncoding": "encoding/base64",
+ "big.Int": "math/big",
+ "big.MaxBase": "math/big",
+ "big.NewInt": "math/big",
+ "big.NewRat": "math/big",
+ "big.Rat": "math/big",
+ "big.Word": "math/big",
+ "binary.BigEndian": "encoding/binary",
+ "binary.ByteOrder": "encoding/binary",
+ "binary.LittleEndian": "encoding/binary",
+ "binary.MaxVarintLen16": "encoding/binary",
+ "binary.MaxVarintLen32": "encoding/binary",
+ "binary.MaxVarintLen64": "encoding/binary",
+ "binary.PutUvarint": "encoding/binary",
+ "binary.PutVarint": "encoding/binary",
+ "binary.Read": "encoding/binary",
+ "binary.ReadUvarint": "encoding/binary",
+ "binary.ReadVarint": "encoding/binary",
+ "binary.Size": "encoding/binary",
+ "binary.Uvarint": "encoding/binary",
+ "binary.Varint": "encoding/binary",
+ "binary.Write": "encoding/binary",
+ "bufio.ErrAdvanceTooFar": "bufio",
+ "bufio.ErrBufferFull": "bufio",
+ "bufio.ErrInvalidUnreadByte": "bufio",
+ "bufio.ErrInvalidUnreadRune": "bufio",
+ "bufio.ErrNegativeAdvance": "bufio",
+ "bufio.ErrNegativeCount": "bufio",
+ "bufio.ErrTooLong": "bufio",
+ "bufio.MaxScanTokenSize": "bufio",
+ "bufio.NewReadWriter": "bufio",
+ "bufio.NewReader": "bufio",
+ "bufio.NewReaderSize": "bufio",
+ "bufio.NewScanner": "bufio",
+ "bufio.NewWriter": "bufio",
+ "bufio.NewWriterSize": "bufio",
+ "bufio.ReadWriter": "bufio",
+ "bufio.Reader": "bufio",
+ "bufio.ScanBytes": "bufio",
+ "bufio.ScanLines": "bufio",
+ "bufio.ScanRunes": "bufio",
+ "bufio.ScanWords": "bufio",
+ "bufio.Scanner": "bufio",
+ "bufio.SplitFunc": "bufio",
+ "bufio.Writer": "bufio",
+ "build.AllowBinary": "go/build",
+ "build.ArchChar": "go/build",
+ "build.Context": "go/build",
+ "build.Default": "go/build",
+ "build.FindOnly": "go/build",
+ "build.Import": "go/build",
+ "build.ImportDir": "go/build",
+ "build.ImportMode": "go/build",
+ "build.IsLocalImport": "go/build",
+ "build.NoGoError": "go/build",
+ "build.Package": "go/build",
+ "build.ToolDir": "go/build",
+ "bytes.Buffer": "bytes",
+ "bytes.Compare": "bytes",
+ "bytes.Contains": "bytes",
+ "bytes.Count": "bytes",
+ "bytes.Equal": "bytes",
+ "bytes.EqualFold": "bytes",
+ "bytes.ErrTooLarge": "bytes",
+ "bytes.Fields": "bytes",
+ "bytes.FieldsFunc": "bytes",
+ "bytes.HasPrefix": "bytes",
+ "bytes.HasSuffix": "bytes",
+ "bytes.Index": "bytes",
+ "bytes.IndexAny": "bytes",
+ "bytes.IndexByte": "bytes",
+ "bytes.IndexFunc": "bytes",
+ "bytes.IndexRune": "bytes",
+ "bytes.Join": "bytes",
+ "bytes.LastIndex": "bytes",
+ "bytes.LastIndexAny": "bytes",
+ "bytes.LastIndexFunc": "bytes",
+ "bytes.Map": "bytes",
+ "bytes.MinRead": "bytes",
+ "bytes.NewBuffer": "bytes",
+ "bytes.NewBufferString": "bytes",
+ "bytes.NewReader": "bytes",
+ "bytes.Reader": "bytes",
+ "bytes.Repeat": "bytes",
+ "bytes.Replace": "bytes",
+ "bytes.Runes": "bytes",
+ "bytes.Split": "bytes",
+ "bytes.SplitAfter": "bytes",
+ "bytes.SplitAfterN": "bytes",
+ "bytes.SplitN": "bytes",
+ "bytes.Title": "bytes",
+ "bytes.ToLower": "bytes",
+ "bytes.ToLowerSpecial": "bytes",
+ "bytes.ToTitle": "bytes",
+ "bytes.ToTitleSpecial": "bytes",
+ "bytes.ToUpper": "bytes",
+ "bytes.ToUpperSpecial": "bytes",
+ "bytes.Trim": "bytes",
+ "bytes.TrimFunc": "bytes",
+ "bytes.TrimLeft": "bytes",
+ "bytes.TrimLeftFunc": "bytes",
+ "bytes.TrimPrefix": "bytes",
+ "bytes.TrimRight": "bytes",
+ "bytes.TrimRightFunc": "bytes",
+ "bytes.TrimSpace": "bytes",
+ "bytes.TrimSuffix": "bytes",
+ "bzip2.NewReader": "compress/bzip2",
+ "bzip2.StructuralError": "compress/bzip2",
+ "cgi.Handler": "net/http/cgi",
+ "cgi.Request": "net/http/cgi",
+ "cgi.RequestFromMap": "net/http/cgi",
+ "cgi.Serve": "net/http/cgi",
+ "cipher.AEAD": "crypto/cipher",
+ "cipher.Block": "crypto/cipher",
+ "cipher.BlockMode": "crypto/cipher",
+ "cipher.NewCBCDecrypter": "crypto/cipher",
+ "cipher.NewCBCEncrypter": "crypto/cipher",
+ "cipher.NewCFBDecrypter": "crypto/cipher",
+ "cipher.NewCFBEncrypter": "crypto/cipher",
+ "cipher.NewCTR": "crypto/cipher",
+ "cipher.NewGCM": "crypto/cipher",
+ "cipher.NewOFB": "crypto/cipher",
+ "cipher.Stream": "crypto/cipher",
+ "cipher.StreamReader": "crypto/cipher",
+ "cipher.StreamWriter": "crypto/cipher",
+ "cmplx.Abs": "math/cmplx",
+ "cmplx.Acos": "math/cmplx",
+ "cmplx.Acosh": "math/cmplx",
+ "cmplx.Asin": "math/cmplx",
+ "cmplx.Asinh": "math/cmplx",
+ "cmplx.Atan": "math/cmplx",
+ "cmplx.Atanh": "math/cmplx",
+ "cmplx.Conj": "math/cmplx",
+ "cmplx.Cos": "math/cmplx",
+ "cmplx.Cosh": "math/cmplx",
+ "cmplx.Cot": "math/cmplx",
+ "cmplx.Exp": "math/cmplx",
+ "cmplx.Inf": "math/cmplx",
+ "cmplx.IsInf": "math/cmplx",
+ "cmplx.IsNaN": "math/cmplx",
+ "cmplx.Log": "math/cmplx",
+ "cmplx.Log10": "math/cmplx",
+ "cmplx.NaN": "math/cmplx",
+ "cmplx.Phase": "math/cmplx",
+ "cmplx.Polar": "math/cmplx",
+ "cmplx.Pow": "math/cmplx",
+ "cmplx.Rect": "math/cmplx",
+ "cmplx.Sin": "math/cmplx",
+ "cmplx.Sinh": "math/cmplx",
+ "cmplx.Sqrt": "math/cmplx",
+ "cmplx.Tan": "math/cmplx",
+ "cmplx.Tanh": "math/cmplx",
+ "color.Alpha": "image/color",
+ "color.Alpha16": "image/color",
+ "color.Alpha16Model": "image/color",
+ "color.AlphaModel": "image/color",
+ "color.Black": "image/color",
+ "color.Color": "image/color",
+ "color.Gray": "image/color",
+ "color.Gray16": "image/color",
+ "color.Gray16Model": "image/color",
+ "color.GrayModel": "image/color",
+ "color.Model": "image/color",
+ "color.ModelFunc": "image/color",
+ "color.NRGBA": "image/color",
+ "color.NRGBA64": "image/color",
+ "color.NRGBA64Model": "image/color",
+ "color.NRGBAModel": "image/color",
+ "color.Opaque": "image/color",
+ "color.Palette": "image/color",
+ "color.RGBA": "image/color",
+ "color.RGBA64": "image/color",
+ "color.RGBA64Model": "image/color",
+ "color.RGBAModel": "image/color",
+ "color.RGBToYCbCr": "image/color",
+ "color.Transparent": "image/color",
+ "color.White": "image/color",
+ "color.YCbCr": "image/color",
+ "color.YCbCrModel": "image/color",
+ "color.YCbCrToRGB": "image/color",
+ "cookiejar.Jar": "net/http/cookiejar",
+ "cookiejar.New": "net/http/cookiejar",
+ "cookiejar.Options": "net/http/cookiejar",
+ "cookiejar.PublicSuffixList": "net/http/cookiejar",
+ "crc32.Castagnoli": "hash/crc32",
+ "crc32.Checksum": "hash/crc32",
+ "crc32.ChecksumIEEE": "hash/crc32",
+ "crc32.IEEE": "hash/crc32",
+ "crc32.IEEETable": "hash/crc32",
+ "crc32.Koopman": "hash/crc32",
+ "crc32.MakeTable": "hash/crc32",
+ "crc32.New": "hash/crc32",
+ "crc32.NewIEEE": "hash/crc32",
+ "crc32.Size": "hash/crc32",
+ "crc32.Table": "hash/crc32",
+ "crc32.Update": "hash/crc32",
+ "crc64.Checksum": "hash/crc64",
+ "crc64.ECMA": "hash/crc64",
+ "crc64.ISO": "hash/crc64",
+ "crc64.MakeTable": "hash/crc64",
+ "crc64.New": "hash/crc64",
+ "crc64.Size": "hash/crc64",
+ "crc64.Table": "hash/crc64",
+ "crc64.Update": "hash/crc64",
+ "crypto.Hash": "crypto",
+ "crypto.MD4": "crypto",
+ "crypto.MD5": "crypto",
+ "crypto.MD5SHA1": "crypto",
+ "crypto.PrivateKey": "crypto",
+ "crypto.PublicKey": "crypto",
+ "crypto.RIPEMD160": "crypto",
+ "crypto.RegisterHash": "crypto",
+ "crypto.SHA1": "crypto",
+ "crypto.SHA224": "crypto",
+ "crypto.SHA256": "crypto",
+ "crypto.SHA384": "crypto",
+ "crypto.SHA512": "crypto",
+ "csv.ErrBareQuote": "encoding/csv",
+ "csv.ErrFieldCount": "encoding/csv",
+ "csv.ErrQuote": "encoding/csv",
+ "csv.ErrTrailingComma": "encoding/csv",
+ "csv.NewReader": "encoding/csv",
+ "csv.NewWriter": "encoding/csv",
+ "csv.ParseError": "encoding/csv",
+ "csv.Reader": "encoding/csv",
+ "csv.Writer": "encoding/csv",
+ "debug.FreeOSMemory": "runtime/debug",
+ "debug.GCStats": "runtime/debug",
+ "debug.PrintStack": "runtime/debug",
+ "debug.ReadGCStats": "runtime/debug",
+ "debug.SetGCPercent": "runtime/debug",
+ "debug.SetMaxStack": "runtime/debug",
+ "debug.SetMaxThreads": "runtime/debug",
+ "debug.Stack": "runtime/debug",
+ "des.BlockSize": "crypto/des",
+ "des.KeySizeError": "crypto/des",
+ "des.NewCipher": "crypto/des",
+ "des.NewTripleDESCipher": "crypto/des",
+ "doc.AllDecls": "go/doc",
+ "doc.AllMethods": "go/doc",
+ "doc.Example": "go/doc",
+ "doc.Examples": "go/doc",
+ "doc.Filter": "go/doc",
+ "doc.Func": "go/doc",
+ "doc.IllegalPrefixes": "go/doc",
+ "doc.Mode": "go/doc",
+ "doc.New": "go/doc",
+ "doc.Note": "go/doc",
+ "doc.Package": "go/doc",
+ "doc.Synopsis": "go/doc",
+ "doc.ToHTML": "go/doc",
+ "doc.ToText": "go/doc",
+ "doc.Type": "go/doc",
+ "doc.Value": "go/doc",
+ "draw.Draw": "image/draw",
+ "draw.DrawMask": "image/draw",
+ "draw.Drawer": "image/draw",
+ "draw.FloydSteinberg": "image/draw",
+ "draw.Image": "image/draw",
+ "draw.Op": "image/draw",
+ "draw.Over": "image/draw",
+ "draw.Quantizer": "image/draw",
+ "draw.Src": "image/draw",
+ "driver.Bool": "database/sql/driver",
+ "driver.ColumnConverter": "database/sql/driver",
+ "driver.Conn": "database/sql/driver",
+ "driver.DefaultParameterConverter": "database/sql/driver",
+ "driver.Driver": "database/sql/driver",
+ "driver.ErrBadConn": "database/sql/driver",
+ "driver.ErrSkip": "database/sql/driver",
+ "driver.Execer": "database/sql/driver",
+ "driver.Int32": "database/sql/driver",
+ "driver.IsScanValue": "database/sql/driver",
+ "driver.IsValue": "database/sql/driver",
+ "driver.NotNull": "database/sql/driver",
+ "driver.Null": "database/sql/driver",
+ "driver.Queryer": "database/sql/driver",
+ "driver.Result": "database/sql/driver",
+ "driver.ResultNoRows": "database/sql/driver",
+ "driver.Rows": "database/sql/driver",
+ "driver.RowsAffected": "database/sql/driver",
+ "driver.Stmt": "database/sql/driver",
+ "driver.String": "database/sql/driver",
+ "driver.Tx": "database/sql/driver",
+ "driver.Value": "database/sql/driver",
+ "driver.ValueConverter": "database/sql/driver",
+ "driver.Valuer": "database/sql/driver",
+ "dsa.ErrInvalidPublicKey": "crypto/dsa",
+ "dsa.GenerateKey": "crypto/dsa",
+ "dsa.GenerateParameters": "crypto/dsa",
+ "dsa.L1024N160": "crypto/dsa",
+ "dsa.L2048N224": "crypto/dsa",
+ "dsa.L2048N256": "crypto/dsa",
+ "dsa.L3072N256": "crypto/dsa",
+ "dsa.ParameterSizes": "crypto/dsa",
+ "dsa.Parameters": "crypto/dsa",
+ "dsa.PrivateKey": "crypto/dsa",
+ "dsa.PublicKey": "crypto/dsa",
+ "dsa.Sign": "crypto/dsa",
+ "dsa.Verify": "crypto/dsa",
+ "dwarf.AddrType": "debug/dwarf",
+ "dwarf.ArrayType": "debug/dwarf",
+ "dwarf.Attr": "debug/dwarf",
+ "dwarf.AttrAbstractOrigin": "debug/dwarf",
+ "dwarf.AttrAccessibility": "debug/dwarf",
+ "dwarf.AttrAddrClass": "debug/dwarf",
+ "dwarf.AttrAllocated": "debug/dwarf",
+ "dwarf.AttrArtificial": "debug/dwarf",
+ "dwarf.AttrAssociated": "debug/dwarf",
+ "dwarf.AttrBaseTypes": "debug/dwarf",
+ "dwarf.AttrBitOffset": "debug/dwarf",
+ "dwarf.AttrBitSize": "debug/dwarf",
+ "dwarf.AttrByteSize": "debug/dwarf",
+ "dwarf.AttrCallColumn": "debug/dwarf",
+ "dwarf.AttrCallFile": "debug/dwarf",
+ "dwarf.AttrCallLine": "debug/dwarf",
+ "dwarf.AttrCalling": "debug/dwarf",
+ "dwarf.AttrCommonRef": "debug/dwarf",
+ "dwarf.AttrCompDir": "debug/dwarf",
+ "dwarf.AttrConstValue": "debug/dwarf",
+ "dwarf.AttrContainingType": "debug/dwarf",
+ "dwarf.AttrCount": "debug/dwarf",
+ "dwarf.AttrDataLocation": "debug/dwarf",
+ "dwarf.AttrDataMemberLoc": "debug/dwarf",
+ "dwarf.AttrDeclColumn": "debug/dwarf",
+ "dwarf.AttrDeclFile": "debug/dwarf",
+ "dwarf.AttrDeclLine": "debug/dwarf",
+ "dwarf.AttrDeclaration": "debug/dwarf",
+ "dwarf.AttrDefaultValue": "debug/dwarf",
+ "dwarf.AttrDescription": "debug/dwarf",
+ "dwarf.AttrDiscr": "debug/dwarf",
+ "dwarf.AttrDiscrList": "debug/dwarf",
+ "dwarf.AttrDiscrValue": "debug/dwarf",
+ "dwarf.AttrEncoding": "debug/dwarf",
+ "dwarf.AttrEntrypc": "debug/dwarf",
+ "dwarf.AttrExtension": "debug/dwarf",
+ "dwarf.AttrExternal": "debug/dwarf",
+ "dwarf.AttrFrameBase": "debug/dwarf",
+ "dwarf.AttrFriend": "debug/dwarf",
+ "dwarf.AttrHighpc": "debug/dwarf",
+ "dwarf.AttrIdentifierCase": "debug/dwarf",
+ "dwarf.AttrImport": "debug/dwarf",
+ "dwarf.AttrInline": "debug/dwarf",
+ "dwarf.AttrIsOptional": "debug/dwarf",
+ "dwarf.AttrLanguage": "debug/dwarf",
+ "dwarf.AttrLocation": "debug/dwarf",
+ "dwarf.AttrLowerBound": "debug/dwarf",
+ "dwarf.AttrLowpc": "debug/dwarf",
+ "dwarf.AttrMacroInfo": "debug/dwarf",
+ "dwarf.AttrName": "debug/dwarf",
+ "dwarf.AttrNamelistItem": "debug/dwarf",
+ "dwarf.AttrOrdering": "debug/dwarf",
+ "dwarf.AttrPriority": "debug/dwarf",
+ "dwarf.AttrProducer": "debug/dwarf",
+ "dwarf.AttrPrototyped": "debug/dwarf",
+ "dwarf.AttrRanges": "debug/dwarf",
+ "dwarf.AttrReturnAddr": "debug/dwarf",
+ "dwarf.AttrSegment": "debug/dwarf",
+ "dwarf.AttrSibling": "debug/dwarf",
+ "dwarf.AttrSpecification": "debug/dwarf",
+ "dwarf.AttrStartScope": "debug/dwarf",
+ "dwarf.AttrStaticLink": "debug/dwarf",
+ "dwarf.AttrStmtList": "debug/dwarf",
+ "dwarf.AttrStride": "debug/dwarf",
+ "dwarf.AttrStrideSize": "debug/dwarf",
+ "dwarf.AttrStringLength": "debug/dwarf",
+ "dwarf.AttrTrampoline": "debug/dwarf",
+ "dwarf.AttrType": "debug/dwarf",
+ "dwarf.AttrUpperBound": "debug/dwarf",
+ "dwarf.AttrUseLocation": "debug/dwarf",
+ "dwarf.AttrUseUTF8": "debug/dwarf",
+ "dwarf.AttrVarParam": "debug/dwarf",
+ "dwarf.AttrVirtuality": "debug/dwarf",
+ "dwarf.AttrVisibility": "debug/dwarf",
+ "dwarf.AttrVtableElemLoc": "debug/dwarf",
+ "dwarf.BasicType": "debug/dwarf",
+ "dwarf.BoolType": "debug/dwarf",
+ "dwarf.CharType": "debug/dwarf",
+ "dwarf.CommonType": "debug/dwarf",
+ "dwarf.ComplexType": "debug/dwarf",
+ "dwarf.Data": "debug/dwarf",
+ "dwarf.DecodeError": "debug/dwarf",
+ "dwarf.DotDotDotType": "debug/dwarf",
+ "dwarf.Entry": "debug/dwarf",
+ "dwarf.EnumType": "debug/dwarf",
+ "dwarf.EnumValue": "debug/dwarf",
+ "dwarf.Field": "debug/dwarf",
+ "dwarf.FloatType": "debug/dwarf",
+ "dwarf.FuncType": "debug/dwarf",
+ "dwarf.IntType": "debug/dwarf",
+ "dwarf.New": "debug/dwarf",
+ "dwarf.Offset": "debug/dwarf",
+ "dwarf.PtrType": "debug/dwarf",
+ "dwarf.QualType": "debug/dwarf",
+ "dwarf.Reader": "debug/dwarf",
+ "dwarf.StructField": "debug/dwarf",
+ "dwarf.StructType": "debug/dwarf",
+ "dwarf.Tag": "debug/dwarf",
+ "dwarf.TagAccessDeclaration": "debug/dwarf",
+ "dwarf.TagArrayType": "debug/dwarf",
+ "dwarf.TagBaseType": "debug/dwarf",
+ "dwarf.TagCatchDwarfBlock": "debug/dwarf",
+ "dwarf.TagClassType": "debug/dwarf",
+ "dwarf.TagCommonDwarfBlock": "debug/dwarf",
+ "dwarf.TagCommonInclusion": "debug/dwarf",
+ "dwarf.TagCompileUnit": "debug/dwarf",
+ "dwarf.TagConstType": "debug/dwarf",
+ "dwarf.TagConstant": "debug/dwarf",
+ "dwarf.TagDwarfProcedure": "debug/dwarf",
+ "dwarf.TagEntryPoint": "debug/dwarf",
+ "dwarf.TagEnumerationType": "debug/dwarf",
+ "dwarf.TagEnumerator": "debug/dwarf",
+ "dwarf.TagFileType": "debug/dwarf",
+ "dwarf.TagFormalParameter": "debug/dwarf",
+ "dwarf.TagFriend": "debug/dwarf",
+ "dwarf.TagImportedDeclaration": "debug/dwarf",
+ "dwarf.TagImportedModule": "debug/dwarf",
+ "dwarf.TagImportedUnit": "debug/dwarf",
+ "dwarf.TagInheritance": "debug/dwarf",
+ "dwarf.TagInlinedSubroutine": "debug/dwarf",
+ "dwarf.TagInterfaceType": "debug/dwarf",
+ "dwarf.TagLabel": "debug/dwarf",
+ "dwarf.TagLexDwarfBlock": "debug/dwarf",
+ "dwarf.TagMember": "debug/dwarf",
+ "dwarf.TagModule": "debug/dwarf",
+ "dwarf.TagMutableType": "debug/dwarf",
+ "dwarf.TagNamelist": "debug/dwarf",
+ "dwarf.TagNamelistItem": "debug/dwarf",
+ "dwarf.TagNamespace": "debug/dwarf",
+ "dwarf.TagPackedType": "debug/dwarf",
+ "dwarf.TagPartialUnit": "debug/dwarf",
+ "dwarf.TagPointerType": "debug/dwarf",
+ "dwarf.TagPtrToMemberType": "debug/dwarf",
+ "dwarf.TagReferenceType": "debug/dwarf",
+ "dwarf.TagRestrictType": "debug/dwarf",
+ "dwarf.TagSetType": "debug/dwarf",
+ "dwarf.TagStringType": "debug/dwarf",
+ "dwarf.TagStructType": "debug/dwarf",
+ "dwarf.TagSubprogram": "debug/dwarf",
+ "dwarf.TagSubrangeType": "debug/dwarf",
+ "dwarf.TagSubroutineType": "debug/dwarf",
+ "dwarf.TagTemplateTypeParameter": "debug/dwarf",
+ "dwarf.TagTemplateValueParameter": "debug/dwarf",
+ "dwarf.TagThrownType": "debug/dwarf",
+ "dwarf.TagTryDwarfBlock": "debug/dwarf",
+ "dwarf.TagTypedef": "debug/dwarf",
+ "dwarf.TagUnionType": "debug/dwarf",
+ "dwarf.TagUnspecifiedParameters": "debug/dwarf",
+ "dwarf.TagUnspecifiedType": "debug/dwarf",
+ "dwarf.TagVariable": "debug/dwarf",
+ "dwarf.TagVariant": "debug/dwarf",
+ "dwarf.TagVariantPart": "debug/dwarf",
+ "dwarf.TagVolatileType": "debug/dwarf",
+ "dwarf.TagWithStmt": "debug/dwarf",
+ "dwarf.Type": "debug/dwarf",
+ "dwarf.TypedefType": "debug/dwarf",
+ "dwarf.UcharType": "debug/dwarf",
+ "dwarf.UintType": "debug/dwarf",
+ "dwarf.VoidType": "debug/dwarf",
+ "ecdsa.GenerateKey": "crypto/ecdsa",
+ "ecdsa.PrivateKey": "crypto/ecdsa",
+ "ecdsa.PublicKey": "crypto/ecdsa",
+ "ecdsa.Sign": "crypto/ecdsa",
+ "ecdsa.Verify": "crypto/ecdsa",
+ "elf.ARM_MAGIC_TRAMP_NUMBER": "debug/elf",
+ "elf.Class": "debug/elf",
+ "elf.DF_BIND_NOW": "debug/elf",
+ "elf.DF_ORIGIN": "debug/elf",
+ "elf.DF_STATIC_TLS": "debug/elf",
+ "elf.DF_SYMBOLIC": "debug/elf",
+ "elf.DF_TEXTREL": "debug/elf",
+ "elf.DT_BIND_NOW": "debug/elf",
+ "elf.DT_DEBUG": "debug/elf",
+ "elf.DT_ENCODING": "debug/elf",
+ "elf.DT_FINI": "debug/elf",
+ "elf.DT_FINI_ARRAY": "debug/elf",
+ "elf.DT_FINI_ARRAYSZ": "debug/elf",
+ "elf.DT_FLAGS": "debug/elf",
+ "elf.DT_HASH": "debug/elf",
+ "elf.DT_HIOS": "debug/elf",
+ "elf.DT_HIPROC": "debug/elf",
+ "elf.DT_INIT": "debug/elf",
+ "elf.DT_INIT_ARRAY": "debug/elf",
+ "elf.DT_INIT_ARRAYSZ": "debug/elf",
+ "elf.DT_JMPREL": "debug/elf",
+ "elf.DT_LOOS": "debug/elf",
+ "elf.DT_LOPROC": "debug/elf",
+ "elf.DT_NEEDED": "debug/elf",
+ "elf.DT_NULL": "debug/elf",
+ "elf.DT_PLTGOT": "debug/elf",
+ "elf.DT_PLTREL": "debug/elf",
+ "elf.DT_PLTRELSZ": "debug/elf",
+ "elf.DT_PREINIT_ARRAY": "debug/elf",
+ "elf.DT_PREINIT_ARRAYSZ": "debug/elf",
+ "elf.DT_REL": "debug/elf",
+ "elf.DT_RELA": "debug/elf",
+ "elf.DT_RELAENT": "debug/elf",
+ "elf.DT_RELASZ": "debug/elf",
+ "elf.DT_RELENT": "debug/elf",
+ "elf.DT_RELSZ": "debug/elf",
+ "elf.DT_RPATH": "debug/elf",
+ "elf.DT_RUNPATH": "debug/elf",
+ "elf.DT_SONAME": "debug/elf",
+ "elf.DT_STRSZ": "debug/elf",
+ "elf.DT_STRTAB": "debug/elf",
+ "elf.DT_SYMBOLIC": "debug/elf",
+ "elf.DT_SYMENT": "debug/elf",
+ "elf.DT_SYMTAB": "debug/elf",
+ "elf.DT_TEXTREL": "debug/elf",
+ "elf.DT_VERNEED": "debug/elf",
+ "elf.DT_VERNEEDNUM": "debug/elf",
+ "elf.DT_VERSYM": "debug/elf",
+ "elf.Data": "debug/elf",
+ "elf.Dyn32": "debug/elf",
+ "elf.Dyn64": "debug/elf",
+ "elf.DynFlag": "debug/elf",
+ "elf.DynTag": "debug/elf",
+ "elf.EI_ABIVERSION": "debug/elf",
+ "elf.EI_CLASS": "debug/elf",
+ "elf.EI_DATA": "debug/elf",
+ "elf.EI_NIDENT": "debug/elf",
+ "elf.EI_OSABI": "debug/elf",
+ "elf.EI_PAD": "debug/elf",
+ "elf.EI_VERSION": "debug/elf",
+ "elf.ELFCLASS32": "debug/elf",
+ "elf.ELFCLASS64": "debug/elf",
+ "elf.ELFCLASSNONE": "debug/elf",
+ "elf.ELFDATA2LSB": "debug/elf",
+ "elf.ELFDATA2MSB": "debug/elf",
+ "elf.ELFDATANONE": "debug/elf",
+ "elf.ELFMAG": "debug/elf",
+ "elf.ELFOSABI_86OPEN": "debug/elf",
+ "elf.ELFOSABI_AIX": "debug/elf",
+ "elf.ELFOSABI_ARM": "debug/elf",
+ "elf.ELFOSABI_FREEBSD": "debug/elf",
+ "elf.ELFOSABI_HPUX": "debug/elf",
+ "elf.ELFOSABI_HURD": "debug/elf",
+ "elf.ELFOSABI_IRIX": "debug/elf",
+ "elf.ELFOSABI_LINUX": "debug/elf",
+ "elf.ELFOSABI_MODESTO": "debug/elf",
+ "elf.ELFOSABI_NETBSD": "debug/elf",
+ "elf.ELFOSABI_NONE": "debug/elf",
+ "elf.ELFOSABI_NSK": "debug/elf",
+ "elf.ELFOSABI_OPENBSD": "debug/elf",
+ "elf.ELFOSABI_OPENVMS": "debug/elf",
+ "elf.ELFOSABI_SOLARIS": "debug/elf",
+ "elf.ELFOSABI_STANDALONE": "debug/elf",
+ "elf.ELFOSABI_TRU64": "debug/elf",
+ "elf.EM_386": "debug/elf",
+ "elf.EM_486": "debug/elf",
+ "elf.EM_68HC12": "debug/elf",
+ "elf.EM_68K": "debug/elf",
+ "elf.EM_860": "debug/elf",
+ "elf.EM_88K": "debug/elf",
+ "elf.EM_960": "debug/elf",
+ "elf.EM_ALPHA": "debug/elf",
+ "elf.EM_ALPHA_STD": "debug/elf",
+ "elf.EM_ARC": "debug/elf",
+ "elf.EM_ARM": "debug/elf",
+ "elf.EM_COLDFIRE": "debug/elf",
+ "elf.EM_FR20": "debug/elf",
+ "elf.EM_H8S": "debug/elf",
+ "elf.EM_H8_300": "debug/elf",
+ "elf.EM_H8_300H": "debug/elf",
+ "elf.EM_H8_500": "debug/elf",
+ "elf.EM_IA_64": "debug/elf",
+ "elf.EM_M32": "debug/elf",
+ "elf.EM_ME16": "debug/elf",
+ "elf.EM_MIPS": "debug/elf",
+ "elf.EM_MIPS_RS3_LE": "debug/elf",
+ "elf.EM_MIPS_RS4_BE": "debug/elf",
+ "elf.EM_MIPS_X": "debug/elf",
+ "elf.EM_MMA": "debug/elf",
+ "elf.EM_NCPU": "debug/elf",
+ "elf.EM_NDR1": "debug/elf",
+ "elf.EM_NONE": "debug/elf",
+ "elf.EM_PARISC": "debug/elf",
+ "elf.EM_PCP": "debug/elf",
+ "elf.EM_PPC": "debug/elf",
+ "elf.EM_PPC64": "debug/elf",
+ "elf.EM_RCE": "debug/elf",
+ "elf.EM_RH32": "debug/elf",
+ "elf.EM_S370": "debug/elf",
+ "elf.EM_S390": "debug/elf",
+ "elf.EM_SH": "debug/elf",
+ "elf.EM_SPARC": "debug/elf",
+ "elf.EM_SPARC32PLUS": "debug/elf",
+ "elf.EM_SPARCV9": "debug/elf",
+ "elf.EM_ST100": "debug/elf",
+ "elf.EM_STARCORE": "debug/elf",
+ "elf.EM_TINYJ": "debug/elf",
+ "elf.EM_TRICORE": "debug/elf",
+ "elf.EM_V800": "debug/elf",
+ "elf.EM_VPP500": "debug/elf",
+ "elf.EM_X86_64": "debug/elf",
+ "elf.ET_CORE": "debug/elf",
+ "elf.ET_DYN": "debug/elf",
+ "elf.ET_EXEC": "debug/elf",
+ "elf.ET_HIOS": "debug/elf",
+ "elf.ET_HIPROC": "debug/elf",
+ "elf.ET_LOOS": "debug/elf",
+ "elf.ET_LOPROC": "debug/elf",
+ "elf.ET_NONE": "debug/elf",
+ "elf.ET_REL": "debug/elf",
+ "elf.EV_CURRENT": "debug/elf",
+ "elf.EV_NONE": "debug/elf",
+ "elf.File": "debug/elf",
+ "elf.FileHeader": "debug/elf",
+ "elf.FormatError": "debug/elf",
+ "elf.Header32": "debug/elf",
+ "elf.Header64": "debug/elf",
+ "elf.ImportedSymbol": "debug/elf",
+ "elf.Machine": "debug/elf",
+ "elf.NT_FPREGSET": "debug/elf",
+ "elf.NT_PRPSINFO": "debug/elf",
+ "elf.NT_PRSTATUS": "debug/elf",
+ "elf.NType": "debug/elf",
+ "elf.NewFile": "debug/elf",
+ "elf.OSABI": "debug/elf",
+ "elf.Open": "debug/elf",
+ "elf.PF_MASKOS": "debug/elf",
+ "elf.PF_MASKPROC": "debug/elf",
+ "elf.PF_R": "debug/elf",
+ "elf.PF_W": "debug/elf",
+ "elf.PF_X": "debug/elf",
+ "elf.PT_DYNAMIC": "debug/elf",
+ "elf.PT_HIOS": "debug/elf",
+ "elf.PT_HIPROC": "debug/elf",
+ "elf.PT_INTERP": "debug/elf",
+ "elf.PT_LOAD": "debug/elf",
+ "elf.PT_LOOS": "debug/elf",
+ "elf.PT_LOPROC": "debug/elf",
+ "elf.PT_NOTE": "debug/elf",
+ "elf.PT_NULL": "debug/elf",
+ "elf.PT_PHDR": "debug/elf",
+ "elf.PT_SHLIB": "debug/elf",
+ "elf.PT_TLS": "debug/elf",
+ "elf.Prog": "debug/elf",
+ "elf.Prog32": "debug/elf",
+ "elf.Prog64": "debug/elf",
+ "elf.ProgFlag": "debug/elf",
+ "elf.ProgHeader": "debug/elf",
+ "elf.ProgType": "debug/elf",
+ "elf.R_386": "debug/elf",
+ "elf.R_386_32": "debug/elf",
+ "elf.R_386_COPY": "debug/elf",
+ "elf.R_386_GLOB_DAT": "debug/elf",
+ "elf.R_386_GOT32": "debug/elf",
+ "elf.R_386_GOTOFF": "debug/elf",
+ "elf.R_386_GOTPC": "debug/elf",
+ "elf.R_386_JMP_SLOT": "debug/elf",
+ "elf.R_386_NONE": "debug/elf",
+ "elf.R_386_PC32": "debug/elf",
+ "elf.R_386_PLT32": "debug/elf",
+ "elf.R_386_RELATIVE": "debug/elf",
+ "elf.R_386_TLS_DTPMOD32": "debug/elf",
+ "elf.R_386_TLS_DTPOFF32": "debug/elf",
+ "elf.R_386_TLS_GD": "debug/elf",
+ "elf.R_386_TLS_GD_32": "debug/elf",
+ "elf.R_386_TLS_GD_CALL": "debug/elf",
+ "elf.R_386_TLS_GD_POP": "debug/elf",
+ "elf.R_386_TLS_GD_PUSH": "debug/elf",
+ "elf.R_386_TLS_GOTIE": "debug/elf",
+ "elf.R_386_TLS_IE": "debug/elf",
+ "elf.R_386_TLS_IE_32": "debug/elf",
+ "elf.R_386_TLS_LDM": "debug/elf",
+ "elf.R_386_TLS_LDM_32": "debug/elf",
+ "elf.R_386_TLS_LDM_CALL": "debug/elf",
+ "elf.R_386_TLS_LDM_POP": "debug/elf",
+ "elf.R_386_TLS_LDM_PUSH": "debug/elf",
+ "elf.R_386_TLS_LDO_32": "debug/elf",
+ "elf.R_386_TLS_LE": "debug/elf",
+ "elf.R_386_TLS_LE_32": "debug/elf",
+ "elf.R_386_TLS_TPOFF": "debug/elf",
+ "elf.R_386_TLS_TPOFF32": "debug/elf",
+ "elf.R_ALPHA": "debug/elf",
+ "elf.R_ALPHA_BRADDR": "debug/elf",
+ "elf.R_ALPHA_COPY": "debug/elf",
+ "elf.R_ALPHA_GLOB_DAT": "debug/elf",
+ "elf.R_ALPHA_GPDISP": "debug/elf",
+ "elf.R_ALPHA_GPREL32": "debug/elf",
+ "elf.R_ALPHA_GPRELHIGH": "debug/elf",
+ "elf.R_ALPHA_GPRELLOW": "debug/elf",
+ "elf.R_ALPHA_GPVALUE": "debug/elf",
+ "elf.R_ALPHA_HINT": "debug/elf",
+ "elf.R_ALPHA_IMMED_BR_HI32": "debug/elf",
+ "elf.R_ALPHA_IMMED_GP_16": "debug/elf",
+ "elf.R_ALPHA_IMMED_GP_HI32": "debug/elf",
+ "elf.R_ALPHA_IMMED_LO32": "debug/elf",
+ "elf.R_ALPHA_IMMED_SCN_HI32": "debug/elf",
+ "elf.R_ALPHA_JMP_SLOT": "debug/elf",
+ "elf.R_ALPHA_LITERAL": "debug/elf",
+ "elf.R_ALPHA_LITUSE": "debug/elf",
+ "elf.R_ALPHA_NONE": "debug/elf",
+ "elf.R_ALPHA_OP_PRSHIFT": "debug/elf",
+ "elf.R_ALPHA_OP_PSUB": "debug/elf",
+ "elf.R_ALPHA_OP_PUSH": "debug/elf",
+ "elf.R_ALPHA_OP_STORE": "debug/elf",
+ "elf.R_ALPHA_REFLONG": "debug/elf",
+ "elf.R_ALPHA_REFQUAD": "debug/elf",
+ "elf.R_ALPHA_RELATIVE": "debug/elf",
+ "elf.R_ALPHA_SREL16": "debug/elf",
+ "elf.R_ALPHA_SREL32": "debug/elf",
+ "elf.R_ALPHA_SREL64": "debug/elf",
+ "elf.R_ARM": "debug/elf",
+ "elf.R_ARM_ABS12": "debug/elf",
+ "elf.R_ARM_ABS16": "debug/elf",
+ "elf.R_ARM_ABS32": "debug/elf",
+ "elf.R_ARM_ABS8": "debug/elf",
+ "elf.R_ARM_AMP_VCALL9": "debug/elf",
+ "elf.R_ARM_COPY": "debug/elf",
+ "elf.R_ARM_GLOB_DAT": "debug/elf",
+ "elf.R_ARM_GNU_VTENTRY": "debug/elf",
+ "elf.R_ARM_GNU_VTINHERIT": "debug/elf",
+ "elf.R_ARM_GOT32": "debug/elf",
+ "elf.R_ARM_GOTOFF": "debug/elf",
+ "elf.R_ARM_GOTPC": "debug/elf",
+ "elf.R_ARM_JUMP_SLOT": "debug/elf",
+ "elf.R_ARM_NONE": "debug/elf",
+ "elf.R_ARM_PC13": "debug/elf",
+ "elf.R_ARM_PC24": "debug/elf",
+ "elf.R_ARM_PLT32": "debug/elf",
+ "elf.R_ARM_RABS32": "debug/elf",
+ "elf.R_ARM_RBASE": "debug/elf",
+ "elf.R_ARM_REL32": "debug/elf",
+ "elf.R_ARM_RELATIVE": "debug/elf",
+ "elf.R_ARM_RPC24": "debug/elf",
+ "elf.R_ARM_RREL32": "debug/elf",
+ "elf.R_ARM_RSBREL32": "debug/elf",
+ "elf.R_ARM_SBREL32": "debug/elf",
+ "elf.R_ARM_SWI24": "debug/elf",
+ "elf.R_ARM_THM_ABS5": "debug/elf",
+ "elf.R_ARM_THM_PC22": "debug/elf",
+ "elf.R_ARM_THM_PC8": "debug/elf",
+ "elf.R_ARM_THM_RPC22": "debug/elf",
+ "elf.R_ARM_THM_SWI8": "debug/elf",
+ "elf.R_ARM_THM_XPC22": "debug/elf",
+ "elf.R_ARM_XPC25": "debug/elf",
+ "elf.R_INFO": "debug/elf",
+ "elf.R_INFO32": "debug/elf",
+ "elf.R_PPC": "debug/elf",
+ "elf.R_PPC_ADDR14": "debug/elf",
+ "elf.R_PPC_ADDR14_BRNTAKEN": "debug/elf",
+ "elf.R_PPC_ADDR14_BRTAKEN": "debug/elf",
+ "elf.R_PPC_ADDR16": "debug/elf",
+ "elf.R_PPC_ADDR16_HA": "debug/elf",
+ "elf.R_PPC_ADDR16_HI": "debug/elf",
+ "elf.R_PPC_ADDR16_LO": "debug/elf",
+ "elf.R_PPC_ADDR24": "debug/elf",
+ "elf.R_PPC_ADDR32": "debug/elf",
+ "elf.R_PPC_COPY": "debug/elf",
+ "elf.R_PPC_DTPMOD32": "debug/elf",
+ "elf.R_PPC_DTPREL16": "debug/elf",
+ "elf.R_PPC_DTPREL16_HA": "debug/elf",
+ "elf.R_PPC_DTPREL16_HI": "debug/elf",
+ "elf.R_PPC_DTPREL16_LO": "debug/elf",
+ "elf.R_PPC_DTPREL32": "debug/elf",
+ "elf.R_PPC_EMB_BIT_FLD": "debug/elf",
+ "elf.R_PPC_EMB_MRKREF": "debug/elf",
+ "elf.R_PPC_EMB_NADDR16": "debug/elf",
+ "elf.R_PPC_EMB_NADDR16_HA": "debug/elf",
+ "elf.R_PPC_EMB_NADDR16_HI": "debug/elf",
+ "elf.R_PPC_EMB_NADDR16_LO": "debug/elf",
+ "elf.R_PPC_EMB_NADDR32": "debug/elf",
+ "elf.R_PPC_EMB_RELSDA": "debug/elf",
+ "elf.R_PPC_EMB_RELSEC16": "debug/elf",
+ "elf.R_PPC_EMB_RELST_HA": "debug/elf",
+ "elf.R_PPC_EMB_RELST_HI": "debug/elf",
+ "elf.R_PPC_EMB_RELST_LO": "debug/elf",
+ "elf.R_PPC_EMB_SDA21": "debug/elf",
+ "elf.R_PPC_EMB_SDA2I16": "debug/elf",
+ "elf.R_PPC_EMB_SDA2REL": "debug/elf",
+ "elf.R_PPC_EMB_SDAI16": "debug/elf",
+ "elf.R_PPC_GLOB_DAT": "debug/elf",
+ "elf.R_PPC_GOT16": "debug/elf",
+ "elf.R_PPC_GOT16_HA": "debug/elf",
+ "elf.R_PPC_GOT16_HI": "debug/elf",
+ "elf.R_PPC_GOT16_LO": "debug/elf",
+ "elf.R_PPC_GOT_TLSGD16": "debug/elf",
+ "elf.R_PPC_GOT_TLSGD16_HA": "debug/elf",
+ "elf.R_PPC_GOT_TLSGD16_HI": "debug/elf",
+ "elf.R_PPC_GOT_TLSGD16_LO": "debug/elf",
+ "elf.R_PPC_GOT_TLSLD16": "debug/elf",
+ "elf.R_PPC_GOT_TLSLD16_HA": "debug/elf",
+ "elf.R_PPC_GOT_TLSLD16_HI": "debug/elf",
+ "elf.R_PPC_GOT_TLSLD16_LO": "debug/elf",
+ "elf.R_PPC_GOT_TPREL16": "debug/elf",
+ "elf.R_PPC_GOT_TPREL16_HA": "debug/elf",
+ "elf.R_PPC_GOT_TPREL16_HI": "debug/elf",
+ "elf.R_PPC_GOT_TPREL16_LO": "debug/elf",
+ "elf.R_PPC_JMP_SLOT": "debug/elf",
+ "elf.R_PPC_LOCAL24PC": "debug/elf",
+ "elf.R_PPC_NONE": "debug/elf",
+ "elf.R_PPC_PLT16_HA": "debug/elf",
+ "elf.R_PPC_PLT16_HI": "debug/elf",
+ "elf.R_PPC_PLT16_LO": "debug/elf",
+ "elf.R_PPC_PLT32": "debug/elf",
+ "elf.R_PPC_PLTREL24": "debug/elf",
+ "elf.R_PPC_PLTREL32": "debug/elf",
+ "elf.R_PPC_REL14": "debug/elf",
+ "elf.R_PPC_REL14_BRNTAKEN": "debug/elf",
+ "elf.R_PPC_REL14_BRTAKEN": "debug/elf",
+ "elf.R_PPC_REL24": "debug/elf",
+ "elf.R_PPC_REL32": "debug/elf",
+ "elf.R_PPC_RELATIVE": "debug/elf",
+ "elf.R_PPC_SDAREL16": "debug/elf",
+ "elf.R_PPC_SECTOFF": "debug/elf",
+ "elf.R_PPC_SECTOFF_HA": "debug/elf",
+ "elf.R_PPC_SECTOFF_HI": "debug/elf",
+ "elf.R_PPC_SECTOFF_LO": "debug/elf",
+ "elf.R_PPC_TLS": "debug/elf",
+ "elf.R_PPC_TPREL16": "debug/elf",
+ "elf.R_PPC_TPREL16_HA": "debug/elf",
+ "elf.R_PPC_TPREL16_HI": "debug/elf",
+ "elf.R_PPC_TPREL16_LO": "debug/elf",
+ "elf.R_PPC_TPREL32": "debug/elf",
+ "elf.R_PPC_UADDR16": "debug/elf",
+ "elf.R_PPC_UADDR32": "debug/elf",
+ "elf.R_SPARC": "debug/elf",
+ "elf.R_SPARC_10": "debug/elf",
+ "elf.R_SPARC_11": "debug/elf",
+ "elf.R_SPARC_13": "debug/elf",
+ "elf.R_SPARC_16": "debug/elf",
+ "elf.R_SPARC_22": "debug/elf",
+ "elf.R_SPARC_32": "debug/elf",
+ "elf.R_SPARC_5": "debug/elf",
+ "elf.R_SPARC_6": "debug/elf",
+ "elf.R_SPARC_64": "debug/elf",
+ "elf.R_SPARC_7": "debug/elf",
+ "elf.R_SPARC_8": "debug/elf",
+ "elf.R_SPARC_COPY": "debug/elf",
+ "elf.R_SPARC_DISP16": "debug/elf",
+ "elf.R_SPARC_DISP32": "debug/elf",
+ "elf.R_SPARC_DISP64": "debug/elf",
+ "elf.R_SPARC_DISP8": "debug/elf",
+ "elf.R_SPARC_GLOB_DAT": "debug/elf",
+ "elf.R_SPARC_GLOB_JMP": "debug/elf",
+ "elf.R_SPARC_GOT10": "debug/elf",
+ "elf.R_SPARC_GOT13": "debug/elf",
+ "elf.R_SPARC_GOT22": "debug/elf",
+ "elf.R_SPARC_H44": "debug/elf",
+ "elf.R_SPARC_HH22": "debug/elf",
+ "elf.R_SPARC_HI22": "debug/elf",
+ "elf.R_SPARC_HIPLT22": "debug/elf",
+ "elf.R_SPARC_HIX22": "debug/elf",
+ "elf.R_SPARC_HM10": "debug/elf",
+ "elf.R_SPARC_JMP_SLOT": "debug/elf",
+ "elf.R_SPARC_L44": "debug/elf",
+ "elf.R_SPARC_LM22": "debug/elf",
+ "elf.R_SPARC_LO10": "debug/elf",
+ "elf.R_SPARC_LOPLT10": "debug/elf",
+ "elf.R_SPARC_LOX10": "debug/elf",
+ "elf.R_SPARC_M44": "debug/elf",
+ "elf.R_SPARC_NONE": "debug/elf",
+ "elf.R_SPARC_OLO10": "debug/elf",
+ "elf.R_SPARC_PC10": "debug/elf",
+ "elf.R_SPARC_PC22": "debug/elf",
+ "elf.R_SPARC_PCPLT10": "debug/elf",
+ "elf.R_SPARC_PCPLT22": "debug/elf",
+ "elf.R_SPARC_PCPLT32": "debug/elf",
+ "elf.R_SPARC_PC_HH22": "debug/elf",
+ "elf.R_SPARC_PC_HM10": "debug/elf",
+ "elf.R_SPARC_PC_LM22": "debug/elf",
+ "elf.R_SPARC_PLT32": "debug/elf",
+ "elf.R_SPARC_PLT64": "debug/elf",
+ "elf.R_SPARC_REGISTER": "debug/elf",
+ "elf.R_SPARC_RELATIVE": "debug/elf",
+ "elf.R_SPARC_UA16": "debug/elf",
+ "elf.R_SPARC_UA32": "debug/elf",
+ "elf.R_SPARC_UA64": "debug/elf",
+ "elf.R_SPARC_WDISP16": "debug/elf",
+ "elf.R_SPARC_WDISP19": "debug/elf",
+ "elf.R_SPARC_WDISP22": "debug/elf",
+ "elf.R_SPARC_WDISP30": "debug/elf",
+ "elf.R_SPARC_WPLT30": "debug/elf",
+ "elf.R_SYM32": "debug/elf",
+ "elf.R_SYM64": "debug/elf",
+ "elf.R_TYPE32": "debug/elf",
+ "elf.R_TYPE64": "debug/elf",
+ "elf.R_X86_64": "debug/elf",
+ "elf.R_X86_64_16": "debug/elf",
+ "elf.R_X86_64_32": "debug/elf",
+ "elf.R_X86_64_32S": "debug/elf",
+ "elf.R_X86_64_64": "debug/elf",
+ "elf.R_X86_64_8": "debug/elf",
+ "elf.R_X86_64_COPY": "debug/elf",
+ "elf.R_X86_64_DTPMOD64": "debug/elf",
+ "elf.R_X86_64_DTPOFF32": "debug/elf",
+ "elf.R_X86_64_DTPOFF64": "debug/elf",
+ "elf.R_X86_64_GLOB_DAT": "debug/elf",
+ "elf.R_X86_64_GOT32": "debug/elf",
+ "elf.R_X86_64_GOTPCREL": "debug/elf",
+ "elf.R_X86_64_GOTTPOFF": "debug/elf",
+ "elf.R_X86_64_JMP_SLOT": "debug/elf",
+ "elf.R_X86_64_NONE": "debug/elf",
+ "elf.R_X86_64_PC16": "debug/elf",
+ "elf.R_X86_64_PC32": "debug/elf",
+ "elf.R_X86_64_PC8": "debug/elf",
+ "elf.R_X86_64_PLT32": "debug/elf",
+ "elf.R_X86_64_RELATIVE": "debug/elf",
+ "elf.R_X86_64_TLSGD": "debug/elf",
+ "elf.R_X86_64_TLSLD": "debug/elf",
+ "elf.R_X86_64_TPOFF32": "debug/elf",
+ "elf.R_X86_64_TPOFF64": "debug/elf",
+ "elf.Rel32": "debug/elf",
+ "elf.Rel64": "debug/elf",
+ "elf.Rela32": "debug/elf",
+ "elf.Rela64": "debug/elf",
+ "elf.SHF_ALLOC": "debug/elf",
+ "elf.SHF_EXECINSTR": "debug/elf",
+ "elf.SHF_GROUP": "debug/elf",
+ "elf.SHF_INFO_LINK": "debug/elf",
+ "elf.SHF_LINK_ORDER": "debug/elf",
+ "elf.SHF_MASKOS": "debug/elf",
+ "elf.SHF_MASKPROC": "debug/elf",
+ "elf.SHF_MERGE": "debug/elf",
+ "elf.SHF_OS_NONCONFORMING": "debug/elf",
+ "elf.SHF_STRINGS": "debug/elf",
+ "elf.SHF_TLS": "debug/elf",
+ "elf.SHF_WRITE": "debug/elf",
+ "elf.SHN_ABS": "debug/elf",
+ "elf.SHN_COMMON": "debug/elf",
+ "elf.SHN_HIOS": "debug/elf",
+ "elf.SHN_HIPROC": "debug/elf",
+ "elf.SHN_HIRESERVE": "debug/elf",
+ "elf.SHN_LOOS": "debug/elf",
+ "elf.SHN_LOPROC": "debug/elf",
+ "elf.SHN_LORESERVE": "debug/elf",
+ "elf.SHN_UNDEF": "debug/elf",
+ "elf.SHN_XINDEX": "debug/elf",
+ "elf.SHT_DYNAMIC": "debug/elf",
+ "elf.SHT_DYNSYM": "debug/elf",
+ "elf.SHT_FINI_ARRAY": "debug/elf",
+ "elf.SHT_GNU_ATTRIBUTES": "debug/elf",
+ "elf.SHT_GNU_HASH": "debug/elf",
+ "elf.SHT_GNU_LIBLIST": "debug/elf",
+ "elf.SHT_GNU_VERDEF": "debug/elf",
+ "elf.SHT_GNU_VERNEED": "debug/elf",
+ "elf.SHT_GNU_VERSYM": "debug/elf",
+ "elf.SHT_GROUP": "debug/elf",
+ "elf.SHT_HASH": "debug/elf",
+ "elf.SHT_HIOS": "debug/elf",
+ "elf.SHT_HIPROC": "debug/elf",
+ "elf.SHT_HIUSER": "debug/elf",
+ "elf.SHT_INIT_ARRAY": "debug/elf",
+ "elf.SHT_LOOS": "debug/elf",
+ "elf.SHT_LOPROC": "debug/elf",
+ "elf.SHT_LOUSER": "debug/elf",
+ "elf.SHT_NOBITS": "debug/elf",
+ "elf.SHT_NOTE": "debug/elf",
+ "elf.SHT_NULL": "debug/elf",
+ "elf.SHT_PREINIT_ARRAY": "debug/elf",
+ "elf.SHT_PROGBITS": "debug/elf",
+ "elf.SHT_REL": "debug/elf",
+ "elf.SHT_RELA": "debug/elf",
+ "elf.SHT_SHLIB": "debug/elf",
+ "elf.SHT_STRTAB": "debug/elf",
+ "elf.SHT_SYMTAB": "debug/elf",
+ "elf.SHT_SYMTAB_SHNDX": "debug/elf",
+ "elf.STB_GLOBAL": "debug/elf",
+ "elf.STB_HIOS": "debug/elf",
+ "elf.STB_HIPROC": "debug/elf",
+ "elf.STB_LOCAL": "debug/elf",
+ "elf.STB_LOOS": "debug/elf",
+ "elf.STB_LOPROC": "debug/elf",
+ "elf.STB_WEAK": "debug/elf",
+ "elf.STT_COMMON": "debug/elf",
+ "elf.STT_FILE": "debug/elf",
+ "elf.STT_FUNC": "debug/elf",
+ "elf.STT_HIOS": "debug/elf",
+ "elf.STT_HIPROC": "debug/elf",
+ "elf.STT_LOOS": "debug/elf",
+ "elf.STT_LOPROC": "debug/elf",
+ "elf.STT_NOTYPE": "debug/elf",
+ "elf.STT_OBJECT": "debug/elf",
+ "elf.STT_SECTION": "debug/elf",
+ "elf.STT_TLS": "debug/elf",
+ "elf.STV_DEFAULT": "debug/elf",
+ "elf.STV_HIDDEN": "debug/elf",
+ "elf.STV_INTERNAL": "debug/elf",
+ "elf.STV_PROTECTED": "debug/elf",
+ "elf.ST_BIND": "debug/elf",
+ "elf.ST_INFO": "debug/elf",
+ "elf.ST_TYPE": "debug/elf",
+ "elf.ST_VISIBILITY": "debug/elf",
+ "elf.Section": "debug/elf",
+ "elf.Section32": "debug/elf",
+ "elf.Section64": "debug/elf",
+ "elf.SectionFlag": "debug/elf",
+ "elf.SectionHeader": "debug/elf",
+ "elf.SectionIndex": "debug/elf",
+ "elf.SectionType": "debug/elf",
+ "elf.Sym32": "debug/elf",
+ "elf.Sym32Size": "debug/elf",
+ "elf.Sym64": "debug/elf",
+ "elf.Sym64Size": "debug/elf",
+ "elf.SymBind": "debug/elf",
+ "elf.SymType": "debug/elf",
+ "elf.SymVis": "debug/elf",
+ "elf.Symbol": "debug/elf",
+ "elf.Type": "debug/elf",
+ "elf.Version": "debug/elf",
+ "elliptic.Curve": "crypto/elliptic",
+ "elliptic.CurveParams": "crypto/elliptic",
+ "elliptic.GenerateKey": "crypto/elliptic",
+ "elliptic.Marshal": "crypto/elliptic",
+ "elliptic.P224": "crypto/elliptic",
+ "elliptic.P256": "crypto/elliptic",
+ "elliptic.P384": "crypto/elliptic",
+ "elliptic.P521": "crypto/elliptic",
+ "elliptic.Unmarshal": "crypto/elliptic",
+ "encoding.BinaryMarshaler": "encoding",
+ "encoding.BinaryUnmarshaler": "encoding",
+ "encoding.TextMarshaler": "encoding",
+ "encoding.TextUnmarshaler": "encoding",
+ "errors.New": "errors",
+ "exec.Cmd": "os/exec",
+ "exec.Command": "os/exec",
+ "exec.ErrNotFound": "os/exec",
+ "exec.Error": "os/exec",
+ "exec.ExitError": "os/exec",
+ "exec.LookPath": "os/exec",
+ "expvar.Do": "expvar",
+ "expvar.Float": "expvar",
+ "expvar.Func": "expvar",
+ "expvar.Get": "expvar",
+ "expvar.Int": "expvar",
+ "expvar.KeyValue": "expvar",
+ "expvar.Map": "expvar",
+ "expvar.NewFloat": "expvar",
+ "expvar.NewInt": "expvar",
+ "expvar.NewMap": "expvar",
+ "expvar.NewString": "expvar",
+ "expvar.Publish": "expvar",
+ "expvar.String": "expvar",
+ "expvar.Var": "expvar",
+ "fcgi.Serve": "net/http/fcgi",
+ "filepath.Abs": "path/filepath",
+ "filepath.Base": "path/filepath",
+ "filepath.Clean": "path/filepath",
+ "filepath.Dir": "path/filepath",
+ "filepath.ErrBadPattern": "path/filepath",
+ "filepath.EvalSymlinks": "path/filepath",
+ "filepath.Ext": "path/filepath",
+ "filepath.FromSlash": "path/filepath",
+ "filepath.Glob": "path/filepath",
+ "filepath.HasPrefix": "path/filepath",
+ "filepath.IsAbs": "path/filepath",
+ "filepath.Join": "path/filepath",
+ "filepath.ListSeparator": "path/filepath",
+ "filepath.Match": "path/filepath",
+ "filepath.Rel": "path/filepath",
+ "filepath.Separator": "path/filepath",
+ "filepath.SkipDir": "path/filepath",
+ "filepath.Split": "path/filepath",
+ "filepath.SplitList": "path/filepath",
+ "filepath.ToSlash": "path/filepath",
+ "filepath.VolumeName": "path/filepath",
+ "filepath.Walk": "path/filepath",
+ "filepath.WalkFunc": "path/filepath",
+ "flag.Arg": "flag",
+ "flag.Args": "flag",
+ "flag.Bool": "flag",
+ "flag.BoolVar": "flag",
+ "flag.CommandLine": "flag",
+ "flag.ContinueOnError": "flag",
+ "flag.Duration": "flag",
+ "flag.DurationVar": "flag",
+ "flag.ErrHelp": "flag",
+ "flag.ErrorHandling": "flag",
+ "flag.ExitOnError": "flag",
+ "flag.Flag": "flag",
+ "flag.FlagSet": "flag",
+ "flag.Float64": "flag",
+ "flag.Float64Var": "flag",
+ "flag.Getter": "flag",
+ "flag.Int": "flag",
+ "flag.Int64": "flag",
+ "flag.Int64Var": "flag",
+ "flag.IntVar": "flag",
+ "flag.Lookup": "flag",
+ "flag.NArg": "flag",
+ "flag.NFlag": "flag",
+ "flag.NewFlagSet": "flag",
+ "flag.PanicOnError": "flag",
+ "flag.Parse": "flag",
+ "flag.Parsed": "flag",
+ "flag.PrintDefaults": "flag",
+ "flag.Set": "flag",
+ "flag.String": "flag",
+ "flag.StringVar": "flag",
+ "flag.Uint": "flag",
+ "flag.Uint64": "flag",
+ "flag.Uint64Var": "flag",
+ "flag.UintVar": "flag",
+ "flag.Usage": "flag",
+ "flag.Value": "flag",
+ "flag.Var": "flag",
+ "flag.Visit": "flag",
+ "flag.VisitAll": "flag",
+ "flate.BestCompression": "compress/flate",
+ "flate.BestSpeed": "compress/flate",
+ "flate.CorruptInputError": "compress/flate",
+ "flate.DefaultCompression": "compress/flate",
+ "flate.InternalError": "compress/flate",
+ "flate.NewReader": "compress/flate",
+ "flate.NewReaderDict": "compress/flate",
+ "flate.NewWriter": "compress/flate",
+ "flate.NewWriterDict": "compress/flate",
+ "flate.NoCompression": "compress/flate",
+ "flate.ReadError": "compress/flate",
+ "flate.Reader": "compress/flate",
+ "flate.WriteError": "compress/flate",
+ "flate.Writer": "compress/flate",
+ "fmt.Errorf": "fmt",
+ "fmt.Formatter": "fmt",
+ "fmt.Fprint": "fmt",
+ "fmt.Fprintf": "fmt",
+ "fmt.Fprintln": "fmt",
+ "fmt.Fscan": "fmt",
+ "fmt.Fscanf": "fmt",
+ "fmt.Fscanln": "fmt",
+ "fmt.GoStringer": "fmt",
+ "fmt.Print": "fmt",
+ "fmt.Printf": "fmt",
+ "fmt.Println": "fmt",
+ "fmt.Scan": "fmt",
+ "fmt.ScanState": "fmt",
+ "fmt.Scanf": "fmt",
+ "fmt.Scanln": "fmt",
+ "fmt.Scanner": "fmt",
+ "fmt.Sprint": "fmt",
+ "fmt.Sprintf": "fmt",
+ "fmt.Sprintln": "fmt",
+ "fmt.Sscan": "fmt",
+ "fmt.Sscanf": "fmt",
+ "fmt.Sscanln": "fmt",
+ "fmt.State": "fmt",
+ "fmt.Stringer": "fmt",
+ "fnv.New32": "hash/fnv",
+ "fnv.New32a": "hash/fnv",
+ "fnv.New64": "hash/fnv",
+ "fnv.New64a": "hash/fnv",
+ "format.Node": "go/format",
+ "format.Source": "go/format",
+ "gif.Decode": "image/gif",
+ "gif.DecodeAll": "image/gif",
+ "gif.DecodeConfig": "image/gif",
+ "gif.Encode": "image/gif",
+ "gif.EncodeAll": "image/gif",
+ "gif.GIF": "image/gif",
+ "gif.Options": "image/gif",
+ "gob.CommonType": "encoding/gob",
+ "gob.Decoder": "encoding/gob",
+ "gob.Encoder": "encoding/gob",
+ "gob.GobDecoder": "encoding/gob",
+ "gob.GobEncoder": "encoding/gob",
+ "gob.NewDecoder": "encoding/gob",
+ "gob.NewEncoder": "encoding/gob",
+ "gob.Register": "encoding/gob",
+ "gob.RegisterName": "encoding/gob",
+ "gosym.DecodingError": "debug/gosym",
+ "gosym.Func": "debug/gosym",
+ "gosym.LineTable": "debug/gosym",
+ "gosym.NewLineTable": "debug/gosym",
+ "gosym.NewTable": "debug/gosym",
+ "gosym.Obj": "debug/gosym",
+ "gosym.Sym": "debug/gosym",
+ "gosym.Table": "debug/gosym",
+ "gosym.UnknownFileError": "debug/gosym",
+ "gosym.UnknownLineError": "debug/gosym",
+ "gzip.BestCompression": "compress/gzip",
+ "gzip.BestSpeed": "compress/gzip",
+ "gzip.DefaultCompression": "compress/gzip",
+ "gzip.ErrChecksum": "compress/gzip",
+ "gzip.ErrHeader": "compress/gzip",
+ "gzip.Header": "compress/gzip",
+ "gzip.NewReader": "compress/gzip",
+ "gzip.NewWriter": "compress/gzip",
+ "gzip.NewWriterLevel": "compress/gzip",
+ "gzip.NoCompression": "compress/gzip",
+ "gzip.Reader": "compress/gzip",
+ "gzip.Writer": "compress/gzip",
+ "hash.Hash": "hash",
+ "hash.Hash32": "hash",
+ "hash.Hash64": "hash",
+ "heap.Fix": "container/heap",
+ "heap.Init": "container/heap",
+ "heap.Interface": "container/heap",
+ "heap.Pop": "container/heap",
+ "heap.Push": "container/heap",
+ "heap.Remove": "container/heap",
+ "hex.Decode": "encoding/hex",
+ "hex.DecodeString": "encoding/hex",
+ "hex.DecodedLen": "encoding/hex",
+ "hex.Dump": "encoding/hex",
+ "hex.Dumper": "encoding/hex",
+ "hex.Encode": "encoding/hex",
+ "hex.EncodeToString": "encoding/hex",
+ "hex.EncodedLen": "encoding/hex",
+ "hex.ErrLength": "encoding/hex",
+ "hex.InvalidByteError": "encoding/hex",
+ "hmac.Equal": "crypto/hmac",
+ "hmac.New": "crypto/hmac",
+ "html.EscapeString": "html",
+ "html.UnescapeString": "html",
+ "http.CanonicalHeaderKey": "net/http",
+ "http.Client": "net/http",
+ "http.CloseNotifier": "net/http",
+ "http.Cookie": "net/http",
+ "http.CookieJar": "net/http",
+ "http.DefaultClient": "net/http",
+ "http.DefaultMaxHeaderBytes": "net/http",
+ "http.DefaultMaxIdleConnsPerHost": "net/http",
+ "http.DefaultServeMux": "net/http",
+ "http.DefaultTransport": "net/http",
+ "http.DetectContentType": "net/http",
+ "http.Dir": "net/http",
+ "http.ErrBodyNotAllowed": "net/http",
+ "http.ErrBodyReadAfterClose": "net/http",
+ "http.ErrContentLength": "net/http",
+ "http.ErrHandlerTimeout": "net/http",
+ "http.ErrHeaderTooLong": "net/http",
+ "http.ErrHijacked": "net/http",
+ "http.ErrLineTooLong": "net/http",
+ "http.ErrMissingBoundary": "net/http",
+ "http.ErrMissingContentLength": "net/http",
+ "http.ErrMissingFile": "net/http",
+ "http.ErrNoCookie": "net/http",
+ "http.ErrNoLocation": "net/http",
+ "http.ErrNotMultipart": "net/http",
+ "http.ErrNotSupported": "net/http",
+ "http.ErrShortBody": "net/http",
+ "http.ErrUnexpectedTrailer": "net/http",
+ "http.ErrWriteAfterFlush": "net/http",
+ "http.Error": "net/http",
+ "http.File": "net/http",
+ "http.FileServer": "net/http",
+ "http.FileSystem": "net/http",
+ "http.Flusher": "net/http",
+ "http.Get": "net/http",
+ "http.Handle": "net/http",
+ "http.HandleFunc": "net/http",
+ "http.Handler": "net/http",
+ "http.HandlerFunc": "net/http",
+ "http.Head": "net/http",
+ "http.Header": "net/http",
+ "http.Hijacker": "net/http",
+ "http.ListenAndServe": "net/http",
+ "http.ListenAndServeTLS": "net/http",
+ "http.MaxBytesReader": "net/http",
+ "http.NewFileTransport": "net/http",
+ "http.NewRequest": "net/http",
+ "http.NewServeMux": "net/http",
+ "http.NotFound": "net/http",
+ "http.NotFoundHandler": "net/http",
+ "http.ParseHTTPVersion": "net/http",
+ "http.ParseTime": "net/http",
+ "http.Post": "net/http",
+ "http.PostForm": "net/http",
+ "http.ProtocolError": "net/http",
+ "http.ProxyFromEnvironment": "net/http",
+ "http.ProxyURL": "net/http",
+ "http.ReadRequest": "net/http",
+ "http.ReadResponse": "net/http",
+ "http.Redirect": "net/http",
+ "http.RedirectHandler": "net/http",
+ "http.Request": "net/http",
+ "http.Response": "net/http",
+ "http.ResponseWriter": "net/http",
+ "http.RoundTripper": "net/http",
+ "http.Serve": "net/http",
+ "http.ServeContent": "net/http",
+ "http.ServeFile": "net/http",
+ "http.ServeMux": "net/http",
+ "http.Server": "net/http",
+ "http.SetCookie": "net/http",
+ "http.StatusAccepted": "net/http",
+ "http.StatusBadGateway": "net/http",
+ "http.StatusBadRequest": "net/http",
+ "http.StatusConflict": "net/http",
+ "http.StatusContinue": "net/http",
+ "http.StatusCreated": "net/http",
+ "http.StatusExpectationFailed": "net/http",
+ "http.StatusForbidden": "net/http",
+ "http.StatusFound": "net/http",
+ "http.StatusGatewayTimeout": "net/http",
+ "http.StatusGone": "net/http",
+ "http.StatusHTTPVersionNotSupported": "net/http",
+ "http.StatusInternalServerError": "net/http",
+ "http.StatusLengthRequired": "net/http",
+ "http.StatusMethodNotAllowed": "net/http",
+ "http.StatusMovedPermanently": "net/http",
+ "http.StatusMultipleChoices": "net/http",
+ "http.StatusNoContent": "net/http",
+ "http.StatusNonAuthoritativeInfo": "net/http",
+ "http.StatusNotAcceptable": "net/http",
+ "http.StatusNotFound": "net/http",
+ "http.StatusNotImplemented": "net/http",
+ "http.StatusNotModified": "net/http",
+ "http.StatusOK": "net/http",
+ "http.StatusPartialContent": "net/http",
+ "http.StatusPaymentRequired": "net/http",
+ "http.StatusPreconditionFailed": "net/http",
+ "http.StatusProxyAuthRequired": "net/http",
+ "http.StatusRequestEntityTooLarge": "net/http",
+ "http.StatusRequestTimeout": "net/http",
+ "http.StatusRequestURITooLong": "net/http",
+ "http.StatusRequestedRangeNotSatisfiable": "net/http",
+ "http.StatusResetContent": "net/http",
+ "http.StatusSeeOther": "net/http",
+ "http.StatusServiceUnavailable": "net/http",
+ "http.StatusSwitchingProtocols": "net/http",
+ "http.StatusTeapot": "net/http",
+ "http.StatusTemporaryRedirect": "net/http",
+ "http.StatusText": "net/http",
+ "http.StatusUnauthorized": "net/http",
+ "http.StatusUnsupportedMediaType": "net/http",
+ "http.StatusUseProxy": "net/http",
+ "http.StripPrefix": "net/http",
+ "http.TimeFormat": "net/http",
+ "http.TimeoutHandler": "net/http",
+ "http.Transport": "net/http",
+ "httptest.DefaultRemoteAddr": "net/http/httptest",
+ "httptest.NewRecorder": "net/http/httptest",
+ "httptest.NewServer": "net/http/httptest",
+ "httptest.NewTLSServer": "net/http/httptest",
+ "httptest.NewUnstartedServer": "net/http/httptest",
+ "httptest.ResponseRecorder": "net/http/httptest",
+ "httptest.Server": "net/http/httptest",
+ "httputil.ClientConn": "net/http/httputil",
+ "httputil.DumpRequest": "net/http/httputil",
+ "httputil.DumpRequestOut": "net/http/httputil",
+ "httputil.DumpResponse": "net/http/httputil",
+ "httputil.ErrClosed": "net/http/httputil",
+ "httputil.ErrLineTooLong": "net/http/httputil",
+ "httputil.ErrPersistEOF": "net/http/httputil",
+ "httputil.ErrPipeline": "net/http/httputil",
+ "httputil.NewChunkedReader": "net/http/httputil",
+ "httputil.NewChunkedWriter": "net/http/httputil",
+ "httputil.NewClientConn": "net/http/httputil",
+ "httputil.NewProxyClientConn": "net/http/httputil",
+ "httputil.NewServerConn": "net/http/httputil",
+ "httputil.NewSingleHostReverseProxy": "net/http/httputil",
+ "httputil.ReverseProxy": "net/http/httputil",
+ "httputil.ServerConn": "net/http/httputil",
+ "image.Alpha": "image",
+ "image.Alpha16": "image",
+ "image.Black": "image",
+ "image.Config": "image",
+ "image.Decode": "image",
+ "image.DecodeConfig": "image",
+ "image.ErrFormat": "image",
+ "image.Gray": "image",
+ "image.Gray16": "image",
+ "image.Image": "image",
+ "image.NRGBA": "image",
+ "image.NRGBA64": "image",
+ "image.NewAlpha": "image",
+ "image.NewAlpha16": "image",
+ "image.NewGray": "image",
+ "image.NewGray16": "image",
+ "image.NewNRGBA": "image",
+ "image.NewNRGBA64": "image",
+ "image.NewPaletted": "image",
+ "image.NewRGBA": "image",
+ "image.NewRGBA64": "image",
+ "image.NewUniform": "image",
+ "image.NewYCbCr": "image",
+ "image.Opaque": "image",
+ "image.Paletted": "image",
+ "image.PalettedImage": "image",
+ "image.Point": "image",
+ "image.Pt": "image",
+ "image.RGBA": "image",
+ "image.RGBA64": "image",
+ "image.Rect": "image",
+ "image.Rectangle": "image",
+ "image.RegisterFormat": "image",
+ "image.Transparent": "image",
+ "image.Uniform": "image",
+ "image.White": "image",
+ "image.YCbCr": "image",
+ "image.YCbCrSubsampleRatio": "image",
+ "image.YCbCrSubsampleRatio420": "image",
+ "image.YCbCrSubsampleRatio422": "image",
+ "image.YCbCrSubsampleRatio440": "image",
+ "image.YCbCrSubsampleRatio444": "image",
+ "image.ZP": "image",
+ "image.ZR": "image",
+ "io.ByteReader": "io",
+ "io.ByteScanner": "io",
+ "io.ByteWriter": "io",
+ "io.Closer": "io",
+ "io.Copy": "io",
+ "io.CopyN": "io",
+ "io.EOF": "io",
+ "io.ErrClosedPipe": "io",
+ "io.ErrNoProgress": "io",
+ "io.ErrShortBuffer": "io",
+ "io.ErrShortWrite": "io",
+ "io.ErrUnexpectedEOF": "io",
+ "io.LimitReader": "io",
+ "io.LimitedReader": "io",
+ "io.MultiReader": "io",
+ "io.MultiWriter": "io",
+ "io.NewSectionReader": "io",
+ "io.Pipe": "io",
+ "io.PipeReader": "io",
+ "io.PipeWriter": "io",
+ "io.ReadAtLeast": "io",
+ "io.ReadCloser": "io",
+ "io.ReadFull": "io",
+ "io.ReadSeeker": "io",
+ "io.ReadWriteCloser": "io",
+ "io.ReadWriteSeeker": "io",
+ "io.ReadWriter": "io",
+ "io.Reader": "io",
+ "io.ReaderAt": "io",
+ "io.ReaderFrom": "io",
+ "io.RuneReader": "io",
+ "io.RuneScanner": "io",
+ "io.SectionReader": "io",
+ "io.Seeker": "io",
+ "io.TeeReader": "io",
+ "io.WriteCloser": "io",
+ "io.WriteSeeker": "io",
+ "io.WriteString": "io",
+ "io.Writer": "io",
+ "io.WriterAt": "io",
+ "io.WriterTo": "io",
+ "iotest.DataErrReader": "testing/iotest",
+ "iotest.ErrTimeout": "testing/iotest",
+ "iotest.HalfReader": "testing/iotest",
+ "iotest.NewReadLogger": "testing/iotest",
+ "iotest.NewWriteLogger": "testing/iotest",
+ "iotest.OneByteReader": "testing/iotest",
+ "iotest.TimeoutReader": "testing/iotest",
+ "iotest.TruncateWriter": "testing/iotest",
+ "ioutil.Discard": "io/ioutil",
+ "ioutil.NopCloser": "io/ioutil",
+ "ioutil.ReadAll": "io/ioutil",
+ "ioutil.ReadDir": "io/ioutil",
+ "ioutil.ReadFile": "io/ioutil",
+ "ioutil.TempDir": "io/ioutil",
+ "ioutil.TempFile": "io/ioutil",
+ "ioutil.WriteFile": "io/ioutil",
+ "jpeg.Decode": "image/jpeg",
+ "jpeg.DecodeConfig": "image/jpeg",
+ "jpeg.DefaultQuality": "image/jpeg",
+ "jpeg.Encode": "image/jpeg",
+ "jpeg.FormatError": "image/jpeg",
+ "jpeg.Options": "image/jpeg",
+ "jpeg.Reader": "image/jpeg",
+ "jpeg.UnsupportedError": "image/jpeg",
+ "json.Compact": "encoding/json",
+ "json.Decoder": "encoding/json",
+ "json.Encoder": "encoding/json",
+ "json.HTMLEscape": "encoding/json",
+ "json.Indent": "encoding/json",
+ "json.InvalidUTF8Error": "encoding/json",
+ "json.InvalidUnmarshalError": "encoding/json",
+ "json.Marshal": "encoding/json",
+ "json.MarshalIndent": "encoding/json",
+ "json.Marshaler": "encoding/json",
+ "json.MarshalerError": "encoding/json",
+ "json.NewDecoder": "encoding/json",
+ "json.NewEncoder": "encoding/json",
+ "json.Number": "encoding/json",
+ "json.RawMessage": "encoding/json",
+ "json.SyntaxError": "encoding/json",
+ "json.Unmarshal": "encoding/json",
+ "json.UnmarshalFieldError": "encoding/json",
+ "json.UnmarshalTypeError": "encoding/json",
+ "json.Unmarshaler": "encoding/json",
+ "json.UnsupportedTypeError": "encoding/json",
+ "json.UnsupportedValueError": "encoding/json",
+ "jsonrpc.Dial": "net/rpc/jsonrpc",
+ "jsonrpc.NewClient": "net/rpc/jsonrpc",
+ "jsonrpc.NewClientCodec": "net/rpc/jsonrpc",
+ "jsonrpc.NewServerCodec": "net/rpc/jsonrpc",
+ "jsonrpc.ServeConn": "net/rpc/jsonrpc",
+ "list.Element": "container/list",
+ "list.List": "container/list",
+ "list.New": "container/list",
+ "log.Fatal": "log",
+ "log.Fatalf": "log",
+ "log.Fatalln": "log",
+ "log.Flags": "log",
+ "log.Ldate": "log",
+ "log.Llongfile": "log",
+ "log.Lmicroseconds": "log",
+ "log.Logger": "log",
+ "log.Lshortfile": "log",
+ "log.LstdFlags": "log",
+ "log.Ltime": "log",
+ "log.New": "log",
+ "log.Panic": "log",
+ "log.Panicf": "log",
+ "log.Panicln": "log",
+ "log.Prefix": "log",
+ "log.Print": "log",
+ "log.Printf": "log",
+ "log.Println": "log",
+ "log.SetFlags": "log",
+ "log.SetOutput": "log",
+ "log.SetPrefix": "log",
+ "lzw.LSB": "compress/lzw",
+ "lzw.MSB": "compress/lzw",
+ "lzw.NewReader": "compress/lzw",
+ "lzw.NewWriter": "compress/lzw",
+ "lzw.Order": "compress/lzw",
+ "macho.Cpu": "debug/macho",
+ "macho.Cpu386": "debug/macho",
+ "macho.CpuAmd64": "debug/macho",
+ "macho.Dylib": "debug/macho",
+ "macho.DylibCmd": "debug/macho",
+ "macho.Dysymtab": "debug/macho",
+ "macho.DysymtabCmd": "debug/macho",
+ "macho.File": "debug/macho",
+ "macho.FileHeader": "debug/macho",
+ "macho.FormatError": "debug/macho",
+ "macho.Load": "debug/macho",
+ "macho.LoadBytes": "debug/macho",
+ "macho.LoadCmd": "debug/macho",
+ "macho.LoadCmdDylib": "debug/macho",
+ "macho.LoadCmdDylinker": "debug/macho",
+ "macho.LoadCmdDysymtab": "debug/macho",
+ "macho.LoadCmdSegment": "debug/macho",
+ "macho.LoadCmdSegment64": "debug/macho",
+ "macho.LoadCmdSymtab": "debug/macho",
+ "macho.LoadCmdThread": "debug/macho",
+ "macho.LoadCmdUnixThread": "debug/macho",
+ "macho.Magic32": "debug/macho",
+ "macho.Magic64": "debug/macho",
+ "macho.NewFile": "debug/macho",
+ "macho.Nlist32": "debug/macho",
+ "macho.Nlist64": "debug/macho",
+ "macho.Open": "debug/macho",
+ "macho.Regs386": "debug/macho",
+ "macho.RegsAMD64": "debug/macho",
+ "macho.Section": "debug/macho",
+ "macho.Section32": "debug/macho",
+ "macho.Section64": "debug/macho",
+ "macho.SectionHeader": "debug/macho",
+ "macho.Segment": "debug/macho",
+ "macho.Segment32": "debug/macho",
+ "macho.Segment64": "debug/macho",
+ "macho.SegmentHeader": "debug/macho",
+ "macho.Symbol": "debug/macho",
+ "macho.Symtab": "debug/macho",
+ "macho.SymtabCmd": "debug/macho",
+ "macho.Thread": "debug/macho",
+ "macho.Type": "debug/macho",
+ "macho.TypeExec": "debug/macho",
+ "macho.TypeObj": "debug/macho",
+ "mail.Address": "net/mail",
+ "mail.ErrHeaderNotPresent": "net/mail",
+ "mail.Header": "net/mail",
+ "mail.Message": "net/mail",
+ "mail.ParseAddress": "net/mail",
+ "mail.ParseAddressList": "net/mail",
+ "mail.ReadMessage": "net/mail",
+ "math.Abs": "math",
+ "math.Acos": "math",
+ "math.Acosh": "math",
+ "math.Asin": "math",
+ "math.Asinh": "math",
+ "math.Atan": "math",
+ "math.Atan2": "math",
+ "math.Atanh": "math",
+ "math.Cbrt": "math",
+ "math.Ceil": "math",
+ "math.Copysign": "math",
+ "math.Cos": "math",
+ "math.Cosh": "math",
+ "math.Dim": "math",
+ "math.E": "math",
+ "math.Erf": "math",
+ "math.Erfc": "math",
+ "math.Exp": "math",
+ "math.Exp2": "math",
+ "math.Expm1": "math",
+ "math.Float32bits": "math",
+ "math.Float32frombits": "math",
+ "math.Float64bits": "math",
+ "math.Float64frombits": "math",
+ "math.Floor": "math",
+ "math.Frexp": "math",
+ "math.Gamma": "math",
+ "math.Hypot": "math",
+ "math.Ilogb": "math",
+ "math.Inf": "math",
+ "math.IsInf": "math",
+ "math.IsNaN": "math",
+ "math.J0": "math",
+ "math.J1": "math",
+ "math.Jn": "math",
+ "math.Ldexp": "math",
+ "math.Lgamma": "math",
+ "math.Ln10": "math",
+ "math.Ln2": "math",
+ "math.Log": "math",
+ "math.Log10": "math",
+ "math.Log10E": "math",
+ "math.Log1p": "math",
+ "math.Log2": "math",
+ "math.Log2E": "math",
+ "math.Logb": "math",
+ "math.Max": "math",
+ "math.MaxFloat32": "math",
+ "math.MaxFloat64": "math",
+ "math.MaxInt16": "math",
+ "math.MaxInt32": "math",
+ "math.MaxInt64": "math",
+ "math.MaxInt8": "math",
+ "math.MaxUint16": "math",
+ "math.MaxUint32": "math",
+ "math.MaxUint64": "math",
+ "math.MaxUint8": "math",
+ "math.Min": "math",
+ "math.MinInt16": "math",
+ "math.MinInt32": "math",
+ "math.MinInt64": "math",
+ "math.MinInt8": "math",
+ "math.Mod": "math",
+ "math.Modf": "math",
+ "math.NaN": "math",
+ "math.Nextafter": "math",
+ "math.Phi": "math",
+ "math.Pi": "math",
+ "math.Pow": "math",
+ "math.Pow10": "math",
+ "math.Remainder": "math",
+ "math.Signbit": "math",
+ "math.Sin": "math",
+ "math.Sincos": "math",
+ "math.Sinh": "math",
+ "math.SmallestNonzeroFloat32": "math",
+ "math.SmallestNonzeroFloat64": "math",
+ "math.Sqrt": "math",
+ "math.Sqrt2": "math",
+ "math.SqrtE": "math",
+ "math.SqrtPhi": "math",
+ "math.SqrtPi": "math",
+ "math.Tan": "math",
+ "math.Tanh": "math",
+ "math.Trunc": "math",
+ "math.Y0": "math",
+ "math.Y1": "math",
+ "math.Yn": "math",
+ "md5.BlockSize": "crypto/md5",
+ "md5.New": "crypto/md5",
+ "md5.Size": "crypto/md5",
+ "md5.Sum": "crypto/md5",
+ "mime.AddExtensionType": "mime",
+ "mime.FormatMediaType": "mime",
+ "mime.ParseMediaType": "mime",
+ "mime.TypeByExtension": "mime",
+ "multipart.File": "mime/multipart",
+ "multipart.FileHeader": "mime/multipart",
+ "multipart.Form": "mime/multipart",
+ "multipart.NewReader": "mime/multipart",
+ "multipart.NewWriter": "mime/multipart",
+ "multipart.Part": "mime/multipart",
+ "multipart.Reader": "mime/multipart",
+ "multipart.Writer": "mime/multipart",
+ "net.Addr": "net",
+ "net.AddrError": "net",
+ "net.CIDRMask": "net",
+ "net.Conn": "net",
+ "net.DNSConfigError": "net",
+ "net.DNSError": "net",
+ "net.Dial": "net",
+ "net.DialIP": "net",
+ "net.DialTCP": "net",
+ "net.DialTimeout": "net",
+ "net.DialUDP": "net",
+ "net.DialUnix": "net",
+ "net.Dialer": "net",
+ "net.ErrWriteToConnected": "net",
+ "net.Error": "net",
+ "net.FileConn": "net",
+ "net.FileListener": "net",
+ "net.FilePacketConn": "net",
+ "net.FlagBroadcast": "net",
+ "net.FlagLoopback": "net",
+ "net.FlagMulticast": "net",
+ "net.FlagPointToPoint": "net",
+ "net.FlagUp": "net",
+ "net.Flags": "net",
+ "net.HardwareAddr": "net",
+ "net.IP": "net",
+ "net.IPAddr": "net",
+ "net.IPConn": "net",
+ "net.IPMask": "net",
+ "net.IPNet": "net",
+ "net.IPv4": "net",
+ "net.IPv4Mask": "net",
+ "net.IPv4allrouter": "net",
+ "net.IPv4allsys": "net",
+ "net.IPv4bcast": "net",
+ "net.IPv4len": "net",
+ "net.IPv4zero": "net",
+ "net.IPv6interfacelocalallnodes": "net",
+ "net.IPv6len": "net",
+ "net.IPv6linklocalallnodes": "net",
+ "net.IPv6linklocalallrouters": "net",
+ "net.IPv6loopback": "net",
+ "net.IPv6unspecified": "net",
+ "net.IPv6zero": "net",
+ "net.Interface": "net",
+ "net.InterfaceAddrs": "net",
+ "net.InterfaceByIndex": "net",
+ "net.InterfaceByName": "net",
+ "net.Interfaces": "net",
+ "net.InvalidAddrError": "net",
+ "net.JoinHostPort": "net",
+ "net.Listen": "net",
+ "net.ListenIP": "net",
+ "net.ListenMulticastUDP": "net",
+ "net.ListenPacket": "net",
+ "net.ListenTCP": "net",
+ "net.ListenUDP": "net",
+ "net.ListenUnix": "net",
+ "net.ListenUnixgram": "net",
+ "net.Listener": "net",
+ "net.LookupAddr": "net",
+ "net.LookupCNAME": "net",
+ "net.LookupHost": "net",
+ "net.LookupIP": "net",
+ "net.LookupMX": "net",
+ "net.LookupNS": "net",
+ "net.LookupPort": "net",
+ "net.LookupSRV": "net",
+ "net.LookupTXT": "net",
+ "net.MX": "net",
+ "net.NS": "net",
+ "net.OpError": "net",
+ "net.PacketConn": "net",
+ "net.ParseCIDR": "net",
+ "net.ParseError": "net",
+ "net.ParseIP": "net",
+ "net.ParseMAC": "net",
+ "net.Pipe": "net",
+ "net.ResolveIPAddr": "net",
+ "net.ResolveTCPAddr": "net",
+ "net.ResolveUDPAddr": "net",
+ "net.ResolveUnixAddr": "net",
+ "net.SRV": "net",
+ "net.SplitHostPort": "net",
+ "net.TCPAddr": "net",
+ "net.TCPConn": "net",
+ "net.TCPListener": "net",
+ "net.UDPAddr": "net",
+ "net.UDPConn": "net",
+ "net.UnixAddr": "net",
+ "net.UnixConn": "net",
+ "net.UnixListener": "net",
+ "net.UnknownNetworkError": "net",
+ "os.Args": "os",
+ "os.Chdir": "os",
+ "os.Chmod": "os",
+ "os.Chown": "os",
+ "os.Chtimes": "os",
+ "os.Clearenv": "os",
+ "os.Create": "os",
+ "os.DevNull": "os",
+ "os.Environ": "os",
+ "os.ErrExist": "os",
+ "os.ErrInvalid": "os",
+ "os.ErrNotExist": "os",
+ "os.ErrPermission": "os",
+ "os.Exit": "os",
+ "os.Expand": "os",
+ "os.ExpandEnv": "os",
+ "os.File": "os",
+ "os.FileInfo": "os",
+ "os.FileMode": "os",
+ "os.FindProcess": "os",
+ "os.Getegid": "os",
+ "os.Getenv": "os",
+ "os.Geteuid": "os",
+ "os.Getgid": "os",
+ "os.Getgroups": "os",
+ "os.Getpagesize": "os",
+ "os.Getpid": "os",
+ "os.Getppid": "os",
+ "os.Getuid": "os",
+ "os.Getwd": "os",
+ "os.Hostname": "os",
+ "os.Interrupt": "os",
+ "os.IsExist": "os",
+ "os.IsNotExist": "os",
+ "os.IsPathSeparator": "os",
+ "os.IsPermission": "os",
+ "os.Kill": "os",
+ "os.Lchown": "os",
+ "os.Link": "os",
+ "os.LinkError": "os",
+ "os.Lstat": "os",
+ "os.Mkdir": "os",
+ "os.MkdirAll": "os",
+ "os.ModeAppend": "os",
+ "os.ModeCharDevice": "os",
+ "os.ModeDevice": "os",
+ "os.ModeDir": "os",
+ "os.ModeExclusive": "os",
+ "os.ModeNamedPipe": "os",
+ "os.ModePerm": "os",
+ "os.ModeSetgid": "os",
+ "os.ModeSetuid": "os",
+ "os.ModeSocket": "os",
+ "os.ModeSticky": "os",
+ "os.ModeSymlink": "os",
+ "os.ModeTemporary": "os",
+ "os.ModeType": "os",
+ "os.NewFile": "os",
+ "os.NewSyscallError": "os",
+ "os.O_APPEND": "os",
+ "os.O_CREATE": "os",
+ "os.O_EXCL": "os",
+ "os.O_RDONLY": "os",
+ "os.O_RDWR": "os",
+ "os.O_SYNC": "os",
+ "os.O_TRUNC": "os",
+ "os.O_WRONLY": "os",
+ "os.Open": "os",
+ "os.OpenFile": "os",
+ "os.PathError": "os",
+ "os.PathListSeparator": "os",
+ "os.PathSeparator": "os",
+ "os.Pipe": "os",
+ "os.ProcAttr": "os",
+ "os.Process": "os",
+ "os.ProcessState": "os",
+ "os.Readlink": "os",
+ "os.Remove": "os",
+ "os.RemoveAll": "os",
+ "os.Rename": "os",
+ "os.SEEK_CUR": "os",
+ "os.SEEK_END": "os",
+ "os.SEEK_SET": "os",
+ "os.SameFile": "os",
+ "os.Setenv": "os",
+ "os.Signal": "os",
+ "os.StartProcess": "os",
+ "os.Stat": "os",
+ "os.Stderr": "os",
+ "os.Stdin": "os",
+ "os.Stdout": "os",
+ "os.Symlink": "os",
+ "os.SyscallError": "os",
+ "os.TempDir": "os",
+ "os.Truncate": "os",
+ "palette.Plan9": "image/color/palette",
+ "palette.WebSafe": "image/color/palette",
+ "parse.ActionNode": "text/template/parse",
+ "parse.BoolNode": "text/template/parse",
+ "parse.BranchNode": "text/template/parse",
+ "parse.ChainNode": "text/template/parse",
+ "parse.CommandNode": "text/template/parse",
+ "parse.DotNode": "text/template/parse",
+ "parse.FieldNode": "text/template/parse",
+ "parse.IdentifierNode": "text/template/parse",
+ "parse.IfNode": "text/template/parse",
+ "parse.IsEmptyTree": "text/template/parse",
+ "parse.ListNode": "text/template/parse",
+ "parse.New": "text/template/parse",
+ "parse.NewIdentifier": "text/template/parse",
+ "parse.NilNode": "text/template/parse",
+ "parse.Node": "text/template/parse",
+ "parse.NodeAction": "text/template/parse",
+ "parse.NodeBool": "text/template/parse",
+ "parse.NodeChain": "text/template/parse",
+ "parse.NodeCommand": "text/template/parse",
+ "parse.NodeDot": "text/template/parse",
+ "parse.NodeField": "text/template/parse",
+ "parse.NodeIdentifier": "text/template/parse",
+ "parse.NodeIf": "text/template/parse",
+ "parse.NodeList": "text/template/parse",
+ "parse.NodeNil": "text/template/parse",
+ "parse.NodeNumber": "text/template/parse",
+ "parse.NodePipe": "text/template/parse",
+ "parse.NodeRange": "text/template/parse",
+ "parse.NodeString": "text/template/parse",
+ "parse.NodeTemplate": "text/template/parse",
+ "parse.NodeText": "text/template/parse",
+ "parse.NodeType": "text/template/parse",
+ "parse.NodeVariable": "text/template/parse",
+ "parse.NodeWith": "text/template/parse",
+ "parse.NumberNode": "text/template/parse",
+ "parse.Parse": "text/template/parse",
+ "parse.PipeNode": "text/template/parse",
+ "parse.Pos": "text/template/parse",
+ "parse.RangeNode": "text/template/parse",
+ "parse.StringNode": "text/template/parse",
+ "parse.TemplateNode": "text/template/parse",
+ "parse.TextNode": "text/template/parse",
+ "parse.Tree": "text/template/parse",
+ "parse.VariableNode": "text/template/parse",
+ "parse.WithNode": "text/template/parse",
+ "parser.AllErrors": "go/parser",
+ "parser.DeclarationErrors": "go/parser",
+ "parser.ImportsOnly": "go/parser",
+ "parser.Mode": "go/parser",
+ "parser.PackageClauseOnly": "go/parser",
+ "parser.ParseComments": "go/parser",
+ "parser.ParseDir": "go/parser",
+ "parser.ParseExpr": "go/parser",
+ "parser.ParseFile": "go/parser",
+ "parser.SpuriousErrors": "go/parser",
+ "parser.Trace": "go/parser",
+ "path.Base": "path",
+ "path.Clean": "path",
+ "path.Dir": "path",
+ "path.ErrBadPattern": "path",
+ "path.Ext": "path",
+ "path.IsAbs": "path",
+ "path.Join": "path",
+ "path.Match": "path",
+ "path.Split": "path",
+ "pe.COFFSymbol": "debug/pe",
+ "pe.COFFSymbolSize": "debug/pe",
+ "pe.File": "debug/pe",
+ "pe.FileHeader": "debug/pe",
+ "pe.FormatError": "debug/pe",
+ "pe.IMAGE_FILE_MACHINE_AM33": "debug/pe",
+ "pe.IMAGE_FILE_MACHINE_AMD64": "debug/pe",
+ "pe.IMAGE_FILE_MACHINE_ARM": "debug/pe",
+ "pe.IMAGE_FILE_MACHINE_EBC": "debug/pe",
+ "pe.IMAGE_FILE_MACHINE_I386": "debug/pe",
+ "pe.IMAGE_FILE_MACHINE_IA64": "debug/pe",
+ "pe.IMAGE_FILE_MACHINE_M32R": "debug/pe",
+ "pe.IMAGE_FILE_MACHINE_MIPS16": "debug/pe",
+ "pe.IMAGE_FILE_MACHINE_MIPSFPU": "debug/pe",
+ "pe.IMAGE_FILE_MACHINE_MIPSFPU16": "debug/pe",
+ "pe.IMAGE_FILE_MACHINE_POWERPC": "debug/pe",
+ "pe.IMAGE_FILE_MACHINE_POWERPCFP": "debug/pe",
+ "pe.IMAGE_FILE_MACHINE_R4000": "debug/pe",
+ "pe.IMAGE_FILE_MACHINE_SH3": "debug/pe",
+ "pe.IMAGE_FILE_MACHINE_SH3DSP": "debug/pe",
+ "pe.IMAGE_FILE_MACHINE_SH4": "debug/pe",
+ "pe.IMAGE_FILE_MACHINE_SH5": "debug/pe",
+ "pe.IMAGE_FILE_MACHINE_THUMB": "debug/pe",
+ "pe.IMAGE_FILE_MACHINE_UNKNOWN": "debug/pe",
+ "pe.IMAGE_FILE_MACHINE_WCEMIPSV2": "debug/pe",
+ "pe.ImportDirectory": "debug/pe",
+ "pe.NewFile": "debug/pe",
+ "pe.Open": "debug/pe",
+ "pe.Section": "debug/pe",
+ "pe.SectionHeader": "debug/pe",
+ "pe.SectionHeader32": "debug/pe",
+ "pe.Symbol": "debug/pe",
+ "pem.Block": "encoding/pem",
+ "pem.Decode": "encoding/pem",
+ "pem.Encode": "encoding/pem",
+ "pem.EncodeToMemory": "encoding/pem",
+ "pkix.AlgorithmIdentifier": "crypto/x509/pkix",
+ "pkix.AttributeTypeAndValue": "crypto/x509/pkix",
+ "pkix.CertificateList": "crypto/x509/pkix",
+ "pkix.Extension": "crypto/x509/pkix",
+ "pkix.Name": "crypto/x509/pkix",
+ "pkix.RDNSequence": "crypto/x509/pkix",
+ "pkix.RelativeDistinguishedNameSET": "crypto/x509/pkix",
+ "pkix.RevokedCertificate": "crypto/x509/pkix",
+ "pkix.TBSCertificateList": "crypto/x509/pkix",
+ "png.Decode": "image/png",
+ "png.DecodeConfig": "image/png",
+ "png.Encode": "image/png",
+ "png.FormatError": "image/png",
+ "png.UnsupportedError": "image/png",
+ "pprof.Cmdline": "net/http/pprof",
+ "pprof.Handler": "net/http/pprof",
+ "pprof.Index": "net/http/pprof",
+ "pprof.Lookup": "runtime/pprof",
+ "pprof.NewProfile": "runtime/pprof",
+ // "pprof.Profile" is ambiguous
+ "pprof.Profiles": "runtime/pprof",
+ "pprof.StartCPUProfile": "runtime/pprof",
+ "pprof.StopCPUProfile": "runtime/pprof",
+ "pprof.Symbol": "net/http/pprof",
+ "pprof.WriteHeapProfile": "runtime/pprof",
+ "printer.CommentedNode": "go/printer",
+ "printer.Config": "go/printer",
+ "printer.Fprint": "go/printer",
+ "printer.Mode": "go/printer",
+ "printer.RawFormat": "go/printer",
+ "printer.SourcePos": "go/printer",
+ "printer.TabIndent": "go/printer",
+ "printer.UseSpaces": "go/printer",
+ "quick.Check": "testing/quick",
+ "quick.CheckEqual": "testing/quick",
+ "quick.CheckEqualError": "testing/quick",
+ "quick.CheckError": "testing/quick",
+ "quick.Config": "testing/quick",
+ "quick.Generator": "testing/quick",
+ "quick.SetupError": "testing/quick",
+ "quick.Value": "testing/quick",
+ "rand.ExpFloat64": "math/rand",
+ "rand.Float32": "math/rand",
+ "rand.Float64": "math/rand",
+ // "rand.Int" is ambiguous
+ "rand.Int31": "math/rand",
+ "rand.Int31n": "math/rand",
+ "rand.Int63": "math/rand",
+ "rand.Int63n": "math/rand",
+ "rand.Intn": "math/rand",
+ "rand.New": "math/rand",
+ "rand.NewSource": "math/rand",
+ "rand.NewZipf": "math/rand",
+ "rand.NormFloat64": "math/rand",
+ "rand.Perm": "math/rand",
+ "rand.Prime": "crypto/rand",
+ "rand.Rand": "math/rand",
+ "rand.Read": "crypto/rand",
+ "rand.Reader": "crypto/rand",
+ "rand.Seed": "math/rand",
+ "rand.Source": "math/rand",
+ "rand.Uint32": "math/rand",
+ "rand.Zipf": "math/rand",
+ "rc4.Cipher": "crypto/rc4",
+ "rc4.KeySizeError": "crypto/rc4",
+ "rc4.NewCipher": "crypto/rc4",
+ "reflect.Append": "reflect",
+ "reflect.AppendSlice": "reflect",
+ "reflect.Array": "reflect",
+ "reflect.Bool": "reflect",
+ "reflect.BothDir": "reflect",
+ "reflect.Chan": "reflect",
+ "reflect.ChanDir": "reflect",
+ "reflect.ChanOf": "reflect",
+ "reflect.Complex128": "reflect",
+ "reflect.Complex64": "reflect",
+ "reflect.Copy": "reflect",
+ "reflect.DeepEqual": "reflect",
+ "reflect.Float32": "reflect",
+ "reflect.Float64": "reflect",
+ "reflect.Func": "reflect",
+ "reflect.Indirect": "reflect",
+ "reflect.Int": "reflect",
+ "reflect.Int16": "reflect",
+ "reflect.Int32": "reflect",
+ "reflect.Int64": "reflect",
+ "reflect.Int8": "reflect",
+ "reflect.Interface": "reflect",
+ "reflect.Invalid": "reflect",
+ "reflect.Kind": "reflect",
+ "reflect.MakeChan": "reflect",
+ "reflect.MakeFunc": "reflect",
+ "reflect.MakeMap": "reflect",
+ "reflect.MakeSlice": "reflect",
+ "reflect.Map": "reflect",
+ "reflect.MapOf": "reflect",
+ "reflect.Method": "reflect",
+ "reflect.New": "reflect",
+ "reflect.NewAt": "reflect",
+ "reflect.Ptr": "reflect",
+ "reflect.PtrTo": "reflect",
+ "reflect.RecvDir": "reflect",
+ "reflect.Select": "reflect",
+ "reflect.SelectCase": "reflect",
+ "reflect.SelectDefault": "reflect",
+ "reflect.SelectDir": "reflect",
+ "reflect.SelectRecv": "reflect",
+ "reflect.SelectSend": "reflect",
+ "reflect.SendDir": "reflect",
+ "reflect.Slice": "reflect",
+ "reflect.SliceHeader": "reflect",
+ "reflect.SliceOf": "reflect",
+ "reflect.String": "reflect",
+ "reflect.StringHeader": "reflect",
+ "reflect.Struct": "reflect",
+ "reflect.StructField": "reflect",
+ "reflect.StructTag": "reflect",
+ "reflect.TypeOf": "reflect",
+ "reflect.Uint": "reflect",
+ "reflect.Uint16": "reflect",
+ "reflect.Uint32": "reflect",
+ "reflect.Uint64": "reflect",
+ "reflect.Uint8": "reflect",
+ "reflect.Uintptr": "reflect",
+ "reflect.UnsafePointer": "reflect",
+ "reflect.Value": "reflect",
+ "reflect.ValueError": "reflect",
+ "reflect.ValueOf": "reflect",
+ "reflect.Zero": "reflect",
+ "regexp.Compile": "regexp",
+ "regexp.CompilePOSIX": "regexp",
+ "regexp.Match": "regexp",
+ "regexp.MatchReader": "regexp",
+ "regexp.MatchString": "regexp",
+ "regexp.MustCompile": "regexp",
+ "regexp.MustCompilePOSIX": "regexp",
+ "regexp.QuoteMeta": "regexp",
+ "regexp.Regexp": "regexp",
+ "ring.New": "container/ring",
+ "ring.Ring": "container/ring",
+ "rpc.Accept": "net/rpc",
+ "rpc.Call": "net/rpc",
+ "rpc.Client": "net/rpc",
+ "rpc.ClientCodec": "net/rpc",
+ "rpc.DefaultDebugPath": "net/rpc",
+ "rpc.DefaultRPCPath": "net/rpc",
+ "rpc.DefaultServer": "net/rpc",
+ "rpc.Dial": "net/rpc",
+ "rpc.DialHTTP": "net/rpc",
+ "rpc.DialHTTPPath": "net/rpc",
+ "rpc.ErrShutdown": "net/rpc",
+ "rpc.HandleHTTP": "net/rpc",
+ "rpc.NewClient": "net/rpc",
+ "rpc.NewClientWithCodec": "net/rpc",
+ "rpc.NewServer": "net/rpc",
+ "rpc.Register": "net/rpc",
+ "rpc.RegisterName": "net/rpc",
+ "rpc.Request": "net/rpc",
+ "rpc.Response": "net/rpc",
+ "rpc.ServeCodec": "net/rpc",
+ "rpc.ServeConn": "net/rpc",
+ "rpc.ServeRequest": "net/rpc",
+ "rpc.Server": "net/rpc",
+ "rpc.ServerCodec": "net/rpc",
+ "rpc.ServerError": "net/rpc",
+ "rsa.CRTValue": "crypto/rsa",
+ "rsa.DecryptOAEP": "crypto/rsa",
+ "rsa.DecryptPKCS1v15": "crypto/rsa",
+ "rsa.DecryptPKCS1v15SessionKey": "crypto/rsa",
+ "rsa.EncryptOAEP": "crypto/rsa",
+ "rsa.EncryptPKCS1v15": "crypto/rsa",
+ "rsa.ErrDecryption": "crypto/rsa",
+ "rsa.ErrMessageTooLong": "crypto/rsa",
+ "rsa.ErrVerification": "crypto/rsa",
+ "rsa.GenerateKey": "crypto/rsa",
+ "rsa.GenerateMultiPrimeKey": "crypto/rsa",
+ "rsa.PSSOptions": "crypto/rsa",
+ "rsa.PSSSaltLengthAuto": "crypto/rsa",
+ "rsa.PSSSaltLengthEqualsHash": "crypto/rsa",
+ "rsa.PrecomputedValues": "crypto/rsa",
+ "rsa.PrivateKey": "crypto/rsa",
+ "rsa.PublicKey": "crypto/rsa",
+ "rsa.SignPKCS1v15": "crypto/rsa",
+ "rsa.SignPSS": "crypto/rsa",
+ "rsa.VerifyPKCS1v15": "crypto/rsa",
+ "rsa.VerifyPSS": "crypto/rsa",
+ "runtime.BlockProfile": "runtime",
+ "runtime.BlockProfileRecord": "runtime",
+ "runtime.Breakpoint": "runtime",
+ "runtime.CPUProfile": "runtime",
+ "runtime.Caller": "runtime",
+ "runtime.Callers": "runtime",
+ "runtime.Compiler": "runtime",
+ "runtime.Error": "runtime",
+ "runtime.Func": "runtime",
+ "runtime.FuncForPC": "runtime",
+ "runtime.GC": "runtime",
+ "runtime.GOARCH": "runtime",
+ "runtime.GOMAXPROCS": "runtime",
+ "runtime.GOOS": "runtime",
+ "runtime.GOROOT": "runtime",
+ "runtime.Goexit": "runtime",
+ "runtime.GoroutineProfile": "runtime",
+ "runtime.Gosched": "runtime",
+ "runtime.LockOSThread": "runtime",
+ "runtime.MemProfile": "runtime",
+ "runtime.MemProfileRate": "runtime",
+ "runtime.MemProfileRecord": "runtime",
+ "runtime.MemStats": "runtime",
+ "runtime.NumCPU": "runtime",
+ "runtime.NumCgoCall": "runtime",
+ "runtime.NumGoroutine": "runtime",
+ "runtime.ReadMemStats": "runtime",
+ "runtime.SetBlockProfileRate": "runtime",
+ "runtime.SetCPUProfileRate": "runtime",
+ "runtime.SetFinalizer": "runtime",
+ "runtime.Stack": "runtime",
+ "runtime.StackRecord": "runtime",
+ "runtime.ThreadCreateProfile": "runtime",
+ "runtime.TypeAssertionError": "runtime",
+ "runtime.UnlockOSThread": "runtime",
+ "runtime.Version": "runtime",
+ "scanner.Char": "text/scanner",
+ "scanner.Comment": "text/scanner",
+ "scanner.EOF": "text/scanner",
+ "scanner.Error": "go/scanner",
+ "scanner.ErrorHandler": "go/scanner",
+ "scanner.ErrorList": "go/scanner",
+ "scanner.Float": "text/scanner",
+ "scanner.GoTokens": "text/scanner",
+ "scanner.GoWhitespace": "text/scanner",
+ "scanner.Ident": "text/scanner",
+ "scanner.Int": "text/scanner",
+ "scanner.Mode": "go/scanner",
+ "scanner.Position": "text/scanner",
+ "scanner.PrintError": "go/scanner",
+ "scanner.RawString": "text/scanner",
+ "scanner.ScanChars": "text/scanner",
+ // "scanner.ScanComments" is ambiguous
+ "scanner.ScanFloats": "text/scanner",
+ "scanner.ScanIdents": "text/scanner",
+ "scanner.ScanInts": "text/scanner",
+ "scanner.ScanRawStrings": "text/scanner",
+ "scanner.ScanStrings": "text/scanner",
+ // "scanner.Scanner" is ambiguous
+ "scanner.SkipComments": "text/scanner",
+ "scanner.String": "text/scanner",
+ "scanner.TokenString": "text/scanner",
+ "sha1.BlockSize": "crypto/sha1",
+ "sha1.New": "crypto/sha1",
+ "sha1.Size": "crypto/sha1",
+ "sha1.Sum": "crypto/sha1",
+ "sha256.BlockSize": "crypto/sha256",
+ "sha256.New": "crypto/sha256",
+ "sha256.New224": "crypto/sha256",
+ "sha256.Size": "crypto/sha256",
+ "sha256.Size224": "crypto/sha256",
+ "sha256.Sum224": "crypto/sha256",
+ "sha256.Sum256": "crypto/sha256",
+ "sha512.BlockSize": "crypto/sha512",
+ "sha512.New": "crypto/sha512",
+ "sha512.New384": "crypto/sha512",
+ "sha512.Size": "crypto/sha512",
+ "sha512.Size384": "crypto/sha512",
+ "sha512.Sum384": "crypto/sha512",
+ "sha512.Sum512": "crypto/sha512",
+ "signal.Notify": "os/signal",
+ "signal.Stop": "os/signal",
+ "smtp.Auth": "net/smtp",
+ "smtp.CRAMMD5Auth": "net/smtp",
+ "smtp.Client": "net/smtp",
+ "smtp.Dial": "net/smtp",
+ "smtp.NewClient": "net/smtp",
+ "smtp.PlainAuth": "net/smtp",
+ "smtp.SendMail": "net/smtp",
+ "smtp.ServerInfo": "net/smtp",
+ "sort.Float64Slice": "sort",
+ "sort.Float64s": "sort",
+ "sort.Float64sAreSorted": "sort",
+ "sort.IntSlice": "sort",
+ "sort.Interface": "sort",
+ "sort.Ints": "sort",
+ "sort.IntsAreSorted": "sort",
+ "sort.IsSorted": "sort",
+ "sort.Reverse": "sort",
+ "sort.Search": "sort",
+ "sort.SearchFloat64s": "sort",
+ "sort.SearchInts": "sort",
+ "sort.SearchStrings": "sort",
+ "sort.Sort": "sort",
+ "sort.Stable": "sort",
+ "sort.StringSlice": "sort",
+ "sort.Strings": "sort",
+ "sort.StringsAreSorted": "sort",
+ "sql.DB": "database/sql",
+ "sql.ErrNoRows": "database/sql",
+ "sql.ErrTxDone": "database/sql",
+ "sql.NullBool": "database/sql",
+ "sql.NullFloat64": "database/sql",
+ "sql.NullInt64": "database/sql",
+ "sql.NullString": "database/sql",
+ "sql.Open": "database/sql",
+ "sql.RawBytes": "database/sql",
+ "sql.Register": "database/sql",
+ "sql.Result": "database/sql",
+ "sql.Row": "database/sql",
+ "sql.Rows": "database/sql",
+ "sql.Scanner": "database/sql",
+ "sql.Stmt": "database/sql",
+ "sql.Tx": "database/sql",
+ "strconv.AppendBool": "strconv",
+ "strconv.AppendFloat": "strconv",
+ "strconv.AppendInt": "strconv",
+ "strconv.AppendQuote": "strconv",
+ "strconv.AppendQuoteRune": "strconv",
+ "strconv.AppendQuoteRuneToASCII": "strconv",
+ "strconv.AppendQuoteToASCII": "strconv",
+ "strconv.AppendUint": "strconv",
+ "strconv.Atoi": "strconv",
+ "strconv.CanBackquote": "strconv",
+ "strconv.ErrRange": "strconv",
+ "strconv.ErrSyntax": "strconv",
+ "strconv.FormatBool": "strconv",
+ "strconv.FormatFloat": "strconv",
+ "strconv.FormatInt": "strconv",
+ "strconv.FormatUint": "strconv",
+ "strconv.IntSize": "strconv",
+ "strconv.IsPrint": "strconv",
+ "strconv.Itoa": "strconv",
+ "strconv.NumError": "strconv",
+ "strconv.ParseBool": "strconv",
+ "strconv.ParseFloat": "strconv",
+ "strconv.ParseInt": "strconv",
+ "strconv.ParseUint": "strconv",
+ "strconv.Quote": "strconv",
+ "strconv.QuoteRune": "strconv",
+ "strconv.QuoteRuneToASCII": "strconv",
+ "strconv.QuoteToASCII": "strconv",
+ "strconv.Unquote": "strconv",
+ "strconv.UnquoteChar": "strconv",
+ "strings.Contains": "strings",
+ "strings.ContainsAny": "strings",
+ "strings.ContainsRune": "strings",
+ "strings.Count": "strings",
+ "strings.EqualFold": "strings",
+ "strings.Fields": "strings",
+ "strings.FieldsFunc": "strings",
+ "strings.HasPrefix": "strings",
+ "strings.HasSuffix": "strings",
+ "strings.Index": "strings",
+ "strings.IndexAny": "strings",
+ "strings.IndexByte": "strings",
+ "strings.IndexFunc": "strings",
+ "strings.IndexRune": "strings",
+ "strings.Join": "strings",
+ "strings.LastIndex": "strings",
+ "strings.LastIndexAny": "strings",
+ "strings.LastIndexFunc": "strings",
+ "strings.Map": "strings",
+ "strings.NewReader": "strings",
+ "strings.NewReplacer": "strings",
+ "strings.Reader": "strings",
+ "strings.Repeat": "strings",
+ "strings.Replace": "strings",
+ "strings.Replacer": "strings",
+ "strings.Split": "strings",
+ "strings.SplitAfter": "strings",
+ "strings.SplitAfterN": "strings",
+ "strings.SplitN": "strings",
+ "strings.Title": "strings",
+ "strings.ToLower": "strings",
+ "strings.ToLowerSpecial": "strings",
+ "strings.ToTitle": "strings",
+ "strings.ToTitleSpecial": "strings",
+ "strings.ToUpper": "strings",
+ "strings.ToUpperSpecial": "strings",
+ "strings.Trim": "strings",
+ "strings.TrimFunc": "strings",
+ "strings.TrimLeft": "strings",
+ "strings.TrimLeftFunc": "strings",
+ "strings.TrimPrefix": "strings",
+ "strings.TrimRight": "strings",
+ "strings.TrimRightFunc": "strings",
+ "strings.TrimSpace": "strings",
+ "strings.TrimSuffix": "strings",
+ "subtle.ConstantTimeByteEq": "crypto/subtle",
+ "subtle.ConstantTimeCompare": "crypto/subtle",
+ "subtle.ConstantTimeCopy": "crypto/subtle",
+ "subtle.ConstantTimeEq": "crypto/subtle",
+ "subtle.ConstantTimeLessOrEq": "crypto/subtle",
+ "subtle.ConstantTimeSelect": "crypto/subtle",
+ "suffixarray.Index": "index/suffixarray",
+ "suffixarray.New": "index/suffixarray",
+ "sync.Cond": "sync",
+ "sync.Locker": "sync",
+ "sync.Mutex": "sync",
+ "sync.NewCond": "sync",
+ "sync.Once": "sync",
+ "sync.RWMutex": "sync",
+ "sync.WaitGroup": "sync",
+ "syntax.ClassNL": "regexp/syntax",
+ "syntax.Compile": "regexp/syntax",
+ "syntax.DotNL": "regexp/syntax",
+ "syntax.EmptyBeginLine": "regexp/syntax",
+ "syntax.EmptyBeginText": "regexp/syntax",
+ "syntax.EmptyEndLine": "regexp/syntax",
+ "syntax.EmptyEndText": "regexp/syntax",
+ "syntax.EmptyNoWordBoundary": "regexp/syntax",
+ "syntax.EmptyOp": "regexp/syntax",
+ "syntax.EmptyOpContext": "regexp/syntax",
+ "syntax.EmptyWordBoundary": "regexp/syntax",
+ "syntax.ErrInternalError": "regexp/syntax",
+ "syntax.ErrInvalidCharClass": "regexp/syntax",
+ "syntax.ErrInvalidCharRange": "regexp/syntax",
+ "syntax.ErrInvalidEscape": "regexp/syntax",
+ "syntax.ErrInvalidNamedCapture": "regexp/syntax",
+ "syntax.ErrInvalidPerlOp": "regexp/syntax",
+ "syntax.ErrInvalidRepeatOp": "regexp/syntax",
+ "syntax.ErrInvalidRepeatSize": "regexp/syntax",
+ "syntax.ErrInvalidUTF8": "regexp/syntax",
+ "syntax.ErrMissingBracket": "regexp/syntax",
+ "syntax.ErrMissingParen": "regexp/syntax",
+ "syntax.ErrMissingRepeatArgument": "regexp/syntax",
+ "syntax.ErrTrailingBackslash": "regexp/syntax",
+ "syntax.ErrUnexpectedParen": "regexp/syntax",
+ "syntax.Error": "regexp/syntax",
+ "syntax.ErrorCode": "regexp/syntax",
+ "syntax.Flags": "regexp/syntax",
+ "syntax.FoldCase": "regexp/syntax",
+ "syntax.Inst": "regexp/syntax",
+ "syntax.InstAlt": "regexp/syntax",
+ "syntax.InstAltMatch": "regexp/syntax",
+ "syntax.InstCapture": "regexp/syntax",
+ "syntax.InstEmptyWidth": "regexp/syntax",
+ "syntax.InstFail": "regexp/syntax",
+ "syntax.InstMatch": "regexp/syntax",
+ "syntax.InstNop": "regexp/syntax",
+ "syntax.InstOp": "regexp/syntax",
+ "syntax.InstRune": "regexp/syntax",
+ "syntax.InstRune1": "regexp/syntax",
+ "syntax.InstRuneAny": "regexp/syntax",
+ "syntax.InstRuneAnyNotNL": "regexp/syntax",
+ "syntax.IsWordChar": "regexp/syntax",
+ "syntax.Literal": "regexp/syntax",
+ "syntax.MatchNL": "regexp/syntax",
+ "syntax.NonGreedy": "regexp/syntax",
+ "syntax.OneLine": "regexp/syntax",
+ "syntax.Op": "regexp/syntax",
+ "syntax.OpAlternate": "regexp/syntax",
+ "syntax.OpAnyChar": "regexp/syntax",
+ "syntax.OpAnyCharNotNL": "regexp/syntax",
+ "syntax.OpBeginLine": "regexp/syntax",
+ "syntax.OpBeginText": "regexp/syntax",
+ "syntax.OpCapture": "regexp/syntax",
+ "syntax.OpCharClass": "regexp/syntax",
+ "syntax.OpConcat": "regexp/syntax",
+ "syntax.OpEmptyMatch": "regexp/syntax",
+ "syntax.OpEndLine": "regexp/syntax",
+ "syntax.OpEndText": "regexp/syntax",
+ "syntax.OpLiteral": "regexp/syntax",
+ "syntax.OpNoMatch": "regexp/syntax",
+ "syntax.OpNoWordBoundary": "regexp/syntax",
+ "syntax.OpPlus": "regexp/syntax",
+ "syntax.OpQuest": "regexp/syntax",
+ "syntax.OpRepeat": "regexp/syntax",
+ "syntax.OpStar": "regexp/syntax",
+ "syntax.OpWordBoundary": "regexp/syntax",
+ "syntax.POSIX": "regexp/syntax",
+ "syntax.Parse": "regexp/syntax",
+ "syntax.Perl": "regexp/syntax",
+ "syntax.PerlX": "regexp/syntax",
+ "syntax.Prog": "regexp/syntax",
+ "syntax.Regexp": "regexp/syntax",
+ "syntax.Simple": "regexp/syntax",
+ "syntax.UnicodeGroups": "regexp/syntax",
+ "syntax.WasDollar": "regexp/syntax",
+ "syscall.AF_ALG": "syscall",
+ "syscall.AF_APPLETALK": "syscall",
+ "syscall.AF_ARP": "syscall",
+ "syscall.AF_ASH": "syscall",
+ "syscall.AF_ATM": "syscall",
+ "syscall.AF_ATMPVC": "syscall",
+ "syscall.AF_ATMSVC": "syscall",
+ "syscall.AF_AX25": "syscall",
+ "syscall.AF_BLUETOOTH": "syscall",
+ "syscall.AF_BRIDGE": "syscall",
+ "syscall.AF_CAIF": "syscall",
+ "syscall.AF_CAN": "syscall",
+ "syscall.AF_CCITT": "syscall",
+ "syscall.AF_CHAOS": "syscall",
+ "syscall.AF_CNT": "syscall",
+ "syscall.AF_COIP": "syscall",
+ "syscall.AF_DATAKIT": "syscall",
+ "syscall.AF_DECnet": "syscall",
+ "syscall.AF_DLI": "syscall",
+ "syscall.AF_E164": "syscall",
+ "syscall.AF_ECMA": "syscall",
+ "syscall.AF_ECONET": "syscall",
+ "syscall.AF_ENCAP": "syscall",
+ "syscall.AF_FILE": "syscall",
+ "syscall.AF_HYLINK": "syscall",
+ "syscall.AF_IEEE80211": "syscall",
+ "syscall.AF_IEEE802154": "syscall",
+ "syscall.AF_IMPLINK": "syscall",
+ "syscall.AF_INET": "syscall",
+ "syscall.AF_INET6": "syscall",
+ "syscall.AF_IPX": "syscall",
+ "syscall.AF_IRDA": "syscall",
+ "syscall.AF_ISDN": "syscall",
+ "syscall.AF_ISO": "syscall",
+ "syscall.AF_IUCV": "syscall",
+ "syscall.AF_KEY": "syscall",
+ "syscall.AF_LAT": "syscall",
+ "syscall.AF_LINK": "syscall",
+ "syscall.AF_LLC": "syscall",
+ "syscall.AF_LOCAL": "syscall",
+ "syscall.AF_MAX": "syscall",
+ "syscall.AF_MPLS": "syscall",
+ "syscall.AF_NATM": "syscall",
+ "syscall.AF_NDRV": "syscall",
+ "syscall.AF_NETBEUI": "syscall",
+ "syscall.AF_NETBIOS": "syscall",
+ "syscall.AF_NETGRAPH": "syscall",
+ "syscall.AF_NETLINK": "syscall",
+ "syscall.AF_NETROM": "syscall",
+ "syscall.AF_NS": "syscall",
+ "syscall.AF_OROUTE": "syscall",
+ "syscall.AF_OSI": "syscall",
+ "syscall.AF_PACKET": "syscall",
+ "syscall.AF_PHONET": "syscall",
+ "syscall.AF_PPP": "syscall",
+ "syscall.AF_PPPOX": "syscall",
+ "syscall.AF_PUP": "syscall",
+ "syscall.AF_RDS": "syscall",
+ "syscall.AF_RESERVED_36": "syscall",
+ "syscall.AF_ROSE": "syscall",
+ "syscall.AF_ROUTE": "syscall",
+ "syscall.AF_RXRPC": "syscall",
+ "syscall.AF_SCLUSTER": "syscall",
+ "syscall.AF_SECURITY": "syscall",
+ "syscall.AF_SIP": "syscall",
+ "syscall.AF_SLOW": "syscall",
+ "syscall.AF_SNA": "syscall",
+ "syscall.AF_SYSTEM": "syscall",
+ "syscall.AF_TIPC": "syscall",
+ "syscall.AF_UNIX": "syscall",
+ "syscall.AF_UNSPEC": "syscall",
+ "syscall.AF_VENDOR00": "syscall",
+ "syscall.AF_VENDOR01": "syscall",
+ "syscall.AF_VENDOR02": "syscall",
+ "syscall.AF_VENDOR03": "syscall",
+ "syscall.AF_VENDOR04": "syscall",
+ "syscall.AF_VENDOR05": "syscall",
+ "syscall.AF_VENDOR06": "syscall",
+ "syscall.AF_VENDOR07": "syscall",
+ "syscall.AF_VENDOR08": "syscall",
+ "syscall.AF_VENDOR09": "syscall",
+ "syscall.AF_VENDOR10": "syscall",
+ "syscall.AF_VENDOR11": "syscall",
+ "syscall.AF_VENDOR12": "syscall",
+ "syscall.AF_VENDOR13": "syscall",
+ "syscall.AF_VENDOR14": "syscall",
+ "syscall.AF_VENDOR15": "syscall",
+ "syscall.AF_VENDOR16": "syscall",
+ "syscall.AF_VENDOR17": "syscall",
+ "syscall.AF_VENDOR18": "syscall",
+ "syscall.AF_VENDOR19": "syscall",
+ "syscall.AF_VENDOR20": "syscall",
+ "syscall.AF_VENDOR21": "syscall",
+ "syscall.AF_VENDOR22": "syscall",
+ "syscall.AF_VENDOR23": "syscall",
+ "syscall.AF_VENDOR24": "syscall",
+ "syscall.AF_VENDOR25": "syscall",
+ "syscall.AF_VENDOR26": "syscall",
+ "syscall.AF_VENDOR27": "syscall",
+ "syscall.AF_VENDOR28": "syscall",
+ "syscall.AF_VENDOR29": "syscall",
+ "syscall.AF_VENDOR30": "syscall",
+ "syscall.AF_VENDOR31": "syscall",
+ "syscall.AF_VENDOR32": "syscall",
+ "syscall.AF_VENDOR33": "syscall",
+ "syscall.AF_VENDOR34": "syscall",
+ "syscall.AF_VENDOR35": "syscall",
+ "syscall.AF_VENDOR36": "syscall",
+ "syscall.AF_VENDOR37": "syscall",
+ "syscall.AF_VENDOR38": "syscall",
+ "syscall.AF_VENDOR39": "syscall",
+ "syscall.AF_VENDOR40": "syscall",
+ "syscall.AF_VENDOR41": "syscall",
+ "syscall.AF_VENDOR42": "syscall",
+ "syscall.AF_VENDOR43": "syscall",
+ "syscall.AF_VENDOR44": "syscall",
+ "syscall.AF_VENDOR45": "syscall",
+ "syscall.AF_VENDOR46": "syscall",
+ "syscall.AF_VENDOR47": "syscall",
+ "syscall.AF_WANPIPE": "syscall",
+ "syscall.AF_X25": "syscall",
+ "syscall.AI_CANONNAME": "syscall",
+ "syscall.AI_NUMERICHOST": "syscall",
+ "syscall.AI_PASSIVE": "syscall",
+ "syscall.APPLICATION_ERROR": "syscall",
+ "syscall.ARPHRD_ADAPT": "syscall",
+ "syscall.ARPHRD_APPLETLK": "syscall",
+ "syscall.ARPHRD_ARCNET": "syscall",
+ "syscall.ARPHRD_ASH": "syscall",
+ "syscall.ARPHRD_ATM": "syscall",
+ "syscall.ARPHRD_AX25": "syscall",
+ "syscall.ARPHRD_BIF": "syscall",
+ "syscall.ARPHRD_CHAOS": "syscall",
+ "syscall.ARPHRD_CISCO": "syscall",
+ "syscall.ARPHRD_CSLIP": "syscall",
+ "syscall.ARPHRD_CSLIP6": "syscall",
+ "syscall.ARPHRD_DDCMP": "syscall",
+ "syscall.ARPHRD_DLCI": "syscall",
+ "syscall.ARPHRD_ECONET": "syscall",
+ "syscall.ARPHRD_EETHER": "syscall",
+ "syscall.ARPHRD_ETHER": "syscall",
+ "syscall.ARPHRD_EUI64": "syscall",
+ "syscall.ARPHRD_FCAL": "syscall",
+ "syscall.ARPHRD_FCFABRIC": "syscall",
+ "syscall.ARPHRD_FCPL": "syscall",
+ "syscall.ARPHRD_FCPP": "syscall",
+ "syscall.ARPHRD_FDDI": "syscall",
+ "syscall.ARPHRD_FRAD": "syscall",
+ "syscall.ARPHRD_FRELAY": "syscall",
+ "syscall.ARPHRD_HDLC": "syscall",
+ "syscall.ARPHRD_HIPPI": "syscall",
+ "syscall.ARPHRD_HWX25": "syscall",
+ "syscall.ARPHRD_IEEE1394": "syscall",
+ "syscall.ARPHRD_IEEE802": "syscall",
+ "syscall.ARPHRD_IEEE80211": "syscall",
+ "syscall.ARPHRD_IEEE80211_PRISM": "syscall",
+ "syscall.ARPHRD_IEEE80211_RADIOTAP": "syscall",
+ "syscall.ARPHRD_IEEE802154": "syscall",
+ "syscall.ARPHRD_IEEE802154_PHY": "syscall",
+ "syscall.ARPHRD_IEEE802_TR": "syscall",
+ "syscall.ARPHRD_INFINIBAND": "syscall",
+ "syscall.ARPHRD_IPDDP": "syscall",
+ "syscall.ARPHRD_IPGRE": "syscall",
+ "syscall.ARPHRD_IRDA": "syscall",
+ "syscall.ARPHRD_LAPB": "syscall",
+ "syscall.ARPHRD_LOCALTLK": "syscall",
+ "syscall.ARPHRD_LOOPBACK": "syscall",
+ "syscall.ARPHRD_METRICOM": "syscall",
+ "syscall.ARPHRD_NETROM": "syscall",
+ "syscall.ARPHRD_NONE": "syscall",
+ "syscall.ARPHRD_PIMREG": "syscall",
+ "syscall.ARPHRD_PPP": "syscall",
+ "syscall.ARPHRD_PRONET": "syscall",
+ "syscall.ARPHRD_RAWHDLC": "syscall",
+ "syscall.ARPHRD_ROSE": "syscall",
+ "syscall.ARPHRD_RSRVD": "syscall",
+ "syscall.ARPHRD_SIT": "syscall",
+ "syscall.ARPHRD_SKIP": "syscall",
+ "syscall.ARPHRD_SLIP": "syscall",
+ "syscall.ARPHRD_SLIP6": "syscall",
+ "syscall.ARPHRD_STRIP": "syscall",
+ "syscall.ARPHRD_TUNNEL": "syscall",
+ "syscall.ARPHRD_TUNNEL6": "syscall",
+ "syscall.ARPHRD_VOID": "syscall",
+ "syscall.ARPHRD_X25": "syscall",
+ "syscall.AUTHTYPE_CLIENT": "syscall",
+ "syscall.AUTHTYPE_SERVER": "syscall",
+ "syscall.Accept": "syscall",
+ "syscall.Accept4": "syscall",
+ "syscall.AcceptEx": "syscall",
+ "syscall.Access": "syscall",
+ "syscall.Acct": "syscall",
+ "syscall.AddrinfoW": "syscall",
+ "syscall.Adjtime": "syscall",
+ "syscall.Adjtimex": "syscall",
+ "syscall.AttachLsf": "syscall",
+ "syscall.B0": "syscall",
+ "syscall.B1000000": "syscall",
+ "syscall.B110": "syscall",
+ "syscall.B115200": "syscall",
+ "syscall.B1152000": "syscall",
+ "syscall.B1200": "syscall",
+ "syscall.B134": "syscall",
+ "syscall.B14400": "syscall",
+ "syscall.B150": "syscall",
+ "syscall.B1500000": "syscall",
+ "syscall.B1800": "syscall",
+ "syscall.B19200": "syscall",
+ "syscall.B200": "syscall",
+ "syscall.B2000000": "syscall",
+ "syscall.B230400": "syscall",
+ "syscall.B2400": "syscall",
+ "syscall.B2500000": "syscall",
+ "syscall.B28800": "syscall",
+ "syscall.B300": "syscall",
+ "syscall.B3000000": "syscall",
+ "syscall.B3500000": "syscall",
+ "syscall.B38400": "syscall",
+ "syscall.B4000000": "syscall",
+ "syscall.B460800": "syscall",
+ "syscall.B4800": "syscall",
+ "syscall.B50": "syscall",
+ "syscall.B500000": "syscall",
+ "syscall.B57600": "syscall",
+ "syscall.B576000": "syscall",
+ "syscall.B600": "syscall",
+ "syscall.B7200": "syscall",
+ "syscall.B75": "syscall",
+ "syscall.B76800": "syscall",
+ "syscall.B921600": "syscall",
+ "syscall.B9600": "syscall",
+ "syscall.BASE_PROTOCOL": "syscall",
+ "syscall.BIOCFEEDBACK": "syscall",
+ "syscall.BIOCFLUSH": "syscall",
+ "syscall.BIOCGBLEN": "syscall",
+ "syscall.BIOCGDIRECTION": "syscall",
+ "syscall.BIOCGDIRFILT": "syscall",
+ "syscall.BIOCGDLT": "syscall",
+ "syscall.BIOCGDLTLIST": "syscall",
+ "syscall.BIOCGETBUFMODE": "syscall",
+ "syscall.BIOCGETIF": "syscall",
+ "syscall.BIOCGETZMAX": "syscall",
+ "syscall.BIOCGFEEDBACK": "syscall",
+ "syscall.BIOCGFILDROP": "syscall",
+ "syscall.BIOCGHDRCMPLT": "syscall",
+ "syscall.BIOCGRSIG": "syscall",
+ "syscall.BIOCGRTIMEOUT": "syscall",
+ "syscall.BIOCGSEESENT": "syscall",
+ "syscall.BIOCGSTATS": "syscall",
+ "syscall.BIOCGSTATSOLD": "syscall",
+ "syscall.BIOCGTSTAMP": "syscall",
+ "syscall.BIOCIMMEDIATE": "syscall",
+ "syscall.BIOCLOCK": "syscall",
+ "syscall.BIOCPROMISC": "syscall",
+ "syscall.BIOCROTZBUF": "syscall",
+ "syscall.BIOCSBLEN": "syscall",
+ "syscall.BIOCSDIRECTION": "syscall",
+ "syscall.BIOCSDIRFILT": "syscall",
+ "syscall.BIOCSDLT": "syscall",
+ "syscall.BIOCSETBUFMODE": "syscall",
+ "syscall.BIOCSETF": "syscall",
+ "syscall.BIOCSETFNR": "syscall",
+ "syscall.BIOCSETIF": "syscall",
+ "syscall.BIOCSETWF": "syscall",
+ "syscall.BIOCSETZBUF": "syscall",
+ "syscall.BIOCSFEEDBACK": "syscall",
+ "syscall.BIOCSFILDROP": "syscall",
+ "syscall.BIOCSHDRCMPLT": "syscall",
+ "syscall.BIOCSRSIG": "syscall",
+ "syscall.BIOCSRTIMEOUT": "syscall",
+ "syscall.BIOCSSEESENT": "syscall",
+ "syscall.BIOCSTCPF": "syscall",
+ "syscall.BIOCSTSTAMP": "syscall",
+ "syscall.BIOCSUDPF": "syscall",
+ "syscall.BIOCVERSION": "syscall",
+ "syscall.BPF_A": "syscall",
+ "syscall.BPF_ABS": "syscall",
+ "syscall.BPF_ADD": "syscall",
+ "syscall.BPF_ALIGNMENT": "syscall",
+ "syscall.BPF_ALIGNMENT32": "syscall",
+ "syscall.BPF_ALU": "syscall",
+ "syscall.BPF_AND": "syscall",
+ "syscall.BPF_B": "syscall",
+ "syscall.BPF_BUFMODE_BUFFER": "syscall",
+ "syscall.BPF_BUFMODE_ZBUF": "syscall",
+ "syscall.BPF_DFLTBUFSIZE": "syscall",
+ "syscall.BPF_DIRECTION_IN": "syscall",
+ "syscall.BPF_DIRECTION_OUT": "syscall",
+ "syscall.BPF_DIV": "syscall",
+ "syscall.BPF_H": "syscall",
+ "syscall.BPF_IMM": "syscall",
+ "syscall.BPF_IND": "syscall",
+ "syscall.BPF_JA": "syscall",
+ "syscall.BPF_JEQ": "syscall",
+ "syscall.BPF_JGE": "syscall",
+ "syscall.BPF_JGT": "syscall",
+ "syscall.BPF_JMP": "syscall",
+ "syscall.BPF_JSET": "syscall",
+ "syscall.BPF_K": "syscall",
+ "syscall.BPF_LD": "syscall",
+ "syscall.BPF_LDX": "syscall",
+ "syscall.BPF_LEN": "syscall",
+ "syscall.BPF_LSH": "syscall",
+ "syscall.BPF_MAJOR_VERSION": "syscall",
+ "syscall.BPF_MAXBUFSIZE": "syscall",
+ "syscall.BPF_MAXINSNS": "syscall",
+ "syscall.BPF_MEM": "syscall",
+ "syscall.BPF_MEMWORDS": "syscall",
+ "syscall.BPF_MINBUFSIZE": "syscall",
+ "syscall.BPF_MINOR_VERSION": "syscall",
+ "syscall.BPF_MISC": "syscall",
+ "syscall.BPF_MSH": "syscall",
+ "syscall.BPF_MUL": "syscall",
+ "syscall.BPF_NEG": "syscall",
+ "syscall.BPF_OR": "syscall",
+ "syscall.BPF_RELEASE": "syscall",
+ "syscall.BPF_RET": "syscall",
+ "syscall.BPF_RSH": "syscall",
+ "syscall.BPF_ST": "syscall",
+ "syscall.BPF_STX": "syscall",
+ "syscall.BPF_SUB": "syscall",
+ "syscall.BPF_TAX": "syscall",
+ "syscall.BPF_TXA": "syscall",
+ "syscall.BPF_T_BINTIME": "syscall",
+ "syscall.BPF_T_BINTIME_FAST": "syscall",
+ "syscall.BPF_T_BINTIME_MONOTONIC": "syscall",
+ "syscall.BPF_T_BINTIME_MONOTONIC_FAST": "syscall",
+ "syscall.BPF_T_FAST": "syscall",
+ "syscall.BPF_T_FLAG_MASK": "syscall",
+ "syscall.BPF_T_FORMAT_MASK": "syscall",
+ "syscall.BPF_T_MICROTIME": "syscall",
+ "syscall.BPF_T_MICROTIME_FAST": "syscall",
+ "syscall.BPF_T_MICROTIME_MONOTONIC": "syscall",
+ "syscall.BPF_T_MICROTIME_MONOTONIC_FAST": "syscall",
+ "syscall.BPF_T_MONOTONIC": "syscall",
+ "syscall.BPF_T_MONOTONIC_FAST": "syscall",
+ "syscall.BPF_T_NANOTIME": "syscall",
+ "syscall.BPF_T_NANOTIME_FAST": "syscall",
+ "syscall.BPF_T_NANOTIME_MONOTONIC": "syscall",
+ "syscall.BPF_T_NANOTIME_MONOTONIC_FAST": "syscall",
+ "syscall.BPF_T_NONE": "syscall",
+ "syscall.BPF_T_NORMAL": "syscall",
+ "syscall.BPF_W": "syscall",
+ "syscall.BPF_X": "syscall",
+ "syscall.BRKINT": "syscall",
+ "syscall.Bind": "syscall",
+ "syscall.BindToDevice": "syscall",
+ "syscall.BpfBuflen": "syscall",
+ "syscall.BpfDatalink": "syscall",
+ "syscall.BpfHdr": "syscall",
+ "syscall.BpfHeadercmpl": "syscall",
+ "syscall.BpfInsn": "syscall",
+ "syscall.BpfInterface": "syscall",
+ "syscall.BpfJump": "syscall",
+ "syscall.BpfProgram": "syscall",
+ "syscall.BpfStat": "syscall",
+ "syscall.BpfStats": "syscall",
+ "syscall.BpfStmt": "syscall",
+ "syscall.BpfTimeout": "syscall",
+ "syscall.BpfTimeval": "syscall",
+ "syscall.BpfVersion": "syscall",
+ "syscall.BpfZbuf": "syscall",
+ "syscall.BpfZbufHeader": "syscall",
+ "syscall.ByHandleFileInformation": "syscall",
+ "syscall.BytePtrFromString": "syscall",
+ "syscall.ByteSliceFromString": "syscall",
+ "syscall.CCR0_FLUSH": "syscall",
+ "syscall.CERT_CHAIN_POLICY_AUTHENTICODE": "syscall",
+ "syscall.CERT_CHAIN_POLICY_AUTHENTICODE_TS": "syscall",
+ "syscall.CERT_CHAIN_POLICY_BASE": "syscall",
+ "syscall.CERT_CHAIN_POLICY_BASIC_CONSTRAINTS": "syscall",
+ "syscall.CERT_CHAIN_POLICY_EV": "syscall",
+ "syscall.CERT_CHAIN_POLICY_MICROSOFT_ROOT": "syscall",
+ "syscall.CERT_CHAIN_POLICY_NT_AUTH": "syscall",
+ "syscall.CERT_CHAIN_POLICY_SSL": "syscall",
+ "syscall.CERT_E_CN_NO_MATCH": "syscall",
+ "syscall.CERT_E_EXPIRED": "syscall",
+ "syscall.CERT_E_PURPOSE": "syscall",
+ "syscall.CERT_E_ROLE": "syscall",
+ "syscall.CERT_E_UNTRUSTEDROOT": "syscall",
+ "syscall.CERT_STORE_ADD_ALWAYS": "syscall",
+ "syscall.CERT_STORE_DEFER_CLOSE_UNTIL_LAST_FREE_FLAG": "syscall",
+ "syscall.CERT_STORE_PROV_MEMORY": "syscall",
+ "syscall.CERT_TRUST_HAS_EXCLUDED_NAME_CONSTRAINT": "syscall",
+ "syscall.CERT_TRUST_HAS_NOT_DEFINED_NAME_CONSTRAINT": "syscall",
+ "syscall.CERT_TRUST_HAS_NOT_PERMITTED_NAME_CONSTRAINT": "syscall",
+ "syscall.CERT_TRUST_HAS_NOT_SUPPORTED_CRITICAL_EXT": "syscall",
+ "syscall.CERT_TRUST_HAS_NOT_SUPPORTED_NAME_CONSTRAINT": "syscall",
+ "syscall.CERT_TRUST_INVALID_BASIC_CONSTRAINTS": "syscall",
+ "syscall.CERT_TRUST_INVALID_EXTENSION": "syscall",
+ "syscall.CERT_TRUST_INVALID_NAME_CONSTRAINTS": "syscall",
+ "syscall.CERT_TRUST_INVALID_POLICY_CONSTRAINTS": "syscall",
+ "syscall.CERT_TRUST_IS_CYCLIC": "syscall",
+ "syscall.CERT_TRUST_IS_EXPLICIT_DISTRUST": "syscall",
+ "syscall.CERT_TRUST_IS_NOT_SIGNATURE_VALID": "syscall",
+ "syscall.CERT_TRUST_IS_NOT_TIME_VALID": "syscall",
+ "syscall.CERT_TRUST_IS_NOT_VALID_FOR_USAGE": "syscall",
+ "syscall.CERT_TRUST_IS_OFFLINE_REVOCATION": "syscall",
+ "syscall.CERT_TRUST_IS_REVOKED": "syscall",
+ "syscall.CERT_TRUST_IS_UNTRUSTED_ROOT": "syscall",
+ "syscall.CERT_TRUST_NO_ERROR": "syscall",
+ "syscall.CERT_TRUST_NO_ISSUANCE_CHAIN_POLICY": "syscall",
+ "syscall.CERT_TRUST_REVOCATION_STATUS_UNKNOWN": "syscall",
+ "syscall.CFLUSH": "syscall",
+ "syscall.CLOCAL": "syscall",
+ "syscall.CLONE_CHILD_CLEARTID": "syscall",
+ "syscall.CLONE_CHILD_SETTID": "syscall",
+ "syscall.CLONE_DETACHED": "syscall",
+ "syscall.CLONE_FILES": "syscall",
+ "syscall.CLONE_FS": "syscall",
+ "syscall.CLONE_IO": "syscall",
+ "syscall.CLONE_NEWIPC": "syscall",
+ "syscall.CLONE_NEWNET": "syscall",
+ "syscall.CLONE_NEWNS": "syscall",
+ "syscall.CLONE_NEWPID": "syscall",
+ "syscall.CLONE_NEWUSER": "syscall",
+ "syscall.CLONE_NEWUTS": "syscall",
+ "syscall.CLONE_PARENT": "syscall",
+ "syscall.CLONE_PARENT_SETTID": "syscall",
+ "syscall.CLONE_PTRACE": "syscall",
+ "syscall.CLONE_SETTLS": "syscall",
+ "syscall.CLONE_SIGHAND": "syscall",
+ "syscall.CLONE_SYSVSEM": "syscall",
+ "syscall.CLONE_THREAD": "syscall",
+ "syscall.CLONE_UNTRACED": "syscall",
+ "syscall.CLONE_VFORK": "syscall",
+ "syscall.CLONE_VM": "syscall",
+ "syscall.CPUID_CFLUSH": "syscall",
+ "syscall.CREAD": "syscall",
+ "syscall.CREATE_ALWAYS": "syscall",
+ "syscall.CREATE_NEW": "syscall",
+ "syscall.CREATE_NEW_PROCESS_GROUP": "syscall",
+ "syscall.CREATE_UNICODE_ENVIRONMENT": "syscall",
+ "syscall.CRYPT_DEFAULT_CONTAINER_OPTIONAL": "syscall",
+ "syscall.CRYPT_DELETEKEYSET": "syscall",
+ "syscall.CRYPT_MACHINE_KEYSET": "syscall",
+ "syscall.CRYPT_NEWKEYSET": "syscall",
+ "syscall.CRYPT_SILENT": "syscall",
+ "syscall.CRYPT_VERIFYCONTEXT": "syscall",
+ "syscall.CS5": "syscall",
+ "syscall.CS6": "syscall",
+ "syscall.CS7": "syscall",
+ "syscall.CS8": "syscall",
+ "syscall.CSIZE": "syscall",
+ "syscall.CSTART": "syscall",
+ "syscall.CSTATUS": "syscall",
+ "syscall.CSTOP": "syscall",
+ "syscall.CSTOPB": "syscall",
+ "syscall.CSUSP": "syscall",
+ "syscall.CTL_MAXNAME": "syscall",
+ "syscall.CTL_NET": "syscall",
+ "syscall.CTL_QUERY": "syscall",
+ "syscall.CTRL_BREAK_EVENT": "syscall",
+ "syscall.CTRL_C_EVENT": "syscall",
+ "syscall.CancelIo": "syscall",
+ "syscall.CancelIoEx": "syscall",
+ "syscall.CertAddCertificateContextToStore": "syscall",
+ "syscall.CertChainContext": "syscall",
+ "syscall.CertChainElement": "syscall",
+ "syscall.CertChainPara": "syscall",
+ "syscall.CertChainPolicyPara": "syscall",
+ "syscall.CertChainPolicyStatus": "syscall",
+ "syscall.CertCloseStore": "syscall",
+ "syscall.CertContext": "syscall",
+ "syscall.CertCreateCertificateContext": "syscall",
+ "syscall.CertEnhKeyUsage": "syscall",
+ "syscall.CertEnumCertificatesInStore": "syscall",
+ "syscall.CertFreeCertificateChain": "syscall",
+ "syscall.CertFreeCertificateContext": "syscall",
+ "syscall.CertGetCertificateChain": "syscall",
+ "syscall.CertOpenStore": "syscall",
+ "syscall.CertOpenSystemStore": "syscall",
+ "syscall.CertRevocationInfo": "syscall",
+ "syscall.CertSimpleChain": "syscall",
+ "syscall.CertTrustStatus": "syscall",
+ "syscall.CertUsageMatch": "syscall",
+ "syscall.CertVerifyCertificateChainPolicy": "syscall",
+ "syscall.Chdir": "syscall",
+ "syscall.CheckBpfVersion": "syscall",
+ "syscall.Chflags": "syscall",
+ "syscall.Chmod": "syscall",
+ "syscall.Chown": "syscall",
+ "syscall.Chroot": "syscall",
+ "syscall.Clearenv": "syscall",
+ "syscall.Close": "syscall",
+ "syscall.CloseHandle": "syscall",
+ "syscall.CloseOnExec": "syscall",
+ "syscall.Closesocket": "syscall",
+ "syscall.CmsgLen": "syscall",
+ "syscall.CmsgSpace": "syscall",
+ "syscall.Cmsghdr": "syscall",
+ "syscall.CommandLineToArgv": "syscall",
+ "syscall.ComputerName": "syscall",
+ "syscall.Connect": "syscall",
+ "syscall.ConnectEx": "syscall",
+ "syscall.ConvertSidToStringSid": "syscall",
+ "syscall.ConvertStringSidToSid": "syscall",
+ "syscall.CopySid": "syscall",
+ "syscall.Creat": "syscall",
+ "syscall.CreateDirectory": "syscall",
+ "syscall.CreateFile": "syscall",
+ "syscall.CreateFileMapping": "syscall",
+ "syscall.CreateIoCompletionPort": "syscall",
+ "syscall.CreatePipe": "syscall",
+ "syscall.CreateProcess": "syscall",
+ "syscall.Credential": "syscall",
+ "syscall.CryptAcquireContext": "syscall",
+ "syscall.CryptGenRandom": "syscall",
+ "syscall.CryptReleaseContext": "syscall",
+ "syscall.DIOCBSFLUSH": "syscall",
+ "syscall.DIOCOSFPFLUSH": "syscall",
+ "syscall.DLL": "syscall",
+ "syscall.DLLError": "syscall",
+ "syscall.DLT_A429": "syscall",
+ "syscall.DLT_A653_ICM": "syscall",
+ "syscall.DLT_AIRONET_HEADER": "syscall",
+ "syscall.DLT_AOS": "syscall",
+ "syscall.DLT_APPLE_IP_OVER_IEEE1394": "syscall",
+ "syscall.DLT_ARCNET": "syscall",
+ "syscall.DLT_ARCNET_LINUX": "syscall",
+ "syscall.DLT_ATM_CLIP": "syscall",
+ "syscall.DLT_ATM_RFC1483": "syscall",
+ "syscall.DLT_AURORA": "syscall",
+ "syscall.DLT_AX25": "syscall",
+ "syscall.DLT_AX25_KISS": "syscall",
+ "syscall.DLT_BACNET_MS_TP": "syscall",
+ "syscall.DLT_BLUETOOTH_HCI_H4": "syscall",
+ "syscall.DLT_BLUETOOTH_HCI_H4_WITH_PHDR": "syscall",
+ "syscall.DLT_CAN20B": "syscall",
+ "syscall.DLT_CAN_SOCKETCAN": "syscall",
+ "syscall.DLT_CHAOS": "syscall",
+ "syscall.DLT_CHDLC": "syscall",
+ "syscall.DLT_CISCO_IOS": "syscall",
+ "syscall.DLT_C_HDLC": "syscall",
+ "syscall.DLT_C_HDLC_WITH_DIR": "syscall",
+ "syscall.DLT_DBUS": "syscall",
+ "syscall.DLT_DECT": "syscall",
+ "syscall.DLT_DOCSIS": "syscall",
+ "syscall.DLT_DVB_CI": "syscall",
+ "syscall.DLT_ECONET": "syscall",
+ "syscall.DLT_EN10MB": "syscall",
+ "syscall.DLT_EN3MB": "syscall",
+ "syscall.DLT_ENC": "syscall",
+ "syscall.DLT_ERF": "syscall",
+ "syscall.DLT_ERF_ETH": "syscall",
+ "syscall.DLT_ERF_POS": "syscall",
+ "syscall.DLT_FC_2": "syscall",
+ "syscall.DLT_FC_2_WITH_FRAME_DELIMS": "syscall",
+ "syscall.DLT_FDDI": "syscall",
+ "syscall.DLT_FLEXRAY": "syscall",
+ "syscall.DLT_FRELAY": "syscall",
+ "syscall.DLT_FRELAY_WITH_DIR": "syscall",
+ "syscall.DLT_GCOM_SERIAL": "syscall",
+ "syscall.DLT_GCOM_T1E1": "syscall",
+ "syscall.DLT_GPF_F": "syscall",
+ "syscall.DLT_GPF_T": "syscall",
+ "syscall.DLT_GPRS_LLC": "syscall",
+ "syscall.DLT_GSMTAP_ABIS": "syscall",
+ "syscall.DLT_GSMTAP_UM": "syscall",
+ "syscall.DLT_HDLC": "syscall",
+ "syscall.DLT_HHDLC": "syscall",
+ "syscall.DLT_HIPPI": "syscall",
+ "syscall.DLT_IBM_SN": "syscall",
+ "syscall.DLT_IBM_SP": "syscall",
+ "syscall.DLT_IEEE802": "syscall",
+ "syscall.DLT_IEEE802_11": "syscall",
+ "syscall.DLT_IEEE802_11_RADIO": "syscall",
+ "syscall.DLT_IEEE802_11_RADIO_AVS": "syscall",
+ "syscall.DLT_IEEE802_15_4": "syscall",
+ "syscall.DLT_IEEE802_15_4_LINUX": "syscall",
+ "syscall.DLT_IEEE802_15_4_NOFCS": "syscall",
+ "syscall.DLT_IEEE802_15_4_NONASK_PHY": "syscall",
+ "syscall.DLT_IEEE802_16_MAC_CPS": "syscall",
+ "syscall.DLT_IEEE802_16_MAC_CPS_RADIO": "syscall",
+ "syscall.DLT_IPFILTER": "syscall",
+ "syscall.DLT_IPMB": "syscall",
+ "syscall.DLT_IPMB_LINUX": "syscall",
+ "syscall.DLT_IPNET": "syscall",
+ "syscall.DLT_IPOIB": "syscall",
+ "syscall.DLT_IPV4": "syscall",
+ "syscall.DLT_IPV6": "syscall",
+ "syscall.DLT_IP_OVER_FC": "syscall",
+ "syscall.DLT_JUNIPER_ATM1": "syscall",
+ "syscall.DLT_JUNIPER_ATM2": "syscall",
+ "syscall.DLT_JUNIPER_ATM_CEMIC": "syscall",
+ "syscall.DLT_JUNIPER_CHDLC": "syscall",
+ "syscall.DLT_JUNIPER_ES": "syscall",
+ "syscall.DLT_JUNIPER_ETHER": "syscall",
+ "syscall.DLT_JUNIPER_FIBRECHANNEL": "syscall",
+ "syscall.DLT_JUNIPER_FRELAY": "syscall",
+ "syscall.DLT_JUNIPER_GGSN": "syscall",
+ "syscall.DLT_JUNIPER_ISM": "syscall",
+ "syscall.DLT_JUNIPER_MFR": "syscall",
+ "syscall.DLT_JUNIPER_MLFR": "syscall",
+ "syscall.DLT_JUNIPER_MLPPP": "syscall",
+ "syscall.DLT_JUNIPER_MONITOR": "syscall",
+ "syscall.DLT_JUNIPER_PIC_PEER": "syscall",
+ "syscall.DLT_JUNIPER_PPP": "syscall",
+ "syscall.DLT_JUNIPER_PPPOE": "syscall",
+ "syscall.DLT_JUNIPER_PPPOE_ATM": "syscall",
+ "syscall.DLT_JUNIPER_SERVICES": "syscall",
+ "syscall.DLT_JUNIPER_SRX_E2E": "syscall",
+ "syscall.DLT_JUNIPER_ST": "syscall",
+ "syscall.DLT_JUNIPER_VP": "syscall",
+ "syscall.DLT_JUNIPER_VS": "syscall",
+ "syscall.DLT_LAPB_WITH_DIR": "syscall",
+ "syscall.DLT_LAPD": "syscall",
+ "syscall.DLT_LIN": "syscall",
+ "syscall.DLT_LINUX_EVDEV": "syscall",
+ "syscall.DLT_LINUX_IRDA": "syscall",
+ "syscall.DLT_LINUX_LAPD": "syscall",
+ "syscall.DLT_LINUX_PPP_WITHDIRECTION": "syscall",
+ "syscall.DLT_LINUX_SLL": "syscall",
+ "syscall.DLT_LOOP": "syscall",
+ "syscall.DLT_LTALK": "syscall",
+ "syscall.DLT_MATCHING_MAX": "syscall",
+ "syscall.DLT_MATCHING_MIN": "syscall",
+ "syscall.DLT_MFR": "syscall",
+ "syscall.DLT_MOST": "syscall",
+ "syscall.DLT_MPEG_2_TS": "syscall",
+ "syscall.DLT_MPLS": "syscall",
+ "syscall.DLT_MTP2": "syscall",
+ "syscall.DLT_MTP2_WITH_PHDR": "syscall",
+ "syscall.DLT_MTP3": "syscall",
+ "syscall.DLT_MUX27010": "syscall",
+ "syscall.DLT_NETANALYZER": "syscall",
+ "syscall.DLT_NETANALYZER_TRANSPARENT": "syscall",
+ "syscall.DLT_NFC_LLCP": "syscall",
+ "syscall.DLT_NFLOG": "syscall",
+ "syscall.DLT_NG40": "syscall",
+ "syscall.DLT_NULL": "syscall",
+ "syscall.DLT_PCI_EXP": "syscall",
+ "syscall.DLT_PFLOG": "syscall",
+ "syscall.DLT_PFSYNC": "syscall",
+ "syscall.DLT_PPI": "syscall",
+ "syscall.DLT_PPP": "syscall",
+ "syscall.DLT_PPP_BSDOS": "syscall",
+ "syscall.DLT_PPP_ETHER": "syscall",
+ "syscall.DLT_PPP_PPPD": "syscall",
+ "syscall.DLT_PPP_SERIAL": "syscall",
+ "syscall.DLT_PPP_WITH_DIR": "syscall",
+ "syscall.DLT_PPP_WITH_DIRECTION": "syscall",
+ "syscall.DLT_PRISM_HEADER": "syscall",
+ "syscall.DLT_PRONET": "syscall",
+ "syscall.DLT_RAIF1": "syscall",
+ "syscall.DLT_RAW": "syscall",
+ "syscall.DLT_RAWAF_MASK": "syscall",
+ "syscall.DLT_RIO": "syscall",
+ "syscall.DLT_SCCP": "syscall",
+ "syscall.DLT_SITA": "syscall",
+ "syscall.DLT_SLIP": "syscall",
+ "syscall.DLT_SLIP_BSDOS": "syscall",
+ "syscall.DLT_STANAG_5066_D_PDU": "syscall",
+ "syscall.DLT_SUNATM": "syscall",
+ "syscall.DLT_SYMANTEC_FIREWALL": "syscall",
+ "syscall.DLT_TZSP": "syscall",
+ "syscall.DLT_USB": "syscall",
+ "syscall.DLT_USB_LINUX": "syscall",
+ "syscall.DLT_USB_LINUX_MMAPPED": "syscall",
+ "syscall.DLT_USER0": "syscall",
+ "syscall.DLT_USER1": "syscall",
+ "syscall.DLT_USER10": "syscall",
+ "syscall.DLT_USER11": "syscall",
+ "syscall.DLT_USER12": "syscall",
+ "syscall.DLT_USER13": "syscall",
+ "syscall.DLT_USER14": "syscall",
+ "syscall.DLT_USER15": "syscall",
+ "syscall.DLT_USER2": "syscall",
+ "syscall.DLT_USER3": "syscall",
+ "syscall.DLT_USER4": "syscall",
+ "syscall.DLT_USER5": "syscall",
+ "syscall.DLT_USER6": "syscall",
+ "syscall.DLT_USER7": "syscall",
+ "syscall.DLT_USER8": "syscall",
+ "syscall.DLT_USER9": "syscall",
+ "syscall.DLT_WIHART": "syscall",
+ "syscall.DLT_X2E_SERIAL": "syscall",
+ "syscall.DLT_X2E_XORAYA": "syscall",
+ "syscall.DNSMXData": "syscall",
+ "syscall.DNSPTRData": "syscall",
+ "syscall.DNSRecord": "syscall",
+ "syscall.DNSSRVData": "syscall",
+ "syscall.DNSTXTData": "syscall",
+ "syscall.DNS_TYPE_A": "syscall",
+ "syscall.DNS_TYPE_A6": "syscall",
+ "syscall.DNS_TYPE_AAAA": "syscall",
+ "syscall.DNS_TYPE_ADDRS": "syscall",
+ "syscall.DNS_TYPE_AFSDB": "syscall",
+ "syscall.DNS_TYPE_ALL": "syscall",
+ "syscall.DNS_TYPE_ANY": "syscall",
+ "syscall.DNS_TYPE_ATMA": "syscall",
+ "syscall.DNS_TYPE_AXFR": "syscall",
+ "syscall.DNS_TYPE_CERT": "syscall",
+ "syscall.DNS_TYPE_CNAME": "syscall",
+ "syscall.DNS_TYPE_DHCID": "syscall",
+ "syscall.DNS_TYPE_DNAME": "syscall",
+ "syscall.DNS_TYPE_DNSKEY": "syscall",
+ "syscall.DNS_TYPE_DS": "syscall",
+ "syscall.DNS_TYPE_EID": "syscall",
+ "syscall.DNS_TYPE_GID": "syscall",
+ "syscall.DNS_TYPE_GPOS": "syscall",
+ "syscall.DNS_TYPE_HINFO": "syscall",
+ "syscall.DNS_TYPE_ISDN": "syscall",
+ "syscall.DNS_TYPE_IXFR": "syscall",
+ "syscall.DNS_TYPE_KEY": "syscall",
+ "syscall.DNS_TYPE_KX": "syscall",
+ "syscall.DNS_TYPE_LOC": "syscall",
+ "syscall.DNS_TYPE_MAILA": "syscall",
+ "syscall.DNS_TYPE_MAILB": "syscall",
+ "syscall.DNS_TYPE_MB": "syscall",
+ "syscall.DNS_TYPE_MD": "syscall",
+ "syscall.DNS_TYPE_MF": "syscall",
+ "syscall.DNS_TYPE_MG": "syscall",
+ "syscall.DNS_TYPE_MINFO": "syscall",
+ "syscall.DNS_TYPE_MR": "syscall",
+ "syscall.DNS_TYPE_MX": "syscall",
+ "syscall.DNS_TYPE_NAPTR": "syscall",
+ "syscall.DNS_TYPE_NBSTAT": "syscall",
+ "syscall.DNS_TYPE_NIMLOC": "syscall",
+ "syscall.DNS_TYPE_NS": "syscall",
+ "syscall.DNS_TYPE_NSAP": "syscall",
+ "syscall.DNS_TYPE_NSAPPTR": "syscall",
+ "syscall.DNS_TYPE_NSEC": "syscall",
+ "syscall.DNS_TYPE_NULL": "syscall",
+ "syscall.DNS_TYPE_NXT": "syscall",
+ "syscall.DNS_TYPE_OPT": "syscall",
+ "syscall.DNS_TYPE_PTR": "syscall",
+ "syscall.DNS_TYPE_PX": "syscall",
+ "syscall.DNS_TYPE_RP": "syscall",
+ "syscall.DNS_TYPE_RRSIG": "syscall",
+ "syscall.DNS_TYPE_RT": "syscall",
+ "syscall.DNS_TYPE_SIG": "syscall",
+ "syscall.DNS_TYPE_SINK": "syscall",
+ "syscall.DNS_TYPE_SOA": "syscall",
+ "syscall.DNS_TYPE_SRV": "syscall",
+ "syscall.DNS_TYPE_TEXT": "syscall",
+ "syscall.DNS_TYPE_TKEY": "syscall",
+ "syscall.DNS_TYPE_TSIG": "syscall",
+ "syscall.DNS_TYPE_UID": "syscall",
+ "syscall.DNS_TYPE_UINFO": "syscall",
+ "syscall.DNS_TYPE_UNSPEC": "syscall",
+ "syscall.DNS_TYPE_WINS": "syscall",
+ "syscall.DNS_TYPE_WINSR": "syscall",
+ "syscall.DNS_TYPE_WKS": "syscall",
+ "syscall.DNS_TYPE_X25": "syscall",
+ "syscall.DT_BLK": "syscall",
+ "syscall.DT_CHR": "syscall",
+ "syscall.DT_DIR": "syscall",
+ "syscall.DT_FIFO": "syscall",
+ "syscall.DT_LNK": "syscall",
+ "syscall.DT_REG": "syscall",
+ "syscall.DT_SOCK": "syscall",
+ "syscall.DT_UNKNOWN": "syscall",
+ "syscall.DT_WHT": "syscall",
+ "syscall.DUPLICATE_CLOSE_SOURCE": "syscall",
+ "syscall.DUPLICATE_SAME_ACCESS": "syscall",
+ "syscall.DeleteFile": "syscall",
+ "syscall.DetachLsf": "syscall",
+ "syscall.Dirent": "syscall",
+ "syscall.DnsQuery": "syscall",
+ "syscall.DnsRecordListFree": "syscall",
+ "syscall.Dup": "syscall",
+ "syscall.Dup2": "syscall",
+ "syscall.Dup3": "syscall",
+ "syscall.DuplicateHandle": "syscall",
+ "syscall.E2BIG": "syscall",
+ "syscall.EACCES": "syscall",
+ "syscall.EADDRINUSE": "syscall",
+ "syscall.EADDRNOTAVAIL": "syscall",
+ "syscall.EADV": "syscall",
+ "syscall.EAFNOSUPPORT": "syscall",
+ "syscall.EAGAIN": "syscall",
+ "syscall.EALREADY": "syscall",
+ "syscall.EAUTH": "syscall",
+ "syscall.EBADARCH": "syscall",
+ "syscall.EBADE": "syscall",
+ "syscall.EBADEXEC": "syscall",
+ "syscall.EBADF": "syscall",
+ "syscall.EBADFD": "syscall",
+ "syscall.EBADMACHO": "syscall",
+ "syscall.EBADMSG": "syscall",
+ "syscall.EBADR": "syscall",
+ "syscall.EBADRPC": "syscall",
+ "syscall.EBADRQC": "syscall",
+ "syscall.EBADSLT": "syscall",
+ "syscall.EBFONT": "syscall",
+ "syscall.EBUSY": "syscall",
+ "syscall.ECANCELED": "syscall",
+ "syscall.ECAPMODE": "syscall",
+ "syscall.ECHILD": "syscall",
+ "syscall.ECHO": "syscall",
+ "syscall.ECHOCTL": "syscall",
+ "syscall.ECHOE": "syscall",
+ "syscall.ECHOK": "syscall",
+ "syscall.ECHOKE": "syscall",
+ "syscall.ECHONL": "syscall",
+ "syscall.ECHOPRT": "syscall",
+ "syscall.ECHRNG": "syscall",
+ "syscall.ECOMM": "syscall",
+ "syscall.ECONNABORTED": "syscall",
+ "syscall.ECONNREFUSED": "syscall",
+ "syscall.ECONNRESET": "syscall",
+ "syscall.EDEADLK": "syscall",
+ "syscall.EDEADLOCK": "syscall",
+ "syscall.EDESTADDRREQ": "syscall",
+ "syscall.EDEVERR": "syscall",
+ "syscall.EDOM": "syscall",
+ "syscall.EDOOFUS": "syscall",
+ "syscall.EDOTDOT": "syscall",
+ "syscall.EDQUOT": "syscall",
+ "syscall.EEXIST": "syscall",
+ "syscall.EFAULT": "syscall",
+ "syscall.EFBIG": "syscall",
+ "syscall.EFER_LMA": "syscall",
+ "syscall.EFER_LME": "syscall",
+ "syscall.EFER_NXE": "syscall",
+ "syscall.EFER_SCE": "syscall",
+ "syscall.EFTYPE": "syscall",
+ "syscall.EHOSTDOWN": "syscall",
+ "syscall.EHOSTUNREACH": "syscall",
+ "syscall.EHWPOISON": "syscall",
+ "syscall.EIDRM": "syscall",
+ "syscall.EILSEQ": "syscall",
+ "syscall.EINPROGRESS": "syscall",
+ "syscall.EINTR": "syscall",
+ "syscall.EINVAL": "syscall",
+ "syscall.EIO": "syscall",
+ "syscall.EIPSEC": "syscall",
+ "syscall.EISCONN": "syscall",
+ "syscall.EISDIR": "syscall",
+ "syscall.EISNAM": "syscall",
+ "syscall.EKEYEXPIRED": "syscall",
+ "syscall.EKEYREJECTED": "syscall",
+ "syscall.EKEYREVOKED": "syscall",
+ "syscall.EL2HLT": "syscall",
+ "syscall.EL2NSYNC": "syscall",
+ "syscall.EL3HLT": "syscall",
+ "syscall.EL3RST": "syscall",
+ "syscall.ELAST": "syscall",
+ "syscall.ELF_NGREG": "syscall",
+ "syscall.ELF_PRARGSZ": "syscall",
+ "syscall.ELIBACC": "syscall",
+ "syscall.ELIBBAD": "syscall",
+ "syscall.ELIBEXEC": "syscall",
+ "syscall.ELIBMAX": "syscall",
+ "syscall.ELIBSCN": "syscall",
+ "syscall.ELNRNG": "syscall",
+ "syscall.ELOOP": "syscall",
+ "syscall.EMEDIUMTYPE": "syscall",
+ "syscall.EMFILE": "syscall",
+ "syscall.EMLINK": "syscall",
+ "syscall.EMSGSIZE": "syscall",
+ "syscall.EMT_TAGOVF": "syscall",
+ "syscall.EMULTIHOP": "syscall",
+ "syscall.EMUL_ENABLED": "syscall",
+ "syscall.EMUL_LINUX": "syscall",
+ "syscall.EMUL_LINUX32": "syscall",
+ "syscall.EMUL_MAXID": "syscall",
+ "syscall.EMUL_NATIVE": "syscall",
+ "syscall.ENAMETOOLONG": "syscall",
+ "syscall.ENAVAIL": "syscall",
+ "syscall.ENDRUNDISC": "syscall",
+ "syscall.ENEEDAUTH": "syscall",
+ "syscall.ENETDOWN": "syscall",
+ "syscall.ENETRESET": "syscall",
+ "syscall.ENETUNREACH": "syscall",
+ "syscall.ENFILE": "syscall",
+ "syscall.ENOANO": "syscall",
+ "syscall.ENOATTR": "syscall",
+ "syscall.ENOBUFS": "syscall",
+ "syscall.ENOCSI": "syscall",
+ "syscall.ENODATA": "syscall",
+ "syscall.ENODEV": "syscall",
+ "syscall.ENOENT": "syscall",
+ "syscall.ENOEXEC": "syscall",
+ "syscall.ENOKEY": "syscall",
+ "syscall.ENOLCK": "syscall",
+ "syscall.ENOLINK": "syscall",
+ "syscall.ENOMEDIUM": "syscall",
+ "syscall.ENOMEM": "syscall",
+ "syscall.ENOMSG": "syscall",
+ "syscall.ENONET": "syscall",
+ "syscall.ENOPKG": "syscall",
+ "syscall.ENOPOLICY": "syscall",
+ "syscall.ENOPROTOOPT": "syscall",
+ "syscall.ENOSPC": "syscall",
+ "syscall.ENOSR": "syscall",
+ "syscall.ENOSTR": "syscall",
+ "syscall.ENOSYS": "syscall",
+ "syscall.ENOTBLK": "syscall",
+ "syscall.ENOTCAPABLE": "syscall",
+ "syscall.ENOTCONN": "syscall",
+ "syscall.ENOTDIR": "syscall",
+ "syscall.ENOTEMPTY": "syscall",
+ "syscall.ENOTNAM": "syscall",
+ "syscall.ENOTRECOVERABLE": "syscall",
+ "syscall.ENOTSOCK": "syscall",
+ "syscall.ENOTSUP": "syscall",
+ "syscall.ENOTTY": "syscall",
+ "syscall.ENOTUNIQ": "syscall",
+ "syscall.ENXIO": "syscall",
+ "syscall.EN_SW_CTL_INF": "syscall",
+ "syscall.EN_SW_CTL_PREC": "syscall",
+ "syscall.EN_SW_CTL_ROUND": "syscall",
+ "syscall.EN_SW_DATACHAIN": "syscall",
+ "syscall.EN_SW_DENORM": "syscall",
+ "syscall.EN_SW_INVOP": "syscall",
+ "syscall.EN_SW_OVERFLOW": "syscall",
+ "syscall.EN_SW_PRECLOSS": "syscall",
+ "syscall.EN_SW_UNDERFLOW": "syscall",
+ "syscall.EN_SW_ZERODIV": "syscall",
+ "syscall.EOPNOTSUPP": "syscall",
+ "syscall.EOVERFLOW": "syscall",
+ "syscall.EOWNERDEAD": "syscall",
+ "syscall.EPERM": "syscall",
+ "syscall.EPFNOSUPPORT": "syscall",
+ "syscall.EPIPE": "syscall",
+ "syscall.EPOLLERR": "syscall",
+ "syscall.EPOLLET": "syscall",
+ "syscall.EPOLLHUP": "syscall",
+ "syscall.EPOLLIN": "syscall",
+ "syscall.EPOLLMSG": "syscall",
+ "syscall.EPOLLONESHOT": "syscall",
+ "syscall.EPOLLOUT": "syscall",
+ "syscall.EPOLLPRI": "syscall",
+ "syscall.EPOLLRDBAND": "syscall",
+ "syscall.EPOLLRDHUP": "syscall",
+ "syscall.EPOLLRDNORM": "syscall",
+ "syscall.EPOLLWRBAND": "syscall",
+ "syscall.EPOLLWRNORM": "syscall",
+ "syscall.EPOLL_CLOEXEC": "syscall",
+ "syscall.EPOLL_CTL_ADD": "syscall",
+ "syscall.EPOLL_CTL_DEL": "syscall",
+ "syscall.EPOLL_CTL_MOD": "syscall",
+ "syscall.EPOLL_NONBLOCK": "syscall",
+ "syscall.EPROCLIM": "syscall",
+ "syscall.EPROCUNAVAIL": "syscall",
+ "syscall.EPROGMISMATCH": "syscall",
+ "syscall.EPROGUNAVAIL": "syscall",
+ "syscall.EPROTO": "syscall",
+ "syscall.EPROTONOSUPPORT": "syscall",
+ "syscall.EPROTOTYPE": "syscall",
+ "syscall.EPWROFF": "syscall",
+ "syscall.ERANGE": "syscall",
+ "syscall.EREMCHG": "syscall",
+ "syscall.EREMOTE": "syscall",
+ "syscall.EREMOTEIO": "syscall",
+ "syscall.ERESTART": "syscall",
+ "syscall.ERFKILL": "syscall",
+ "syscall.EROFS": "syscall",
+ "syscall.ERPCMISMATCH": "syscall",
+ "syscall.ERROR_ACCESS_DENIED": "syscall",
+ "syscall.ERROR_ALREADY_EXISTS": "syscall",
+ "syscall.ERROR_BROKEN_PIPE": "syscall",
+ "syscall.ERROR_BUFFER_OVERFLOW": "syscall",
+ "syscall.ERROR_ENVVAR_NOT_FOUND": "syscall",
+ "syscall.ERROR_FILE_EXISTS": "syscall",
+ "syscall.ERROR_FILE_NOT_FOUND": "syscall",
+ "syscall.ERROR_HANDLE_EOF": "syscall",
+ "syscall.ERROR_INSUFFICIENT_BUFFER": "syscall",
+ "syscall.ERROR_IO_PENDING": "syscall",
+ "syscall.ERROR_MOD_NOT_FOUND": "syscall",
+ "syscall.ERROR_NOT_FOUND": "syscall",
+ "syscall.ERROR_NO_MORE_FILES": "syscall",
+ "syscall.ERROR_OPERATION_ABORTED": "syscall",
+ "syscall.ERROR_PATH_NOT_FOUND": "syscall",
+ "syscall.ERROR_PROC_NOT_FOUND": "syscall",
+ "syscall.ESHLIBVERS": "syscall",
+ "syscall.ESHUTDOWN": "syscall",
+ "syscall.ESOCKTNOSUPPORT": "syscall",
+ "syscall.ESPIPE": "syscall",
+ "syscall.ESRCH": "syscall",
+ "syscall.ESRMNT": "syscall",
+ "syscall.ESTALE": "syscall",
+ "syscall.ESTRPIPE": "syscall",
+ "syscall.ETHERCAP_JUMBO_MTU": "syscall",
+ "syscall.ETHERCAP_VLAN_HWTAGGING": "syscall",
+ "syscall.ETHERCAP_VLAN_MTU": "syscall",
+ "syscall.ETHERMIN": "syscall",
+ "syscall.ETHERMTU": "syscall",
+ "syscall.ETHERMTU_JUMBO": "syscall",
+ "syscall.ETHERTYPE_8023": "syscall",
+ "syscall.ETHERTYPE_AARP": "syscall",
+ "syscall.ETHERTYPE_ACCTON": "syscall",
+ "syscall.ETHERTYPE_AEONIC": "syscall",
+ "syscall.ETHERTYPE_ALPHA": "syscall",
+ "syscall.ETHERTYPE_AMBER": "syscall",
+ "syscall.ETHERTYPE_AMOEBA": "syscall",
+ "syscall.ETHERTYPE_AOE": "syscall",
+ "syscall.ETHERTYPE_APOLLO": "syscall",
+ "syscall.ETHERTYPE_APOLLODOMAIN": "syscall",
+ "syscall.ETHERTYPE_APPLETALK": "syscall",
+ "syscall.ETHERTYPE_APPLITEK": "syscall",
+ "syscall.ETHERTYPE_ARGONAUT": "syscall",
+ "syscall.ETHERTYPE_ARP": "syscall",
+ "syscall.ETHERTYPE_AT": "syscall",
+ "syscall.ETHERTYPE_ATALK": "syscall",
+ "syscall.ETHERTYPE_ATOMIC": "syscall",
+ "syscall.ETHERTYPE_ATT": "syscall",
+ "syscall.ETHERTYPE_ATTSTANFORD": "syscall",
+ "syscall.ETHERTYPE_AUTOPHON": "syscall",
+ "syscall.ETHERTYPE_AXIS": "syscall",
+ "syscall.ETHERTYPE_BCLOOP": "syscall",
+ "syscall.ETHERTYPE_BOFL": "syscall",
+ "syscall.ETHERTYPE_CABLETRON": "syscall",
+ "syscall.ETHERTYPE_CHAOS": "syscall",
+ "syscall.ETHERTYPE_COMDESIGN": "syscall",
+ "syscall.ETHERTYPE_COMPUGRAPHIC": "syscall",
+ "syscall.ETHERTYPE_COUNTERPOINT": "syscall",
+ "syscall.ETHERTYPE_CRONUS": "syscall",
+ "syscall.ETHERTYPE_CRONUSVLN": "syscall",
+ "syscall.ETHERTYPE_DCA": "syscall",
+ "syscall.ETHERTYPE_DDE": "syscall",
+ "syscall.ETHERTYPE_DEBNI": "syscall",
+ "syscall.ETHERTYPE_DECAM": "syscall",
+ "syscall.ETHERTYPE_DECCUST": "syscall",
+ "syscall.ETHERTYPE_DECDIAG": "syscall",
+ "syscall.ETHERTYPE_DECDNS": "syscall",
+ "syscall.ETHERTYPE_DECDTS": "syscall",
+ "syscall.ETHERTYPE_DECEXPER": "syscall",
+ "syscall.ETHERTYPE_DECLAST": "syscall",
+ "syscall.ETHERTYPE_DECLTM": "syscall",
+ "syscall.ETHERTYPE_DECMUMPS": "syscall",
+ "syscall.ETHERTYPE_DECNETBIOS": "syscall",
+ "syscall.ETHERTYPE_DELTACON": "syscall",
+ "syscall.ETHERTYPE_DIDDLE": "syscall",
+ "syscall.ETHERTYPE_DLOG1": "syscall",
+ "syscall.ETHERTYPE_DLOG2": "syscall",
+ "syscall.ETHERTYPE_DN": "syscall",
+ "syscall.ETHERTYPE_DOGFIGHT": "syscall",
+ "syscall.ETHERTYPE_DSMD": "syscall",
+ "syscall.ETHERTYPE_ECMA": "syscall",
+ "syscall.ETHERTYPE_ENCRYPT": "syscall",
+ "syscall.ETHERTYPE_ES": "syscall",
+ "syscall.ETHERTYPE_EXCELAN": "syscall",
+ "syscall.ETHERTYPE_EXPERDATA": "syscall",
+ "syscall.ETHERTYPE_FLIP": "syscall",
+ "syscall.ETHERTYPE_FLOWCONTROL": "syscall",
+ "syscall.ETHERTYPE_FRARP": "syscall",
+ "syscall.ETHERTYPE_GENDYN": "syscall",
+ "syscall.ETHERTYPE_HAYES": "syscall",
+ "syscall.ETHERTYPE_HIPPI_FP": "syscall",
+ "syscall.ETHERTYPE_HITACHI": "syscall",
+ "syscall.ETHERTYPE_HP": "syscall",
+ "syscall.ETHERTYPE_IEEEPUP": "syscall",
+ "syscall.ETHERTYPE_IEEEPUPAT": "syscall",
+ "syscall.ETHERTYPE_IMLBL": "syscall",
+ "syscall.ETHERTYPE_IMLBLDIAG": "syscall",
+ "syscall.ETHERTYPE_IP": "syscall",
+ "syscall.ETHERTYPE_IPAS": "syscall",
+ "syscall.ETHERTYPE_IPV6": "syscall",
+ "syscall.ETHERTYPE_IPX": "syscall",
+ "syscall.ETHERTYPE_IPXNEW": "syscall",
+ "syscall.ETHERTYPE_KALPANA": "syscall",
+ "syscall.ETHERTYPE_LANBRIDGE": "syscall",
+ "syscall.ETHERTYPE_LANPROBE": "syscall",
+ "syscall.ETHERTYPE_LAT": "syscall",
+ "syscall.ETHERTYPE_LBACK": "syscall",
+ "syscall.ETHERTYPE_LITTLE": "syscall",
+ "syscall.ETHERTYPE_LLDP": "syscall",
+ "syscall.ETHERTYPE_LOGICRAFT": "syscall",
+ "syscall.ETHERTYPE_LOOPBACK": "syscall",
+ "syscall.ETHERTYPE_MATRA": "syscall",
+ "syscall.ETHERTYPE_MAX": "syscall",
+ "syscall.ETHERTYPE_MERIT": "syscall",
+ "syscall.ETHERTYPE_MICP": "syscall",
+ "syscall.ETHERTYPE_MOPDL": "syscall",
+ "syscall.ETHERTYPE_MOPRC": "syscall",
+ "syscall.ETHERTYPE_MOTOROLA": "syscall",
+ "syscall.ETHERTYPE_MPLS": "syscall",
+ "syscall.ETHERTYPE_MPLS_MCAST": "syscall",
+ "syscall.ETHERTYPE_MUMPS": "syscall",
+ "syscall.ETHERTYPE_NBPCC": "syscall",
+ "syscall.ETHERTYPE_NBPCLAIM": "syscall",
+ "syscall.ETHERTYPE_NBPCLREQ": "syscall",
+ "syscall.ETHERTYPE_NBPCLRSP": "syscall",
+ "syscall.ETHERTYPE_NBPCREQ": "syscall",
+ "syscall.ETHERTYPE_NBPCRSP": "syscall",
+ "syscall.ETHERTYPE_NBPDG": "syscall",
+ "syscall.ETHERTYPE_NBPDGB": "syscall",
+ "syscall.ETHERTYPE_NBPDLTE": "syscall",
+ "syscall.ETHERTYPE_NBPRAR": "syscall",
+ "syscall.ETHERTYPE_NBPRAS": "syscall",
+ "syscall.ETHERTYPE_NBPRST": "syscall",
+ "syscall.ETHERTYPE_NBPSCD": "syscall",
+ "syscall.ETHERTYPE_NBPVCD": "syscall",
+ "syscall.ETHERTYPE_NBS": "syscall",
+ "syscall.ETHERTYPE_NCD": "syscall",
+ "syscall.ETHERTYPE_NESTAR": "syscall",
+ "syscall.ETHERTYPE_NETBEUI": "syscall",
+ "syscall.ETHERTYPE_NOVELL": "syscall",
+ "syscall.ETHERTYPE_NS": "syscall",
+ "syscall.ETHERTYPE_NSAT": "syscall",
+ "syscall.ETHERTYPE_NSCOMPAT": "syscall",
+ "syscall.ETHERTYPE_NTRAILER": "syscall",
+ "syscall.ETHERTYPE_OS9": "syscall",
+ "syscall.ETHERTYPE_OS9NET": "syscall",
+ "syscall.ETHERTYPE_PACER": "syscall",
+ "syscall.ETHERTYPE_PAE": "syscall",
+ "syscall.ETHERTYPE_PCS": "syscall",
+ "syscall.ETHERTYPE_PLANNING": "syscall",
+ "syscall.ETHERTYPE_PPP": "syscall",
+ "syscall.ETHERTYPE_PPPOE": "syscall",
+ "syscall.ETHERTYPE_PPPOEDISC": "syscall",
+ "syscall.ETHERTYPE_PRIMENTS": "syscall",
+ "syscall.ETHERTYPE_PUP": "syscall",
+ "syscall.ETHERTYPE_PUPAT": "syscall",
+ "syscall.ETHERTYPE_QINQ": "syscall",
+ "syscall.ETHERTYPE_RACAL": "syscall",
+ "syscall.ETHERTYPE_RATIONAL": "syscall",
+ "syscall.ETHERTYPE_RAWFR": "syscall",
+ "syscall.ETHERTYPE_RCL": "syscall",
+ "syscall.ETHERTYPE_RDP": "syscall",
+ "syscall.ETHERTYPE_RETIX": "syscall",
+ "syscall.ETHERTYPE_REVARP": "syscall",
+ "syscall.ETHERTYPE_SCA": "syscall",
+ "syscall.ETHERTYPE_SECTRA": "syscall",
+ "syscall.ETHERTYPE_SECUREDATA": "syscall",
+ "syscall.ETHERTYPE_SGITW": "syscall",
+ "syscall.ETHERTYPE_SG_BOUNCE": "syscall",
+ "syscall.ETHERTYPE_SG_DIAG": "syscall",
+ "syscall.ETHERTYPE_SG_NETGAMES": "syscall",
+ "syscall.ETHERTYPE_SG_RESV": "syscall",
+ "syscall.ETHERTYPE_SIMNET": "syscall",
+ "syscall.ETHERTYPE_SLOW": "syscall",
+ "syscall.ETHERTYPE_SLOWPROTOCOLS": "syscall",
+ "syscall.ETHERTYPE_SNA": "syscall",
+ "syscall.ETHERTYPE_SNMP": "syscall",
+ "syscall.ETHERTYPE_SONIX": "syscall",
+ "syscall.ETHERTYPE_SPIDER": "syscall",
+ "syscall.ETHERTYPE_SPRITE": "syscall",
+ "syscall.ETHERTYPE_STP": "syscall",
+ "syscall.ETHERTYPE_TALARIS": "syscall",
+ "syscall.ETHERTYPE_TALARISMC": "syscall",
+ "syscall.ETHERTYPE_TCPCOMP": "syscall",
+ "syscall.ETHERTYPE_TCPSM": "syscall",
+ "syscall.ETHERTYPE_TEC": "syscall",
+ "syscall.ETHERTYPE_TIGAN": "syscall",
+ "syscall.ETHERTYPE_TRAIL": "syscall",
+ "syscall.ETHERTYPE_TRANSETHER": "syscall",
+ "syscall.ETHERTYPE_TYMSHARE": "syscall",
+ "syscall.ETHERTYPE_UBBST": "syscall",
+ "syscall.ETHERTYPE_UBDEBUG": "syscall",
+ "syscall.ETHERTYPE_UBDIAGLOOP": "syscall",
+ "syscall.ETHERTYPE_UBDL": "syscall",
+ "syscall.ETHERTYPE_UBNIU": "syscall",
+ "syscall.ETHERTYPE_UBNMC": "syscall",
+ "syscall.ETHERTYPE_VALID": "syscall",
+ "syscall.ETHERTYPE_VARIAN": "syscall",
+ "syscall.ETHERTYPE_VAXELN": "syscall",
+ "syscall.ETHERTYPE_VEECO": "syscall",
+ "syscall.ETHERTYPE_VEXP": "syscall",
+ "syscall.ETHERTYPE_VGLAB": "syscall",
+ "syscall.ETHERTYPE_VINES": "syscall",
+ "syscall.ETHERTYPE_VINESECHO": "syscall",
+ "syscall.ETHERTYPE_VINESLOOP": "syscall",
+ "syscall.ETHERTYPE_VITAL": "syscall",
+ "syscall.ETHERTYPE_VLAN": "syscall",
+ "syscall.ETHERTYPE_VLTLMAN": "syscall",
+ "syscall.ETHERTYPE_VPROD": "syscall",
+ "syscall.ETHERTYPE_VURESERVED": "syscall",
+ "syscall.ETHERTYPE_WATERLOO": "syscall",
+ "syscall.ETHERTYPE_WELLFLEET": "syscall",
+ "syscall.ETHERTYPE_X25": "syscall",
+ "syscall.ETHERTYPE_X75": "syscall",
+ "syscall.ETHERTYPE_XNSSM": "syscall",
+ "syscall.ETHERTYPE_XTP": "syscall",
+ "syscall.ETHER_ADDR_LEN": "syscall",
+ "syscall.ETHER_ALIGN": "syscall",
+ "syscall.ETHER_CRC_LEN": "syscall",
+ "syscall.ETHER_CRC_POLY_BE": "syscall",
+ "syscall.ETHER_CRC_POLY_LE": "syscall",
+ "syscall.ETHER_HDR_LEN": "syscall",
+ "syscall.ETHER_MAX_DIX_LEN": "syscall",
+ "syscall.ETHER_MAX_LEN": "syscall",
+ "syscall.ETHER_MAX_LEN_JUMBO": "syscall",
+ "syscall.ETHER_MIN_LEN": "syscall",
+ "syscall.ETHER_PPPOE_ENCAP_LEN": "syscall",
+ "syscall.ETHER_TYPE_LEN": "syscall",
+ "syscall.ETHER_VLAN_ENCAP_LEN": "syscall",
+ "syscall.ETH_P_1588": "syscall",
+ "syscall.ETH_P_8021Q": "syscall",
+ "syscall.ETH_P_802_2": "syscall",
+ "syscall.ETH_P_802_3": "syscall",
+ "syscall.ETH_P_AARP": "syscall",
+ "syscall.ETH_P_ALL": "syscall",
+ "syscall.ETH_P_AOE": "syscall",
+ "syscall.ETH_P_ARCNET": "syscall",
+ "syscall.ETH_P_ARP": "syscall",
+ "syscall.ETH_P_ATALK": "syscall",
+ "syscall.ETH_P_ATMFATE": "syscall",
+ "syscall.ETH_P_ATMMPOA": "syscall",
+ "syscall.ETH_P_AX25": "syscall",
+ "syscall.ETH_P_BPQ": "syscall",
+ "syscall.ETH_P_CAIF": "syscall",
+ "syscall.ETH_P_CAN": "syscall",
+ "syscall.ETH_P_CONTROL": "syscall",
+ "syscall.ETH_P_CUST": "syscall",
+ "syscall.ETH_P_DDCMP": "syscall",
+ "syscall.ETH_P_DEC": "syscall",
+ "syscall.ETH_P_DIAG": "syscall",
+ "syscall.ETH_P_DNA_DL": "syscall",
+ "syscall.ETH_P_DNA_RC": "syscall",
+ "syscall.ETH_P_DNA_RT": "syscall",
+ "syscall.ETH_P_DSA": "syscall",
+ "syscall.ETH_P_ECONET": "syscall",
+ "syscall.ETH_P_EDSA": "syscall",
+ "syscall.ETH_P_FCOE": "syscall",
+ "syscall.ETH_P_FIP": "syscall",
+ "syscall.ETH_P_HDLC": "syscall",
+ "syscall.ETH_P_IEEE802154": "syscall",
+ "syscall.ETH_P_IEEEPUP": "syscall",
+ "syscall.ETH_P_IEEEPUPAT": "syscall",
+ "syscall.ETH_P_IP": "syscall",
+ "syscall.ETH_P_IPV6": "syscall",
+ "syscall.ETH_P_IPX": "syscall",
+ "syscall.ETH_P_IRDA": "syscall",
+ "syscall.ETH_P_LAT": "syscall",
+ "syscall.ETH_P_LINK_CTL": "syscall",
+ "syscall.ETH_P_LOCALTALK": "syscall",
+ "syscall.ETH_P_LOOP": "syscall",
+ "syscall.ETH_P_MOBITEX": "syscall",
+ "syscall.ETH_P_MPLS_MC": "syscall",
+ "syscall.ETH_P_MPLS_UC": "syscall",
+ "syscall.ETH_P_PAE": "syscall",
+ "syscall.ETH_P_PAUSE": "syscall",
+ "syscall.ETH_P_PHONET": "syscall",
+ "syscall.ETH_P_PPPTALK": "syscall",
+ "syscall.ETH_P_PPP_DISC": "syscall",
+ "syscall.ETH_P_PPP_MP": "syscall",
+ "syscall.ETH_P_PPP_SES": "syscall",
+ "syscall.ETH_P_PUP": "syscall",
+ "syscall.ETH_P_PUPAT": "syscall",
+ "syscall.ETH_P_RARP": "syscall",
+ "syscall.ETH_P_SCA": "syscall",
+ "syscall.ETH_P_SLOW": "syscall",
+ "syscall.ETH_P_SNAP": "syscall",
+ "syscall.ETH_P_TEB": "syscall",
+ "syscall.ETH_P_TIPC": "syscall",
+ "syscall.ETH_P_TRAILER": "syscall",
+ "syscall.ETH_P_TR_802_2": "syscall",
+ "syscall.ETH_P_WAN_PPP": "syscall",
+ "syscall.ETH_P_WCCP": "syscall",
+ "syscall.ETH_P_X25": "syscall",
+ "syscall.ETIME": "syscall",
+ "syscall.ETIMEDOUT": "syscall",
+ "syscall.ETOOMANYREFS": "syscall",
+ "syscall.ETXTBSY": "syscall",
+ "syscall.EUCLEAN": "syscall",
+ "syscall.EUNATCH": "syscall",
+ "syscall.EUSERS": "syscall",
+ "syscall.EVFILT_AIO": "syscall",
+ "syscall.EVFILT_FS": "syscall",
+ "syscall.EVFILT_LIO": "syscall",
+ "syscall.EVFILT_MACHPORT": "syscall",
+ "syscall.EVFILT_PROC": "syscall",
+ "syscall.EVFILT_READ": "syscall",
+ "syscall.EVFILT_SIGNAL": "syscall",
+ "syscall.EVFILT_SYSCOUNT": "syscall",
+ "syscall.EVFILT_THREADMARKER": "syscall",
+ "syscall.EVFILT_TIMER": "syscall",
+ "syscall.EVFILT_USER": "syscall",
+ "syscall.EVFILT_VM": "syscall",
+ "syscall.EVFILT_VNODE": "syscall",
+ "syscall.EVFILT_WRITE": "syscall",
+ "syscall.EV_ADD": "syscall",
+ "syscall.EV_CLEAR": "syscall",
+ "syscall.EV_DELETE": "syscall",
+ "syscall.EV_DISABLE": "syscall",
+ "syscall.EV_DISPATCH": "syscall",
+ "syscall.EV_ENABLE": "syscall",
+ "syscall.EV_EOF": "syscall",
+ "syscall.EV_ERROR": "syscall",
+ "syscall.EV_FLAG0": "syscall",
+ "syscall.EV_FLAG1": "syscall",
+ "syscall.EV_ONESHOT": "syscall",
+ "syscall.EV_OOBAND": "syscall",
+ "syscall.EV_POLL": "syscall",
+ "syscall.EV_RECEIPT": "syscall",
+ "syscall.EV_SYSFLAGS": "syscall",
+ "syscall.EWINDOWS": "syscall",
+ "syscall.EWOULDBLOCK": "syscall",
+ "syscall.EXDEV": "syscall",
+ "syscall.EXFULL": "syscall",
+ "syscall.EXTA": "syscall",
+ "syscall.EXTB": "syscall",
+ "syscall.EXTPROC": "syscall",
+ "syscall.Environ": "syscall",
+ "syscall.EpollCreate": "syscall",
+ "syscall.EpollCreate1": "syscall",
+ "syscall.EpollCtl": "syscall",
+ "syscall.EpollEvent": "syscall",
+ "syscall.EpollWait": "syscall",
+ "syscall.Errno": "syscall",
+ "syscall.EscapeArg": "syscall",
+ "syscall.Exchangedata": "syscall",
+ "syscall.Exec": "syscall",
+ "syscall.Exit": "syscall",
+ "syscall.ExitProcess": "syscall",
+ "syscall.FD_CLOEXEC": "syscall",
+ "syscall.FD_SETSIZE": "syscall",
+ "syscall.FILE_ACTION_ADDED": "syscall",
+ "syscall.FILE_ACTION_MODIFIED": "syscall",
+ "syscall.FILE_ACTION_REMOVED": "syscall",
+ "syscall.FILE_ACTION_RENAMED_NEW_NAME": "syscall",
+ "syscall.FILE_ACTION_RENAMED_OLD_NAME": "syscall",
+ "syscall.FILE_APPEND_DATA": "syscall",
+ "syscall.FILE_ATTRIBUTE_ARCHIVE": "syscall",
+ "syscall.FILE_ATTRIBUTE_DIRECTORY": "syscall",
+ "syscall.FILE_ATTRIBUTE_HIDDEN": "syscall",
+ "syscall.FILE_ATTRIBUTE_NORMAL": "syscall",
+ "syscall.FILE_ATTRIBUTE_READONLY": "syscall",
+ "syscall.FILE_ATTRIBUTE_SYSTEM": "syscall",
+ "syscall.FILE_BEGIN": "syscall",
+ "syscall.FILE_CURRENT": "syscall",
+ "syscall.FILE_END": "syscall",
+ "syscall.FILE_FLAG_BACKUP_SEMANTICS": "syscall",
+ "syscall.FILE_FLAG_OVERLAPPED": "syscall",
+ "syscall.FILE_LIST_DIRECTORY": "syscall",
+ "syscall.FILE_MAP_COPY": "syscall",
+ "syscall.FILE_MAP_EXECUTE": "syscall",
+ "syscall.FILE_MAP_READ": "syscall",
+ "syscall.FILE_MAP_WRITE": "syscall",
+ "syscall.FILE_NOTIFY_CHANGE_ATTRIBUTES": "syscall",
+ "syscall.FILE_NOTIFY_CHANGE_CREATION": "syscall",
+ "syscall.FILE_NOTIFY_CHANGE_DIR_NAME": "syscall",
+ "syscall.FILE_NOTIFY_CHANGE_FILE_NAME": "syscall",
+ "syscall.FILE_NOTIFY_CHANGE_LAST_ACCESS": "syscall",
+ "syscall.FILE_NOTIFY_CHANGE_LAST_WRITE": "syscall",
+ "syscall.FILE_NOTIFY_CHANGE_SIZE": "syscall",
+ "syscall.FILE_SHARE_DELETE": "syscall",
+ "syscall.FILE_SHARE_READ": "syscall",
+ "syscall.FILE_SHARE_WRITE": "syscall",
+ "syscall.FILE_SKIP_COMPLETION_PORT_ON_SUCCESS": "syscall",
+ "syscall.FILE_SKIP_SET_EVENT_ON_HANDLE": "syscall",
+ "syscall.FILE_TYPE_CHAR": "syscall",
+ "syscall.FILE_TYPE_DISK": "syscall",
+ "syscall.FILE_TYPE_PIPE": "syscall",
+ "syscall.FILE_TYPE_REMOTE": "syscall",
+ "syscall.FILE_TYPE_UNKNOWN": "syscall",
+ "syscall.FILE_WRITE_ATTRIBUTES": "syscall",
+ "syscall.FLUSHO": "syscall",
+ "syscall.FORMAT_MESSAGE_ALLOCATE_BUFFER": "syscall",
+ "syscall.FORMAT_MESSAGE_ARGUMENT_ARRAY": "syscall",
+ "syscall.FORMAT_MESSAGE_FROM_HMODULE": "syscall",
+ "syscall.FORMAT_MESSAGE_FROM_STRING": "syscall",
+ "syscall.FORMAT_MESSAGE_FROM_SYSTEM": "syscall",
+ "syscall.FORMAT_MESSAGE_IGNORE_INSERTS": "syscall",
+ "syscall.FORMAT_MESSAGE_MAX_WIDTH_MASK": "syscall",
+ "syscall.F_ADDFILESIGS": "syscall",
+ "syscall.F_ADDSIGS": "syscall",
+ "syscall.F_ALLOCATEALL": "syscall",
+ "syscall.F_ALLOCATECONTIG": "syscall",
+ "syscall.F_CANCEL": "syscall",
+ "syscall.F_CHKCLEAN": "syscall",
+ "syscall.F_CLOSEM": "syscall",
+ "syscall.F_DUP2FD": "syscall",
+ "syscall.F_DUP2FD_CLOEXEC": "syscall",
+ "syscall.F_DUPFD": "syscall",
+ "syscall.F_DUPFD_CLOEXEC": "syscall",
+ "syscall.F_EXLCK": "syscall",
+ "syscall.F_FLUSH_DATA": "syscall",
+ "syscall.F_FREEZE_FS": "syscall",
+ "syscall.F_FSCTL": "syscall",
+ "syscall.F_FSDIRMASK": "syscall",
+ "syscall.F_FSIN": "syscall",
+ "syscall.F_FSINOUT": "syscall",
+ "syscall.F_FSOUT": "syscall",
+ "syscall.F_FSPRIV": "syscall",
+ "syscall.F_FSVOID": "syscall",
+ "syscall.F_FULLFSYNC": "syscall",
+ "syscall.F_GETFD": "syscall",
+ "syscall.F_GETFL": "syscall",
+ "syscall.F_GETLEASE": "syscall",
+ "syscall.F_GETLK": "syscall",
+ "syscall.F_GETLK64": "syscall",
+ "syscall.F_GETLKPID": "syscall",
+ "syscall.F_GETNOSIGPIPE": "syscall",
+ "syscall.F_GETOWN": "syscall",
+ "syscall.F_GETOWN_EX": "syscall",
+ "syscall.F_GETPATH": "syscall",
+ "syscall.F_GETPATH_MTMINFO": "syscall",
+ "syscall.F_GETPIPE_SZ": "syscall",
+ "syscall.F_GETPROTECTIONCLASS": "syscall",
+ "syscall.F_GETSIG": "syscall",
+ "syscall.F_GLOBAL_NOCACHE": "syscall",
+ "syscall.F_LOCK": "syscall",
+ "syscall.F_LOG2PHYS": "syscall",
+ "syscall.F_LOG2PHYS_EXT": "syscall",
+ "syscall.F_MARKDEPENDENCY": "syscall",
+ "syscall.F_MAXFD": "syscall",
+ "syscall.F_NOCACHE": "syscall",
+ "syscall.F_NODIRECT": "syscall",
+ "syscall.F_NOTIFY": "syscall",
+ "syscall.F_OGETLK": "syscall",
+ "syscall.F_OK": "syscall",
+ "syscall.F_OSETLK": "syscall",
+ "syscall.F_OSETLKW": "syscall",
+ "syscall.F_PARAM_MASK": "syscall",
+ "syscall.F_PARAM_MAX": "syscall",
+ "syscall.F_PATHPKG_CHECK": "syscall",
+ "syscall.F_PEOFPOSMODE": "syscall",
+ "syscall.F_PREALLOCATE": "syscall",
+ "syscall.F_RDADVISE": "syscall",
+ "syscall.F_RDAHEAD": "syscall",
+ "syscall.F_RDLCK": "syscall",
+ "syscall.F_READAHEAD": "syscall",
+ "syscall.F_READBOOTSTRAP": "syscall",
+ "syscall.F_SETBACKINGSTORE": "syscall",
+ "syscall.F_SETFD": "syscall",
+ "syscall.F_SETFL": "syscall",
+ "syscall.F_SETLEASE": "syscall",
+ "syscall.F_SETLK": "syscall",
+ "syscall.F_SETLK64": "syscall",
+ "syscall.F_SETLKW": "syscall",
+ "syscall.F_SETLKW64": "syscall",
+ "syscall.F_SETLK_REMOTE": "syscall",
+ "syscall.F_SETNOSIGPIPE": "syscall",
+ "syscall.F_SETOWN": "syscall",
+ "syscall.F_SETOWN_EX": "syscall",
+ "syscall.F_SETPIPE_SZ": "syscall",
+ "syscall.F_SETPROTECTIONCLASS": "syscall",
+ "syscall.F_SETSIG": "syscall",
+ "syscall.F_SETSIZE": "syscall",
+ "syscall.F_SHLCK": "syscall",
+ "syscall.F_TEST": "syscall",
+ "syscall.F_THAW_FS": "syscall",
+ "syscall.F_TLOCK": "syscall",
+ "syscall.F_ULOCK": "syscall",
+ "syscall.F_UNLCK": "syscall",
+ "syscall.F_UNLCKSYS": "syscall",
+ "syscall.F_VOLPOSMODE": "syscall",
+ "syscall.F_WRITEBOOTSTRAP": "syscall",
+ "syscall.F_WRLCK": "syscall",
+ "syscall.Faccessat": "syscall",
+ "syscall.Fallocate": "syscall",
+ "syscall.Fbootstraptransfer_t": "syscall",
+ "syscall.Fchdir": "syscall",
+ "syscall.Fchflags": "syscall",
+ "syscall.Fchmod": "syscall",
+ "syscall.Fchmodat": "syscall",
+ "syscall.Fchown": "syscall",
+ "syscall.Fchownat": "syscall",
+ "syscall.FdSet": "syscall",
+ "syscall.Fdatasync": "syscall",
+ "syscall.FileNotifyInformation": "syscall",
+ "syscall.Filetime": "syscall",
+ "syscall.FindClose": "syscall",
+ "syscall.FindFirstFile": "syscall",
+ "syscall.FindNextFile": "syscall",
+ "syscall.Flock": "syscall",
+ "syscall.Flock_t": "syscall",
+ "syscall.FlushBpf": "syscall",
+ "syscall.FlushFileBuffers": "syscall",
+ "syscall.FlushViewOfFile": "syscall",
+ "syscall.ForkExec": "syscall",
+ "syscall.ForkLock": "syscall",
+ "syscall.FormatMessage": "syscall",
+ "syscall.Fpathconf": "syscall",
+ "syscall.FreeAddrInfoW": "syscall",
+ "syscall.FreeEnvironmentStrings": "syscall",
+ "syscall.FreeLibrary": "syscall",
+ "syscall.Fsid": "syscall",
+ "syscall.Fstat": "syscall",
+ "syscall.Fstatfs": "syscall",
+ "syscall.Fstore_t": "syscall",
+ "syscall.Fsync": "syscall",
+ "syscall.Ftruncate": "syscall",
+ "syscall.Futimes": "syscall",
+ "syscall.Futimesat": "syscall",
+ "syscall.GENERIC_ALL": "syscall",
+ "syscall.GENERIC_EXECUTE": "syscall",
+ "syscall.GENERIC_READ": "syscall",
+ "syscall.GENERIC_WRITE": "syscall",
+ "syscall.GUID": "syscall",
+ "syscall.GetAcceptExSockaddrs": "syscall",
+ "syscall.GetAdaptersInfo": "syscall",
+ "syscall.GetAddrInfoW": "syscall",
+ "syscall.GetCommandLine": "syscall",
+ "syscall.GetComputerName": "syscall",
+ "syscall.GetConsoleMode": "syscall",
+ "syscall.GetCurrentDirectory": "syscall",
+ "syscall.GetCurrentProcess": "syscall",
+ "syscall.GetEnvironmentStrings": "syscall",
+ "syscall.GetEnvironmentVariable": "syscall",
+ "syscall.GetExitCodeProcess": "syscall",
+ "syscall.GetFileAttributes": "syscall",
+ "syscall.GetFileAttributesEx": "syscall",
+ "syscall.GetFileExInfoStandard": "syscall",
+ "syscall.GetFileExMaxInfoLevel": "syscall",
+ "syscall.GetFileInformationByHandle": "syscall",
+ "syscall.GetFileType": "syscall",
+ "syscall.GetFullPathName": "syscall",
+ "syscall.GetHostByName": "syscall",
+ "syscall.GetIfEntry": "syscall",
+ "syscall.GetLastError": "syscall",
+ "syscall.GetLengthSid": "syscall",
+ "syscall.GetLongPathName": "syscall",
+ "syscall.GetProcAddress": "syscall",
+ "syscall.GetProcessTimes": "syscall",
+ "syscall.GetProtoByName": "syscall",
+ "syscall.GetQueuedCompletionStatus": "syscall",
+ "syscall.GetServByName": "syscall",
+ "syscall.GetShortPathName": "syscall",
+ "syscall.GetStartupInfo": "syscall",
+ "syscall.GetStdHandle": "syscall",
+ "syscall.GetSystemTimeAsFileTime": "syscall",
+ "syscall.GetTempPath": "syscall",
+ "syscall.GetTimeZoneInformation": "syscall",
+ "syscall.GetTokenInformation": "syscall",
+ "syscall.GetUserNameEx": "syscall",
+ "syscall.GetUserProfileDirectory": "syscall",
+ "syscall.GetVersion": "syscall",
+ "syscall.Getcwd": "syscall",
+ "syscall.Getdents": "syscall",
+ "syscall.Getdirentries": "syscall",
+ "syscall.Getdtablesize": "syscall",
+ "syscall.Getegid": "syscall",
+ "syscall.Getenv": "syscall",
+ "syscall.Geteuid": "syscall",
+ "syscall.Getfsstat": "syscall",
+ "syscall.Getgid": "syscall",
+ "syscall.Getgroups": "syscall",
+ "syscall.Getpagesize": "syscall",
+ "syscall.Getpeername": "syscall",
+ "syscall.Getpgid": "syscall",
+ "syscall.Getpgrp": "syscall",
+ "syscall.Getpid": "syscall",
+ "syscall.Getppid": "syscall",
+ "syscall.Getpriority": "syscall",
+ "syscall.Getrlimit": "syscall",
+ "syscall.Getrusage": "syscall",
+ "syscall.Getsid": "syscall",
+ "syscall.Getsockname": "syscall",
+ "syscall.Getsockopt": "syscall",
+ "syscall.GetsockoptByte": "syscall",
+ "syscall.GetsockoptICMPv6Filter": "syscall",
+ "syscall.GetsockoptIPMreq": "syscall",
+ "syscall.GetsockoptIPMreqn": "syscall",
+ "syscall.GetsockoptIPv6MTUInfo": "syscall",
+ "syscall.GetsockoptIPv6Mreq": "syscall",
+ "syscall.GetsockoptInet4Addr": "syscall",
+ "syscall.GetsockoptInt": "syscall",
+ "syscall.GetsockoptUcred": "syscall",
+ "syscall.Gettid": "syscall",
+ "syscall.Gettimeofday": "syscall",
+ "syscall.Getuid": "syscall",
+ "syscall.Getwd": "syscall",
+ "syscall.Getxattr": "syscall",
+ "syscall.HANDLE_FLAG_INHERIT": "syscall",
+ "syscall.HKEY_CLASSES_ROOT": "syscall",
+ "syscall.HKEY_CURRENT_CONFIG": "syscall",
+ "syscall.HKEY_CURRENT_USER": "syscall",
+ "syscall.HKEY_DYN_DATA": "syscall",
+ "syscall.HKEY_LOCAL_MACHINE": "syscall",
+ "syscall.HKEY_PERFORMANCE_DATA": "syscall",
+ "syscall.HKEY_USERS": "syscall",
+ "syscall.HUPCL": "syscall",
+ "syscall.Handle": "syscall",
+ "syscall.Hostent": "syscall",
+ "syscall.ICANON": "syscall",
+ "syscall.ICMP6_FILTER": "syscall",
+ "syscall.ICMPV6_FILTER": "syscall",
+ "syscall.ICMPv6Filter": "syscall",
+ "syscall.ICRNL": "syscall",
+ "syscall.IEXTEN": "syscall",
+ "syscall.IFAN_ARRIVAL": "syscall",
+ "syscall.IFAN_DEPARTURE": "syscall",
+ "syscall.IFA_ADDRESS": "syscall",
+ "syscall.IFA_ANYCAST": "syscall",
+ "syscall.IFA_BROADCAST": "syscall",
+ "syscall.IFA_CACHEINFO": "syscall",
+ "syscall.IFA_F_DADFAILED": "syscall",
+ "syscall.IFA_F_DEPRECATED": "syscall",
+ "syscall.IFA_F_HOMEADDRESS": "syscall",
+ "syscall.IFA_F_NODAD": "syscall",
+ "syscall.IFA_F_OPTIMISTIC": "syscall",
+ "syscall.IFA_F_PERMANENT": "syscall",
+ "syscall.IFA_F_SECONDARY": "syscall",
+ "syscall.IFA_F_TEMPORARY": "syscall",
+ "syscall.IFA_F_TENTATIVE": "syscall",
+ "syscall.IFA_LABEL": "syscall",
+ "syscall.IFA_LOCAL": "syscall",
+ "syscall.IFA_MAX": "syscall",
+ "syscall.IFA_MULTICAST": "syscall",
+ "syscall.IFA_ROUTE": "syscall",
+ "syscall.IFA_UNSPEC": "syscall",
+ "syscall.IFF_ALLMULTI": "syscall",
+ "syscall.IFF_ALTPHYS": "syscall",
+ "syscall.IFF_AUTOMEDIA": "syscall",
+ "syscall.IFF_BROADCAST": "syscall",
+ "syscall.IFF_CANTCHANGE": "syscall",
+ "syscall.IFF_CANTCONFIG": "syscall",
+ "syscall.IFF_DEBUG": "syscall",
+ "syscall.IFF_DRV_OACTIVE": "syscall",
+ "syscall.IFF_DRV_RUNNING": "syscall",
+ "syscall.IFF_DYING": "syscall",
+ "syscall.IFF_DYNAMIC": "syscall",
+ "syscall.IFF_LINK0": "syscall",
+ "syscall.IFF_LINK1": "syscall",
+ "syscall.IFF_LINK2": "syscall",
+ "syscall.IFF_LOOPBACK": "syscall",
+ "syscall.IFF_MASTER": "syscall",
+ "syscall.IFF_MONITOR": "syscall",
+ "syscall.IFF_MULTICAST": "syscall",
+ "syscall.IFF_NOARP": "syscall",
+ "syscall.IFF_NOTRAILERS": "syscall",
+ "syscall.IFF_NO_PI": "syscall",
+ "syscall.IFF_OACTIVE": "syscall",
+ "syscall.IFF_ONE_QUEUE": "syscall",
+ "syscall.IFF_POINTOPOINT": "syscall",
+ "syscall.IFF_POINTTOPOINT": "syscall",
+ "syscall.IFF_PORTSEL": "syscall",
+ "syscall.IFF_PPROMISC": "syscall",
+ "syscall.IFF_PROMISC": "syscall",
+ "syscall.IFF_RENAMING": "syscall",
+ "syscall.IFF_RUNNING": "syscall",
+ "syscall.IFF_SIMPLEX": "syscall",
+ "syscall.IFF_SLAVE": "syscall",
+ "syscall.IFF_SMART": "syscall",
+ "syscall.IFF_STATICARP": "syscall",
+ "syscall.IFF_TAP": "syscall",
+ "syscall.IFF_TUN": "syscall",
+ "syscall.IFF_TUN_EXCL": "syscall",
+ "syscall.IFF_UP": "syscall",
+ "syscall.IFF_VNET_HDR": "syscall",
+ "syscall.IFLA_ADDRESS": "syscall",
+ "syscall.IFLA_BROADCAST": "syscall",
+ "syscall.IFLA_COST": "syscall",
+ "syscall.IFLA_IFALIAS": "syscall",
+ "syscall.IFLA_IFNAME": "syscall",
+ "syscall.IFLA_LINK": "syscall",
+ "syscall.IFLA_LINKINFO": "syscall",
+ "syscall.IFLA_LINKMODE": "syscall",
+ "syscall.IFLA_MAP": "syscall",
+ "syscall.IFLA_MASTER": "syscall",
+ "syscall.IFLA_MAX": "syscall",
+ "syscall.IFLA_MTU": "syscall",
+ "syscall.IFLA_NET_NS_PID": "syscall",
+ "syscall.IFLA_OPERSTATE": "syscall",
+ "syscall.IFLA_PRIORITY": "syscall",
+ "syscall.IFLA_PROTINFO": "syscall",
+ "syscall.IFLA_QDISC": "syscall",
+ "syscall.IFLA_STATS": "syscall",
+ "syscall.IFLA_TXQLEN": "syscall",
+ "syscall.IFLA_UNSPEC": "syscall",
+ "syscall.IFLA_WEIGHT": "syscall",
+ "syscall.IFLA_WIRELESS": "syscall",
+ "syscall.IFNAMSIZ": "syscall",
+ "syscall.IFT_1822": "syscall",
+ "syscall.IFT_A12MPPSWITCH": "syscall",
+ "syscall.IFT_AAL2": "syscall",
+ "syscall.IFT_AAL5": "syscall",
+ "syscall.IFT_ADSL": "syscall",
+ "syscall.IFT_AFLANE8023": "syscall",
+ "syscall.IFT_AFLANE8025": "syscall",
+ "syscall.IFT_ARAP": "syscall",
+ "syscall.IFT_ARCNET": "syscall",
+ "syscall.IFT_ARCNETPLUS": "syscall",
+ "syscall.IFT_ASYNC": "syscall",
+ "syscall.IFT_ATM": "syscall",
+ "syscall.IFT_ATMDXI": "syscall",
+ "syscall.IFT_ATMFUNI": "syscall",
+ "syscall.IFT_ATMIMA": "syscall",
+ "syscall.IFT_ATMLOGICAL": "syscall",
+ "syscall.IFT_ATMRADIO": "syscall",
+ "syscall.IFT_ATMSUBINTERFACE": "syscall",
+ "syscall.IFT_ATMVCIENDPT": "syscall",
+ "syscall.IFT_ATMVIRTUAL": "syscall",
+ "syscall.IFT_BGPPOLICYACCOUNTING": "syscall",
+ "syscall.IFT_BLUETOOTH": "syscall",
+ "syscall.IFT_BRIDGE": "syscall",
+ "syscall.IFT_BSC": "syscall",
+ "syscall.IFT_CARP": "syscall",
+ "syscall.IFT_CCTEMUL": "syscall",
+ "syscall.IFT_CELLULAR": "syscall",
+ "syscall.IFT_CEPT": "syscall",
+ "syscall.IFT_CES": "syscall",
+ "syscall.IFT_CHANNEL": "syscall",
+ "syscall.IFT_CNR": "syscall",
+ "syscall.IFT_COFFEE": "syscall",
+ "syscall.IFT_COMPOSITELINK": "syscall",
+ "syscall.IFT_DCN": "syscall",
+ "syscall.IFT_DIGITALPOWERLINE": "syscall",
+ "syscall.IFT_DIGITALWRAPPEROVERHEADCHANNEL": "syscall",
+ "syscall.IFT_DLSW": "syscall",
+ "syscall.IFT_DOCSCABLEDOWNSTREAM": "syscall",
+ "syscall.IFT_DOCSCABLEMACLAYER": "syscall",
+ "syscall.IFT_DOCSCABLEUPSTREAM": "syscall",
+ "syscall.IFT_DOCSCABLEUPSTREAMCHANNEL": "syscall",
+ "syscall.IFT_DS0": "syscall",
+ "syscall.IFT_DS0BUNDLE": "syscall",
+ "syscall.IFT_DS1FDL": "syscall",
+ "syscall.IFT_DS3": "syscall",
+ "syscall.IFT_DTM": "syscall",
+ "syscall.IFT_DUMMY": "syscall",
+ "syscall.IFT_DVBASILN": "syscall",
+ "syscall.IFT_DVBASIOUT": "syscall",
+ "syscall.IFT_DVBRCCDOWNSTREAM": "syscall",
+ "syscall.IFT_DVBRCCMACLAYER": "syscall",
+ "syscall.IFT_DVBRCCUPSTREAM": "syscall",
+ "syscall.IFT_ECONET": "syscall",
+ "syscall.IFT_ENC": "syscall",
+ "syscall.IFT_EON": "syscall",
+ "syscall.IFT_EPLRS": "syscall",
+ "syscall.IFT_ESCON": "syscall",
+ "syscall.IFT_ETHER": "syscall",
+ "syscall.IFT_FAITH": "syscall",
+ "syscall.IFT_FAST": "syscall",
+ "syscall.IFT_FASTETHER": "syscall",
+ "syscall.IFT_FASTETHERFX": "syscall",
+ "syscall.IFT_FDDI": "syscall",
+ "syscall.IFT_FIBRECHANNEL": "syscall",
+ "syscall.IFT_FRAMERELAYINTERCONNECT": "syscall",
+ "syscall.IFT_FRAMERELAYMPI": "syscall",
+ "syscall.IFT_FRDLCIENDPT": "syscall",
+ "syscall.IFT_FRELAY": "syscall",
+ "syscall.IFT_FRELAYDCE": "syscall",
+ "syscall.IFT_FRF16MFRBUNDLE": "syscall",
+ "syscall.IFT_FRFORWARD": "syscall",
+ "syscall.IFT_G703AT2MB": "syscall",
+ "syscall.IFT_G703AT64K": "syscall",
+ "syscall.IFT_GIF": "syscall",
+ "syscall.IFT_GIGABITETHERNET": "syscall",
+ "syscall.IFT_GR303IDT": "syscall",
+ "syscall.IFT_GR303RDT": "syscall",
+ "syscall.IFT_H323GATEKEEPER": "syscall",
+ "syscall.IFT_H323PROXY": "syscall",
+ "syscall.IFT_HDH1822": "syscall",
+ "syscall.IFT_HDLC": "syscall",
+ "syscall.IFT_HDSL2": "syscall",
+ "syscall.IFT_HIPERLAN2": "syscall",
+ "syscall.IFT_HIPPI": "syscall",
+ "syscall.IFT_HIPPIINTERFACE": "syscall",
+ "syscall.IFT_HOSTPAD": "syscall",
+ "syscall.IFT_HSSI": "syscall",
+ "syscall.IFT_HY": "syscall",
+ "syscall.IFT_IBM370PARCHAN": "syscall",
+ "syscall.IFT_IDSL": "syscall",
+ "syscall.IFT_IEEE1394": "syscall",
+ "syscall.IFT_IEEE80211": "syscall",
+ "syscall.IFT_IEEE80212": "syscall",
+ "syscall.IFT_IEEE8023ADLAG": "syscall",
+ "syscall.IFT_IFGSN": "syscall",
+ "syscall.IFT_IMT": "syscall",
+ "syscall.IFT_INFINIBAND": "syscall",
+ "syscall.IFT_INTERLEAVE": "syscall",
+ "syscall.IFT_IP": "syscall",
+ "syscall.IFT_IPFORWARD": "syscall",
+ "syscall.IFT_IPOVERATM": "syscall",
+ "syscall.IFT_IPOVERCDLC": "syscall",
+ "syscall.IFT_IPOVERCLAW": "syscall",
+ "syscall.IFT_IPSWITCH": "syscall",
+ "syscall.IFT_IPXIP": "syscall",
+ "syscall.IFT_ISDN": "syscall",
+ "syscall.IFT_ISDNBASIC": "syscall",
+ "syscall.IFT_ISDNPRIMARY": "syscall",
+ "syscall.IFT_ISDNS": "syscall",
+ "syscall.IFT_ISDNU": "syscall",
+ "syscall.IFT_ISO88022LLC": "syscall",
+ "syscall.IFT_ISO88023": "syscall",
+ "syscall.IFT_ISO88024": "syscall",
+ "syscall.IFT_ISO88025": "syscall",
+ "syscall.IFT_ISO88025CRFPINT": "syscall",
+ "syscall.IFT_ISO88025DTR": "syscall",
+ "syscall.IFT_ISO88025FIBER": "syscall",
+ "syscall.IFT_ISO88026": "syscall",
+ "syscall.IFT_ISUP": "syscall",
+ "syscall.IFT_L2VLAN": "syscall",
+ "syscall.IFT_L3IPVLAN": "syscall",
+ "syscall.IFT_L3IPXVLAN": "syscall",
+ "syscall.IFT_LAPB": "syscall",
+ "syscall.IFT_LAPD": "syscall",
+ "syscall.IFT_LAPF": "syscall",
+ "syscall.IFT_LINEGROUP": "syscall",
+ "syscall.IFT_LOCALTALK": "syscall",
+ "syscall.IFT_LOOP": "syscall",
+ "syscall.IFT_MEDIAMAILOVERIP": "syscall",
+ "syscall.IFT_MFSIGLINK": "syscall",
+ "syscall.IFT_MIOX25": "syscall",
+ "syscall.IFT_MODEM": "syscall",
+ "syscall.IFT_MPC": "syscall",
+ "syscall.IFT_MPLS": "syscall",
+ "syscall.IFT_MPLSTUNNEL": "syscall",
+ "syscall.IFT_MSDSL": "syscall",
+ "syscall.IFT_MVL": "syscall",
+ "syscall.IFT_MYRINET": "syscall",
+ "syscall.IFT_NFAS": "syscall",
+ "syscall.IFT_NSIP": "syscall",
+ "syscall.IFT_OPTICALCHANNEL": "syscall",
+ "syscall.IFT_OPTICALTRANSPORT": "syscall",
+ "syscall.IFT_OTHER": "syscall",
+ "syscall.IFT_P10": "syscall",
+ "syscall.IFT_P80": "syscall",
+ "syscall.IFT_PARA": "syscall",
+ "syscall.IFT_PDP": "syscall",
+ "syscall.IFT_PFLOG": "syscall",
+ "syscall.IFT_PFLOW": "syscall",
+ "syscall.IFT_PFSYNC": "syscall",
+ "syscall.IFT_PLC": "syscall",
+ "syscall.IFT_PON155": "syscall",
+ "syscall.IFT_PON622": "syscall",
+ "syscall.IFT_POS": "syscall",
+ "syscall.IFT_PPP": "syscall",
+ "syscall.IFT_PPPMULTILINKBUNDLE": "syscall",
+ "syscall.IFT_PROPATM": "syscall",
+ "syscall.IFT_PROPBWAP2MP": "syscall",
+ "syscall.IFT_PROPCNLS": "syscall",
+ "syscall.IFT_PROPDOCSWIRELESSDOWNSTREAM": "syscall",
+ "syscall.IFT_PROPDOCSWIRELESSMACLAYER": "syscall",
+ "syscall.IFT_PROPDOCSWIRELESSUPSTREAM": "syscall",
+ "syscall.IFT_PROPMUX": "syscall",
+ "syscall.IFT_PROPVIRTUAL": "syscall",
+ "syscall.IFT_PROPWIRELESSP2P": "syscall",
+ "syscall.IFT_PTPSERIAL": "syscall",
+ "syscall.IFT_PVC": "syscall",
+ "syscall.IFT_Q2931": "syscall",
+ "syscall.IFT_QLLC": "syscall",
+ "syscall.IFT_RADIOMAC": "syscall",
+ "syscall.IFT_RADSL": "syscall",
+ "syscall.IFT_REACHDSL": "syscall",
+ "syscall.IFT_RFC1483": "syscall",
+ "syscall.IFT_RS232": "syscall",
+ "syscall.IFT_RSRB": "syscall",
+ "syscall.IFT_SDLC": "syscall",
+ "syscall.IFT_SDSL": "syscall",
+ "syscall.IFT_SHDSL": "syscall",
+ "syscall.IFT_SIP": "syscall",
+ "syscall.IFT_SIPSIG": "syscall",
+ "syscall.IFT_SIPTG": "syscall",
+ "syscall.IFT_SLIP": "syscall",
+ "syscall.IFT_SMDSDXI": "syscall",
+ "syscall.IFT_SMDSICIP": "syscall",
+ "syscall.IFT_SONET": "syscall",
+ "syscall.IFT_SONETOVERHEADCHANNEL": "syscall",
+ "syscall.IFT_SONETPATH": "syscall",
+ "syscall.IFT_SONETVT": "syscall",
+ "syscall.IFT_SRP": "syscall",
+ "syscall.IFT_SS7SIGLINK": "syscall",
+ "syscall.IFT_STACKTOSTACK": "syscall",
+ "syscall.IFT_STARLAN": "syscall",
+ "syscall.IFT_STF": "syscall",
+ "syscall.IFT_T1": "syscall",
+ "syscall.IFT_TDLC": "syscall",
+ "syscall.IFT_TELINK": "syscall",
+ "syscall.IFT_TERMPAD": "syscall",
+ "syscall.IFT_TR008": "syscall",
+ "syscall.IFT_TRANSPHDLC": "syscall",
+ "syscall.IFT_TUNNEL": "syscall",
+ "syscall.IFT_ULTRA": "syscall",
+ "syscall.IFT_USB": "syscall",
+ "syscall.IFT_V11": "syscall",
+ "syscall.IFT_V35": "syscall",
+ "syscall.IFT_V36": "syscall",
+ "syscall.IFT_V37": "syscall",
+ "syscall.IFT_VDSL": "syscall",
+ "syscall.IFT_VIRTUALIPADDRESS": "syscall",
+ "syscall.IFT_VIRTUALTG": "syscall",
+ "syscall.IFT_VOICEDID": "syscall",
+ "syscall.IFT_VOICEEM": "syscall",
+ "syscall.IFT_VOICEEMFGD": "syscall",
+ "syscall.IFT_VOICEENCAP": "syscall",
+ "syscall.IFT_VOICEFGDEANA": "syscall",
+ "syscall.IFT_VOICEFXO": "syscall",
+ "syscall.IFT_VOICEFXS": "syscall",
+ "syscall.IFT_VOICEOVERATM": "syscall",
+ "syscall.IFT_VOICEOVERCABLE": "syscall",
+ "syscall.IFT_VOICEOVERFRAMERELAY": "syscall",
+ "syscall.IFT_VOICEOVERIP": "syscall",
+ "syscall.IFT_X213": "syscall",
+ "syscall.IFT_X25": "syscall",
+ "syscall.IFT_X25DDN": "syscall",
+ "syscall.IFT_X25HUNTGROUP": "syscall",
+ "syscall.IFT_X25MLP": "syscall",
+ "syscall.IFT_X25PLE": "syscall",
+ "syscall.IFT_XETHER": "syscall",
+ "syscall.IGNBRK": "syscall",
+ "syscall.IGNCR": "syscall",
+ "syscall.IGNORE": "syscall",
+ "syscall.IGNPAR": "syscall",
+ "syscall.IMAXBEL": "syscall",
+ "syscall.INFINITE": "syscall",
+ "syscall.INLCR": "syscall",
+ "syscall.INPCK": "syscall",
+ "syscall.INVALID_FILE_ATTRIBUTES": "syscall",
+ "syscall.IN_ACCESS": "syscall",
+ "syscall.IN_ALL_EVENTS": "syscall",
+ "syscall.IN_ATTRIB": "syscall",
+ "syscall.IN_CLASSA_HOST": "syscall",
+ "syscall.IN_CLASSA_MAX": "syscall",
+ "syscall.IN_CLASSA_NET": "syscall",
+ "syscall.IN_CLASSA_NSHIFT": "syscall",
+ "syscall.IN_CLASSB_HOST": "syscall",
+ "syscall.IN_CLASSB_MAX": "syscall",
+ "syscall.IN_CLASSB_NET": "syscall",
+ "syscall.IN_CLASSB_NSHIFT": "syscall",
+ "syscall.IN_CLASSC_HOST": "syscall",
+ "syscall.IN_CLASSC_NET": "syscall",
+ "syscall.IN_CLASSC_NSHIFT": "syscall",
+ "syscall.IN_CLASSD_HOST": "syscall",
+ "syscall.IN_CLASSD_NET": "syscall",
+ "syscall.IN_CLASSD_NSHIFT": "syscall",
+ "syscall.IN_CLOEXEC": "syscall",
+ "syscall.IN_CLOSE": "syscall",
+ "syscall.IN_CLOSE_NOWRITE": "syscall",
+ "syscall.IN_CLOSE_WRITE": "syscall",
+ "syscall.IN_CREATE": "syscall",
+ "syscall.IN_DELETE": "syscall",
+ "syscall.IN_DELETE_SELF": "syscall",
+ "syscall.IN_DONT_FOLLOW": "syscall",
+ "syscall.IN_EXCL_UNLINK": "syscall",
+ "syscall.IN_IGNORED": "syscall",
+ "syscall.IN_ISDIR": "syscall",
+ "syscall.IN_LINKLOCALNETNUM": "syscall",
+ "syscall.IN_LOOPBACKNET": "syscall",
+ "syscall.IN_MASK_ADD": "syscall",
+ "syscall.IN_MODIFY": "syscall",
+ "syscall.IN_MOVE": "syscall",
+ "syscall.IN_MOVED_FROM": "syscall",
+ "syscall.IN_MOVED_TO": "syscall",
+ "syscall.IN_MOVE_SELF": "syscall",
+ "syscall.IN_NONBLOCK": "syscall",
+ "syscall.IN_ONESHOT": "syscall",
+ "syscall.IN_ONLYDIR": "syscall",
+ "syscall.IN_OPEN": "syscall",
+ "syscall.IN_Q_OVERFLOW": "syscall",
+ "syscall.IN_RFC3021_HOST": "syscall",
+ "syscall.IN_RFC3021_MASK": "syscall",
+ "syscall.IN_RFC3021_NET": "syscall",
+ "syscall.IN_RFC3021_NSHIFT": "syscall",
+ "syscall.IN_UNMOUNT": "syscall",
+ "syscall.IOC_IN": "syscall",
+ "syscall.IOC_INOUT": "syscall",
+ "syscall.IOC_OUT": "syscall",
+ "syscall.IOC_WS2": "syscall",
+ "syscall.IPMreq": "syscall",
+ "syscall.IPMreqn": "syscall",
+ "syscall.IPPROTO_3PC": "syscall",
+ "syscall.IPPROTO_ADFS": "syscall",
+ "syscall.IPPROTO_AH": "syscall",
+ "syscall.IPPROTO_AHIP": "syscall",
+ "syscall.IPPROTO_APES": "syscall",
+ "syscall.IPPROTO_ARGUS": "syscall",
+ "syscall.IPPROTO_AX25": "syscall",
+ "syscall.IPPROTO_BHA": "syscall",
+ "syscall.IPPROTO_BLT": "syscall",
+ "syscall.IPPROTO_BRSATMON": "syscall",
+ "syscall.IPPROTO_CARP": "syscall",
+ "syscall.IPPROTO_CFTP": "syscall",
+ "syscall.IPPROTO_CHAOS": "syscall",
+ "syscall.IPPROTO_CMTP": "syscall",
+ "syscall.IPPROTO_COMP": "syscall",
+ "syscall.IPPROTO_CPHB": "syscall",
+ "syscall.IPPROTO_CPNX": "syscall",
+ "syscall.IPPROTO_DCCP": "syscall",
+ "syscall.IPPROTO_DDP": "syscall",
+ "syscall.IPPROTO_DGP": "syscall",
+ "syscall.IPPROTO_DIVERT": "syscall",
+ "syscall.IPPROTO_DONE": "syscall",
+ "syscall.IPPROTO_DSTOPTS": "syscall",
+ "syscall.IPPROTO_EGP": "syscall",
+ "syscall.IPPROTO_EMCON": "syscall",
+ "syscall.IPPROTO_ENCAP": "syscall",
+ "syscall.IPPROTO_EON": "syscall",
+ "syscall.IPPROTO_ESP": "syscall",
+ "syscall.IPPROTO_ETHERIP": "syscall",
+ "syscall.IPPROTO_FRAGMENT": "syscall",
+ "syscall.IPPROTO_GGP": "syscall",
+ "syscall.IPPROTO_GMTP": "syscall",
+ "syscall.IPPROTO_GRE": "syscall",
+ "syscall.IPPROTO_HELLO": "syscall",
+ "syscall.IPPROTO_HMP": "syscall",
+ "syscall.IPPROTO_HOPOPTS": "syscall",
+ "syscall.IPPROTO_ICMP": "syscall",
+ "syscall.IPPROTO_ICMPV6": "syscall",
+ "syscall.IPPROTO_IDP": "syscall",
+ "syscall.IPPROTO_IDPR": "syscall",
+ "syscall.IPPROTO_IDRP": "syscall",
+ "syscall.IPPROTO_IGMP": "syscall",
+ "syscall.IPPROTO_IGP": "syscall",
+ "syscall.IPPROTO_IGRP": "syscall",
+ "syscall.IPPROTO_IL": "syscall",
+ "syscall.IPPROTO_INLSP": "syscall",
+ "syscall.IPPROTO_INP": "syscall",
+ "syscall.IPPROTO_IP": "syscall",
+ "syscall.IPPROTO_IPCOMP": "syscall",
+ "syscall.IPPROTO_IPCV": "syscall",
+ "syscall.IPPROTO_IPEIP": "syscall",
+ "syscall.IPPROTO_IPIP": "syscall",
+ "syscall.IPPROTO_IPPC": "syscall",
+ "syscall.IPPROTO_IPV4": "syscall",
+ "syscall.IPPROTO_IPV6": "syscall",
+ "syscall.IPPROTO_IPV6_ICMP": "syscall",
+ "syscall.IPPROTO_IRTP": "syscall",
+ "syscall.IPPROTO_KRYPTOLAN": "syscall",
+ "syscall.IPPROTO_LARP": "syscall",
+ "syscall.IPPROTO_LEAF1": "syscall",
+ "syscall.IPPROTO_LEAF2": "syscall",
+ "syscall.IPPROTO_MAX": "syscall",
+ "syscall.IPPROTO_MAXID": "syscall",
+ "syscall.IPPROTO_MEAS": "syscall",
+ "syscall.IPPROTO_MH": "syscall",
+ "syscall.IPPROTO_MHRP": "syscall",
+ "syscall.IPPROTO_MICP": "syscall",
+ "syscall.IPPROTO_MOBILE": "syscall",
+ "syscall.IPPROTO_MPLS": "syscall",
+ "syscall.IPPROTO_MTP": "syscall",
+ "syscall.IPPROTO_MUX": "syscall",
+ "syscall.IPPROTO_ND": "syscall",
+ "syscall.IPPROTO_NHRP": "syscall",
+ "syscall.IPPROTO_NONE": "syscall",
+ "syscall.IPPROTO_NSP": "syscall",
+ "syscall.IPPROTO_NVPII": "syscall",
+ "syscall.IPPROTO_OLD_DIVERT": "syscall",
+ "syscall.IPPROTO_OSPFIGP": "syscall",
+ "syscall.IPPROTO_PFSYNC": "syscall",
+ "syscall.IPPROTO_PGM": "syscall",
+ "syscall.IPPROTO_PIGP": "syscall",
+ "syscall.IPPROTO_PIM": "syscall",
+ "syscall.IPPROTO_PRM": "syscall",
+ "syscall.IPPROTO_PUP": "syscall",
+ "syscall.IPPROTO_PVP": "syscall",
+ "syscall.IPPROTO_RAW": "syscall",
+ "syscall.IPPROTO_RCCMON": "syscall",
+ "syscall.IPPROTO_RDP": "syscall",
+ "syscall.IPPROTO_ROUTING": "syscall",
+ "syscall.IPPROTO_RSVP": "syscall",
+ "syscall.IPPROTO_RVD": "syscall",
+ "syscall.IPPROTO_SATEXPAK": "syscall",
+ "syscall.IPPROTO_SATMON": "syscall",
+ "syscall.IPPROTO_SCCSP": "syscall",
+ "syscall.IPPROTO_SCTP": "syscall",
+ "syscall.IPPROTO_SDRP": "syscall",
+ "syscall.IPPROTO_SEND": "syscall",
+ "syscall.IPPROTO_SEP": "syscall",
+ "syscall.IPPROTO_SKIP": "syscall",
+ "syscall.IPPROTO_SPACER": "syscall",
+ "syscall.IPPROTO_SRPC": "syscall",
+ "syscall.IPPROTO_ST": "syscall",
+ "syscall.IPPROTO_SVMTP": "syscall",
+ "syscall.IPPROTO_SWIPE": "syscall",
+ "syscall.IPPROTO_TCF": "syscall",
+ "syscall.IPPROTO_TCP": "syscall",
+ "syscall.IPPROTO_TLSP": "syscall",
+ "syscall.IPPROTO_TP": "syscall",
+ "syscall.IPPROTO_TPXX": "syscall",
+ "syscall.IPPROTO_TRUNK1": "syscall",
+ "syscall.IPPROTO_TRUNK2": "syscall",
+ "syscall.IPPROTO_TTP": "syscall",
+ "syscall.IPPROTO_UDP": "syscall",
+ "syscall.IPPROTO_UDPLITE": "syscall",
+ "syscall.IPPROTO_VINES": "syscall",
+ "syscall.IPPROTO_VISA": "syscall",
+ "syscall.IPPROTO_VMTP": "syscall",
+ "syscall.IPPROTO_VRRP": "syscall",
+ "syscall.IPPROTO_WBEXPAK": "syscall",
+ "syscall.IPPROTO_WBMON": "syscall",
+ "syscall.IPPROTO_WSN": "syscall",
+ "syscall.IPPROTO_XNET": "syscall",
+ "syscall.IPPROTO_XTP": "syscall",
+ "syscall.IPV6_2292DSTOPTS": "syscall",
+ "syscall.IPV6_2292HOPLIMIT": "syscall",
+ "syscall.IPV6_2292HOPOPTS": "syscall",
+ "syscall.IPV6_2292NEXTHOP": "syscall",
+ "syscall.IPV6_2292PKTINFO": "syscall",
+ "syscall.IPV6_2292PKTOPTIONS": "syscall",
+ "syscall.IPV6_2292RTHDR": "syscall",
+ "syscall.IPV6_ADDRFORM": "syscall",
+ "syscall.IPV6_ADD_MEMBERSHIP": "syscall",
+ "syscall.IPV6_AUTHHDR": "syscall",
+ "syscall.IPV6_AUTH_LEVEL": "syscall",
+ "syscall.IPV6_AUTOFLOWLABEL": "syscall",
+ "syscall.IPV6_BINDANY": "syscall",
+ "syscall.IPV6_BINDV6ONLY": "syscall",
+ "syscall.IPV6_BOUND_IF": "syscall",
+ "syscall.IPV6_CHECKSUM": "syscall",
+ "syscall.IPV6_DEFAULT_MULTICAST_HOPS": "syscall",
+ "syscall.IPV6_DEFAULT_MULTICAST_LOOP": "syscall",
+ "syscall.IPV6_DEFHLIM": "syscall",
+ "syscall.IPV6_DONTFRAG": "syscall",
+ "syscall.IPV6_DROP_MEMBERSHIP": "syscall",
+ "syscall.IPV6_DSTOPTS": "syscall",
+ "syscall.IPV6_ESP_NETWORK_LEVEL": "syscall",
+ "syscall.IPV6_ESP_TRANS_LEVEL": "syscall",
+ "syscall.IPV6_FAITH": "syscall",
+ "syscall.IPV6_FLOWINFO_MASK": "syscall",
+ "syscall.IPV6_FLOWLABEL_MASK": "syscall",
+ "syscall.IPV6_FRAGTTL": "syscall",
+ "syscall.IPV6_FW_ADD": "syscall",
+ "syscall.IPV6_FW_DEL": "syscall",
+ "syscall.IPV6_FW_FLUSH": "syscall",
+ "syscall.IPV6_FW_GET": "syscall",
+ "syscall.IPV6_FW_ZERO": "syscall",
+ "syscall.IPV6_HLIMDEC": "syscall",
+ "syscall.IPV6_HOPLIMIT": "syscall",
+ "syscall.IPV6_HOPOPTS": "syscall",
+ "syscall.IPV6_IPCOMP_LEVEL": "syscall",
+ "syscall.IPV6_IPSEC_POLICY": "syscall",
+ "syscall.IPV6_JOIN_ANYCAST": "syscall",
+ "syscall.IPV6_JOIN_GROUP": "syscall",
+ "syscall.IPV6_LEAVE_ANYCAST": "syscall",
+ "syscall.IPV6_LEAVE_GROUP": "syscall",
+ "syscall.IPV6_MAXHLIM": "syscall",
+ "syscall.IPV6_MAXOPTHDR": "syscall",
+ "syscall.IPV6_MAXPACKET": "syscall",
+ "syscall.IPV6_MAX_GROUP_SRC_FILTER": "syscall",
+ "syscall.IPV6_MAX_MEMBERSHIPS": "syscall",
+ "syscall.IPV6_MAX_SOCK_SRC_FILTER": "syscall",
+ "syscall.IPV6_MIN_MEMBERSHIPS": "syscall",
+ "syscall.IPV6_MMTU": "syscall",
+ "syscall.IPV6_MSFILTER": "syscall",
+ "syscall.IPV6_MTU": "syscall",
+ "syscall.IPV6_MTU_DISCOVER": "syscall",
+ "syscall.IPV6_MULTICAST_HOPS": "syscall",
+ "syscall.IPV6_MULTICAST_IF": "syscall",
+ "syscall.IPV6_MULTICAST_LOOP": "syscall",
+ "syscall.IPV6_NEXTHOP": "syscall",
+ "syscall.IPV6_OPTIONS": "syscall",
+ "syscall.IPV6_PATHMTU": "syscall",
+ "syscall.IPV6_PIPEX": "syscall",
+ "syscall.IPV6_PKTINFO": "syscall",
+ "syscall.IPV6_PMTUDISC_DO": "syscall",
+ "syscall.IPV6_PMTUDISC_DONT": "syscall",
+ "syscall.IPV6_PMTUDISC_PROBE": "syscall",
+ "syscall.IPV6_PMTUDISC_WANT": "syscall",
+ "syscall.IPV6_PORTRANGE": "syscall",
+ "syscall.IPV6_PORTRANGE_DEFAULT": "syscall",
+ "syscall.IPV6_PORTRANGE_HIGH": "syscall",
+ "syscall.IPV6_PORTRANGE_LOW": "syscall",
+ "syscall.IPV6_PREFER_TEMPADDR": "syscall",
+ "syscall.IPV6_RECVDSTOPTS": "syscall",
+ "syscall.IPV6_RECVERR": "syscall",
+ "syscall.IPV6_RECVHOPLIMIT": "syscall",
+ "syscall.IPV6_RECVHOPOPTS": "syscall",
+ "syscall.IPV6_RECVPATHMTU": "syscall",
+ "syscall.IPV6_RECVPKTINFO": "syscall",
+ "syscall.IPV6_RECVRTHDR": "syscall",
+ "syscall.IPV6_RECVTCLASS": "syscall",
+ "syscall.IPV6_ROUTER_ALERT": "syscall",
+ "syscall.IPV6_RTABLE": "syscall",
+ "syscall.IPV6_RTHDR": "syscall",
+ "syscall.IPV6_RTHDRDSTOPTS": "syscall",
+ "syscall.IPV6_RTHDR_LOOSE": "syscall",
+ "syscall.IPV6_RTHDR_STRICT": "syscall",
+ "syscall.IPV6_RTHDR_TYPE_0": "syscall",
+ "syscall.IPV6_RXDSTOPTS": "syscall",
+ "syscall.IPV6_RXHOPOPTS": "syscall",
+ "syscall.IPV6_SOCKOPT_RESERVED1": "syscall",
+ "syscall.IPV6_TCLASS": "syscall",
+ "syscall.IPV6_UNICAST_HOPS": "syscall",
+ "syscall.IPV6_USE_MIN_MTU": "syscall",
+ "syscall.IPV6_V6ONLY": "syscall",
+ "syscall.IPV6_VERSION": "syscall",
+ "syscall.IPV6_VERSION_MASK": "syscall",
+ "syscall.IPV6_XFRM_POLICY": "syscall",
+ "syscall.IP_ADD_MEMBERSHIP": "syscall",
+ "syscall.IP_ADD_SOURCE_MEMBERSHIP": "syscall",
+ "syscall.IP_AUTH_LEVEL": "syscall",
+ "syscall.IP_BINDANY": "syscall",
+ "syscall.IP_BLOCK_SOURCE": "syscall",
+ "syscall.IP_BOUND_IF": "syscall",
+ "syscall.IP_DEFAULT_MULTICAST_LOOP": "syscall",
+ "syscall.IP_DEFAULT_MULTICAST_TTL": "syscall",
+ "syscall.IP_DF": "syscall",
+ "syscall.IP_DONTFRAG": "syscall",
+ "syscall.IP_DROP_MEMBERSHIP": "syscall",
+ "syscall.IP_DROP_SOURCE_MEMBERSHIP": "syscall",
+ "syscall.IP_DUMMYNET3": "syscall",
+ "syscall.IP_DUMMYNET_CONFIGURE": "syscall",
+ "syscall.IP_DUMMYNET_DEL": "syscall",
+ "syscall.IP_DUMMYNET_FLUSH": "syscall",
+ "syscall.IP_DUMMYNET_GET": "syscall",
+ "syscall.IP_EF": "syscall",
+ "syscall.IP_ERRORMTU": "syscall",
+ "syscall.IP_ESP_NETWORK_LEVEL": "syscall",
+ "syscall.IP_ESP_TRANS_LEVEL": "syscall",
+ "syscall.IP_FAITH": "syscall",
+ "syscall.IP_FREEBIND": "syscall",
+ "syscall.IP_FW3": "syscall",
+ "syscall.IP_FW_ADD": "syscall",
+ "syscall.IP_FW_DEL": "syscall",
+ "syscall.IP_FW_FLUSH": "syscall",
+ "syscall.IP_FW_GET": "syscall",
+ "syscall.IP_FW_NAT_CFG": "syscall",
+ "syscall.IP_FW_NAT_DEL": "syscall",
+ "syscall.IP_FW_NAT_GET_CONFIG": "syscall",
+ "syscall.IP_FW_NAT_GET_LOG": "syscall",
+ "syscall.IP_FW_RESETLOG": "syscall",
+ "syscall.IP_FW_TABLE_ADD": "syscall",
+ "syscall.IP_FW_TABLE_DEL": "syscall",
+ "syscall.IP_FW_TABLE_FLUSH": "syscall",
+ "syscall.IP_FW_TABLE_GETSIZE": "syscall",
+ "syscall.IP_FW_TABLE_LIST": "syscall",
+ "syscall.IP_FW_ZERO": "syscall",
+ "syscall.IP_HDRINCL": "syscall",
+ "syscall.IP_IPCOMP_LEVEL": "syscall",
+ "syscall.IP_IPSECFLOWINFO": "syscall",
+ "syscall.IP_IPSEC_LOCAL_AUTH": "syscall",
+ "syscall.IP_IPSEC_LOCAL_CRED": "syscall",
+ "syscall.IP_IPSEC_LOCAL_ID": "syscall",
+ "syscall.IP_IPSEC_POLICY": "syscall",
+ "syscall.IP_IPSEC_REMOTE_AUTH": "syscall",
+ "syscall.IP_IPSEC_REMOTE_CRED": "syscall",
+ "syscall.IP_IPSEC_REMOTE_ID": "syscall",
+ "syscall.IP_MAXPACKET": "syscall",
+ "syscall.IP_MAX_GROUP_SRC_FILTER": "syscall",
+ "syscall.IP_MAX_MEMBERSHIPS": "syscall",
+ "syscall.IP_MAX_SOCK_MUTE_FILTER": "syscall",
+ "syscall.IP_MAX_SOCK_SRC_FILTER": "syscall",
+ "syscall.IP_MAX_SOURCE_FILTER": "syscall",
+ "syscall.IP_MF": "syscall",
+ "syscall.IP_MINFRAGSIZE": "syscall",
+ "syscall.IP_MINTTL": "syscall",
+ "syscall.IP_MIN_MEMBERSHIPS": "syscall",
+ "syscall.IP_MSFILTER": "syscall",
+ "syscall.IP_MSS": "syscall",
+ "syscall.IP_MTU": "syscall",
+ "syscall.IP_MTU_DISCOVER": "syscall",
+ "syscall.IP_MULTICAST_IF": "syscall",
+ "syscall.IP_MULTICAST_IFINDEX": "syscall",
+ "syscall.IP_MULTICAST_LOOP": "syscall",
+ "syscall.IP_MULTICAST_TTL": "syscall",
+ "syscall.IP_MULTICAST_VIF": "syscall",
+ "syscall.IP_NAT__XXX": "syscall",
+ "syscall.IP_OFFMASK": "syscall",
+ "syscall.IP_OLD_FW_ADD": "syscall",
+ "syscall.IP_OLD_FW_DEL": "syscall",
+ "syscall.IP_OLD_FW_FLUSH": "syscall",
+ "syscall.IP_OLD_FW_GET": "syscall",
+ "syscall.IP_OLD_FW_RESETLOG": "syscall",
+ "syscall.IP_OLD_FW_ZERO": "syscall",
+ "syscall.IP_ONESBCAST": "syscall",
+ "syscall.IP_OPTIONS": "syscall",
+ "syscall.IP_ORIGDSTADDR": "syscall",
+ "syscall.IP_PASSSEC": "syscall",
+ "syscall.IP_PIPEX": "syscall",
+ "syscall.IP_PKTINFO": "syscall",
+ "syscall.IP_PKTOPTIONS": "syscall",
+ "syscall.IP_PMTUDISC": "syscall",
+ "syscall.IP_PMTUDISC_DO": "syscall",
+ "syscall.IP_PMTUDISC_DONT": "syscall",
+ "syscall.IP_PMTUDISC_PROBE": "syscall",
+ "syscall.IP_PMTUDISC_WANT": "syscall",
+ "syscall.IP_PORTRANGE": "syscall",
+ "syscall.IP_PORTRANGE_DEFAULT": "syscall",
+ "syscall.IP_PORTRANGE_HIGH": "syscall",
+ "syscall.IP_PORTRANGE_LOW": "syscall",
+ "syscall.IP_RECVDSTADDR": "syscall",
+ "syscall.IP_RECVDSTPORT": "syscall",
+ "syscall.IP_RECVERR": "syscall",
+ "syscall.IP_RECVIF": "syscall",
+ "syscall.IP_RECVOPTS": "syscall",
+ "syscall.IP_RECVORIGDSTADDR": "syscall",
+ "syscall.IP_RECVPKTINFO": "syscall",
+ "syscall.IP_RECVRETOPTS": "syscall",
+ "syscall.IP_RECVRTABLE": "syscall",
+ "syscall.IP_RECVTOS": "syscall",
+ "syscall.IP_RECVTTL": "syscall",
+ "syscall.IP_RETOPTS": "syscall",
+ "syscall.IP_RF": "syscall",
+ "syscall.IP_ROUTER_ALERT": "syscall",
+ "syscall.IP_RSVP_OFF": "syscall",
+ "syscall.IP_RSVP_ON": "syscall",
+ "syscall.IP_RSVP_VIF_OFF": "syscall",
+ "syscall.IP_RSVP_VIF_ON": "syscall",
+ "syscall.IP_RTABLE": "syscall",
+ "syscall.IP_SENDSRCADDR": "syscall",
+ "syscall.IP_STRIPHDR": "syscall",
+ "syscall.IP_TOS": "syscall",
+ "syscall.IP_TRAFFIC_MGT_BACKGROUND": "syscall",
+ "syscall.IP_TRANSPARENT": "syscall",
+ "syscall.IP_TTL": "syscall",
+ "syscall.IP_UNBLOCK_SOURCE": "syscall",
+ "syscall.IP_XFRM_POLICY": "syscall",
+ "syscall.IPv6MTUInfo": "syscall",
+ "syscall.IPv6Mreq": "syscall",
+ "syscall.ISIG": "syscall",
+ "syscall.ISTRIP": "syscall",
+ "syscall.IUCLC": "syscall",
+ "syscall.IUTF8": "syscall",
+ "syscall.IXANY": "syscall",
+ "syscall.IXOFF": "syscall",
+ "syscall.IXON": "syscall",
+ "syscall.IfAddrmsg": "syscall",
+ "syscall.IfAnnounceMsghdr": "syscall",
+ "syscall.IfData": "syscall",
+ "syscall.IfInfomsg": "syscall",
+ "syscall.IfMsghdr": "syscall",
+ "syscall.IfaMsghdr": "syscall",
+ "syscall.IfmaMsghdr": "syscall",
+ "syscall.IfmaMsghdr2": "syscall",
+ "syscall.ImplementsGetwd": "syscall",
+ "syscall.Inet4Pktinfo": "syscall",
+ "syscall.Inet6Pktinfo": "syscall",
+ "syscall.InotifyAddWatch": "syscall",
+ "syscall.InotifyEvent": "syscall",
+ "syscall.InotifyInit": "syscall",
+ "syscall.InotifyInit1": "syscall",
+ "syscall.InotifyRmWatch": "syscall",
+ "syscall.InterfaceAddrMessage": "syscall",
+ "syscall.InterfaceAnnounceMessage": "syscall",
+ "syscall.InterfaceInfo": "syscall",
+ "syscall.InterfaceMessage": "syscall",
+ "syscall.InterfaceMulticastAddrMessage": "syscall",
+ "syscall.InvalidHandle": "syscall",
+ "syscall.Ioperm": "syscall",
+ "syscall.Iopl": "syscall",
+ "syscall.Iovec": "syscall",
+ "syscall.IpAdapterInfo": "syscall",
+ "syscall.IpAddrString": "syscall",
+ "syscall.IpAddressString": "syscall",
+ "syscall.IpMaskString": "syscall",
+ "syscall.Issetugid": "syscall",
+ "syscall.KEY_ALL_ACCESS": "syscall",
+ "syscall.KEY_CREATE_LINK": "syscall",
+ "syscall.KEY_CREATE_SUB_KEY": "syscall",
+ "syscall.KEY_ENUMERATE_SUB_KEYS": "syscall",
+ "syscall.KEY_EXECUTE": "syscall",
+ "syscall.KEY_NOTIFY": "syscall",
+ "syscall.KEY_QUERY_VALUE": "syscall",
+ "syscall.KEY_READ": "syscall",
+ "syscall.KEY_SET_VALUE": "syscall",
+ "syscall.KEY_WOW64_32KEY": "syscall",
+ "syscall.KEY_WOW64_64KEY": "syscall",
+ "syscall.KEY_WRITE": "syscall",
+ "syscall.Kevent": "syscall",
+ "syscall.Kevent_t": "syscall",
+ "syscall.Kill": "syscall",
+ "syscall.Klogctl": "syscall",
+ "syscall.Kqueue": "syscall",
+ "syscall.LANG_ENGLISH": "syscall",
+ "syscall.LAYERED_PROTOCOL": "syscall",
+ "syscall.LCNT_OVERLOAD_FLUSH": "syscall",
+ "syscall.LINUX_REBOOT_CMD_CAD_OFF": "syscall",
+ "syscall.LINUX_REBOOT_CMD_CAD_ON": "syscall",
+ "syscall.LINUX_REBOOT_CMD_HALT": "syscall",
+ "syscall.LINUX_REBOOT_CMD_KEXEC": "syscall",
+ "syscall.LINUX_REBOOT_CMD_POWER_OFF": "syscall",
+ "syscall.LINUX_REBOOT_CMD_RESTART": "syscall",
+ "syscall.LINUX_REBOOT_CMD_RESTART2": "syscall",
+ "syscall.LINUX_REBOOT_CMD_SW_SUSPEND": "syscall",
+ "syscall.LINUX_REBOOT_MAGIC1": "syscall",
+ "syscall.LINUX_REBOOT_MAGIC2": "syscall",
+ "syscall.LOCK_EX": "syscall",
+ "syscall.LOCK_NB": "syscall",
+ "syscall.LOCK_SH": "syscall",
+ "syscall.LOCK_UN": "syscall",
+ "syscall.LazyDLL": "syscall",
+ "syscall.LazyProc": "syscall",
+ "syscall.Lchown": "syscall",
+ "syscall.Linger": "syscall",
+ "syscall.Link": "syscall",
+ "syscall.Listen": "syscall",
+ "syscall.Listxattr": "syscall",
+ "syscall.LoadCancelIoEx": "syscall",
+ "syscall.LoadConnectEx": "syscall",
+ "syscall.LoadDLL": "syscall",
+ "syscall.LoadGetAddrInfo": "syscall",
+ "syscall.LoadLibrary": "syscall",
+ "syscall.LoadSetFileCompletionNotificationModes": "syscall",
+ "syscall.LocalFree": "syscall",
+ "syscall.Log2phys_t": "syscall",
+ "syscall.LookupAccountName": "syscall",
+ "syscall.LookupAccountSid": "syscall",
+ "syscall.LookupSID": "syscall",
+ "syscall.LsfJump": "syscall",
+ "syscall.LsfSocket": "syscall",
+ "syscall.LsfStmt": "syscall",
+ "syscall.Lstat": "syscall",
+ "syscall.MADV_AUTOSYNC": "syscall",
+ "syscall.MADV_CAN_REUSE": "syscall",
+ "syscall.MADV_CORE": "syscall",
+ "syscall.MADV_DOFORK": "syscall",
+ "syscall.MADV_DONTFORK": "syscall",
+ "syscall.MADV_DONTNEED": "syscall",
+ "syscall.MADV_FREE": "syscall",
+ "syscall.MADV_FREE_REUSABLE": "syscall",
+ "syscall.MADV_FREE_REUSE": "syscall",
+ "syscall.MADV_HUGEPAGE": "syscall",
+ "syscall.MADV_HWPOISON": "syscall",
+ "syscall.MADV_MERGEABLE": "syscall",
+ "syscall.MADV_NOCORE": "syscall",
+ "syscall.MADV_NOHUGEPAGE": "syscall",
+ "syscall.MADV_NORMAL": "syscall",
+ "syscall.MADV_NOSYNC": "syscall",
+ "syscall.MADV_PROTECT": "syscall",
+ "syscall.MADV_RANDOM": "syscall",
+ "syscall.MADV_REMOVE": "syscall",
+ "syscall.MADV_SEQUENTIAL": "syscall",
+ "syscall.MADV_UNMERGEABLE": "syscall",
+ "syscall.MADV_WILLNEED": "syscall",
+ "syscall.MADV_ZERO_WIRED_PAGES": "syscall",
+ "syscall.MAP_32BIT": "syscall",
+ "syscall.MAP_ANON": "syscall",
+ "syscall.MAP_ANONYMOUS": "syscall",
+ "syscall.MAP_COPY": "syscall",
+ "syscall.MAP_DENYWRITE": "syscall",
+ "syscall.MAP_EXECUTABLE": "syscall",
+ "syscall.MAP_FILE": "syscall",
+ "syscall.MAP_FIXED": "syscall",
+ "syscall.MAP_GROWSDOWN": "syscall",
+ "syscall.MAP_HASSEMAPHORE": "syscall",
+ "syscall.MAP_HUGETLB": "syscall",
+ "syscall.MAP_JIT": "syscall",
+ "syscall.MAP_LOCKED": "syscall",
+ "syscall.MAP_NOCACHE": "syscall",
+ "syscall.MAP_NOCORE": "syscall",
+ "syscall.MAP_NOEXTEND": "syscall",
+ "syscall.MAP_NONBLOCK": "syscall",
+ "syscall.MAP_NORESERVE": "syscall",
+ "syscall.MAP_NOSYNC": "syscall",
+ "syscall.MAP_POPULATE": "syscall",
+ "syscall.MAP_PREFAULT_READ": "syscall",
+ "syscall.MAP_PRIVATE": "syscall",
+ "syscall.MAP_RENAME": "syscall",
+ "syscall.MAP_RESERVED0080": "syscall",
+ "syscall.MAP_RESERVED0100": "syscall",
+ "syscall.MAP_SHARED": "syscall",
+ "syscall.MAP_STACK": "syscall",
+ "syscall.MAP_TYPE": "syscall",
+ "syscall.MAXLEN_IFDESCR": "syscall",
+ "syscall.MAXLEN_PHYSADDR": "syscall",
+ "syscall.MAX_ADAPTER_ADDRESS_LENGTH": "syscall",
+ "syscall.MAX_ADAPTER_DESCRIPTION_LENGTH": "syscall",
+ "syscall.MAX_ADAPTER_NAME_LENGTH": "syscall",
+ "syscall.MAX_COMPUTERNAME_LENGTH": "syscall",
+ "syscall.MAX_INTERFACE_NAME_LEN": "syscall",
+ "syscall.MAX_LONG_PATH": "syscall",
+ "syscall.MAX_PATH": "syscall",
+ "syscall.MAX_PROTOCOL_CHAIN": "syscall",
+ "syscall.MCL_CURRENT": "syscall",
+ "syscall.MCL_FUTURE": "syscall",
+ "syscall.MNT_DETACH": "syscall",
+ "syscall.MNT_EXPIRE": "syscall",
+ "syscall.MNT_FORCE": "syscall",
+ "syscall.MSG_BCAST": "syscall",
+ "syscall.MSG_CMSG_CLOEXEC": "syscall",
+ "syscall.MSG_COMPAT": "syscall",
+ "syscall.MSG_CONFIRM": "syscall",
+ "syscall.MSG_CONTROLMBUF": "syscall",
+ "syscall.MSG_CTRUNC": "syscall",
+ "syscall.MSG_DONTROUTE": "syscall",
+ "syscall.MSG_DONTWAIT": "syscall",
+ "syscall.MSG_EOF": "syscall",
+ "syscall.MSG_EOR": "syscall",
+ "syscall.MSG_ERRQUEUE": "syscall",
+ "syscall.MSG_FASTOPEN": "syscall",
+ "syscall.MSG_FIN": "syscall",
+ "syscall.MSG_FLUSH": "syscall",
+ "syscall.MSG_HAVEMORE": "syscall",
+ "syscall.MSG_HOLD": "syscall",
+ "syscall.MSG_IOVUSRSPACE": "syscall",
+ "syscall.MSG_LENUSRSPACE": "syscall",
+ "syscall.MSG_MCAST": "syscall",
+ "syscall.MSG_MORE": "syscall",
+ "syscall.MSG_NAMEMBUF": "syscall",
+ "syscall.MSG_NBIO": "syscall",
+ "syscall.MSG_NEEDSA": "syscall",
+ "syscall.MSG_NOSIGNAL": "syscall",
+ "syscall.MSG_NOTIFICATION": "syscall",
+ "syscall.MSG_OOB": "syscall",
+ "syscall.MSG_PEEK": "syscall",
+ "syscall.MSG_PROXY": "syscall",
+ "syscall.MSG_RCVMORE": "syscall",
+ "syscall.MSG_RST": "syscall",
+ "syscall.MSG_SEND": "syscall",
+ "syscall.MSG_SYN": "syscall",
+ "syscall.MSG_TRUNC": "syscall",
+ "syscall.MSG_TRYHARD": "syscall",
+ "syscall.MSG_USERFLAGS": "syscall",
+ "syscall.MSG_WAITALL": "syscall",
+ "syscall.MSG_WAITFORONE": "syscall",
+ "syscall.MSG_WAITSTREAM": "syscall",
+ "syscall.MS_ACTIVE": "syscall",
+ "syscall.MS_ASYNC": "syscall",
+ "syscall.MS_BIND": "syscall",
+ "syscall.MS_DEACTIVATE": "syscall",
+ "syscall.MS_DIRSYNC": "syscall",
+ "syscall.MS_INVALIDATE": "syscall",
+ "syscall.MS_I_VERSION": "syscall",
+ "syscall.MS_KERNMOUNT": "syscall",
+ "syscall.MS_KILLPAGES": "syscall",
+ "syscall.MS_MANDLOCK": "syscall",
+ "syscall.MS_MGC_MSK": "syscall",
+ "syscall.MS_MGC_VAL": "syscall",
+ "syscall.MS_MOVE": "syscall",
+ "syscall.MS_NOATIME": "syscall",
+ "syscall.MS_NODEV": "syscall",
+ "syscall.MS_NODIRATIME": "syscall",
+ "syscall.MS_NOEXEC": "syscall",
+ "syscall.MS_NOSUID": "syscall",
+ "syscall.MS_NOUSER": "syscall",
+ "syscall.MS_POSIXACL": "syscall",
+ "syscall.MS_PRIVATE": "syscall",
+ "syscall.MS_RDONLY": "syscall",
+ "syscall.MS_REC": "syscall",
+ "syscall.MS_RELATIME": "syscall",
+ "syscall.MS_REMOUNT": "syscall",
+ "syscall.MS_RMT_MASK": "syscall",
+ "syscall.MS_SHARED": "syscall",
+ "syscall.MS_SILENT": "syscall",
+ "syscall.MS_SLAVE": "syscall",
+ "syscall.MS_STRICTATIME": "syscall",
+ "syscall.MS_SYNC": "syscall",
+ "syscall.MS_SYNCHRONOUS": "syscall",
+ "syscall.MS_UNBINDABLE": "syscall",
+ "syscall.Madvise": "syscall",
+ "syscall.MapViewOfFile": "syscall",
+ "syscall.MaxTokenInfoClass": "syscall",
+ "syscall.Mclpool": "syscall",
+ "syscall.MibIfRow": "syscall",
+ "syscall.Mkdir": "syscall",
+ "syscall.Mkdirat": "syscall",
+ "syscall.Mkfifo": "syscall",
+ "syscall.Mknod": "syscall",
+ "syscall.Mknodat": "syscall",
+ "syscall.Mlock": "syscall",
+ "syscall.Mlockall": "syscall",
+ "syscall.Mmap": "syscall",
+ "syscall.Mount": "syscall",
+ "syscall.MoveFile": "syscall",
+ "syscall.Mprotect": "syscall",
+ "syscall.Msghdr": "syscall",
+ "syscall.Munlock": "syscall",
+ "syscall.Munlockall": "syscall",
+ "syscall.Munmap": "syscall",
+ "syscall.MustLoadDLL": "syscall",
+ "syscall.NAME_MAX": "syscall",
+ "syscall.NETLINK_ADD_MEMBERSHIP": "syscall",
+ "syscall.NETLINK_AUDIT": "syscall",
+ "syscall.NETLINK_BROADCAST_ERROR": "syscall",
+ "syscall.NETLINK_CONNECTOR": "syscall",
+ "syscall.NETLINK_DNRTMSG": "syscall",
+ "syscall.NETLINK_DROP_MEMBERSHIP": "syscall",
+ "syscall.NETLINK_ECRYPTFS": "syscall",
+ "syscall.NETLINK_FIB_LOOKUP": "syscall",
+ "syscall.NETLINK_FIREWALL": "syscall",
+ "syscall.NETLINK_GENERIC": "syscall",
+ "syscall.NETLINK_INET_DIAG": "syscall",
+ "syscall.NETLINK_IP6_FW": "syscall",
+ "syscall.NETLINK_ISCSI": "syscall",
+ "syscall.NETLINK_KOBJECT_UEVENT": "syscall",
+ "syscall.NETLINK_NETFILTER": "syscall",
+ "syscall.NETLINK_NFLOG": "syscall",
+ "syscall.NETLINK_NO_ENOBUFS": "syscall",
+ "syscall.NETLINK_PKTINFO": "syscall",
+ "syscall.NETLINK_RDMA": "syscall",
+ "syscall.NETLINK_ROUTE": "syscall",
+ "syscall.NETLINK_SCSITRANSPORT": "syscall",
+ "syscall.NETLINK_SELINUX": "syscall",
+ "syscall.NETLINK_UNUSED": "syscall",
+ "syscall.NETLINK_USERSOCK": "syscall",
+ "syscall.NETLINK_XFRM": "syscall",
+ "syscall.NET_RT_DUMP": "syscall",
+ "syscall.NET_RT_DUMP2": "syscall",
+ "syscall.NET_RT_FLAGS": "syscall",
+ "syscall.NET_RT_IFLIST": "syscall",
+ "syscall.NET_RT_IFLIST2": "syscall",
+ "syscall.NET_RT_IFLISTL": "syscall",
+ "syscall.NET_RT_IFMALIST": "syscall",
+ "syscall.NET_RT_MAXID": "syscall",
+ "syscall.NET_RT_OIFLIST": "syscall",
+ "syscall.NET_RT_OOIFLIST": "syscall",
+ "syscall.NET_RT_STAT": "syscall",
+ "syscall.NET_RT_STATS": "syscall",
+ "syscall.NET_RT_TABLE": "syscall",
+ "syscall.NET_RT_TRASH": "syscall",
+ "syscall.NLA_ALIGNTO": "syscall",
+ "syscall.NLA_F_NESTED": "syscall",
+ "syscall.NLA_F_NET_BYTEORDER": "syscall",
+ "syscall.NLA_HDRLEN": "syscall",
+ "syscall.NLMSG_ALIGNTO": "syscall",
+ "syscall.NLMSG_DONE": "syscall",
+ "syscall.NLMSG_ERROR": "syscall",
+ "syscall.NLMSG_HDRLEN": "syscall",
+ "syscall.NLMSG_MIN_TYPE": "syscall",
+ "syscall.NLMSG_NOOP": "syscall",
+ "syscall.NLMSG_OVERRUN": "syscall",
+ "syscall.NLM_F_ACK": "syscall",
+ "syscall.NLM_F_APPEND": "syscall",
+ "syscall.NLM_F_ATOMIC": "syscall",
+ "syscall.NLM_F_CREATE": "syscall",
+ "syscall.NLM_F_DUMP": "syscall",
+ "syscall.NLM_F_ECHO": "syscall",
+ "syscall.NLM_F_EXCL": "syscall",
+ "syscall.NLM_F_MATCH": "syscall",
+ "syscall.NLM_F_MULTI": "syscall",
+ "syscall.NLM_F_REPLACE": "syscall",
+ "syscall.NLM_F_REQUEST": "syscall",
+ "syscall.NLM_F_ROOT": "syscall",
+ "syscall.NOFLSH": "syscall",
+ "syscall.NOTE_ABSOLUTE": "syscall",
+ "syscall.NOTE_ATTRIB": "syscall",
+ "syscall.NOTE_CHILD": "syscall",
+ "syscall.NOTE_DELETE": "syscall",
+ "syscall.NOTE_EOF": "syscall",
+ "syscall.NOTE_EXEC": "syscall",
+ "syscall.NOTE_EXIT": "syscall",
+ "syscall.NOTE_EXITSTATUS": "syscall",
+ "syscall.NOTE_EXTEND": "syscall",
+ "syscall.NOTE_FFAND": "syscall",
+ "syscall.NOTE_FFCOPY": "syscall",
+ "syscall.NOTE_FFCTRLMASK": "syscall",
+ "syscall.NOTE_FFLAGSMASK": "syscall",
+ "syscall.NOTE_FFNOP": "syscall",
+ "syscall.NOTE_FFOR": "syscall",
+ "syscall.NOTE_FORK": "syscall",
+ "syscall.NOTE_LINK": "syscall",
+ "syscall.NOTE_LOWAT": "syscall",
+ "syscall.NOTE_NONE": "syscall",
+ "syscall.NOTE_NSECONDS": "syscall",
+ "syscall.NOTE_PCTRLMASK": "syscall",
+ "syscall.NOTE_PDATAMASK": "syscall",
+ "syscall.NOTE_REAP": "syscall",
+ "syscall.NOTE_RENAME": "syscall",
+ "syscall.NOTE_RESOURCEEND": "syscall",
+ "syscall.NOTE_REVOKE": "syscall",
+ "syscall.NOTE_SECONDS": "syscall",
+ "syscall.NOTE_SIGNAL": "syscall",
+ "syscall.NOTE_TRACK": "syscall",
+ "syscall.NOTE_TRACKERR": "syscall",
+ "syscall.NOTE_TRIGGER": "syscall",
+ "syscall.NOTE_TRUNCATE": "syscall",
+ "syscall.NOTE_USECONDS": "syscall",
+ "syscall.NOTE_VM_ERROR": "syscall",
+ "syscall.NOTE_VM_PRESSURE": "syscall",
+ "syscall.NOTE_VM_PRESSURE_SUDDEN_TERMINATE": "syscall",
+ "syscall.NOTE_VM_PRESSURE_TERMINATE": "syscall",
+ "syscall.NOTE_WRITE": "syscall",
+ "syscall.NameCanonical": "syscall",
+ "syscall.NameCanonicalEx": "syscall",
+ "syscall.NameDisplay": "syscall",
+ "syscall.NameDnsDomain": "syscall",
+ "syscall.NameFullyQualifiedDN": "syscall",
+ "syscall.NameSamCompatible": "syscall",
+ "syscall.NameServicePrincipal": "syscall",
+ "syscall.NameUniqueId": "syscall",
+ "syscall.NameUnknown": "syscall",
+ "syscall.NameUserPrincipal": "syscall",
+ "syscall.Nanosleep": "syscall",
+ "syscall.NetApiBufferFree": "syscall",
+ "syscall.NetGetJoinInformation": "syscall",
+ "syscall.NetSetupDomainName": "syscall",
+ "syscall.NetSetupUnjoined": "syscall",
+ "syscall.NetSetupUnknownStatus": "syscall",
+ "syscall.NetSetupWorkgroupName": "syscall",
+ "syscall.NetUserGetInfo": "syscall",
+ "syscall.NetlinkMessage": "syscall",
+ "syscall.NetlinkRIB": "syscall",
+ "syscall.NetlinkRouteAttr": "syscall",
+ "syscall.NetlinkRouteRequest": "syscall",
+ "syscall.NewCallback": "syscall",
+ "syscall.NewLazyDLL": "syscall",
+ "syscall.NlAttr": "syscall",
+ "syscall.NlMsgerr": "syscall",
+ "syscall.NlMsghdr": "syscall",
+ "syscall.NsecToFiletime": "syscall",
+ "syscall.NsecToTimespec": "syscall",
+ "syscall.NsecToTimeval": "syscall",
+ "syscall.Ntohs": "syscall",
+ "syscall.OCRNL": "syscall",
+ "syscall.OFDEL": "syscall",
+ "syscall.OFILL": "syscall",
+ "syscall.OFIOGETBMAP": "syscall",
+ "syscall.OID_PKIX_KP_SERVER_AUTH": "syscall",
+ "syscall.OID_SERVER_GATED_CRYPTO": "syscall",
+ "syscall.OID_SGC_NETSCAPE": "syscall",
+ "syscall.OLCUC": "syscall",
+ "syscall.ONLCR": "syscall",
+ "syscall.ONLRET": "syscall",
+ "syscall.ONOCR": "syscall",
+ "syscall.ONOEOT": "syscall",
+ "syscall.OPEN_ALWAYS": "syscall",
+ "syscall.OPEN_EXISTING": "syscall",
+ "syscall.OPOST": "syscall",
+ "syscall.O_ACCMODE": "syscall",
+ "syscall.O_ALERT": "syscall",
+ "syscall.O_ALT_IO": "syscall",
+ "syscall.O_APPEND": "syscall",
+ "syscall.O_ASYNC": "syscall",
+ "syscall.O_CLOEXEC": "syscall",
+ "syscall.O_CREAT": "syscall",
+ "syscall.O_DIRECT": "syscall",
+ "syscall.O_DIRECTORY": "syscall",
+ "syscall.O_DSYNC": "syscall",
+ "syscall.O_EVTONLY": "syscall",
+ "syscall.O_EXCL": "syscall",
+ "syscall.O_EXEC": "syscall",
+ "syscall.O_EXLOCK": "syscall",
+ "syscall.O_FSYNC": "syscall",
+ "syscall.O_LARGEFILE": "syscall",
+ "syscall.O_NDELAY": "syscall",
+ "syscall.O_NOATIME": "syscall",
+ "syscall.O_NOCTTY": "syscall",
+ "syscall.O_NOFOLLOW": "syscall",
+ "syscall.O_NONBLOCK": "syscall",
+ "syscall.O_NOSIGPIPE": "syscall",
+ "syscall.O_POPUP": "syscall",
+ "syscall.O_RDONLY": "syscall",
+ "syscall.O_RDWR": "syscall",
+ "syscall.O_RSYNC": "syscall",
+ "syscall.O_SHLOCK": "syscall",
+ "syscall.O_SYMLINK": "syscall",
+ "syscall.O_SYNC": "syscall",
+ "syscall.O_TRUNC": "syscall",
+ "syscall.O_TTY_INIT": "syscall",
+ "syscall.O_WRONLY": "syscall",
+ "syscall.Open": "syscall",
+ "syscall.OpenCurrentProcessToken": "syscall",
+ "syscall.OpenProcess": "syscall",
+ "syscall.OpenProcessToken": "syscall",
+ "syscall.Openat": "syscall",
+ "syscall.Overlapped": "syscall",
+ "syscall.PACKET_ADD_MEMBERSHIP": "syscall",
+ "syscall.PACKET_BROADCAST": "syscall",
+ "syscall.PACKET_DROP_MEMBERSHIP": "syscall",
+ "syscall.PACKET_FASTROUTE": "syscall",
+ "syscall.PACKET_HOST": "syscall",
+ "syscall.PACKET_LOOPBACK": "syscall",
+ "syscall.PACKET_MR_ALLMULTI": "syscall",
+ "syscall.PACKET_MR_MULTICAST": "syscall",
+ "syscall.PACKET_MR_PROMISC": "syscall",
+ "syscall.PACKET_MULTICAST": "syscall",
+ "syscall.PACKET_OTHERHOST": "syscall",
+ "syscall.PACKET_OUTGOING": "syscall",
+ "syscall.PACKET_RECV_OUTPUT": "syscall",
+ "syscall.PACKET_RX_RING": "syscall",
+ "syscall.PACKET_STATISTICS": "syscall",
+ "syscall.PAGE_EXECUTE_READ": "syscall",
+ "syscall.PAGE_EXECUTE_READWRITE": "syscall",
+ "syscall.PAGE_EXECUTE_WRITECOPY": "syscall",
+ "syscall.PAGE_READONLY": "syscall",
+ "syscall.PAGE_READWRITE": "syscall",
+ "syscall.PAGE_WRITECOPY": "syscall",
+ "syscall.PARENB": "syscall",
+ "syscall.PARMRK": "syscall",
+ "syscall.PARODD": "syscall",
+ "syscall.PENDIN": "syscall",
+ "syscall.PFL_HIDDEN": "syscall",
+ "syscall.PFL_MATCHES_PROTOCOL_ZERO": "syscall",
+ "syscall.PFL_MULTIPLE_PROTO_ENTRIES": "syscall",
+ "syscall.PFL_NETWORKDIRECT_PROVIDER": "syscall",
+ "syscall.PFL_RECOMMENDED_PROTO_ENTRY": "syscall",
+ "syscall.PF_FLUSH": "syscall",
+ "syscall.PKCS_7_ASN_ENCODING": "syscall",
+ "syscall.PMC5_PIPELINE_FLUSH": "syscall",
+ "syscall.PRIO_PGRP": "syscall",
+ "syscall.PRIO_PROCESS": "syscall",
+ "syscall.PRIO_USER": "syscall",
+ "syscall.PRI_IOFLUSH": "syscall",
+ "syscall.PROCESS_QUERY_INFORMATION": "syscall",
+ "syscall.PROCESS_TERMINATE": "syscall",
+ "syscall.PROT_EXEC": "syscall",
+ "syscall.PROT_GROWSDOWN": "syscall",
+ "syscall.PROT_GROWSUP": "syscall",
+ "syscall.PROT_NONE": "syscall",
+ "syscall.PROT_READ": "syscall",
+ "syscall.PROT_WRITE": "syscall",
+ "syscall.PROV_DH_SCHANNEL": "syscall",
+ "syscall.PROV_DSS": "syscall",
+ "syscall.PROV_DSS_DH": "syscall",
+ "syscall.PROV_EC_ECDSA_FULL": "syscall",
+ "syscall.PROV_EC_ECDSA_SIG": "syscall",
+ "syscall.PROV_EC_ECNRA_FULL": "syscall",
+ "syscall.PROV_EC_ECNRA_SIG": "syscall",
+ "syscall.PROV_FORTEZZA": "syscall",
+ "syscall.PROV_INTEL_SEC": "syscall",
+ "syscall.PROV_MS_EXCHANGE": "syscall",
+ "syscall.PROV_REPLACE_OWF": "syscall",
+ "syscall.PROV_RNG": "syscall",
+ "syscall.PROV_RSA_AES": "syscall",
+ "syscall.PROV_RSA_FULL": "syscall",
+ "syscall.PROV_RSA_SCHANNEL": "syscall",
+ "syscall.PROV_RSA_SIG": "syscall",
+ "syscall.PROV_SPYRUS_LYNKS": "syscall",
+ "syscall.PROV_SSL": "syscall",
+ "syscall.PR_CAPBSET_DROP": "syscall",
+ "syscall.PR_CAPBSET_READ": "syscall",
+ "syscall.PR_CLEAR_SECCOMP_FILTER": "syscall",
+ "syscall.PR_ENDIAN_BIG": "syscall",
+ "syscall.PR_ENDIAN_LITTLE": "syscall",
+ "syscall.PR_ENDIAN_PPC_LITTLE": "syscall",
+ "syscall.PR_FPEMU_NOPRINT": "syscall",
+ "syscall.PR_FPEMU_SIGFPE": "syscall",
+ "syscall.PR_FP_EXC_ASYNC": "syscall",
+ "syscall.PR_FP_EXC_DISABLED": "syscall",
+ "syscall.PR_FP_EXC_DIV": "syscall",
+ "syscall.PR_FP_EXC_INV": "syscall",
+ "syscall.PR_FP_EXC_NONRECOV": "syscall",
+ "syscall.PR_FP_EXC_OVF": "syscall",
+ "syscall.PR_FP_EXC_PRECISE": "syscall",
+ "syscall.PR_FP_EXC_RES": "syscall",
+ "syscall.PR_FP_EXC_SW_ENABLE": "syscall",
+ "syscall.PR_FP_EXC_UND": "syscall",
+ "syscall.PR_GET_DUMPABLE": "syscall",
+ "syscall.PR_GET_ENDIAN": "syscall",
+ "syscall.PR_GET_FPEMU": "syscall",
+ "syscall.PR_GET_FPEXC": "syscall",
+ "syscall.PR_GET_KEEPCAPS": "syscall",
+ "syscall.PR_GET_NAME": "syscall",
+ "syscall.PR_GET_PDEATHSIG": "syscall",
+ "syscall.PR_GET_SECCOMP": "syscall",
+ "syscall.PR_GET_SECCOMP_FILTER": "syscall",
+ "syscall.PR_GET_SECUREBITS": "syscall",
+ "syscall.PR_GET_TIMERSLACK": "syscall",
+ "syscall.PR_GET_TIMING": "syscall",
+ "syscall.PR_GET_TSC": "syscall",
+ "syscall.PR_GET_UNALIGN": "syscall",
+ "syscall.PR_MCE_KILL": "syscall",
+ "syscall.PR_MCE_KILL_CLEAR": "syscall",
+ "syscall.PR_MCE_KILL_DEFAULT": "syscall",
+ "syscall.PR_MCE_KILL_EARLY": "syscall",
+ "syscall.PR_MCE_KILL_GET": "syscall",
+ "syscall.PR_MCE_KILL_LATE": "syscall",
+ "syscall.PR_MCE_KILL_SET": "syscall",
+ "syscall.PR_SECCOMP_FILTER_EVENT": "syscall",
+ "syscall.PR_SECCOMP_FILTER_SYSCALL": "syscall",
+ "syscall.PR_SET_DUMPABLE": "syscall",
+ "syscall.PR_SET_ENDIAN": "syscall",
+ "syscall.PR_SET_FPEMU": "syscall",
+ "syscall.PR_SET_FPEXC": "syscall",
+ "syscall.PR_SET_KEEPCAPS": "syscall",
+ "syscall.PR_SET_NAME": "syscall",
+ "syscall.PR_SET_PDEATHSIG": "syscall",
+ "syscall.PR_SET_PTRACER": "syscall",
+ "syscall.PR_SET_SECCOMP": "syscall",
+ "syscall.PR_SET_SECCOMP_FILTER": "syscall",
+ "syscall.PR_SET_SECUREBITS": "syscall",
+ "syscall.PR_SET_TIMERSLACK": "syscall",
+ "syscall.PR_SET_TIMING": "syscall",
+ "syscall.PR_SET_TSC": "syscall",
+ "syscall.PR_SET_UNALIGN": "syscall",
+ "syscall.PR_TASK_PERF_EVENTS_DISABLE": "syscall",
+ "syscall.PR_TASK_PERF_EVENTS_ENABLE": "syscall",
+ "syscall.PR_TIMING_STATISTICAL": "syscall",
+ "syscall.PR_TIMING_TIMESTAMP": "syscall",
+ "syscall.PR_TSC_ENABLE": "syscall",
+ "syscall.PR_TSC_SIGSEGV": "syscall",
+ "syscall.PR_UNALIGN_NOPRINT": "syscall",
+ "syscall.PR_UNALIGN_SIGBUS": "syscall",
+ "syscall.PTRACE_ARCH_PRCTL": "syscall",
+ "syscall.PTRACE_ATTACH": "syscall",
+ "syscall.PTRACE_CONT": "syscall",
+ "syscall.PTRACE_DETACH": "syscall",
+ "syscall.PTRACE_EVENT_CLONE": "syscall",
+ "syscall.PTRACE_EVENT_EXEC": "syscall",
+ "syscall.PTRACE_EVENT_EXIT": "syscall",
+ "syscall.PTRACE_EVENT_FORK": "syscall",
+ "syscall.PTRACE_EVENT_VFORK": "syscall",
+ "syscall.PTRACE_EVENT_VFORK_DONE": "syscall",
+ "syscall.PTRACE_GETCRUNCHREGS": "syscall",
+ "syscall.PTRACE_GETEVENTMSG": "syscall",
+ "syscall.PTRACE_GETFPREGS": "syscall",
+ "syscall.PTRACE_GETFPXREGS": "syscall",
+ "syscall.PTRACE_GETHBPREGS": "syscall",
+ "syscall.PTRACE_GETREGS": "syscall",
+ "syscall.PTRACE_GETREGSET": "syscall",
+ "syscall.PTRACE_GETSIGINFO": "syscall",
+ "syscall.PTRACE_GETVFPREGS": "syscall",
+ "syscall.PTRACE_GETWMMXREGS": "syscall",
+ "syscall.PTRACE_GET_THREAD_AREA": "syscall",
+ "syscall.PTRACE_KILL": "syscall",
+ "syscall.PTRACE_OLDSETOPTIONS": "syscall",
+ "syscall.PTRACE_O_MASK": "syscall",
+ "syscall.PTRACE_O_TRACECLONE": "syscall",
+ "syscall.PTRACE_O_TRACEEXEC": "syscall",
+ "syscall.PTRACE_O_TRACEEXIT": "syscall",
+ "syscall.PTRACE_O_TRACEFORK": "syscall",
+ "syscall.PTRACE_O_TRACESYSGOOD": "syscall",
+ "syscall.PTRACE_O_TRACEVFORK": "syscall",
+ "syscall.PTRACE_O_TRACEVFORKDONE": "syscall",
+ "syscall.PTRACE_PEEKDATA": "syscall",
+ "syscall.PTRACE_PEEKTEXT": "syscall",
+ "syscall.PTRACE_PEEKUSR": "syscall",
+ "syscall.PTRACE_POKEDATA": "syscall",
+ "syscall.PTRACE_POKETEXT": "syscall",
+ "syscall.PTRACE_POKEUSR": "syscall",
+ "syscall.PTRACE_SETCRUNCHREGS": "syscall",
+ "syscall.PTRACE_SETFPREGS": "syscall",
+ "syscall.PTRACE_SETFPXREGS": "syscall",
+ "syscall.PTRACE_SETHBPREGS": "syscall",
+ "syscall.PTRACE_SETOPTIONS": "syscall",
+ "syscall.PTRACE_SETREGS": "syscall",
+ "syscall.PTRACE_SETREGSET": "syscall",
+ "syscall.PTRACE_SETSIGINFO": "syscall",
+ "syscall.PTRACE_SETVFPREGS": "syscall",
+ "syscall.PTRACE_SETWMMXREGS": "syscall",
+ "syscall.PTRACE_SET_SYSCALL": "syscall",
+ "syscall.PTRACE_SET_THREAD_AREA": "syscall",
+ "syscall.PTRACE_SINGLEBLOCK": "syscall",
+ "syscall.PTRACE_SINGLESTEP": "syscall",
+ "syscall.PTRACE_SYSCALL": "syscall",
+ "syscall.PTRACE_SYSEMU": "syscall",
+ "syscall.PTRACE_SYSEMU_SINGLESTEP": "syscall",
+ "syscall.PTRACE_TRACEME": "syscall",
+ "syscall.PT_ATTACH": "syscall",
+ "syscall.PT_ATTACHEXC": "syscall",
+ "syscall.PT_CONTINUE": "syscall",
+ "syscall.PT_DATA_ADDR": "syscall",
+ "syscall.PT_DENY_ATTACH": "syscall",
+ "syscall.PT_DETACH": "syscall",
+ "syscall.PT_FIRSTMACH": "syscall",
+ "syscall.PT_FORCEQUOTA": "syscall",
+ "syscall.PT_KILL": "syscall",
+ "syscall.PT_MASK": "syscall",
+ "syscall.PT_READ_D": "syscall",
+ "syscall.PT_READ_I": "syscall",
+ "syscall.PT_READ_U": "syscall",
+ "syscall.PT_SIGEXC": "syscall",
+ "syscall.PT_STEP": "syscall",
+ "syscall.PT_TEXT_ADDR": "syscall",
+ "syscall.PT_TEXT_END_ADDR": "syscall",
+ "syscall.PT_THUPDATE": "syscall",
+ "syscall.PT_TRACE_ME": "syscall",
+ "syscall.PT_WRITE_D": "syscall",
+ "syscall.PT_WRITE_I": "syscall",
+ "syscall.PT_WRITE_U": "syscall",
+ "syscall.ParseDirent": "syscall",
+ "syscall.ParseNetlinkMessage": "syscall",
+ "syscall.ParseNetlinkRouteAttr": "syscall",
+ "syscall.ParseRoutingMessage": "syscall",
+ "syscall.ParseRoutingSockaddr": "syscall",
+ "syscall.ParseSocketControlMessage": "syscall",
+ "syscall.ParseUnixCredentials": "syscall",
+ "syscall.ParseUnixRights": "syscall",
+ "syscall.PathMax": "syscall",
+ "syscall.Pathconf": "syscall",
+ "syscall.Pause": "syscall",
+ "syscall.Pipe": "syscall",
+ "syscall.Pipe2": "syscall",
+ "syscall.PivotRoot": "syscall",
+ "syscall.PostQueuedCompletionStatus": "syscall",
+ "syscall.Pread": "syscall",
+ "syscall.Proc": "syscall",
+ "syscall.ProcAttr": "syscall",
+ "syscall.ProcessInformation": "syscall",
+ "syscall.Protoent": "syscall",
+ "syscall.PtraceAttach": "syscall",
+ "syscall.PtraceCont": "syscall",
+ "syscall.PtraceDetach": "syscall",
+ "syscall.PtraceGetEventMsg": "syscall",
+ "syscall.PtraceGetRegs": "syscall",
+ "syscall.PtracePeekData": "syscall",
+ "syscall.PtracePeekText": "syscall",
+ "syscall.PtracePokeData": "syscall",
+ "syscall.PtracePokeText": "syscall",
+ "syscall.PtraceRegs": "syscall",
+ "syscall.PtraceSetOptions": "syscall",
+ "syscall.PtraceSetRegs": "syscall",
+ "syscall.PtraceSingleStep": "syscall",
+ "syscall.PtraceSyscall": "syscall",
+ "syscall.Pwrite": "syscall",
+ "syscall.REG_BINARY": "syscall",
+ "syscall.REG_DWORD": "syscall",
+ "syscall.REG_DWORD_BIG_ENDIAN": "syscall",
+ "syscall.REG_DWORD_LITTLE_ENDIAN": "syscall",
+ "syscall.REG_EXPAND_SZ": "syscall",
+ "syscall.REG_FULL_RESOURCE_DESCRIPTOR": "syscall",
+ "syscall.REG_LINK": "syscall",
+ "syscall.REG_MULTI_SZ": "syscall",
+ "syscall.REG_NONE": "syscall",
+ "syscall.REG_QWORD": "syscall",
+ "syscall.REG_QWORD_LITTLE_ENDIAN": "syscall",
+ "syscall.REG_RESOURCE_LIST": "syscall",
+ "syscall.REG_RESOURCE_REQUIREMENTS_LIST": "syscall",
+ "syscall.REG_SZ": "syscall",
+ "syscall.RLIMIT_AS": "syscall",
+ "syscall.RLIMIT_CORE": "syscall",
+ "syscall.RLIMIT_CPU": "syscall",
+ "syscall.RLIMIT_DATA": "syscall",
+ "syscall.RLIMIT_FSIZE": "syscall",
+ "syscall.RLIMIT_NOFILE": "syscall",
+ "syscall.RLIMIT_STACK": "syscall",
+ "syscall.RLIM_INFINITY": "syscall",
+ "syscall.RTAX_ADVMSS": "syscall",
+ "syscall.RTAX_AUTHOR": "syscall",
+ "syscall.RTAX_BRD": "syscall",
+ "syscall.RTAX_CWND": "syscall",
+ "syscall.RTAX_DST": "syscall",
+ "syscall.RTAX_FEATURES": "syscall",
+ "syscall.RTAX_FEATURE_ALLFRAG": "syscall",
+ "syscall.RTAX_FEATURE_ECN": "syscall",
+ "syscall.RTAX_FEATURE_SACK": "syscall",
+ "syscall.RTAX_FEATURE_TIMESTAMP": "syscall",
+ "syscall.RTAX_GATEWAY": "syscall",
+ "syscall.RTAX_GENMASK": "syscall",
+ "syscall.RTAX_HOPLIMIT": "syscall",
+ "syscall.RTAX_IFA": "syscall",
+ "syscall.RTAX_IFP": "syscall",
+ "syscall.RTAX_INITCWND": "syscall",
+ "syscall.RTAX_INITRWND": "syscall",
+ "syscall.RTAX_LABEL": "syscall",
+ "syscall.RTAX_LOCK": "syscall",
+ "syscall.RTAX_MAX": "syscall",
+ "syscall.RTAX_MTU": "syscall",
+ "syscall.RTAX_NETMASK": "syscall",
+ "syscall.RTAX_REORDERING": "syscall",
+ "syscall.RTAX_RTO_MIN": "syscall",
+ "syscall.RTAX_RTT": "syscall",
+ "syscall.RTAX_RTTVAR": "syscall",
+ "syscall.RTAX_SRC": "syscall",
+ "syscall.RTAX_SRCMASK": "syscall",
+ "syscall.RTAX_SSTHRESH": "syscall",
+ "syscall.RTAX_TAG": "syscall",
+ "syscall.RTAX_UNSPEC": "syscall",
+ "syscall.RTAX_WINDOW": "syscall",
+ "syscall.RTA_ALIGNTO": "syscall",
+ "syscall.RTA_AUTHOR": "syscall",
+ "syscall.RTA_BRD": "syscall",
+ "syscall.RTA_CACHEINFO": "syscall",
+ "syscall.RTA_DST": "syscall",
+ "syscall.RTA_FLOW": "syscall",
+ "syscall.RTA_GATEWAY": "syscall",
+ "syscall.RTA_GENMASK": "syscall",
+ "syscall.RTA_IFA": "syscall",
+ "syscall.RTA_IFP": "syscall",
+ "syscall.RTA_IIF": "syscall",
+ "syscall.RTA_LABEL": "syscall",
+ "syscall.RTA_MAX": "syscall",
+ "syscall.RTA_METRICS": "syscall",
+ "syscall.RTA_MULTIPATH": "syscall",
+ "syscall.RTA_NETMASK": "syscall",
+ "syscall.RTA_OIF": "syscall",
+ "syscall.RTA_PREFSRC": "syscall",
+ "syscall.RTA_PRIORITY": "syscall",
+ "syscall.RTA_SRC": "syscall",
+ "syscall.RTA_SRCMASK": "syscall",
+ "syscall.RTA_TABLE": "syscall",
+ "syscall.RTA_TAG": "syscall",
+ "syscall.RTA_UNSPEC": "syscall",
+ "syscall.RTCF_DIRECTSRC": "syscall",
+ "syscall.RTCF_DOREDIRECT": "syscall",
+ "syscall.RTCF_LOG": "syscall",
+ "syscall.RTCF_MASQ": "syscall",
+ "syscall.RTCF_NAT": "syscall",
+ "syscall.RTCF_VALVE": "syscall",
+ "syscall.RTF_ADDRCLASSMASK": "syscall",
+ "syscall.RTF_ADDRCONF": "syscall",
+ "syscall.RTF_ALLONLINK": "syscall",
+ "syscall.RTF_ANNOUNCE": "syscall",
+ "syscall.RTF_BLACKHOLE": "syscall",
+ "syscall.RTF_BROADCAST": "syscall",
+ "syscall.RTF_CACHE": "syscall",
+ "syscall.RTF_CLONED": "syscall",
+ "syscall.RTF_CLONING": "syscall",
+ "syscall.RTF_CONDEMNED": "syscall",
+ "syscall.RTF_DEFAULT": "syscall",
+ "syscall.RTF_DELCLONE": "syscall",
+ "syscall.RTF_DONE": "syscall",
+ "syscall.RTF_DYNAMIC": "syscall",
+ "syscall.RTF_FLOW": "syscall",
+ "syscall.RTF_FMASK": "syscall",
+ "syscall.RTF_GATEWAY": "syscall",
+ "syscall.RTF_HOST": "syscall",
+ "syscall.RTF_IFREF": "syscall",
+ "syscall.RTF_IFSCOPE": "syscall",
+ "syscall.RTF_INTERFACE": "syscall",
+ "syscall.RTF_IRTT": "syscall",
+ "syscall.RTF_LINKRT": "syscall",
+ "syscall.RTF_LLDATA": "syscall",
+ "syscall.RTF_LLINFO": "syscall",
+ "syscall.RTF_LOCAL": "syscall",
+ "syscall.RTF_MASK": "syscall",
+ "syscall.RTF_MODIFIED": "syscall",
+ "syscall.RTF_MPATH": "syscall",
+ "syscall.RTF_MPLS": "syscall",
+ "syscall.RTF_MSS": "syscall",
+ "syscall.RTF_MTU": "syscall",
+ "syscall.RTF_MULTICAST": "syscall",
+ "syscall.RTF_NAT": "syscall",
+ "syscall.RTF_NOFORWARD": "syscall",
+ "syscall.RTF_NONEXTHOP": "syscall",
+ "syscall.RTF_NOPMTUDISC": "syscall",
+ "syscall.RTF_PERMANENT_ARP": "syscall",
+ "syscall.RTF_PINNED": "syscall",
+ "syscall.RTF_POLICY": "syscall",
+ "syscall.RTF_PRCLONING": "syscall",
+ "syscall.RTF_PROTO1": "syscall",
+ "syscall.RTF_PROTO2": "syscall",
+ "syscall.RTF_PROTO3": "syscall",
+ "syscall.RTF_REINSTATE": "syscall",
+ "syscall.RTF_REJECT": "syscall",
+ "syscall.RTF_RNH_LOCKED": "syscall",
+ "syscall.RTF_SOURCE": "syscall",
+ "syscall.RTF_SRC": "syscall",
+ "syscall.RTF_STATIC": "syscall",
+ "syscall.RTF_STICKY": "syscall",
+ "syscall.RTF_THROW": "syscall",
+ "syscall.RTF_TUNNEL": "syscall",
+ "syscall.RTF_UP": "syscall",
+ "syscall.RTF_USETRAILERS": "syscall",
+ "syscall.RTF_WASCLONED": "syscall",
+ "syscall.RTF_WINDOW": "syscall",
+ "syscall.RTF_XRESOLVE": "syscall",
+ "syscall.RTM_ADD": "syscall",
+ "syscall.RTM_BASE": "syscall",
+ "syscall.RTM_CHANGE": "syscall",
+ "syscall.RTM_CHGADDR": "syscall",
+ "syscall.RTM_DELACTION": "syscall",
+ "syscall.RTM_DELADDR": "syscall",
+ "syscall.RTM_DELADDRLABEL": "syscall",
+ "syscall.RTM_DELETE": "syscall",
+ "syscall.RTM_DELLINK": "syscall",
+ "syscall.RTM_DELMADDR": "syscall",
+ "syscall.RTM_DELNEIGH": "syscall",
+ "syscall.RTM_DELQDISC": "syscall",
+ "syscall.RTM_DELROUTE": "syscall",
+ "syscall.RTM_DELRULE": "syscall",
+ "syscall.RTM_DELTCLASS": "syscall",
+ "syscall.RTM_DELTFILTER": "syscall",
+ "syscall.RTM_DESYNC": "syscall",
+ "syscall.RTM_F_CLONED": "syscall",
+ "syscall.RTM_F_EQUALIZE": "syscall",
+ "syscall.RTM_F_NOTIFY": "syscall",
+ "syscall.RTM_F_PREFIX": "syscall",
+ "syscall.RTM_GET": "syscall",
+ "syscall.RTM_GET2": "syscall",
+ "syscall.RTM_GETACTION": "syscall",
+ "syscall.RTM_GETADDR": "syscall",
+ "syscall.RTM_GETADDRLABEL": "syscall",
+ "syscall.RTM_GETANYCAST": "syscall",
+ "syscall.RTM_GETDCB": "syscall",
+ "syscall.RTM_GETLINK": "syscall",
+ "syscall.RTM_GETMULTICAST": "syscall",
+ "syscall.RTM_GETNEIGH": "syscall",
+ "syscall.RTM_GETNEIGHTBL": "syscall",
+ "syscall.RTM_GETQDISC": "syscall",
+ "syscall.RTM_GETROUTE": "syscall",
+ "syscall.RTM_GETRULE": "syscall",
+ "syscall.RTM_GETTCLASS": "syscall",
+ "syscall.RTM_GETTFILTER": "syscall",
+ "syscall.RTM_IEEE80211": "syscall",
+ "syscall.RTM_IFANNOUNCE": "syscall",
+ "syscall.RTM_IFINFO": "syscall",
+ "syscall.RTM_IFINFO2": "syscall",
+ "syscall.RTM_LLINFO_UPD": "syscall",
+ "syscall.RTM_LOCK": "syscall",
+ "syscall.RTM_LOSING": "syscall",
+ "syscall.RTM_MAX": "syscall",
+ "syscall.RTM_MAXSIZE": "syscall",
+ "syscall.RTM_MISS": "syscall",
+ "syscall.RTM_NEWACTION": "syscall",
+ "syscall.RTM_NEWADDR": "syscall",
+ "syscall.RTM_NEWADDRLABEL": "syscall",
+ "syscall.RTM_NEWLINK": "syscall",
+ "syscall.RTM_NEWMADDR": "syscall",
+ "syscall.RTM_NEWMADDR2": "syscall",
+ "syscall.RTM_NEWNDUSEROPT": "syscall",
+ "syscall.RTM_NEWNEIGH": "syscall",
+ "syscall.RTM_NEWNEIGHTBL": "syscall",
+ "syscall.RTM_NEWPREFIX": "syscall",
+ "syscall.RTM_NEWQDISC": "syscall",
+ "syscall.RTM_NEWROUTE": "syscall",
+ "syscall.RTM_NEWRULE": "syscall",
+ "syscall.RTM_NEWTCLASS": "syscall",
+ "syscall.RTM_NEWTFILTER": "syscall",
+ "syscall.RTM_NR_FAMILIES": "syscall",
+ "syscall.RTM_NR_MSGTYPES": "syscall",
+ "syscall.RTM_OIFINFO": "syscall",
+ "syscall.RTM_OLDADD": "syscall",
+ "syscall.RTM_OLDDEL": "syscall",
+ "syscall.RTM_OOIFINFO": "syscall",
+ "syscall.RTM_REDIRECT": "syscall",
+ "syscall.RTM_RESOLVE": "syscall",
+ "syscall.RTM_RTTUNIT": "syscall",
+ "syscall.RTM_SETDCB": "syscall",
+ "syscall.RTM_SETGATE": "syscall",
+ "syscall.RTM_SETLINK": "syscall",
+ "syscall.RTM_SETNEIGHTBL": "syscall",
+ "syscall.RTM_VERSION": "syscall",
+ "syscall.RTNH_ALIGNTO": "syscall",
+ "syscall.RTNH_F_DEAD": "syscall",
+ "syscall.RTNH_F_ONLINK": "syscall",
+ "syscall.RTNH_F_PERVASIVE": "syscall",
+ "syscall.RTNLGRP_IPV4_IFADDR": "syscall",
+ "syscall.RTNLGRP_IPV4_MROUTE": "syscall",
+ "syscall.RTNLGRP_IPV4_ROUTE": "syscall",
+ "syscall.RTNLGRP_IPV4_RULE": "syscall",
+ "syscall.RTNLGRP_IPV6_IFADDR": "syscall",
+ "syscall.RTNLGRP_IPV6_IFINFO": "syscall",
+ "syscall.RTNLGRP_IPV6_MROUTE": "syscall",
+ "syscall.RTNLGRP_IPV6_PREFIX": "syscall",
+ "syscall.RTNLGRP_IPV6_ROUTE": "syscall",
+ "syscall.RTNLGRP_IPV6_RULE": "syscall",
+ "syscall.RTNLGRP_LINK": "syscall",
+ "syscall.RTNLGRP_ND_USEROPT": "syscall",
+ "syscall.RTNLGRP_NEIGH": "syscall",
+ "syscall.RTNLGRP_NONE": "syscall",
+ "syscall.RTNLGRP_NOTIFY": "syscall",
+ "syscall.RTNLGRP_TC": "syscall",
+ "syscall.RTN_ANYCAST": "syscall",
+ "syscall.RTN_BLACKHOLE": "syscall",
+ "syscall.RTN_BROADCAST": "syscall",
+ "syscall.RTN_LOCAL": "syscall",
+ "syscall.RTN_MAX": "syscall",
+ "syscall.RTN_MULTICAST": "syscall",
+ "syscall.RTN_NAT": "syscall",
+ "syscall.RTN_PROHIBIT": "syscall",
+ "syscall.RTN_THROW": "syscall",
+ "syscall.RTN_UNICAST": "syscall",
+ "syscall.RTN_UNREACHABLE": "syscall",
+ "syscall.RTN_UNSPEC": "syscall",
+ "syscall.RTN_XRESOLVE": "syscall",
+ "syscall.RTPROT_BIRD": "syscall",
+ "syscall.RTPROT_BOOT": "syscall",
+ "syscall.RTPROT_DHCP": "syscall",
+ "syscall.RTPROT_DNROUTED": "syscall",
+ "syscall.RTPROT_GATED": "syscall",
+ "syscall.RTPROT_KERNEL": "syscall",
+ "syscall.RTPROT_MRT": "syscall",
+ "syscall.RTPROT_NTK": "syscall",
+ "syscall.RTPROT_RA": "syscall",
+ "syscall.RTPROT_REDIRECT": "syscall",
+ "syscall.RTPROT_STATIC": "syscall",
+ "syscall.RTPROT_UNSPEC": "syscall",
+ "syscall.RTPROT_XORP": "syscall",
+ "syscall.RTPROT_ZEBRA": "syscall",
+ "syscall.RTV_EXPIRE": "syscall",
+ "syscall.RTV_HOPCOUNT": "syscall",
+ "syscall.RTV_MTU": "syscall",
+ "syscall.RTV_RPIPE": "syscall",
+ "syscall.RTV_RTT": "syscall",
+ "syscall.RTV_RTTVAR": "syscall",
+ "syscall.RTV_SPIPE": "syscall",
+ "syscall.RTV_SSTHRESH": "syscall",
+ "syscall.RTV_WEIGHT": "syscall",
+ "syscall.RT_CACHING_CONTEXT": "syscall",
+ "syscall.RT_CLASS_DEFAULT": "syscall",
+ "syscall.RT_CLASS_LOCAL": "syscall",
+ "syscall.RT_CLASS_MAIN": "syscall",
+ "syscall.RT_CLASS_MAX": "syscall",
+ "syscall.RT_CLASS_UNSPEC": "syscall",
+ "syscall.RT_DEFAULT_FIB": "syscall",
+ "syscall.RT_NORTREF": "syscall",
+ "syscall.RT_SCOPE_HOST": "syscall",
+ "syscall.RT_SCOPE_LINK": "syscall",
+ "syscall.RT_SCOPE_NOWHERE": "syscall",
+ "syscall.RT_SCOPE_SITE": "syscall",
+ "syscall.RT_SCOPE_UNIVERSE": "syscall",
+ "syscall.RT_TABLEID_MAX": "syscall",
+ "syscall.RT_TABLE_COMPAT": "syscall",
+ "syscall.RT_TABLE_DEFAULT": "syscall",
+ "syscall.RT_TABLE_LOCAL": "syscall",
+ "syscall.RT_TABLE_MAIN": "syscall",
+ "syscall.RT_TABLE_MAX": "syscall",
+ "syscall.RT_TABLE_UNSPEC": "syscall",
+ "syscall.RUSAGE_CHILDREN": "syscall",
+ "syscall.RUSAGE_SELF": "syscall",
+ "syscall.RUSAGE_THREAD": "syscall",
+ "syscall.Radvisory_t": "syscall",
+ "syscall.RawSockaddr": "syscall",
+ "syscall.RawSockaddrAny": "syscall",
+ "syscall.RawSockaddrDatalink": "syscall",
+ "syscall.RawSockaddrInet4": "syscall",
+ "syscall.RawSockaddrInet6": "syscall",
+ "syscall.RawSockaddrLinklayer": "syscall",
+ "syscall.RawSockaddrNetlink": "syscall",
+ "syscall.RawSockaddrUnix": "syscall",
+ "syscall.RawSyscall": "syscall",
+ "syscall.RawSyscall6": "syscall",
+ "syscall.Read": "syscall",
+ "syscall.ReadConsole": "syscall",
+ "syscall.ReadDirectoryChanges": "syscall",
+ "syscall.ReadDirent": "syscall",
+ "syscall.ReadFile": "syscall",
+ "syscall.Readlink": "syscall",
+ "syscall.Reboot": "syscall",
+ "syscall.Recvfrom": "syscall",
+ "syscall.Recvmsg": "syscall",
+ "syscall.RegCloseKey": "syscall",
+ "syscall.RegEnumKeyEx": "syscall",
+ "syscall.RegOpenKeyEx": "syscall",
+ "syscall.RegQueryInfoKey": "syscall",
+ "syscall.RegQueryValueEx": "syscall",
+ "syscall.RemoveDirectory": "syscall",
+ "syscall.Removexattr": "syscall",
+ "syscall.Rename": "syscall",
+ "syscall.Renameat": "syscall",
+ "syscall.Revoke": "syscall",
+ "syscall.Rlimit": "syscall",
+ "syscall.Rmdir": "syscall",
+ "syscall.RouteMessage": "syscall",
+ "syscall.RouteRIB": "syscall",
+ "syscall.RtAttr": "syscall",
+ "syscall.RtGenmsg": "syscall",
+ "syscall.RtMetrics": "syscall",
+ "syscall.RtMsg": "syscall",
+ "syscall.RtMsghdr": "syscall",
+ "syscall.RtNexthop": "syscall",
+ "syscall.Rusage": "syscall",
+ "syscall.SCM_BINTIME": "syscall",
+ "syscall.SCM_CREDENTIALS": "syscall",
+ "syscall.SCM_CREDS": "syscall",
+ "syscall.SCM_RIGHTS": "syscall",
+ "syscall.SCM_TIMESTAMP": "syscall",
+ "syscall.SCM_TIMESTAMPING": "syscall",
+ "syscall.SCM_TIMESTAMPNS": "syscall",
+ "syscall.SCM_TIMESTAMP_MONOTONIC": "syscall",
+ "syscall.SHUT_RD": "syscall",
+ "syscall.SHUT_RDWR": "syscall",
+ "syscall.SHUT_WR": "syscall",
+ "syscall.SID": "syscall",
+ "syscall.SIDAndAttributes": "syscall",
+ "syscall.SIGABRT": "syscall",
+ "syscall.SIGALRM": "syscall",
+ "syscall.SIGBUS": "syscall",
+ "syscall.SIGCHLD": "syscall",
+ "syscall.SIGCLD": "syscall",
+ "syscall.SIGCONT": "syscall",
+ "syscall.SIGEMT": "syscall",
+ "syscall.SIGFPE": "syscall",
+ "syscall.SIGHUP": "syscall",
+ "syscall.SIGILL": "syscall",
+ "syscall.SIGINFO": "syscall",
+ "syscall.SIGINT": "syscall",
+ "syscall.SIGIO": "syscall",
+ "syscall.SIGIOT": "syscall",
+ "syscall.SIGKILL": "syscall",
+ "syscall.SIGLIBRT": "syscall",
+ "syscall.SIGLWP": "syscall",
+ "syscall.SIGPIPE": "syscall",
+ "syscall.SIGPOLL": "syscall",
+ "syscall.SIGPROF": "syscall",
+ "syscall.SIGPWR": "syscall",
+ "syscall.SIGQUIT": "syscall",
+ "syscall.SIGSEGV": "syscall",
+ "syscall.SIGSTKFLT": "syscall",
+ "syscall.SIGSTOP": "syscall",
+ "syscall.SIGSYS": "syscall",
+ "syscall.SIGTERM": "syscall",
+ "syscall.SIGTHR": "syscall",
+ "syscall.SIGTRAP": "syscall",
+ "syscall.SIGTSTP": "syscall",
+ "syscall.SIGTTIN": "syscall",
+ "syscall.SIGTTOU": "syscall",
+ "syscall.SIGUNUSED": "syscall",
+ "syscall.SIGURG": "syscall",
+ "syscall.SIGUSR1": "syscall",
+ "syscall.SIGUSR2": "syscall",
+ "syscall.SIGVTALRM": "syscall",
+ "syscall.SIGWINCH": "syscall",
+ "syscall.SIGXCPU": "syscall",
+ "syscall.SIGXFSZ": "syscall",
+ "syscall.SIOCADDDLCI": "syscall",
+ "syscall.SIOCADDMULTI": "syscall",
+ "syscall.SIOCADDRT": "syscall",
+ "syscall.SIOCAIFADDR": "syscall",
+ "syscall.SIOCAIFGROUP": "syscall",
+ "syscall.SIOCALIFADDR": "syscall",
+ "syscall.SIOCARPIPLL": "syscall",
+ "syscall.SIOCATMARK": "syscall",
+ "syscall.SIOCAUTOADDR": "syscall",
+ "syscall.SIOCAUTONETMASK": "syscall",
+ "syscall.SIOCBRDGADD": "syscall",
+ "syscall.SIOCBRDGADDS": "syscall",
+ "syscall.SIOCBRDGARL": "syscall",
+ "syscall.SIOCBRDGDADDR": "syscall",
+ "syscall.SIOCBRDGDEL": "syscall",
+ "syscall.SIOCBRDGDELS": "syscall",
+ "syscall.SIOCBRDGFLUSH": "syscall",
+ "syscall.SIOCBRDGFRL": "syscall",
+ "syscall.SIOCBRDGGCACHE": "syscall",
+ "syscall.SIOCBRDGGFD": "syscall",
+ "syscall.SIOCBRDGGHT": "syscall",
+ "syscall.SIOCBRDGGIFFLGS": "syscall",
+ "syscall.SIOCBRDGGMA": "syscall",
+ "syscall.SIOCBRDGGPARAM": "syscall",
+ "syscall.SIOCBRDGGPRI": "syscall",
+ "syscall.SIOCBRDGGRL": "syscall",
+ "syscall.SIOCBRDGGSIFS": "syscall",
+ "syscall.SIOCBRDGGTO": "syscall",
+ "syscall.SIOCBRDGIFS": "syscall",
+ "syscall.SIOCBRDGRTS": "syscall",
+ "syscall.SIOCBRDGSADDR": "syscall",
+ "syscall.SIOCBRDGSCACHE": "syscall",
+ "syscall.SIOCBRDGSFD": "syscall",
+ "syscall.SIOCBRDGSHT": "syscall",
+ "syscall.SIOCBRDGSIFCOST": "syscall",
+ "syscall.SIOCBRDGSIFFLGS": "syscall",
+ "syscall.SIOCBRDGSIFPRIO": "syscall",
+ "syscall.SIOCBRDGSMA": "syscall",
+ "syscall.SIOCBRDGSPRI": "syscall",
+ "syscall.SIOCBRDGSPROTO": "syscall",
+ "syscall.SIOCBRDGSTO": "syscall",
+ "syscall.SIOCBRDGSTXHC": "syscall",
+ "syscall.SIOCDARP": "syscall",
+ "syscall.SIOCDELDLCI": "syscall",
+ "syscall.SIOCDELMULTI": "syscall",
+ "syscall.SIOCDELRT": "syscall",
+ "syscall.SIOCDEVPRIVATE": "syscall",
+ "syscall.SIOCDIFADDR": "syscall",
+ "syscall.SIOCDIFGROUP": "syscall",
+ "syscall.SIOCDIFPHYADDR": "syscall",
+ "syscall.SIOCDLIFADDR": "syscall",
+ "syscall.SIOCDRARP": "syscall",
+ "syscall.SIOCGARP": "syscall",
+ "syscall.SIOCGDRVSPEC": "syscall",
+ "syscall.SIOCGETKALIVE": "syscall",
+ "syscall.SIOCGETLABEL": "syscall",
+ "syscall.SIOCGETPFLOW": "syscall",
+ "syscall.SIOCGETPFSYNC": "syscall",
+ "syscall.SIOCGETSGCNT": "syscall",
+ "syscall.SIOCGETVIFCNT": "syscall",
+ "syscall.SIOCGETVLAN": "syscall",
+ "syscall.SIOCGHIWAT": "syscall",
+ "syscall.SIOCGIFADDR": "syscall",
+ "syscall.SIOCGIFADDRPREF": "syscall",
+ "syscall.SIOCGIFALIAS": "syscall",
+ "syscall.SIOCGIFALTMTU": "syscall",
+ "syscall.SIOCGIFASYNCMAP": "syscall",
+ "syscall.SIOCGIFBOND": "syscall",
+ "syscall.SIOCGIFBR": "syscall",
+ "syscall.SIOCGIFBRDADDR": "syscall",
+ "syscall.SIOCGIFCAP": "syscall",
+ "syscall.SIOCGIFCONF": "syscall",
+ "syscall.SIOCGIFCOUNT": "syscall",
+ "syscall.SIOCGIFDATA": "syscall",
+ "syscall.SIOCGIFDESCR": "syscall",
+ "syscall.SIOCGIFDEVMTU": "syscall",
+ "syscall.SIOCGIFDLT": "syscall",
+ "syscall.SIOCGIFDSTADDR": "syscall",
+ "syscall.SIOCGIFENCAP": "syscall",
+ "syscall.SIOCGIFFIB": "syscall",
+ "syscall.SIOCGIFFLAGS": "syscall",
+ "syscall.SIOCGIFGATTR": "syscall",
+ "syscall.SIOCGIFGENERIC": "syscall",
+ "syscall.SIOCGIFGMEMB": "syscall",
+ "syscall.SIOCGIFGROUP": "syscall",
+ "syscall.SIOCGIFHWADDR": "syscall",
+ "syscall.SIOCGIFINDEX": "syscall",
+ "syscall.SIOCGIFKPI": "syscall",
+ "syscall.SIOCGIFMAC": "syscall",
+ "syscall.SIOCGIFMAP": "syscall",
+ "syscall.SIOCGIFMEDIA": "syscall",
+ "syscall.SIOCGIFMEM": "syscall",
+ "syscall.SIOCGIFMETRIC": "syscall",
+ "syscall.SIOCGIFMTU": "syscall",
+ "syscall.SIOCGIFNAME": "syscall",
+ "syscall.SIOCGIFNETMASK": "syscall",
+ "syscall.SIOCGIFPDSTADDR": "syscall",
+ "syscall.SIOCGIFPFLAGS": "syscall",
+ "syscall.SIOCGIFPHYS": "syscall",
+ "syscall.SIOCGIFPRIORITY": "syscall",
+ "syscall.SIOCGIFPSRCADDR": "syscall",
+ "syscall.SIOCGIFRDOMAIN": "syscall",
+ "syscall.SIOCGIFRTLABEL": "syscall",
+ "syscall.SIOCGIFSLAVE": "syscall",
+ "syscall.SIOCGIFSTATUS": "syscall",
+ "syscall.SIOCGIFTIMESLOT": "syscall",
+ "syscall.SIOCGIFTXQLEN": "syscall",
+ "syscall.SIOCGIFVLAN": "syscall",
+ "syscall.SIOCGIFWAKEFLAGS": "syscall",
+ "syscall.SIOCGIFXFLAGS": "syscall",
+ "syscall.SIOCGLIFADDR": "syscall",
+ "syscall.SIOCGLIFPHYADDR": "syscall",
+ "syscall.SIOCGLIFPHYRTABLE": "syscall",
+ "syscall.SIOCGLINKSTR": "syscall",
+ "syscall.SIOCGLOWAT": "syscall",
+ "syscall.SIOCGPGRP": "syscall",
+ "syscall.SIOCGPRIVATE_0": "syscall",
+ "syscall.SIOCGPRIVATE_1": "syscall",
+ "syscall.SIOCGRARP": "syscall",
+ "syscall.SIOCGSTAMP": "syscall",
+ "syscall.SIOCGSTAMPNS": "syscall",
+ "syscall.SIOCGVH": "syscall",
+ "syscall.SIOCIFCREATE": "syscall",
+ "syscall.SIOCIFCREATE2": "syscall",
+ "syscall.SIOCIFDESTROY": "syscall",
+ "syscall.SIOCIFGCLONERS": "syscall",
+ "syscall.SIOCINITIFADDR": "syscall",
+ "syscall.SIOCPROTOPRIVATE": "syscall",
+ "syscall.SIOCRSLVMULTI": "syscall",
+ "syscall.SIOCRTMSG": "syscall",
+ "syscall.SIOCSARP": "syscall",
+ "syscall.SIOCSDRVSPEC": "syscall",
+ "syscall.SIOCSETKALIVE": "syscall",
+ "syscall.SIOCSETLABEL": "syscall",
+ "syscall.SIOCSETPFLOW": "syscall",
+ "syscall.SIOCSETPFSYNC": "syscall",
+ "syscall.SIOCSETVLAN": "syscall",
+ "syscall.SIOCSHIWAT": "syscall",
+ "syscall.SIOCSIFADDR": "syscall",
+ "syscall.SIOCSIFADDRPREF": "syscall",
+ "syscall.SIOCSIFALTMTU": "syscall",
+ "syscall.SIOCSIFASYNCMAP": "syscall",
+ "syscall.SIOCSIFBOND": "syscall",
+ "syscall.SIOCSIFBR": "syscall",
+ "syscall.SIOCSIFBRDADDR": "syscall",
+ "syscall.SIOCSIFCAP": "syscall",
+ "syscall.SIOCSIFDESCR": "syscall",
+ "syscall.SIOCSIFDSTADDR": "syscall",
+ "syscall.SIOCSIFENCAP": "syscall",
+ "syscall.SIOCSIFFIB": "syscall",
+ "syscall.SIOCSIFFLAGS": "syscall",
+ "syscall.SIOCSIFGATTR": "syscall",
+ "syscall.SIOCSIFGENERIC": "syscall",
+ "syscall.SIOCSIFHWADDR": "syscall",
+ "syscall.SIOCSIFHWBROADCAST": "syscall",
+ "syscall.SIOCSIFKPI": "syscall",
+ "syscall.SIOCSIFLINK": "syscall",
+ "syscall.SIOCSIFLLADDR": "syscall",
+ "syscall.SIOCSIFMAC": "syscall",
+ "syscall.SIOCSIFMAP": "syscall",
+ "syscall.SIOCSIFMEDIA": "syscall",
+ "syscall.SIOCSIFMEM": "syscall",
+ "syscall.SIOCSIFMETRIC": "syscall",
+ "syscall.SIOCSIFMTU": "syscall",
+ "syscall.SIOCSIFNAME": "syscall",
+ "syscall.SIOCSIFNETMASK": "syscall",
+ "syscall.SIOCSIFPFLAGS": "syscall",
+ "syscall.SIOCSIFPHYADDR": "syscall",
+ "syscall.SIOCSIFPHYS": "syscall",
+ "syscall.SIOCSIFPRIORITY": "syscall",
+ "syscall.SIOCSIFRDOMAIN": "syscall",
+ "syscall.SIOCSIFRTLABEL": "syscall",
+ "syscall.SIOCSIFRVNET": "syscall",
+ "syscall.SIOCSIFSLAVE": "syscall",
+ "syscall.SIOCSIFTIMESLOT": "syscall",
+ "syscall.SIOCSIFTXQLEN": "syscall",
+ "syscall.SIOCSIFVLAN": "syscall",
+ "syscall.SIOCSIFVNET": "syscall",
+ "syscall.SIOCSIFXFLAGS": "syscall",
+ "syscall.SIOCSLIFPHYADDR": "syscall",
+ "syscall.SIOCSLIFPHYRTABLE": "syscall",
+ "syscall.SIOCSLINKSTR": "syscall",
+ "syscall.SIOCSLOWAT": "syscall",
+ "syscall.SIOCSPGRP": "syscall",
+ "syscall.SIOCSRARP": "syscall",
+ "syscall.SIOCSVH": "syscall",
+ "syscall.SIOCZIFDATA": "syscall",
+ "syscall.SIO_GET_EXTENSION_FUNCTION_POINTER": "syscall",
+ "syscall.SIO_GET_INTERFACE_LIST": "syscall",
+ "syscall.SOCK_CLOEXEC": "syscall",
+ "syscall.SOCK_DCCP": "syscall",
+ "syscall.SOCK_DGRAM": "syscall",
+ "syscall.SOCK_FLAGS_MASK": "syscall",
+ "syscall.SOCK_MAXADDRLEN": "syscall",
+ "syscall.SOCK_NONBLOCK": "syscall",
+ "syscall.SOCK_NOSIGPIPE": "syscall",
+ "syscall.SOCK_PACKET": "syscall",
+ "syscall.SOCK_RAW": "syscall",
+ "syscall.SOCK_RDM": "syscall",
+ "syscall.SOCK_SEQPACKET": "syscall",
+ "syscall.SOCK_STREAM": "syscall",
+ "syscall.SOL_AAL": "syscall",
+ "syscall.SOL_ATM": "syscall",
+ "syscall.SOL_DECNET": "syscall",
+ "syscall.SOL_ICMPV6": "syscall",
+ "syscall.SOL_IP": "syscall",
+ "syscall.SOL_IPV6": "syscall",
+ "syscall.SOL_IRDA": "syscall",
+ "syscall.SOL_PACKET": "syscall",
+ "syscall.SOL_RAW": "syscall",
+ "syscall.SOL_SOCKET": "syscall",
+ "syscall.SOL_TCP": "syscall",
+ "syscall.SOL_X25": "syscall",
+ "syscall.SOMAXCONN": "syscall",
+ "syscall.SO_ACCEPTCONN": "syscall",
+ "syscall.SO_ACCEPTFILTER": "syscall",
+ "syscall.SO_ATTACH_FILTER": "syscall",
+ "syscall.SO_BINDANY": "syscall",
+ "syscall.SO_BINDTODEVICE": "syscall",
+ "syscall.SO_BINTIME": "syscall",
+ "syscall.SO_BROADCAST": "syscall",
+ "syscall.SO_BSDCOMPAT": "syscall",
+ "syscall.SO_DEBUG": "syscall",
+ "syscall.SO_DETACH_FILTER": "syscall",
+ "syscall.SO_DOMAIN": "syscall",
+ "syscall.SO_DONTROUTE": "syscall",
+ "syscall.SO_DONTTRUNC": "syscall",
+ "syscall.SO_ERROR": "syscall",
+ "syscall.SO_KEEPALIVE": "syscall",
+ "syscall.SO_LABEL": "syscall",
+ "syscall.SO_LINGER": "syscall",
+ "syscall.SO_LINGER_SEC": "syscall",
+ "syscall.SO_LISTENINCQLEN": "syscall",
+ "syscall.SO_LISTENQLEN": "syscall",
+ "syscall.SO_LISTENQLIMIT": "syscall",
+ "syscall.SO_MARK": "syscall",
+ "syscall.SO_NETPROC": "syscall",
+ "syscall.SO_NKE": "syscall",
+ "syscall.SO_NOADDRERR": "syscall",
+ "syscall.SO_NOHEADER": "syscall",
+ "syscall.SO_NOSIGPIPE": "syscall",
+ "syscall.SO_NOTIFYCONFLICT": "syscall",
+ "syscall.SO_NO_CHECK": "syscall",
+ "syscall.SO_NO_DDP": "syscall",
+ "syscall.SO_NO_OFFLOAD": "syscall",
+ "syscall.SO_NP_EXTENSIONS": "syscall",
+ "syscall.SO_NREAD": "syscall",
+ "syscall.SO_NWRITE": "syscall",
+ "syscall.SO_OOBINLINE": "syscall",
+ "syscall.SO_OVERFLOWED": "syscall",
+ "syscall.SO_PASSCRED": "syscall",
+ "syscall.SO_PASSSEC": "syscall",
+ "syscall.SO_PEERCRED": "syscall",
+ "syscall.SO_PEERLABEL": "syscall",
+ "syscall.SO_PEERNAME": "syscall",
+ "syscall.SO_PEERSEC": "syscall",
+ "syscall.SO_PRIORITY": "syscall",
+ "syscall.SO_PROTOCOL": "syscall",
+ "syscall.SO_PROTOTYPE": "syscall",
+ "syscall.SO_RANDOMPORT": "syscall",
+ "syscall.SO_RCVBUF": "syscall",
+ "syscall.SO_RCVBUFFORCE": "syscall",
+ "syscall.SO_RCVLOWAT": "syscall",
+ "syscall.SO_RCVTIMEO": "syscall",
+ "syscall.SO_RESTRICTIONS": "syscall",
+ "syscall.SO_RESTRICT_DENYIN": "syscall",
+ "syscall.SO_RESTRICT_DENYOUT": "syscall",
+ "syscall.SO_RESTRICT_DENYSET": "syscall",
+ "syscall.SO_REUSEADDR": "syscall",
+ "syscall.SO_REUSEPORT": "syscall",
+ "syscall.SO_REUSESHAREUID": "syscall",
+ "syscall.SO_RTABLE": "syscall",
+ "syscall.SO_RXQ_OVFL": "syscall",
+ "syscall.SO_SECURITY_AUTHENTICATION": "syscall",
+ "syscall.SO_SECURITY_ENCRYPTION_NETWORK": "syscall",
+ "syscall.SO_SECURITY_ENCRYPTION_TRANSPORT": "syscall",
+ "syscall.SO_SETFIB": "syscall",
+ "syscall.SO_SNDBUF": "syscall",
+ "syscall.SO_SNDBUFFORCE": "syscall",
+ "syscall.SO_SNDLOWAT": "syscall",
+ "syscall.SO_SNDTIMEO": "syscall",
+ "syscall.SO_SPLICE": "syscall",
+ "syscall.SO_TIMESTAMP": "syscall",
+ "syscall.SO_TIMESTAMPING": "syscall",
+ "syscall.SO_TIMESTAMPNS": "syscall",
+ "syscall.SO_TIMESTAMP_MONOTONIC": "syscall",
+ "syscall.SO_TYPE": "syscall",
+ "syscall.SO_UPCALLCLOSEWAIT": "syscall",
+ "syscall.SO_UPDATE_ACCEPT_CONTEXT": "syscall",
+ "syscall.SO_UPDATE_CONNECT_CONTEXT": "syscall",
+ "syscall.SO_USELOOPBACK": "syscall",
+ "syscall.SO_USER_COOKIE": "syscall",
+ "syscall.SO_WANTMORE": "syscall",
+ "syscall.SO_WANTOOBFLAG": "syscall",
+ "syscall.SSLExtraCertChainPolicyPara": "syscall",
+ "syscall.STANDARD_RIGHTS_ALL": "syscall",
+ "syscall.STANDARD_RIGHTS_EXECUTE": "syscall",
+ "syscall.STANDARD_RIGHTS_READ": "syscall",
+ "syscall.STANDARD_RIGHTS_REQUIRED": "syscall",
+ "syscall.STANDARD_RIGHTS_WRITE": "syscall",
+ "syscall.STARTF_USESHOWWINDOW": "syscall",
+ "syscall.STARTF_USESTDHANDLES": "syscall",
+ "syscall.STD_ERROR_HANDLE": "syscall",
+ "syscall.STD_INPUT_HANDLE": "syscall",
+ "syscall.STD_OUTPUT_HANDLE": "syscall",
+ "syscall.SUBLANG_ENGLISH_US": "syscall",
+ "syscall.SW_FORCEMINIMIZE": "syscall",
+ "syscall.SW_HIDE": "syscall",
+ "syscall.SW_MAXIMIZE": "syscall",
+ "syscall.SW_MINIMIZE": "syscall",
+ "syscall.SW_NORMAL": "syscall",
+ "syscall.SW_RESTORE": "syscall",
+ "syscall.SW_SHOW": "syscall",
+ "syscall.SW_SHOWDEFAULT": "syscall",
+ "syscall.SW_SHOWMAXIMIZED": "syscall",
+ "syscall.SW_SHOWMINIMIZED": "syscall",
+ "syscall.SW_SHOWMINNOACTIVE": "syscall",
+ "syscall.SW_SHOWNA": "syscall",
+ "syscall.SW_SHOWNOACTIVATE": "syscall",
+ "syscall.SW_SHOWNORMAL": "syscall",
+ "syscall.SYNCHRONIZE": "syscall",
+ "syscall.SYSCTL_VERSION": "syscall",
+ "syscall.SYSCTL_VERS_0": "syscall",
+ "syscall.SYSCTL_VERS_1": "syscall",
+ "syscall.SYSCTL_VERS_MASK": "syscall",
+ "syscall.SYS_ABORT2": "syscall",
+ "syscall.SYS_ACCEPT": "syscall",
+ "syscall.SYS_ACCEPT4": "syscall",
+ "syscall.SYS_ACCEPT_NOCANCEL": "syscall",
+ "syscall.SYS_ACCESS": "syscall",
+ "syscall.SYS_ACCESS_EXTENDED": "syscall",
+ "syscall.SYS_ACCT": "syscall",
+ "syscall.SYS_ADD_KEY": "syscall",
+ "syscall.SYS_ADD_PROFIL": "syscall",
+ "syscall.SYS_ADJFREQ": "syscall",
+ "syscall.SYS_ADJTIME": "syscall",
+ "syscall.SYS_ADJTIMEX": "syscall",
+ "syscall.SYS_AFS_SYSCALL": "syscall",
+ "syscall.SYS_AIO_CANCEL": "syscall",
+ "syscall.SYS_AIO_ERROR": "syscall",
+ "syscall.SYS_AIO_FSYNC": "syscall",
+ "syscall.SYS_AIO_READ": "syscall",
+ "syscall.SYS_AIO_RETURN": "syscall",
+ "syscall.SYS_AIO_SUSPEND": "syscall",
+ "syscall.SYS_AIO_SUSPEND_NOCANCEL": "syscall",
+ "syscall.SYS_AIO_WRITE": "syscall",
+ "syscall.SYS_ALARM": "syscall",
+ "syscall.SYS_ARCH_PRCTL": "syscall",
+ "syscall.SYS_ARM_FADVISE64_64": "syscall",
+ "syscall.SYS_ARM_SYNC_FILE_RANGE": "syscall",
+ "syscall.SYS_ATGETMSG": "syscall",
+ "syscall.SYS_ATPGETREQ": "syscall",
+ "syscall.SYS_ATPGETRSP": "syscall",
+ "syscall.SYS_ATPSNDREQ": "syscall",
+ "syscall.SYS_ATPSNDRSP": "syscall",
+ "syscall.SYS_ATPUTMSG": "syscall",
+ "syscall.SYS_ATSOCKET": "syscall",
+ "syscall.SYS_AUDIT": "syscall",
+ "syscall.SYS_AUDITCTL": "syscall",
+ "syscall.SYS_AUDITON": "syscall",
+ "syscall.SYS_AUDIT_SESSION_JOIN": "syscall",
+ "syscall.SYS_AUDIT_SESSION_PORT": "syscall",
+ "syscall.SYS_AUDIT_SESSION_SELF": "syscall",
+ "syscall.SYS_BDFLUSH": "syscall",
+ "syscall.SYS_BIND": "syscall",
+ "syscall.SYS_BREAK": "syscall",
+ "syscall.SYS_BRK": "syscall",
+ "syscall.SYS_BSDTHREAD_CREATE": "syscall",
+ "syscall.SYS_BSDTHREAD_REGISTER": "syscall",
+ "syscall.SYS_BSDTHREAD_TERMINATE": "syscall",
+ "syscall.SYS_CAPGET": "syscall",
+ "syscall.SYS_CAPSET": "syscall",
+ "syscall.SYS_CAP_ENTER": "syscall",
+ "syscall.SYS_CAP_FCNTLS_GET": "syscall",
+ "syscall.SYS_CAP_FCNTLS_LIMIT": "syscall",
+ "syscall.SYS_CAP_GETMODE": "syscall",
+ "syscall.SYS_CAP_GETRIGHTS": "syscall",
+ "syscall.SYS_CAP_IOCTLS_GET": "syscall",
+ "syscall.SYS_CAP_IOCTLS_LIMIT": "syscall",
+ "syscall.SYS_CAP_NEW": "syscall",
+ "syscall.SYS_CAP_RIGHTS_GET": "syscall",
+ "syscall.SYS_CAP_RIGHTS_LIMIT": "syscall",
+ "syscall.SYS_CHDIR": "syscall",
+ "syscall.SYS_CHFLAGS": "syscall",
+ "syscall.SYS_CHMOD": "syscall",
+ "syscall.SYS_CHMOD_EXTENDED": "syscall",
+ "syscall.SYS_CHOWN": "syscall",
+ "syscall.SYS_CHOWN32": "syscall",
+ "syscall.SYS_CHROOT": "syscall",
+ "syscall.SYS_CHUD": "syscall",
+ "syscall.SYS_CLOCK_ADJTIME": "syscall",
+ "syscall.SYS_CLOCK_GETCPUCLOCKID2": "syscall",
+ "syscall.SYS_CLOCK_GETRES": "syscall",
+ "syscall.SYS_CLOCK_GETTIME": "syscall",
+ "syscall.SYS_CLOCK_NANOSLEEP": "syscall",
+ "syscall.SYS_CLOCK_SETTIME": "syscall",
+ "syscall.SYS_CLONE": "syscall",
+ "syscall.SYS_CLOSE": "syscall",
+ "syscall.SYS_CLOSEFROM": "syscall",
+ "syscall.SYS_CLOSE_NOCANCEL": "syscall",
+ "syscall.SYS_CONNECT": "syscall",
+ "syscall.SYS_CONNECT_NOCANCEL": "syscall",
+ "syscall.SYS_COPYFILE": "syscall",
+ "syscall.SYS_CPUSET": "syscall",
+ "syscall.SYS_CPUSET_GETAFFINITY": "syscall",
+ "syscall.SYS_CPUSET_GETID": "syscall",
+ "syscall.SYS_CPUSET_SETAFFINITY": "syscall",
+ "syscall.SYS_CPUSET_SETID": "syscall",
+ "syscall.SYS_CREAT": "syscall",
+ "syscall.SYS_CREATE_MODULE": "syscall",
+ "syscall.SYS_CSOPS": "syscall",
+ "syscall.SYS_DELETE": "syscall",
+ "syscall.SYS_DELETE_MODULE": "syscall",
+ "syscall.SYS_DUP": "syscall",
+ "syscall.SYS_DUP2": "syscall",
+ "syscall.SYS_DUP3": "syscall",
+ "syscall.SYS_EACCESS": "syscall",
+ "syscall.SYS_EPOLL_CREATE": "syscall",
+ "syscall.SYS_EPOLL_CREATE1": "syscall",
+ "syscall.SYS_EPOLL_CTL": "syscall",
+ "syscall.SYS_EPOLL_CTL_OLD": "syscall",
+ "syscall.SYS_EPOLL_PWAIT": "syscall",
+ "syscall.SYS_EPOLL_WAIT": "syscall",
+ "syscall.SYS_EPOLL_WAIT_OLD": "syscall",
+ "syscall.SYS_EVENTFD": "syscall",
+ "syscall.SYS_EVENTFD2": "syscall",
+ "syscall.SYS_EXCHANGEDATA": "syscall",
+ "syscall.SYS_EXECVE": "syscall",
+ "syscall.SYS_EXIT": "syscall",
+ "syscall.SYS_EXIT_GROUP": "syscall",
+ "syscall.SYS_EXTATTRCTL": "syscall",
+ "syscall.SYS_EXTATTR_DELETE_FD": "syscall",
+ "syscall.SYS_EXTATTR_DELETE_FILE": "syscall",
+ "syscall.SYS_EXTATTR_DELETE_LINK": "syscall",
+ "syscall.SYS_EXTATTR_GET_FD": "syscall",
+ "syscall.SYS_EXTATTR_GET_FILE": "syscall",
+ "syscall.SYS_EXTATTR_GET_LINK": "syscall",
+ "syscall.SYS_EXTATTR_LIST_FD": "syscall",
+ "syscall.SYS_EXTATTR_LIST_FILE": "syscall",
+ "syscall.SYS_EXTATTR_LIST_LINK": "syscall",
+ "syscall.SYS_EXTATTR_SET_FD": "syscall",
+ "syscall.SYS_EXTATTR_SET_FILE": "syscall",
+ "syscall.SYS_EXTATTR_SET_LINK": "syscall",
+ "syscall.SYS_FACCESSAT": "syscall",
+ "syscall.SYS_FADVISE64": "syscall",
+ "syscall.SYS_FADVISE64_64": "syscall",
+ "syscall.SYS_FALLOCATE": "syscall",
+ "syscall.SYS_FANOTIFY_INIT": "syscall",
+ "syscall.SYS_FANOTIFY_MARK": "syscall",
+ "syscall.SYS_FCHDIR": "syscall",
+ "syscall.SYS_FCHFLAGS": "syscall",
+ "syscall.SYS_FCHMOD": "syscall",
+ "syscall.SYS_FCHMODAT": "syscall",
+ "syscall.SYS_FCHMOD_EXTENDED": "syscall",
+ "syscall.SYS_FCHOWN": "syscall",
+ "syscall.SYS_FCHOWN32": "syscall",
+ "syscall.SYS_FCHOWNAT": "syscall",
+ "syscall.SYS_FCHROOT": "syscall",
+ "syscall.SYS_FCNTL": "syscall",
+ "syscall.SYS_FCNTL64": "syscall",
+ "syscall.SYS_FCNTL_NOCANCEL": "syscall",
+ "syscall.SYS_FDATASYNC": "syscall",
+ "syscall.SYS_FEXECVE": "syscall",
+ "syscall.SYS_FFCLOCK_GETCOUNTER": "syscall",
+ "syscall.SYS_FFCLOCK_GETESTIMATE": "syscall",
+ "syscall.SYS_FFCLOCK_SETESTIMATE": "syscall",
+ "syscall.SYS_FFSCTL": "syscall",
+ "syscall.SYS_FGETATTRLIST": "syscall",
+ "syscall.SYS_FGETXATTR": "syscall",
+ "syscall.SYS_FHOPEN": "syscall",
+ "syscall.SYS_FHSTAT": "syscall",
+ "syscall.SYS_FHSTATFS": "syscall",
+ "syscall.SYS_FILEPORT_MAKEFD": "syscall",
+ "syscall.SYS_FILEPORT_MAKEPORT": "syscall",
+ "syscall.SYS_FKTRACE": "syscall",
+ "syscall.SYS_FLISTXATTR": "syscall",
+ "syscall.SYS_FLOCK": "syscall",
+ "syscall.SYS_FORK": "syscall",
+ "syscall.SYS_FPATHCONF": "syscall",
+ "syscall.SYS_FREEBSD6_FTRUNCATE": "syscall",
+ "syscall.SYS_FREEBSD6_LSEEK": "syscall",
+ "syscall.SYS_FREEBSD6_MMAP": "syscall",
+ "syscall.SYS_FREEBSD6_PREAD": "syscall",
+ "syscall.SYS_FREEBSD6_PWRITE": "syscall",
+ "syscall.SYS_FREEBSD6_TRUNCATE": "syscall",
+ "syscall.SYS_FREMOVEXATTR": "syscall",
+ "syscall.SYS_FSCTL": "syscall",
+ "syscall.SYS_FSETATTRLIST": "syscall",
+ "syscall.SYS_FSETXATTR": "syscall",
+ "syscall.SYS_FSGETPATH": "syscall",
+ "syscall.SYS_FSTAT": "syscall",
+ "syscall.SYS_FSTAT64": "syscall",
+ "syscall.SYS_FSTAT64_EXTENDED": "syscall",
+ "syscall.SYS_FSTATAT": "syscall",
+ "syscall.SYS_FSTATAT64": "syscall",
+ "syscall.SYS_FSTATFS": "syscall",
+ "syscall.SYS_FSTATFS64": "syscall",
+ "syscall.SYS_FSTATV": "syscall",
+ "syscall.SYS_FSTATVFS1": "syscall",
+ "syscall.SYS_FSTAT_EXTENDED": "syscall",
+ "syscall.SYS_FSYNC": "syscall",
+ "syscall.SYS_FSYNC_NOCANCEL": "syscall",
+ "syscall.SYS_FSYNC_RANGE": "syscall",
+ "syscall.SYS_FTIME": "syscall",
+ "syscall.SYS_FTRUNCATE": "syscall",
+ "syscall.SYS_FTRUNCATE64": "syscall",
+ "syscall.SYS_FUTEX": "syscall",
+ "syscall.SYS_FUTIMENS": "syscall",
+ "syscall.SYS_FUTIMES": "syscall",
+ "syscall.SYS_FUTIMESAT": "syscall",
+ "syscall.SYS_GETATTRLIST": "syscall",
+ "syscall.SYS_GETAUDIT": "syscall",
+ "syscall.SYS_GETAUDIT_ADDR": "syscall",
+ "syscall.SYS_GETAUID": "syscall",
+ "syscall.SYS_GETCONTEXT": "syscall",
+ "syscall.SYS_GETCPU": "syscall",
+ "syscall.SYS_GETCWD": "syscall",
+ "syscall.SYS_GETDENTS": "syscall",
+ "syscall.SYS_GETDENTS64": "syscall",
+ "syscall.SYS_GETDIRENTRIES": "syscall",
+ "syscall.SYS_GETDIRENTRIES64": "syscall",
+ "syscall.SYS_GETDIRENTRIESATTR": "syscall",
+ "syscall.SYS_GETDTABLECOUNT": "syscall",
+ "syscall.SYS_GETDTABLESIZE": "syscall",
+ "syscall.SYS_GETEGID": "syscall",
+ "syscall.SYS_GETEGID32": "syscall",
+ "syscall.SYS_GETEUID": "syscall",
+ "syscall.SYS_GETEUID32": "syscall",
+ "syscall.SYS_GETFH": "syscall",
+ "syscall.SYS_GETFSSTAT": "syscall",
+ "syscall.SYS_GETFSSTAT64": "syscall",
+ "syscall.SYS_GETGID": "syscall",
+ "syscall.SYS_GETGID32": "syscall",
+ "syscall.SYS_GETGROUPS": "syscall",
+ "syscall.SYS_GETGROUPS32": "syscall",
+ "syscall.SYS_GETHOSTUUID": "syscall",
+ "syscall.SYS_GETITIMER": "syscall",
+ "syscall.SYS_GETLCID": "syscall",
+ "syscall.SYS_GETLOGIN": "syscall",
+ "syscall.SYS_GETLOGINCLASS": "syscall",
+ "syscall.SYS_GETPEERNAME": "syscall",
+ "syscall.SYS_GETPGID": "syscall",
+ "syscall.SYS_GETPGRP": "syscall",
+ "syscall.SYS_GETPID": "syscall",
+ "syscall.SYS_GETPMSG": "syscall",
+ "syscall.SYS_GETPPID": "syscall",
+ "syscall.SYS_GETPRIORITY": "syscall",
+ "syscall.SYS_GETRESGID": "syscall",
+ "syscall.SYS_GETRESGID32": "syscall",
+ "syscall.SYS_GETRESUID": "syscall",
+ "syscall.SYS_GETRESUID32": "syscall",
+ "syscall.SYS_GETRLIMIT": "syscall",
+ "syscall.SYS_GETRTABLE": "syscall",
+ "syscall.SYS_GETRUSAGE": "syscall",
+ "syscall.SYS_GETSGROUPS": "syscall",
+ "syscall.SYS_GETSID": "syscall",
+ "syscall.SYS_GETSOCKNAME": "syscall",
+ "syscall.SYS_GETSOCKOPT": "syscall",
+ "syscall.SYS_GETTHRID": "syscall",
+ "syscall.SYS_GETTID": "syscall",
+ "syscall.SYS_GETTIMEOFDAY": "syscall",
+ "syscall.SYS_GETUID": "syscall",
+ "syscall.SYS_GETUID32": "syscall",
+ "syscall.SYS_GETVFSSTAT": "syscall",
+ "syscall.SYS_GETWGROUPS": "syscall",
+ "syscall.SYS_GETXATTR": "syscall",
+ "syscall.SYS_GET_KERNEL_SYMS": "syscall",
+ "syscall.SYS_GET_MEMPOLICY": "syscall",
+ "syscall.SYS_GET_ROBUST_LIST": "syscall",
+ "syscall.SYS_GET_THREAD_AREA": "syscall",
+ "syscall.SYS_GTTY": "syscall",
+ "syscall.SYS_IDENTITYSVC": "syscall",
+ "syscall.SYS_IDLE": "syscall",
+ "syscall.SYS_INITGROUPS": "syscall",
+ "syscall.SYS_INIT_MODULE": "syscall",
+ "syscall.SYS_INOTIFY_ADD_WATCH": "syscall",
+ "syscall.SYS_INOTIFY_INIT": "syscall",
+ "syscall.SYS_INOTIFY_INIT1": "syscall",
+ "syscall.SYS_INOTIFY_RM_WATCH": "syscall",
+ "syscall.SYS_IOCTL": "syscall",
+ "syscall.SYS_IOPERM": "syscall",
+ "syscall.SYS_IOPL": "syscall",
+ "syscall.SYS_IOPOLICYSYS": "syscall",
+ "syscall.SYS_IOPRIO_GET": "syscall",
+ "syscall.SYS_IOPRIO_SET": "syscall",
+ "syscall.SYS_IO_CANCEL": "syscall",
+ "syscall.SYS_IO_DESTROY": "syscall",
+ "syscall.SYS_IO_GETEVENTS": "syscall",
+ "syscall.SYS_IO_SETUP": "syscall",
+ "syscall.SYS_IO_SUBMIT": "syscall",
+ "syscall.SYS_IPC": "syscall",
+ "syscall.SYS_ISSETUGID": "syscall",
+ "syscall.SYS_JAIL": "syscall",
+ "syscall.SYS_JAIL_ATTACH": "syscall",
+ "syscall.SYS_JAIL_GET": "syscall",
+ "syscall.SYS_JAIL_REMOVE": "syscall",
+ "syscall.SYS_JAIL_SET": "syscall",
+ "syscall.SYS_KDEBUG_TRACE": "syscall",
+ "syscall.SYS_KENV": "syscall",
+ "syscall.SYS_KEVENT": "syscall",
+ "syscall.SYS_KEVENT64": "syscall",
+ "syscall.SYS_KEXEC_LOAD": "syscall",
+ "syscall.SYS_KEYCTL": "syscall",
+ "syscall.SYS_KILL": "syscall",
+ "syscall.SYS_KLDFIND": "syscall",
+ "syscall.SYS_KLDFIRSTMOD": "syscall",
+ "syscall.SYS_KLDLOAD": "syscall",
+ "syscall.SYS_KLDNEXT": "syscall",
+ "syscall.SYS_KLDSTAT": "syscall",
+ "syscall.SYS_KLDSYM": "syscall",
+ "syscall.SYS_KLDUNLOAD": "syscall",
+ "syscall.SYS_KLDUNLOADF": "syscall",
+ "syscall.SYS_KQUEUE": "syscall",
+ "syscall.SYS_KQUEUE1": "syscall",
+ "syscall.SYS_KTIMER_CREATE": "syscall",
+ "syscall.SYS_KTIMER_DELETE": "syscall",
+ "syscall.SYS_KTIMER_GETOVERRUN": "syscall",
+ "syscall.SYS_KTIMER_GETTIME": "syscall",
+ "syscall.SYS_KTIMER_SETTIME": "syscall",
+ "syscall.SYS_KTRACE": "syscall",
+ "syscall.SYS_LCHFLAGS": "syscall",
+ "syscall.SYS_LCHMOD": "syscall",
+ "syscall.SYS_LCHOWN": "syscall",
+ "syscall.SYS_LCHOWN32": "syscall",
+ "syscall.SYS_LGETFH": "syscall",
+ "syscall.SYS_LGETXATTR": "syscall",
+ "syscall.SYS_LINK": "syscall",
+ "syscall.SYS_LINKAT": "syscall",
+ "syscall.SYS_LIO_LISTIO": "syscall",
+ "syscall.SYS_LISTEN": "syscall",
+ "syscall.SYS_LISTXATTR": "syscall",
+ "syscall.SYS_LLISTXATTR": "syscall",
+ "syscall.SYS_LOCK": "syscall",
+ "syscall.SYS_LOOKUP_DCOOKIE": "syscall",
+ "syscall.SYS_LPATHCONF": "syscall",
+ "syscall.SYS_LREMOVEXATTR": "syscall",
+ "syscall.SYS_LSEEK": "syscall",
+ "syscall.SYS_LSETXATTR": "syscall",
+ "syscall.SYS_LSTAT": "syscall",
+ "syscall.SYS_LSTAT64": "syscall",
+ "syscall.SYS_LSTAT64_EXTENDED": "syscall",
+ "syscall.SYS_LSTATV": "syscall",
+ "syscall.SYS_LSTAT_EXTENDED": "syscall",
+ "syscall.SYS_LUTIMES": "syscall",
+ "syscall.SYS_MAC_SYSCALL": "syscall",
+ "syscall.SYS_MADVISE": "syscall",
+ "syscall.SYS_MADVISE1": "syscall",
+ "syscall.SYS_MAXSYSCALL": "syscall",
+ "syscall.SYS_MBIND": "syscall",
+ "syscall.SYS_MIGRATE_PAGES": "syscall",
+ "syscall.SYS_MINCORE": "syscall",
+ "syscall.SYS_MINHERIT": "syscall",
+ "syscall.SYS_MKCOMPLEX": "syscall",
+ "syscall.SYS_MKDIR": "syscall",
+ "syscall.SYS_MKDIRAT": "syscall",
+ "syscall.SYS_MKDIR_EXTENDED": "syscall",
+ "syscall.SYS_MKFIFO": "syscall",
+ "syscall.SYS_MKFIFOAT": "syscall",
+ "syscall.SYS_MKFIFO_EXTENDED": "syscall",
+ "syscall.SYS_MKNOD": "syscall",
+ "syscall.SYS_MKNODAT": "syscall",
+ "syscall.SYS_MLOCK": "syscall",
+ "syscall.SYS_MLOCKALL": "syscall",
+ "syscall.SYS_MMAP": "syscall",
+ "syscall.SYS_MMAP2": "syscall",
+ "syscall.SYS_MODCTL": "syscall",
+ "syscall.SYS_MODFIND": "syscall",
+ "syscall.SYS_MODFNEXT": "syscall",
+ "syscall.SYS_MODIFY_LDT": "syscall",
+ "syscall.SYS_MODNEXT": "syscall",
+ "syscall.SYS_MODSTAT": "syscall",
+ "syscall.SYS_MODWATCH": "syscall",
+ "syscall.SYS_MOUNT": "syscall",
+ "syscall.SYS_MOVE_PAGES": "syscall",
+ "syscall.SYS_MPROTECT": "syscall",
+ "syscall.SYS_MPX": "syscall",
+ "syscall.SYS_MQUERY": "syscall",
+ "syscall.SYS_MQ_GETSETATTR": "syscall",
+ "syscall.SYS_MQ_NOTIFY": "syscall",
+ "syscall.SYS_MQ_OPEN": "syscall",
+ "syscall.SYS_MQ_TIMEDRECEIVE": "syscall",
+ "syscall.SYS_MQ_TIMEDSEND": "syscall",
+ "syscall.SYS_MQ_UNLINK": "syscall",
+ "syscall.SYS_MREMAP": "syscall",
+ "syscall.SYS_MSGCTL": "syscall",
+ "syscall.SYS_MSGGET": "syscall",
+ "syscall.SYS_MSGRCV": "syscall",
+ "syscall.SYS_MSGRCV_NOCANCEL": "syscall",
+ "syscall.SYS_MSGSND": "syscall",
+ "syscall.SYS_MSGSND_NOCANCEL": "syscall",
+ "syscall.SYS_MSGSYS": "syscall",
+ "syscall.SYS_MSYNC": "syscall",
+ "syscall.SYS_MSYNC_NOCANCEL": "syscall",
+ "syscall.SYS_MUNLOCK": "syscall",
+ "syscall.SYS_MUNLOCKALL": "syscall",
+ "syscall.SYS_MUNMAP": "syscall",
+ "syscall.SYS_NAME_TO_HANDLE_AT": "syscall",
+ "syscall.SYS_NANOSLEEP": "syscall",
+ "syscall.SYS_NEWFSTATAT": "syscall",
+ "syscall.SYS_NFSCLNT": "syscall",
+ "syscall.SYS_NFSSERVCTL": "syscall",
+ "syscall.SYS_NFSSVC": "syscall",
+ "syscall.SYS_NFSTAT": "syscall",
+ "syscall.SYS_NICE": "syscall",
+ "syscall.SYS_NLSTAT": "syscall",
+ "syscall.SYS_NMOUNT": "syscall",
+ "syscall.SYS_NSTAT": "syscall",
+ "syscall.SYS_NTP_ADJTIME": "syscall",
+ "syscall.SYS_NTP_GETTIME": "syscall",
+ "syscall.SYS_OABI_SYSCALL_BASE": "syscall",
+ "syscall.SYS_OBREAK": "syscall",
+ "syscall.SYS_OLDFSTAT": "syscall",
+ "syscall.SYS_OLDLSTAT": "syscall",
+ "syscall.SYS_OLDOLDUNAME": "syscall",
+ "syscall.SYS_OLDSTAT": "syscall",
+ "syscall.SYS_OLDUNAME": "syscall",
+ "syscall.SYS_OPEN": "syscall",
+ "syscall.SYS_OPENAT": "syscall",
+ "syscall.SYS_OPENBSD_POLL": "syscall",
+ "syscall.SYS_OPEN_BY_HANDLE_AT": "syscall",
+ "syscall.SYS_OPEN_EXTENDED": "syscall",
+ "syscall.SYS_OPEN_NOCANCEL": "syscall",
+ "syscall.SYS_OVADVISE": "syscall",
+ "syscall.SYS_PACCEPT": "syscall",
+ "syscall.SYS_PATHCONF": "syscall",
+ "syscall.SYS_PAUSE": "syscall",
+ "syscall.SYS_PCICONFIG_IOBASE": "syscall",
+ "syscall.SYS_PCICONFIG_READ": "syscall",
+ "syscall.SYS_PCICONFIG_WRITE": "syscall",
+ "syscall.SYS_PDFORK": "syscall",
+ "syscall.SYS_PDGETPID": "syscall",
+ "syscall.SYS_PDKILL": "syscall",
+ "syscall.SYS_PERF_EVENT_OPEN": "syscall",
+ "syscall.SYS_PERSONALITY": "syscall",
+ "syscall.SYS_PID_HIBERNATE": "syscall",
+ "syscall.SYS_PID_RESUME": "syscall",
+ "syscall.SYS_PID_SHUTDOWN_SOCKETS": "syscall",
+ "syscall.SYS_PID_SUSPEND": "syscall",
+ "syscall.SYS_PIPE": "syscall",
+ "syscall.SYS_PIPE2": "syscall",
+ "syscall.SYS_PIVOT_ROOT": "syscall",
+ "syscall.SYS_PMC_CONTROL": "syscall",
+ "syscall.SYS_PMC_GET_INFO": "syscall",
+ "syscall.SYS_POLL": "syscall",
+ "syscall.SYS_POLLTS": "syscall",
+ "syscall.SYS_POLL_NOCANCEL": "syscall",
+ "syscall.SYS_POSIX_FADVISE": "syscall",
+ "syscall.SYS_POSIX_FALLOCATE": "syscall",
+ "syscall.SYS_POSIX_OPENPT": "syscall",
+ "syscall.SYS_POSIX_SPAWN": "syscall",
+ "syscall.SYS_PPOLL": "syscall",
+ "syscall.SYS_PRCTL": "syscall",
+ "syscall.SYS_PREAD": "syscall",
+ "syscall.SYS_PREAD64": "syscall",
+ "syscall.SYS_PREADV": "syscall",
+ "syscall.SYS_PREAD_NOCANCEL": "syscall",
+ "syscall.SYS_PRLIMIT64": "syscall",
+ "syscall.SYS_PROCESS_POLICY": "syscall",
+ "syscall.SYS_PROCESS_VM_READV": "syscall",
+ "syscall.SYS_PROCESS_VM_WRITEV": "syscall",
+ "syscall.SYS_PROC_INFO": "syscall",
+ "syscall.SYS_PROF": "syscall",
+ "syscall.SYS_PROFIL": "syscall",
+ "syscall.SYS_PSELECT": "syscall",
+ "syscall.SYS_PSELECT6": "syscall",
+ "syscall.SYS_PSET_ASSIGN": "syscall",
+ "syscall.SYS_PSET_CREATE": "syscall",
+ "syscall.SYS_PSET_DESTROY": "syscall",
+ "syscall.SYS_PSYNCH_CVBROAD": "syscall",
+ "syscall.SYS_PSYNCH_CVCLRPREPOST": "syscall",
+ "syscall.SYS_PSYNCH_CVSIGNAL": "syscall",
+ "syscall.SYS_PSYNCH_CVWAIT": "syscall",
+ "syscall.SYS_PSYNCH_MUTEXDROP": "syscall",
+ "syscall.SYS_PSYNCH_MUTEXWAIT": "syscall",
+ "syscall.SYS_PSYNCH_RW_DOWNGRADE": "syscall",
+ "syscall.SYS_PSYNCH_RW_LONGRDLOCK": "syscall",
+ "syscall.SYS_PSYNCH_RW_RDLOCK": "syscall",
+ "syscall.SYS_PSYNCH_RW_UNLOCK": "syscall",
+ "syscall.SYS_PSYNCH_RW_UNLOCK2": "syscall",
+ "syscall.SYS_PSYNCH_RW_UPGRADE": "syscall",
+ "syscall.SYS_PSYNCH_RW_WRLOCK": "syscall",
+ "syscall.SYS_PSYNCH_RW_YIELDWRLOCK": "syscall",
+ "syscall.SYS_PTRACE": "syscall",
+ "syscall.SYS_PUTPMSG": "syscall",
+ "syscall.SYS_PWRITE": "syscall",
+ "syscall.SYS_PWRITE64": "syscall",
+ "syscall.SYS_PWRITEV": "syscall",
+ "syscall.SYS_PWRITE_NOCANCEL": "syscall",
+ "syscall.SYS_QUERY_MODULE": "syscall",
+ "syscall.SYS_QUOTACTL": "syscall",
+ "syscall.SYS_RASCTL": "syscall",
+ "syscall.SYS_RCTL_ADD_RULE": "syscall",
+ "syscall.SYS_RCTL_GET_LIMITS": "syscall",
+ "syscall.SYS_RCTL_GET_RACCT": "syscall",
+ "syscall.SYS_RCTL_GET_RULES": "syscall",
+ "syscall.SYS_RCTL_REMOVE_RULE": "syscall",
+ "syscall.SYS_READ": "syscall",
+ "syscall.SYS_READAHEAD": "syscall",
+ "syscall.SYS_READDIR": "syscall",
+ "syscall.SYS_READLINK": "syscall",
+ "syscall.SYS_READLINKAT": "syscall",
+ "syscall.SYS_READV": "syscall",
+ "syscall.SYS_READV_NOCANCEL": "syscall",
+ "syscall.SYS_READ_NOCANCEL": "syscall",
+ "syscall.SYS_REBOOT": "syscall",
+ "syscall.SYS_RECV": "syscall",
+ "syscall.SYS_RECVFROM": "syscall",
+ "syscall.SYS_RECVFROM_NOCANCEL": "syscall",
+ "syscall.SYS_RECVMMSG": "syscall",
+ "syscall.SYS_RECVMSG": "syscall",
+ "syscall.SYS_RECVMSG_NOCANCEL": "syscall",
+ "syscall.SYS_REMAP_FILE_PAGES": "syscall",
+ "syscall.SYS_REMOVEXATTR": "syscall",
+ "syscall.SYS_RENAME": "syscall",
+ "syscall.SYS_RENAMEAT": "syscall",
+ "syscall.SYS_REQUEST_KEY": "syscall",
+ "syscall.SYS_RESTART_SYSCALL": "syscall",
+ "syscall.SYS_REVOKE": "syscall",
+ "syscall.SYS_RFORK": "syscall",
+ "syscall.SYS_RMDIR": "syscall",
+ "syscall.SYS_RTPRIO": "syscall",
+ "syscall.SYS_RTPRIO_THREAD": "syscall",
+ "syscall.SYS_RT_SIGACTION": "syscall",
+ "syscall.SYS_RT_SIGPENDING": "syscall",
+ "syscall.SYS_RT_SIGPROCMASK": "syscall",
+ "syscall.SYS_RT_SIGQUEUEINFO": "syscall",
+ "syscall.SYS_RT_SIGRETURN": "syscall",
+ "syscall.SYS_RT_SIGSUSPEND": "syscall",
+ "syscall.SYS_RT_SIGTIMEDWAIT": "syscall",
+ "syscall.SYS_RT_TGSIGQUEUEINFO": "syscall",
+ "syscall.SYS_SBRK": "syscall",
+ "syscall.SYS_SCHED_GETAFFINITY": "syscall",
+ "syscall.SYS_SCHED_GETPARAM": "syscall",
+ "syscall.SYS_SCHED_GETSCHEDULER": "syscall",
+ "syscall.SYS_SCHED_GET_PRIORITY_MAX": "syscall",
+ "syscall.SYS_SCHED_GET_PRIORITY_MIN": "syscall",
+ "syscall.SYS_SCHED_RR_GET_INTERVAL": "syscall",
+ "syscall.SYS_SCHED_SETAFFINITY": "syscall",
+ "syscall.SYS_SCHED_SETPARAM": "syscall",
+ "syscall.SYS_SCHED_SETSCHEDULER": "syscall",
+ "syscall.SYS_SCHED_YIELD": "syscall",
+ "syscall.SYS_SCTP_GENERIC_RECVMSG": "syscall",
+ "syscall.SYS_SCTP_GENERIC_SENDMSG": "syscall",
+ "syscall.SYS_SCTP_GENERIC_SENDMSG_IOV": "syscall",
+ "syscall.SYS_SCTP_PEELOFF": "syscall",
+ "syscall.SYS_SEARCHFS": "syscall",
+ "syscall.SYS_SECURITY": "syscall",
+ "syscall.SYS_SELECT": "syscall",
+ "syscall.SYS_SELECT_NOCANCEL": "syscall",
+ "syscall.SYS_SEMCONFIG": "syscall",
+ "syscall.SYS_SEMCTL": "syscall",
+ "syscall.SYS_SEMGET": "syscall",
+ "syscall.SYS_SEMOP": "syscall",
+ "syscall.SYS_SEMSYS": "syscall",
+ "syscall.SYS_SEMTIMEDOP": "syscall",
+ "syscall.SYS_SEM_CLOSE": "syscall",
+ "syscall.SYS_SEM_DESTROY": "syscall",
+ "syscall.SYS_SEM_GETVALUE": "syscall",
+ "syscall.SYS_SEM_INIT": "syscall",
+ "syscall.SYS_SEM_OPEN": "syscall",
+ "syscall.SYS_SEM_POST": "syscall",
+ "syscall.SYS_SEM_TRYWAIT": "syscall",
+ "syscall.SYS_SEM_UNLINK": "syscall",
+ "syscall.SYS_SEM_WAIT": "syscall",
+ "syscall.SYS_SEM_WAIT_NOCANCEL": "syscall",
+ "syscall.SYS_SEND": "syscall",
+ "syscall.SYS_SENDFILE": "syscall",
+ "syscall.SYS_SENDFILE64": "syscall",
+ "syscall.SYS_SENDMMSG": "syscall",
+ "syscall.SYS_SENDMSG": "syscall",
+ "syscall.SYS_SENDMSG_NOCANCEL": "syscall",
+ "syscall.SYS_SENDTO": "syscall",
+ "syscall.SYS_SENDTO_NOCANCEL": "syscall",
+ "syscall.SYS_SETATTRLIST": "syscall",
+ "syscall.SYS_SETAUDIT": "syscall",
+ "syscall.SYS_SETAUDIT_ADDR": "syscall",
+ "syscall.SYS_SETAUID": "syscall",
+ "syscall.SYS_SETCONTEXT": "syscall",
+ "syscall.SYS_SETDOMAINNAME": "syscall",
+ "syscall.SYS_SETEGID": "syscall",
+ "syscall.SYS_SETEUID": "syscall",
+ "syscall.SYS_SETFIB": "syscall",
+ "syscall.SYS_SETFSGID": "syscall",
+ "syscall.SYS_SETFSGID32": "syscall",
+ "syscall.SYS_SETFSUID": "syscall",
+ "syscall.SYS_SETFSUID32": "syscall",
+ "syscall.SYS_SETGID": "syscall",
+ "syscall.SYS_SETGID32": "syscall",
+ "syscall.SYS_SETGROUPS": "syscall",
+ "syscall.SYS_SETGROUPS32": "syscall",
+ "syscall.SYS_SETHOSTNAME": "syscall",
+ "syscall.SYS_SETITIMER": "syscall",
+ "syscall.SYS_SETLCID": "syscall",
+ "syscall.SYS_SETLOGIN": "syscall",
+ "syscall.SYS_SETLOGINCLASS": "syscall",
+ "syscall.SYS_SETNS": "syscall",
+ "syscall.SYS_SETPGID": "syscall",
+ "syscall.SYS_SETPRIORITY": "syscall",
+ "syscall.SYS_SETPRIVEXEC": "syscall",
+ "syscall.SYS_SETREGID": "syscall",
+ "syscall.SYS_SETREGID32": "syscall",
+ "syscall.SYS_SETRESGID": "syscall",
+ "syscall.SYS_SETRESGID32": "syscall",
+ "syscall.SYS_SETRESUID": "syscall",
+ "syscall.SYS_SETRESUID32": "syscall",
+ "syscall.SYS_SETREUID": "syscall",
+ "syscall.SYS_SETREUID32": "syscall",
+ "syscall.SYS_SETRLIMIT": "syscall",
+ "syscall.SYS_SETRTABLE": "syscall",
+ "syscall.SYS_SETSGROUPS": "syscall",
+ "syscall.SYS_SETSID": "syscall",
+ "syscall.SYS_SETSOCKOPT": "syscall",
+ "syscall.SYS_SETTID": "syscall",
+ "syscall.SYS_SETTID_WITH_PID": "syscall",
+ "syscall.SYS_SETTIMEOFDAY": "syscall",
+ "syscall.SYS_SETUID": "syscall",
+ "syscall.SYS_SETUID32": "syscall",
+ "syscall.SYS_SETWGROUPS": "syscall",
+ "syscall.SYS_SETXATTR": "syscall",
+ "syscall.SYS_SET_MEMPOLICY": "syscall",
+ "syscall.SYS_SET_ROBUST_LIST": "syscall",
+ "syscall.SYS_SET_THREAD_AREA": "syscall",
+ "syscall.SYS_SET_TID_ADDRESS": "syscall",
+ "syscall.SYS_SGETMASK": "syscall",
+ "syscall.SYS_SHARED_REGION_CHECK_NP": "syscall",
+ "syscall.SYS_SHARED_REGION_MAP_AND_SLIDE_NP": "syscall",
+ "syscall.SYS_SHMAT": "syscall",
+ "syscall.SYS_SHMCTL": "syscall",
+ "syscall.SYS_SHMDT": "syscall",
+ "syscall.SYS_SHMGET": "syscall",
+ "syscall.SYS_SHMSYS": "syscall",
+ "syscall.SYS_SHM_OPEN": "syscall",
+ "syscall.SYS_SHM_UNLINK": "syscall",
+ "syscall.SYS_SHUTDOWN": "syscall",
+ "syscall.SYS_SIGACTION": "syscall",
+ "syscall.SYS_SIGALTSTACK": "syscall",
+ "syscall.SYS_SIGNAL": "syscall",
+ "syscall.SYS_SIGNALFD": "syscall",
+ "syscall.SYS_SIGNALFD4": "syscall",
+ "syscall.SYS_SIGPENDING": "syscall",
+ "syscall.SYS_SIGPROCMASK": "syscall",
+ "syscall.SYS_SIGQUEUE": "syscall",
+ "syscall.SYS_SIGQUEUEINFO": "syscall",
+ "syscall.SYS_SIGRETURN": "syscall",
+ "syscall.SYS_SIGSUSPEND": "syscall",
+ "syscall.SYS_SIGSUSPEND_NOCANCEL": "syscall",
+ "syscall.SYS_SIGTIMEDWAIT": "syscall",
+ "syscall.SYS_SIGWAIT": "syscall",
+ "syscall.SYS_SIGWAITINFO": "syscall",
+ "syscall.SYS_SOCKET": "syscall",
+ "syscall.SYS_SOCKETCALL": "syscall",
+ "syscall.SYS_SOCKETPAIR": "syscall",
+ "syscall.SYS_SPLICE": "syscall",
+ "syscall.SYS_SSETMASK": "syscall",
+ "syscall.SYS_SSTK": "syscall",
+ "syscall.SYS_STACK_SNAPSHOT": "syscall",
+ "syscall.SYS_STAT": "syscall",
+ "syscall.SYS_STAT64": "syscall",
+ "syscall.SYS_STAT64_EXTENDED": "syscall",
+ "syscall.SYS_STATFS": "syscall",
+ "syscall.SYS_STATFS64": "syscall",
+ "syscall.SYS_STATV": "syscall",
+ "syscall.SYS_STATVFS1": "syscall",
+ "syscall.SYS_STAT_EXTENDED": "syscall",
+ "syscall.SYS_STIME": "syscall",
+ "syscall.SYS_STTY": "syscall",
+ "syscall.SYS_SWAPCONTEXT": "syscall",
+ "syscall.SYS_SWAPCTL": "syscall",
+ "syscall.SYS_SWAPOFF": "syscall",
+ "syscall.SYS_SWAPON": "syscall",
+ "syscall.SYS_SYMLINK": "syscall",
+ "syscall.SYS_SYMLINKAT": "syscall",
+ "syscall.SYS_SYNC": "syscall",
+ "syscall.SYS_SYNCFS": "syscall",
+ "syscall.SYS_SYNC_FILE_RANGE": "syscall",
+ "syscall.SYS_SYSARCH": "syscall",
+ "syscall.SYS_SYSCALL": "syscall",
+ "syscall.SYS_SYSCALL_BASE": "syscall",
+ "syscall.SYS_SYSFS": "syscall",
+ "syscall.SYS_SYSINFO": "syscall",
+ "syscall.SYS_SYSLOG": "syscall",
+ "syscall.SYS_TEE": "syscall",
+ "syscall.SYS_TGKILL": "syscall",
+ "syscall.SYS_THREAD_SELFID": "syscall",
+ "syscall.SYS_THR_CREATE": "syscall",
+ "syscall.SYS_THR_EXIT": "syscall",
+ "syscall.SYS_THR_KILL": "syscall",
+ "syscall.SYS_THR_KILL2": "syscall",
+ "syscall.SYS_THR_NEW": "syscall",
+ "syscall.SYS_THR_SELF": "syscall",
+ "syscall.SYS_THR_SET_NAME": "syscall",
+ "syscall.SYS_THR_SUSPEND": "syscall",
+ "syscall.SYS_THR_WAKE": "syscall",
+ "syscall.SYS_TIME": "syscall",
+ "syscall.SYS_TIMERFD_CREATE": "syscall",
+ "syscall.SYS_TIMERFD_GETTIME": "syscall",
+ "syscall.SYS_TIMERFD_SETTIME": "syscall",
+ "syscall.SYS_TIMER_CREATE": "syscall",
+ "syscall.SYS_TIMER_DELETE": "syscall",
+ "syscall.SYS_TIMER_GETOVERRUN": "syscall",
+ "syscall.SYS_TIMER_GETTIME": "syscall",
+ "syscall.SYS_TIMER_SETTIME": "syscall",
+ "syscall.SYS_TIMES": "syscall",
+ "syscall.SYS_TKILL": "syscall",
+ "syscall.SYS_TRUNCATE": "syscall",
+ "syscall.SYS_TRUNCATE64": "syscall",
+ "syscall.SYS_TUXCALL": "syscall",
+ "syscall.SYS_UGETRLIMIT": "syscall",
+ "syscall.SYS_ULIMIT": "syscall",
+ "syscall.SYS_UMASK": "syscall",
+ "syscall.SYS_UMASK_EXTENDED": "syscall",
+ "syscall.SYS_UMOUNT": "syscall",
+ "syscall.SYS_UMOUNT2": "syscall",
+ "syscall.SYS_UNAME": "syscall",
+ "syscall.SYS_UNDELETE": "syscall",
+ "syscall.SYS_UNLINK": "syscall",
+ "syscall.SYS_UNLINKAT": "syscall",
+ "syscall.SYS_UNMOUNT": "syscall",
+ "syscall.SYS_UNSHARE": "syscall",
+ "syscall.SYS_USELIB": "syscall",
+ "syscall.SYS_USTAT": "syscall",
+ "syscall.SYS_UTIME": "syscall",
+ "syscall.SYS_UTIMENSAT": "syscall",
+ "syscall.SYS_UTIMES": "syscall",
+ "syscall.SYS_UTRACE": "syscall",
+ "syscall.SYS_UUIDGEN": "syscall",
+ "syscall.SYS_VADVISE": "syscall",
+ "syscall.SYS_VFORK": "syscall",
+ "syscall.SYS_VHANGUP": "syscall",
+ "syscall.SYS_VM86": "syscall",
+ "syscall.SYS_VM86OLD": "syscall",
+ "syscall.SYS_VMSPLICE": "syscall",
+ "syscall.SYS_VM_PRESSURE_MONITOR": "syscall",
+ "syscall.SYS_VSERVER": "syscall",
+ "syscall.SYS_WAIT4": "syscall",
+ "syscall.SYS_WAIT4_NOCANCEL": "syscall",
+ "syscall.SYS_WAIT6": "syscall",
+ "syscall.SYS_WAITEVENT": "syscall",
+ "syscall.SYS_WAITID": "syscall",
+ "syscall.SYS_WAITID_NOCANCEL": "syscall",
+ "syscall.SYS_WAITPID": "syscall",
+ "syscall.SYS_WATCHEVENT": "syscall",
+ "syscall.SYS_WORKQ_KERNRETURN": "syscall",
+ "syscall.SYS_WORKQ_OPEN": "syscall",
+ "syscall.SYS_WRITE": "syscall",
+ "syscall.SYS_WRITEV": "syscall",
+ "syscall.SYS_WRITEV_NOCANCEL": "syscall",
+ "syscall.SYS_WRITE_NOCANCEL": "syscall",
+ "syscall.SYS_YIELD": "syscall",
+ "syscall.SYS__LLSEEK": "syscall",
+ "syscall.SYS__LWP_CONTINUE": "syscall",
+ "syscall.SYS__LWP_CREATE": "syscall",
+ "syscall.SYS__LWP_CTL": "syscall",
+ "syscall.SYS__LWP_DETACH": "syscall",
+ "syscall.SYS__LWP_EXIT": "syscall",
+ "syscall.SYS__LWP_GETNAME": "syscall",
+ "syscall.SYS__LWP_GETPRIVATE": "syscall",
+ "syscall.SYS__LWP_KILL": "syscall",
+ "syscall.SYS__LWP_PARK": "syscall",
+ "syscall.SYS__LWP_SELF": "syscall",
+ "syscall.SYS__LWP_SETNAME": "syscall",
+ "syscall.SYS__LWP_SETPRIVATE": "syscall",
+ "syscall.SYS__LWP_SUSPEND": "syscall",
+ "syscall.SYS__LWP_UNPARK": "syscall",
+ "syscall.SYS__LWP_UNPARK_ALL": "syscall",
+ "syscall.SYS__LWP_WAIT": "syscall",
+ "syscall.SYS__LWP_WAKEUP": "syscall",
+ "syscall.SYS__NEWSELECT": "syscall",
+ "syscall.SYS__PSET_BIND": "syscall",
+ "syscall.SYS__SCHED_GETAFFINITY": "syscall",
+ "syscall.SYS__SCHED_GETPARAM": "syscall",
+ "syscall.SYS__SCHED_SETAFFINITY": "syscall",
+ "syscall.SYS__SCHED_SETPARAM": "syscall",
+ "syscall.SYS__SYSCTL": "syscall",
+ "syscall.SYS__UMTX_LOCK": "syscall",
+ "syscall.SYS__UMTX_OP": "syscall",
+ "syscall.SYS__UMTX_UNLOCK": "syscall",
+ "syscall.SYS___ACL_ACLCHECK_FD": "syscall",
+ "syscall.SYS___ACL_ACLCHECK_FILE": "syscall",
+ "syscall.SYS___ACL_ACLCHECK_LINK": "syscall",
+ "syscall.SYS___ACL_DELETE_FD": "syscall",
+ "syscall.SYS___ACL_DELETE_FILE": "syscall",
+ "syscall.SYS___ACL_DELETE_LINK": "syscall",
+ "syscall.SYS___ACL_GET_FD": "syscall",
+ "syscall.SYS___ACL_GET_FILE": "syscall",
+ "syscall.SYS___ACL_GET_LINK": "syscall",
+ "syscall.SYS___ACL_SET_FD": "syscall",
+ "syscall.SYS___ACL_SET_FILE": "syscall",
+ "syscall.SYS___ACL_SET_LINK": "syscall",
+ "syscall.SYS___CLONE": "syscall",
+ "syscall.SYS___DISABLE_THREADSIGNAL": "syscall",
+ "syscall.SYS___GETCWD": "syscall",
+ "syscall.SYS___GETLOGIN": "syscall",
+ "syscall.SYS___GET_TCB": "syscall",
+ "syscall.SYS___MAC_EXECVE": "syscall",
+ "syscall.SYS___MAC_GETFSSTAT": "syscall",
+ "syscall.SYS___MAC_GET_FD": "syscall",
+ "syscall.SYS___MAC_GET_FILE": "syscall",
+ "syscall.SYS___MAC_GET_LCID": "syscall",
+ "syscall.SYS___MAC_GET_LCTX": "syscall",
+ "syscall.SYS___MAC_GET_LINK": "syscall",
+ "syscall.SYS___MAC_GET_MOUNT": "syscall",
+ "syscall.SYS___MAC_GET_PID": "syscall",
+ "syscall.SYS___MAC_GET_PROC": "syscall",
+ "syscall.SYS___MAC_MOUNT": "syscall",
+ "syscall.SYS___MAC_SET_FD": "syscall",
+ "syscall.SYS___MAC_SET_FILE": "syscall",
+ "syscall.SYS___MAC_SET_LCTX": "syscall",
+ "syscall.SYS___MAC_SET_LINK": "syscall",
+ "syscall.SYS___MAC_SET_PROC": "syscall",
+ "syscall.SYS___MAC_SYSCALL": "syscall",
+ "syscall.SYS___OLD_SEMWAIT_SIGNAL": "syscall",
+ "syscall.SYS___OLD_SEMWAIT_SIGNAL_NOCANCEL": "syscall",
+ "syscall.SYS___POSIX_CHOWN": "syscall",
+ "syscall.SYS___POSIX_FCHOWN": "syscall",
+ "syscall.SYS___POSIX_LCHOWN": "syscall",
+ "syscall.SYS___POSIX_RENAME": "syscall",
+ "syscall.SYS___PTHREAD_CANCELED": "syscall",
+ "syscall.SYS___PTHREAD_CHDIR": "syscall",
+ "syscall.SYS___PTHREAD_FCHDIR": "syscall",
+ "syscall.SYS___PTHREAD_KILL": "syscall",
+ "syscall.SYS___PTHREAD_MARKCANCEL": "syscall",
+ "syscall.SYS___PTHREAD_SIGMASK": "syscall",
+ "syscall.SYS___QUOTACTL": "syscall",
+ "syscall.SYS___SEMCTL": "syscall",
+ "syscall.SYS___SEMWAIT_SIGNAL": "syscall",
+ "syscall.SYS___SEMWAIT_SIGNAL_NOCANCEL": "syscall",
+ "syscall.SYS___SETLOGIN": "syscall",
+ "syscall.SYS___SETUGID": "syscall",
+ "syscall.SYS___SET_TCB": "syscall",
+ "syscall.SYS___SIGACTION_SIGTRAMP": "syscall",
+ "syscall.SYS___SIGTIMEDWAIT": "syscall",
+ "syscall.SYS___SIGWAIT": "syscall",
+ "syscall.SYS___SIGWAIT_NOCANCEL": "syscall",
+ "syscall.SYS___SYSCTL": "syscall",
+ "syscall.SYS___TFORK": "syscall",
+ "syscall.SYS___THREXIT": "syscall",
+ "syscall.SYS___THRSIGDIVERT": "syscall",
+ "syscall.SYS___THRSLEEP": "syscall",
+ "syscall.SYS___THRWAKEUP": "syscall",
+ "syscall.S_ARCH1": "syscall",
+ "syscall.S_ARCH2": "syscall",
+ "syscall.S_BLKSIZE": "syscall",
+ "syscall.S_IEXEC": "syscall",
+ "syscall.S_IFBLK": "syscall",
+ "syscall.S_IFCHR": "syscall",
+ "syscall.S_IFDIR": "syscall",
+ "syscall.S_IFIFO": "syscall",
+ "syscall.S_IFLNK": "syscall",
+ "syscall.S_IFMT": "syscall",
+ "syscall.S_IFREG": "syscall",
+ "syscall.S_IFSOCK": "syscall",
+ "syscall.S_IFWHT": "syscall",
+ "syscall.S_IREAD": "syscall",
+ "syscall.S_IRGRP": "syscall",
+ "syscall.S_IROTH": "syscall",
+ "syscall.S_IRUSR": "syscall",
+ "syscall.S_IRWXG": "syscall",
+ "syscall.S_IRWXO": "syscall",
+ "syscall.S_IRWXU": "syscall",
+ "syscall.S_ISGID": "syscall",
+ "syscall.S_ISTXT": "syscall",
+ "syscall.S_ISUID": "syscall",
+ "syscall.S_ISVTX": "syscall",
+ "syscall.S_IWGRP": "syscall",
+ "syscall.S_IWOTH": "syscall",
+ "syscall.S_IWRITE": "syscall",
+ "syscall.S_IWUSR": "syscall",
+ "syscall.S_IXGRP": "syscall",
+ "syscall.S_IXOTH": "syscall",
+ "syscall.S_IXUSR": "syscall",
+ "syscall.S_LOGIN_SET": "syscall",
+ "syscall.SecurityAttributes": "syscall",
+ "syscall.Seek": "syscall",
+ "syscall.Select": "syscall",
+ "syscall.Sendfile": "syscall",
+ "syscall.Sendmsg": "syscall",
+ "syscall.Sendto": "syscall",
+ "syscall.Servent": "syscall",
+ "syscall.SetBpf": "syscall",
+ "syscall.SetBpfBuflen": "syscall",
+ "syscall.SetBpfDatalink": "syscall",
+ "syscall.SetBpfHeadercmpl": "syscall",
+ "syscall.SetBpfImmediate": "syscall",
+ "syscall.SetBpfInterface": "syscall",
+ "syscall.SetBpfPromisc": "syscall",
+ "syscall.SetBpfTimeout": "syscall",
+ "syscall.SetCurrentDirectory": "syscall",
+ "syscall.SetEndOfFile": "syscall",
+ "syscall.SetEnvironmentVariable": "syscall",
+ "syscall.SetFileAttributes": "syscall",
+ "syscall.SetFileCompletionNotificationModes": "syscall",
+ "syscall.SetFilePointer": "syscall",
+ "syscall.SetFileTime": "syscall",
+ "syscall.SetHandleInformation": "syscall",
+ "syscall.SetKevent": "syscall",
+ "syscall.SetLsfPromisc": "syscall",
+ "syscall.SetNonblock": "syscall",
+ "syscall.Setdomainname": "syscall",
+ "syscall.Setegid": "syscall",
+ "syscall.Setenv": "syscall",
+ "syscall.Seteuid": "syscall",
+ "syscall.Setfsgid": "syscall",
+ "syscall.Setfsuid": "syscall",
+ "syscall.Setgid": "syscall",
+ "syscall.Setgroups": "syscall",
+ "syscall.Sethostname": "syscall",
+ "syscall.Setlogin": "syscall",
+ "syscall.Setpgid": "syscall",
+ "syscall.Setpriority": "syscall",
+ "syscall.Setprivexec": "syscall",
+ "syscall.Setregid": "syscall",
+ "syscall.Setresgid": "syscall",
+ "syscall.Setresuid": "syscall",
+ "syscall.Setreuid": "syscall",
+ "syscall.Setrlimit": "syscall",
+ "syscall.Setsid": "syscall",
+ "syscall.Setsockopt": "syscall",
+ "syscall.SetsockoptByte": "syscall",
+ "syscall.SetsockoptICMPv6Filter": "syscall",
+ "syscall.SetsockoptIPMreq": "syscall",
+ "syscall.SetsockoptIPMreqn": "syscall",
+ "syscall.SetsockoptIPv6Mreq": "syscall",
+ "syscall.SetsockoptInet4Addr": "syscall",
+ "syscall.SetsockoptInt": "syscall",
+ "syscall.SetsockoptLinger": "syscall",
+ "syscall.SetsockoptString": "syscall",
+ "syscall.SetsockoptTimeval": "syscall",
+ "syscall.Settimeofday": "syscall",
+ "syscall.Setuid": "syscall",
+ "syscall.Setxattr": "syscall",
+ "syscall.Shutdown": "syscall",
+ "syscall.SidTypeAlias": "syscall",
+ "syscall.SidTypeComputer": "syscall",
+ "syscall.SidTypeDeletedAccount": "syscall",
+ "syscall.SidTypeDomain": "syscall",
+ "syscall.SidTypeGroup": "syscall",
+ "syscall.SidTypeInvalid": "syscall",
+ "syscall.SidTypeLabel": "syscall",
+ "syscall.SidTypeUnknown": "syscall",
+ "syscall.SidTypeUser": "syscall",
+ "syscall.SidTypeWellKnownGroup": "syscall",
+ "syscall.Signal": "syscall",
+ "syscall.SizeofBpfHdr": "syscall",
+ "syscall.SizeofBpfInsn": "syscall",
+ "syscall.SizeofBpfProgram": "syscall",
+ "syscall.SizeofBpfStat": "syscall",
+ "syscall.SizeofBpfVersion": "syscall",
+ "syscall.SizeofBpfZbuf": "syscall",
+ "syscall.SizeofBpfZbufHeader": "syscall",
+ "syscall.SizeofCmsghdr": "syscall",
+ "syscall.SizeofICMPv6Filter": "syscall",
+ "syscall.SizeofIPMreq": "syscall",
+ "syscall.SizeofIPMreqn": "syscall",
+ "syscall.SizeofIPv6MTUInfo": "syscall",
+ "syscall.SizeofIPv6Mreq": "syscall",
+ "syscall.SizeofIfAddrmsg": "syscall",
+ "syscall.SizeofIfAnnounceMsghdr": "syscall",
+ "syscall.SizeofIfData": "syscall",
+ "syscall.SizeofIfInfomsg": "syscall",
+ "syscall.SizeofIfMsghdr": "syscall",
+ "syscall.SizeofIfaMsghdr": "syscall",
+ "syscall.SizeofIfmaMsghdr": "syscall",
+ "syscall.SizeofIfmaMsghdr2": "syscall",
+ "syscall.SizeofInet4Pktinfo": "syscall",
+ "syscall.SizeofInet6Pktinfo": "syscall",
+ "syscall.SizeofInotifyEvent": "syscall",
+ "syscall.SizeofLinger": "syscall",
+ "syscall.SizeofMsghdr": "syscall",
+ "syscall.SizeofNlAttr": "syscall",
+ "syscall.SizeofNlMsgerr": "syscall",
+ "syscall.SizeofNlMsghdr": "syscall",
+ "syscall.SizeofRtAttr": "syscall",
+ "syscall.SizeofRtGenmsg": "syscall",
+ "syscall.SizeofRtMetrics": "syscall",
+ "syscall.SizeofRtMsg": "syscall",
+ "syscall.SizeofRtMsghdr": "syscall",
+ "syscall.SizeofRtNexthop": "syscall",
+ "syscall.SizeofSockFilter": "syscall",
+ "syscall.SizeofSockFprog": "syscall",
+ "syscall.SizeofSockaddrAny": "syscall",
+ "syscall.SizeofSockaddrDatalink": "syscall",
+ "syscall.SizeofSockaddrInet4": "syscall",
+ "syscall.SizeofSockaddrInet6": "syscall",
+ "syscall.SizeofSockaddrLinklayer": "syscall",
+ "syscall.SizeofSockaddrNetlink": "syscall",
+ "syscall.SizeofSockaddrUnix": "syscall",
+ "syscall.SizeofTCPInfo": "syscall",
+ "syscall.SizeofUcred": "syscall",
+ "syscall.SlicePtrFromStrings": "syscall",
+ "syscall.SockFilter": "syscall",
+ "syscall.SockFprog": "syscall",
+ "syscall.SockaddrDatalink": "syscall",
+ "syscall.SockaddrGen": "syscall",
+ "syscall.SockaddrInet4": "syscall",
+ "syscall.SockaddrInet6": "syscall",
+ "syscall.SockaddrLinklayer": "syscall",
+ "syscall.SockaddrNetlink": "syscall",
+ "syscall.SockaddrUnix": "syscall",
+ "syscall.Socket": "syscall",
+ "syscall.SocketControlMessage": "syscall",
+ "syscall.SocketDisableIPv6": "syscall",
+ "syscall.Socketpair": "syscall",
+ "syscall.Splice": "syscall",
+ "syscall.StartProcess": "syscall",
+ "syscall.StartupInfo": "syscall",
+ "syscall.Stat": "syscall",
+ "syscall.Stat_t": "syscall",
+ "syscall.Statfs": "syscall",
+ "syscall.Statfs_t": "syscall",
+ "syscall.Stderr": "syscall",
+ "syscall.Stdin": "syscall",
+ "syscall.Stdout": "syscall",
+ "syscall.StringBytePtr": "syscall",
+ "syscall.StringByteSlice": "syscall",
+ "syscall.StringSlicePtr": "syscall",
+ "syscall.StringToSid": "syscall",
+ "syscall.StringToUTF16": "syscall",
+ "syscall.StringToUTF16Ptr": "syscall",
+ "syscall.Symlink": "syscall",
+ "syscall.Sync": "syscall",
+ "syscall.SyncFileRange": "syscall",
+ "syscall.SysProcAttr": "syscall",
+ "syscall.Syscall": "syscall",
+ "syscall.Syscall12": "syscall",
+ "syscall.Syscall15": "syscall",
+ "syscall.Syscall6": "syscall",
+ "syscall.Syscall9": "syscall",
+ "syscall.Sysctl": "syscall",
+ "syscall.SysctlUint32": "syscall",
+ "syscall.Sysctlnode": "syscall",
+ "syscall.Sysinfo": "syscall",
+ "syscall.Sysinfo_t": "syscall",
+ "syscall.Systemtime": "syscall",
+ "syscall.TCGETS": "syscall",
+ "syscall.TCIFLUSH": "syscall",
+ "syscall.TCIOFLUSH": "syscall",
+ "syscall.TCOFLUSH": "syscall",
+ "syscall.TCPInfo": "syscall",
+ "syscall.TCP_CA_NAME_MAX": "syscall",
+ "syscall.TCP_CONGCTL": "syscall",
+ "syscall.TCP_CONGESTION": "syscall",
+ "syscall.TCP_CONNECTIONTIMEOUT": "syscall",
+ "syscall.TCP_CORK": "syscall",
+ "syscall.TCP_DEFER_ACCEPT": "syscall",
+ "syscall.TCP_INFO": "syscall",
+ "syscall.TCP_KEEPALIVE": "syscall",
+ "syscall.TCP_KEEPCNT": "syscall",
+ "syscall.TCP_KEEPIDLE": "syscall",
+ "syscall.TCP_KEEPINIT": "syscall",
+ "syscall.TCP_KEEPINTVL": "syscall",
+ "syscall.TCP_LINGER2": "syscall",
+ "syscall.TCP_MAXBURST": "syscall",
+ "syscall.TCP_MAXHLEN": "syscall",
+ "syscall.TCP_MAXOLEN": "syscall",
+ "syscall.TCP_MAXSEG": "syscall",
+ "syscall.TCP_MAXWIN": "syscall",
+ "syscall.TCP_MAX_SACK": "syscall",
+ "syscall.TCP_MAX_WINSHIFT": "syscall",
+ "syscall.TCP_MD5SIG": "syscall",
+ "syscall.TCP_MD5SIG_MAXKEYLEN": "syscall",
+ "syscall.TCP_MINMSS": "syscall",
+ "syscall.TCP_MINMSSOVERLOAD": "syscall",
+ "syscall.TCP_MSS": "syscall",
+ "syscall.TCP_NODELAY": "syscall",
+ "syscall.TCP_NOOPT": "syscall",
+ "syscall.TCP_NOPUSH": "syscall",
+ "syscall.TCP_NSTATES": "syscall",
+ "syscall.TCP_QUICKACK": "syscall",
+ "syscall.TCP_RXT_CONNDROPTIME": "syscall",
+ "syscall.TCP_RXT_FINDROP": "syscall",
+ "syscall.TCP_SACK_ENABLE": "syscall",
+ "syscall.TCP_SYNCNT": "syscall",
+ "syscall.TCP_WINDOW_CLAMP": "syscall",
+ "syscall.TCSAFLUSH": "syscall",
+ "syscall.TCSETS": "syscall",
+ "syscall.TF_DISCONNECT": "syscall",
+ "syscall.TF_REUSE_SOCKET": "syscall",
+ "syscall.TF_USE_DEFAULT_WORKER": "syscall",
+ "syscall.TF_USE_KERNEL_APC": "syscall",
+ "syscall.TF_USE_SYSTEM_THREAD": "syscall",
+ "syscall.TF_WRITE_BEHIND": "syscall",
+ "syscall.TIME_ZONE_ID_DAYLIGHT": "syscall",
+ "syscall.TIME_ZONE_ID_STANDARD": "syscall",
+ "syscall.TIME_ZONE_ID_UNKNOWN": "syscall",
+ "syscall.TIOCCBRK": "syscall",
+ "syscall.TIOCCDTR": "syscall",
+ "syscall.TIOCCONS": "syscall",
+ "syscall.TIOCDCDTIMESTAMP": "syscall",
+ "syscall.TIOCDRAIN": "syscall",
+ "syscall.TIOCDSIMICROCODE": "syscall",
+ "syscall.TIOCEXCL": "syscall",
+ "syscall.TIOCEXT": "syscall",
+ "syscall.TIOCFLAG_CDTRCTS": "syscall",
+ "syscall.TIOCFLAG_CLOCAL": "syscall",
+ "syscall.TIOCFLAG_CRTSCTS": "syscall",
+ "syscall.TIOCFLAG_MDMBUF": "syscall",
+ "syscall.TIOCFLAG_PPS": "syscall",
+ "syscall.TIOCFLAG_SOFTCAR": "syscall",
+ "syscall.TIOCFLUSH": "syscall",
+ "syscall.TIOCGDEV": "syscall",
+ "syscall.TIOCGDRAINWAIT": "syscall",
+ "syscall.TIOCGETA": "syscall",
+ "syscall.TIOCGETD": "syscall",
+ "syscall.TIOCGFLAGS": "syscall",
+ "syscall.TIOCGICOUNT": "syscall",
+ "syscall.TIOCGLCKTRMIOS": "syscall",
+ "syscall.TIOCGLINED": "syscall",
+ "syscall.TIOCGPGRP": "syscall",
+ "syscall.TIOCGPTN": "syscall",
+ "syscall.TIOCGQSIZE": "syscall",
+ "syscall.TIOCGRANTPT": "syscall",
+ "syscall.TIOCGRS485": "syscall",
+ "syscall.TIOCGSERIAL": "syscall",
+ "syscall.TIOCGSID": "syscall",
+ "syscall.TIOCGSIZE": "syscall",
+ "syscall.TIOCGSOFTCAR": "syscall",
+ "syscall.TIOCGTSTAMP": "syscall",
+ "syscall.TIOCGWINSZ": "syscall",
+ "syscall.TIOCINQ": "syscall",
+ "syscall.TIOCIXOFF": "syscall",
+ "syscall.TIOCIXON": "syscall",
+ "syscall.TIOCLINUX": "syscall",
+ "syscall.TIOCMBIC": "syscall",
+ "syscall.TIOCMBIS": "syscall",
+ "syscall.TIOCMGDTRWAIT": "syscall",
+ "syscall.TIOCMGET": "syscall",
+ "syscall.TIOCMIWAIT": "syscall",
+ "syscall.TIOCMODG": "syscall",
+ "syscall.TIOCMODS": "syscall",
+ "syscall.TIOCMSDTRWAIT": "syscall",
+ "syscall.TIOCMSET": "syscall",
+ "syscall.TIOCM_CAR": "syscall",
+ "syscall.TIOCM_CD": "syscall",
+ "syscall.TIOCM_CTS": "syscall",
+ "syscall.TIOCM_DCD": "syscall",
+ "syscall.TIOCM_DSR": "syscall",
+ "syscall.TIOCM_DTR": "syscall",
+ "syscall.TIOCM_LE": "syscall",
+ "syscall.TIOCM_RI": "syscall",
+ "syscall.TIOCM_RNG": "syscall",
+ "syscall.TIOCM_RTS": "syscall",
+ "syscall.TIOCM_SR": "syscall",
+ "syscall.TIOCM_ST": "syscall",
+ "syscall.TIOCNOTTY": "syscall",
+ "syscall.TIOCNXCL": "syscall",
+ "syscall.TIOCOUTQ": "syscall",
+ "syscall.TIOCPKT": "syscall",
+ "syscall.TIOCPKT_DATA": "syscall",
+ "syscall.TIOCPKT_DOSTOP": "syscall",
+ "syscall.TIOCPKT_FLUSHREAD": "syscall",
+ "syscall.TIOCPKT_FLUSHWRITE": "syscall",
+ "syscall.TIOCPKT_IOCTL": "syscall",
+ "syscall.TIOCPKT_NOSTOP": "syscall",
+ "syscall.TIOCPKT_START": "syscall",
+ "syscall.TIOCPKT_STOP": "syscall",
+ "syscall.TIOCPTMASTER": "syscall",
+ "syscall.TIOCPTMGET": "syscall",
+ "syscall.TIOCPTSNAME": "syscall",
+ "syscall.TIOCPTYGNAME": "syscall",
+ "syscall.TIOCPTYGRANT": "syscall",
+ "syscall.TIOCPTYUNLK": "syscall",
+ "syscall.TIOCRCVFRAME": "syscall",
+ "syscall.TIOCREMOTE": "syscall",
+ "syscall.TIOCSBRK": "syscall",
+ "syscall.TIOCSCONS": "syscall",
+ "syscall.TIOCSCTTY": "syscall",
+ "syscall.TIOCSDRAINWAIT": "syscall",
+ "syscall.TIOCSDTR": "syscall",
+ "syscall.TIOCSERCONFIG": "syscall",
+ "syscall.TIOCSERGETLSR": "syscall",
+ "syscall.TIOCSERGETMULTI": "syscall",
+ "syscall.TIOCSERGSTRUCT": "syscall",
+ "syscall.TIOCSERGWILD": "syscall",
+ "syscall.TIOCSERSETMULTI": "syscall",
+ "syscall.TIOCSERSWILD": "syscall",
+ "syscall.TIOCSER_TEMT": "syscall",
+ "syscall.TIOCSETA": "syscall",
+ "syscall.TIOCSETAF": "syscall",
+ "syscall.TIOCSETAW": "syscall",
+ "syscall.TIOCSETD": "syscall",
+ "syscall.TIOCSFLAGS": "syscall",
+ "syscall.TIOCSIG": "syscall",
+ "syscall.TIOCSLCKTRMIOS": "syscall",
+ "syscall.TIOCSLINED": "syscall",
+ "syscall.TIOCSPGRP": "syscall",
+ "syscall.TIOCSPTLCK": "syscall",
+ "syscall.TIOCSQSIZE": "syscall",
+ "syscall.TIOCSRS485": "syscall",
+ "syscall.TIOCSSERIAL": "syscall",
+ "syscall.TIOCSSIZE": "syscall",
+ "syscall.TIOCSSOFTCAR": "syscall",
+ "syscall.TIOCSTART": "syscall",
+ "syscall.TIOCSTAT": "syscall",
+ "syscall.TIOCSTI": "syscall",
+ "syscall.TIOCSTOP": "syscall",
+ "syscall.TIOCSTSTAMP": "syscall",
+ "syscall.TIOCSWINSZ": "syscall",
+ "syscall.TIOCTIMESTAMP": "syscall",
+ "syscall.TIOCUCNTL": "syscall",
+ "syscall.TIOCVHANGUP": "syscall",
+ "syscall.TIOCXMTFRAME": "syscall",
+ "syscall.TOKEN_ADJUST_DEFAULT": "syscall",
+ "syscall.TOKEN_ADJUST_GROUPS": "syscall",
+ "syscall.TOKEN_ADJUST_PRIVILEGES": "syscall",
+ "syscall.TOKEN_ALL_ACCESS": "syscall",
+ "syscall.TOKEN_ASSIGN_PRIMARY": "syscall",
+ "syscall.TOKEN_DUPLICATE": "syscall",
+ "syscall.TOKEN_EXECUTE": "syscall",
+ "syscall.TOKEN_IMPERSONATE": "syscall",
+ "syscall.TOKEN_QUERY": "syscall",
+ "syscall.TOKEN_QUERY_SOURCE": "syscall",
+ "syscall.TOKEN_READ": "syscall",
+ "syscall.TOKEN_WRITE": "syscall",
+ "syscall.TOSTOP": "syscall",
+ "syscall.TRUNCATE_EXISTING": "syscall",
+ "syscall.TUNATTACHFILTER": "syscall",
+ "syscall.TUNDETACHFILTER": "syscall",
+ "syscall.TUNGETFEATURES": "syscall",
+ "syscall.TUNGETIFF": "syscall",
+ "syscall.TUNGETSNDBUF": "syscall",
+ "syscall.TUNGETVNETHDRSZ": "syscall",
+ "syscall.TUNSETDEBUG": "syscall",
+ "syscall.TUNSETGROUP": "syscall",
+ "syscall.TUNSETIFF": "syscall",
+ "syscall.TUNSETLINK": "syscall",
+ "syscall.TUNSETNOCSUM": "syscall",
+ "syscall.TUNSETOFFLOAD": "syscall",
+ "syscall.TUNSETOWNER": "syscall",
+ "syscall.TUNSETPERSIST": "syscall",
+ "syscall.TUNSETSNDBUF": "syscall",
+ "syscall.TUNSETTXFILTER": "syscall",
+ "syscall.TUNSETVNETHDRSZ": "syscall",
+ "syscall.Tee": "syscall",
+ "syscall.TerminateProcess": "syscall",
+ "syscall.Termios": "syscall",
+ "syscall.Tgkill": "syscall",
+ "syscall.Time": "syscall",
+ "syscall.Time_t": "syscall",
+ "syscall.Times": "syscall",
+ "syscall.Timespec": "syscall",
+ "syscall.TimespecToNsec": "syscall",
+ "syscall.Timeval": "syscall",
+ "syscall.Timeval32": "syscall",
+ "syscall.TimevalToNsec": "syscall",
+ "syscall.Timex": "syscall",
+ "syscall.Timezoneinformation": "syscall",
+ "syscall.Tms": "syscall",
+ "syscall.Token": "syscall",
+ "syscall.TokenAccessInformation": "syscall",
+ "syscall.TokenAuditPolicy": "syscall",
+ "syscall.TokenDefaultDacl": "syscall",
+ "syscall.TokenElevation": "syscall",
+ "syscall.TokenElevationType": "syscall",
+ "syscall.TokenGroups": "syscall",
+ "syscall.TokenGroupsAndPrivileges": "syscall",
+ "syscall.TokenHasRestrictions": "syscall",
+ "syscall.TokenImpersonationLevel": "syscall",
+ "syscall.TokenIntegrityLevel": "syscall",
+ "syscall.TokenLinkedToken": "syscall",
+ "syscall.TokenLogonSid": "syscall",
+ "syscall.TokenMandatoryPolicy": "syscall",
+ "syscall.TokenOrigin": "syscall",
+ "syscall.TokenOwner": "syscall",
+ "syscall.TokenPrimaryGroup": "syscall",
+ "syscall.TokenPrivileges": "syscall",
+ "syscall.TokenRestrictedSids": "syscall",
+ "syscall.TokenSandBoxInert": "syscall",
+ "syscall.TokenSessionId": "syscall",
+ "syscall.TokenSessionReference": "syscall",
+ "syscall.TokenSource": "syscall",
+ "syscall.TokenStatistics": "syscall",
+ "syscall.TokenType": "syscall",
+ "syscall.TokenUIAccess": "syscall",
+ "syscall.TokenUser": "syscall",
+ "syscall.TokenVirtualizationAllowed": "syscall",
+ "syscall.TokenVirtualizationEnabled": "syscall",
+ "syscall.Tokenprimarygroup": "syscall",
+ "syscall.Tokenuser": "syscall",
+ "syscall.TranslateAccountName": "syscall",
+ "syscall.TranslateName": "syscall",
+ "syscall.TransmitFile": "syscall",
+ "syscall.TransmitFileBuffers": "syscall",
+ "syscall.Truncate": "syscall",
+ "syscall.USAGE_MATCH_TYPE_AND": "syscall",
+ "syscall.USAGE_MATCH_TYPE_OR": "syscall",
+ "syscall.UTF16FromString": "syscall",
+ "syscall.UTF16PtrFromString": "syscall",
+ "syscall.UTF16ToString": "syscall",
+ "syscall.Ucred": "syscall",
+ "syscall.Umask": "syscall",
+ "syscall.Uname": "syscall",
+ "syscall.Undelete": "syscall",
+ "syscall.UnixCredentials": "syscall",
+ "syscall.UnixRights": "syscall",
+ "syscall.Unlink": "syscall",
+ "syscall.Unlinkat": "syscall",
+ "syscall.UnmapViewOfFile": "syscall",
+ "syscall.Unmount": "syscall",
+ "syscall.Unshare": "syscall",
+ "syscall.UserInfo10": "syscall",
+ "syscall.Ustat": "syscall",
+ "syscall.Ustat_t": "syscall",
+ "syscall.Utimbuf": "syscall",
+ "syscall.Utime": "syscall",
+ "syscall.Utimes": "syscall",
+ "syscall.UtimesNano": "syscall",
+ "syscall.Utsname": "syscall",
+ "syscall.VDISCARD": "syscall",
+ "syscall.VDSUSP": "syscall",
+ "syscall.VEOF": "syscall",
+ "syscall.VEOL": "syscall",
+ "syscall.VEOL2": "syscall",
+ "syscall.VERASE": "syscall",
+ "syscall.VERASE2": "syscall",
+ "syscall.VINTR": "syscall",
+ "syscall.VKILL": "syscall",
+ "syscall.VLNEXT": "syscall",
+ "syscall.VMIN": "syscall",
+ "syscall.VQUIT": "syscall",
+ "syscall.VREPRINT": "syscall",
+ "syscall.VSTART": "syscall",
+ "syscall.VSTATUS": "syscall",
+ "syscall.VSTOP": "syscall",
+ "syscall.VSUSP": "syscall",
+ "syscall.VSWTC": "syscall",
+ "syscall.VT0": "syscall",
+ "syscall.VT1": "syscall",
+ "syscall.VTDLY": "syscall",
+ "syscall.VTIME": "syscall",
+ "syscall.VWERASE": "syscall",
+ "syscall.VirtualLock": "syscall",
+ "syscall.VirtualUnlock": "syscall",
+ "syscall.WAIT_ABANDONED": "syscall",
+ "syscall.WAIT_FAILED": "syscall",
+ "syscall.WAIT_OBJECT_0": "syscall",
+ "syscall.WAIT_TIMEOUT": "syscall",
+ "syscall.WALL": "syscall",
+ "syscall.WALLSIG": "syscall",
+ "syscall.WALTSIG": "syscall",
+ "syscall.WCLONE": "syscall",
+ "syscall.WCONTINUED": "syscall",
+ "syscall.WCOREFLAG": "syscall",
+ "syscall.WEXITED": "syscall",
+ "syscall.WLINUXCLONE": "syscall",
+ "syscall.WNOHANG": "syscall",
+ "syscall.WNOTHREAD": "syscall",
+ "syscall.WNOWAIT": "syscall",
+ "syscall.WNOZOMBIE": "syscall",
+ "syscall.WOPTSCHECKED": "syscall",
+ "syscall.WORDSIZE": "syscall",
+ "syscall.WSABuf": "syscall",
+ "syscall.WSACleanup": "syscall",
+ "syscall.WSADESCRIPTION_LEN": "syscall",
+ "syscall.WSAData": "syscall",
+ "syscall.WSAEACCES": "syscall",
+ "syscall.WSAEnumProtocols": "syscall",
+ "syscall.WSAID_CONNECTEX": "syscall",
+ "syscall.WSAIoctl": "syscall",
+ "syscall.WSAPROTOCOL_LEN": "syscall",
+ "syscall.WSAProtocolChain": "syscall",
+ "syscall.WSAProtocolInfo": "syscall",
+ "syscall.WSARecv": "syscall",
+ "syscall.WSARecvFrom": "syscall",
+ "syscall.WSASYS_STATUS_LEN": "syscall",
+ "syscall.WSASend": "syscall",
+ "syscall.WSASendTo": "syscall",
+ "syscall.WSASendto": "syscall",
+ "syscall.WSAStartup": "syscall",
+ "syscall.WSTOPPED": "syscall",
+ "syscall.WTRAPPED": "syscall",
+ "syscall.WUNTRACED": "syscall",
+ "syscall.Wait4": "syscall",
+ "syscall.WaitForSingleObject": "syscall",
+ "syscall.WaitStatus": "syscall",
+ "syscall.Win32FileAttributeData": "syscall",
+ "syscall.Win32finddata": "syscall",
+ "syscall.Write": "syscall",
+ "syscall.WriteConsole": "syscall",
+ "syscall.WriteFile": "syscall",
+ "syscall.X509_ASN_ENCODING": "syscall",
+ "syscall.XCASE": "syscall",
+ "syscall.XP1_CONNECTIONLESS": "syscall",
+ "syscall.XP1_CONNECT_DATA": "syscall",
+ "syscall.XP1_DISCONNECT_DATA": "syscall",
+ "syscall.XP1_EXPEDITED_DATA": "syscall",
+ "syscall.XP1_GRACEFUL_CLOSE": "syscall",
+ "syscall.XP1_GUARANTEED_DELIVERY": "syscall",
+ "syscall.XP1_GUARANTEED_ORDER": "syscall",
+ "syscall.XP1_IFS_HANDLES": "syscall",
+ "syscall.XP1_MESSAGE_ORIENTED": "syscall",
+ "syscall.XP1_MULTIPOINT_CONTROL_PLANE": "syscall",
+ "syscall.XP1_MULTIPOINT_DATA_PLANE": "syscall",
+ "syscall.XP1_PARTIAL_MESSAGE": "syscall",
+ "syscall.XP1_PSEUDO_STREAM": "syscall",
+ "syscall.XP1_QOS_SUPPORTED": "syscall",
+ "syscall.XP1_SAN_SUPPORT_SDP": "syscall",
+ "syscall.XP1_SUPPORT_BROADCAST": "syscall",
+ "syscall.XP1_SUPPORT_MULTIPOINT": "syscall",
+ "syscall.XP1_UNI_RECV": "syscall",
+ "syscall.XP1_UNI_SEND": "syscall",
+ "syslog.Dial": "log/syslog",
+ "syslog.LOG_ALERT": "log/syslog",
+ "syslog.LOG_AUTH": "log/syslog",
+ "syslog.LOG_AUTHPRIV": "log/syslog",
+ "syslog.LOG_CRIT": "log/syslog",
+ "syslog.LOG_CRON": "log/syslog",
+ "syslog.LOG_DAEMON": "log/syslog",
+ "syslog.LOG_DEBUG": "log/syslog",
+ "syslog.LOG_EMERG": "log/syslog",
+ "syslog.LOG_ERR": "log/syslog",
+ "syslog.LOG_FTP": "log/syslog",
+ "syslog.LOG_INFO": "log/syslog",
+ "syslog.LOG_KERN": "log/syslog",
+ "syslog.LOG_LOCAL0": "log/syslog",
+ "syslog.LOG_LOCAL1": "log/syslog",
+ "syslog.LOG_LOCAL2": "log/syslog",
+ "syslog.LOG_LOCAL3": "log/syslog",
+ "syslog.LOG_LOCAL4": "log/syslog",
+ "syslog.LOG_LOCAL5": "log/syslog",
+ "syslog.LOG_LOCAL6": "log/syslog",
+ "syslog.LOG_LOCAL7": "log/syslog",
+ "syslog.LOG_LPR": "log/syslog",
+ "syslog.LOG_MAIL": "log/syslog",
+ "syslog.LOG_NEWS": "log/syslog",
+ "syslog.LOG_NOTICE": "log/syslog",
+ "syslog.LOG_SYSLOG": "log/syslog",
+ "syslog.LOG_USER": "log/syslog",
+ "syslog.LOG_UUCP": "log/syslog",
+ "syslog.LOG_WARNING": "log/syslog",
+ "syslog.New": "log/syslog",
+ "syslog.NewLogger": "log/syslog",
+ "syslog.Priority": "log/syslog",
+ "syslog.Writer": "log/syslog",
+ "tabwriter.AlignRight": "text/tabwriter",
+ "tabwriter.Debug": "text/tabwriter",
+ "tabwriter.DiscardEmptyColumns": "text/tabwriter",
+ "tabwriter.Escape": "text/tabwriter",
+ "tabwriter.FilterHTML": "text/tabwriter",
+ "tabwriter.NewWriter": "text/tabwriter",
+ "tabwriter.StripEscape": "text/tabwriter",
+ "tabwriter.TabIndent": "text/tabwriter",
+ "tabwriter.Writer": "text/tabwriter",
+ "tar.ErrFieldTooLong": "archive/tar",
+ "tar.ErrHeader": "archive/tar",
+ "tar.ErrWriteAfterClose": "archive/tar",
+ "tar.ErrWriteTooLong": "archive/tar",
+ "tar.FileInfoHeader": "archive/tar",
+ "tar.Header": "archive/tar",
+ "tar.NewReader": "archive/tar",
+ "tar.NewWriter": "archive/tar",
+ "tar.Reader": "archive/tar",
+ "tar.TypeBlock": "archive/tar",
+ "tar.TypeChar": "archive/tar",
+ "tar.TypeCont": "archive/tar",
+ "tar.TypeDir": "archive/tar",
+ "tar.TypeFifo": "archive/tar",
+ "tar.TypeGNULongLink": "archive/tar",
+ "tar.TypeGNULongName": "archive/tar",
+ "tar.TypeLink": "archive/tar",
+ "tar.TypeReg": "archive/tar",
+ "tar.TypeRegA": "archive/tar",
+ "tar.TypeSymlink": "archive/tar",
+ "tar.TypeXGlobalHeader": "archive/tar",
+ "tar.TypeXHeader": "archive/tar",
+ "tar.Writer": "archive/tar",
+ "template.CSS": "html/template",
+ "template.ErrAmbigContext": "html/template",
+ "template.ErrBadHTML": "html/template",
+ "template.ErrBranchEnd": "html/template",
+ "template.ErrEndContext": "html/template",
+ "template.ErrNoSuchTemplate": "html/template",
+ "template.ErrOutputContext": "html/template",
+ "template.ErrPartialCharset": "html/template",
+ "template.ErrPartialEscape": "html/template",
+ "template.ErrRangeLoopReentry": "html/template",
+ "template.ErrSlashAmbig": "html/template",
+ "template.Error": "html/template",
+ "template.ErrorCode": "html/template",
+ // "template.FuncMap" is ambiguous
+ "template.HTML": "html/template",
+ "template.HTMLAttr": "html/template",
+ // "template.HTMLEscape" is ambiguous
+ // "template.HTMLEscapeString" is ambiguous
+ // "template.HTMLEscaper" is ambiguous
+ "template.JS": "html/template",
+ // "template.JSEscape" is ambiguous
+ // "template.JSEscapeString" is ambiguous
+ // "template.JSEscaper" is ambiguous
+ "template.JSStr": "html/template",
+ // "template.Must" is ambiguous
+ // "template.New" is ambiguous
+ "template.OK": "html/template",
+ // "template.ParseFiles" is ambiguous
+ // "template.ParseGlob" is ambiguous
+ // "template.Template" is ambiguous
+ "template.URL": "html/template",
+ // "template.URLQueryEscaper" is ambiguous
+ "testing.AllocsPerRun": "testing",
+ "testing.B": "testing",
+ "testing.Benchmark": "testing",
+ "testing.BenchmarkResult": "testing",
+ "testing.Cover": "testing",
+ "testing.CoverBlock": "testing",
+ "testing.InternalBenchmark": "testing",
+ "testing.InternalExample": "testing",
+ "testing.InternalTest": "testing",
+ "testing.Main": "testing",
+ "testing.RegisterCover": "testing",
+ "testing.RunBenchmarks": "testing",
+ "testing.RunExamples": "testing",
+ "testing.RunTests": "testing",
+ "testing.Short": "testing",
+ "testing.T": "testing",
+ "testing.Verbose": "testing",
+ "textproto.CanonicalMIMEHeaderKey": "net/textproto",
+ "textproto.Conn": "net/textproto",
+ "textproto.Dial": "net/textproto",
+ "textproto.Error": "net/textproto",
+ "textproto.MIMEHeader": "net/textproto",
+ "textproto.NewConn": "net/textproto",
+ "textproto.NewReader": "net/textproto",
+ "textproto.NewWriter": "net/textproto",
+ "textproto.Pipeline": "net/textproto",
+ "textproto.ProtocolError": "net/textproto",
+ "textproto.Reader": "net/textproto",
+ "textproto.TrimBytes": "net/textproto",
+ "textproto.TrimString": "net/textproto",
+ "textproto.Writer": "net/textproto",
+ "time.ANSIC": "time",
+ "time.After": "time",
+ "time.AfterFunc": "time",
+ "time.April": "time",
+ "time.August": "time",
+ "time.Date": "time",
+ "time.December": "time",
+ "time.Duration": "time",
+ "time.February": "time",
+ "time.FixedZone": "time",
+ "time.Friday": "time",
+ "time.Hour": "time",
+ "time.January": "time",
+ "time.July": "time",
+ "time.June": "time",
+ "time.Kitchen": "time",
+ "time.LoadLocation": "time",
+ "time.Local": "time",
+ "time.Location": "time",
+ "time.March": "time",
+ "time.May": "time",
+ "time.Microsecond": "time",
+ "time.Millisecond": "time",
+ "time.Minute": "time",
+ "time.Monday": "time",
+ "time.Month": "time",
+ "time.Nanosecond": "time",
+ "time.NewTicker": "time",
+ "time.NewTimer": "time",
+ "time.November": "time",
+ "time.Now": "time",
+ "time.October": "time",
+ "time.Parse": "time",
+ "time.ParseDuration": "time",
+ "time.ParseError": "time",
+ "time.ParseInLocation": "time",
+ "time.RFC1123": "time",
+ "time.RFC1123Z": "time",
+ "time.RFC3339": "time",
+ "time.RFC3339Nano": "time",
+ "time.RFC822": "time",
+ "time.RFC822Z": "time",
+ "time.RFC850": "time",
+ "time.RubyDate": "time",
+ "time.Saturday": "time",
+ "time.Second": "time",
+ "time.September": "time",
+ "time.Since": "time",
+ "time.Sleep": "time",
+ "time.Stamp": "time",
+ "time.StampMicro": "time",
+ "time.StampMilli": "time",
+ "time.StampNano": "time",
+ "time.Sunday": "time",
+ "time.Thursday": "time",
+ "time.Tick": "time",
+ "time.Ticker": "time",
+ "time.Time": "time",
+ "time.Timer": "time",
+ "time.Tuesday": "time",
+ "time.UTC": "time",
+ "time.Unix": "time",
+ "time.UnixDate": "time",
+ "time.Wednesday": "time",
+ "time.Weekday": "time",
+ "tls.Certificate": "crypto/tls",
+ "tls.Client": "crypto/tls",
+ "tls.ClientAuthType": "crypto/tls",
+ "tls.Config": "crypto/tls",
+ "tls.Conn": "crypto/tls",
+ "tls.ConnectionState": "crypto/tls",
+ "tls.Dial": "crypto/tls",
+ "tls.Listen": "crypto/tls",
+ "tls.LoadX509KeyPair": "crypto/tls",
+ "tls.NewListener": "crypto/tls",
+ "tls.NoClientCert": "crypto/tls",
+ "tls.RequestClientCert": "crypto/tls",
+ "tls.RequireAndVerifyClientCert": "crypto/tls",
+ "tls.RequireAnyClientCert": "crypto/tls",
+ "tls.Server": "crypto/tls",
+ "tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA": "crypto/tls",
+ "tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256": "crypto/tls",
+ "tls.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA": "crypto/tls",
+ "tls.TLS_ECDHE_ECDSA_WITH_RC4_128_SHA": "crypto/tls",
+ "tls.TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA": "crypto/tls",
+ "tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA": "crypto/tls",
+ "tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256": "crypto/tls",
+ "tls.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA": "crypto/tls",
+ "tls.TLS_ECDHE_RSA_WITH_RC4_128_SHA": "crypto/tls",
+ "tls.TLS_RSA_WITH_3DES_EDE_CBC_SHA": "crypto/tls",
+ "tls.TLS_RSA_WITH_AES_128_CBC_SHA": "crypto/tls",
+ "tls.TLS_RSA_WITH_AES_256_CBC_SHA": "crypto/tls",
+ "tls.TLS_RSA_WITH_RC4_128_SHA": "crypto/tls",
+ "tls.VerifyClientCertIfGiven": "crypto/tls",
+ "tls.VersionSSL30": "crypto/tls",
+ "tls.VersionTLS10": "crypto/tls",
+ "tls.VersionTLS11": "crypto/tls",
+ "tls.VersionTLS12": "crypto/tls",
+ "tls.X509KeyPair": "crypto/tls",
+ "token.ADD": "go/token",
+ "token.ADD_ASSIGN": "go/token",
+ "token.AND": "go/token",
+ "token.AND_ASSIGN": "go/token",
+ "token.AND_NOT": "go/token",
+ "token.AND_NOT_ASSIGN": "go/token",
+ "token.ARROW": "go/token",
+ "token.ASSIGN": "go/token",
+ "token.BREAK": "go/token",
+ "token.CASE": "go/token",
+ "token.CHAN": "go/token",
+ "token.CHAR": "go/token",
+ "token.COLON": "go/token",
+ "token.COMMA": "go/token",
+ "token.COMMENT": "go/token",
+ "token.CONST": "go/token",
+ "token.CONTINUE": "go/token",
+ "token.DEC": "go/token",
+ "token.DEFAULT": "go/token",
+ "token.DEFER": "go/token",
+ "token.DEFINE": "go/token",
+ "token.ELLIPSIS": "go/token",
+ "token.ELSE": "go/token",
+ "token.EOF": "go/token",
+ "token.EQL": "go/token",
+ "token.FALLTHROUGH": "go/token",
+ "token.FLOAT": "go/token",
+ "token.FOR": "go/token",
+ "token.FUNC": "go/token",
+ "token.File": "go/token",
+ "token.FileSet": "go/token",
+ "token.GEQ": "go/token",
+ "token.GO": "go/token",
+ "token.GOTO": "go/token",
+ "token.GTR": "go/token",
+ "token.HighestPrec": "go/token",
+ "token.IDENT": "go/token",
+ "token.IF": "go/token",
+ "token.ILLEGAL": "go/token",
+ "token.IMAG": "go/token",
+ "token.IMPORT": "go/token",
+ "token.INC": "go/token",
+ "token.INT": "go/token",
+ "token.INTERFACE": "go/token",
+ "token.LAND": "go/token",
+ "token.LBRACE": "go/token",
+ "token.LBRACK": "go/token",
+ "token.LEQ": "go/token",
+ "token.LOR": "go/token",
+ "token.LPAREN": "go/token",
+ "token.LSS": "go/token",
+ "token.Lookup": "go/token",
+ "token.LowestPrec": "go/token",
+ "token.MAP": "go/token",
+ "token.MUL": "go/token",
+ "token.MUL_ASSIGN": "go/token",
+ "token.NEQ": "go/token",
+ "token.NOT": "go/token",
+ "token.NewFileSet": "go/token",
+ "token.NoPos": "go/token",
+ "token.OR": "go/token",
+ "token.OR_ASSIGN": "go/token",
+ "token.PACKAGE": "go/token",
+ "token.PERIOD": "go/token",
+ "token.Pos": "go/token",
+ "token.Position": "go/token",
+ "token.QUO": "go/token",
+ "token.QUO_ASSIGN": "go/token",
+ "token.RANGE": "go/token",
+ "token.RBRACE": "go/token",
+ "token.RBRACK": "go/token",
+ "token.REM": "go/token",
+ "token.REM_ASSIGN": "go/token",
+ "token.RETURN": "go/token",
+ "token.RPAREN": "go/token",
+ "token.SELECT": "go/token",
+ "token.SEMICOLON": "go/token",
+ "token.SHL": "go/token",
+ "token.SHL_ASSIGN": "go/token",
+ "token.SHR": "go/token",
+ "token.SHR_ASSIGN": "go/token",
+ "token.STRING": "go/token",
+ "token.STRUCT": "go/token",
+ "token.SUB": "go/token",
+ "token.SUB_ASSIGN": "go/token",
+ "token.SWITCH": "go/token",
+ "token.TYPE": "go/token",
+ "token.Token": "go/token",
+ "token.UnaryPrec": "go/token",
+ "token.VAR": "go/token",
+ "token.XOR": "go/token",
+ "token.XOR_ASSIGN": "go/token",
+ "unicode.ASCII_Hex_Digit": "unicode",
+ "unicode.Arabic": "unicode",
+ "unicode.Armenian": "unicode",
+ "unicode.Avestan": "unicode",
+ "unicode.AzeriCase": "unicode",
+ "unicode.Balinese": "unicode",
+ "unicode.Bamum": "unicode",
+ "unicode.Batak": "unicode",
+ "unicode.Bengali": "unicode",
+ "unicode.Bidi_Control": "unicode",
+ "unicode.Bopomofo": "unicode",
+ "unicode.Brahmi": "unicode",
+ "unicode.Braille": "unicode",
+ "unicode.Buginese": "unicode",
+ "unicode.Buhid": "unicode",
+ "unicode.C": "unicode",
+ "unicode.Canadian_Aboriginal": "unicode",
+ "unicode.Carian": "unicode",
+ "unicode.CaseRange": "unicode",
+ "unicode.CaseRanges": "unicode",
+ "unicode.Categories": "unicode",
+ "unicode.Cc": "unicode",
+ "unicode.Cf": "unicode",
+ "unicode.Chakma": "unicode",
+ "unicode.Cham": "unicode",
+ "unicode.Cherokee": "unicode",
+ "unicode.Co": "unicode",
+ "unicode.Common": "unicode",
+ "unicode.Coptic": "unicode",
+ "unicode.Cs": "unicode",
+ "unicode.Cuneiform": "unicode",
+ "unicode.Cypriot": "unicode",
+ "unicode.Cyrillic": "unicode",
+ "unicode.Dash": "unicode",
+ "unicode.Deprecated": "unicode",
+ "unicode.Deseret": "unicode",
+ "unicode.Devanagari": "unicode",
+ "unicode.Diacritic": "unicode",
+ "unicode.Digit": "unicode",
+ "unicode.Egyptian_Hieroglyphs": "unicode",
+ "unicode.Ethiopic": "unicode",
+ "unicode.Extender": "unicode",
+ "unicode.FoldCategory": "unicode",
+ "unicode.FoldScript": "unicode",
+ "unicode.Georgian": "unicode",
+ "unicode.Glagolitic": "unicode",
+ "unicode.Gothic": "unicode",
+ "unicode.GraphicRanges": "unicode",
+ "unicode.Greek": "unicode",
+ "unicode.Gujarati": "unicode",
+ "unicode.Gurmukhi": "unicode",
+ "unicode.Han": "unicode",
+ "unicode.Hangul": "unicode",
+ "unicode.Hanunoo": "unicode",
+ "unicode.Hebrew": "unicode",
+ "unicode.Hex_Digit": "unicode",
+ "unicode.Hiragana": "unicode",
+ "unicode.Hyphen": "unicode",
+ "unicode.IDS_Binary_Operator": "unicode",
+ "unicode.IDS_Trinary_Operator": "unicode",
+ "unicode.Ideographic": "unicode",
+ "unicode.Imperial_Aramaic": "unicode",
+ "unicode.In": "unicode",
+ "unicode.Inherited": "unicode",
+ "unicode.Inscriptional_Pahlavi": "unicode",
+ "unicode.Inscriptional_Parthian": "unicode",
+ "unicode.Is": "unicode",
+ "unicode.IsControl": "unicode",
+ "unicode.IsDigit": "unicode",
+ "unicode.IsGraphic": "unicode",
+ "unicode.IsLetter": "unicode",
+ "unicode.IsLower": "unicode",
+ "unicode.IsMark": "unicode",
+ "unicode.IsNumber": "unicode",
+ "unicode.IsOneOf": "unicode",
+ "unicode.IsPrint": "unicode",
+ "unicode.IsPunct": "unicode",
+ "unicode.IsSpace": "unicode",
+ "unicode.IsSymbol": "unicode",
+ "unicode.IsTitle": "unicode",
+ "unicode.IsUpper": "unicode",
+ "unicode.Javanese": "unicode",
+ "unicode.Join_Control": "unicode",
+ "unicode.Kaithi": "unicode",
+ "unicode.Kannada": "unicode",
+ "unicode.Katakana": "unicode",
+ "unicode.Kayah_Li": "unicode",
+ "unicode.Kharoshthi": "unicode",
+ "unicode.Khmer": "unicode",
+ "unicode.L": "unicode",
+ "unicode.Lao": "unicode",
+ "unicode.Latin": "unicode",
+ "unicode.Lepcha": "unicode",
+ "unicode.Letter": "unicode",
+ "unicode.Limbu": "unicode",
+ "unicode.Linear_B": "unicode",
+ "unicode.Lisu": "unicode",
+ "unicode.Ll": "unicode",
+ "unicode.Lm": "unicode",
+ "unicode.Lo": "unicode",
+ "unicode.Logical_Order_Exception": "unicode",
+ "unicode.Lower": "unicode",
+ "unicode.LowerCase": "unicode",
+ "unicode.Lt": "unicode",
+ "unicode.Lu": "unicode",
+ "unicode.Lycian": "unicode",
+ "unicode.Lydian": "unicode",
+ "unicode.M": "unicode",
+ "unicode.Malayalam": "unicode",
+ "unicode.Mandaic": "unicode",
+ "unicode.Mark": "unicode",
+ "unicode.MaxASCII": "unicode",
+ "unicode.MaxCase": "unicode",
+ "unicode.MaxLatin1": "unicode",
+ "unicode.MaxRune": "unicode",
+ "unicode.Mc": "unicode",
+ "unicode.Me": "unicode",
+ "unicode.Meetei_Mayek": "unicode",
+ "unicode.Meroitic_Cursive": "unicode",
+ "unicode.Meroitic_Hieroglyphs": "unicode",
+ "unicode.Miao": "unicode",
+ "unicode.Mn": "unicode",
+ "unicode.Mongolian": "unicode",
+ "unicode.Myanmar": "unicode",
+ "unicode.N": "unicode",
+ "unicode.Nd": "unicode",
+ "unicode.New_Tai_Lue": "unicode",
+ "unicode.Nko": "unicode",
+ "unicode.Nl": "unicode",
+ "unicode.No": "unicode",
+ "unicode.Noncharacter_Code_Point": "unicode",
+ "unicode.Number": "unicode",
+ "unicode.Ogham": "unicode",
+ "unicode.Ol_Chiki": "unicode",
+ "unicode.Old_Italic": "unicode",
+ "unicode.Old_Persian": "unicode",
+ "unicode.Old_South_Arabian": "unicode",
+ "unicode.Old_Turkic": "unicode",
+ "unicode.Oriya": "unicode",
+ "unicode.Osmanya": "unicode",
+ "unicode.Other": "unicode",
+ "unicode.Other_Alphabetic": "unicode",
+ "unicode.Other_Default_Ignorable_Code_Point": "unicode",
+ "unicode.Other_Grapheme_Extend": "unicode",
+ "unicode.Other_ID_Continue": "unicode",
+ "unicode.Other_ID_Start": "unicode",
+ "unicode.Other_Lowercase": "unicode",
+ "unicode.Other_Math": "unicode",
+ "unicode.Other_Uppercase": "unicode",
+ "unicode.P": "unicode",
+ "unicode.Pattern_Syntax": "unicode",
+ "unicode.Pattern_White_Space": "unicode",
+ "unicode.Pc": "unicode",
+ "unicode.Pd": "unicode",
+ "unicode.Pe": "unicode",
+ "unicode.Pf": "unicode",
+ "unicode.Phags_Pa": "unicode",
+ "unicode.Phoenician": "unicode",
+ "unicode.Pi": "unicode",
+ "unicode.Po": "unicode",
+ "unicode.PrintRanges": "unicode",
+ "unicode.Properties": "unicode",
+ "unicode.Ps": "unicode",
+ "unicode.Punct": "unicode",
+ "unicode.Quotation_Mark": "unicode",
+ "unicode.Radical": "unicode",
+ "unicode.Range16": "unicode",
+ "unicode.Range32": "unicode",
+ "unicode.RangeTable": "unicode",
+ "unicode.Rejang": "unicode",
+ "unicode.ReplacementChar": "unicode",
+ "unicode.Runic": "unicode",
+ "unicode.S": "unicode",
+ "unicode.STerm": "unicode",
+ "unicode.Samaritan": "unicode",
+ "unicode.Saurashtra": "unicode",
+ "unicode.Sc": "unicode",
+ "unicode.Scripts": "unicode",
+ "unicode.Sharada": "unicode",
+ "unicode.Shavian": "unicode",
+ "unicode.SimpleFold": "unicode",
+ "unicode.Sinhala": "unicode",
+ "unicode.Sk": "unicode",
+ "unicode.Sm": "unicode",
+ "unicode.So": "unicode",
+ "unicode.Soft_Dotted": "unicode",
+ "unicode.Sora_Sompeng": "unicode",
+ "unicode.Space": "unicode",
+ "unicode.SpecialCase": "unicode",
+ "unicode.Sundanese": "unicode",
+ "unicode.Syloti_Nagri": "unicode",
+ "unicode.Symbol": "unicode",
+ "unicode.Syriac": "unicode",
+ "unicode.Tagalog": "unicode",
+ "unicode.Tagbanwa": "unicode",
+ "unicode.Tai_Le": "unicode",
+ "unicode.Tai_Tham": "unicode",
+ "unicode.Tai_Viet": "unicode",
+ "unicode.Takri": "unicode",
+ "unicode.Tamil": "unicode",
+ "unicode.Telugu": "unicode",
+ "unicode.Terminal_Punctuation": "unicode",
+ "unicode.Thaana": "unicode",
+ "unicode.Thai": "unicode",
+ "unicode.Tibetan": "unicode",
+ "unicode.Tifinagh": "unicode",
+ "unicode.Title": "unicode",
+ "unicode.TitleCase": "unicode",
+ "unicode.To": "unicode",
+ "unicode.ToLower": "unicode",
+ "unicode.ToTitle": "unicode",
+ "unicode.ToUpper": "unicode",
+ "unicode.TurkishCase": "unicode",
+ "unicode.Ugaritic": "unicode",
+ "unicode.Unified_Ideograph": "unicode",
+ "unicode.Upper": "unicode",
+ "unicode.UpperCase": "unicode",
+ "unicode.UpperLower": "unicode",
+ "unicode.Vai": "unicode",
+ "unicode.Variation_Selector": "unicode",
+ "unicode.Version": "unicode",
+ "unicode.White_Space": "unicode",
+ "unicode.Yi": "unicode",
+ "unicode.Z": "unicode",
+ "unicode.Zl": "unicode",
+ "unicode.Zp": "unicode",
+ "unicode.Zs": "unicode",
+ "url.Error": "net/url",
+ "url.EscapeError": "net/url",
+ "url.Parse": "net/url",
+ "url.ParseQuery": "net/url",
+ "url.ParseRequestURI": "net/url",
+ "url.QueryEscape": "net/url",
+ "url.QueryUnescape": "net/url",
+ "url.URL": "net/url",
+ "url.User": "net/url",
+ "url.UserPassword": "net/url",
+ "url.Userinfo": "net/url",
+ "url.Values": "net/url",
+ "user.Current": "os/user",
+ "user.Lookup": "os/user",
+ "user.LookupId": "os/user",
+ "user.UnknownUserError": "os/user",
+ "user.UnknownUserIdError": "os/user",
+ "user.User": "os/user",
+ "utf16.Decode": "unicode/utf16",
+ "utf16.DecodeRune": "unicode/utf16",
+ "utf16.Encode": "unicode/utf16",
+ "utf16.EncodeRune": "unicode/utf16",
+ "utf16.IsSurrogate": "unicode/utf16",
+ "utf8.DecodeLastRune": "unicode/utf8",
+ "utf8.DecodeLastRuneInString": "unicode/utf8",
+ "utf8.DecodeRune": "unicode/utf8",
+ "utf8.DecodeRuneInString": "unicode/utf8",
+ "utf8.EncodeRune": "unicode/utf8",
+ "utf8.FullRune": "unicode/utf8",
+ "utf8.FullRuneInString": "unicode/utf8",
+ "utf8.MaxRune": "unicode/utf8",
+ "utf8.RuneCount": "unicode/utf8",
+ "utf8.RuneCountInString": "unicode/utf8",
+ "utf8.RuneError": "unicode/utf8",
+ "utf8.RuneLen": "unicode/utf8",
+ "utf8.RuneSelf": "unicode/utf8",
+ "utf8.RuneStart": "unicode/utf8",
+ "utf8.UTFMax": "unicode/utf8",
+ "utf8.Valid": "unicode/utf8",
+ "utf8.ValidRune": "unicode/utf8",
+ "utf8.ValidString": "unicode/utf8",
+ "x509.CANotAuthorizedForThisName": "crypto/x509",
+ "x509.CertPool": "crypto/x509",
+ "x509.Certificate": "crypto/x509",
+ "x509.CertificateInvalidError": "crypto/x509",
+ "x509.ConstraintViolationError": "crypto/x509",
+ "x509.CreateCertificate": "crypto/x509",
+ "x509.DSA": "crypto/x509",
+ "x509.DSAWithSHA1": "crypto/x509",
+ "x509.DSAWithSHA256": "crypto/x509",
+ "x509.DecryptPEMBlock": "crypto/x509",
+ "x509.ECDSA": "crypto/x509",
+ "x509.ECDSAWithSHA1": "crypto/x509",
+ "x509.ECDSAWithSHA256": "crypto/x509",
+ "x509.ECDSAWithSHA384": "crypto/x509",
+ "x509.ECDSAWithSHA512": "crypto/x509",
+ "x509.EncryptPEMBlock": "crypto/x509",
+ "x509.ErrUnsupportedAlgorithm": "crypto/x509",
+ "x509.Expired": "crypto/x509",
+ "x509.ExtKeyUsage": "crypto/x509",
+ "x509.ExtKeyUsageAny": "crypto/x509",
+ "x509.ExtKeyUsageClientAuth": "crypto/x509",
+ "x509.ExtKeyUsageCodeSigning": "crypto/x509",
+ "x509.ExtKeyUsageEmailProtection": "crypto/x509",
+ "x509.ExtKeyUsageIPSECEndSystem": "crypto/x509",
+ "x509.ExtKeyUsageIPSECTunnel": "crypto/x509",
+ "x509.ExtKeyUsageIPSECUser": "crypto/x509",
+ "x509.ExtKeyUsageMicrosoftServerGatedCrypto": "crypto/x509",
+ "x509.ExtKeyUsageNetscapeServerGatedCrypto": "crypto/x509",
+ "x509.ExtKeyUsageOCSPSigning": "crypto/x509",
+ "x509.ExtKeyUsageServerAuth": "crypto/x509",
+ "x509.ExtKeyUsageTimeStamping": "crypto/x509",
+ "x509.HostnameError": "crypto/x509",
+ "x509.IncompatibleUsage": "crypto/x509",
+ "x509.IncorrectPasswordError": "crypto/x509",
+ "x509.InvalidReason": "crypto/x509",
+ "x509.IsEncryptedPEMBlock": "crypto/x509",
+ "x509.KeyUsage": "crypto/x509",
+ "x509.KeyUsageCRLSign": "crypto/x509",
+ "x509.KeyUsageCertSign": "crypto/x509",
+ "x509.KeyUsageContentCommitment": "crypto/x509",
+ "x509.KeyUsageDataEncipherment": "crypto/x509",
+ "x509.KeyUsageDecipherOnly": "crypto/x509",
+ "x509.KeyUsageDigitalSignature": "crypto/x509",
+ "x509.KeyUsageEncipherOnly": "crypto/x509",
+ "x509.KeyUsageKeyAgreement": "crypto/x509",
+ "x509.KeyUsageKeyEncipherment": "crypto/x509",
+ "x509.MD2WithRSA": "crypto/x509",
+ "x509.MD5WithRSA": "crypto/x509",
+ "x509.MarshalECPrivateKey": "crypto/x509",
+ "x509.MarshalPKCS1PrivateKey": "crypto/x509",
+ "x509.MarshalPKIXPublicKey": "crypto/x509",
+ "x509.NewCertPool": "crypto/x509",
+ "x509.NotAuthorizedToSign": "crypto/x509",
+ "x509.PEMCipher": "crypto/x509",
+ "x509.PEMCipher3DES": "crypto/x509",
+ "x509.PEMCipherAES128": "crypto/x509",
+ "x509.PEMCipherAES192": "crypto/x509",
+ "x509.PEMCipherAES256": "crypto/x509",
+ "x509.PEMCipherDES": "crypto/x509",
+ "x509.ParseCRL": "crypto/x509",
+ "x509.ParseCertificate": "crypto/x509",
+ "x509.ParseCertificates": "crypto/x509",
+ "x509.ParseDERCRL": "crypto/x509",
+ "x509.ParseECPrivateKey": "crypto/x509",
+ "x509.ParsePKCS1PrivateKey": "crypto/x509",
+ "x509.ParsePKCS8PrivateKey": "crypto/x509",
+ "x509.ParsePKIXPublicKey": "crypto/x509",
+ "x509.PublicKeyAlgorithm": "crypto/x509",
+ "x509.RSA": "crypto/x509",
+ "x509.SHA1WithRSA": "crypto/x509",
+ "x509.SHA256WithRSA": "crypto/x509",
+ "x509.SHA384WithRSA": "crypto/x509",
+ "x509.SHA512WithRSA": "crypto/x509",
+ "x509.SignatureAlgorithm": "crypto/x509",
+ "x509.SystemRootsError": "crypto/x509",
+ "x509.TooManyIntermediates": "crypto/x509",
+ "x509.UnhandledCriticalExtension": "crypto/x509",
+ "x509.UnknownAuthorityError": "crypto/x509",
+ "x509.UnknownPublicKeyAlgorithm": "crypto/x509",
+ "x509.UnknownSignatureAlgorithm": "crypto/x509",
+ "x509.VerifyOptions": "crypto/x509",
+ "xml.Attr": "encoding/xml",
+ "xml.CharData": "encoding/xml",
+ "xml.Comment": "encoding/xml",
+ "xml.CopyToken": "encoding/xml",
+ "xml.Decoder": "encoding/xml",
+ "xml.Directive": "encoding/xml",
+ "xml.Encoder": "encoding/xml",
+ "xml.EndElement": "encoding/xml",
+ "xml.Escape": "encoding/xml",
+ "xml.EscapeText": "encoding/xml",
+ "xml.HTMLAutoClose": "encoding/xml",
+ "xml.HTMLEntity": "encoding/xml",
+ "xml.Header": "encoding/xml",
+ "xml.Marshal": "encoding/xml",
+ "xml.MarshalIndent": "encoding/xml",
+ "xml.Marshaler": "encoding/xml",
+ "xml.MarshalerAttr": "encoding/xml",
+ "xml.Name": "encoding/xml",
+ "xml.NewDecoder": "encoding/xml",
+ "xml.NewEncoder": "encoding/xml",
+ "xml.ProcInst": "encoding/xml",
+ "xml.StartElement": "encoding/xml",
+ "xml.SyntaxError": "encoding/xml",
+ "xml.TagPathError": "encoding/xml",
+ "xml.Token": "encoding/xml",
+ "xml.Unmarshal": "encoding/xml",
+ "xml.UnmarshalError": "encoding/xml",
+ "xml.Unmarshaler": "encoding/xml",
+ "xml.UnmarshalerAttr": "encoding/xml",
+ "xml.UnsupportedTypeError": "encoding/xml",
+ "zip.Compressor": "archive/zip",
+ "zip.Decompressor": "archive/zip",
+ "zip.Deflate": "archive/zip",
+ "zip.ErrAlgorithm": "archive/zip",
+ "zip.ErrChecksum": "archive/zip",
+ "zip.ErrFormat": "archive/zip",
+ "zip.File": "archive/zip",
+ "zip.FileHeader": "archive/zip",
+ "zip.FileInfoHeader": "archive/zip",
+ "zip.NewReader": "archive/zip",
+ "zip.NewWriter": "archive/zip",
+ "zip.OpenReader": "archive/zip",
+ "zip.ReadCloser": "archive/zip",
+ "zip.Reader": "archive/zip",
+ "zip.RegisterCompressor": "archive/zip",
+ "zip.RegisterDecompressor": "archive/zip",
+ "zip.Store": "archive/zip",
+ "zip.Writer": "archive/zip",
+ "zlib.BestCompression": "compress/zlib",
+ "zlib.BestSpeed": "compress/zlib",
+ "zlib.DefaultCompression": "compress/zlib",
+ "zlib.ErrChecksum": "compress/zlib",
+ "zlib.ErrDictionary": "compress/zlib",
+ "zlib.ErrHeader": "compress/zlib",
+ "zlib.NewReader": "compress/zlib",
+ "zlib.NewReaderDict": "compress/zlib",
+ "zlib.NewWriter": "compress/zlib",
+ "zlib.NewWriterLevel": "compress/zlib",
+ "zlib.NewWriterLevelDict": "compress/zlib",
+ "zlib.NoCompression": "compress/zlib",
+ "zlib.Writer": "compress/zlib",
+}
diff --git a/oracle/TODO b/oracle/TODO
new file mode 100644
index 0000000..8fbf5e8
--- /dev/null
+++ b/oracle/TODO
@@ -0,0 +1,83 @@
+
+
+ORACLE TODO
+===========
+
+General
+=======
+
+Save unsaved editor buffers into an archive and provide that to the
+tools, which should act as if they were saved.
+
+Include complete pos/end information Serial output.
+ But beware that sometimes a single token (e.g. +) is more helpful
+ than the pos/end of the containing expression (e.g. x \n + \n y).
+
+Specific queries
+================
+
+callers, callees
+
+ Use a type-based (e.g. RTA) callgraph when a callers/callees query is
+ outside the analysis scope.
+
+implements
+
+ Make it require that the selection is a type, and show only the
+ implements relation as it applies to that type.
+
+definition, referrers
+
+ definition: Make it work with qualified identifiers (SelectorExpr) too.
+
+ references: Make it work on things that are implicit idents, like
+ import specs, perhaps?
+
+what
+
+ Report def/ref info if available.
+ Editors could use it to highlight all idents of the same local var.
+
+ More tests.
+
+pointsto
+
+ When invoked on a function Ident, we get an error.
+
+ When invoked on a named return parameter, we get an error.
+
+describe
+
+ When invoked on a var, we want to see the type and its methods.
+
+ Split "show type" and "describe syntax" into separate commands?
+
+peers
+
+ Permit querying from a makechan, for...range, or reflective op.
+
+ Report aliasing reflect.{Send,Recv,Close} and close() operations.
+
+New queries
+
+"updaters": show all statements that may update the selected lvalue
+ (local, global, field, etc).
+
+"creators": show all places where an object of type T is created
+ (&T{}, var t T, new(T), new(struct{array [3]T}), etc.
+ (Useful for datatypes whose zero value is not safe)
+
+
+Editor-specific
+===============
+
+Add support for "what" to .el; clean up.
+
+Emacs: use JSON to get the raw information from the oracle. Don't
+ open an editor buffer for simpler queries, just jump to the result
+ and/or display it in the modeline.
+
+Emacs: go-root-and-paths depends on the current buffer, so be sure to
+ call it from within the source file, not the *go-oracle* buffer:
+ the user may have switched workspaces and the oracle should run in
+ the new one.
diff --git a/oracle/callees.go b/oracle/callees.go
new file mode 100644
index 0000000..56e45e1
--- /dev/null
+++ b/oracle/callees.go
@@ -0,0 +1,253 @@
+// 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 oracle
+
+import (
+ "fmt"
+ "go/ast"
+ "go/token"
+ "sort"
+
+ "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"
+ "golang.org/x/tools/go/types"
+ "golang.org/x/tools/oracle/serial"
+)
+
+// Callees reports the possible callees of the function call site
+// identified by the specified source location.
+func callees(q *Query) error {
+ lconf := loader.Config{Build: q.Build}
+
+ if err := setPTAScope(&lconf, q.Scope); err != nil {
+ return err
+ }
+
+ // Load/parse/type-check the program.
+ lprog, err := lconf.Load()
+ if err != nil {
+ return err
+ }
+ q.Fset = lprog.Fset
+
+ qpos, err := parseQueryPos(lprog, q.Pos, true) // needs exact pos
+ if err != nil {
+ return err
+ }
+
+ // Determine the enclosing call for the specified position.
+ var e *ast.CallExpr
+ for _, n := range qpos.path {
+ if e, _ = n.(*ast.CallExpr); e != nil {
+ break
+ }
+ }
+ if e == nil {
+ return fmt.Errorf("there is no function call here")
+ }
+ // TODO(adonovan): issue an error if the call is "too far
+ // away" from the current selection, as this most likely is
+ // not what the user intended.
+
+ // Reject type conversions.
+ if qpos.info.Types[e.Fun].IsType() {
+ return fmt.Errorf("this is a type conversion, not a function call")
+ }
+
+ // Deal with obviously static calls before constructing SSA form.
+ // Some static calls may yet require SSA construction,
+ // e.g. f := func(){}; f().
+ switch funexpr := unparen(e.Fun).(type) {
+ case *ast.Ident:
+ switch obj := qpos.info.Uses[funexpr].(type) {
+ case *types.Builtin:
+ // Reject calls to built-ins.
+ return fmt.Errorf("this is a call to the built-in '%s' operator", obj.Name())
+ case *types.Func:
+ // This is a static function call
+ q.result = &calleesTypesResult{
+ site: e,
+ callee: obj,
+ }
+ return nil
+ }
+ case *ast.SelectorExpr:
+ sel := qpos.info.Selections[funexpr]
+ if sel == nil {
+ // qualified identifier.
+ // May refer to top level function variable
+ // or to top level function.
+ callee := qpos.info.Uses[funexpr.Sel]
+ if obj, ok := callee.(*types.Func); ok {
+ q.result = &calleesTypesResult{
+ site: e,
+ callee: obj,
+ }
+ return nil
+ }
+ } else if sel.Kind() == types.MethodVal {
+ recvtype := sel.Recv()
+ if !types.IsInterface(recvtype) {
+ // static method call
+ q.result = &calleesTypesResult{
+ site: e,
+ callee: sel.Obj().(*types.Func),
+ }
+ return nil
+ }
+ }
+ }
+
+ prog := ssautil.CreateProgram(lprog, ssa.GlobalDebug)
+
+ ptaConfig, err := setupPTA(prog, lprog, q.PTALog, q.Reflection)
+ if err != nil {
+ return err
+ }
+
+ pkg := prog.Package(qpos.info.Pkg)
+ if pkg == nil {
+ return fmt.Errorf("no SSA package")
+ }
+
+ // Defer SSA construction till after errors are reported.
+ prog.BuildAll()
+
+ // Ascertain calling function and call site.
+ callerFn := ssa.EnclosingFunction(pkg, qpos.path)
+ if callerFn == nil {
+ return fmt.Errorf("no SSA function built for this location (dead code?)")
+ }
+
+ // Find the call site.
+ site, err := findCallSite(callerFn, e)
+ if err != nil {
+ return err
+ }
+
+ funcs, err := findCallees(ptaConfig, site)
+ if err != nil {
+ return err
+ }
+
+ q.result = &calleesSSAResult{
+ site: site,
+ funcs: funcs,
+ }
+ return nil
+}
+
+func findCallSite(fn *ssa.Function, call *ast.CallExpr) (ssa.CallInstruction, error) {
+ instr, _ := fn.ValueForExpr(call)
+ callInstr, _ := instr.(ssa.CallInstruction)
+ if instr == nil {
+ return nil, fmt.Errorf("this call site is unreachable in this analysis")
+ }
+ return callInstr, nil
+}
+
+func findCallees(conf *pointer.Config, site ssa.CallInstruction) ([]*ssa.Function, error) {
+ // Avoid running the pointer analysis for static calls.
+ if callee := site.Common().StaticCallee(); callee != nil {
+ switch callee.String() {
+ case "runtime.SetFinalizer", "(reflect.Value).Call":
+ // The PTA treats calls to these intrinsics as dynamic.
+ // TODO(adonovan): avoid reliance on PTA internals.
+
+ default:
+ return []*ssa.Function{callee}, nil // singleton
+ }
+ }
+
+ // Dynamic call: use pointer analysis.
+ conf.BuildCallGraph = true
+ cg := ptrAnalysis(conf).CallGraph
+ cg.DeleteSyntheticNodes()
+
+ // Find all call edges from the site.
+ n := cg.Nodes[site.Parent()]
+ if n == nil {
+ return nil, fmt.Errorf("this call site is unreachable in this analysis")
+ }
+ calleesMap := make(map[*ssa.Function]bool)
+ for _, edge := range n.Out {
+ if edge.Site == site {
+ calleesMap[edge.Callee.Func] = true
+ }
+ }
+
+ // De-duplicate and sort.
+ funcs := make([]*ssa.Function, 0, len(calleesMap))
+ for f := range calleesMap {
+ funcs = append(funcs, f)
+ }
+ sort.Sort(byFuncPos(funcs))
+ return funcs, nil
+}
+
+type calleesSSAResult struct {
+ site ssa.CallInstruction
+ funcs []*ssa.Function
+}
+
+type calleesTypesResult struct {
+ site *ast.CallExpr
+ callee *types.Func
+}
+
+func (r *calleesSSAResult) display(printf printfFunc) {
+ if len(r.funcs) == 0 {
+ // dynamic call on a provably nil func/interface
+ printf(r.site, "%s on nil value", r.site.Common().Description())
+ } else {
+ printf(r.site, "this %s dispatches to:", r.site.Common().Description())
+ for _, callee := range r.funcs {
+ printf(callee, "\t%s", callee)
+ }
+ }
+}
+
+func (r *calleesSSAResult) toSerial(res *serial.Result, fset *token.FileSet) {
+ j := &serial.Callees{
+ Pos: fset.Position(r.site.Pos()).String(),
+ Desc: r.site.Common().Description(),
+ }
+ for _, callee := range r.funcs {
+ j.Callees = append(j.Callees, &serial.CalleesItem{
+ Name: callee.String(),
+ Pos: fset.Position(callee.Pos()).String(),
+ })
+ }
+ res.Callees = j
+}
+
+func (r *calleesTypesResult) display(printf printfFunc) {
+ printf(r.site, "this static function call dispatches to:")
+ printf(r.callee, "\t%s", r.callee.FullName())
+}
+
+func (r *calleesTypesResult) toSerial(res *serial.Result, fset *token.FileSet) {
+ j := &serial.Callees{
+ Pos: fset.Position(r.site.Pos()).String(),
+ Desc: "static function call",
+ }
+ j.Callees = []*serial.CalleesItem{
+ &serial.CalleesItem{
+ Name: r.callee.FullName(),
+ Pos: fset.Position(r.callee.Pos()).String(),
+ },
+ }
+ res.Callees = j
+}
+
+// NB: byFuncPos is not deterministic across packages since it depends on load order.
+// Use lessPos if the tests need it.
+type byFuncPos []*ssa.Function
+
+func (a byFuncPos) Len() int { return len(a) }
+func (a byFuncPos) Less(i, j int) bool { return a[i].Pos() < a[j].Pos() }
+func (a byFuncPos) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
diff --git a/oracle/callers.go b/oracle/callers.go
new file mode 100644
index 0000000..159a403
--- /dev/null
+++ b/oracle/callers.go
@@ -0,0 +1,115 @@
+// 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 oracle
+
+import (
+ "fmt"
+ "go/token"
+
+ "golang.org/x/tools/go/callgraph"
+ "golang.org/x/tools/go/loader"
+ "golang.org/x/tools/go/ssa"
+ "golang.org/x/tools/go/ssa/ssautil"
+ "golang.org/x/tools/oracle/serial"
+)
+
+// Callers reports the possible callers of the function
+// immediately enclosing the specified source location.
+//
+func callers(q *Query) error {
+ lconf := loader.Config{Build: q.Build}
+
+ if err := setPTAScope(&lconf, q.Scope); err != nil {
+ return err
+ }
+
+ // Load/parse/type-check the program.
+ lprog, err := lconf.Load()
+ if err != nil {
+ return err
+ }
+ q.Fset = lprog.Fset
+
+ qpos, err := parseQueryPos(lprog, q.Pos, false)
+ if err != nil {
+ return err
+ }
+
+ prog := ssautil.CreateProgram(lprog, 0)
+
+ ptaConfig, err := setupPTA(prog, lprog, q.PTALog, q.Reflection)
+ if err != nil {
+ return err
+ }
+
+ pkg := prog.Package(qpos.info.Pkg)
+ if pkg == nil {
+ return fmt.Errorf("no SSA package")
+ }
+ if !ssa.HasEnclosingFunction(pkg, qpos.path) {
+ return fmt.Errorf("this position is not inside a function")
+ }
+
+ // Defer SSA construction till after errors are reported.
+ prog.BuildAll()
+
+ target := ssa.EnclosingFunction(pkg, qpos.path)
+ if target == nil {
+ return fmt.Errorf("no SSA function built for this location (dead code?)")
+ }
+
+ // TODO(adonovan): opt: if function is never address-taken, skip
+ // the pointer analysis. Just look for direct calls. This can
+ // be done in a single pass over the SSA.
+
+ // Run the pointer analysis, recording each
+ // call found to originate from target.
+ ptaConfig.BuildCallGraph = true
+ cg := ptrAnalysis(ptaConfig).CallGraph
+ cg.DeleteSyntheticNodes()
+ edges := cg.CreateNode(target).In
+ // TODO(adonovan): sort + dedup calls to ensure test determinism.
+
+ q.result = &callersResult{
+ target: target,
+ callgraph: cg,
+ edges: edges,
+ }
+ return nil
+}
+
+type callersResult struct {
+ target *ssa.Function
+ callgraph *callgraph.Graph
+ edges []*callgraph.Edge
+}
+
+func (r *callersResult) display(printf printfFunc) {
+ root := r.callgraph.Root
+ if r.edges == nil {
+ printf(r.target, "%s is not reachable in this program.", r.target)
+ } else {
+ printf(r.target, "%s is called from these %d sites:", r.target, len(r.edges))
+ for _, edge := range r.edges {
+ if edge.Caller == root {
+ printf(r.target, "the root of the call graph")
+ } else {
+ printf(edge, "\t%s from %s", edge.Description(), edge.Caller.Func)
+ }
+ }
+ }
+}
+
+func (r *callersResult) toSerial(res *serial.Result, fset *token.FileSet) {
+ var callers []serial.Caller
+ for _, edge := range r.edges {
+ callers = append(callers, serial.Caller{
+ Caller: edge.Caller.Func.String(),
+ Pos: fset.Position(edge.Pos()).String(),
+ Desc: edge.Description(),
+ })
+ }
+ res.Callers = callers
+}
diff --git a/oracle/callstack.go b/oracle/callstack.go
new file mode 100644
index 0000000..6f04b60
--- /dev/null
+++ b/oracle/callstack.go
@@ -0,0 +1,126 @@
+// 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 oracle
+
+import (
+ "fmt"
+ "go/token"
+
+ "golang.org/x/tools/go/callgraph"
+ "golang.org/x/tools/go/loader"
+ "golang.org/x/tools/go/ssa"
+ "golang.org/x/tools/go/ssa/ssautil"
+ "golang.org/x/tools/oracle/serial"
+)
+
+// Callstack displays an arbitrary path from a root of the callgraph
+// to the function at the current position.
+//
+// The information may be misleading in a context-insensitive
+// analysis. e.g. the call path X->Y->Z might be infeasible if Y never
+// calls Z when it is called from X. TODO(adonovan): think about UI.
+//
+// TODO(adonovan): permit user to specify a starting point other than
+// the analysis root.
+//
+func callstack(q *Query) error {
+ fset := token.NewFileSet()
+ lconf := loader.Config{Fset: fset, Build: q.Build}
+
+ if err := setPTAScope(&lconf, q.Scope); err != nil {
+ return err
+ }
+
+ // Load/parse/type-check the program.
+ lprog, err := lconf.Load()
+ if err != nil {
+ return err
+ }
+
+ qpos, err := parseQueryPos(lprog, q.Pos, false)
+ if err != nil {
+ return err
+ }
+
+ prog := ssautil.CreateProgram(lprog, 0)
+
+ ptaConfig, err := setupPTA(prog, lprog, q.PTALog, q.Reflection)
+ if err != nil {
+ return err
+ }
+
+ pkg := prog.Package(qpos.info.Pkg)
+ if pkg == nil {
+ return fmt.Errorf("no SSA package")
+ }
+
+ if !ssa.HasEnclosingFunction(pkg, qpos.path) {
+ return fmt.Errorf("this position is not inside a function")
+ }
+
+ // Defer SSA construction till after errors are reported.
+ prog.BuildAll()
+
+ target := ssa.EnclosingFunction(pkg, qpos.path)
+ if target == nil {
+ return fmt.Errorf("no SSA function built for this location (dead code?)")
+ }
+
+ // Run the pointer analysis and build the complete call graph.
+ ptaConfig.BuildCallGraph = true
+ cg := ptrAnalysis(ptaConfig).CallGraph
+ cg.DeleteSyntheticNodes()
+
+ // Search for an arbitrary path from a root to the target function.
+ isEnd := func(n *callgraph.Node) bool { return n.Func == target }
+ callpath := callgraph.PathSearch(cg.Root, isEnd)
+ if callpath != nil {
+ callpath = callpath[1:] // remove synthetic edge from <root>
+ }
+
+ q.Fset = fset
+ q.result = &callstackResult{
+ qpos: qpos,
+ target: target,
+ callpath: callpath,
+ }
+ return nil
+}
+
+type callstackResult struct {
+ qpos *queryPos
+ target *ssa.Function
+ callpath []*callgraph.Edge
+}
+
+func (r *callstackResult) display(printf printfFunc) {
+ if r.callpath != nil {
+ printf(r.qpos, "Found a call path from root to %s", r.target)
+ printf(r.target, "%s", r.target)
+ for i := len(r.callpath) - 1; i >= 0; i-- {
+ edge := r.callpath[i]
+ printf(edge, "%s from %s", edge.Description(), edge.Caller.Func)
+ }
+ } else {
+ printf(r.target, "%s is unreachable in this analysis scope", r.target)
+ }
+}
+
+func (r *callstackResult) toSerial(res *serial.Result, fset *token.FileSet) {
+ var callers []serial.Caller
+ for i := len(r.callpath) - 1; i >= 0; i-- { // (innermost first)
+ edge := r.callpath[i]
+ callers = append(callers, serial.Caller{
+ Pos: fset.Position(edge.Pos()).String(),
+ Caller: edge.Caller.Func.String(),
+ Desc: edge.Description(),
+ })
+ }
+ res.Callstack = &serial.CallStack{
+ Pos: fset.Position(r.target.Pos()).String(),
+ Target: r.target.String(),
+ Callers: callers,
+ }
+}
diff --git a/oracle/definition.go b/oracle/definition.go
new file mode 100644
index 0000000..a0340c6
--- /dev/null
+++ b/oracle/definition.go
@@ -0,0 +1,76 @@
+// 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 oracle
+
+import (
+ "fmt"
+ "go/ast"
+ "go/token"
+
+ "golang.org/x/tools/go/loader"
+ "golang.org/x/tools/go/types"
+ "golang.org/x/tools/oracle/serial"
+)
+
+// definition reports the location of the definition of an identifier.
+//
+// TODO(adonovan): opt: for intra-file references, the parser's
+// resolution might be enough; we should start with that.
+//
+func definition(q *Query) error {
+ lconf := loader.Config{Build: q.Build}
+ allowErrors(&lconf)
+
+ if err := importQueryPackage(q.Pos, &lconf); err != nil {
+ return err
+ }
+
+ // Load/parse/type-check the program.
+ lprog, err := lconf.Load()
+ if err != nil {
+ return err
+ }
+ q.Fset = lprog.Fset
+
+ qpos, err := parseQueryPos(lprog, q.Pos, false)
+ if err != nil {
+ return err
+ }
+
+ id, _ := qpos.path[0].(*ast.Ident)
+ if id == nil {
+ return fmt.Errorf("no identifier here")
+ }
+
+ obj := qpos.info.ObjectOf(id)
+ if obj == nil {
+ // Happens for y in "switch y := x.(type)",
+ // and the package declaration,
+ // but I think that's all.
+ return fmt.Errorf("no object for identifier")
+ }
+
+ q.result = &definitionResult{qpos, obj}
+ return nil
+}
+
+type definitionResult struct {
+ qpos *queryPos
+ obj types.Object // object it denotes
+}
+
+func (r *definitionResult) display(printf printfFunc) {
+ printf(r.obj, "defined here as %s", r.qpos.objectString(r.obj))
+}
+
+func (r *definitionResult) toSerial(res *serial.Result, fset *token.FileSet) {
+ definition := &serial.Definition{
+ Desc: r.obj.String(),
+ }
+ if pos := r.obj.Pos(); pos != token.NoPos { // Package objects have no Pos()
+ definition.ObjPos = fset.Position(pos).String()
+ }
+ res.Definition = definition
+}
diff --git a/oracle/describe.go b/oracle/describe.go
new file mode 100644
index 0000000..ea1c5ec
--- /dev/null
+++ b/oracle/describe.go
@@ -0,0 +1,763 @@
+// 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 oracle
+
+import (
+ "bytes"
+ "fmt"
+ "go/ast"
+ "go/token"
+ "log"
+ "os"
+ "strings"
+
+ "golang.org/x/tools/go/ast/astutil"
+ "golang.org/x/tools/go/exact"
+ "golang.org/x/tools/go/loader"
+ "golang.org/x/tools/go/types"
+ "golang.org/x/tools/go/types/typeutil"
+ "golang.org/x/tools/oracle/serial"
+)
+
+// describe describes the syntax node denoted by the query position,
+// including:
+// - its syntactic category
+// - the definition of its referent (for identifiers) [now redundant]
+// - its type and method set (for an expression or type expression)
+//
+func describe(q *Query) error {
+ lconf := loader.Config{Build: q.Build}
+ allowErrors(&lconf)
+
+ if err := importQueryPackage(q.Pos, &lconf); err != nil {
+ return err
+ }
+
+ // Load/parse/type-check the program.
+ lprog, err := lconf.Load()
+ if err != nil {
+ return err
+ }
+ q.Fset = lprog.Fset
+
+ qpos, err := parseQueryPos(lprog, q.Pos, true) // (need exact pos)
+ if err != nil {
+ return err
+ }
+
+ if false { // debugging
+ fprintf(os.Stderr, lprog.Fset, qpos.path[0], "you selected: %s %s",
+ astutil.NodeDescription(qpos.path[0]), pathToString(qpos.path))
+ }
+
+ path, action := findInterestingNode(qpos.info, qpos.path)
+ switch action {
+ case actionExpr:
+ q.result, err = describeValue(qpos, path)
+
+ case actionType:
+ q.result, err = describeType(qpos, path)
+
+ case actionPackage:
+ q.result, err = describePackage(qpos, path)
+
+ case actionStmt:
+ q.result, err = describeStmt(qpos, path)
+
+ case actionUnknown:
+ q.result = &describeUnknownResult{path[0]}
+
+ default:
+ panic(action) // unreachable
+ }
+ return err
+}
+
+type describeUnknownResult struct {
+ node ast.Node
+}
+
+func (r *describeUnknownResult) display(printf printfFunc) {
+ // Nothing much to say about misc syntax.
+ printf(r.node, "%s", astutil.NodeDescription(r.node))
+}
+
+func (r *describeUnknownResult) toSerial(res *serial.Result, fset *token.FileSet) {
+ res.Describe = &serial.Describe{
+ Desc: astutil.NodeDescription(r.node),
+ Pos: fset.Position(r.node.Pos()).String(),
+ }
+}
+
+type action int
+
+const (
+ actionUnknown action = iota // None of the below
+ actionExpr // FuncDecl, true Expr or Ident(types.{Const,Var})
+ actionType // type Expr or Ident(types.TypeName).
+ actionStmt // Stmt or Ident(types.Label)
+ actionPackage // Ident(types.Package) or ImportSpec
+)
+
+// findInterestingNode classifies the syntax node denoted by path as one of:
+// - an expression, part of an expression or a reference to a constant
+// or variable;
+// - a type, part of a type, or a reference to a named type;
+// - a statement, part of a statement, or a label referring to a statement;
+// - part of a package declaration or import spec.
+// - none of the above.
+// and returns the most "interesting" associated node, which may be
+// the same node, an ancestor or a descendent.
+//
+func findInterestingNode(pkginfo *loader.PackageInfo, path []ast.Node) ([]ast.Node, action) {
+ // TODO(adonovan): integrate with go/types/stdlib_test.go and
+ // apply this to every AST node we can find to make sure it
+ // doesn't crash.
+
+ // TODO(adonovan): audit for ParenExpr safety, esp. since we
+ // traverse up and down.
+
+ // TODO(adonovan): if the users selects the "." in
+ // "fmt.Fprintf()", they'll get an ambiguous selection error;
+ // we won't even reach here. Can we do better?
+
+ // TODO(adonovan): describing a field within 'type T struct {...}'
+ // describes the (anonymous) struct type and concludes "no methods".
+ // We should ascend to the enclosing type decl, if any.
+
+ for len(path) > 0 {
+ switch n := path[0].(type) {
+ case *ast.GenDecl:
+ if len(n.Specs) == 1 {
+ // Descend to sole {Import,Type,Value}Spec child.
+ path = append([]ast.Node{n.Specs[0]}, path...)
+ continue
+ }
+ return path, actionUnknown // uninteresting
+
+ case *ast.FuncDecl:
+ // Descend to function name.
+ path = append([]ast.Node{n.Name}, path...)
+ continue
+
+ case *ast.ImportSpec:
+ return path, actionPackage
+
+ case *ast.ValueSpec:
+ if len(n.Names) == 1 {
+ // Descend to sole Ident child.
+ path = append([]ast.Node{n.Names[0]}, path...)
+ continue
+ }
+ return path, actionUnknown // uninteresting
+
+ case *ast.TypeSpec:
+ // Descend to type name.
+ path = append([]ast.Node{n.Name}, path...)
+ continue
+
+ case ast.Stmt:
+ return path, actionStmt
+
+ case *ast.ArrayType,
+ *ast.StructType,
+ *ast.FuncType,
+ *ast.InterfaceType,
+ *ast.MapType,
+ *ast.ChanType:
+ return path, actionType
+
+ case *ast.Comment, *ast.CommentGroup, *ast.File, *ast.KeyValueExpr, *ast.CommClause:
+ return path, actionUnknown // uninteresting
+
+ case *ast.Ellipsis:
+ // Continue to enclosing node.
+ // e.g. [...]T in ArrayType
+ // f(x...) in CallExpr
+ // f(x...T) in FuncType
+
+ case *ast.Field:
+ // TODO(adonovan): this needs more thought,
+ // since fields can be so many things.
+ if len(n.Names) == 1 {
+ // Descend to sole Ident child.
+ path = append([]ast.Node{n.Names[0]}, path...)
+ continue
+ }
+ // Zero names (e.g. anon field in struct)
+ // or multiple field or param names:
+ // continue to enclosing field list.
+
+ case *ast.FieldList:
+ // Continue to enclosing node:
+ // {Struct,Func,Interface}Type or FuncDecl.
+
+ case *ast.BasicLit:
+ if _, ok := path[1].(*ast.ImportSpec); ok {
+ return path[1:], actionPackage
+ }
+ return path, actionExpr
+
+ case *ast.SelectorExpr:
+ // TODO(adonovan): use Selections info directly.
+ if pkginfo.Uses[n.Sel] == nil {
+ // TODO(adonovan): is this reachable?
+ return path, actionUnknown
+ }
+ // Descend to .Sel child.
+ path = append([]ast.Node{n.Sel}, path...)
+ continue
+
+ case *ast.Ident:
+ switch pkginfo.ObjectOf(n).(type) {
+ case *types.PkgName:
+ return path, actionPackage
+
+ case *types.Const:
+ return path, actionExpr
+
+ case *types.Label:
+ return path, actionStmt
+
+ case *types.TypeName:
+ return path, actionType
+
+ case *types.Var:
+ // For x in 'struct {x T}', return struct type, for now.
+ if _, ok := path[1].(*ast.Field); ok {
+ _ = path[2].(*ast.FieldList) // assertion
+ if _, ok := path[3].(*ast.StructType); ok {
+ return path[3:], actionType
+ }
+ }
+ return path, actionExpr
+
+ case *types.Func:
+ return path, actionExpr
+
+ case *types.Builtin:
+ // For reference to built-in function, return enclosing call.
+ path = path[1:] // ascend to enclosing function call
+ continue
+
+ case *types.Nil:
+ return path, actionExpr
+ }
+
+ // No object.
+ switch path[1].(type) {
+ case *ast.SelectorExpr:
+ // Return enclosing selector expression.
+ return path[1:], actionExpr
+
+ case *ast.Field:
+ // TODO(adonovan): test this.
+ // e.g. all f in:
+ // struct { f, g int }
+ // interface { f() }
+ // func (f T) method(f, g int) (f, g bool)
+ //
+ // switch path[3].(type) {
+ // case *ast.FuncDecl:
+ // case *ast.StructType:
+ // case *ast.InterfaceType:
+ // }
+ //
+ // return path[1:], actionExpr
+ //
+ // Unclear what to do with these.
+ // Struct.Fields -- field
+ // Interface.Methods -- field
+ // FuncType.{Params.Results} -- actionExpr
+ // FuncDecl.Recv -- actionExpr
+
+ case *ast.File:
+ // 'package foo'
+ return path, actionPackage
+
+ case *ast.ImportSpec:
+ // TODO(adonovan): fix: why no package object? go/types bug?
+ return path[1:], actionPackage
+
+ default:
+ // e.g. blank identifier
+ // or y in "switch y := x.(type)"
+ // or code in a _test.go file that's not part of the package.
+ log.Printf("unknown reference %s in %T\n", n, path[1])
+ return path, actionUnknown
+ }
+
+ case *ast.StarExpr:
+ if pkginfo.Types[n].IsType() {
+ return path, actionType
+ }
+ return path, actionExpr
+
+ case ast.Expr:
+ // All Expr but {BasicLit,Ident,StarExpr} are
+ // "true" expressions that evaluate to a value.
+ return path, actionExpr
+ }
+
+ // Ascend to parent.
+ path = path[1:]
+ }
+
+ return nil, actionUnknown // unreachable
+}
+
+func describeValue(qpos *queryPos, path []ast.Node) (*describeValueResult, error) {
+ var expr ast.Expr
+ var obj types.Object
+ switch n := path[0].(type) {
+ case *ast.ValueSpec:
+ // ambiguous ValueSpec containing multiple names
+ return nil, fmt.Errorf("multiple value specification")
+ case *ast.Ident:
+ obj = qpos.info.ObjectOf(n)
+ expr = n
+ case ast.Expr:
+ expr = n
+ default:
+ // TODO(adonovan): is this reachable?
+ return nil, fmt.Errorf("unexpected AST for expr: %T", n)
+ }
+
+ typ := qpos.info.TypeOf(expr)
+ constVal := qpos.info.Types[expr].Value
+
+ return &describeValueResult{
+ qpos: qpos,
+ expr: expr,
+ typ: typ,
+ constVal: constVal,
+ obj: obj,
+ }, nil
+}
+
+type describeValueResult struct {
+ qpos *queryPos
+ expr ast.Expr // query node
+ typ types.Type // type of expression
+ constVal exact.Value // value of expression, if constant
+ obj types.Object // var/func/const object, if expr was Ident
+}
+
+func (r *describeValueResult) display(printf printfFunc) {
+ var prefix, suffix string
+ if r.constVal != nil {
+ suffix = fmt.Sprintf(" of constant value %s", r.constVal)
+ }
+ switch obj := r.obj.(type) {
+ case *types.Func:
+ if recv := obj.Type().(*types.Signature).Recv(); recv != nil {
+ if _, ok := recv.Type().Underlying().(*types.Interface); ok {
+ prefix = "interface method "
+ } else {
+ prefix = "method "
+ }
+ }
+ }
+
+ // Describe the expression.
+ if r.obj != nil {
+ if r.obj.Pos() == r.expr.Pos() {
+ // defining ident
+ printf(r.expr, "definition of %s%s%s", prefix, r.qpos.objectString(r.obj), suffix)
+ } else {
+ // referring ident
+ printf(r.expr, "reference to %s%s%s", prefix, r.qpos.objectString(r.obj), suffix)
+ if def := r.obj.Pos(); def != token.NoPos {
+ printf(def, "defined here")
+ }
+ }
+ } else {
+ desc := astutil.NodeDescription(r.expr)
+ if suffix != "" {
+ // constant expression
+ printf(r.expr, "%s%s", desc, suffix)
+ } else {
+ // non-constant expression
+ printf(r.expr, "%s of type %s", desc, r.qpos.typeString(r.typ))
+ }
+ }
+}
+
+func (r *describeValueResult) toSerial(res *serial.Result, fset *token.FileSet) {
+ var value, objpos string
+ if r.constVal != nil {
+ value = r.constVal.String()
+ }
+ if r.obj != nil {
+ objpos = fset.Position(r.obj.Pos()).String()
+ }
+
+ res.Describe = &serial.Describe{
+ Desc: astutil.NodeDescription(r.expr),
+ Pos: fset.Position(r.expr.Pos()).String(),
+ Detail: "value",
+ Value: &serial.DescribeValue{
+ Type: r.qpos.typeString(r.typ),
+ Value: value,
+ ObjPos: objpos,
+ },
+ }
+}
+
+// ---- TYPE ------------------------------------------------------------
+
+func describeType(qpos *queryPos, path []ast.Node) (*describeTypeResult, error) {
+ var description string
+ var t types.Type
+ switch n := path[0].(type) {
+ case *ast.Ident:
+ t = qpos.info.TypeOf(n)
+ switch t := t.(type) {
+ case *types.Basic:
+ description = "reference to built-in "
+
+ case *types.Named:
+ isDef := t.Obj().Pos() == n.Pos() // see caveats at isDef above
+ if isDef {
+ description = "definition of "
+ } else {
+ description = "reference to "
+ }
+ }
+
+ case ast.Expr:
+ t = qpos.info.TypeOf(n)
+
+ default:
+ // Unreachable?
+ return nil, fmt.Errorf("unexpected AST for type: %T", n)
+ }
+
+ description = description + "type " + qpos.typeString(t)
+
+ // Show sizes for structs and named types (it's fairly obvious for others).
+ switch t.(type) {
+ case *types.Named, *types.Struct:
+ szs := types.StdSizes{8, 8} // assume amd64
+ description = fmt.Sprintf("%s (size %d, align %d)", description,
+ szs.Sizeof(t), szs.Alignof(t))
+ }
+
+ return &describeTypeResult{
+ qpos: qpos,
+ node: path[0],
+ description: description,
+ typ: t,
+ methods: accessibleMethods(t, qpos.info.Pkg),
+ }, nil
+}
+
+type describeTypeResult struct {
+ qpos *queryPos
+ node ast.Node
+ description string
+ typ types.Type
+ methods []*types.Selection
+}
+
+func (r *describeTypeResult) display(printf printfFunc) {
+ printf(r.node, "%s", r.description)
+
+ // Show the underlying type for a reference to a named type.
+ if nt, ok := r.typ.(*types.Named); ok && r.node.Pos() != nt.Obj().Pos() {
+ printf(nt.Obj(), "defined as %s", r.qpos.typeString(nt.Underlying()))
+ }
+
+ // Print the method set, if the type kind is capable of bearing methods.
+ switch r.typ.(type) {
+ case *types.Interface, *types.Struct, *types.Named:
+ if len(r.methods) > 0 {
+ printf(r.node, "Method set:")
+ for _, meth := range r.methods {
+ // TODO(adonovan): print these relative
+ // to the owning package, not the
+ // query package.
+ printf(meth.Obj(), "\t%s", r.qpos.selectionString(meth))
+ }
+ } else {
+ printf(r.node, "No methods.")
+ }
+ }
+}
+
+func (r *describeTypeResult) toSerial(res *serial.Result, fset *token.FileSet) {
+ var namePos, nameDef string
+ if nt, ok := r.typ.(*types.Named); ok {
+ namePos = fset.Position(nt.Obj().Pos()).String()
+ nameDef = nt.Underlying().String()
+ }
+ res.Describe = &serial.Describe{
+ Desc: r.description,
+ Pos: fset.Position(r.node.Pos()).String(),
+ Detail: "type",
+ Type: &serial.DescribeType{
+ Type: r.qpos.typeString(r.typ),
+ NamePos: namePos,
+ NameDef: nameDef,
+ Methods: methodsToSerial(r.qpos.info.Pkg, r.methods, fset),
+ },
+ }
+}
+
+// ---- PACKAGE ------------------------------------------------------------
+
+func describePackage(qpos *queryPos, path []ast.Node) (*describePackageResult, error) {
+ var description string
+ var pkg *types.Package
+ switch n := path[0].(type) {
+ case *ast.ImportSpec:
+ var pkgname *types.PkgName
+ if n.Name != nil {
+ pkgname = qpos.info.Defs[n.Name].(*types.PkgName)
+ } else if p := qpos.info.Implicits[n]; p != nil {
+ pkgname = p.(*types.PkgName)
+ }
+ pkg = pkgname.Imported()
+ description = fmt.Sprintf("import of package %q", pkg.Path())
+
+ case *ast.Ident:
+ if _, isDef := path[1].(*ast.File); isDef {
+ // e.g. package id
+ pkg = qpos.info.Pkg
+ description = fmt.Sprintf("definition of package %q", pkg.Path())
+ } else {
+ // e.g. import id "..."
+ // or id.F()
+ pkg = qpos.info.ObjectOf(n).(*types.PkgName).Imported()
+ description = fmt.Sprintf("reference to package %q", pkg.Path())
+ }
+
+ default:
+ // Unreachable?
+ return nil, fmt.Errorf("unexpected AST for package: %T", n)
+ }
+
+ var members []*describeMember
+ // NB: "unsafe" has no types.Package
+ if pkg != nil {
+ // Enumerate the accessible package members
+ // in lexicographic order.
+ for _, name := range pkg.Scope().Names() {
+ if pkg == qpos.info.Pkg || ast.IsExported(name) {
+ mem := pkg.Scope().Lookup(name)
+ var methods []*types.Selection
+ if mem, ok := mem.(*types.TypeName); ok {
+ methods = accessibleMethods(mem.Type(), qpos.info.Pkg)
+ }
+ members = append(members, &describeMember{
+ mem,
+ methods,
+ })
+
+ }
+ }
+ }
+
+ return &describePackageResult{qpos.fset, path[0], description, pkg, members}, nil
+}
+
+type describePackageResult struct {
+ fset *token.FileSet
+ node ast.Node
+ description string
+ pkg *types.Package
+ members []*describeMember // in lexicographic name order
+}
+
+type describeMember struct {
+ obj types.Object
+ methods []*types.Selection // in types.MethodSet order
+}
+
+func (r *describePackageResult) display(printf printfFunc) {
+ printf(r.node, "%s", r.description)
+
+ // Compute max width of name "column".
+ maxname := 0
+ for _, mem := range r.members {
+ if l := len(mem.obj.Name()); l > maxname {
+ maxname = l
+ }
+ }
+
+ for _, mem := range r.members {
+ printf(mem.obj, "\t%s", formatMember(mem.obj, maxname))
+ for _, meth := range mem.methods {
+ printf(meth.Obj(), "\t\t%s", types.SelectionString(meth, types.RelativeTo(r.pkg)))
+ }
+ }
+}
+
+func formatMember(obj types.Object, maxname int) string {
+ qualifier := types.RelativeTo(obj.Pkg())
+ var buf bytes.Buffer
+ fmt.Fprintf(&buf, "%-5s %-*s", tokenOf(obj), maxname, obj.Name())
+ switch obj := obj.(type) {
+ case *types.Const:
+ fmt.Fprintf(&buf, " %s = %s", types.TypeString(obj.Type(), qualifier), obj.Val().String())
+
+ case *types.Func:
+ fmt.Fprintf(&buf, " %s", types.TypeString(obj.Type(), qualifier))
+
+ case *types.TypeName:
+ // Abbreviate long aggregate type names.
+ var abbrev string
+ switch t := obj.Type().Underlying().(type) {
+ case *types.Interface:
+ if t.NumMethods() > 1 {
+ abbrev = "interface{...}"
+ }
+ case *types.Struct:
+ if t.NumFields() > 1 {
+ abbrev = "struct{...}"
+ }
+ }
+ if abbrev == "" {
+ fmt.Fprintf(&buf, " %s", types.TypeString(obj.Type().Underlying(), qualifier))
+ } else {
+ fmt.Fprintf(&buf, " %s", abbrev)
+ }
+
+ case *types.Var:
+ fmt.Fprintf(&buf, " %s", types.TypeString(obj.Type(), qualifier))
+ }
+ return buf.String()
+}
+
+func (r *describePackageResult) toSerial(res *serial.Result, fset *token.FileSet) {
+ var members []*serial.DescribeMember
+ for _, mem := range r.members {
+ typ := mem.obj.Type()
+ var val string
+ switch mem := mem.obj.(type) {
+ case *types.Const:
+ val = mem.Val().String()
+ case *types.TypeName:
+ typ = typ.Underlying()
+ }
+ members = append(members, &serial.DescribeMember{
+ Name: mem.obj.Name(),
+ Type: typ.String(),
+ Value: val,
+ Pos: fset.Position(mem.obj.Pos()).String(),
+ Kind: tokenOf(mem.obj),
+ Methods: methodsToSerial(r.pkg, mem.methods, fset),
+ })
+ }
+ res.Describe = &serial.Describe{
+ Desc: r.description,
+ Pos: fset.Position(r.node.Pos()).String(),
+ Detail: "package",
+ Package: &serial.DescribePackage{
+ Path: r.pkg.Path(),
+ Members: members,
+ },
+ }
+}
+
+func tokenOf(o types.Object) string {
+ switch o.(type) {
+ case *types.Func:
+ return "func"
+ case *types.Var:
+ return "var"
+ case *types.TypeName:
+ return "type"
+ case *types.Const:
+ return "const"
+ case *types.PkgName:
+ return "package"
+ }
+ panic(o)
+}
+
+// ---- STATEMENT ------------------------------------------------------------
+
+func describeStmt(qpos *queryPos, path []ast.Node) (*describeStmtResult, error) {
+ var description string
+ switch n := path[0].(type) {
+ case *ast.Ident:
+ if qpos.info.Defs[n] != nil {
+ description = "labelled statement"
+ } else {
+ description = "reference to labelled statement"
+ }
+
+ default:
+ // Nothing much to say about statements.
+ description = astutil.NodeDescription(n)
+ }
+ return &describeStmtResult{qpos.fset, path[0], description}, nil
+}
+
+type describeStmtResult struct {
+ fset *token.FileSet
+ node ast.Node
+ description string
+}
+
+func (r *describeStmtResult) display(printf printfFunc) {
+ printf(r.node, "%s", r.description)
+}
+
+func (r *describeStmtResult) toSerial(res *serial.Result, fset *token.FileSet) {
+ res.Describe = &serial.Describe{
+ Desc: r.description,
+ Pos: fset.Position(r.node.Pos()).String(),
+ Detail: "unknown",
+ }
+}
+
+// ------------------- Utilities -------------------
+
+// pathToString returns a string containing the concrete types of the
+// nodes in path.
+func pathToString(path []ast.Node) string {
+ var buf bytes.Buffer
+ fmt.Fprint(&buf, "[")
+ for i, n := range path {
+ if i > 0 {
+ fmt.Fprint(&buf, " ")
+ }
+ fmt.Fprint(&buf, strings.TrimPrefix(fmt.Sprintf("%T", n), "*ast."))
+ }
+ fmt.Fprint(&buf, "]")
+ return buf.String()
+}
+
+func accessibleMethods(t types.Type, from *types.Package) []*types.Selection {
+ var methods []*types.Selection
+ for _, meth := range typeutil.IntuitiveMethodSet(t, nil) {
+ if isAccessibleFrom(meth.Obj(), from) {
+ methods = append(methods, meth)
+ }
+ }
+ return methods
+}
+
+func isAccessibleFrom(obj types.Object, pkg *types.Package) bool {
+ return ast.IsExported(obj.Name()) || obj.Pkg() == pkg
+}
+
+func methodsToSerial(this *types.Package, methods []*types.Selection, fset *token.FileSet) []serial.DescribeMethod {
+ qualifier := types.RelativeTo(this)
+ var jmethods []serial.DescribeMethod
+ for _, meth := range methods {
+ var ser serial.DescribeMethod
+ if meth != nil { // may contain nils when called by implements (on a method)
+ ser = serial.DescribeMethod{
+ Name: types.SelectionString(meth, qualifier),
+ Pos: fset.Position(meth.Obj().Pos()).String(),
+ }
+ }
+ jmethods = append(jmethods, ser)
+ }
+ return jmethods
+}
diff --git a/oracle/freevars.go b/oracle/freevars.go
new file mode 100644
index 0000000..400a118
--- /dev/null
+++ b/oracle/freevars.go
@@ -0,0 +1,222 @@
+// 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 oracle
+
+import (
+ "bytes"
+ "go/ast"
+ "go/printer"
+ "go/token"
+ "sort"
+
+ "golang.org/x/tools/go/loader"
+ "golang.org/x/tools/go/types"
+ "golang.org/x/tools/oracle/serial"
+)
+
+// freevars displays the lexical (not package-level) free variables of
+// the selection.
+//
+// It treats A.B.C as a separate variable from A to reveal the parts
+// of an aggregate type that are actually needed.
+// This aids refactoring.
+//
+// TODO(adonovan): optionally display the free references to
+// file/package scope objects, and to objects from other packages.
+// Depending on where the resulting function abstraction will go,
+// these might be interesting. Perhaps group the results into three
+// bands.
+//
+func freevars(q *Query) error {
+ lconf := loader.Config{Build: q.Build}
+ allowErrors(&lconf)
+
+ if err := importQueryPackage(q.Pos, &lconf); err != nil {
+ return err
+ }
+
+ // Load/parse/type-check the program.
+ lprog, err := lconf.Load()
+ if err != nil {
+ return err
+ }
+ q.Fset = lprog.Fset
+
+ qpos, err := parseQueryPos(lprog, q.Pos, false)
+ if err != nil {
+ return err
+ }
+
+ file := qpos.path[len(qpos.path)-1] // the enclosing file
+ fileScope := qpos.info.Scopes[file]
+ pkgScope := fileScope.Parent()
+
+ // The id and sel functions return non-nil if they denote an
+ // object o or selection o.x.y that is referenced by the
+ // selection but defined neither within the selection nor at
+ // file scope, i.e. it is in the lexical environment.
+ var id func(n *ast.Ident) types.Object
+ var sel func(n *ast.SelectorExpr) types.Object
+
+ sel = func(n *ast.SelectorExpr) types.Object {
+ switch x := unparen(n.X).(type) {
+ case *ast.SelectorExpr:
+ return sel(x)
+ case *ast.Ident:
+ return id(x)
+ }
+ return nil
+ }
+
+ id = func(n *ast.Ident) types.Object {
+ obj := qpos.info.Uses[n]
+ if obj == nil {
+ return nil // not a reference
+ }
+ if _, ok := obj.(*types.PkgName); ok {
+ return nil // imported package
+ }
+ if !(file.Pos() <= obj.Pos() && obj.Pos() <= file.End()) {
+ return nil // not defined in this file
+ }
+ scope := obj.Parent()
+ if scope == nil {
+ return nil // e.g. interface method, struct field
+ }
+ if scope == fileScope || scope == pkgScope {
+ return nil // defined at file or package scope
+ }
+ if qpos.start <= obj.Pos() && obj.Pos() <= qpos.end {
+ return nil // defined within selection => not free
+ }
+ return obj
+ }
+
+ // Maps each reference that is free in the selection
+ // to the object it refers to.
+ // The map de-duplicates repeated references.
+ refsMap := make(map[string]freevarsRef)
+
+ // Visit all the identifiers in the selected ASTs.
+ ast.Inspect(qpos.path[0], func(n ast.Node) bool {
+ if n == nil {
+ return true // popping DFS stack
+ }
+
+ // Is this node contained within the selection?
+ // (freevars permits inexact selections,
+ // like two stmts in a block.)
+ if qpos.start <= n.Pos() && n.End() <= qpos.end {
+ var obj types.Object
+ var prune bool
+ switch n := n.(type) {
+ case *ast.Ident:
+ obj = id(n)
+
+ case *ast.SelectorExpr:
+ obj = sel(n)
+ prune = true
+ }
+
+ if obj != nil {
+ var kind string
+ switch obj.(type) {
+ case *types.Var:
+ kind = "var"
+ case *types.Func:
+ kind = "func"
+ case *types.TypeName:
+ kind = "type"
+ case *types.Const:
+ kind = "const"
+ case *types.Label:
+ kind = "label"
+ default:
+ panic(obj)
+ }
+
+ typ := qpos.info.TypeOf(n.(ast.Expr))
+ ref := freevarsRef{kind, printNode(lprog.Fset, n), typ, obj}
+ refsMap[ref.ref] = ref
+
+ if prune {
+ return false // don't descend
+ }
+ }
+ }
+
+ return true // descend
+ })
+
+ refs := make([]freevarsRef, 0, len(refsMap))
+ for _, ref := range refsMap {
+ refs = append(refs, ref)
+ }
+ sort.Sort(byRef(refs))
+
+ q.result = &freevarsResult{
+ qpos: qpos,
+ refs: refs,
+ }
+ return nil
+}
+
+type freevarsResult struct {
+ qpos *queryPos
+ refs []freevarsRef
+}
+
+type freevarsRef struct {
+ kind string
+ ref string
+ typ types.Type
+ obj types.Object
+}
+
+func (r *freevarsResult) display(printf printfFunc) {
+ if len(r.refs) == 0 {
+ printf(r.qpos, "No free identifiers.")
+ } else {
+ printf(r.qpos, "Free identifiers:")
+ qualifier := types.RelativeTo(r.qpos.info.Pkg)
+ for _, ref := range r.refs {
+ // Avoid printing "type T T".
+ var typstr string
+ if ref.kind != "type" {
+ typstr = " " + types.TypeString(ref.typ, qualifier)
+ }
+ printf(ref.obj, "%s %s%s", ref.kind, ref.ref, typstr)
+ }
+ }
+}
+
+func (r *freevarsResult) toSerial(res *serial.Result, fset *token.FileSet) {
+ var refs []*serial.FreeVar
+ for _, ref := range r.refs {
+ refs = append(refs,
+ &serial.FreeVar{
+ Pos: fset.Position(ref.obj.Pos()).String(),
+ Kind: ref.kind,
+ Ref: ref.ref,
+ Type: ref.typ.String(),
+ })
+ }
+ res.Freevars = refs
+}
+
+// -------- utils --------
+
+type byRef []freevarsRef
+
+func (p byRef) Len() int { return len(p) }
+func (p byRef) Less(i, j int) bool { return p[i].ref < p[j].ref }
+func (p byRef) Swap(i, j int) { p[i], p[j] = p[j], p[i] }
+
+// printNode returns the pretty-printed syntax of n.
+func printNode(fset *token.FileSet, n ast.Node) string {
+ var buf bytes.Buffer
+ printer.Fprint(&buf, fset, n)
+ return buf.String()
+}
diff --git a/oracle/implements.go b/oracle/implements.go
new file mode 100644
index 0000000..3155ca2
--- /dev/null
+++ b/oracle/implements.go
@@ -0,0 +1,330 @@
+// 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 oracle
+
+import (
+ "fmt"
+ "go/ast"
+ "go/token"
+ "reflect"
+ "sort"
+ "strings"
+
+ "golang.org/x/tools/go/loader"
+ "golang.org/x/tools/go/types"
+ "golang.org/x/tools/go/types/typeutil"
+ "golang.org/x/tools/oracle/serial"
+)
+
+// Implements displays the "implements" relation as it pertains to the
+// selected type within a single package.
+// If the selection is a method, 'implements' displays
+// the corresponding methods of the types that would have been reported
+// by an implements query on the receiver type.
+//
+func implements(q *Query) error {
+ lconf := loader.Config{Build: q.Build}
+ allowErrors(&lconf)
+
+ if err := importQueryPackage(q.Pos, &lconf); err != nil {
+ return err
+ }
+
+ // Load/parse/type-check the program.
+ lprog, err := lconf.Load()
+ if err != nil {
+ return err
+ }
+ q.Fset = lprog.Fset
+
+ qpos, err := parseQueryPos(lprog, q.Pos, false)
+ if err != nil {
+ return err
+ }
+
+ // Find the selected type.
+ path, action := findInterestingNode(qpos.info, qpos.path)
+
+ var method *types.Func
+ var T types.Type // selected type (receiver if method != nil)
+
+ switch action {
+ case actionExpr:
+ // method?
+ if id, ok := path[0].(*ast.Ident); ok {
+ if obj, ok := qpos.info.ObjectOf(id).(*types.Func); ok {
+ recv := obj.Type().(*types.Signature).Recv()
+ if recv == nil {
+ return fmt.Errorf("this function is not a method")
+ }
+ method = obj
+ T = recv.Type()
+ }
+ }
+ case actionType:
+ T = qpos.info.TypeOf(path[0].(ast.Expr))
+ }
+ if T == nil {
+ return fmt.Errorf("no type or method here")
+ }
+
+ // Find all named types, even local types (which can have
+ // methods via promotion) and the built-in "error".
+ //
+ // TODO(adonovan): include all packages in PTA scope too?
+ // i.e. don't reduceScope?
+ //
+ var allNamed []types.Type
+ for _, info := range lprog.AllPackages {
+ for _, obj := range info.Defs {
+ if obj, ok := obj.(*types.TypeName); ok {
+ allNamed = append(allNamed, obj.Type())
+ }
+ }
+ }
+ allNamed = append(allNamed, types.Universe.Lookup("error").Type())
+
+ var msets typeutil.MethodSetCache
+
+ // Test each named type.
+ var to, from, fromPtr []types.Type
+ for _, U := range allNamed {
+ if isInterface(T) {
+ if msets.MethodSet(T).Len() == 0 {
+ continue // empty interface
+ }
+ if isInterface(U) {
+ if msets.MethodSet(U).Len() == 0 {
+ continue // empty interface
+ }
+
+ // T interface, U interface
+ if !types.Identical(T, U) {
+ if types.AssignableTo(U, T) {
+ to = append(to, U)
+ }
+ if types.AssignableTo(T, U) {
+ from = append(from, U)
+ }
+ }
+ } else {
+ // T interface, U concrete
+ if types.AssignableTo(U, T) {
+ to = append(to, U)
+ } else if pU := types.NewPointer(U); types.AssignableTo(pU, T) {
+ to = append(to, pU)
+ }
+ }
+ } else if isInterface(U) {
+ if msets.MethodSet(U).Len() == 0 {
+ continue // empty interface
+ }
+
+ // T concrete, U interface
+ if types.AssignableTo(T, U) {
+ from = append(from, U)
+ } else if pT := types.NewPointer(T); types.AssignableTo(pT, U) {
+ fromPtr = append(fromPtr, U)
+ }
+ }
+ }
+
+ var pos interface{} = qpos
+ if nt, ok := deref(T).(*types.Named); ok {
+ pos = nt.Obj()
+ }
+
+ // Sort types (arbitrarily) to ensure test determinism.
+ sort.Sort(typesByString(to))
+ sort.Sort(typesByString(from))
+ sort.Sort(typesByString(fromPtr))
+
+ var toMethod, fromMethod, fromPtrMethod []*types.Selection // contain nils
+ if method != nil {
+ for _, t := range to {
+ toMethod = append(toMethod,
+ types.NewMethodSet(t).Lookup(method.Pkg(), method.Name()))
+ }
+ for _, t := range from {
+ fromMethod = append(fromMethod,
+ types.NewMethodSet(t).Lookup(method.Pkg(), method.Name()))
+ }
+ for _, t := range fromPtr {
+ fromPtrMethod = append(fromPtrMethod,
+ types.NewMethodSet(t).Lookup(method.Pkg(), method.Name()))
+ }
+ }
+
+ q.result = &implementsResult{
+ qpos, T, pos, to, from, fromPtr, method, toMethod, fromMethod, fromPtrMethod,
+ }
+ return nil
+}
+
+type implementsResult struct {
+ qpos *queryPos
+
+ t types.Type // queried type (not necessarily named)
+ pos interface{} // pos of t (*types.Name or *QueryPos)
+ to []types.Type // named or ptr-to-named types assignable to interface T
+ from []types.Type // named interfaces assignable from T
+ fromPtr []types.Type // named interfaces assignable only from *T
+
+ // if a method was queried:
+ method *types.Func // queried method
+ toMethod []*types.Selection // method of type to[i], if any
+ fromMethod []*types.Selection // method of type from[i], if any
+ fromPtrMethod []*types.Selection // method of type fromPtrMethod[i], if any
+}
+
+func (r *implementsResult) display(printf printfFunc) {
+ relation := "is implemented by"
+
+ meth := func(sel *types.Selection) {
+ if sel != nil {
+ printf(sel.Obj(), "\t%s method (%s).%s",
+ relation, r.qpos.typeString(sel.Recv()), sel.Obj().Name())
+ }
+ }
+
+ if isInterface(r.t) {
+ if types.NewMethodSet(r.t).Len() == 0 { // TODO(adonovan): cache mset
+ printf(r.pos, "empty interface type %s", r.qpos.typeString(r.t))
+ return
+ }
+
+ if r.method == nil {
+ printf(r.pos, "interface type %s", r.qpos.typeString(r.t))
+ } else {
+ printf(r.method, "abstract method %s", r.qpos.objectString(r.method))
+ }
+
+ // Show concrete types (or methods) first; use two passes.
+ for i, sub := range r.to {
+ if !isInterface(sub) {
+ if r.method == nil {
+ printf(deref(sub).(*types.Named).Obj(), "\t%s %s type %s",
+ relation, typeKind(sub), r.qpos.typeString(sub))
+ } else {
+ meth(r.toMethod[i])
+ }
+ }
+ }
+ for i, sub := range r.to {
+ if isInterface(sub) {
+ if r.method == nil {
+ printf(sub.(*types.Named).Obj(), "\t%s %s type %s",
+ relation, typeKind(sub), r.qpos.typeString(sub))
+ } else {
+ meth(r.toMethod[i])
+ }
+ }
+ }
+
+ relation = "implements"
+ for i, super := range r.from {
+ if r.method == nil {
+ printf(super.(*types.Named).Obj(), "\t%s %s",
+ relation, r.qpos.typeString(super))
+ } else {
+ meth(r.fromMethod[i])
+ }
+ }
+ } else {
+ relation = "implements"
+
+ if r.from != nil {
+ if r.method == nil {
+ printf(r.pos, "%s type %s",
+ typeKind(r.t), r.qpos.typeString(r.t))
+ } else {
+ printf(r.method, "concrete method %s",
+ r.qpos.objectString(r.method))
+ }
+ for i, super := range r.from {
+ if r.method == nil {
+ printf(super.(*types.Named).Obj(), "\t%s %s",
+ relation, r.qpos.typeString(super))
+ } else {
+ meth(r.fromMethod[i])
+ }
+ }
+ }
+ if r.fromPtr != nil {
+ if r.method == nil {
+ printf(r.pos, "pointer type *%s", r.qpos.typeString(r.t))
+ } else {
+ // TODO(adonovan): de-dup (C).f and (*C).f implementing (I).f.
+ printf(r.method, "concrete method %s",
+ r.qpos.objectString(r.method))
+ }
+
+ for i, psuper := range r.fromPtr {
+ if r.method == nil {
+ printf(psuper.(*types.Named).Obj(), "\t%s %s",
+ relation, r.qpos.typeString(psuper))
+ } else {
+ meth(r.fromPtrMethod[i])
+ }
+ }
+ } else if r.from == nil {
+ printf(r.pos, "%s type %s implements only interface{}",
+ typeKind(r.t), r.qpos.typeString(r.t))
+ }
+ }
+}
+
+func (r *implementsResult) toSerial(res *serial.Result, fset *token.FileSet) {
+ res.Implements = &serial.Implements{
+ T: makeImplementsType(r.t, fset),
+ AssignableTo: makeImplementsTypes(r.to, fset),
+ AssignableFrom: makeImplementsTypes(r.from, fset),
+ AssignableFromPtr: makeImplementsTypes(r.fromPtr, fset),
+ AssignableToMethod: methodsToSerial(r.qpos.info.Pkg, r.toMethod, fset),
+ AssignableFromMethod: methodsToSerial(r.qpos.info.Pkg, r.fromMethod, fset),
+ AssignableFromPtrMethod: methodsToSerial(r.qpos.info.Pkg, r.fromPtrMethod, fset),
+ }
+ if r.method != nil {
+ res.Implements.Method = &serial.DescribeMethod{
+ Name: r.qpos.objectString(r.method),
+ Pos: fset.Position(r.method.Pos()).String(),
+ }
+ }
+}
+
+func makeImplementsTypes(tt []types.Type, fset *token.FileSet) []serial.ImplementsType {
+ var r []serial.ImplementsType
+ for _, t := range tt {
+ r = append(r, makeImplementsType(t, fset))
+ }
+ return r
+}
+
+func makeImplementsType(T types.Type, fset *token.FileSet) serial.ImplementsType {
+ var pos token.Pos
+ if nt, ok := deref(T).(*types.Named); ok { // implementsResult.t may be non-named
+ pos = nt.Obj().Pos()
+ }
+ return serial.ImplementsType{
+ Name: T.String(),
+ Pos: fset.Position(pos).String(),
+ Kind: typeKind(T),
+ }
+}
+
+// typeKind returns a string describing the underlying kind of type,
+// e.g. "slice", "array", "struct".
+func typeKind(T types.Type) string {
+ s := reflect.TypeOf(T.Underlying()).String()
+ return strings.ToLower(strings.TrimPrefix(s, "*types."))
+}
+
+func isInterface(T types.Type) bool { return types.IsInterface(T) }
+
+type typesByString []types.Type
+
+func (p typesByString) Len() int { return len(p) }
+func (p typesByString) Less(i, j int) bool { return p[i].String() < p[j].String() }
+func (p typesByString) Swap(i, j int) { p[i], p[j] = p[j], p[i] }
diff --git a/oracle/oracle.go b/oracle/oracle.go
new file mode 100644
index 0000000..544cfa4
--- /dev/null
+++ b/oracle/oracle.go
@@ -0,0 +1,364 @@
+// 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 oracle contains the implementation of the oracle tool whose
+// command-line is provided by golang.org/x/tools/cmd/oracle.
+//
+// http://golang.org/s/oracle-design
+// http://golang.org/s/oracle-user-manual
+//
+package oracle // import "golang.org/x/tools/oracle"
+
+// This file defines oracle.Query, the entry point for the oracle tool.
+// The actual executable is defined in cmd/oracle.
+
+// TODO(adonovan): new queries
+// - show all statements that may update the selected lvalue
+// (local, global, field, etc).
+// - show all places where an object of type T is created
+// (&T{}, var t T, new(T), new(struct{array [3]T}), etc.
+
+import (
+ "fmt"
+ "go/ast"
+ "go/build"
+ "go/parser"
+ "go/token"
+ "io"
+ "path/filepath"
+
+ "golang.org/x/tools/go/ast/astutil"
+ "golang.org/x/tools/go/loader"
+ "golang.org/x/tools/go/pointer"
+ "golang.org/x/tools/go/ssa"
+ "golang.org/x/tools/go/types"
+ "golang.org/x/tools/oracle/serial"
+)
+
+type printfFunc func(pos interface{}, format string, args ...interface{})
+
+// queryResult is the interface of each query-specific result type.
+type queryResult interface {
+ toSerial(res *serial.Result, fset *token.FileSet)
+ display(printf printfFunc)
+}
+
+// A QueryPos represents the position provided as input to a query:
+// a textual extent in the program's source code, the AST node it
+// corresponds to, and the package to which it belongs.
+// Instances are created by parseQueryPos.
+type queryPos struct {
+ fset *token.FileSet
+ start, end token.Pos // source extent of query
+ path []ast.Node // AST path from query node to root of ast.File
+ exact bool // 2nd result of PathEnclosingInterval
+ info *loader.PackageInfo // type info for the queried package (nil for fastQueryPos)
+}
+
+// TypeString prints type T relative to the query position.
+func (qpos *queryPos) typeString(T types.Type) string {
+ return types.TypeString(T, types.RelativeTo(qpos.info.Pkg))
+}
+
+// ObjectString prints object obj relative to the query position.
+func (qpos *queryPos) objectString(obj types.Object) string {
+ return types.ObjectString(obj, types.RelativeTo(qpos.info.Pkg))
+}
+
+// SelectionString prints selection sel relative to the query position.
+func (qpos *queryPos) selectionString(sel *types.Selection) string {
+ return types.SelectionString(sel, types.RelativeTo(qpos.info.Pkg))
+}
+
+// A Query specifies a single oracle query.
+type Query struct {
+ Mode string // query mode ("callers", etc)
+ Pos string // query position
+ Build *build.Context // package loading configuration
+
+ // pointer analysis options
+ Scope []string // main packages in (*loader.Config).FromArgs syntax
+ PTALog io.Writer // (optional) pointer-analysis log file
+ Reflection bool // model reflection soundly (currently slow).
+
+ // Populated during Run()
+ Fset *token.FileSet
+ result queryResult
+}
+
+// Serial returns an instance of serial.Result, which implements the
+// {xml,json}.Marshaler interfaces so that query results can be
+// serialized as JSON or XML.
+//
+func (q *Query) Serial() *serial.Result {
+ resj := &serial.Result{Mode: q.Mode}
+ q.result.toSerial(resj, q.Fset)
+ return resj
+}
+
+// WriteTo writes the oracle query result res to out in a compiler diagnostic format.
+func (q *Query) WriteTo(out io.Writer) {
+ printf := func(pos interface{}, format string, args ...interface{}) {
+ fprintf(out, q.Fset, pos, format, args...)
+ }
+ q.result.display(printf)
+}
+
+// Run runs an oracle query and populates its Fset and Result.
+func Run(q *Query) error {
+ switch q.Mode {
+ case "callees":
+ return callees(q)
+ case "callers":
+ return callers(q)
+ case "callstack":
+ return callstack(q)
+ case "peers":
+ return peers(q)
+ case "pointsto":
+ return pointsto(q)
+ case "whicherrs":
+ return whicherrs(q)
+ case "definition":
+ return definition(q)
+ case "describe":
+ return describe(q)
+ case "freevars":
+ return freevars(q)
+ case "implements":
+ return implements(q)
+ case "referrers":
+ return referrers(q)
+ case "what":
+ return what(q)
+ default:
+ return fmt.Errorf("invalid mode: %q", q.Mode)
+ }
+}
+
+func setPTAScope(lconf *loader.Config, scope []string) error {
+ if len(scope) == 0 {
+ return fmt.Errorf("no packages specified for pointer analysis scope")
+ }
+
+ // Determine initial packages for PTA.
+ args, err := lconf.FromArgs(scope, true)
+ if err != nil {
+ return err
+ }
+ if len(args) > 0 {
+ return fmt.Errorf("surplus arguments: %q", args)
+ }
+ return nil
+}
+
+// Create a pointer.Config whose scope is the initial packages of lprog
+// and their dependencies.
+func setupPTA(prog *ssa.Program, lprog *loader.Program, ptaLog io.Writer, reflection bool) (*pointer.Config, error) {
+ // TODO(adonovan): the body of this function is essentially
+ // duplicated in all go/pointer clients. Refactor.
+
+ // For each initial package (specified on the command line),
+ // if it has a main function, analyze that,
+ // otherwise analyze its tests, if any.
+ var testPkgs, mains []*ssa.Package
+ for _, info := range lprog.InitialPackages() {
+ initialPkg := prog.Package(info.Pkg)
+
+ // Add package to the pointer analysis scope.
+ if initialPkg.Func("main") != nil {
+ mains = append(mains, initialPkg)
+ } else {
+ testPkgs = append(testPkgs, initialPkg)
+ }
+ }
+ if testPkgs != nil {
+ if p := prog.CreateTestMainPackage(testPkgs...); p != nil {
+ mains = append(mains, p)
+ }
+ }
+ if mains == nil {
+ return nil, fmt.Errorf("analysis scope has no main and no tests")
+ }
+ return &pointer.Config{
+ Log: ptaLog,
+ Reflection: reflection,
+ Mains: mains,
+ }, nil
+}
+
+// importQueryPackage finds the package P containing the
+// query position and tells conf to import it.
+func importQueryPackage(pos string, conf *loader.Config) error {
+ fqpos, err := fastQueryPos(pos)
+ if err != nil {
+ return err // bad query
+ }
+ filename := fqpos.fset.File(fqpos.start).Name()
+
+ // This will not work for ad-hoc packages
+ // such as $GOROOT/src/net/http/triv.go.
+ // TODO(adonovan): ensure we report a clear error.
+ _, importPath, err := guessImportPath(filename, conf.Build)
+ if err != nil {
+ return err // can't find GOPATH dir
+ }
+ if importPath == "" {
+ return fmt.Errorf("can't guess import path from %s", filename)
+ }
+
+ // Check that it's possible to load the queried package.
+ // (e.g. oracle tests contain different 'package' decls in same dir.)
+ // Keep consistent with logic in loader/util.go!
+ cfg2 := *conf.Build
+ cfg2.CgoEnabled = false
+ bp, err := cfg2.Import(importPath, "", 0)
+ if err != nil {
+ return err // no files for package
+ }
+
+ switch pkgContainsFile(bp, filename) {
+ case 'T':
+ conf.ImportWithTests(importPath)
+ case 'X':
+ conf.ImportWithTests(importPath)
+ importPath += "_test" // for TypeCheckFuncBodies
+ case 'G':
+ conf.Import(importPath)
+ default:
+ return fmt.Errorf("package %q doesn't contain file %s",
+ importPath, filename)
+ }
+
+ conf.TypeCheckFuncBodies = func(p string) bool { return p == importPath }
+
+ return nil
+}
+
+// pkgContainsFile reports whether file was among the packages Go
+// files, Test files, eXternal test files, or not found.
+func pkgContainsFile(bp *build.Package, filename string) byte {
+ for i, files := range [][]string{bp.GoFiles, bp.TestGoFiles, bp.XTestGoFiles} {
+ for _, file := range files {
+ if sameFile(filepath.Join(bp.Dir, file), filename) {
+ return "GTX"[i]
+ }
+ }
+ }
+ return 0 // not found
+}
+
+// ParseQueryPos parses the source query position pos and returns the
+// AST node of the loaded program lprog that it identifies.
+// If needExact, it must identify a single AST subtree;
+// this is appropriate for queries that allow fairly arbitrary syntax,
+// e.g. "describe".
+//
+func parseQueryPos(lprog *loader.Program, posFlag string, needExact bool) (*queryPos, error) {
+ filename, startOffset, endOffset, err := parsePosFlag(posFlag)
+ if err != nil {
+ return nil, err
+ }
+ start, end, err := findQueryPos(lprog.Fset, filename, startOffset, endOffset)
+ if err != nil {
+ return nil, err
+ }
+ info, path, exact := lprog.PathEnclosingInterval(start, end)
+ if path == nil {
+ return nil, fmt.Errorf("no syntax here")
+ }
+ if needExact && !exact {
+ return nil, fmt.Errorf("ambiguous selection within %s", astutil.NodeDescription(path[0]))
+ }
+ return &queryPos{lprog.Fset, start, end, path, exact, info}, nil
+}
+
+// ---------- Utilities ----------
+
+// allowErrors causes type errors to be silently ignored.
+// (Not suitable if SSA construction follows.)
+func allowErrors(lconf *loader.Config) {
+ ctxt := *lconf.Build // copy
+ ctxt.CgoEnabled = false
+ lconf.Build = &ctxt
+ lconf.AllowErrors = true
+ // AllErrors makes the parser always return an AST instead of
+ // bailing out after 10 errors and returning an empty ast.File.
+ lconf.ParserMode = parser.AllErrors
+ lconf.TypeChecker.Error = func(err error) {}
+}
+
+// ptrAnalysis runs the pointer analysis and returns its result.
+func ptrAnalysis(conf *pointer.Config) *pointer.Result {
+ result, err := pointer.Analyze(conf)
+ if err != nil {
+ panic(err) // pointer analysis internal error
+ }
+ return result
+}
+
+func unparen(e ast.Expr) ast.Expr { return astutil.Unparen(e) }
+
+// deref returns a pointer's element type; otherwise it returns typ.
+func deref(typ types.Type) types.Type {
+ if p, ok := typ.Underlying().(*types.Pointer); ok {
+ return p.Elem()
+ }
+ return typ
+}
+
+// fprintf prints to w a message of the form "location: message\n"
+// where location is derived from pos.
+//
+// pos must be one of:
+// - a token.Pos, denoting a position
+// - an ast.Node, denoting an interval
+// - anything with a Pos() method:
+// ssa.Member, ssa.Value, ssa.Instruction, types.Object, pointer.Label, etc.
+// - a QueryPos, denoting the extent of the user's query.
+// - nil, meaning no position at all.
+//
+// The output format is is compatible with the 'gnu'
+// compilation-error-regexp in Emacs' compilation mode.
+// TODO(adonovan): support other editors.
+//
+func fprintf(w io.Writer, fset *token.FileSet, pos interface{}, format string, args ...interface{}) {
+ var start, end token.Pos
+ switch pos := pos.(type) {
+ case ast.Node:
+ start = pos.Pos()
+ end = pos.End()
+ case token.Pos:
+ start = pos
+ end = start
+ case interface {
+ Pos() token.Pos
+ }:
+ start = pos.Pos()
+ end = start
+ case *queryPos:
+ start = pos.start
+ end = pos.end
+ case nil:
+ // no-op
+ default:
+ panic(fmt.Sprintf("invalid pos: %T", pos))
+ }
+
+ if sp := fset.Position(start); start == end {
+ // (prints "-: " for token.NoPos)
+ fmt.Fprintf(w, "%s: ", sp)
+ } else {
+ ep := fset.Position(end)
+ // The -1 below is a concession to Emacs's broken use of
+ // inclusive (not half-open) intervals.
+ // Other editors may not want it.
+ // TODO(adonovan): add an -editor=vim|emacs|acme|auto
+ // flag; auto uses EMACS=t / VIM=... / etc env vars.
+ fmt.Fprintf(w, "%s:%d.%d-%d.%d: ",
+ sp.Filename, sp.Line, sp.Column, ep.Line, ep.Column-1)
+ }
+ fmt.Fprintf(w, format, args...)
+ io.WriteString(w, "\n")
+}
diff --git a/oracle/oracle_test.go b/oracle/oracle_test.go
new file mode 100644
index 0000000..0dd1cdc
--- /dev/null
+++ b/oracle/oracle_test.go
@@ -0,0 +1,272 @@
+// 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 oracle_test
+
+// This file defines a test framework for oracle queries.
+//
+// The files beneath testdata/src/main contain Go programs containing
+// query annotations of the form:
+//
+// @verb id "select"
+//
+// where verb is the query mode (e.g. "callers"), id is a unique name
+// for this query, and "select" is a regular expression matching the
+// substring of the current line that is the query's input selection.
+//
+// The expected output for each query is provided in the accompanying
+// .golden file.
+//
+// (Location information is not included because it's too fragile to
+// display as text. TODO(adonovan): think about how we can test its
+// correctness, since it is critical information.)
+//
+// Run this test with:
+// % go test golang.org/x/tools/oracle -update
+// to update the golden files.
+
+import (
+ "bytes"
+ "encoding/json"
+ "flag"
+ "fmt"
+ "go/build"
+ "go/parser"
+ "go/token"
+ "io"
+ "io/ioutil"
+ "os"
+ "os/exec"
+ "regexp"
+ "runtime"
+ "strconv"
+ "strings"
+ "testing"
+
+ "golang.org/x/tools/oracle"
+)
+
+var updateFlag = flag.Bool("update", false, "Update the golden files.")
+
+type query struct {
+ id string // unique id
+ verb string // query mode, e.g. "callees"
+ posn token.Position // position of of query
+ filename string
+ queryPos string // value of -pos flag
+}
+
+func parseRegexp(text string) (*regexp.Regexp, error) {
+ pattern, err := strconv.Unquote(text)
+ if err != nil {
+ return nil, fmt.Errorf("can't unquote %s", text)
+ }
+ return regexp.Compile(pattern)
+}
+
+// parseQueries parses and returns the queries in the named file.
+func parseQueries(t *testing.T, filename string) []*query {
+ filedata, err := ioutil.ReadFile(filename)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ // Parse the file once to discover the test queries.
+ fset := token.NewFileSet()
+ f, err := parser.ParseFile(fset, filename, filedata, parser.ParseComments)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ lines := bytes.Split(filedata, []byte("\n"))
+
+ var queries []*query
+ queriesById := make(map[string]*query)
+
+ // Find all annotations of these forms:
+ expectRe := regexp.MustCompile(`@([a-z]+)\s+(\S+)\s+(\".*)$`) // @verb id "regexp"
+ for _, c := range f.Comments {
+ text := strings.TrimSpace(c.Text())
+ if text == "" || text[0] != '@' {
+ continue
+ }
+ posn := fset.Position(c.Pos())
+
+ // @verb id "regexp"
+ match := expectRe.FindStringSubmatch(text)
+ if match == nil {
+ t.Errorf("%s: ill-formed query: %s", posn, text)
+ continue
+ }
+
+ id := match[2]
+ if prev, ok := queriesById[id]; ok {
+ t.Errorf("%s: duplicate id %s", posn, id)
+ t.Errorf("%s: previously used here", prev.posn)
+ continue
+ }
+
+ q := &query{
+ id: id,
+ verb: match[1],
+ filename: filename,
+ posn: posn,
+ }
+
+ if match[3] != `"nopos"` {
+ selectRe, err := parseRegexp(match[3])
+ if err != nil {
+ t.Errorf("%s: %s", posn, err)
+ continue
+ }
+
+ // Find text of the current line, sans query.
+ // (Queries must be // not /**/ comments.)
+ line := lines[posn.Line-1][:posn.Column-1]
+
+ // Apply regexp to current line to find input selection.
+ loc := selectRe.FindIndex(line)
+ if loc == nil {
+ t.Errorf("%s: selection pattern %s doesn't match line %q",
+ posn, match[3], string(line))
+ continue
+ }
+
+ // Assumes ASCII. TODO(adonovan): test on UTF-8.
+ linestart := posn.Offset - (posn.Column - 1)
+
+ // Compute the file offsets.
+ q.queryPos = fmt.Sprintf("%s:#%d,#%d",
+ filename, linestart+loc[0], linestart+loc[1])
+ }
+
+ queries = append(queries, q)
+ queriesById[id] = q
+ }
+
+ // Return the slice, not map, for deterministic iteration.
+ return queries
+}
+
+// WriteResult writes res (-format=plain) to w, stripping file locations.
+func WriteResult(w io.Writer, q *oracle.Query) {
+ capture := new(bytes.Buffer) // capture standard output
+ q.WriteTo(capture)
+ for _, line := range strings.Split(capture.String(), "\n") {
+ // Remove a "file:line: " prefix.
+ if i := strings.Index(line, ": "); i >= 0 {
+ line = line[i+2:]
+ }
+ fmt.Fprintf(w, "%s\n", line)
+ }
+}
+
+// doQuery poses query q to the oracle and writes its response and
+// error (if any) to out.
+func doQuery(out io.Writer, q *query, useJson bool) {
+ fmt.Fprintf(out, "-------- @%s %s --------\n", q.verb, q.id)
+
+ var buildContext = build.Default
+ buildContext.GOPATH = "testdata"
+ query := oracle.Query{
+ Mode: q.verb,
+ Pos: q.queryPos,
+ Build: &buildContext,
+ Scope: []string{q.filename},
+ Reflection: true,
+ }
+ if err := oracle.Run(&query); err != nil {
+ fmt.Fprintf(out, "\nError: %s\n", err)
+ return
+ }
+
+ if useJson {
+ // JSON output
+ b, err := json.MarshalIndent(query.Serial(), "", "\t")
+ if err != nil {
+ fmt.Fprintf(out, "JSON error: %s\n", err.Error())
+ return
+ }
+ out.Write(b)
+ fmt.Fprintln(out)
+ } else {
+ // "plain" (compiler diagnostic format) output
+ WriteResult(out, &query)
+ }
+}
+
+func TestOracle(t *testing.T) {
+ switch runtime.GOOS {
+ case "android":
+ t.Skipf("skipping test on %q (no testdata dir)", runtime.GOOS)
+ case "windows":
+ t.Skipf("skipping test on %q (no /usr/bin/diff)", runtime.GOOS)
+ }
+
+ for _, filename := range []string{
+ "testdata/src/calls/main.go",
+ "testdata/src/describe/main.go",
+ "testdata/src/freevars/main.go",
+ "testdata/src/implements/main.go",
+ "testdata/src/implements-methods/main.go",
+ "testdata/src/imports/main.go",
+ "testdata/src/peers/main.go",
+ "testdata/src/pointsto/main.go",
+ "testdata/src/referrers/main.go",
+ "testdata/src/reflection/main.go",
+ "testdata/src/what/main.go",
+ "testdata/src/whicherrs/main.go",
+ // JSON:
+ // TODO(adonovan): most of these are very similar; combine them.
+ "testdata/src/calls-json/main.go",
+ "testdata/src/peers-json/main.go",
+ "testdata/src/describe-json/main.go",
+ "testdata/src/implements-json/main.go",
+ "testdata/src/implements-methods-json/main.go",
+ "testdata/src/pointsto-json/main.go",
+ "testdata/src/referrers-json/main.go",
+ "testdata/src/what-json/main.go",
+ } {
+ useJson := strings.Contains(filename, "-json/")
+ queries := parseQueries(t, filename)
+ golden := filename + "lden"
+ got := filename + "t"
+ gotfh, err := os.Create(got)
+ if err != nil {
+ t.Errorf("Create(%s) failed: %s", got, err)
+ continue
+ }
+ defer gotfh.Close()
+ defer os.Remove(got)
+
+ // Run the oracle on each query, redirecting its output
+ // and error (if any) to the foo.got file.
+ for _, q := range queries {
+ doQuery(gotfh, q, useJson)
+ }
+
+ // Compare foo.got with foo.golden.
+ var cmd *exec.Cmd
+ switch runtime.GOOS {
+ case "plan9":
+ cmd = exec.Command("/bin/diff", "-c", golden, got)
+ default:
+ cmd = exec.Command("/usr/bin/diff", "-u", golden, got)
+ }
+ buf := new(bytes.Buffer)
+ cmd.Stdout = buf
+ cmd.Stderr = os.Stderr
+ if err := cmd.Run(); err != nil {
+ t.Errorf("Oracle tests for %s failed: %s.\n%s\n",
+ filename, err, buf)
+
+ if *updateFlag {
+ t.Logf("Updating %s...", golden)
+ if err := exec.Command("/bin/cp", got, golden).Run(); err != nil {
+ t.Errorf("Update failed: %s", err)
+ }
+ }
+ }
+ }
+}
diff --git a/oracle/peers.go b/oracle/peers.go
new file mode 100644
index 0000000..9c2a497
--- /dev/null
+++ b/oracle/peers.go
@@ -0,0 +1,252 @@
+// 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 oracle
+
+import (
+ "fmt"
+ "go/ast"
+ "go/token"
+ "sort"
+
+ "golang.org/x/tools/go/loader"
+ "golang.org/x/tools/go/ssa"
+ "golang.org/x/tools/go/ssa/ssautil"
+ "golang.org/x/tools/go/types"
+ "golang.org/x/tools/oracle/serial"
+)
+
+// peers enumerates, for a given channel send (or receive) operation,
+// the set of possible receives (or sends) that correspond to it.
+//
+// TODO(adonovan): support reflect.{Select,Recv,Send,Close}.
+// TODO(adonovan): permit the user to query based on a MakeChan (not send/recv),
+// or the implicit receive in "for v := range ch".
+func peers(q *Query) error {
+ lconf := loader.Config{Build: q.Build}
+
+ if err := setPTAScope(&lconf, q.Scope); err != nil {
+ return err
+ }
+
+ // Load/parse/type-check the program.
+ lprog, err := lconf.Load()
+ if err != nil {
+ return err
+ }
+ q.Fset = lprog.Fset
+
+ qpos, err := parseQueryPos(lprog, q.Pos, false)
+ if err != nil {
+ return err
+ }
+
+ prog := ssautil.CreateProgram(lprog, ssa.GlobalDebug)
+
+ ptaConfig, err := setupPTA(prog, lprog, q.PTALog, q.Reflection)
+ if err != nil {
+ return err
+ }
+
+ opPos := findOp(qpos)
+ if opPos == token.NoPos {
+ return fmt.Errorf("there is no channel operation here")
+ }
+
+ // Defer SSA construction till after errors are reported.
+ prog.BuildAll()
+
+ var queryOp chanOp // the originating send or receive operation
+ var ops []chanOp // all sends/receives of opposite direction
+
+ // Look at all channel operations in the whole ssa.Program.
+ // Build a list of those of same type as the query.
+ allFuncs := ssautil.AllFunctions(prog)
+ for fn := range allFuncs {
+ for _, b := range fn.Blocks {
+ for _, instr := range b.Instrs {
+ for _, op := range chanOps(instr) {
+ ops = append(ops, op)
+ if op.pos == opPos {
+ queryOp = op // we found the query op
+ }
+ }
+ }
+ }
+ }
+ if queryOp.ch == nil {
+ return fmt.Errorf("ssa.Instruction for send/receive not found")
+ }
+
+ // Discard operations of wrong channel element type.
+ // Build set of channel ssa.Values as query to pointer analysis.
+ // We compare channels by element types, not channel types, to
+ // ignore both directionality and type names.
+ queryType := queryOp.ch.Type()
+ queryElemType := queryType.Underlying().(*types.Chan).Elem()
+ ptaConfig.AddQuery(queryOp.ch)
+ i := 0
+ for _, op := range ops {
+ if types.Identical(op.ch.Type().Underlying().(*types.Chan).Elem(), queryElemType) {
+ ptaConfig.AddQuery(op.ch)
+ ops[i] = op
+ i++
+ }
+ }
+ ops = ops[:i]
+
+ // Run the pointer analysis.
+ ptares := ptrAnalysis(ptaConfig)
+
+ // Find the points-to set.
+ queryChanPtr := ptares.Queries[queryOp.ch]
+
+ // Ascertain which make(chan) labels the query's channel can alias.
+ var makes []token.Pos
+ for _, label := range queryChanPtr.PointsTo().Labels() {
+ makes = append(makes, label.Pos())
+ }
+ sort.Sort(byPos(makes))
+
+ // Ascertain which channel operations can alias the same make(chan) labels.
+ var sends, receives, closes []token.Pos
+ for _, op := range ops {
+ if ptr, ok := ptares.Queries[op.ch]; ok && ptr.MayAlias(queryChanPtr) {
+ switch op.dir {
+ case types.SendOnly:
+ sends = append(sends, op.pos)
+ case types.RecvOnly:
+ receives = append(receives, op.pos)
+ case types.SendRecv:
+ closes = append(closes, op.pos)
+ }
+ }
+ }
+ sort.Sort(byPos(sends))
+ sort.Sort(byPos(receives))
+ sort.Sort(byPos(closes))
+
+ q.result = &peersResult{
+ queryPos: opPos,
+ queryType: queryType,
+ makes: makes,
+ sends: sends,
+ receives: receives,
+ closes: closes,
+ }
+ return nil
+}
+
+// findOp returns the position of the enclosing send/receive/close op.
+// For send and receive operations, this is the position of the <- token;
+// for close operations, it's the Lparen of the function call.
+//
+// TODO(adonovan): handle implicit receive operations from 'for...range chan' statements.
+func findOp(qpos *queryPos) token.Pos {
+ for _, n := range qpos.path {
+ switch n := n.(type) {
+ case *ast.UnaryExpr:
+ if n.Op == token.ARROW {
+ return n.OpPos
+ }
+ case *ast.SendStmt:
+ return n.Arrow
+ case *ast.CallExpr:
+ // close function call can only exist as a direct identifier
+ if close, ok := unparen(n.Fun).(*ast.Ident); ok {
+ if b, ok := qpos.info.Info.Uses[close].(*types.Builtin); ok && b.Name() == "close" {
+ return n.Lparen
+ }
+ }
+ }
+ }
+ return token.NoPos
+}
+
+// chanOp abstracts an ssa.Send, ssa.Unop(ARROW), or a SelectState.
+type chanOp struct {
+ ch ssa.Value
+ dir types.ChanDir // SendOnly=send, RecvOnly=recv, SendRecv=close
+ pos token.Pos
+}
+
+// chanOps returns a slice of all the channel operations in the instruction.
+func chanOps(instr ssa.Instruction) []chanOp {
+ // TODO(adonovan): handle calls to reflect.{Select,Recv,Send,Close} too.
+ var ops []chanOp
+ switch instr := instr.(type) {
+ case *ssa.UnOp:
+ if instr.Op == token.ARROW {
+ ops = append(ops, chanOp{instr.X, types.RecvOnly, instr.Pos()})
+ }
+ case *ssa.Send:
+ ops = append(ops, chanOp{instr.Chan, types.SendOnly, instr.Pos()})
+ case *ssa.Select:
+ for _, st := range instr.States {
+ ops = append(ops, chanOp{st.Chan, st.Dir, st.Pos})
+ }
+ case ssa.CallInstruction:
+ cc := instr.Common()
+ if b, ok := cc.Value.(*ssa.Builtin); ok && b.Name() == "close" {
+ ops = append(ops, chanOp{cc.Args[0], types.SendRecv, cc.Pos()})
+ }
+ }
+ return ops
+}
+
+type peersResult struct {
+ queryPos token.Pos // of queried channel op
+ queryType types.Type // type of queried channel
+ makes, sends, receives, closes []token.Pos // positions of aliased makechan/send/receive/close instrs
+}
+
+func (r *peersResult) display(printf printfFunc) {
+ if len(r.makes) == 0 {
+ printf(r.queryPos, "This channel can't point to anything.")
+ return
+ }
+ printf(r.queryPos, "This channel of type %s may be:", r.queryType)
+ for _, alloc := range r.makes {
+ printf(alloc, "\tallocated here")
+ }
+ for _, send := range r.sends {
+ printf(send, "\tsent to, here")
+ }
+ for _, receive := range r.receives {
+ printf(receive, "\treceived from, here")
+ }
+ for _, clos := range r.closes {
+ printf(clos, "\tclosed, here")
+ }
+}
+
+func (r *peersResult) toSerial(res *serial.Result, fset *token.FileSet) {
+ peers := &serial.Peers{
+ Pos: fset.Position(r.queryPos).String(),
+ Type: r.queryType.String(),
+ }
+ for _, alloc := range r.makes {
+ peers.Allocs = append(peers.Allocs, fset.Position(alloc).String())
+ }
+ for _, send := range r.sends {
+ peers.Sends = append(peers.Sends, fset.Position(send).String())
+ }
+ for _, receive := range r.receives {
+ peers.Receives = append(peers.Receives, fset.Position(receive).String())
+ }
+ for _, clos := range r.closes {
+ peers.Closes = append(peers.Closes, fset.Position(clos).String())
+ }
+ res.Peers = peers
+}
+
+// -------- utils --------
+
+// NB: byPos is not deterministic across packages since it depends on load order.
+// Use lessPos if the tests need it.
+type byPos []token.Pos
+
+func (p byPos) Len() int { return len(p) }
+func (p byPos) Less(i, j int) bool { return p[i] < p[j] }
+func (p byPos) Swap(i, j int) { p[i], p[j] = p[j], p[i] }
diff --git a/oracle/pointsto.go b/oracle/pointsto.go
new file mode 100644
index 0000000..d366dd3
--- /dev/null
+++ b/oracle/pointsto.go
@@ -0,0 +1,291 @@
+// 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 oracle
+
+import (
+ "fmt"
+ "go/ast"
+ "go/token"
+ "sort"
+
+ "golang.org/x/tools/go/ast/astutil"
+ "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"
+ "golang.org/x/tools/go/types"
+ "golang.org/x/tools/oracle/serial"
+)
+
+// pointsto runs the pointer analysis on the selected expression,
+// and reports its points-to set (for a pointer-like expression)
+// or its dynamic types (for an interface, reflect.Value, or
+// reflect.Type expression) and their points-to sets.
+//
+// All printed sets are sorted to ensure determinism.
+//
+func pointsto(q *Query) error {
+ lconf := loader.Config{Build: q.Build}
+
+ if err := setPTAScope(&lconf, q.Scope); err != nil {
+ return err
+ }
+
+ // Load/parse/type-check the program.
+ lprog, err := lconf.Load()
+ if err != nil {
+ return err
+ }
+ q.Fset = lprog.Fset
+
+ qpos, err := parseQueryPos(lprog, q.Pos, true) // needs exact pos
+ if err != nil {
+ return err
+ }
+
+ prog := ssautil.CreateProgram(lprog, ssa.GlobalDebug)
+
+ ptaConfig, err := setupPTA(prog, lprog, q.PTALog, q.Reflection)
+ if err != nil {
+ return err
+ }
+
+ path, action := findInterestingNode(qpos.info, qpos.path)
+ if action != actionExpr {
+ return fmt.Errorf("pointer analysis wants an expression; got %s",
+ astutil.NodeDescription(qpos.path[0]))
+ }
+
+ var expr ast.Expr
+ var obj types.Object
+ switch n := path[0].(type) {
+ case *ast.ValueSpec:
+ // ambiguous ValueSpec containing multiple names
+ return fmt.Errorf("multiple value specification")
+ case *ast.Ident:
+ obj = qpos.info.ObjectOf(n)
+ expr = n
+ case ast.Expr:
+ expr = n
+ default:
+ // TODO(adonovan): is this reachable?
+ return fmt.Errorf("unexpected AST for expr: %T", n)
+ }
+
+ // Reject non-pointerlike types (includes all constants---except nil).
+ // TODO(adonovan): reject nil too.
+ typ := qpos.info.TypeOf(expr)
+ if !pointer.CanPoint(typ) {
+ return fmt.Errorf("pointer analysis wants an expression of reference type; got %s", typ)
+ }
+
+ // Determine the ssa.Value for the expression.
+ var value ssa.Value
+ var isAddr bool
+ if obj != nil {
+ // def/ref of func/var object
+ value, isAddr, err = ssaValueForIdent(prog, qpos.info, obj, path)
+ } else {
+ value, isAddr, err = ssaValueForExpr(prog, qpos.info, path)
+ }
+ if err != nil {
+ return err // e.g. trivially dead code
+ }
+
+ // Defer SSA construction till after errors are reported.
+ prog.BuildAll()
+
+ // Run the pointer analysis.
+ ptrs, err := runPTA(ptaConfig, value, isAddr)
+ if err != nil {
+ return err // e.g. analytically unreachable
+ }
+
+ q.result = &pointstoResult{
+ qpos: qpos,
+ typ: typ,
+ ptrs: ptrs,
+ }
+ return nil
+}
+
+// ssaValueForIdent returns the ssa.Value for the ast.Ident whose path
+// to the root of the AST is path. isAddr reports whether the
+// ssa.Value is the address denoted by the ast.Ident, not its value.
+//
+func ssaValueForIdent(prog *ssa.Program, qinfo *loader.PackageInfo, obj types.Object, path []ast.Node) (value ssa.Value, isAddr bool, err error) {
+ switch obj := obj.(type) {
+ case *types.Var:
+ pkg := prog.Package(qinfo.Pkg)
+ pkg.Build()
+ if v, addr := prog.VarValue(obj, pkg, path); v != nil {
+ return v, addr, nil
+ }
+ return nil, false, fmt.Errorf("can't locate SSA Value for var %s", obj.Name())
+
+ case *types.Func:
+ fn := prog.FuncValue(obj)
+ if fn == nil {
+ return nil, false, fmt.Errorf("%s is an interface method", obj)
+ }
+ // TODO(adonovan): there's no point running PTA on a *Func ident.
+ // Eliminate this feature.
+ return fn, false, nil
+ }
+ panic(obj)
+}
+
+// ssaValueForExpr returns the ssa.Value of the non-ast.Ident
+// expression whose path to the root of the AST is path.
+//
+func ssaValueForExpr(prog *ssa.Program, qinfo *loader.PackageInfo, path []ast.Node) (value ssa.Value, isAddr bool, err error) {
+ pkg := prog.Package(qinfo.Pkg)
+ pkg.SetDebugMode(true)
+ pkg.Build()
+
+ fn := ssa.EnclosingFunction(pkg, path)
+ if fn == nil {
+ return nil, false, fmt.Errorf("no SSA function built for this location (dead code?)")
+ }
+
+ if v, addr := fn.ValueForExpr(path[0].(ast.Expr)); v != nil {
+ return v, addr, nil
+ }
+
+ return nil, false, fmt.Errorf("can't locate SSA Value for expression in %s", fn)
+}
+
+// runPTA runs the pointer analysis of the selected SSA value or address.
+func runPTA(conf *pointer.Config, v ssa.Value, isAddr bool) (ptrs []pointerResult, err error) {
+ T := v.Type()
+ if isAddr {
+ conf.AddIndirectQuery(v)
+ T = deref(T)
+ } else {
+ conf.AddQuery(v)
+ }
+ ptares := ptrAnalysis(conf)
+
+ var ptr pointer.Pointer
+ if isAddr {
+ ptr = ptares.IndirectQueries[v]
+ } else {
+ ptr = ptares.Queries[v]
+ }
+ if ptr == (pointer.Pointer{}) {
+ return nil, fmt.Errorf("pointer analysis did not find expression (dead code?)")
+ }
+ pts := ptr.PointsTo()
+
+ if pointer.CanHaveDynamicTypes(T) {
+ // Show concrete types for interface/reflect.Value expression.
+ if concs := pts.DynamicTypes(); concs.Len() > 0 {
+ concs.Iterate(func(conc types.Type, pta interface{}) {
+ labels := pta.(pointer.PointsToSet).Labels()
+ sort.Sort(byPosAndString(labels)) // to ensure determinism
+ ptrs = append(ptrs, pointerResult{conc, labels})
+ })
+ }
+ } else {
+ // Show labels for other expressions.
+ labels := pts.Labels()
+ sort.Sort(byPosAndString(labels)) // to ensure determinism
+ ptrs = append(ptrs, pointerResult{T, labels})
+ }
+ sort.Sort(byTypeString(ptrs)) // to ensure determinism
+ return ptrs, nil
+}
+
+type pointerResult struct {
+ typ types.Type // type of the pointer (always concrete)
+ labels []*pointer.Label // set of labels
+}
+
+type pointstoResult struct {
+ qpos *queryPos
+ typ types.Type // type of expression
+ ptrs []pointerResult // pointer info (typ is concrete => len==1)
+}
+
+func (r *pointstoResult) display(printf printfFunc) {
+ if pointer.CanHaveDynamicTypes(r.typ) {
+ // Show concrete types for interface, reflect.Type or
+ // reflect.Value expression.
+
+ if len(r.ptrs) > 0 {
+ printf(r.qpos, "this %s may contain these dynamic types:", r.qpos.typeString(r.typ))
+ for _, ptr := range r.ptrs {
+ var obj types.Object
+ if nt, ok := deref(ptr.typ).(*types.Named); ok {
+ obj = nt.Obj()
+ }
+ if len(ptr.labels) > 0 {
+ printf(obj, "\t%s, may point to:", r.qpos.typeString(ptr.typ))
+ printLabels(printf, ptr.labels, "\t\t")
+ } else {
+ printf(obj, "\t%s", r.qpos.typeString(ptr.typ))
+ }
+ }
+ } else {
+ printf(r.qpos, "this %s cannot contain any dynamic types.", r.typ)
+ }
+ } else {
+ // Show labels for other expressions.
+ if ptr := r.ptrs[0]; len(ptr.labels) > 0 {
+ printf(r.qpos, "this %s may point to these objects:",
+ r.qpos.typeString(r.typ))
+ printLabels(printf, ptr.labels, "\t")
+ } else {
+ printf(r.qpos, "this %s may not point to anything.",
+ r.qpos.typeString(r.typ))
+ }
+ }
+}
+
+func (r *pointstoResult) toSerial(res *serial.Result, fset *token.FileSet) {
+ var pts []serial.PointsTo
+ for _, ptr := range r.ptrs {
+ var namePos string
+ if nt, ok := deref(ptr.typ).(*types.Named); ok {
+ namePos = fset.Position(nt.Obj().Pos()).String()
+ }
+ var labels []serial.PointsToLabel
+ for _, l := range ptr.labels {
+ labels = append(labels, serial.PointsToLabel{
+ Pos: fset.Position(l.Pos()).String(),
+ Desc: l.String(),
+ })
+ }
+ pts = append(pts, serial.PointsTo{
+ Type: r.qpos.typeString(ptr.typ),
+ NamePos: namePos,
+ Labels: labels,
+ })
+ }
+ res.PointsTo = pts
+}
+
+type byTypeString []pointerResult
+
+func (a byTypeString) Len() int { return len(a) }
+func (a byTypeString) Less(i, j int) bool { return a[i].typ.String() < a[j].typ.String() }
+func (a byTypeString) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
+
+type byPosAndString []*pointer.Label
+
+func (a byPosAndString) Len() int { return len(a) }
+func (a byPosAndString) Less(i, j int) bool {
+ cmp := a[i].Pos() - a[j].Pos()
+ return cmp < 0 || (cmp == 0 && a[i].String() < a[j].String())
+}
+func (a byPosAndString) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
+
+func printLabels(printf printfFunc, labels []*pointer.Label, prefix string) {
+ // TODO(adonovan): due to context-sensitivity, many of these
+ // labels may differ only by context, which isn't apparent.
+ for _, label := range labels {
+ printf(label, "%s%s", prefix, label)
+ }
+}
diff --git a/oracle/pos.go b/oracle/pos.go
new file mode 100644
index 0000000..3c706f3
--- /dev/null
+++ b/oracle/pos.go
@@ -0,0 +1,143 @@
+package oracle
+
+// This file defines utilities for working with file positions.
+
+import (
+ "fmt"
+ "go/parser"
+ "go/token"
+ "os"
+ "path/filepath"
+ "strconv"
+ "strings"
+
+ "golang.org/x/tools/go/ast/astutil"
+)
+
+// parseOctothorpDecimal returns the numeric value if s matches "#%d",
+// otherwise -1.
+func parseOctothorpDecimal(s string) int {
+ if s != "" && s[0] == '#' {
+ if s, err := strconv.ParseInt(s[1:], 10, 32); err == nil {
+ return int(s)
+ }
+ }
+ return -1
+}
+
+// parsePosFlag parses a string of the form "file:pos" or
+// file:start,end" where pos, start, end match #%d and represent byte
+// offsets, and returns its components.
+//
+// (Numbers without a '#' prefix are reserved for future use,
+// e.g. to indicate line/column positions.)
+//
+func parsePosFlag(posFlag string) (filename string, startOffset, endOffset int, err error) {
+ if posFlag == "" {
+ err = fmt.Errorf("no source position specified (-pos flag)")
+ return
+ }
+
+ colon := strings.LastIndex(posFlag, ":")
+ if colon < 0 {
+ err = fmt.Errorf("invalid source position -pos=%q", posFlag)
+ return
+ }
+ filename, offset := posFlag[:colon], posFlag[colon+1:]
+ startOffset = -1
+ endOffset = -1
+ if hyphen := strings.Index(offset, ","); hyphen < 0 {
+ // e.g. "foo.go:#123"
+ startOffset = parseOctothorpDecimal(offset)
+ endOffset = startOffset
+ } else {
+ // e.g. "foo.go:#123,#456"
+ startOffset = parseOctothorpDecimal(offset[:hyphen])
+ endOffset = parseOctothorpDecimal(offset[hyphen+1:])
+ }
+ if startOffset < 0 || endOffset < 0 {
+ err = fmt.Errorf("invalid -pos offset %q", offset)
+ return
+ }
+ return
+}
+
+// findQueryPos searches fset for filename and translates the
+// specified file-relative byte offsets into token.Pos form. It
+// returns an error if the file was not found or the offsets were out
+// of bounds.
+//
+func findQueryPos(fset *token.FileSet, filename string, startOffset, endOffset int) (start, end token.Pos, err error) {
+ var file *token.File
+ fset.Iterate(func(f *token.File) bool {
+ if sameFile(filename, f.Name()) {
+ // (f.Name() is absolute)
+ file = f
+ return false // done
+ }
+ return true // continue
+ })
+ if file == nil {
+ err = fmt.Errorf("couldn't find file containing position")
+ return
+ }
+
+ // Range check [start..end], inclusive of both end-points.
+
+ if 0 <= startOffset && startOffset <= file.Size() {
+ start = file.Pos(int(startOffset))
+ } else {
+ err = fmt.Errorf("start position is beyond end of file")
+ return
+ }
+
+ if 0 <= endOffset && endOffset <= file.Size() {
+ end = file.Pos(int(endOffset))
+ } else {
+ err = fmt.Errorf("end position is beyond end of file")
+ return
+ }
+
+ return
+}
+
+// sameFile returns true if x and y have the same basename and denote
+// the same file.
+//
+func sameFile(x, y string) bool {
+ if filepath.Base(x) == filepath.Base(y) { // (optimisation)
+ if xi, err := os.Stat(x); err == nil {
+ if yi, err := os.Stat(y); err == nil {
+ return os.SameFile(xi, yi)
+ }
+ }
+ }
+ return false
+}
+
+// fastQueryPos parses the -pos flag and returns a QueryPos.
+// It parses only a single file, and does not run the type checker.
+func fastQueryPos(posFlag string) (*queryPos, error) {
+ filename, startOffset, endOffset, err := parsePosFlag(posFlag)
+ if err != nil {
+ return nil, err
+ }
+
+ fset := token.NewFileSet()
+ f, err := parser.ParseFile(fset, filename, nil, 0)
+ if err != nil {
+ return nil, err
+ }
+
+ start, end, err := findQueryPos(fset, filename, startOffset, endOffset)
+ if err != nil {
+ return nil, err
+ }
+
+ path, exact := astutil.PathEnclosingInterval(f, start, end)
+ if path == nil {
+ return nil, fmt.Errorf("no syntax here")
+ }
+
+ return &queryPos{fset, start, end, path, exact, nil}, nil
+}
diff --git a/oracle/referrers.go b/oracle/referrers.go
new file mode 100644
index 0000000..7383d1f
--- /dev/null
+++ b/oracle/referrers.go
@@ -0,0 +1,225 @@
+// 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 oracle
+
+import (
+ "bytes"
+ "fmt"
+ "go/ast"
+ "go/token"
+ "io/ioutil"
+ "sort"
+
+ "golang.org/x/tools/go/loader"
+ "golang.org/x/tools/go/types"
+ "golang.org/x/tools/oracle/serial"
+ "golang.org/x/tools/refactor/importgraph"
+)
+
+// Referrers reports all identifiers that resolve to the same object
+// as the queried identifier, within any package in the analysis scope.
+func referrers(q *Query) error {
+ lconf := loader.Config{Build: q.Build}
+ allowErrors(&lconf)
+
+ if err := importQueryPackage(q.Pos, &lconf); err != nil {
+ return err
+ }
+
+ var id *ast.Ident
+ var obj types.Object
+ var lprog *loader.Program
+ var pass2 bool
+ var qpos *queryPos
+ for {
+ // Load/parse/type-check the program.
+ var err error
+ lprog, err = lconf.Load()
+ if err != nil {
+ return err
+ }
+ q.Fset = lprog.Fset
+
+ qpos, err = parseQueryPos(lprog, q.Pos, false)
+ if err != nil {
+ return err
+ }
+
+ id, _ = qpos.path[0].(*ast.Ident)
+ if id == nil {
+ return fmt.Errorf("no identifier here")
+ }
+
+ obj = qpos.info.ObjectOf(id)
+ if obj == nil {
+ // Happens for y in "switch y := x.(type)",
+ // the package declaration,
+ // and unresolved identifiers.
+ if _, ok := qpos.path[1].(*ast.File); ok { // package decl?
+ pkg := qpos.info.Pkg
+ obj = types.NewPkgName(id.Pos(), pkg, pkg.Name(), pkg)
+ } else {
+ return fmt.Errorf("no object for identifier: %T", qpos.path[1])
+ }
+ }
+
+ if pass2 {
+ break
+ }
+
+ // If the identifier is exported, we must load all packages that
+ // depend transitively upon the package that defines it.
+ // Treat PkgNames as exported, even though they're lowercase.
+ if _, isPkg := obj.(*types.PkgName); !(isPkg || obj.Exported()) {
+ break // not exported
+ }
+
+ // Scan the workspace and build the import graph.
+ // Ignore broken packages.
+ _, rev, _ := importgraph.Build(q.Build)
+
+ // Re-load the larger program.
+ // Create a new file set so that ...
+ // External test packages are never imported,
+ // so they will never appear in the graph.
+ // (We must reset the Config here, not just reset the Fset field.)
+ lconf = loader.Config{
+ Fset: token.NewFileSet(),
+ Build: q.Build,
+ }
+ allowErrors(&lconf)
+ for path := range rev.Search(obj.Pkg().Path()) {
+ lconf.ImportWithTests(path)
+ }
+ pass2 = true
+ }
+
+ // Iterate over all go/types' Uses facts for the entire program.
+ var refs []*ast.Ident
+ for _, info := range lprog.AllPackages {
+ for id2, obj2 := range info.Uses {
+ if sameObj(obj, obj2) {
+ refs = append(refs, id2)
+ }
+ }
+ }
+ sort.Sort(byNamePos{q.Fset, refs})
+
+ q.result = &referrersResult{
+ qpos: qpos,
+ query: id,
+ obj: obj,
+ refs: refs,
+ }
+ return nil
+}
+
+// same reports whether x and y are identical, or both are PkgNames
+// that import the same Package.
+//
+func sameObj(x, y types.Object) bool {
+ if x == y {
+ return true
+ }
+ if x, ok := x.(*types.PkgName); ok {
+ if y, ok := y.(*types.PkgName); ok {
+ return x.Imported() == y.Imported()
+ }
+ }
+ return false
+}
+
+// -------- utils --------
+
+// An deterministic ordering for token.Pos that doesn't
+// depend on the order in which packages were loaded.
+func lessPos(fset *token.FileSet, x, y token.Pos) bool {
+ fx := fset.File(x)
+ fy := fset.File(y)
+ if fx != fy {
+ return fx.Name() < fy.Name()
+ }
+ return x < y
+}
+
+type byNamePos struct {
+ fset *token.FileSet
+ ids []*ast.Ident
+}
+
+func (p byNamePos) Len() int { return len(p.ids) }
+func (p byNamePos) Swap(i, j int) { p.ids[i], p.ids[j] = p.ids[j], p.ids[i] }
+func (p byNamePos) Less(i, j int) bool {
+ return lessPos(p.fset, p.ids[i].NamePos, p.ids[j].NamePos)
+}
+
+type referrersResult struct {
+ qpos *queryPos
+ query *ast.Ident // identifier of query
+ obj types.Object // object it denotes
+ refs []*ast.Ident // set of all other references to it
+}
+
+func (r *referrersResult) display(printf printfFunc) {
+ printf(r.obj, "%d references to %s", len(r.refs), r.qpos.objectString(r.obj))
+
+ // Show referring lines, like grep.
+ type fileinfo struct {
+ refs []*ast.Ident
+ linenums []int // line number of refs[i]
+ data chan []byte // file contents
+ }
+ var fileinfos []*fileinfo
+ fileinfosByName := make(map[string]*fileinfo)
+
+ // First pass: start the file reads concurrently.
+ for _, ref := range r.refs {
+ posn := r.qpos.fset.Position(ref.Pos())
+ fi := fileinfosByName[posn.Filename]
+ if fi == nil {
+ fi = &fileinfo{data: make(chan []byte)}
+ fileinfosByName[posn.Filename] = fi
+ fileinfos = append(fileinfos, fi)
+
+ // First request for this file:
+ // start asynchronous read.
+ go func() {
+ content, err := ioutil.ReadFile(posn.Filename)
+ if err != nil {
+ content = []byte(fmt.Sprintf("error: %v", err))
+ }
+ fi.data <- content
+ }()
+ }
+ fi.refs = append(fi.refs, ref)
+ fi.linenums = append(fi.linenums, posn.Line)
+ }
+
+ // Second pass: print refs in original order.
+ // One line may have several refs at different columns.
+ for _, fi := range fileinfos {
+ content := <-fi.data // wait for I/O completion
+ lines := bytes.Split(content, []byte("\n"))
+ for i, ref := range fi.refs {
+ printf(ref, "%s", lines[fi.linenums[i]-1])
+ }
+ }
+}
+
+// TODO(adonovan): encode extent, not just Pos info, in Serial form.
+
+func (r *referrersResult) toSerial(res *serial.Result, fset *token.FileSet) {
+ referrers := &serial.Referrers{
+ Pos: fset.Position(r.query.Pos()).String(),
+ Desc: r.obj.String(),
+ }
+ if pos := r.obj.Pos(); pos != token.NoPos { // Package objects have no Pos()
+ referrers.ObjPos = fset.Position(pos).String()
+ }
+ for _, ref := range r.refs {
+ referrers.Refs = append(referrers.Refs, fset.Position(ref.NamePos).String())
+ }
+ res.Referrers = referrers
+}
diff --git a/oracle/serial/serial.go b/oracle/serial/serial.go
new file mode 100644
index 0000000..65f0822
--- /dev/null
+++ b/oracle/serial/serial.go
@@ -0,0 +1,258 @@
+// 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 serial defines the oracle's schema for structured data
+// serialization using JSON, XML, etc.
+package serial
+
+// All 'pos' strings are of the form "file:line:col".
+// TODO(adonovan): improve performance by sharing filename strings.
+// TODO(adonovan): improve precision by providing the start/end
+// interval when available.
+//
+// TODO(adonovan): consider richer encodings of types, functions,
+// methods, etc.
+
+// A Peers is the result of a 'peers' query.
+// If Allocs is empty, the selected channel can't point to anything.
+type Peers struct {
+ Pos string `json:"pos"` // location of the selected channel op (<-)
+ Type string `json:"type"` // type of the selected channel
+ Allocs []string `json:"allocs,omitempty"` // locations of aliased make(chan) ops
+ Sends []string `json:"sends,omitempty"` // locations of aliased ch<-x ops
+ Receives []string `json:"receives,omitempty"` // locations of aliased <-ch ops
+ Closes []string `json:"closes,omitempty"` // locations of aliased close(ch) ops
+}
+
+// A Referrers is the result of a 'referrers' query.
+type Referrers struct {
+ Pos string `json:"pos"` // location of the query reference
+ ObjPos string `json:"objpos,omitempty"` // location of the definition
+ Desc string `json:"desc"` // description of the denoted object
+ Refs []string `json:"refs,omitempty"` // locations of all references
+}
+
+// A Definition is the result of a 'definition' query.
+type Definition struct {
+ ObjPos string `json:"objpos,omitempty"` // location of the definition
+ Desc string `json:"desc"` // description of the denoted object
+}
+
+type CalleesItem struct {
+ Name string `json:"name"` // full name of called function
+ Pos string `json:"pos"` // location of called function
+}
+
+// A Callees is the result of a 'callees' query.
+//
+// Callees is nonempty unless the call was a dynamic call on a
+// provably nil func or interface value.
+type Callees struct {
+ Pos string `json:"pos"` // location of selected call site
+ Desc string `json:"desc"` // description of call site
+ Callees []*CalleesItem `json:"callees,omitempty"` // set of possible call targets
+}
+
+// A Caller is one element of the slice returned by a 'callers' query.
+// (Callstack also contains a similar slice.)
+//
+// The root of the callgraph has an unspecified "Caller" string.
+type Caller struct {
+ Pos string `json:"pos,omitempty"` // location of the calling function
+ Desc string `json:"desc"` // description of call site
+ Caller string `json:"caller"` // full name of calling function
+}
+
+// A CallStack is the result of a 'callstack' query.
+// It indicates an arbitrary path from the root of the callgraph to
+// the query function.
+//
+// If the Callers slice is empty, the function was unreachable in this
+// analysis scope.
+type CallStack struct {
+ Pos string `json:"pos"` // location of the selected function
+ Target string `json:"target"` // the selected function
+ Callers []Caller `json:"callers"` // enclosing calls, innermost first.
+}
+
+// A FreeVar is one element of the slice returned by a 'freevars'
+// query. Each one identifies an expression referencing a local
+// identifier defined outside the selected region.
+type FreeVar struct {
+ Pos string `json:"pos"` // location of the identifier's definition
+ Kind string `json:"kind"` // one of {var,func,type,const,label}
+ Ref string `json:"ref"` // referring expression (e.g. "x" or "x.y.z")
+ Type string `json:"type"` // type of the expression
+}
+
+// An Implements contains the result of an 'implements' query.
+// It describes the queried type, the set of named non-empty interface
+// types to which it is assignable, and the set of named/*named types
+// (concrete or non-empty interface) which may be assigned to it.
+//
+type Implements struct {
+ T ImplementsType `json:"type,omitempty"` // the queried type
+ AssignableTo []ImplementsType `json:"to,omitempty"` // types assignable to T
+ AssignableFrom []ImplementsType `json:"from,omitempty"` // interface types assignable from T
+ AssignableFromPtr []ImplementsType `json:"fromptr,omitempty"` // interface types assignable only from *T
+
+ // The following fields are set only if the query was a method.
+ // Assignable{To,From,FromPtr}Method[i] is the corresponding
+ // method of type Assignable{To,From,FromPtr}[i], or blank
+ // {"",""} if that type lacks the method.
+ Method *DescribeMethod `json:"method,omitempty"` // the queried method
+ AssignableToMethod []DescribeMethod `json:"to_method,omitempty"`
+ AssignableFromMethod []DescribeMethod `json:"from_method,omitempty"`
+ AssignableFromPtrMethod []DescribeMethod `json:"fromptr_method,omitempty"`
+}
+
+// An ImplementsType describes a single type as part of an 'implements' query.
+type ImplementsType struct {
+ Name string `json:"name"` // full name of the type
+ Pos string `json:"pos"` // location of its definition
+ Kind string `json:"kind"` // "basic", "array", etc
+}
+
+// A SyntaxNode is one element of a stack of enclosing syntax nodes in
+// a "what" query.
+type SyntaxNode struct {
+ Description string `json:"desc"` // description of syntax tree
+ Start int `json:"start"` // start byte offset, 0-based
+ End int `json:"end"` // end byte offset
+}
+
+// A What is the result of the "what" query, which quickly identifies
+// the selection, parsing only a single file. It is intended for use
+// in low-latency GUIs.
+type What struct {
+ Enclosing []SyntaxNode `json:"enclosing"` // enclosing nodes of syntax tree
+ Modes []string `json:"modes"` // query modes enabled for this selection.
+ SrcDir string `json:"srcdir,omitempty"` // $GOROOT src directory containing queried package
+ ImportPath string `json:"importpath,omitempty"` // import path of queried package
+}
+
+// A PointsToLabel describes a pointer analysis label.
+//
+// A "label" is an object that may be pointed to by a pointer, map,
+// channel, 'func', slice or interface. Labels include:
+// - functions
+// - globals
+// - arrays created by literals (e.g. []byte("foo")) and conversions ([]byte(s))
+// - stack- and heap-allocated variables (including composite literals)
+// - arrays allocated by append()
+// - channels, maps and arrays created by make()
+// - and their subelements, e.g. "alloc.y[*].z"
+//
+type PointsToLabel struct {
+ Pos string `json:"pos"` // location of syntax that allocated the object
+ Desc string `json:"desc"` // description of the label
+}
+
+// A PointsTo is one element of the result of a 'pointsto' query on an
+// expression. It describes a single pointer: its type and the set of
+// "labels" it points to.
+//
+// If the pointer is of interface type, it will have one PTS entry
+// describing each concrete type that it may contain. For each
+// concrete type that is a pointer, the PTS entry describes the labels
+// it may point to. The same is true for reflect.Values, except the
+// dynamic types needn't be concrete.
+//
+type PointsTo struct {
+ Type string `json:"type"` // (concrete) type of the pointer
+ NamePos string `json:"namepos,omitempty"` // location of type defn, if Named
+ Labels []PointsToLabel `json:"labels,omitempty"` // pointed-to objects
+}
+
+// A DescribeValue is the additional result of a 'describe' query
+// if the selection indicates a value or expression.
+type DescribeValue struct {
+ Type string `json:"type"` // type of the expression
+ Value string `json:"value,omitempty"` // value of the expression, if constant
+ ObjPos string `json:"objpos,omitempty"` // location of the definition, if an Ident
+}
+
+type DescribeMethod struct {
+ Name string `json:"name"` // method name, as defined by types.Selection.String()
+ Pos string `json:"pos"` // location of the method's definition
+}
+
+// A DescribeType is the additional result of a 'describe' query
+// if the selection indicates a type.
+type DescribeType struct {
+ Type string `json:"type"` // the string form of the type
+ NamePos string `json:"namepos,omitempty"` // location of definition of type, if named
+ NameDef string `json:"namedef,omitempty"` // underlying definition of type, if named
+ Methods []DescribeMethod `json:"methods,omitempty"` // methods of the type
+}
+
+type DescribeMember struct {
+ Name string `json:"name"` // name of member
+ Type string `json:"type,omitempty"` // type of member (underlying, if 'type')
+ Value string `json:"value,omitempty"` // value of member (if 'const')
+ Pos string `json:"pos"` // location of definition of member
+ Kind string `json:"kind"` // one of {var,const,func,type}
+ Methods []DescribeMethod `json:"methods,omitempty"` // methods (if member is a type)
+}
+
+// A DescribePackage is the additional result of a 'describe' if
+// the selection indicates a package.
+type DescribePackage struct {
+ Path string `json:"path"` // import path of the package
+ Members []*DescribeMember `json:"members,omitempty"` // accessible members of the package
+}
+
+// A Describe is the result of a 'describe' query.
+// It may contain an element describing the selected semantic entity
+// in detail.
+type Describe struct {
+ Desc string `json:"desc"` // description of the selected syntax node
+ Pos string `json:"pos"` // location of the selected syntax node
+ Detail string `json:"detail,omitempty"` // one of {package, type, value}, or "".
+
+ // At most one of the following fields is populated:
+ // the one specified by 'detail'.
+ Package *DescribePackage `json:"package,omitempty"`
+ Type *DescribeType `json:"type,omitempty"`
+ Value *DescribeValue `json:"value,omitempty"`
+}
+
+// A WhichErrs is the result of a 'whicherrs' query.
+// It contains the position of the queried error and the possible globals,
+// constants, and types it may point to.
+type WhichErrs struct {
+ ErrPos string `json:"errpos,omitempty"` // location of queried error
+ Globals []string `json:"globals,omitempty"` // locations of globals
+ Constants []string `json:"constants,omitempty"` // locations of constants
+ Types []WhichErrsType `json:"types,omitempty"` // Types
+}
+
+type WhichErrsType struct {
+ Type string `json:"type,omitempty"`
+ Position string `json:"position,omitempty"`
+}
+
+// A Result is the common result of any oracle query.
+// It contains a query-specific result element.
+//
+// TODO(adonovan): perhaps include other info such as: analysis scope,
+// raw query position, stack of ast nodes, query package, etc.
+type Result struct {
+ Mode string `json:"mode"` // mode of the query
+
+ // Exactly one of the following fields is populated:
+ // the one specified by 'mode'.
+ Callees *Callees `json:"callees,omitempty"`
+ Callers []Caller `json:"callers,omitempty"`
+ Callstack *CallStack `json:"callstack,omitempty"`
+ Definition *Definition `json:"definition,omitempty"`
+ Describe *Describe `json:"describe,omitempty"`
+ Freevars []*FreeVar `json:"freevars,omitempty"`
+ Implements *Implements `json:"implements,omitempty"`
+ Peers *Peers `json:"peers,omitempty"`
+ PointsTo []PointsTo `json:"pointsto,omitempty"`
+ Referrers *Referrers `json:"referrers,omitempty"`
+ What *What `json:"what,omitempty"`
+ WhichErrs *WhichErrs `json:"whicherrs,omitempty"`
+}
diff --git a/oracle/testdata/src/calls-json/main.go b/oracle/testdata/src/calls-json/main.go
new file mode 100644
index 0000000..1c7a6c9
--- /dev/null
+++ b/oracle/testdata/src/calls-json/main.go
@@ -0,0 +1,16 @@
+package main
+
+// Tests of call-graph queries, -format=json.
+// See go.tools/oracle/oracle_test.go for explanation.
+// See calls-json.golden for expected query results.
+
+func call(f func()) {
+ f() // @callees @callees-f "f"
+}
+
+func main() {
+ call(func() {
+ // @callers callers-main.anon "^"
+ // @callstack callstack-main.anon "^"
+ })
+}
diff --git a/oracle/testdata/src/calls-json/main.golden b/oracle/testdata/src/calls-json/main.golden
new file mode 100644
index 0000000..f5eced6
--- /dev/null
+++ b/oracle/testdata/src/calls-json/main.golden
@@ -0,0 +1,34 @@
+-------- @callees @callees-f --------
+{
+ "mode": "callees",
+ "callees": {
+ "pos": "testdata/src/calls-json/main.go:8:3",
+ "desc": "dynamic function call",
+ "callees": [
+ {
+ "name": "main.main$1",
+ "pos": "testdata/src/calls-json/main.go:12:7"
+ }
+ ]
+ }
+}
+-------- @callstack callstack-main.anon --------
+{
+ "mode": "callstack",
+ "callstack": {
+ "pos": "testdata/src/calls-json/main.go:12:7",
+ "target": "main.main$1",
+ "callers": [
+ {
+ "pos": "testdata/src/calls-json/main.go:8:3",
+ "desc": "dynamic function call",
+ "caller": "main.call"
+ },
+ {
+ "pos": "testdata/src/calls-json/main.go:12:6",
+ "desc": "static function call",
+ "caller": "main.main"
+ }
+ ]
+ }
+}
diff --git a/oracle/testdata/src/calls/main.go b/oracle/testdata/src/calls/main.go
new file mode 100644
index 0000000..54bb895
--- /dev/null
+++ b/oracle/testdata/src/calls/main.go
@@ -0,0 +1,118 @@
+package main
+
+import (
+ "fmt"
+)
+
+// Tests of call-graph queries.
+// See go.tools/oracle/oracle_test.go for explanation.
+// See calls.golden for expected query results.
+
+func A(x *int) { // @pointsto pointsto-A-x "x"
+ // @callers callers-A "^"
+ // @callstack callstack-A "^"
+}
+
+func B(x *int) { // @pointsto pointsto-B-x "x"
+ // @callers callers-B "^"
+}
+
+func foo() {
+}
+
+// apply is not (yet) treated context-sensitively.
+func apply(f func(x *int), x *int) {
+ f(x) // @callees callees-apply "f"
+ // @callers callers-apply "^"
+}
+
+// store *is* treated context-sensitively,
+// so the points-to sets for pc, pd are precise.
+func store(ptr **int, value *int) {
+ *ptr = value
+ // @callers callers-store "^"
+}
+
+func call(f func() *int) {
+ // Result points to anon function.
+ f() // @pointsto pointsto-result-f "f"
+
+ // Target of call is anon function.
+ f() // @callees callees-main.call-f "f"
+
+ // @callers callers-main.call "^"
+}
+
+func main() {
+ var a, b int
+ go apply(A, &a) // @callees callees-main-apply1 "app"
+ defer apply(B, &b)
+
+ var c, d int
+ var pc, pd *int // @pointsto pointsto-pc "pc"
+ store(&pc, &c)
+ store(&pd, &d)
+ _ = pd // @pointsto pointsto-pd "pd"
+
+ call(func() *int {
+ // We are called twice from main.call
+ // @callers callers-main.anon "^"
+ return &a
+ })
+
+ // Errors
+ _ = "no function call here" // @callees callees-err-no-call "no"
+ print("builtin") // @callees callees-err-builtin "builtin"
+ _ = string("type conversion") // @callees callees-err-conversion "str"
+ call(nil) // @callees callees-err-bad-selection "call\\(nil"
+ if false {
+ main() // @callees callees-err-deadcode1 "main"
+ }
+ var nilFunc func()
+ nilFunc() // @callees callees-err-nil-func "nilFunc"
+ var i interface {
+ f()
+ }
+ i.f() // @callees callees-err-nil-interface "i.f"
+
+ i = new(myint)
+ i.f() // @callees callees-not-a-wrapper "f"
+
+ // statically dispatched calls. Handled specially by callees, so test that they work.
+ foo() // @callees callees-static-call "foo"
+ fmt.Println() // @callees callees-qualified-call "Println"
+ m := new(method)
+ m.f() // @callees callees-static-method-call "f"
+}
+
+type myint int
+
+func (myint) f() {
+ // @callers callers-not-a-wrapper "^"
+}
+
+type method int
+
+func (method) f() {
+}
+
+var dynamic = func() {}
+
+func deadcode() {
+ main() // @callees callees-err-deadcode2 "main"
+ // @callers callers-err-deadcode "^"
+ // @callstack callstack-err-deadcode "^"
+
+ // Within dead code, dynamic calls have no callees.
+ dynamic() // @callees callees-err-deadcode3 "dynamic"
+}
+
+// This code belongs to init.
+var global = 123 // @callers callers-global "global"
+
+// The package initializer may be called by other packages' inits, or
+// in this case, the root of the callgraph. The source-level init functions
+// are in turn called by it.
+func init() {
+ // @callstack callstack-init "^"
+}
diff --git a/oracle/testdata/src/calls/main.golden b/oracle/testdata/src/calls/main.golden
new file mode 100644
index 0000000..b5e6547
--- /dev/null
+++ b/oracle/testdata/src/calls/main.golden
@@ -0,0 +1,121 @@
+-------- @pointsto pointsto-A-x --------
+this *int may point to these objects:
+ a
+ b
+
+-------- @callstack callstack-A --------
+Found a call path from root to main.A
+main.A
+dynamic function call from main.apply
+concurrent static function call from main.main
+
+-------- @pointsto pointsto-B-x --------
+this *int may point to these objects:
+ a
+ b
+
+-------- @callers callers-B --------
+main.B is called from these 1 sites:
+ dynamic function call from main.apply
+
+-------- @callees callees-apply --------
+this dynamic function call dispatches to:
+ main.A
+ main.B
+
+-------- @callers callers-apply --------
+main.apply is called from these 2 sites:
+ concurrent static function call from main.main
+ deferred static function call from main.main
+
+-------- @callers callers-store --------
+main.store is called from these 2 sites:
+ static function call from main.main
+ static function call from main.main
+
+-------- @pointsto pointsto-result-f --------
+this func() *int may point to these objects:
+ main.main$1
+
+-------- @callees callees-main.call-f --------
+this dynamic function call dispatches to:
+ main.main$1
+
+-------- @callers callers-main.call --------
+main.call is called from these 2 sites:
+ static function call from main.main
+ static function call from main.main
+
+-------- @callees callees-main-apply1 --------
+this static function call dispatches to:
+ main.apply
+
+-------- @pointsto pointsto-pc --------
+this *int may point to these objects:
+ c
+
+-------- @pointsto pointsto-pd --------
+this *int may point to these objects:
+ d
+
+-------- @callees callees-err-no-call --------
+
+Error: there is no function call here
+-------- @callees callees-err-builtin --------
+
+Error: this is a call to the built-in 'print' operator
+-------- @callees callees-err-conversion --------
+
+Error: this is a type conversion, not a function call
+-------- @callees callees-err-bad-selection --------
+
+Error: ambiguous selection within function call (or conversion)
+-------- @callees callees-err-deadcode1 --------
+this static function call dispatches to:
+ main.main
+
+-------- @callees callees-err-nil-func --------
+dynamic function call on nil value
+
+-------- @callees callees-err-nil-interface --------
+dynamic method call on nil value
+
+-------- @callees callees-not-a-wrapper --------
+this dynamic method call dispatches to:
+ (main.myint).f
+
+-------- @callees callees-static-call --------
+this static function call dispatches to:
+ main.foo
+
+-------- @callees callees-qualified-call --------
+this static function call dispatches to:
+ fmt.Println
+
+-------- @callees callees-static-method-call --------
+this static function call dispatches to:
+ (main.method).f
+
+-------- @callers callers-not-a-wrapper --------
+(main.myint).f is called from these 1 sites:
+ dynamic method call from main.main
+
+-------- @callees callees-err-deadcode2 --------
+this static function call dispatches to:
+ main.main
+
+-------- @callstack callstack-err-deadcode --------
+main.deadcode is unreachable in this analysis scope
+
+-------- @callees callees-err-deadcode3 --------
+
+Error: this call site is unreachable in this analysis
+-------- @callers callers-global --------
+main.init is called from these 1 sites:
+the root of the call graph
+
+-------- @callstack callstack-init --------
+Found a call path from root to main.init#1
+main.init#1
+static function call from main.init
+
diff --git a/oracle/testdata/src/describe-json/main.go b/oracle/testdata/src/describe-json/main.go
new file mode 100644
index 0000000..359c731
--- /dev/null
+++ b/oracle/testdata/src/describe-json/main.go
@@ -0,0 +1,29 @@
+package describe // @describe pkgdecl "describe"
+
+// Tests of 'describe' query, -format=json.
+// See go.tools/oracle/oracle_test.go for explanation.
+// See describe-json.golden for expected query results.
+
+func main() {
+ var s struct{ x [3]int }
+ p := &s.x[0] // @describe desc-val-p "p"
+ _ = p
+
+ var i I = C(0)
+ if i == nil {
+ i = new(D)
+ }
+ print(i) // @describe desc-val-i "\\bi\\b"
+
+ go main() // @describe desc-stmt "go"
+}
+
+type I interface {
+ f()
+}
+
+type C int // @describe desc-type-C "C"
+type D struct{}
+
+func (c C) f() {}
+func (d *D) f() {}
diff --git a/oracle/testdata/src/describe-json/main.golden b/oracle/testdata/src/describe-json/main.golden
new file mode 100644
index 0000000..9d03661
--- /dev/null
+++ b/oracle/testdata/src/describe-json/main.golden
@@ -0,0 +1,111 @@
+-------- @describe pkgdecl --------
+{
+ "mode": "describe",
+ "describe": {
+ "desc": "definition of package \"describe-json\"",
+ "pos": "testdata/src/describe-json/main.go:1:9",
+ "detail": "package",
+ "package": {
+ "path": "describe-json",
+ "members": [
+ {
+ "name": "C",
+ "type": "int",
+ "pos": "testdata/src/describe-json/main.go:25:6",
+ "kind": "type",
+ "methods": [
+ {
+ "name": "method (C) f()",
+ "pos": "testdata/src/describe-json/main.go:28:12"
+ }
+ ]
+ },
+ {
+ "name": "D",
+ "type": "struct{}",
+ "pos": "testdata/src/describe-json/main.go:26:6",
+ "kind": "type",
+ "methods": [
+ {
+ "name": "method (*D) f()",
+ "pos": "testdata/src/describe-json/main.go:29:13"
+ }
+ ]
+ },
+ {
+ "name": "I",
+ "type": "interface{f()}",
+ "pos": "testdata/src/describe-json/main.go:21:6",
+ "kind": "type",
+ "methods": [
+ {
+ "name": "method (I) f()",
+ "pos": "testdata/src/describe-json/main.go:22:2"
+ }
+ ]
+ },
+ {
+ "name": "main",
+ "type": "func()",
+ "pos": "testdata/src/describe-json/main.go:7:6",
+ "kind": "func"
+ }
+ ]
+ }
+ }
+}
+-------- @describe desc-val-p --------
+{
+ "mode": "describe",
+ "describe": {
+ "desc": "identifier",
+ "pos": "testdata/src/describe-json/main.go:9:2",
+ "detail": "value",
+ "value": {
+ "type": "*int",
+ "objpos": "testdata/src/describe-json/main.go:9:2"
+ }
+ }
+}
+-------- @describe desc-val-i --------
+{
+ "mode": "describe",
+ "describe": {
+ "desc": "identifier",
+ "pos": "testdata/src/describe-json/main.go:16:8",
+ "detail": "value",
+ "value": {
+ "type": "I",
+ "objpos": "testdata/src/describe-json/main.go:12:6"
+ }
+ }
+}
+-------- @describe desc-stmt --------
+{
+ "mode": "describe",
+ "describe": {
+ "desc": "go statement",
+ "pos": "testdata/src/describe-json/main.go:18:2",
+ "detail": "unknown"
+ }
+}
+-------- @describe desc-type-C --------
+{
+ "mode": "describe",
+ "describe": {
+ "desc": "definition of type C (size 8, align 8)",
+ "pos": "testdata/src/describe-json/main.go:25:6",
+ "detail": "type",
+ "type": {
+ "type": "C",
+ "namepos": "testdata/src/describe-json/main.go:25:6",
+ "namedef": "int",
+ "methods": [
+ {
+ "name": "method (C) f()",
+ "pos": "testdata/src/describe-json/main.go:28:12"
+ }
+ ]
+ }
+ }
+}
diff --git a/oracle/testdata/src/describe/main.go b/oracle/testdata/src/describe/main.go
new file mode 100644
index 0000000..69e0a75
--- /dev/null
+++ b/oracle/testdata/src/describe/main.go
@@ -0,0 +1,87 @@
+package describe // @describe pkgdecl "describe"
+
+// Tests of 'describe' query.
+// See go.tools/oracle/oracle_test.go for explanation.
+// See describe.golden for expected query results.
+
+// TODO(adonovan): more coverage of the (extensive) logic.
+
+type cake float64 // @describe type-ref-builtin "float64"
+
+const c = iota // @describe const-ref-iota "iota"
+
+const pi = 3.141 // @describe const-def-pi "pi"
+const pie = cake(pi) // @describe const-def-pie "pie"
+const _ = pi // @describe const-ref-pi "pi"
+
+var global = new(string) // NB: ssa.Global is indirect, i.e. **string
+
+func main() { // @describe func-def-main "main"
+ // func objects
+ _ = main // @describe func-ref-main "main"
+ _ = (*C).f // @describe func-ref-*C.f "..C..f"
+ _ = D.f // @describe func-ref-D.f "D.f"
+ _ = I.f // @describe func-ref-I.f "I.f"
+ var d D // @describe type-D "D"
+ var i I // @describe type-I "I"
+ _ = d.f // @describe func-ref-d.f "d.f"
+ _ = i.f // @describe func-ref-i.f "i.f"
+
+ // var objects
+ anon := func() {
+ _ = d // @describe ref-lexical-d "d"
+ }
+ _ = anon // @describe ref-anon "anon"
+ _ = global // @describe ref-global "global"
+
+ // SSA affords some local flow sensitivity.
+ var a, b int
+ var x = &a // @describe var-def-x-1 "x"
+ _ = x // @describe var-ref-x-1 "x"
+ x = &b // @describe var-def-x-2 "x"
+ _ = x // @describe var-ref-x-2 "x"
+
+ i = new(C) // @describe var-ref-i-C "i"
+ if i != nil {
+ i = D{} // @describe var-ref-i-D "i"
+ }
+ print(i) // @describe var-ref-i "\\bi\\b"
+
+ // const objects
+ const localpi = 3.141 // @describe const-local-pi "localpi"
+ const localpie = cake(pi) // @describe const-local-pie "localpie"
+ const _ = localpi // @describe const-ref-localpi "localpi"
+
+ // type objects
+ type T int // @describe type-def-T "T"
+ var three T = 3 // @describe type-ref-T "T"
+ _ = three
+
+ print(1 + 2*3) // @describe const-expr " 2.3"
+ print(real(1+2i) - 3) // @describe const-expr2 "real.*3"
+
+ m := map[string]*int{"a": &a}
+ mapval, _ := m["a"] // @describe map-lookup,ok "m..a.."
+ _ = mapval // @describe mapval "mapval"
+ _ = m // @describe m "m"
+
+ defer main() // @describe defer-stmt "defer"
+ go main() // @describe go-stmt "go"
+
+ panic(3) // @describe builtin-ref-panic "panic"
+
+ var a2 int // @describe var-decl-stmt "var a2 int"
+ _ = a2
+ var _ int // @describe var-decl-stmt2 "var _ int"
+ var _ int // @describe var-def-blank "_"
+}
+
+type I interface { // @describe def-iface-I "I"
+ f() // @describe def-imethod-I.f "f"
+}
+
+type C int
+type D struct{}
+
+func (c *C) f() {}
+func (d D) f() {}
diff --git a/oracle/testdata/src/describe/main.golden b/oracle/testdata/src/describe/main.golden
new file mode 100644
index 0000000..33d751a
--- /dev/null
+++ b/oracle/testdata/src/describe/main.golden
@@ -0,0 +1,171 @@
+-------- @describe pkgdecl --------
+definition of package "describe"
+ type C int
+ method (*C) f()
+ type D struct{}
+ method (D) f()
+ type I interface{f()}
+ method (I) f()
+ const c untyped int = 0
+ type cake float64
+ var global *string
+ func main func()
+ const pi untyped float = 3141/1000
+ const pie cake = 1768225803696341/562949953421312
+
+-------- @describe type-ref-builtin --------
+reference to built-in type float64
+
+-------- @describe const-ref-iota --------
+reference to const iota untyped int of constant value 0
+
+-------- @describe const-def-pi --------
+definition of const pi untyped float
+
+-------- @describe const-def-pie --------
+definition of const pie cake
+
+-------- @describe const-ref-pi --------
+reference to const pi untyped float of constant value 3141/1000
+defined here
+
+-------- @describe func-def-main --------
+definition of func main()
+
+-------- @describe func-ref-main --------
+reference to func main()
+defined here
+
+-------- @describe func-ref-*C.f --------
+reference to method func (*C).f()
+defined here
+
+-------- @describe func-ref-D.f --------
+reference to method func (D).f()
+defined here
+
+-------- @describe func-ref-I.f --------
+reference to interface method func (I).f()
+defined here
+
+-------- @describe type-D --------
+reference to type D (size 0, align 1)
+defined as struct{}
+Method set:
+ method (D) f()
+
+-------- @describe type-I --------
+reference to type I (size 16, align 8)
+defined as interface{f()}
+Method set:
+ method (I) f()
+
+-------- @describe func-ref-d.f --------
+reference to method func (D).f()
+defined here
+
+-------- @describe func-ref-i.f --------
+reference to interface method func (I).f()
+defined here
+
+-------- @describe ref-lexical-d --------
+reference to var d D
+defined here
+
+-------- @describe ref-anon --------
+reference to var anon func()
+defined here
+
+-------- @describe ref-global --------
+reference to var global *string
+defined here
+
+-------- @describe var-def-x-1 --------
+definition of var x *int
+
+-------- @describe var-ref-x-1 --------
+reference to var x *int
+defined here
+
+-------- @describe var-def-x-2 --------
+reference to var x *int
+defined here
+
+-------- @describe var-ref-x-2 --------
+reference to var x *int
+defined here
+
+-------- @describe var-ref-i-C --------
+reference to var i I
+defined here
+
+-------- @describe var-ref-i-D --------
+reference to var i I
+defined here
+
+-------- @describe var-ref-i --------
+reference to var i I
+defined here
+
+-------- @describe const-local-pi --------
+definition of const localpi untyped float
+
+-------- @describe const-local-pie --------
+definition of const localpie cake
+
+-------- @describe const-ref-localpi --------
+reference to const localpi untyped float of constant value 3141/1000
+defined here
+
+-------- @describe type-def-T --------
+definition of type T (size 8, align 8)
+No methods.
+
+-------- @describe type-ref-T --------
+reference to type T (size 8, align 8)
+defined as int
+No methods.
+
+-------- @describe const-expr --------
+binary * operation of constant value 6
+
+-------- @describe const-expr2 --------
+binary - operation of constant value -2
+
+-------- @describe map-lookup,ok --------
+index expression of type (*int, bool)
+
+-------- @describe mapval --------
+reference to var mapval *int
+defined here
+
+-------- @describe m --------
+reference to var m map[string]*int
+defined here
+
+-------- @describe defer-stmt --------
+defer statement
+
+-------- @describe go-stmt --------
+go statement
+
+-------- @describe builtin-ref-panic --------
+function call (or conversion) of type ()
+
+-------- @describe var-decl-stmt --------
+definition of var a2 int
+
+-------- @describe var-decl-stmt2 --------
+definition of var _ int
+
+-------- @describe var-def-blank --------
+definition of var _ int
+
+-------- @describe def-iface-I --------
+definition of type I (size 16, align 8)
+Method set:
+ method (I) f()
+
+-------- @describe def-imethod-I.f --------
+definition of interface method func (I).f()
+
diff --git a/oracle/testdata/src/freevars/main.go b/oracle/testdata/src/freevars/main.go
new file mode 100644
index 0000000..1ce0ae6
--- /dev/null
+++ b/oracle/testdata/src/freevars/main.go
@@ -0,0 +1,41 @@
+package main
+
+// Tests of 'freevars' query.
+// See go.tools/oracle/oracle_test.go for explanation.
+// See freevars.golden for expected query results.
+
+// TODO(adonovan): it's hard to test this query in a single line of gofmt'd code.
+
+type T struct {
+ a, b int
+}
+
+type S struct {
+ x int
+ t T
+}
+
+func f(int) {}
+
+func main() {
+ type C int
+ x := 1
+ const exp = 6
+ if y := 2; x+y+int(C(3)) != exp { // @freevars fv1 "if.*{"
+ panic("expected 6")
+ }
+
+ var s S
+
+ for x, y := range "foo" {
+ println(s.x + s.t.a + s.t.b + x + int(y)) // @freevars fv2 "print.*y."
+ }
+
+ f(x) // @freevars fv3 "f.x."
+
+ // TODO(adonovan): enable when go/types supports labels.
+loop: // #@freevars fv-def-label "loop:"
+ for {
+ break loop // #@freevars fv-ref-label "break loop"
+ }
+}
diff --git a/oracle/testdata/src/freevars/main.golden b/oracle/testdata/src/freevars/main.golden
new file mode 100644
index 0000000..b9eeab2
--- /dev/null
+++ b/oracle/testdata/src/freevars/main.golden
@@ -0,0 +1,18 @@
+-------- @freevars fv1 --------
+Free identifiers:
+type C
+const exp int
+var x int
+
+-------- @freevars fv2 --------
+Free identifiers:
+var s.t.a int
+var s.t.b int
+var s.x int
+var x int
+var y rune
+
+-------- @freevars fv3 --------
+Free identifiers:
+var x int
+
diff --git a/oracle/testdata/src/implements-json/main.go b/oracle/testdata/src/implements-json/main.go
new file mode 100644
index 0000000..d5f8102
--- /dev/null
+++ b/oracle/testdata/src/implements-json/main.go
@@ -0,0 +1,27 @@
+package main
+
+// Tests of 'implements' query, -output=json.
+// See go.tools/oracle/oracle_test.go for explanation.
+// See implements.golden for expected query results.
+
+func main() {
+}
+
+type E interface{} // @implements E "E"
+
+type F interface { // @implements F "F"
+ f()
+}
+
+type FG interface { // @implements FG "FG"
+ f()
+ g() []int // @implements slice "..int"
+}
+
+type C int // @implements C "C"
+type D struct{}
+
+func (c *C) f() {} // @implements starC ".C"
+func (d D) f() {} // @implements D "D"
+
+func (d *D) g() []int { return nil } // @implements starD ".D"
diff --git a/oracle/testdata/src/implements-json/main.golden b/oracle/testdata/src/implements-json/main.golden
new file mode 100644
index 0000000..7e37f9e
--- /dev/null
+++ b/oracle/testdata/src/implements-json/main.golden
@@ -0,0 +1,159 @@
+-------- @implements E --------
+{
+ "mode": "implements",
+ "implements": {
+ "type": {
+ "name": "implements-json.E",
+ "pos": "testdata/src/implements-json/main.go:10:6",
+ "kind": "interface"
+ }
+ }
+}
+-------- @implements F --------
+{
+ "mode": "implements",
+ "implements": {
+ "type": {
+ "name": "implements-json.F",
+ "pos": "testdata/src/implements-json/main.go:12:6",
+ "kind": "interface"
+ },
+ "to": [
+ {
+ "name": "*implements-json.C",
+ "pos": "testdata/src/implements-json/main.go:21:6",
+ "kind": "pointer"
+ },
+ {
+ "name": "implements-json.D",
+ "pos": "testdata/src/implements-json/main.go:22:6",
+ "kind": "struct"
+ },
+ {
+ "name": "implements-json.FG",
+ "pos": "testdata/src/implements-json/main.go:16:6",
+ "kind": "interface"
+ }
+ ]
+ }
+}
+-------- @implements FG --------
+{
+ "mode": "implements",
+ "implements": {
+ "type": {
+ "name": "implements-json.FG",
+ "pos": "testdata/src/implements-json/main.go:16:6",
+ "kind": "interface"
+ },
+ "to": [
+ {
+ "name": "*implements-json.D",
+ "pos": "testdata/src/implements-json/main.go:22:6",
+ "kind": "pointer"
+ }
+ ],
+ "from": [
+ {
+ "name": "implements-json.F",
+ "pos": "testdata/src/implements-json/main.go:12:6",
+ "kind": "interface"
+ }
+ ]
+ }
+}
+-------- @implements slice --------
+{
+ "mode": "implements",
+ "implements": {
+ "type": {
+ "name": "[]int",
+ "pos": "-",
+ "kind": "slice"
+ }
+ }
+}
+-------- @implements C --------
+{
+ "mode": "implements",
+ "implements": {
+ "type": {
+ "name": "implements-json.C",
+ "pos": "testdata/src/implements-json/main.go:21:6",
+ "kind": "basic"
+ },
+ "fromptr": [
+ {
+ "name": "implements-json.F",
+ "pos": "testdata/src/implements-json/main.go:12:6",
+ "kind": "interface"
+ }
+ ]
+ }
+}
+-------- @implements starC --------
+{
+ "mode": "implements",
+ "implements": {
+ "type": {
+ "name": "*implements-json.C",
+ "pos": "testdata/src/implements-json/main.go:21:6",
+ "kind": "pointer"
+ },
+ "from": [
+ {
+ "name": "implements-json.F",
+ "pos": "testdata/src/implements-json/main.go:12:6",
+ "kind": "interface"
+ }
+ ]
+ }
+}
+-------- @implements D --------
+{
+ "mode": "implements",
+ "implements": {
+ "type": {
+ "name": "implements-json.D",
+ "pos": "testdata/src/implements-json/main.go:22:6",
+ "kind": "struct"
+ },
+ "from": [
+ {
+ "name": "implements-json.F",
+ "pos": "testdata/src/implements-json/main.go:12:6",
+ "kind": "interface"
+ }
+ ],
+ "fromptr": [
+ {
+ "name": "implements-json.FG",
+ "pos": "testdata/src/implements-json/main.go:16:6",
+ "kind": "interface"
+ }
+ ]
+ }
+}
+-------- @implements starD --------
+{
+ "mode": "implements",
+ "implements": {
+ "type": {
+ "name": "*implements-json.D",
+ "pos": "testdata/src/implements-json/main.go:22:6",
+ "kind": "pointer"
+ },
+ "from": [
+ {
+ "name": "implements-json.F",
+ "pos": "testdata/src/implements-json/main.go:12:6",
+ "kind": "interface"
+ },
+ {
+ "name": "implements-json.FG",
+ "pos": "testdata/src/implements-json/main.go:16:6",
+ "kind": "interface"
+ }
+ ]
+ }
+}
diff --git a/oracle/testdata/src/implements-methods-json/main.go b/oracle/testdata/src/implements-methods-json/main.go
new file mode 100644
index 0000000..6c5bbf4
--- /dev/null
+++ b/oracle/testdata/src/implements-methods-json/main.go
@@ -0,0 +1,37 @@
+package main
+
+// Tests of 'implements' query applied to methods, -output=json.
+// See go.tools/oracle/oracle_test.go for explanation.
+// See implements-methods.golden for expected query results.
+
+import _ "lib"
+
+func main() {
+}
+
+type F interface {
+ f() // @implements F.f "f"
+}
+
+type FG interface {
+ f() // @implements FG.f "f"
+ g() []int // @implements FG.g "g"
+}
+
+type C int
+type D struct{}
+
+func (c *C) f() {} // @implements *C.f "f"
+func (d D) f() {} // @implements D.f "f"
+
+func (d *D) g() []int { return nil } // @implements *D.g "g"
+
+type sorter []int
+
+func (sorter) Len() int { return 0 } // @implements Len "Len"
+func (sorter) Less(i, j int) bool { return false }
+func (sorter) Swap(i, j int) {}
+
+type I interface {
+ Method(*int) *int // @implements I.Method "Method"
+}
diff --git a/oracle/testdata/src/implements-methods-json/main.golden b/oracle/testdata/src/implements-methods-json/main.golden
new file mode 100644
index 0000000..fa117df
--- /dev/null
+++ b/oracle/testdata/src/implements-methods-json/main.golden
@@ -0,0 +1,290 @@
+-------- @implements F.f --------
+{
+ "mode": "implements",
+ "implements": {
+ "type": {
+ "name": "implements-methods-json.F",
+ "pos": "testdata/src/implements-methods-json/main.go:12:6",
+ "kind": "interface"
+ },
+ "to": [
+ {
+ "name": "*implements-methods-json.C",
+ "pos": "testdata/src/implements-methods-json/main.go:21:6",
+ "kind": "pointer"
+ },
+ {
+ "name": "implements-methods-json.D",
+ "pos": "testdata/src/implements-methods-json/main.go:22:6",
+ "kind": "struct"
+ },
+ {
+ "name": "implements-methods-json.FG",
+ "pos": "testdata/src/implements-methods-json/main.go:16:6",
+ "kind": "interface"
+ }
+ ],
+ "method": {
+ "name": "func (F).f()",
+ "pos": "testdata/src/implements-methods-json/main.go:13:2"
+ },
+ "to_method": [
+ {
+ "name": "method (*C) f()",
+ "pos": "testdata/src/implements-methods-json/main.go:24:13"
+ },
+ {
+ "name": "method (D) f()",
+ "pos": "testdata/src/implements-methods-json/main.go:25:12"
+ },
+ {
+ "name": "method (FG) f()",
+ "pos": "testdata/src/implements-methods-json/main.go:17:2"
+ }
+ ]
+ }
+}
+-------- @implements FG.f --------
+{
+ "mode": "implements",
+ "implements": {
+ "type": {
+ "name": "implements-methods-json.FG",
+ "pos": "testdata/src/implements-methods-json/main.go:16:6",
+ "kind": "interface"
+ },
+ "to": [
+ {
+ "name": "*implements-methods-json.D",
+ "pos": "testdata/src/implements-methods-json/main.go:22:6",
+ "kind": "pointer"
+ }
+ ],
+ "from": [
+ {
+ "name": "implements-methods-json.F",
+ "pos": "testdata/src/implements-methods-json/main.go:12:6",
+ "kind": "interface"
+ }
+ ],
+ "method": {
+ "name": "func (FG).f()",
+ "pos": "testdata/src/implements-methods-json/main.go:17:2"
+ },
+ "to_method": [
+ {
+ "name": "method (*D) f()",
+ "pos": "testdata/src/implements-methods-json/main.go:25:12"
+ }
+ ],
+ "from_method": [
+ {
+ "name": "method (F) f()",
+ "pos": "testdata/src/implements-methods-json/main.go:13:2"
+ }
+ ]
+ }
+}
+-------- @implements FG.g --------
+{
+ "mode": "implements",
+ "implements": {
+ "type": {
+ "name": "implements-methods-json.FG",
+ "pos": "testdata/src/implements-methods-json/main.go:16:6",
+ "kind": "interface"
+ },
+ "to": [
+ {
+ "name": "*implements-methods-json.D",
+ "pos": "testdata/src/implements-methods-json/main.go:22:6",
+ "kind": "pointer"
+ }
+ ],
+ "from": [
+ {
+ "name": "implements-methods-json.F",
+ "pos": "testdata/src/implements-methods-json/main.go:12:6",
+ "kind": "interface"
+ }
+ ],
+ "method": {
+ "name": "func (FG).g() []int",
+ "pos": "testdata/src/implements-methods-json/main.go:18:2"
+ },
+ "to_method": [
+ {
+ "name": "method (*D) g() []int",
+ "pos": "testdata/src/implements-methods-json/main.go:27:13"
+ }
+ ],
+ "from_method": [
+ {
+ "name": "",
+ "pos": ""
+ }
+ ]
+ }
+}
+-------- @implements *C.f --------
+{
+ "mode": "implements",
+ "implements": {
+ "type": {
+ "name": "*implements-methods-json.C",
+ "pos": "testdata/src/implements-methods-json/main.go:21:6",
+ "kind": "pointer"
+ },
+ "from": [
+ {
+ "name": "implements-methods-json.F",
+ "pos": "testdata/src/implements-methods-json/main.go:12:6",
+ "kind": "interface"
+ }
+ ],
+ "method": {
+ "name": "func (*C).f()",
+ "pos": "testdata/src/implements-methods-json/main.go:24:13"
+ },
+ "from_method": [
+ {
+ "name": "method (F) f()",
+ "pos": "testdata/src/implements-methods-json/main.go:13:2"
+ }
+ ]
+ }
+}
+-------- @implements D.f --------
+{
+ "mode": "implements",
+ "implements": {
+ "type": {
+ "name": "implements-methods-json.D",
+ "pos": "testdata/src/implements-methods-json/main.go:22:6",
+ "kind": "struct"
+ },
+ "from": [
+ {
+ "name": "implements-methods-json.F",
+ "pos": "testdata/src/implements-methods-json/main.go:12:6",
+ "kind": "interface"
+ }
+ ],
+ "fromptr": [
+ {
+ "name": "implements-methods-json.FG",
+ "pos": "testdata/src/implements-methods-json/main.go:16:6",
+ "kind": "interface"
+ }
+ ],
+ "method": {
+ "name": "func (D).f()",
+ "pos": "testdata/src/implements-methods-json/main.go:25:12"
+ },
+ "from_method": [
+ {
+ "name": "method (F) f()",
+ "pos": "testdata/src/implements-methods-json/main.go:13:2"
+ }
+ ],
+ "fromptr_method": [
+ {
+ "name": "method (FG) f()",
+ "pos": "testdata/src/implements-methods-json/main.go:17:2"
+ }
+ ]
+ }
+}
+-------- @implements *D.g --------
+{
+ "mode": "implements",
+ "implements": {
+ "type": {
+ "name": "*implements-methods-json.D",
+ "pos": "testdata/src/implements-methods-json/main.go:22:6",
+ "kind": "pointer"
+ },
+ "from": [
+ {
+ "name": "implements-methods-json.F",
+ "pos": "testdata/src/implements-methods-json/main.go:12:6",
+ "kind": "interface"
+ },
+ {
+ "name": "implements-methods-json.FG",
+ "pos": "testdata/src/implements-methods-json/main.go:16:6",
+ "kind": "interface"
+ }
+ ],
+ "method": {
+ "name": "func (*D).g() []int",
+ "pos": "testdata/src/implements-methods-json/main.go:27:13"
+ },
+ "from_method": [
+ {
+ "name": "",
+ "pos": ""
+ },
+ {
+ "name": "method (FG) g() []int",
+ "pos": "testdata/src/implements-methods-json/main.go:18:2"
+ }
+ ]
+ }
+}
+-------- @implements Len --------
+{
+ "mode": "implements",
+ "implements": {
+ "type": {
+ "name": "implements-methods-json.sorter",
+ "pos": "testdata/src/implements-methods-json/main.go:29:6",
+ "kind": "slice"
+ },
+ "from": [
+ {
+ "name": "lib.Sorter",
+ "pos": "testdata/src/lib/lib.go:16:6",
+ "kind": "interface"
+ }
+ ],
+ "method": {
+ "name": "func (sorter).Len() int",
+ "pos": "testdata/src/implements-methods-json/main.go:31:15"
+ },
+ "from_method": [
+ {
+ "name": "method (lib.Sorter) Len() int",
+ "pos": "testdata/src/lib/lib.go:17:2"
+ }
+ ]
+ }
+}
+-------- @implements I.Method --------
+{
+ "mode": "implements",
+ "implements": {
+ "type": {
+ "name": "implements-methods-json.I",
+ "pos": "testdata/src/implements-methods-json/main.go:35:6",
+ "kind": "interface"
+ },
+ "to": [
+ {
+ "name": "lib.Type",
+ "pos": "testdata/src/lib/lib.go:3:6",
+ "kind": "basic"
+ }
+ ],
+ "method": {
+ "name": "func (I).Method(*int) *int",
+ "pos": "testdata/src/implements-methods-json/main.go:36:2"
+ },
+ "to_method": [
+ {
+ "name": "method (lib.Type) Method(x *int) *int",
+ "pos": "testdata/src/lib/lib.go:5:13"
+ }
+ ]
+ }
+}
diff --git a/oracle/testdata/src/implements-methods/main.go b/oracle/testdata/src/implements-methods/main.go
new file mode 100644
index 0000000..a24854a
--- /dev/null
+++ b/oracle/testdata/src/implements-methods/main.go
@@ -0,0 +1,37 @@
+package main
+
+// Tests of 'implements' query applied to methods.
+// See go.tools/oracle/oracle_test.go for explanation.
+// See implements-methods.golden for expected query results.
+
+import _ "lib"
+
+func main() {
+}
+
+type F interface {
+ f() // @implements F.f "f"
+}
+
+type FG interface {
+ f() // @implements FG.f "f"
+ g() []int // @implements FG.g "g"
+}
+
+type C int
+type D struct{}
+
+func (c *C) f() {} // @implements *C.f "f"
+func (d D) f() {} // @implements D.f "f"
+
+func (d *D) g() []int { return nil } // @implements *D.g "g"
+
+type sorter []int
+
+func (sorter) Len() int { return 0 } // @implements Len "Len"
+func (sorter) Less(i, j int) bool { return false }
+func (sorter) Swap(i, j int) {}
+
+type I interface {
+ Method(*int) *int // @implements I.Method "Method"
+}
diff --git a/oracle/testdata/src/implements-methods/main.golden b/oracle/testdata/src/implements-methods/main.golden
new file mode 100644
index 0000000..bd591e8
--- /dev/null
+++ b/oracle/testdata/src/implements-methods/main.golden
@@ -0,0 +1,37 @@
+-------- @implements F.f --------
+abstract method func (F).f()
+ is implemented by method (*C).f
+ is implemented by method (D).f
+ is implemented by method (FG).f
+
+-------- @implements FG.f --------
+abstract method func (FG).f()
+ is implemented by method (*D).f
+ implements method (F).f
+
+-------- @implements FG.g --------
+abstract method func (FG).g() []int
+ is implemented by method (*D).g
+
+-------- @implements *C.f --------
+concrete method func (*C).f()
+ implements method (F).f
+
+-------- @implements D.f --------
+concrete method func (D).f()
+ implements method (F).f
+concrete method func (D).f()
+ implements method (FG).f
+
+-------- @implements *D.g --------
+concrete method func (*D).g() []int
+ implements method (FG).g
+
+-------- @implements Len --------
+concrete method func (sorter).Len() int
+ implements method (lib.Sorter).Len
+
+-------- @implements I.Method --------
+abstract method func (I).Method(*int) *int
+ is implemented by method (lib.Type).Method
+
diff --git a/oracle/testdata/src/implements/main.go b/oracle/testdata/src/implements/main.go
new file mode 100644
index 0000000..14a2f16
--- /dev/null
+++ b/oracle/testdata/src/implements/main.go
@@ -0,0 +1,39 @@
+package main
+
+// Tests of 'implements' query.
+// See go.tools/oracle/oracle_test.go for explanation.
+// See implements.golden for expected query results.
+
+import _ "lib"
+
+func main() {
+}
+
+type E interface{} // @implements E "E"
+
+type F interface { // @implements F "F"
+ f()
+}
+
+type FG interface { // @implements FG "FG"
+ f()
+ g() []int // @implements slice "..int"
+}
+
+type C int // @implements C "C"
+type D struct{}
+
+func (c *C) f() {} // @implements starC ".C"
+func (d D) f() {} // @implements D "D"
+
+func (d *D) g() []int { return nil } // @implements starD ".D"
+
+type sorter []int // @implements sorter "sorter"
+
+func (sorter) Len() int { return 0 }
+func (sorter) Less(i, j int) bool { return false }
+func (sorter) Swap(i, j int) {}
+
+type I interface { // @implements I "I"
+ Method(*int) *int
+}
diff --git a/oracle/testdata/src/implements/main.golden b/oracle/testdata/src/implements/main.golden
new file mode 100644
index 0000000..ee00f3d
--- /dev/null
+++ b/oracle/testdata/src/implements/main.golden
@@ -0,0 +1,44 @@
+-------- @implements E --------
+empty interface type E
+
+-------- @implements F --------
+interface type F
+ is implemented by pointer type *C
+ is implemented by struct type D
+ is implemented by interface type FG
+
+-------- @implements FG --------
+interface type FG
+ is implemented by pointer type *D
+ implements F
+
+-------- @implements slice --------
+slice type []int implements only interface{}
+
+-------- @implements C --------
+pointer type *C
+ implements F
+
+-------- @implements starC --------
+pointer type *C
+ implements F
+
+-------- @implements D --------
+struct type D
+ implements F
+pointer type *D
+ implements FG
+
+-------- @implements starD --------
+pointer type *D
+ implements F
+ implements FG
+
+-------- @implements sorter --------
+slice type sorter
+ implements lib.Sorter
+
+-------- @implements I --------
+interface type I
+ is implemented by basic type lib.Type
+
diff --git a/oracle/testdata/src/imports/main.go b/oracle/testdata/src/imports/main.go
new file mode 100644
index 0000000..0f616ab
--- /dev/null
+++ b/oracle/testdata/src/imports/main.go
@@ -0,0 +1,29 @@
+package main
+
+import (
+ "hash/fnv" // @describe ref-pkg-import2 "fnv"
+ "lib" // @describe ref-pkg-import "lib"
+)
+
+// Tests that import another package. (To make the tests run quickly,
+// we avoid using imports in all the other tests. Remember, each
+// query causes parsing and typechecking of the whole program.)
+//
+// See go.tools/oracle/oracle_test.go for explanation.
+// See imports.golden for expected query results.
+
+var a int
+
+func main() {
+ const c = lib.Const // @describe ref-const "Const"
+ lib.Func() // @describe ref-func "Func"
+ lib.Var++ // @describe ref-var "Var"
+ var t lib.Type // @describe ref-type "Type"
+ p := t.Method(&a) // @describe ref-method "Method"
+
+ print(*p + 1) // @pointsto p "p "
+
+ var _ lib.Type // @describe ref-pkg "lib"
+
+ fnv.New32()
+}
diff --git a/oracle/testdata/src/imports/main.golden b/oracle/testdata/src/imports/main.golden
new file mode 100644
index 0000000..9144210
--- /dev/null
+++ b/oracle/testdata/src/imports/main.golden
@@ -0,0 +1,57 @@
+-------- @describe ref-pkg-import2 --------
+import of package "hash/fnv"
+ func New32 func() hash.Hash32
+ func New32a func() hash.Hash32
+ func New64 func() hash.Hash64
+ func New64a func() hash.Hash64
+
+-------- @describe ref-pkg-import --------
+import of package "lib"
+ const Const untyped int = 3
+ func Func func()
+ type Sorter interface{...}
+ method (Sorter) Len() int
+ method (Sorter) Less(i int, j int) bool
+ method (Sorter) Swap(i int, j int)
+ type Type int
+ method (Type) Method(x *int) *int
+ var Var int
+
+-------- @describe ref-const --------
+reference to const lib.Const untyped int
+defined here
+
+-------- @describe ref-func --------
+reference to func lib.Func()
+defined here
+
+-------- @describe ref-var --------
+reference to var lib.Var int
+defined here
+
+-------- @describe ref-type --------
+reference to type lib.Type (size 8, align 8)
+defined as int
+Method set:
+ method (lib.Type) Method(x *int) *int
+
+-------- @describe ref-method --------
+reference to method func (lib.Type).Method(x *int) *int
+defined here
+
+-------- @pointsto p --------
+this *int may point to these objects:
+ main.a
+
+-------- @describe ref-pkg --------
+reference to package "lib"
+ const Const untyped int = 3
+ func Func func()
+ type Sorter interface{...}
+ method (Sorter) Len() int
+ method (Sorter) Less(i int, j int) bool
+ method (Sorter) Swap(i int, j int)
+ type Type int
+ method (Type) Method(x *int) *int
+ var Var int
+
diff --git a/oracle/testdata/src/lib/lib.go b/oracle/testdata/src/lib/lib.go
new file mode 100644
index 0000000..9131c27
--- /dev/null
+++ b/oracle/testdata/src/lib/lib.go
@@ -0,0 +1,20 @@
+package lib
+
+type Type int
+
+func (Type) Method(x *int) *int {
+ return x
+}
+
+func Func() {
+}
+
+const Const = 3
+
+var Var = 0
+
+type Sorter interface {
+ Len() int
+ Less(i, j int) bool
+ Swap(i, j int)
+}
diff --git a/oracle/testdata/src/main/multi.go b/oracle/testdata/src/main/multi.go
new file mode 100644
index 0000000..8c650cd
--- /dev/null
+++ b/oracle/testdata/src/main/multi.go
@@ -0,0 +1,13 @@
+package main
+
+func g(x int) {
+}
+
+func f() {
+ x := 1
+ g(x) // "g(x)" is the selection for multiple queries
+}
+
+func main() {
+ f()
+}
diff --git a/oracle/testdata/src/peers-json/main.go b/oracle/testdata/src/peers-json/main.go
new file mode 100644
index 0000000..1df550b
--- /dev/null
+++ b/oracle/testdata/src/peers-json/main.go
@@ -0,0 +1,13 @@
+package main
+
+// Tests of channel 'peers' query, -format=json.
+// See go.tools/oracle/oracle_test.go for explanation.
+// See peers-json.golden for expected query results.
+
+func main() {
+ chA := make(chan *int)
+ <-chA
+ select {
+ case <-chA: // @peers peer-recv-chA "<-"
+ }
+}
diff --git a/oracle/testdata/src/peers-json/main.golden b/oracle/testdata/src/peers-json/main.golden
new file mode 100644
index 0000000..8c2d06c
--- /dev/null
+++ b/oracle/testdata/src/peers-json/main.golden
@@ -0,0 +1,15 @@
+-------- @peers peer-recv-chA --------
+{
+ "mode": "peers",
+ "peers": {
+ "pos": "testdata/src/peers-json/main.go:11:7",
+ "type": "chan *int",
+ "allocs": [
+ "testdata/src/peers-json/main.go:8:13"
+ ],
+ "receives": [
+ "testdata/src/peers-json/main.go:9:2",
+ "testdata/src/peers-json/main.go:11:7"
+ ]
+ }
+}
diff --git a/oracle/testdata/src/peers/main.go b/oracle/testdata/src/peers/main.go
new file mode 100644
index 0000000..a4cf91b
--- /dev/null
+++ b/oracle/testdata/src/peers/main.go
@@ -0,0 +1,52 @@
+package main
+
+// Tests of channel 'peers' query.
+// See go.tools/oracle/oracle_test.go for explanation.
+// See peers.golden for expected query results.
+
+var a2 int
+
+func main() {
+ chA := make(chan *int)
+ a1 := 1
+ chA <- &a1
+
+ chA2 := make(chan *int, 2)
+ if a2 == 0 {
+ chA = chA2
+ }
+
+ chB := make(chan *int)
+ b := 3
+ chB <- &b
+
+ <-chA // @pointsto pointsto-chA "chA"
+ <-chA2 // @pointsto pointsto-chA2 "chA2"
+ <-chB // @pointsto pointsto-chB "chB"
+
+ select {
+ case rA := <-chA: // @peers peer-recv-chA "<-"
+ _ = rA // @pointsto pointsto-rA "rA"
+ case rB := <-chB: // @peers peer-recv-chB "<-"
+ _ = rB // @pointsto pointsto-rB "rB"
+
+ case <-chA: // @peers peer-recv-chA' "<-"
+
+ case chA2 <- &a2: // @peers peer-send-chA' "<-"
+ }
+
+ for _ = range chA {
+ }
+
+ close(chA) // @peers peer-close-chA "chA"
+
+ chC := make(chan *int)
+ (close)(chC) // @peers peer-close-chC "chC"
+
+ close := func(ch chan *int) chan *int {
+ return ch
+ }
+
+ close(chC) <- &b // @peers peer-send-chC "chC"
+ <-close(chC) // @peers peer-recv-chC "chC"
+}
diff --git a/oracle/testdata/src/peers/main.golden b/oracle/testdata/src/peers/main.golden
new file mode 100644
index 0000000..597a3c6
--- /dev/null
+++ b/oracle/testdata/src/peers/main.golden
@@ -0,0 +1,100 @@
+-------- @pointsto pointsto-chA --------
+this chan *int may point to these objects:
+ makechan
+ makechan
+
+-------- @pointsto pointsto-chA2 --------
+this chan *int may point to these objects:
+ makechan
+
+-------- @pointsto pointsto-chB --------
+this chan *int may point to these objects:
+ makechan
+
+-------- @peers peer-recv-chA --------
+This channel of type chan *int may be:
+ allocated here
+ allocated here
+ sent to, here
+ sent to, here
+ received from, here
+ received from, here
+ received from, here
+ received from, here
+ received from, here
+ closed, here
+
+-------- @pointsto pointsto-rA --------
+this *int may point to these objects:
+ main.a2
+ a1
+
+-------- @peers peer-recv-chB --------
+This channel of type chan *int may be:
+ allocated here
+ sent to, here
+ received from, here
+ received from, here
+
+-------- @pointsto pointsto-rB --------
+this *int may point to these objects:
+ b
+
+-------- @peers peer-recv-chA' --------
+This channel of type chan *int may be:
+ allocated here
+ allocated here
+ sent to, here
+ sent to, here
+ received from, here
+ received from, here
+ received from, here
+ received from, here
+ received from, here
+ closed, here
+
+-------- @peers peer-send-chA' --------
+This channel of type chan *int may be:
+ allocated here
+ sent to, here
+ received from, here
+ received from, here
+ received from, here
+ received from, here
+ received from, here
+ closed, here
+
+-------- @peers peer-close-chA --------
+This channel of type chan *int may be:
+ allocated here
+ allocated here
+ sent to, here
+ sent to, here
+ received from, here
+ received from, here
+ received from, here
+ received from, here
+ received from, here
+ closed, here
+
+-------- @peers peer-close-chC --------
+This channel of type chan *int may be:
+ allocated here
+ sent to, here
+ received from, here
+ closed, here
+
+-------- @peers peer-send-chC --------
+This channel of type chan *int may be:
+ allocated here
+ sent to, here
+ received from, here
+ closed, here
+
+-------- @peers peer-recv-chC --------
+This channel of type chan *int may be:
+ allocated here
+ sent to, here
+ received from, here
+ closed, here
+
diff --git a/oracle/testdata/src/pointsto-json/main.go b/oracle/testdata/src/pointsto-json/main.go
new file mode 100644
index 0000000..38f1148
--- /dev/null
+++ b/oracle/testdata/src/pointsto-json/main.go
@@ -0,0 +1,27 @@
+package main
+
+// Tests of 'pointsto' queries, -format=json.
+// See go.tools/oracle/oracle_test.go for explanation.
+// See pointsto-json.golden for expected query results.
+
+func main() { //
+ var s struct{ x [3]int }
+ p := &s.x[0] // @pointsto val-p "p"
+ _ = p
+
+ var i I = C(0)
+ if i == nil {
+ i = new(D)
+ }
+ print(i) // @pointsto val-i "\\bi\\b"
+}
+
+type I interface {
+ f()
+}
+
+type C int
+type D struct{}
+
+func (c C) f() {}
+func (d *D) f() {}
diff --git a/oracle/testdata/src/pointsto-json/main.golden b/oracle/testdata/src/pointsto-json/main.golden
new file mode 100644
index 0000000..13ac1df
--- /dev/null
+++ b/oracle/testdata/src/pointsto-json/main.golden
@@ -0,0 +1,35 @@
+-------- @pointsto val-p --------
+{
+ "mode": "pointsto",
+ "pointsto": [
+ {
+ "type": "*int",
+ "labels": [
+ {
+ "pos": "testdata/src/pointsto-json/main.go:8:6",
+ "desc": "s.x[*]"
+ }
+ ]
+ }
+ ]
+}
+-------- @pointsto val-i --------
+{
+ "mode": "pointsto",
+ "pointsto": [
+ {
+ "type": "*D",
+ "namepos": "testdata/src/pointsto-json/main.go:24:6",
+ "labels": [
+ {
+ "pos": "testdata/src/pointsto-json/main.go:14:10",
+ "desc": "new"
+ }
+ ]
+ },
+ {
+ "type": "C",
+ "namepos": "testdata/src/pointsto-json/main.go:23:6"
+ }
+ ]
+}
diff --git a/oracle/testdata/src/pointsto/main.go b/oracle/testdata/src/pointsto/main.go
new file mode 100644
index 0000000..9064e46
--- /dev/null
+++ b/oracle/testdata/src/pointsto/main.go
@@ -0,0 +1,75 @@
+package main
+
+// Tests of 'pointsto' query.
+// See go.tools/oracle/oracle_test.go for explanation.
+// See pointsto.golden for expected query results.
+
+const pi = 3.141 // @pointsto const "pi"
+
+var global = new(string) // NB: ssa.Global is indirect, i.e. **string
+
+func main() {
+ livecode()
+
+ // func objects
+ _ = main // @pointsto func-ref-main "main"
+ _ = (*C).f // @pointsto func-ref-*C.f "..C..f"
+ _ = D.f // @pointsto func-ref-D.f "D.f"
+ _ = I.f // @pointsto func-ref-I.f "I.f"
+ var d D
+ var i I
+ _ = d.f // @pointsto func-ref-d.f "d.f"
+ _ = i.f // @pointsto func-ref-i.f "i.f"
+
+ // var objects
+ anon := func() {
+ _ = d.f // @pointsto ref-lexical-d.f "d.f"
+ }
+ _ = anon // @pointsto ref-anon "anon"
+ _ = global // @pointsto ref-global "global"
+
+ // SSA affords some local flow sensitivity.
+ var a, b int
+ var x = &a // @pointsto var-def-x-1 "x"
+ _ = x // @pointsto var-ref-x-1 "x"
+ x = &b // @pointsto var-def-x-2 "x"
+ _ = x // @pointsto var-ref-x-2 "x"
+
+ i = new(C) // @pointsto var-ref-i-C "i"
+ if i != nil {
+ i = D{} // @pointsto var-ref-i-D "i"
+ }
+ print(i) // @pointsto var-ref-i "\\bi\\b"
+
+ m := map[string]*int{"a": &a}
+ mapval, _ := m["a"] // @pointsto map-lookup,ok "m..a.."
+ _ = mapval // @pointsto mapval "mapval"
+ _ = m // @pointsto m "m"
+
+ if false {
+ panic(3) // @pointsto builtin-panic "panic"
+ }
+
+ // NB: s.f is addressable per (*ssa.Program).VarValue,
+ // but our query concerns the object, not its address.
+ s := struct{ f interface{} }{f: make(chan bool)}
+ print(s.f) // @pointsto var-ref-s-f "s.f"
+}
+
+func livecode() {} // @pointsto func-live "livecode"
+
+func deadcode() { // @pointsto func-dead "deadcode"
+ // Pointer analysis can't run on dead code.
+ var b = new(int) // @pointsto b "b"
+ _ = b
+}
+
+type I interface {
+ f()
+}
+
+type C int
+type D struct{}
+
+func (c *C) f() {}
+func (d D) f() {}
diff --git a/oracle/testdata/src/pointsto/main.golden b/oracle/testdata/src/pointsto/main.golden
new file mode 100644
index 0000000..fd68bda
--- /dev/null
+++ b/oracle/testdata/src/pointsto/main.golden
@@ -0,0 +1,96 @@
+-------- @pointsto const --------
+
+Error: pointer analysis wants an expression of reference type; got untyped float
+-------- @pointsto func-ref-main --------
+this func() may point to these objects:
+ main.main
+
+-------- @pointsto func-ref-*C.f --------
+this func() may point to these objects:
+ (*main.C).f
+
+-------- @pointsto func-ref-D.f --------
+this func() may point to these objects:
+ (main.D).f
+
+-------- @pointsto func-ref-I.f --------
+
+Error: func (main.I).f() is an interface method
+-------- @pointsto func-ref-d.f --------
+this func() may point to these objects:
+ (main.D).f
+
+-------- @pointsto func-ref-i.f --------
+
+Error: func (main.I).f() is an interface method
+-------- @pointsto ref-lexical-d.f --------
+this func() may point to these objects:
+ (main.D).f
+
+-------- @pointsto ref-anon --------
+this func() may point to these objects:
+ main.main$1
+
+-------- @pointsto ref-global --------
+this *string may point to these objects:
+ new
+
+-------- @pointsto var-def-x-1 --------
+this *int may point to these objects:
+ a
+
+-------- @pointsto var-ref-x-1 --------
+this *int may point to these objects:
+ a
+
+-------- @pointsto var-def-x-2 --------
+this *int may point to these objects:
+ b
+
+-------- @pointsto var-ref-x-2 --------
+this *int may point to these objects:
+ b
+
+-------- @pointsto var-ref-i-C --------
+this I may contain these dynamic types:
+ *C, may point to:
+ new
+
+-------- @pointsto var-ref-i-D --------
+this I may contain these dynamic types:
+ D
+
+-------- @pointsto var-ref-i --------
+this I may contain these dynamic types:
+ *C, may point to:
+ new
+ D
+
+-------- @pointsto map-lookup,ok --------
+
+Error: pointer analysis wants an expression of reference type; got (*int, bool)
+-------- @pointsto mapval --------
+this *int may point to these objects:
+ a
+
+-------- @pointsto m --------
+this map[string]*int may point to these objects:
+ makemap
+
+-------- @pointsto builtin-panic --------
+
+Error: pointer analysis wants an expression of reference type; got ()
+-------- @pointsto var-ref-s-f --------
+this interface{} may contain these dynamic types:
+ chan bool, may point to:
+ makechan
+
+-------- @pointsto func-live --------
+
+Error: pointer analysis did not find expression (dead code?)
+-------- @pointsto func-dead --------
+
+Error: pointer analysis did not find expression (dead code?)
+-------- @pointsto b --------
+
+Error: pointer analysis did not find expression (dead code?)
diff --git a/oracle/testdata/src/referrers-json/main.go b/oracle/testdata/src/referrers-json/main.go
new file mode 100644
index 0000000..f551ee0
--- /dev/null
+++ b/oracle/testdata/src/referrers-json/main.go
@@ -0,0 +1,24 @@
+package main
+
+// Tests of 'referrers' query.
+// See go.tools/oracle/oracle_test.go for explanation.
+// See referrers.golden for expected query results.
+
+import "lib"
+
+type s struct {
+ f int
+}
+
+func main() {
+ var v lib.Type = lib.Const // @referrers ref-package "lib"
+ _ = v.Method // @referrers ref-method "Method"
+ _ = v.Method
+ v++ //@referrers ref-local "v"
+ v++
+
+ _ = s{}.f // @referrers ref-field "f"
+
+ var s2 s
+ s2.f = 1
+}
diff --git a/oracle/testdata/src/referrers-json/main.golden b/oracle/testdata/src/referrers-json/main.golden
new file mode 100644
index 0000000..47a2d01
--- /dev/null
+++ b/oracle/testdata/src/referrers-json/main.golden
@@ -0,0 +1,59 @@
+-------- @referrers ref-package --------
+{
+ "mode": "referrers",
+ "referrers": {
+ "pos": "testdata/src/referrers-json/main.go:14:8",
+ "objpos": "testdata/src/referrers-json/main.go:7:8",
+ "desc": "package lib",
+ "refs": [
+ "testdata/src/referrers-json/main.go:14:8",
+ "testdata/src/referrers-json/main.go:14:19"
+ ]
+ }
+}
+-------- @referrers ref-method --------
+{
+ "mode": "referrers",
+ "referrers": {
+ "pos": "testdata/src/referrers-json/main.go:15:8",
+ "objpos": "testdata/src/lib/lib.go:5:13",
+ "desc": "func (lib.Type).Method(x *int) *int",
+ "refs": [
+ "testdata/src/imports/main.go:22:9",
+ "testdata/src/referrers-json/main.go:15:8",
+ "testdata/src/referrers-json/main.go:16:8",
+ "testdata/src/referrers/ext_test.go:10:17",
+ "testdata/src/referrers/int_test.go:7:17",
+ "testdata/src/referrers/main.go:17:8",
+ "testdata/src/referrers/main.go:18:8"
+ ]
+ }
+}
+-------- @referrers ref-local --------
+{
+ "mode": "referrers",
+ "referrers": {
+ "pos": "testdata/src/referrers-json/main.go:17:2",
+ "objpos": "testdata/src/referrers-json/main.go:14:6",
+ "desc": "var v lib.Type",
+ "refs": [
+ "testdata/src/referrers-json/main.go:15:6",
+ "testdata/src/referrers-json/main.go:16:6",
+ "testdata/src/referrers-json/main.go:17:2",
+ "testdata/src/referrers-json/main.go:18:2"
+ ]
+ }
+}
+-------- @referrers ref-field --------
+{
+ "mode": "referrers",
+ "referrers": {
+ "pos": "testdata/src/referrers-json/main.go:20:10",
+ "objpos": "testdata/src/referrers-json/main.go:10:2",
+ "desc": "field f int",
+ "refs": [
+ "testdata/src/referrers-json/main.go:20:10",
+ "testdata/src/referrers-json/main.go:23:5"
+ ]
+ }
+}
diff --git a/oracle/testdata/src/referrers/ext_test.go b/oracle/testdata/src/referrers/ext_test.go
new file mode 100644
index 0000000..35e3199
--- /dev/null
+++ b/oracle/testdata/src/referrers/ext_test.go
@@ -0,0 +1,12 @@
+package main_test
+
+import (
+ "lib"
+ renamed "referrers" // package has name "main", path "referrers", local name "renamed"
+)
+
+func _() {
+ // This reference should be found by the ref-method query.
+ _ = (lib.Type).Method // ref from external test package
+ var _ renamed.T
+}
diff --git a/oracle/testdata/src/referrers/int_test.go b/oracle/testdata/src/referrers/int_test.go
new file mode 100644
index 0000000..9102cd6
--- /dev/null
+++ b/oracle/testdata/src/referrers/int_test.go
@@ -0,0 +1,8 @@
+package main
+
+import "lib"
+
+func _() {
+ // This reference should be found by the ref-method query.
+ _ = (lib.Type).Method // ref from internal test package
+}
diff --git a/oracle/testdata/src/referrers/main.go b/oracle/testdata/src/referrers/main.go
new file mode 100644
index 0000000..36cdb7a
--- /dev/null
+++ b/oracle/testdata/src/referrers/main.go
@@ -0,0 +1,26 @@
+package main // @referrers package-decl "main"
+
+// Tests of 'referrers' query.
+// See go.tools/oracle/oracle_test.go for explanation.
+// See referrers.golden for expected query results.
+
+import "lib"
+
+type s struct { // @referrers type " s "
+ f int
+}
+
+type T int
+
+func main() {
+ var v lib.Type = lib.Const // @referrers ref-package "lib"
+ _ = v.Method // @referrers ref-method "Method"
+ _ = v.Method
+ v++ //@referrers ref-local "v"
+ v++
+
+ _ = s{}.f // @referrers ref-field "f"
+
+ var s2 s
+ s2.f = 1
+}
diff --git a/oracle/testdata/src/referrers/main.golden b/oracle/testdata/src/referrers/main.golden
new file mode 100644
index 0000000..1f04be5
--- /dev/null
+++ b/oracle/testdata/src/referrers/main.golden
@@ -0,0 +1,38 @@
+-------- @referrers package-decl --------
+1 references to package main ("referrers")
+ var _ renamed.T
+
+-------- @referrers type --------
+2 references to type s struct{f int}
+ _ = s{}.f // @referrers ref-field "f"
+ var s2 s
+
+-------- @referrers ref-package --------
+4 references to package lib
+ _ = (lib.Type).Method // ref from external test package
+ _ = (lib.Type).Method // ref from internal test package
+ var v lib.Type = lib.Const // @referrers ref-package "lib"
+ var v lib.Type = lib.Const // @referrers ref-package "lib"
+
+-------- @referrers ref-method --------
+7 references to func (lib.Type).Method(x *int) *int
+ p := t.Method(&a) // @describe ref-method "Method"
+ _ = v.Method // @referrers ref-method "Method"
+ _ = v.Method
+ _ = (lib.Type).Method // ref from external test package
+ _ = (lib.Type).Method // ref from internal test package
+ _ = v.Method // @referrers ref-method "Method"
+ _ = v.Method
+
+-------- @referrers ref-local --------
+4 references to var v lib.Type
+ _ = v.Method // @referrers ref-method "Method"
+ _ = v.Method
+ v++ //@referrers ref-local "v"
+ v++
+
+-------- @referrers ref-field --------
+2 references to field f int
+ _ = s{}.f // @referrers ref-field "f"
+ s2.f = 1
+
diff --git a/oracle/testdata/src/reflection/main.go b/oracle/testdata/src/reflection/main.go
new file mode 100644
index 0000000..392643b
--- /dev/null
+++ b/oracle/testdata/src/reflection/main.go
@@ -0,0 +1,30 @@
+package main
+
+// This is a test of 'pointsto', but we split it into a separate file
+// so that pointsto.go doesn't have to import "reflect" each time.
+
+import "reflect"
+
+var a int
+var b bool
+
+func main() {
+ m := make(map[*int]*bool)
+ m[&a] = &b
+
+ mrv := reflect.ValueOf(m)
+ if a > 0 {
+ mrv = reflect.ValueOf(&b)
+ }
+ if a > 0 {
+ mrv = reflect.ValueOf(&a)
+ }
+
+ _ = mrv // @pointsto mrv "mrv"
+ p1 := mrv.Interface() // @pointsto p1 "p1"
+ p2 := mrv.MapKeys() // @pointsto p2 "p2"
+ p3 := p2[0] // @pointsto p3 "p3"
+ p4 := reflect.TypeOf(p1) // @pointsto p4 "p4"
+
+ _, _, _, _ = p1, p2, p3, p4
+}
diff --git a/oracle/testdata/src/reflection/main.golden b/oracle/testdata/src/reflection/main.golden
new file mode 100644
index 0000000..6190c06
--- /dev/null
+++ b/oracle/testdata/src/reflection/main.golden
@@ -0,0 +1,34 @@
+-------- @pointsto mrv --------
+this reflect.Value may contain these dynamic types:
+ *bool, may point to:
+ main.b
+ *int, may point to:
+ main.a
+ map[*int]*bool, may point to:
+ makemap
+
+-------- @pointsto p1 --------
+this interface{} may contain these dynamic types:
+ *bool, may point to:
+ main.b
+ *int, may point to:
+ main.a
+ map[*int]*bool, may point to:
+ makemap
+
+-------- @pointsto p2 --------
+this []reflect.Value may point to these objects:
+ <alloc in (reflect.Value).MapKeys>
+
+-------- @pointsto p3 --------
+this reflect.Value may contain these dynamic types:
+ *int, may point to:
+ main.a
+
+-------- @pointsto p4 --------
+this reflect.Type may contain these dynamic types:
+ *reflect.rtype, may point to:
+ *bool
+ *int
+ map[*int]*bool
+
diff --git a/oracle/testdata/src/what-json/main.go b/oracle/testdata/src/what-json/main.go
new file mode 100644
index 0000000..8d578c7
--- /dev/null
+++ b/oracle/testdata/src/what-json/main.go
@@ -0,0 +1,9 @@
+package main
+
+// Tests of 'what' queries, -format=json.
+// See go.tools/oracle/oracle_test.go for explanation.
+// See what-json.golden for expected query results.
+
+func main() {
+ f() // @what call "f"
+}
diff --git a/oracle/testdata/src/what-json/main.golden b/oracle/testdata/src/what-json/main.golden
new file mode 100644
index 0000000..9a31190
--- /dev/null
+++ b/oracle/testdata/src/what-json/main.golden
@@ -0,0 +1,51 @@
+-------- @what call --------
+{
+ "mode": "what",
+ "what": {
+ "enclosing": [
+ {
+ "desc": "identifier",
+ "start": 179,
+ "end": 180
+ },
+ {
+ "desc": "function call (or conversion)",
+ "start": 179,
+ "end": 182
+ },
+ {
+ "desc": "expression statement",
+ "start": 179,
+ "end": 182
+ },
+ {
+ "desc": "block",
+ "start": 176,
+ "end": 202
+ },
+ {
+ "desc": "function declaration",
+ "start": 164,
+ "end": 202
+ },
+ {
+ "desc": "source file",
+ "start": 0,
+ "end": 202
+ }
+ ],
+ "modes": [
+ "callees",
+ "callers",
+ "callstack",
+ "definition",
+ "describe",
+ "freevars",
+ "implements",
+ "pointsto",
+ "referrers"
+ ],
+ "srcdir": "testdata/src",
+ "importpath": "what-json"
+ }
+}
diff --git a/oracle/testdata/src/what/main.go b/oracle/testdata/src/what/main.go
new file mode 100644
index 0000000..38e9dc7
--- /dev/null
+++ b/oracle/testdata/src/what/main.go
@@ -0,0 +1,11 @@
+package main // @what pkgdecl "main"
+
+// Tests of 'what' queries.
+// See go.tools/oracle/oracle_test.go for explanation.
+// See what.golden for expected query results.
+
+func main() {
+ f() // @what call "f"
+ var ch chan int // @what var "var"
+ <-ch // @what recv "ch"
+}
diff --git a/oracle/testdata/src/what/main.golden b/oracle/testdata/src/what/main.golden
new file mode 100644
index 0000000..56b97dd
--- /dev/null
+++ b/oracle/testdata/src/what/main.golden
@@ -0,0 +1,39 @@
+-------- @what pkgdecl --------
+identifier
+source file
+modes: [definition describe freevars implements pointsto referrers]
+srcdir: testdata/src
+import path: what
+
+-------- @what call --------
+identifier
+function call (or conversion)
+expression statement
+block
+function declaration
+source file
+modes: [callees callers callstack definition describe freevars implements pointsto referrers]
+srcdir: testdata/src
+import path: what
+
+-------- @what var --------
+variable declaration
+variable declaration statement
+block
+function declaration
+source file
+modes: [callers callstack describe freevars pointsto]
+srcdir: testdata/src
+import path: what
+
+-------- @what recv --------
+identifier
+unary <- operation
+expression statement
+block
+function declaration
+source file
+modes: [callers callstack definition describe freevars implements peers pointsto referrers]
+srcdir: testdata/src
+import path: what
+
diff --git a/oracle/testdata/src/whicherrs/main.go b/oracle/testdata/src/whicherrs/main.go
new file mode 100644
index 0000000..27fe6b5
--- /dev/null
+++ b/oracle/testdata/src/whicherrs/main.go
@@ -0,0 +1,27 @@
+package main
+
+type errType string
+
+const constErr errType = "blah"
+
+func (et errType) Error() string {
+ return string(et)
+}
+
+var errVar error = errType("foo")
+
+func genErr(i int) error {
+ switch i {
+ case 0:
+ return constErr
+ case 1:
+ return errVar
+ default:
+ return nil
+ }
+}
+
+func main() {
+ err := genErr(0) // @whicherrs localerrs "err"
+ _ = err
+}
diff --git a/oracle/testdata/src/whicherrs/main.golden b/oracle/testdata/src/whicherrs/main.golden
new file mode 100644
index 0000000..1118e0a
--- /dev/null
+++ b/oracle/testdata/src/whicherrs/main.golden
@@ -0,0 +1,8 @@
+-------- @whicherrs localerrs --------
+this error may point to these globals:
+ errVar
+this error may contain these constants:
+ constErr
+this error may contain these dynamic types:
+ errType
+
diff --git a/oracle/what.go b/oracle/what.go
new file mode 100644
index 0000000..5a5c0cf
--- /dev/null
+++ b/oracle/what.go
@@ -0,0 +1,210 @@
+// 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 oracle
+
+import (
+ "fmt"
+ "go/ast"
+ "go/build"
+ "go/token"
+ "os"
+ "path/filepath"
+ "sort"
+ "strings"
+
+ "golang.org/x/tools/go/ast/astutil"
+ "golang.org/x/tools/oracle/serial"
+)
+
+// what reports all the information about the query selection that can be
+// obtained from parsing only its containing source file.
+// It is intended to be a very low-latency query callable from GUI
+// tools, e.g. to populate a menu of options of slower queries about
+// the selected location.
+//
+func what(q *Query) error {
+ qpos, err := fastQueryPos(q.Pos)
+ if err != nil {
+ return err
+ }
+ q.Fset = qpos.fset
+
+ // (ignore errors)
+ srcdir, importPath, _ := guessImportPath(q.Fset.File(qpos.start).Name(), q.Build)
+
+ // Determine which query modes are applicable to the selection.
+ enable := map[string]bool{
+ "describe": true, // any syntax; always enabled
+ }
+
+ if qpos.end > qpos.start {
+ enable["freevars"] = true // nonempty selection?
+ }
+
+ for _, n := range qpos.path {
+ switch n := n.(type) {
+ case *ast.Ident:
+ enable["definition"] = true
+ enable["referrers"] = true
+ enable["implements"] = true
+ case *ast.CallExpr:
+ enable["callees"] = true
+ case *ast.FuncDecl:
+ enable["callers"] = true
+ enable["callstack"] = true
+ case *ast.SendStmt:
+ enable["peers"] = true
+ case *ast.UnaryExpr:
+ if n.Op == token.ARROW {
+ enable["peers"] = true
+ }
+ }
+
+ // For implements, we approximate findInterestingNode.
+ if _, ok := enable["implements"]; !ok {
+ switch n.(type) {
+ case *ast.ArrayType,
+ *ast.StructType,
+ *ast.FuncType,
+ *ast.InterfaceType,
+ *ast.MapType,
+ *ast.ChanType:
+ enable["implements"] = true
+ }
+ }
+
+ // For pointsto, we approximate findInterestingNode.
+ if _, ok := enable["pointsto"]; !ok {
+ switch n.(type) {
+ case ast.Stmt,
+ *ast.ArrayType,
+ *ast.StructType,
+ *ast.FuncType,
+ *ast.InterfaceType,
+ *ast.MapType,
+ *ast.ChanType:
+ enable["pointsto"] = false // not an expr
+
+ case ast.Expr, ast.Decl, *ast.ValueSpec:
+ enable["pointsto"] = true // an expr, maybe
+
+ default:
+ // Comment, Field, KeyValueExpr, etc: ascend.
+ }
+ }
+ }
+
+ // If we don't have an exact selection, disable modes that need one.
+ if !qpos.exact {
+ enable["callees"] = false
+ enable["pointsto"] = false
+ enable["whicherrs"] = false
+ enable["describe"] = false
+ }
+
+ var modes []string
+ for mode := range enable {
+ modes = append(modes, mode)
+ }
+ sort.Strings(modes)
+
+ q.result = &whatResult{
+ path: qpos.path,
+ srcdir: srcdir,
+ importPath: importPath,
+ modes: modes,
+ }
+ return nil
+}
+
+// guessImportPath finds the package containing filename, and returns
+// its source directory (an element of $GOPATH) and its import path
+// relative to it.
+//
+// TODO(adonovan): what about _test.go files that are not part of the
+// package?
+//
+func guessImportPath(filename string, buildContext *build.Context) (srcdir, importPath string, err error) {
+ absFile, err := filepath.Abs(filename)
+ if err != nil {
+ err = fmt.Errorf("can't form absolute path of %s", filename)
+ return
+ }
+ absFileDir := segments(filepath.Dir(absFile))
+
+ // Find the innermost directory in $GOPATH that encloses filename.
+ minD := 1024
+ for _, gopathDir := range buildContext.SrcDirs() {
+ absDir, err := filepath.Abs(gopathDir)
+ if err != nil {
+ continue // e.g. non-existent dir on $GOPATH
+ }
+ d := prefixLen(segments(absDir), absFileDir)
+ // If there are multiple matches,
+ // prefer the innermost enclosing directory
+ // (smallest d).
+ if d >= 0 && d < minD {
+ minD = d
+ srcdir = gopathDir
+ importPath = strings.Join(absFileDir[len(absFileDir)-minD:], string(os.PathSeparator))
+ }
+ }
+ if srcdir == "" {
+ err = fmt.Errorf("directory %s is not beneath any of these GOROOT/GOPATH directories: %s",
+ filepath.Dir(absFile), strings.Join(buildContext.SrcDirs(), ", "))
+ }
+ return
+}
+
+func segments(path string) []string {
+ return strings.Split(path, string(os.PathSeparator))
+}
+
+// prefixLen returns the length of the remainder of y if x is a prefix
+// of y, a negative number otherwise.
+func prefixLen(x, y []string) int {
+ d := len(y) - len(x)
+ if d >= 0 {
+ for i := range x {
+ if y[i] != x[i] {
+ return -1 // not a prefix
+ }
+ }
+ }
+ return d
+}
+
+type whatResult struct {
+ path []ast.Node
+ modes []string
+ srcdir string
+ importPath string
+}
+
+func (r *whatResult) display(printf printfFunc) {
+ for _, n := range r.path {
+ printf(n, "%s", astutil.NodeDescription(n))
+ }
+ printf(nil, "modes: %s", r.modes)
+ printf(nil, "srcdir: %s", r.srcdir)
+ printf(nil, "import path: %s", r.importPath)
+}
+
+func (r *whatResult) toSerial(res *serial.Result, fset *token.FileSet) {
+ var enclosing []serial.SyntaxNode
+ for _, n := range r.path {
+ enclosing = append(enclosing, serial.SyntaxNode{
+ Description: astutil.NodeDescription(n),
+ Start: fset.Position(n.Pos()).Offset,
+ End: fset.Position(n.End()).Offset,
+ })
+ }
+ res.What = &serial.What{
+ Modes: r.modes,
+ SrcDir: r.srcdir,
+ ImportPath: r.importPath,
+ Enclosing: enclosing,
+ }
+}
diff --git a/oracle/whicherrs.go b/oracle/whicherrs.go
new file mode 100644
index 0000000..aaa6068
--- /dev/null
+++ b/oracle/whicherrs.go
@@ -0,0 +1,326 @@
+// 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 oracle
+
+import (
+ "fmt"
+ "go/ast"
+ "go/token"
+ "sort"
+
+ "golang.org/x/tools/go/ast/astutil"
+ "golang.org/x/tools/go/loader"
+ "golang.org/x/tools/go/ssa"
+ "golang.org/x/tools/go/ssa/ssautil"
+ "golang.org/x/tools/go/types"
+ "golang.org/x/tools/oracle/serial"
+)
+
+var builtinErrorType = types.Universe.Lookup("error").Type()
+
+// whicherrs takes an position to an error and tries to find all types, constants
+// and global value which a given error can point to and which can be checked from the
+// scope where the error lives.
+// In short, it returns a list of things that can be checked against in order to handle
+// an error properly.
+//
+// TODO(dmorsing): figure out if fields in errors like *os.PathError.Err
+// can be queried recursively somehow.
+func whicherrs(q *Query) error {
+ lconf := loader.Config{Build: q.Build}
+
+ if err := setPTAScope(&lconf, q.Scope); err != nil {
+ return err
+ }
+
+ // Load/parse/type-check the program.
+ lprog, err := lconf.Load()
+ if err != nil {
+ return err
+ }
+ q.Fset = lprog.Fset
+
+ qpos, err := parseQueryPos(lprog, q.Pos, true) // needs exact pos
+ if err != nil {
+ return err
+ }
+
+ prog := ssautil.CreateProgram(lprog, ssa.GlobalDebug)
+
+ ptaConfig, err := setupPTA(prog, lprog, q.PTALog, q.Reflection)
+ if err != nil {
+ return err
+ }
+
+ path, action := findInterestingNode(qpos.info, qpos.path)
+ if action != actionExpr {
+ return fmt.Errorf("whicherrs wants an expression; got %s",
+ astutil.NodeDescription(qpos.path[0]))
+ }
+ var expr ast.Expr
+ var obj types.Object
+ switch n := path[0].(type) {
+ case *ast.ValueSpec:
+ // ambiguous ValueSpec containing multiple names
+ return fmt.Errorf("multiple value specification")
+ case *ast.Ident:
+ obj = qpos.info.ObjectOf(n)
+ expr = n
+ case ast.Expr:
+ expr = n
+ default:
+ return fmt.Errorf("unexpected AST for expr: %T", n)
+ }
+
+ typ := qpos.info.TypeOf(expr)
+ if !types.Identical(typ, builtinErrorType) {
+ return fmt.Errorf("selection is not an expression of type 'error'")
+ }
+ // Determine the ssa.Value for the expression.
+ var value ssa.Value
+ if obj != nil {
+ // def/ref of func/var object
+ value, _, err = ssaValueForIdent(prog, qpos.info, obj, path)
+ } else {
+ value, _, err = ssaValueForExpr(prog, qpos.info, path)
+ }
+ if err != nil {
+ return err // e.g. trivially dead code
+ }
+
+ // Defer SSA construction till after errors are reported.
+ prog.BuildAll()
+
+ globals := findVisibleErrs(prog, qpos)
+ constants := findVisibleConsts(prog, qpos)
+
+ res := &whicherrsResult{
+ qpos: qpos,
+ errpos: expr.Pos(),
+ }
+
+ // TODO(adonovan): the following code is heavily duplicated
+ // w.r.t. "pointsto". Refactor?
+
+ // Find the instruction which initialized the
+ // global error. If more than one instruction has stored to the global
+ // remove the global from the set of values that we want to query.
+ allFuncs := ssautil.AllFunctions(prog)
+ for fn := range allFuncs {
+ for _, b := range fn.Blocks {
+ for _, instr := range b.Instrs {
+ store, ok := instr.(*ssa.Store)
+ if !ok {
+ continue
+ }
+ gval, ok := store.Addr.(*ssa.Global)
+ if !ok {
+ continue
+ }
+ gbl, ok := globals[gval]
+ if !ok {
+ continue
+ }
+ // we already found a store to this global
+ // The normal error define is just one store in the init
+ // so we just remove this global from the set we want to query
+ if gbl != nil {
+ delete(globals, gval)
+ }
+ globals[gval] = store.Val
+ }
+ }
+ }
+
+ ptaConfig.AddQuery(value)
+ for _, v := range globals {
+ ptaConfig.AddQuery(v)
+ }
+
+ ptares := ptrAnalysis(ptaConfig)
+ valueptr := ptares.Queries[value]
+ for g, v := range globals {
+ ptr, ok := ptares.Queries[v]
+ if !ok {
+ continue
+ }
+ if !ptr.MayAlias(valueptr) {
+ continue
+ }
+ res.globals = append(res.globals, g)
+ }
+ pts := valueptr.PointsTo()
+ dedup := make(map[*ssa.NamedConst]bool)
+ for _, label := range pts.Labels() {
+ // These values are either MakeInterfaces or reflect
+ // generated interfaces. For the purposes of this
+ // analysis, we don't care about reflect generated ones
+ makeiface, ok := label.Value().(*ssa.MakeInterface)
+ if !ok {
+ continue
+ }
+ constval, ok := makeiface.X.(*ssa.Const)
+ if !ok {
+ continue
+ }
+ c := constants[*constval]
+ if c != nil && !dedup[c] {
+ dedup[c] = true
+ res.consts = append(res.consts, c)
+ }
+ }
+ concs := pts.DynamicTypes()
+ concs.Iterate(func(conc types.Type, _ interface{}) {
+ // go/types is a bit annoying here.
+ // We want to find all the types that we can
+ // typeswitch or assert to. This means finding out
+ // if the type pointed to can be seen by us.
+ //
+ // For the purposes of this analysis, the type is always
+ // either a Named type or a pointer to one.
+ // There are cases where error can be implemented
+ // by unnamed types, but in that case, we can't assert to
+ // it, so we don't care about it for this analysis.
+ var name *types.TypeName
+ switch t := conc.(type) {
+ case *types.Pointer:
+ named, ok := t.Elem().(*types.Named)
+ if !ok {
+ return
+ }
+ name = named.Obj()
+ case *types.Named:
+ name = t.Obj()
+ default:
+ return
+ }
+ if !isAccessibleFrom(name, qpos.info.Pkg) {
+ return
+ }
+ res.types = append(res.types, &errorType{conc, name})
+ })
+ sort.Sort(membersByPosAndString(res.globals))
+ sort.Sort(membersByPosAndString(res.consts))
+ sort.Sort(sorterrorType(res.types))
+
+ q.result = res
+ return nil
+}
+
+// findVisibleErrs returns a mapping from each package-level variable of type "error" to nil.
+func findVisibleErrs(prog *ssa.Program, qpos *queryPos) map[*ssa.Global]ssa.Value {
+ globals := make(map[*ssa.Global]ssa.Value)
+ for _, pkg := range prog.AllPackages() {
+ for _, mem := range pkg.Members {
+ gbl, ok := mem.(*ssa.Global)
+ if !ok {
+ continue
+ }
+ gbltype := gbl.Type()
+ // globals are always pointers
+ if !types.Identical(deref(gbltype), builtinErrorType) {
+ continue
+ }
+ if !isAccessibleFrom(gbl.Object(), qpos.info.Pkg) {
+ continue
+ }
+ globals[gbl] = nil
+ }
+ }
+ return globals
+}
+
+// findVisibleConsts returns a mapping from each package-level constant assignable to type "error", to nil.
+func findVisibleConsts(prog *ssa.Program, qpos *queryPos) map[ssa.Const]*ssa.NamedConst {
+ constants := make(map[ssa.Const]*ssa.NamedConst)
+ for _, pkg := range prog.AllPackages() {
+ for _, mem := range pkg.Members {
+ obj, ok := mem.(*ssa.NamedConst)
+ if !ok {
+ continue
+ }
+ consttype := obj.Type()
+ if !types.AssignableTo(consttype, builtinErrorType) {
+ continue
+ }
+ if !isAccessibleFrom(obj.Object(), qpos.info.Pkg) {
+ continue
+ }
+ constants[*obj.Value] = obj
+ }
+ }
+
+ return constants
+}
+
+type membersByPosAndString []ssa.Member
+
+func (a membersByPosAndString) Len() int { return len(a) }
+func (a membersByPosAndString) Less(i, j int) bool {
+ cmp := a[i].Pos() - a[j].Pos()
+ return cmp < 0 || cmp == 0 && a[i].String() < a[j].String()
+}
+func (a membersByPosAndString) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
+
+type sorterrorType []*errorType
+
+func (a sorterrorType) Len() int { return len(a) }
+func (a sorterrorType) Less(i, j int) bool {
+ cmp := a[i].obj.Pos() - a[j].obj.Pos()
+ return cmp < 0 || cmp == 0 && a[i].typ.String() < a[j].typ.String()
+}
+func (a sorterrorType) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
+
+type errorType struct {
+ typ types.Type // concrete type N or *N that implements error
+ obj *types.TypeName // the named type N
+}
+
+type whicherrsResult struct {
+ qpos *queryPos
+ errpos token.Pos
+ globals []ssa.Member
+ consts []ssa.Member
+ types []*errorType
+}
+
+func (r *whicherrsResult) display(printf printfFunc) {
+ if len(r.globals) > 0 {
+ printf(r.qpos, "this error may point to these globals:")
+ for _, g := range r.globals {
+ printf(g.Pos(), "\t%s", g.RelString(r.qpos.info.Pkg))
+ }
+ }
+ if len(r.consts) > 0 {
+ printf(r.qpos, "this error may contain these constants:")
+ for _, c := range r.consts {
+ printf(c.Pos(), "\t%s", c.RelString(r.qpos.info.Pkg))
+ }
+ }
+ if len(r.types) > 0 {
+ printf(r.qpos, "this error may contain these dynamic types:")
+ for _, t := range r.types {
+ printf(t.obj.Pos(), "\t%s", r.qpos.typeString(t.typ))
+ }
+ }
+}
+
+func (r *whicherrsResult) toSerial(res *serial.Result, fset *token.FileSet) {
+ we := &serial.WhichErrs{}
+ we.ErrPos = fset.Position(r.errpos).String()
+ for _, g := range r.globals {
+ we.Globals = append(we.Globals, fset.Position(g.Pos()).String())
+ }
+ for _, c := range r.consts {
+ we.Constants = append(we.Constants, fset.Position(c.Pos()).String())
+ }
+ for _, t := range r.types {
+ var et serial.WhichErrsType
+ et.Type = r.qpos.typeString(t.typ)
+ et.Position = fset.Position(t.obj.Pos()).String()
+ we.Types = append(we.Types, et)
+ }
+ res.WhichErrs = we
+}
diff --git a/playground/appengine.go b/playground/appengine.go
new file mode 100644
index 0000000..073b419
--- /dev/null
+++ b/playground/appengine.go
@@ -0,0 +1,22 @@
+// 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 playground
+
+import (
+ "net/http"
+
+ "appengine"
+ "appengine/urlfetch"
+)
+
+func client(r *http.Request) *http.Client {
+ return urlfetch.Client(appengine.NewContext(r))
+}
+
+func report(r *http.Request, err error) {
+ appengine.NewContext(r).Errorf("%v", err)
+}
diff --git a/playground/common.go b/playground/common.go
new file mode 100644
index 0000000..3ffce88
--- /dev/null
+++ b/playground/common.go
@@ -0,0 +1,46 @@
+// 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 playground registers HTTP handlers at "/compile" and "/share" that
+// proxy requests to the golang.org playground service.
+// This package may be used unaltered on App Engine.
+package playground // import "golang.org/x/tools/playground"
+
+import (
+ "bytes"
+ "fmt"
+ "io"
+ "net/http"
+)
+
+const baseURL = "http://play.golang.org"
+
+func init() {
+ http.HandleFunc("/compile", bounce)
+ http.HandleFunc("/share", bounce)
+}
+
+func bounce(w http.ResponseWriter, r *http.Request) {
+ b := new(bytes.Buffer)
+ if err := passThru(b, r); err != nil {
+ http.Error(w, "Server error.", http.StatusInternalServerError)
+ report(r, err)
+ return
+ }
+ io.Copy(w, b)
+}
+
+func passThru(w io.Writer, req *http.Request) error {
+ defer req.Body.Close()
+ url := baseURL + req.URL.Path
+ r, err := client(req).Post(url, req.Header.Get("Content-type"), req.Body)
+ if err != nil {
+ return fmt.Errorf("making POST request: %v", err)
+ }
+ defer r.Body.Close()
+ if _, err := io.Copy(w, r.Body); err != nil {
+ return fmt.Errorf("copying response Body: %v", err)
+ }
+ return nil
+}
diff --git a/playground/local.go b/playground/local.go
new file mode 100644
index 0000000..b114b87
--- /dev/null
+++ b/playground/local.go
@@ -0,0 +1,20 @@
+// 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 playground
+
+import (
+ "log"
+ "net/http"
+)
+
+func client(r *http.Request) *http.Client {
+ return http.DefaultClient
+}
+
+func report(r *http.Request, err error) {
+ log.Println(err)
+}
diff --git a/playground/socket/socket.go b/playground/socket/socket.go
new file mode 100644
index 0000000..76527ae
--- /dev/null
+++ b/playground/socket/socket.go
@@ -0,0 +1,474 @@
+// 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 socket implements an WebSocket-based playground backend.
+// Clients connect to a websocket handler and send run/kill commands, and
+// the server sends the output and exit status of the running processes.
+// Multiple clients running multiple processes may be served concurrently.
+// The wire format is JSON and is described by the Message type.
+//
+// This will not run on App Engine as WebSockets are not supported there.
+package socket // import "golang.org/x/tools/playground/socket"
+
+import (
+ "bytes"
+ "encoding/json"
+ "errors"
+ "go/parser"
+ "go/token"
+ "io"
+ "io/ioutil"
+ "log"
+ "net"
+ "net/http"
+ "net/url"
+ "os"
+ "os/exec"
+ "path/filepath"
+ "runtime"
+ "strconv"
+ "strings"
+ "sync"
+ "time"
+ "unicode/utf8"
+
+ "golang.org/x/net/websocket"
+)
+
+// RunScripts specifies whether the socket handler should execute shell scripts
+// (snippets that start with a shebang).
+var RunScripts = true
+
+// Environ provides an environment when a binary, such as the go tool, is
+// invoked.
+var Environ func() []string = os.Environ
+
+const (
+ // The maximum number of messages to send per session (avoid flooding).
+ msgLimit = 1000
+
+ // Batch messages sent in this interval and send as a single message.
+ msgDelay = 10 * time.Millisecond
+)
+
+// Message is the wire format for the websocket connection to the browser.
+// It is used for both sending output messages and receiving commands, as
+// distinguished by the Kind field.
+type Message struct {
+ Id string // client-provided unique id for the process
+ Kind string // in: "run", "kill" out: "stdout", "stderr", "end"
+ Body string
+ Options *Options `json:",omitempty"`
+}
+
+// Options specify additional message options.
+type Options struct {
+ Race bool // use -race flag when building code (for "run" only)
+}
+
+// NewHandler returns a websocket server which checks the origin of requests.
+func NewHandler(origin *url.URL) websocket.Server {
+ return websocket.Server{
+ Config: websocket.Config{Origin: origin},
+ Handshake: handshake,
+ Handler: websocket.Handler(socketHandler),
+ }
+}
+
+// handshake checks the origin of a request during the websocket handshake.
+func handshake(c *websocket.Config, req *http.Request) error {
+ o, err := websocket.Origin(c, req)
+ if err != nil {
+ log.Println("bad websocket origin:", err)
+ return websocket.ErrBadWebSocketOrigin
+ }
+ _, port, err := net.SplitHostPort(c.Origin.Host)
+ if err != nil {
+ log.Println("bad websocket origin:", err)
+ return websocket.ErrBadWebSocketOrigin
+ }
+ ok := c.Origin.Scheme == o.Scheme && (c.Origin.Host == o.Host || c.Origin.Host == net.JoinHostPort(o.Host, port))
+ if !ok {
+ log.Println("bad websocket origin:", o)
+ return websocket.ErrBadWebSocketOrigin
+ }
+ log.Println("accepting connection from:", req.RemoteAddr)
+ return nil
+}
+
+// socketHandler handles the websocket connection for a given present session.
+// It handles transcoding Messages to and from JSON format, and starting
+// and killing processes.
+func socketHandler(c *websocket.Conn) {
+ in, out := make(chan *Message), make(chan *Message)
+ errc := make(chan error, 1)
+
+ // Decode messages from client and send to the in channel.
+ go func() {
+ dec := json.NewDecoder(c)
+ for {
+ var m Message
+ if err := dec.Decode(&m); err != nil {
+ errc <- err
+ return
+ }
+ in <- &m
+ }
+ }()
+
+ // Receive messages from the out channel and encode to the client.
+ go func() {
+ enc := json.NewEncoder(c)
+ for m := range out {
+ if err := enc.Encode(m); err != nil {
+ errc <- err
+ return
+ }
+ }
+ }()
+
+ // Start and kill processes and handle errors.
+ proc := make(map[string]*process)
+ for {
+ select {
+ case m := <-in:
+ switch m.Kind {
+ case "run":
+ log.Println("running snippet from:", c.Request().RemoteAddr)
+ proc[m.Id].Kill()
+ lOut := limiter(in, out)
+ proc[m.Id] = startProcess(m.Id, m.Body, lOut, m.Options)
+ case "kill":
+ proc[m.Id].Kill()
+ }
+ case err := <-errc:
+ if err != io.EOF {
+ // A encode or decode has failed; bail.
+ log.Println(err)
+ }
+ // Shut down any running processes.
+ for _, p := range proc {
+ p.Kill()
+ }
+ return
+ }
+ }
+}
+
+// process represents a running process.
+type process struct {
+ id string
+ out chan<- *Message
+ done chan struct{} // closed when wait completes
+ run *exec.Cmd
+ bin string
+}
+
+// startProcess builds and runs the given program, sending its output
+// and end event as Messages on the provided channel.
+func startProcess(id, body string, out chan<- *Message, opt *Options) *process {
+ p := &process{
+ id: id,
+ out: out,
+ done: make(chan struct{}),
+ }
+ var err error
+ if path, args := shebang(body); path != "" {
+ if RunScripts {
+ err = p.startProcess(path, args, body)
+ } else {
+ err = errors.New("script execution is not allowed")
+ }
+ } else {
+ err = p.start(body, opt)
+ }
+ if err != nil {
+ p.end(err)
+ return nil
+ }
+ go p.wait()
+ return p
+}
+
+// Kill stops the process if it is running and waits for it to exit.
+func (p *process) Kill() {
+ if p == nil {
+ return
+ }
+ p.run.Process.Kill()
+ <-p.done // block until process exits
+}
+
+// shebang looks for a shebang ('#!') at the beginning of the passed string.
+// If found, it returns the path and args after the shebang.
+// args includes the command as args[0].
+func shebang(body string) (path string, args []string) {
+ body = strings.TrimSpace(body)
+ if !strings.HasPrefix(body, "#!") {
+ return "", nil
+ }
+ if i := strings.Index(body, "\n"); i >= 0 {
+ body = body[:i]
+ }
+ fs := strings.Fields(body[2:])
+ return fs[0], fs
+}
+
+// startProcess starts a given program given its path and passing the given body
+// to the command standard input.
+func (p *process) startProcess(path string, args []string, body string) error {
+ cmd := &exec.Cmd{
+ Path: path,
+ Args: args,
+ Stdin: strings.NewReader(body),
+ Stdout: &messageWriter{id: p.id, kind: "stdout", out: p.out},
+ Stderr: &messageWriter{id: p.id, kind: "stderr", out: p.out},
+ }
+ if err := cmd.Start(); err != nil {
+ return err
+ }
+ p.run = cmd
+ return nil
+}
+
+// start builds and starts the given program, sending its output to p.out,
+// and stores the running *exec.Cmd in the run field.
+func (p *process) start(body string, opt *Options) error {
+ // We "go build" and then exec the binary so that the
+ // resultant *exec.Cmd is a handle to the user's program
+ // (rather than the go tool process).
+ // This makes Kill work.
+
+ bin := filepath.Join(tmpdir, "compile"+strconv.Itoa(<-uniq))
+ src := bin + ".go"
+ if runtime.GOOS == "windows" {
+ bin += ".exe"
+ }
+
+ // write body to x.go
+ defer os.Remove(src)
+ err := ioutil.WriteFile(src, []byte(body), 0666)
+ if err != nil {
+ return err
+ }
+
+ // build x.go, creating x
+ p.bin = bin // to be removed by p.end
+ dir, file := filepath.Split(src)
+ args := []string{"go", "build", "-tags", "OMIT"}
+ if opt != nil && opt.Race {
+ p.out <- &Message{
+ Id: p.id, Kind: "stderr",
+ Body: "Running with race detector.\n",
+ }
+ args = append(args, "-race")
+ }
+ args = append(args, "-o", bin, file)
+ cmd := p.cmd(dir, args...)
+ cmd.Stdout = cmd.Stderr // send compiler output to stderr
+ if err := cmd.Run(); err != nil {
+ return err
+ }
+
+ // run x
+ if isNacl() {
+ cmd, err = p.naclCmd(bin)
+ if err != nil {
+ return err
+ }
+ } else {
+ cmd = p.cmd("", bin)
+ }
+ if opt != nil && opt.Race {
+ cmd.Env = append(cmd.Env, "GOMAXPROCS=2")
+ }
+ if err := cmd.Start(); err != nil {
+ // If we failed to exec, that might be because they built
+ // a non-main package instead of an executable.
+ // Check and report that.
+ if name, err := packageName(body); err == nil && name != "main" {
+ return errors.New(`executable programs must use "package main"`)
+ }
+ return err
+ }
+ p.run = cmd
+ return nil
+}
+
+// wait waits for the running process to complete
+// and sends its error state to the client.
+func (p *process) wait() {
+ p.end(p.run.Wait())
+ close(p.done) // unblock waiting Kill calls
+}
+
+// end sends an "end" message to the client, containing the process id and the
+// given error value. It also removes the binary.
+func (p *process) end(err error) {
+ if p.bin != "" {
+ defer os.Remove(p.bin)
+ }
+ m := &Message{Id: p.id, Kind: "end"}
+ if err != nil {
+ m.Body = err.Error()
+ }
+ // Wait for any outstanding reads to finish (potential race here).
+ time.AfterFunc(4*msgDelay, func() { p.out <- m })
+}
+
+// cmd builds an *exec.Cmd that writes its standard output and error to the
+// process' output channel.
+func (p *process) cmd(dir string, args ...string) *exec.Cmd {
+ cmd := exec.Command(args[0], args[1:]...)
+ cmd.Dir = dir
+ cmd.Env = Environ()
+ cmd.Stdout = &messageWriter{id: p.id, kind: "stdout", out: p.out}
+ cmd.Stderr = &messageWriter{id: p.id, kind: "stderr", out: p.out}
+ return cmd
+}
+
+func isNacl() bool {
+ for _, v := range append(Environ(), os.Environ()...) {
+ if v == "GOOS=nacl" {
+ return true
+ }
+ }
+ return false
+}
+
+// naclCmd returns an *exec.Cmd that executes bin under native client.
+func (p *process) naclCmd(bin string) (*exec.Cmd, error) {
+ pwd, err := os.Getwd()
+ if err != nil {
+ return nil, err
+ }
+ var args []string
+ env := []string{
+ "NACLENV_GOOS=" + runtime.GOOS,
+ "NACLENV_GOROOT=/go",
+ "NACLENV_NACLPWD=" + strings.Replace(pwd, runtime.GOROOT(), "/go", 1),
+ }
+ switch runtime.GOARCH {
+ case "amd64":
+ env = append(env, "NACLENV_GOARCH=amd64p32")
+ args = []string{"sel_ldr_x86_64"}
+ case "386":
+ env = append(env, "NACLENV_GOARCH=386")
+ args = []string{"sel_ldr_x86_32"}
+ case "arm":
+ env = append(env, "NACLENV_GOARCH=arm")
+ selLdr, err := exec.LookPath("sel_ldr_arm")
+ if err != nil {
+ return nil, err
+ }
+ args = []string{"nacl_helper_bootstrap_arm", selLdr, "--reserved_at_zero=0xXXXXXXXXXXXXXXXX"}
+ default:
+ return nil, errors.New("native client does not support GOARCH=" + runtime.GOARCH)
+ }
+
+ cmd := p.cmd("", append(args, "-l", "/dev/null", "-S", "-e", bin)...)
+ cmd.Env = append(cmd.Env, env...)
+
+ return cmd, nil
+}
+
+func packageName(body string) (string, error) {
+ f, err := parser.ParseFile(token.NewFileSet(), "prog.go",
+ strings.NewReader(body), parser.PackageClauseOnly)
+ if err != nil {
+ return "", err
+ }
+ return f.Name.String(), nil
+}
+
+// messageWriter is an io.Writer that converts all writes to Message sends on
+// the out channel with the specified id and kind.
+type messageWriter struct {
+ id, kind string
+ out chan<- *Message
+
+ mu sync.Mutex
+ buf []byte
+ send *time.Timer
+}
+
+func (w *messageWriter) Write(b []byte) (n int, err error) {
+ // Buffer writes that occur in a short period to send as one Message.
+ w.mu.Lock()
+ w.buf = append(w.buf, b...)
+ if w.send == nil {
+ w.send = time.AfterFunc(msgDelay, w.sendNow)
+ }
+ w.mu.Unlock()
+ return len(b), nil
+}
+
+func (w *messageWriter) sendNow() {
+ w.mu.Lock()
+ body := safeString(w.buf)
+ w.buf, w.send = nil, nil
+ w.mu.Unlock()
+ w.out <- &Message{Id: w.id, Kind: w.kind, Body: body}
+}
+
+// safeString returns b as a valid UTF-8 string.
+func safeString(b []byte) string {
+ if utf8.Valid(b) {
+ return string(b)
+ }
+ var buf bytes.Buffer
+ for len(b) > 0 {
+ r, size := utf8.DecodeRune(b)
+ b = b[size:]
+ buf.WriteRune(r)
+ }
+ return buf.String()
+}
+
+// limiter returns a channel that wraps dest. Messages sent to the channel are
+// sent to dest. After msgLimit Messages have been passed on, a "kill" Message
+// is sent to the kill channel, and only "end" messages are passed.
+func limiter(kill chan<- *Message, dest chan<- *Message) chan<- *Message {
+ ch := make(chan *Message)
+ go func() {
+ n := 0
+ for m := range ch {
+ switch {
+ case n < msgLimit || m.Kind == "end":
+ dest <- m
+ if m.Kind == "end" {
+ return
+ }
+ case n == msgLimit:
+ // process produced too much output. Kill it.
+ kill <- &Message{Id: m.Id, Kind: "kill"}
+ }
+ n++
+ }
+ }()
+ return ch
+}
+
+var tmpdir string
+
+func init() {
+ // find real path to temporary directory
+ var err error
+ tmpdir, err = filepath.EvalSymlinks(os.TempDir())
+ if err != nil {
+ log.Fatal(err)
+ }
+}
+
+var uniq = make(chan int) // a source of numbers for naming temporary files
+
+func init() {
+ go func() {
+ for i := 0; ; i++ {
+ uniq <- i
+ }
+ }()
+}
diff --git a/present/args.go b/present/args.go
new file mode 100644
index 0000000..49ee1a9
--- /dev/null
+++ b/present/args.go
@@ -0,0 +1,229 @@
+// 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 present
+
+import (
+ "errors"
+ "regexp"
+ "strconv"
+ "unicode/utf8"
+)
+
+// This file is stolen from go/src/cmd/godoc/codewalk.go.
+// It's an evaluator for the file address syntax implemented by acme and sam,
+// but using Go-native regular expressions.
+// To keep things reasonably close, this version uses (?m:re) for all user-provided
+// regular expressions. That is the only change to the code from codewalk.go.
+// See http://plan9.bell-labs.com/sys/doc/sam/sam.html Table II
+// for details on the syntax.
+
+// 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.
+func addrToByteRange(addr string, start int, data []byte) (lo, hi int, err error) {
+ if addr == "" {
+ lo, hi = start, len(data)
+ return
+ }
+ 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) {
+ // We want ^ and $ to work as in sam/acme, so use ?m.
+ re, err := regexp.Compile("(?m:" + 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
+}
diff --git a/present/caption.go b/present/caption.go
new file mode 100644
index 0000000..00e0b5d
--- /dev/null
+++ b/present/caption.go
@@ -0,0 +1,22 @@
+// 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 present
+
+import "strings"
+
+func init() {
+ Register("caption", parseCaption)
+}
+
+type Caption struct {
+ Text string
+}
+
+func (c Caption) TemplateName() string { return "caption" }
+
+func parseCaption(_ *Context, _ string, _ int, text string) (Elem, error) {
+ text = strings.TrimSpace(strings.TrimPrefix(text, ".caption"))
+ return Caption{text}, nil
+}
diff --git a/present/code.go b/present/code.go
new file mode 100644
index 0000000..5a29951
--- /dev/null
+++ b/present/code.go
@@ -0,0 +1,293 @@
+// 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 present
+
+import (
+ "bufio"
+ "bytes"
+ "fmt"
+ "html/template"
+ "path/filepath"
+ "regexp"
+ "strconv"
+ "strings"
+)
+
+// Is the playground available?
+var PlayEnabled = false
+
+// TOOD(adg): replace the PlayEnabled flag with something less spaghetti-like.
+// Instead this will probably be determined by a template execution Context
+// value that contains various global metadata required when rendering
+// templates.
+
+func init() {
+ Register("code", parseCode)
+ Register("play", parseCode)
+}
+
+type Code struct {
+ Text template.HTML
+ Play bool // runnable code
+ FileName string // file name
+ Ext string // file extension
+ Raw []byte // content of the file
+}
+
+func (c Code) TemplateName() string { return "code" }
+
+// The input line is a .code or .play entry with a file name and an optional HLfoo marker on the end.
+// Anything between the file and HL (if any) is an address expression, which we treat as a string here.
+// We pick off the HL first, for easy parsing.
+var (
+ highlightRE = regexp.MustCompile(`\s+HL([a-zA-Z0-9_]+)?$`)
+ hlCommentRE = regexp.MustCompile(`(.+) // HL(.*)$`)
+ codeRE = regexp.MustCompile(`\.(code|play)\s+((?:(?:-edit|-numbers)\s+)*)([^\s]+)(?:\s+(.*))?$`)
+)
+
+// parseCode parses a code present directive. Its syntax:
+// .code [-numbers] [-edit] <filename> [address] [highlight]
+// The directive may also be ".play" if the snippet is executable.
+func parseCode(ctx *Context, sourceFile string, sourceLine int, cmd string) (Elem, error) {
+ cmd = strings.TrimSpace(cmd)
+
+ // Pull off the HL, if any, from the end of the input line.
+ highlight := ""
+ if hl := highlightRE.FindStringSubmatchIndex(cmd); len(hl) == 4 {
+ highlight = cmd[hl[2]:hl[3]]
+ cmd = cmd[:hl[2]-2]
+ }
+
+ // Parse the remaining command line.
+ // Arguments:
+ // args[0]: whole match
+ // args[1]: .code/.play
+ // args[2]: flags ("-edit -numbers")
+ // args[3]: file name
+ // args[4]: optional address
+ args := codeRE.FindStringSubmatch(cmd)
+ if len(args) != 5 {
+ return nil, fmt.Errorf("%s:%d: syntax error for .code/.play invocation", sourceFile, sourceLine)
+ }
+ command, flags, file, addr := args[1], args[2], args[3], strings.TrimSpace(args[4])
+ play := command == "play" && PlayEnabled
+
+ // Read in code file and (optionally) match address.
+ filename := filepath.Join(filepath.Dir(sourceFile), file)
+ textBytes, err := ctx.ReadFile(filename)
+ if err != nil {
+ return nil, fmt.Errorf("%s:%d: %v", sourceFile, sourceLine, err)
+ }
+ lo, hi, err := addrToByteRange(addr, 0, textBytes)
+ if err != nil {
+ return nil, fmt.Errorf("%s:%d: %v", sourceFile, sourceLine, err)
+ }
+
+ // Acme pattern matches can stop mid-line,
+ // so run to end of line in both directions if not at line start/end.
+ for lo > 0 && textBytes[lo-1] != '\n' {
+ lo--
+ }
+ if hi > 0 {
+ for hi < len(textBytes) && textBytes[hi-1] != '\n' {
+ hi++
+ }
+ }
+
+ lines := codeLines(textBytes, lo, hi)
+
+ data := &codeTemplateData{
+ Lines: formatLines(lines, highlight),
+ Edit: strings.Contains(flags, "-edit"),
+ Numbers: strings.Contains(flags, "-numbers"),
+ }
+
+ // Include before and after in a hidden span for playground code.
+ if play {
+ data.Prefix = textBytes[:lo]
+ data.Suffix = textBytes[hi:]
+ }
+
+ var buf bytes.Buffer
+ if err := codeTemplate.Execute(&buf, data); err != nil {
+ return nil, err
+ }
+ return Code{
+ Text: template.HTML(buf.String()),
+ Play: play,
+ FileName: filepath.Base(filename),
+ Ext: filepath.Ext(filename),
+ Raw: rawCode(lines),
+ }, nil
+}
+
+// formatLines returns a new slice of codeLine with the given lines
+// replacing tabs with spaces and adding highlighting where needed.
+func formatLines(lines []codeLine, highlight string) []codeLine {
+ formatted := make([]codeLine, len(lines))
+ for i, line := range lines {
+ // Replace tabs with spaces, which work better in HTML.
+ line.L = strings.Replace(line.L, "\t", " ", -1)
+
+ // Highlight lines that end with "// HL[highlight]"
+ // and strip the magic comment.
+ if m := hlCommentRE.FindStringSubmatch(line.L); m != nil {
+ line.L = m[1]
+ line.HL = m[2] == highlight
+ }
+
+ formatted[i] = line
+ }
+ return formatted
+}
+
+// rawCode returns the code represented by the given codeLines without any kind
+// of formatting.
+func rawCode(lines []codeLine) []byte {
+ b := new(bytes.Buffer)
+ for _, line := range lines {
+ b.WriteString(line.L)
+ b.WriteByte('\n')
+ }
+ return b.Bytes()
+}
+
+type codeTemplateData struct {
+ Lines []codeLine
+ Prefix, Suffix []byte
+ Edit, Numbers bool
+}
+
+var leadingSpaceRE = regexp.MustCompile(`^[ \t]*`)
+
+var codeTemplate = template.Must(template.New("code").Funcs(template.FuncMap{
+ "trimSpace": strings.TrimSpace,
+ "leadingSpace": leadingSpaceRE.FindString,
+}).Parse(codeTemplateHTML))
+
+const codeTemplateHTML = `
+{{with .Prefix}}<pre style="display: none"><span>{{printf "%s" .}}</span></pre>{{end}}
+
+<pre{{if .Edit}} contenteditable="true" spellcheck="false"{{end}}{{if .Numbers}} class="numbers"{{end}}>{{/*
+ */}}{{range .Lines}}<span num="{{.N}}">{{/*
+ */}}{{if .HL}}{{leadingSpace .L}}<b>{{trimSpace .L}}</b>{{/*
+ */}}{{else}}{{.L}}{{end}}{{/*
+*/}}</span>
+{{end}}</pre>
+
+{{with .Suffix}}<pre style="display: none"><span>{{printf "%s" .}}</span></pre>{{end}}
+`
+
+// codeLine represents a line of code extracted from a source file.
+type codeLine struct {
+ L string // The line of code.
+ N int // The line number from the source file.
+ HL bool // Whether the line should be highlighted.
+}
+
+// codeLines takes a source file and returns the lines that
+// span the byte range specified by start and end.
+// It discards lines that end in "OMIT".
+func codeLines(src []byte, start, end int) (lines []codeLine) {
+ startLine := 1
+ for i, b := range src {
+ if i == start {
+ break
+ }
+ if b == '\n' {
+ startLine++
+ }
+ }
+ s := bufio.NewScanner(bytes.NewReader(src[start:end]))
+ for n := startLine; s.Scan(); n++ {
+ l := s.Text()
+ if strings.HasSuffix(l, "OMIT") {
+ continue
+ }
+ lines = append(lines, codeLine{L: l, N: n})
+ }
+ // Trim leading and trailing blank lines.
+ for len(lines) > 0 && len(lines[0].L) == 0 {
+ lines = lines[1:]
+ }
+ for len(lines) > 0 && len(lines[len(lines)-1].L) == 0 {
+ lines = lines[:len(lines)-1]
+ }
+ return
+}
+
+func parseArgs(name string, line int, args []string) (res []interface{}, err error) {
+ res = make([]interface{}, len(args))
+ for i, v := range args {
+ if len(v) == 0 {
+ return nil, fmt.Errorf("%s:%d bad code argument %q", name, line, v)
+ }
+ switch v[0] {
+ case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
+ n, err := strconv.Atoi(v)
+ if err != nil {
+ return nil, fmt.Errorf("%s:%d bad code argument %q", name, line, v)
+ }
+ res[i] = n
+ case '/':
+ if len(v) < 2 || v[len(v)-1] != '/' {
+ return nil, fmt.Errorf("%s:%d bad code argument %q", name, line, v)
+ }
+ res[i] = v
+ case '$':
+ res[i] = "$"
+ case '_':
+ if len(v) == 1 {
+ // Do nothing; "_" indicates an intentionally empty parameter.
+ break
+ }
+ fallthrough
+ default:
+ return nil, fmt.Errorf("%s:%d bad code argument %q", name, line, v)
+ }
+ }
+ return
+}
+
+// parseArg returns the integer or string value of the argument and tells which it is.
+func parseArg(arg interface{}, max int) (ival int, sval string, isInt bool, err error) {
+ switch n := arg.(type) {
+ case int:
+ if n <= 0 || n > max {
+ return 0, "", false, fmt.Errorf("%d is out of range", n)
+ }
+ return n, "", true, nil
+ case string:
+ return 0, n, false, nil
+ }
+ return 0, "", false, fmt.Errorf("unrecognized argument %v type %T", arg, arg)
+}
+
+// match identifies the input line that matches the pattern in a code invocation.
+// If start>0, match lines starting there rather than at the beginning.
+// The return value is 1-indexed.
+func match(file string, start int, lines []string, pattern string) (int, error) {
+ // $ matches the end of the file.
+ if pattern == "$" {
+ if len(lines) == 0 {
+ return 0, fmt.Errorf("%q: empty file", file)
+ }
+ return len(lines), nil
+ }
+ // /regexp/ matches the line that matches the regexp.
+ if len(pattern) > 2 && pattern[0] == '/' && pattern[len(pattern)-1] == '/' {
+ re, err := regexp.Compile(pattern[1 : len(pattern)-1])
+ if err != nil {
+ return 0, err
+ }
+ for i := start; i < len(lines); i++ {
+ if re.MatchString(lines[i]) {
+ return i + 1, nil
+ }
+ }
+ return 0, fmt.Errorf("%s: no match for %#q", file, pattern)
+ }
+ return 0, fmt.Errorf("unrecognized pattern: %q", pattern)
+}
diff --git a/present/doc.go b/present/doc.go
new file mode 100644
index 0000000..584e0c1
--- /dev/null
+++ b/present/doc.go
@@ -0,0 +1,205 @@
+// 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 present file format
+
+Present files have the following format. The first non-blank non-comment
+line is the title, so the header looks like
+
+ Title of document
+ Subtitle of document
+ 15:04 2 Jan 2006
+ Tags: foo, bar, baz
+ <blank line>
+ Author Name
+ Job title, Company
+ joe@example.com
+ http://url/
+ @twitter_name
+
+The subtitle, date, and tags lines are optional.
+
+The date line may be written without a time:
+ 2 Jan 2006
+In this case, the time will be interpreted as 10am UTC on that date.
+
+The tags line is a comma-separated list of tags that may be used to categorize
+the document.
+
+The author section may contain a mixture of text, twitter names, and links.
+For slide presentations, only the plain text lines will be displayed on the
+first slide.
+
+Multiple presenters may be specified, separated by a blank line.
+
+After that come slides/sections, each after a blank line:
+
+ * Title of slide or section (must have asterisk)
+
+ Some Text
+
+ ** Subsection
+
+ - bullets
+ - more bullets
+ - a bullet with
+
+ *** Sub-subsection
+
+ Some More text
+
+ Preformatted text
+ is indented (however you like)
+
+ Further Text, including invocations like:
+
+ .code x.go /^func main/,/^}/
+ .play y.go
+ .image image.jpg
+ .iframe http://foo
+ .link http://foo label
+ .html file.html
+ .caption _Gopher_ by [[http://www.reneefrench.com][Renée French]]
+
+ Again, more text
+
+Blank lines are OK (not mandatory) after the title and after the
+text. Text, bullets, and .code etc. are all optional; title is
+not.
+
+Lines starting with # in column 1 are commentary.
+
+Fonts:
+
+Within the input for plain text or lists, text bracketed by font
+markers will be presented in italic, bold, or program font.
+Marker characters are _ (italic), * (bold) and ` (program font).
+Unmatched markers appear as plain text.
+Within marked text, a single marker character becomes a space
+and a doubled single marker quotes the marker character.
+
+ _italic_
+ *bold*
+ `program`
+ _this_is_all_italic_
+ _Why_use_scoped__ptr_? Use plain ***ptr* instead.
+
+Inline links:
+
+Links can be included in any text with the form [[url][label]], or
+[[url]] to use the URL itself as the label.
+
+Functions:
+
+A number of template functions are available through invocations
+in the input text. Each such invocation contains a period as the
+first character on the line, followed immediately by the name of
+the function, followed by any arguments. A typical invocation might
+be
+ .play demo.go /^func show/,/^}/
+(except that the ".play" must be at the beginning of the line and
+not be indented like this.)
+
+Here follows a description of the functions:
+
+code:
+
+Injects program source into the output by extracting code from files
+and injecting them as HTML-escaped <pre> blocks. The argument is
+a file name followed by an optional address that specifies what
+section of the file to display. The address syntax is similar in
+its simplest form to that of ed, but comes from sam and is more
+general. See
+ http://plan9.bell-labs.com/sys/doc/sam/sam.html Table II
+for full details. The displayed block is always rounded out to a
+full line at both ends.
+
+If no pattern is present, the entire file is displayed.
+
+Any line in the program that ends with the four characters
+ OMIT
+is deleted from the source before inclusion, making it easy
+to write things like
+ .code test.go /START OMIT/,/END OMIT/
+to find snippets like this
+ tedious_code = boring_function()
+ // START OMIT
+ interesting_code = fascinating_function()
+ // END OMIT
+and see only this:
+ interesting_code = fascinating_function()
+
+Also, inside the displayed text a line that ends
+ // HL
+will be highlighted in the display; the 'h' key in the browser will
+toggle extra emphasis of any highlighted lines. A highlighting mark
+may have a suffix word, such as
+ // HLxxx
+Such highlights are enabled only if the code invocation ends with
+"HL" followed by the word:
+ .code test.go /^type Foo/,/^}/ HLxxx
+
+The .code function may take one or more flags immediately preceding
+the filename. This command shows test.go in an editable text area:
+ .code -edit test.go
+This command shows test.go with line numbers:
+ .code -numbers test.go
+
+play:
+
+The function "play" is the same as "code" but puts a button
+on the displayed source so the program can be run from the browser.
+Although only the selected text is shown, all the source is included
+in the HTML output so it can be presented to the compiler.
+
+link:
+
+Create a hyperlink. The syntax is 1 or 2 space-separated arguments.
+The first argument is always the HTTP URL. If there is a second
+argument, it is the text label to display for this link.
+
+ .link http://golang.org golang.org
+
+image:
+
+The template uses the function "image" to inject picture files.
+
+The syntax is simple: 1 or 3 space-separated arguments.
+The first argument is always the file name.
+If there are more arguments, they are the height and width;
+both must be present, or substituted with an underscore.
+Replacing a dimension argument with the underscore parameter
+preserves the aspect ratio of the image when scaling.
+
+ .image images/betsy.jpg 100 200
+
+ .image images/janet.jpg _ 300
+
+
+caption:
+
+The template uses the function "caption" to inject figure captions.
+
+The text after ".caption" is embedded in a figcaption element after
+processing styling and links as in standard text lines.
+
+ .caption _Gopher_ by [[http://www.reneefrench.com][Renée French]]
+
+iframe:
+
+The function "iframe" injects iframes (pages inside pages).
+Its syntax is the same as that of image.
+
+html:
+
+The function html includes the contents of the specified file as
+unescaped HTML. This is useful for including custom HTML elements
+that cannot be created using only the slide format.
+It is your responsibilty to make sure the included HTML is valid and safe.
+
+ .html file.html
+
+*/
+package present // import "golang.org/x/tools/present"
diff --git a/present/html.go b/present/html.go
new file mode 100644
index 0000000..cca90ef
--- /dev/null
+++ b/present/html.go
@@ -0,0 +1,31 @@
+package present
+
+import (
+ "errors"
+ "html/template"
+ "path/filepath"
+ "strings"
+)
+
+func init() {
+ Register("html", parseHTML)
+}
+
+func parseHTML(ctx *Context, fileName string, lineno int, text string) (Elem, error) {
+ p := strings.Fields(text)
+ if len(p) != 2 {
+ return nil, errors.New("invalid .html args")
+ }
+ name := filepath.Join(filepath.Dir(fileName), p[1])
+ b, err := ctx.ReadFile(name)
+ if err != nil {
+ return nil, err
+ }
+ return HTML{template.HTML(b)}, nil
+}
+
+type HTML struct {
+ template.HTML
+}
+
+func (s HTML) TemplateName() string { return "html" }
diff --git a/present/iframe.go b/present/iframe.go
new file mode 100644
index 0000000..2f3c5e5
--- /dev/null
+++ b/present/iframe.go
@@ -0,0 +1,45 @@
+// 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 present
+
+import (
+ "fmt"
+ "strings"
+)
+
+func init() {
+ Register("iframe", parseIframe)
+}
+
+type Iframe struct {
+ URL string
+ Width int
+ Height int
+}
+
+func (i Iframe) TemplateName() string { return "iframe" }
+
+func parseIframe(ctx *Context, fileName string, lineno int, text string) (Elem, error) {
+ args := strings.Fields(text)
+ i := Iframe{URL: args[1]}
+ a, err := parseArgs(fileName, lineno, args[2:])
+ if err != nil {
+ return nil, err
+ }
+ switch len(a) {
+ case 0:
+ // no size parameters
+ case 2:
+ if v, ok := a[0].(int); ok {
+ i.Height = v
+ }
+ if v, ok := a[1].(int); ok {
+ i.Width = v
+ }
+ default:
+ return nil, fmt.Errorf("incorrect image invocation: %q", text)
+ }
+ return i, nil
+}
diff --git a/present/image.go b/present/image.go
new file mode 100644
index 0000000..cfa2af9
--- /dev/null
+++ b/present/image.go
@@ -0,0 +1,50 @@
+// 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 present
+
+import (
+ "fmt"
+ "strings"
+)
+
+func init() {
+ Register("image", parseImage)
+}
+
+type Image struct {
+ URL string
+ Width int
+ Height int
+}
+
+func (i Image) TemplateName() string { return "image" }
+
+func parseImage(ctx *Context, fileName string, lineno int, text string) (Elem, error) {
+ args := strings.Fields(text)
+ img := Image{URL: args[1]}
+ a, err := parseArgs(fileName, lineno, args[2:])
+ if err != nil {
+ return nil, err
+ }
+ switch len(a) {
+ case 0:
+ // no size parameters
+ case 2:
+ // If a parameter is empty (underscore) or invalid
+ // leave the field set to zero. The "image" action
+ // template will then omit that img tag attribute and
+ // the browser will calculate the value to preserve
+ // the aspect ratio.
+ if v, ok := a[0].(int); ok {
+ img.Height = v
+ }
+ if v, ok := a[1].(int); ok {
+ img.Width = v
+ }
+ default:
+ return nil, fmt.Errorf("incorrect image invocation: %q", text)
+ }
+ return img, nil
+}
diff --git a/present/link.go b/present/link.go
new file mode 100644
index 0000000..6b0968f
--- /dev/null
+++ b/present/link.go
@@ -0,0 +1,97 @@
+// 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 present
+
+import (
+ "fmt"
+ "log"
+ "net/url"
+ "strings"
+)
+
+func init() {
+ Register("link", parseLink)
+}
+
+type Link struct {
+ URL *url.URL
+ Label string
+}
+
+func (l Link) TemplateName() string { return "link" }
+
+func parseLink(ctx *Context, fileName string, lineno int, text string) (Elem, error) {
+ args := strings.Fields(text)
+ url, err := url.Parse(args[1])
+ if err != nil {
+ return nil, err
+ }
+ label := ""
+ if len(args) > 2 {
+ label = strings.Join(args[2:], " ")
+ } else {
+ scheme := url.Scheme + "://"
+ if url.Scheme == "mailto" {
+ scheme = "mailto:"
+ }
+ label = strings.Replace(url.String(), scheme, "", 1)
+ }
+ return Link{url, label}, nil
+}
+
+func renderLink(href, text string) string {
+ text = font(text)
+ if text == "" {
+ text = href
+ }
+ // Open links in new window only when their url is absolute.
+ target := "_blank"
+ if u, err := url.Parse(href); err != nil {
+ log.Println("rendernLink parsing url:", err)
+ } else if !u.IsAbs() || u.Scheme == "javascript" {
+ target = "_self"
+ }
+
+ return fmt.Sprintf(`<a href="%s" target="%s">%s</a>`, href, target, text)
+}
+
+// parseInlineLink parses an inline link at the start of s, and returns
+// a rendered HTML link and the total length of the raw inline link.
+// If no inline link is present, it returns all zeroes.
+func parseInlineLink(s string) (link string, length int) {
+ if !strings.HasPrefix(s, "[[") {
+ return
+ }
+ end := strings.Index(s, "]]")
+ if end == -1 {
+ return
+ }
+ urlEnd := strings.Index(s, "]")
+ rawURL := s[2:urlEnd]
+ const badURLChars = `<>"{}|\^[] ` + "`" // per RFC2396 section 2.4.3
+ if strings.ContainsAny(rawURL, badURLChars) {
+ return
+ }
+ if urlEnd == end {
+ simpleUrl := ""
+ url, err := url.Parse(rawURL)
+ if err == nil {
+ // If the URL is http://foo.com, drop the http://
+ // In other words, render [[http://golang.org]] as:
+ // <a href="http://golang.org">golang.org</a>
+ if strings.HasPrefix(rawURL, url.Scheme+"://") {
+ simpleUrl = strings.TrimPrefix(rawURL, url.Scheme+"://")
+ } else if strings.HasPrefix(rawURL, url.Scheme+":") {
+ simpleUrl = strings.TrimPrefix(rawURL, url.Scheme+":")
+ }
+ }
+ return renderLink(rawURL, simpleUrl), end + 2
+ }
+ if s[urlEnd:urlEnd+2] != "][" {
+ return
+ }
+ text := s[urlEnd+2 : end]
+ return renderLink(rawURL, text), end + 2
+}
diff --git a/present/link_test.go b/present/link_test.go
new file mode 100644
index 0000000..334e72b
--- /dev/null
+++ b/present/link_test.go
@@ -0,0 +1,40 @@
+// 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 present
+
+import "testing"
+
+func TestInlineParsing(t *testing.T) {
+ var tests = []struct {
+ in string
+ link string
+ text string
+ length int
+ }{
+ {"[[http://golang.org]]", "http://golang.org", "golang.org", 21},
+ {"[[http://golang.org][]]", "http://golang.org", "http://golang.org", 23},
+ {"[[http://golang.org]] this is ignored", "http://golang.org", "golang.org", 21},
+ {"[[http://golang.org][link]]", "http://golang.org", "link", 27},
+ {"[[http://golang.org][two words]]", "http://golang.org", "two words", 32},
+ {"[[http://golang.org][*link*]]", "http://golang.org", "<b>link</b>", 29},
+ {"[[http://bad[url]]", "", "", 0},
+ {"[[http://golang.org][a [[link]] ]]", "http://golang.org", "a [[link", 31},
+ {"[[http:// *spaces* .com]]", "", "", 0},
+ {"[[http://bad`char.com]]", "", "", 0},
+ {" [[http://google.com]]", "", "", 0},
+ {"[[mailto:gopher@golang.org][Gopher]]", "mailto:gopher@golang.org", "Gopher", 36},
+ {"[[mailto:gopher@golang.org]]", "mailto:gopher@golang.org", "gopher@golang.org", 28},
+ }
+
+ for i, test := range tests {
+ link, length := parseInlineLink(test.in)
+ if length == 0 && test.length == 0 {
+ continue
+ }
+ if a := renderLink(test.link, test.text); length != test.length || link != a {
+ t.Errorf("#%d: parseInlineLink(%q):\ngot\t%q, %d\nwant\t%q, %d", i, test.in, link, length, a, test.length)
+ }
+ }
+}
diff --git a/present/parse.go b/present/parse.go
new file mode 100644
index 0000000..449d5ed
--- /dev/null
+++ b/present/parse.go
@@ -0,0 +1,505 @@
+// 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 present
+
+import (
+ "bufio"
+ "bytes"
+ "errors"
+ "fmt"
+ "html/template"
+ "io"
+ "io/ioutil"
+ "log"
+ "net/url"
+ "regexp"
+ "strings"
+ "time"
+ "unicode"
+ "unicode/utf8"
+)
+
+var (
+ parsers = make(map[string]ParseFunc)
+ funcs = template.FuncMap{}
+)
+
+// Template returns an empty template with the action functions in its FuncMap.
+func Template() *template.Template {
+ return template.New("").Funcs(funcs)
+}
+
+// Render renders the doc to the given writer using the provided template.
+func (d *Doc) Render(w io.Writer, t *template.Template) error {
+ data := struct {
+ *Doc
+ Template *template.Template
+ PlayEnabled bool
+ }{d, t, PlayEnabled}
+ return t.ExecuteTemplate(w, "root", data)
+}
+
+// Render renders the section to the given writer using the provided template.
+func (s *Section) Render(w io.Writer, t *template.Template) error {
+ data := struct {
+ *Section
+ Template *template.Template
+ PlayEnabled bool
+ }{s, t, PlayEnabled}
+ return t.ExecuteTemplate(w, "section", data)
+}
+
+type ParseFunc func(ctx *Context, fileName string, lineNumber int, inputLine string) (Elem, error)
+
+// Register binds the named action, which does not begin with a period, to the
+// specified parser to be invoked when the name, with a period, appears in the
+// present input text.
+func Register(name string, parser ParseFunc) {
+ if len(name) == 0 || name[0] == ';' {
+ panic("bad name in Register: " + name)
+ }
+ parsers["."+name] = parser
+}
+
+// Doc represents an entire document.
+type Doc struct {
+ Title string
+ Subtitle string
+ Time time.Time
+ Authors []Author
+ Sections []Section
+ Tags []string
+}
+
+// Author represents the person who wrote and/or is presenting the document.
+type Author struct {
+ Elem []Elem
+}
+
+// TextElem returns the first text elements of the author details.
+// This is used to display the author' name, job title, and company
+// without the contact details.
+func (p *Author) TextElem() (elems []Elem) {
+ for _, el := range p.Elem {
+ if _, ok := el.(Text); !ok {
+ break
+ }
+ elems = append(elems, el)
+ }
+ return
+}
+
+// Section represents a section of a document (such as a presentation slide)
+// comprising a title and a list of elements.
+type Section struct {
+ Number []int
+ Title string
+ Elem []Elem
+}
+
+func (s Section) Sections() (sections []Section) {
+ for _, e := range s.Elem {
+ if section, ok := e.(Section); ok {
+ sections = append(sections, section)
+ }
+ }
+ return
+}
+
+// Level returns the level of the given section.
+// The document title is level 1, main section 2, etc.
+func (s Section) Level() int {
+ return len(s.Number) + 1
+}
+
+// FormattedNumber returns a string containing the concatenation of the
+// numbers identifying a Section.
+func (s Section) FormattedNumber() string {
+ b := &bytes.Buffer{}
+ for _, n := range s.Number {
+ fmt.Fprintf(b, "%v.", n)
+ }
+ return b.String()
+}
+
+func (s Section) TemplateName() string { return "section" }
+
+// Elem defines the interface for a present element. That is, something that
+// can provide the name of the template used to render the element.
+type Elem interface {
+ TemplateName() string
+}
+
+// renderElem implements the elem template function, used to render
+// sub-templates.
+func renderElem(t *template.Template, e Elem) (template.HTML, error) {
+ var data interface{} = e
+ if s, ok := e.(Section); ok {
+ data = struct {
+ Section
+ Template *template.Template
+ }{s, t}
+ }
+ return execTemplate(t, e.TemplateName(), data)
+}
+
+func init() {
+ funcs["elem"] = renderElem
+}
+
+// execTemplate is a helper to execute a template and return the output as a
+// template.HTML value.
+func execTemplate(t *template.Template, name string, data interface{}) (template.HTML, error) {
+ b := new(bytes.Buffer)
+ err := t.ExecuteTemplate(b, name, data)
+ if err != nil {
+ return "", err
+ }
+ return template.HTML(b.String()), nil
+}
+
+// Text represents an optionally preformatted paragraph.
+type Text struct {
+ Lines []string
+ Pre bool
+}
+
+func (t Text) TemplateName() string { return "text" }
+
+// List represents a bulleted list.
+type List struct {
+ Bullet []string
+}
+
+func (l List) TemplateName() string { return "list" }
+
+// Lines is a helper for parsing line-based input.
+type Lines struct {
+ line int // 0 indexed, so has 1-indexed number of last line returned
+ text []string
+}
+
+func readLines(r io.Reader) (*Lines, error) {
+ var lines []string
+ s := bufio.NewScanner(r)
+ for s.Scan() {
+ lines = append(lines, s.Text())
+ }
+ if err := s.Err(); err != nil {
+ return nil, err
+ }
+ return &Lines{0, lines}, nil
+}
+
+func (l *Lines) next() (text string, ok bool) {
+ for {
+ current := l.line
+ l.line++
+ if current >= len(l.text) {
+ return "", false
+ }
+ text = l.text[current]
+ // Lines starting with # are comments.
+ if len(text) == 0 || text[0] != '#' {
+ ok = true
+ break
+ }
+ }
+ return
+}
+
+func (l *Lines) back() {
+ l.line--
+}
+
+func (l *Lines) nextNonEmpty() (text string, ok bool) {
+ for {
+ text, ok = l.next()
+ if !ok {
+ return
+ }
+ if len(text) > 0 {
+ break
+ }
+ }
+ return
+}
+
+// A Context specifies the supporting context for parsing a presentation.
+type Context struct {
+ // ReadFile reads the file named by filename and returns the contents.
+ ReadFile func(filename string) ([]byte, error)
+}
+
+// ParseMode represents flags for the Parse function.
+type ParseMode int
+
+const (
+ // If set, parse only the title and subtitle.
+ TitlesOnly ParseMode = 1
+)
+
+// Parse parses a document from r.
+func (ctx *Context) Parse(r io.Reader, name string, mode ParseMode) (*Doc, error) {
+ doc := new(Doc)
+ lines, err := readLines(r)
+ if err != nil {
+ return nil, err
+ }
+ err = parseHeader(doc, lines)
+ if err != nil {
+ return nil, err
+ }
+ if mode&TitlesOnly != 0 {
+ return doc, nil
+ }
+ // Authors
+ if doc.Authors, err = parseAuthors(lines); err != nil {
+ return nil, err
+ }
+ // Sections
+ if doc.Sections, err = parseSections(ctx, name, lines, []int{}, doc); err != nil {
+ return nil, err
+ }
+ return doc, nil
+}
+
+// Parse parses a document from r. Parse reads assets used by the presentation
+// from the file system using ioutil.ReadFile.
+func Parse(r io.Reader, name string, mode ParseMode) (*Doc, error) {
+ ctx := Context{ReadFile: ioutil.ReadFile}
+ return ctx.Parse(r, name, mode)
+}
+
+// isHeading matches any section heading.
+var isHeading = regexp.MustCompile(`^\*+ `)
+
+// lesserHeading returns true if text is a heading of a lesser or equal level
+// than that denoted by prefix.
+func lesserHeading(text, prefix string) bool {
+ return isHeading.MatchString(text) && !strings.HasPrefix(text, prefix+"*")
+}
+
+// parseSections parses Sections from lines for the section level indicated by
+// number (a nil number indicates the top level).
+func parseSections(ctx *Context, name string, lines *Lines, number []int, doc *Doc) ([]Section, error) {
+ var sections []Section
+ for i := 1; ; i++ {
+ // Next non-empty line is title.
+ text, ok := lines.nextNonEmpty()
+ for ok && text == "" {
+ text, ok = lines.next()
+ }
+ if !ok {
+ break
+ }
+ prefix := strings.Repeat("*", len(number)+1)
+ if !strings.HasPrefix(text, prefix+" ") {
+ lines.back()
+ break
+ }
+ section := Section{
+ Number: append(append([]int{}, number...), i),
+ Title: text[len(prefix)+1:],
+ }
+ text, ok = lines.nextNonEmpty()
+ for ok && !lesserHeading(text, prefix) {
+ var e Elem
+ r, _ := utf8.DecodeRuneInString(text)
+ switch {
+ case unicode.IsSpace(r):
+ i := strings.IndexFunc(text, func(r rune) bool {
+ return !unicode.IsSpace(r)
+ })
+ if i < 0 {
+ break
+ }
+ indent := text[:i]
+ var s []string
+ for ok && (strings.HasPrefix(text, indent) || text == "") {
+ if text != "" {
+ text = text[i:]
+ }
+ s = append(s, text)
+ text, ok = lines.next()
+ }
+ lines.back()
+ pre := strings.Join(s, "\n")
+ pre = strings.Replace(pre, "\t", " ", -1) // browsers treat tabs badly
+ pre = strings.TrimRightFunc(pre, unicode.IsSpace)
+ e = Text{Lines: []string{pre}, Pre: true}
+ case strings.HasPrefix(text, "- "):
+ var b []string
+ for ok && strings.HasPrefix(text, "- ") {
+ b = append(b, text[2:])
+ text, ok = lines.next()
+ }
+ lines.back()
+ e = List{Bullet: b}
+ case strings.HasPrefix(text, prefix+"* "):
+ lines.back()
+ subsecs, err := parseSections(ctx, name, lines, section.Number, doc)
+ if err != nil {
+ return nil, err
+ }
+ for _, ss := range subsecs {
+ section.Elem = append(section.Elem, ss)
+ }
+ case strings.HasPrefix(text, "."):
+ args := strings.Fields(text)
+ parser := parsers[args[0]]
+ if parser == nil {
+ return nil, fmt.Errorf("%s:%d: unknown command %q\n", name, lines.line, text)
+ }
+ t, err := parser(ctx, name, lines.line, text)
+ if err != nil {
+ return nil, err
+ }
+ e = t
+ default:
+ var l []string
+ for ok && strings.TrimSpace(text) != "" {
+ if text[0] == '.' { // Command breaks text block.
+ break
+ }
+ if strings.HasPrefix(text, `\.`) { // Backslash escapes initial period.
+ text = text[1:]
+ }
+ l = append(l, text)
+ text, ok = lines.next()
+ }
+ if len(l) > 0 {
+ e = Text{Lines: l}
+ }
+ }
+ if e != nil {
+ section.Elem = append(section.Elem, e)
+ }
+ text, ok = lines.nextNonEmpty()
+ }
+ if isHeading.MatchString(text) {
+ lines.back()
+ }
+ sections = append(sections, section)
+ }
+ return sections, nil
+}
+
+func parseHeader(doc *Doc, lines *Lines) error {
+ var ok bool
+ // First non-empty line starts header.
+ doc.Title, ok = lines.nextNonEmpty()
+ if !ok {
+ return errors.New("unexpected EOF; expected title")
+ }
+ for {
+ text, ok := lines.next()
+ if !ok {
+ return errors.New("unexpected EOF")
+ }
+ if text == "" {
+ break
+ }
+ const tagPrefix = "Tags:"
+ if strings.HasPrefix(text, tagPrefix) {
+ tags := strings.Split(text[len(tagPrefix):], ",")
+ for i := range tags {
+ tags[i] = strings.TrimSpace(tags[i])
+ }
+ doc.Tags = append(doc.Tags, tags...)
+ } else if t, ok := parseTime(text); ok {
+ doc.Time = t
+ } else if doc.Subtitle == "" {
+ doc.Subtitle = text
+ } else {
+ return fmt.Errorf("unexpected header line: %q", text)
+ }
+ }
+ return nil
+}
+
+func parseAuthors(lines *Lines) (authors []Author, err error) {
+ // This grammar demarcates authors with blanks.
+
+ // Skip blank lines.
+ if _, ok := lines.nextNonEmpty(); !ok {
+ return nil, errors.New("unexpected EOF")
+ }
+ lines.back()
+
+ var a *Author
+ for {
+ text, ok := lines.next()
+ if !ok {
+ return nil, errors.New("unexpected EOF")
+ }
+
+ // If we find a section heading, we're done.
+ if strings.HasPrefix(text, "* ") {
+ lines.back()
+ break
+ }
+
+ // If we encounter a blank we're done with this author.
+ if a != nil && len(text) == 0 {
+ authors = append(authors, *a)
+ a = nil
+ continue
+ }
+ if a == nil {
+ a = new(Author)
+ }
+
+ // Parse the line. Those that
+ // - begin with @ are twitter names,
+ // - contain slashes are links, or
+ // - contain an @ symbol are an email address.
+ // The rest is just text.
+ var el Elem
+ switch {
+ case strings.HasPrefix(text, "@"):
+ el = parseURL("http://twitter.com/" + text[1:])
+ case strings.Contains(text, ":"):
+ el = parseURL(text)
+ case strings.Contains(text, "@"):
+ el = parseURL("mailto:" + text)
+ }
+ if l, ok := el.(Link); ok {
+ l.Label = text
+ el = l
+ }
+ if el == nil {
+ el = Text{Lines: []string{text}}
+ }
+ a.Elem = append(a.Elem, el)
+ }
+ if a != nil {
+ authors = append(authors, *a)
+ }
+ return authors, nil
+}
+
+func parseURL(text string) Elem {
+ u, err := url.Parse(text)
+ if err != nil {
+ log.Printf("Parse(%q): %v", text, err)
+ return nil
+ }
+ return Link{URL: u}
+}
+
+func parseTime(text string) (t time.Time, ok bool) {
+ t, err := time.Parse("15:04 2 Jan 2006", text)
+ if err == nil {
+ return t, true
+ }
+ t, err = time.Parse("2 Jan 2006", text)
+ if err == nil {
+ // at 11am UTC it is the same date everywhere
+ t = t.Add(time.Hour * 11)
+ return t, true
+ }
+ return time.Time{}, false
+}
diff --git a/present/style.go b/present/style.go
new file mode 100644
index 0000000..1cd240d
--- /dev/null
+++ b/present/style.go
@@ -0,0 +1,166 @@
+// 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 present
+
+import (
+ "bytes"
+ "html"
+ "html/template"
+ "strings"
+ "unicode"
+ "unicode/utf8"
+)
+
+/*
+ Fonts are demarcated by an initial and final char bracketing a
+ space-delimited word, plus possibly some terminal punctuation.
+ The chars are
+ _ for italic
+ * for bold
+ ` (back quote) for fixed width.
+ Inner appearances of the char become spaces. For instance,
+ _this_is_italic_!
+ becomes
+ <i>this is italic</i>!
+*/
+
+func init() {
+ funcs["style"] = Style
+}
+
+// Style returns s with HTML entities escaped and font indicators turned into
+// HTML font tags.
+func Style(s string) template.HTML {
+ return template.HTML(font(html.EscapeString(s)))
+}
+
+// font returns s with font indicators turned into HTML font tags.
+func font(s string) string {
+ if strings.IndexAny(s, "[`_*") == -1 {
+ return s
+ }
+ words := split(s)
+ var b bytes.Buffer
+Word:
+ for w, word := range words {
+ if len(word) < 2 {
+ continue Word
+ }
+ if link, _ := parseInlineLink(word); link != "" {
+ words[w] = link
+ continue Word
+ }
+ const punctuation = `.,;:()!?—–'"`
+ const marker = "_*`"
+ // Initial punctuation is OK but must be peeled off.
+ first := strings.IndexAny(word, marker)
+ if first == -1 {
+ continue Word
+ }
+ // Is the marker prefixed only by punctuation?
+ for _, r := range word[:first] {
+ if !strings.ContainsRune(punctuation, r) {
+ continue Word
+ }
+ }
+ open, word := word[:first], word[first:]
+ char := word[0] // ASCII is OK.
+ close := ""
+ switch char {
+ default:
+ continue Word
+ case '_':
+ open += "<i>"
+ close = "</i>"
+ case '*':
+ open += "<b>"
+ close = "</b>"
+ case '`':
+ open += "<code>"
+ close = "</code>"
+ }
+ // Terminal punctuation is OK but must be peeled off.
+ last := strings.LastIndex(word, word[:1])
+ if last == 0 {
+ continue Word
+ }
+ head, tail := word[:last+1], word[last+1:]
+ for _, r := range tail {
+ if !strings.ContainsRune(punctuation, r) {
+ continue Word
+ }
+ }
+ b.Reset()
+ b.WriteString(open)
+ var wid int
+ for i := 1; i < len(head)-1; i += wid {
+ var r rune
+ r, wid = utf8.DecodeRuneInString(head[i:])
+ if r != rune(char) {
+ // Ordinary character.
+ b.WriteRune(r)
+ continue
+ }
+ if head[i+1] != char {
+ // Inner char becomes space.
+ b.WriteRune(' ')
+ continue
+ }
+ // Doubled char becomes real char.
+ // Not worth worrying about "_x__".
+ b.WriteByte(char)
+ wid++ // Consumed two chars, both ASCII.
+ }
+ b.WriteString(close) // Write closing tag.
+ b.WriteString(tail) // Restore trailing punctuation.
+ words[w] = b.String()
+ }
+ return strings.Join(words, "")
+}
+
+// split is like strings.Fields but also returns the runs of spaces
+// and treats inline links as distinct words.
+func split(s string) []string {
+ var (
+ words = make([]string, 0, 10)
+ start = 0
+ )
+
+ // appendWord appends the string s[start:end] to the words slice.
+ // If the word contains the beginning of a link, the non-link portion
+ // of the word and the entire link are appended as separate words,
+ // and the start index is advanced to the end of the link.
+ appendWord := func(end int) {
+ if j := strings.Index(s[start:end], "[["); j > -1 {
+ if _, l := parseInlineLink(s[start+j:]); l > 0 {
+ // Append portion before link, if any.
+ if j > 0 {
+ words = append(words, s[start:start+j])
+ }
+ // Append link itself.
+ words = append(words, s[start+j:start+j+l])
+ // Advance start index to end of link.
+ start = start + j + l
+ return
+ }
+ }
+ // No link; just add the word.
+ words = append(words, s[start:end])
+ start = end
+ }
+
+ wasSpace := false
+ for i, r := range s {
+ isSpace := unicode.IsSpace(r)
+ if i > start && isSpace != wasSpace {
+ appendWord(i)
+ }
+ wasSpace = isSpace
+ }
+ for start < len(s) {
+ appendWord(len(s))
+ }
+ return words
+}
diff --git a/present/style_test.go b/present/style_test.go
new file mode 100644
index 0000000..d04db72
--- /dev/null
+++ b/present/style_test.go
@@ -0,0 +1,116 @@
+// 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 present
+
+import (
+ "fmt"
+ "reflect"
+ "testing"
+)
+
+func TestSplit(t *testing.T) {
+ var tests = []struct {
+ in string
+ out []string
+ }{
+ {"", []string{}},
+ {" ", []string{" "}},
+ {"abc", []string{"abc"}},
+ {"abc def", []string{"abc", " ", "def"}},
+ {"abc def ", []string{"abc", " ", "def", " "}},
+ {"hey [[http://golang.org][Gophers]] around",
+ []string{"hey", " ", "[[http://golang.org][Gophers]]", " ", "around"}},
+ {"A [[http://golang.org/doc][two words]] link",
+ []string{"A", " ", "[[http://golang.org/doc][two words]]", " ", "link"}},
+ {"Visit [[http://golang.org/doc]] now",
+ []string{"Visit", " ", "[[http://golang.org/doc]]", " ", "now"}},
+ {"not [[http://golang.org/doc][a [[link]] ]] around",
+ []string{"not", " ", "[[http://golang.org/doc][a [[link]]", " ", "]]", " ", "around"}},
+ {"[[http://golang.org][foo bar]]",
+ []string{"[[http://golang.org][foo bar]]"}},
+ {"ends with [[http://golang.org][link]]",
+ []string{"ends", " ", "with", " ", "[[http://golang.org][link]]"}},
+ {"my talk ([[http://talks.golang.org/][slides here]])",
+ []string{"my", " ", "talk", " ", "(", "[[http://talks.golang.org/][slides here]]", ")"}},
+ }
+ for _, test := range tests {
+ out := split(test.in)
+ if !reflect.DeepEqual(out, test.out) {
+ t.Errorf("split(%q):\ngot\t%q\nwant\t%q", test.in, out, test.out)
+ }
+ }
+}
+
+func TestFont(t *testing.T) {
+ var tests = []struct {
+ in string
+ out string
+ }{
+ {"", ""},
+ {" ", " "},
+ {"\tx", "\tx"},
+ {"_a_", "<i>a</i>"},
+ {"*a*", "<b>a</b>"},
+ {"`a`", "<code>a</code>"},
+ {"_a_b_", "<i>a b</i>"},
+ {"_a__b_", "<i>a_b</i>"},
+ {"_a___b_", "<i>a_ b</i>"},
+ {"*a**b*?", "<b>a*b</b>?"},
+ {"_a_<>_b_.", "<i>a <> b</i>."},
+ {"(_a_)", "(<i>a</i>)"},
+ {"((_a_), _b_, _c_).", "((<i>a</i>), <i>b</i>, <i>c</i>)."},
+ {"(_a)", "(_a)"},
+ {"(_a)", "(_a)"},
+ {"_Why_use_scoped__ptr_? Use plain ***ptr* instead.", "<i>Why use scoped_ptr</i>? Use plain <b>*ptr</b> instead."},
+ {"_hey_ [[http://golang.org][*Gophers*]] *around*",
+ `<i>hey</i> <a href="http://golang.org" target="_blank"><b>Gophers</b></a> <b>around</b>`},
+ {"_hey_ [[http://golang.org][so _many_ *Gophers*]] *around*",
+ `<i>hey</i> <a href="http://golang.org" target="_blank">so <i>many</i> <b>Gophers</b></a> <b>around</b>`},
+ {"Visit [[http://golang.org]] now",
+ `Visit <a href="http://golang.org" target="_blank">golang.org</a> now`},
+ {"my talk ([[http://talks.golang.org/][slides here]])",
+ `my talk (<a href="http://talks.golang.org/" target="_blank">slides here</a>)`},
+ }
+ for _, test := range tests {
+ out := font(test.in)
+ if out != test.out {
+ t.Errorf("font(%q):\ngot\t%q\nwant\t%q", test.in, out, test.out)
+ }
+ }
+}
+
+func TestStyle(t *testing.T) {
+ var tests = []struct {
+ in string
+ out string
+ }{
+ {"", ""},
+ {" ", " "},
+ {"\tx", "\tx"},
+ {"_a_", "<i>a</i>"},
+ {"*a*", "<b>a</b>"},
+ {"`a`", "<code>a</code>"},
+ {"_a_b_", "<i>a b</i>"},
+ {"_a__b_", "<i>a_b</i>"},
+ {"_a___b_", "<i>a_ b</i>"},
+ {"*a**b*?", "<b>a*b</b>?"},
+ {"_a_<>_b_.", "<i>a <> b</i>."},
+ {"(_a_<>_b_)", "(<i>a <> b</i>)"},
+ {"((_a_), _b_, _c_).", "((<i>a</i>), <i>b</i>, <i>c</i>)."},
+ {"(_a)", "(_a)"},
+ }
+ for _, test := range tests {
+ out := string(Style(test.in))
+ if out != test.out {
+ t.Errorf("style(%q):\ngot\t%q\nwant\t%q", test.in, out, test.out)
+ }
+ }
+}
+
+func ExampleStyle() {
+ const s = "*Gophers* are _clearly_ > *cats*!"
+ fmt.Println(Style(s))
+ // Output: <b>Gophers</b> are <i>clearly</i> > <b>cats</b>!
+}
diff --git a/refactor/README b/refactor/README
new file mode 100644
index 0000000..a315784
--- /dev/null
+++ b/refactor/README
@@ -0,0 +1 @@
+golang.org/x/tools/refactor: libraries for refactoring tools.
diff --git a/refactor/eg/eg.go b/refactor/eg/eg.go
new file mode 100644
index 0000000..a609255
--- /dev/null
+++ b/refactor/eg/eg.go
@@ -0,0 +1,351 @@
+// Package eg implements the example-based refactoring tool whose
+// command-line is defined in golang.org/x/tools/cmd/eg.
+package eg // import "golang.org/x/tools/refactor/eg"
+
+import (
+ "bytes"
+ "fmt"
+ "go/ast"
+ "go/format"
+ "go/printer"
+ "go/token"
+ "os"
+
+ "golang.org/x/tools/go/loader"
+ "golang.org/x/tools/go/types"
+)
+
+const Help = `
+This tool implements example-based refactoring of expressions.
+
+The transformation is specified as a Go file defining two functions,
+'before' and 'after', of identical types. Each function body consists
+of a single statement: either a return statement with a single
+(possibly multi-valued) expression, or an expression statement. The
+'before' expression specifies a pattern and the 'after' expression its
+replacement.
+
+ package P
+ import ( "errors"; "fmt" )
+ func before(s string) error { return fmt.Errorf("%s", s) }
+ func after(s string) error { return errors.New(s) }
+
+The expression statement form is useful when the expression has no
+result, for example:
+
+ func before(msg string) { log.Fatalf("%s", msg) }
+ func after(msg string) { log.Fatal(msg) }
+
+The parameters of both functions are wildcards that may match any
+expression assignable to that type. If the pattern contains multiple
+occurrences of the same parameter, each must match the same expression
+in the input for the pattern to match. If the replacement contains
+multiple occurrences of the same parameter, the expression will be
+duplicated, possibly changing the side-effects.
+
+The tool analyses all Go code in the packages specified by the
+arguments, replacing all occurrences of the pattern with the
+substitution.
+
+So, the transform above would change this input:
+ err := fmt.Errorf("%s", "error: " + msg)
+to this output:
+ err := errors.New("error: " + msg)
+
+Identifiers, including qualified identifiers (p.X) are considered to
+match only if they denote the same object. This allows correct
+matching even in the presence of dot imports, named imports and
+locally shadowed package names in the input program.
+
+Matching of type syntax is semantic, not syntactic: type syntax in the
+pattern matches type syntax in the input if the types are identical.
+Thus, func(x int) matches func(y int).
+
+This tool was inspired by other example-based refactoring tools,
+'gofmt -r' for Go and Refaster for Java.
+
+
+LIMITATIONS
+===========
+
+EXPRESSIVENESS
+
+Only refactorings that replace one expression with another, regardless
+of the expression's context, may be expressed. Refactoring arbitrary
+statements (or sequences of statements) is a less well-defined problem
+and is less amenable to this approach.
+
+A pattern that contains a function literal (and hence statements)
+never matches.
+
+There is no way to generalize over related types, e.g. to express that
+a wildcard may have any integer type, for example.
+
+It is not possible to replace an expression by one of a different
+type, even in contexts where this is legal, such as x in fmt.Print(x).
+
+The struct literals T{x} and T{K: x} cannot both be matched by a single
+template.
+
+
+SAFETY
+
+Verifying that a transformation does not introduce type errors is very
+complex in the general case. An innocuous-looking replacement of one
+constant by another (e.g. 1 to 2) may cause type errors relating to
+array types and indices, for example. The tool performs only very
+superficial checks of type preservation.
+
+
+IMPORTS
+
+Although the matching algorithm is fully aware of scoping rules, the
+replacement algorithm is not, so the replacement code may contain
+incorrect identifier syntax for imported objects if there are dot
+imports, named imports or locally shadowed package names in the input
+program.
+
+Imports are added as needed, but they are not removed as needed.
+Run 'goimports' on the modified file for now.
+
+Dot imports are forbidden in the template.
+
+
+TIPS
+====
+
+Sometimes a little creativity is required to implement the desired
+migration. This section lists a few tips and tricks.
+
+To remove the final parameter from a function, temporarily change the
+function signature so that the final parameter is variadic, as this
+allows legal calls both with and without the argument. Then use eg to
+remove the final argument from all callers, and remove the variadic
+parameter by hand. The reverse process can be used to add a final
+parameter.
+
+To add or remove parameters other than the final one, you must do it in
+stages: (1) declare a variant function f' with a different name and the
+desired parameters; (2) use eg to transform calls to f into calls to f',
+changing the arguments as needed; (3) change the declaration of f to
+match f'; (4) use eg to rename f' to f in all calls; (5) delete f'.
+`
+
+// TODO(adonovan): allow the tool to be invoked using relative package
+// directory names (./foo). Requires changes to go/loader.
+
+// TODO(adonovan): expand upon the above documentation as an HTML page.
+
+// TODO(adonovan): eliminate dependency on loader.PackageInfo.
+// Move its TypeOf method into go/types.
+
+// A Transformer represents a single example-based transformation.
+type Transformer struct {
+ fset *token.FileSet
+ verbose bool
+ info loader.PackageInfo // combined type info for template/input/output ASTs
+ seenInfos map[*types.Info]bool
+ wildcards map[*types.Var]bool // set of parameters in func before()
+ env map[string]ast.Expr // maps parameter name to wildcard binding
+ importedObjs map[types.Object]*ast.SelectorExpr // objects imported by after().
+ before, after ast.Expr
+ allowWildcards bool
+
+ // Working state of Transform():
+ nsubsts int // number of substitutions made
+ currentPkg *types.Package // package of current call
+}
+
+// NewTransformer returns a transformer based on the specified template,
+// a package containing "before" and "after" functions as described
+// in the package documentation.
+//
+func NewTransformer(fset *token.FileSet, template *loader.PackageInfo, verbose bool) (*Transformer, error) {
+ // Check the template.
+ beforeSig := funcSig(template.Pkg, "before")
+ if beforeSig == nil {
+ return nil, fmt.Errorf("no 'before' func found in template")
+ }
+ afterSig := funcSig(template.Pkg, "after")
+ if afterSig == nil {
+ return nil, fmt.Errorf("no 'after' func found in template")
+ }
+
+ // TODO(adonovan): should we also check the names of the params match?
+ if !types.Identical(afterSig, beforeSig) {
+ return nil, fmt.Errorf("before %s and after %s functions have different signatures",
+ beforeSig, afterSig)
+ }
+
+ templateFile := template.Files[0]
+ for _, imp := range templateFile.Imports {
+ if imp.Name != nil && imp.Name.Name == "." {
+ // Dot imports are currently forbidden. We
+ // make the simplifying assumption that all
+ // imports are regular, without local renames.
+ //TODO document
+ return nil, fmt.Errorf("dot-import (of %s) in template", imp.Path.Value)
+ }
+ }
+ var beforeDecl, afterDecl *ast.FuncDecl
+ for _, decl := range templateFile.Decls {
+ if decl, ok := decl.(*ast.FuncDecl); ok {
+ switch decl.Name.Name {
+ case "before":
+ beforeDecl = decl
+ case "after":
+ afterDecl = decl
+ }
+ }
+ }
+
+ before, err := soleExpr(beforeDecl)
+ if err != nil {
+ return nil, fmt.Errorf("before: %s", err)
+ }
+ after, err := soleExpr(afterDecl)
+ if err != nil {
+ return nil, fmt.Errorf("after: %s", err)
+ }
+
+ wildcards := make(map[*types.Var]bool)
+ for i := 0; i < beforeSig.Params().Len(); i++ {
+ wildcards[beforeSig.Params().At(i)] = true
+ }
+
+ // checkExprTypes returns an error if Tb (type of before()) is not
+ // safe to replace with Ta (type of after()).
+ //
+ // Only superficial checks are performed, and they may result in both
+ // false positives and negatives.
+ //
+ // Ideally, we would only require that the replacement be assignable
+ // to the context of a specific pattern occurrence, but the type
+ // checker doesn't record that information and it's complex to deduce.
+ // A Go type cannot capture all the constraints of a given expression
+ // context, which may include the size, constness, signedness,
+ // namedness or constructor of its type, and even the specific value
+ // of the replacement. (Consider the rule that array literal keys
+ // must be unique.) So we cannot hope to prove the safety of a
+ // transformation in general.
+ Tb := template.TypeOf(before)
+ Ta := template.TypeOf(after)
+ if types.AssignableTo(Tb, Ta) {
+ // safe: replacement is assignable to pattern.
+ } else if tuple, ok := Tb.(*types.Tuple); ok && tuple.Len() == 0 {
+ // safe: pattern has void type (must appear in an ExprStmt).
+ } else {
+ return nil, fmt.Errorf("%s is not a safe replacement for %s", Ta, Tb)
+ }
+
+ tr := &Transformer{
+ fset: fset,
+ verbose: verbose,
+ wildcards: wildcards,
+ allowWildcards: true,
+ seenInfos: make(map[*types.Info]bool),
+ importedObjs: make(map[types.Object]*ast.SelectorExpr),
+ before: before,
+ after: after,
+ }
+
+ // Combine type info from the template and input packages, and
+ // type info for the synthesized ASTs too. This saves us
+ // having to book-keep where each ast.Node originated as we
+ // construct the resulting hybrid AST.
+ //
+ // TODO(adonovan): move type utility methods of PackageInfo to
+ // types.Info, or at least into go/types.typeutil.
+ tr.info.Info = types.Info{
+ Types: make(map[ast.Expr]types.TypeAndValue),
+ Defs: make(map[*ast.Ident]types.Object),
+ Uses: make(map[*ast.Ident]types.Object),
+ Selections: make(map[*ast.SelectorExpr]*types.Selection),
+ }
+ mergeTypeInfo(&tr.info.Info, &template.Info)
+
+ // Compute set of imported objects required by after().
+ // TODO reject dot-imports in pattern
+ ast.Inspect(after, func(n ast.Node) bool {
+ if n, ok := n.(*ast.SelectorExpr); ok {
+ if _, ok := tr.info.Selections[n]; !ok {
+ // qualified ident
+ obj := tr.info.Uses[n.Sel]
+ tr.importedObjs[obj] = n
+ return false // prune
+ }
+ }
+ return true // recur
+ })
+
+ return tr, nil
+}
+
+// WriteAST is a convenience function that writes AST f to the specified file.
+func WriteAST(fset *token.FileSet, filename string, f *ast.File) (err error) {
+ fh, err := os.Create(filename)
+ if err != nil {
+ return err
+ }
+ defer func() {
+ if err2 := fh.Close(); err != nil {
+ err = err2 // prefer earlier error
+ }
+ }()
+ return format.Node(fh, fset, f)
+}
+
+// -- utilities --------------------------------------------------------
+
+// funcSig returns the signature of the specified package-level function.
+func funcSig(pkg *types.Package, name string) *types.Signature {
+ if f, ok := pkg.Scope().Lookup(name).(*types.Func); ok {
+ return f.Type().(*types.Signature)
+ }
+ return nil
+}
+
+// soleExpr returns the sole expression in the before/after template function.
+func soleExpr(fn *ast.FuncDecl) (ast.Expr, error) {
+ if fn.Body == nil {
+ return nil, fmt.Errorf("no body")
+ }
+ if len(fn.Body.List) != 1 {
+ return nil, fmt.Errorf("must contain a single statement")
+ }
+ switch stmt := fn.Body.List[0].(type) {
+ case *ast.ReturnStmt:
+ if len(stmt.Results) != 1 {
+ return nil, fmt.Errorf("return statement must have a single operand")
+ }
+ return stmt.Results[0], nil
+
+ case *ast.ExprStmt:
+ return stmt.X, nil
+ }
+
+ return nil, fmt.Errorf("must contain a single return or expression statement")
+}
+
+// mergeTypeInfo adds type info from src to dst.
+func mergeTypeInfo(dst, src *types.Info) {
+ for k, v := range src.Types {
+ dst.Types[k] = v
+ }
+ for k, v := range src.Defs {
+ dst.Defs[k] = v
+ }
+ for k, v := range src.Uses {
+ dst.Uses[k] = v
+ }
+ for k, v := range src.Selections {
+ dst.Selections[k] = v
+ }
+}
+
+// (debugging only)
+func astString(fset *token.FileSet, n ast.Node) string {
+ var buf bytes.Buffer
+ printer.Fprint(&buf, fset, n)
+ return buf.String()
+}
diff --git a/refactor/eg/eg_test.go b/refactor/eg/eg_test.go
new file mode 100644
index 0000000..295e842
--- /dev/null
+++ b/refactor/eg/eg_test.go
@@ -0,0 +1,160 @@
+// 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 eg_test
+
+import (
+ "bytes"
+ "flag"
+ "go/parser"
+ "go/token"
+ "os"
+ "os/exec"
+ "path/filepath"
+ "runtime"
+ "strings"
+ "testing"
+
+ "golang.org/x/tools/go/exact"
+ "golang.org/x/tools/go/loader"
+ "golang.org/x/tools/go/types"
+ "golang.org/x/tools/refactor/eg"
+)
+
+// TODO(adonovan): more tests:
+// - of command-line tool
+// - of all parts of syntax
+// - of applying a template to a package it imports:
+// the replacement syntax should use unqualified names for its objects.
+
+var (
+ updateFlag = flag.Bool("update", false, "update the golden files")
+ verboseFlag = flag.Bool("verbose", false, "show matcher information")
+)
+
+func Test(t *testing.T) {
+ switch runtime.GOOS {
+ case "windows":
+ t.Skipf("skipping test on %q (no /usr/bin/diff)", runtime.GOOS)
+ }
+
+ conf := loader.Config{
+ Fset: token.NewFileSet(),
+ ParserMode: parser.ParseComments,
+ }
+
+ // Each entry is a single-file package.
+ // (Multi-file packages aren't interesting for this test.)
+ // Order matters: each non-template package is processed using
+ // the preceding template package.
+ for _, filename := range []string{
+ "testdata/A.template",
+ "testdata/A1.go",
+ "testdata/A2.go",
+
+ "testdata/B.template",
+ "testdata/B1.go",
+
+ "testdata/C.template",
+ "testdata/C1.go",
+
+ "testdata/D.template",
+ "testdata/D1.go",
+
+ "testdata/E.template",
+ "testdata/E1.go",
+
+ "testdata/F.template",
+ "testdata/F1.go",
+
+ "testdata/G.template",
+ "testdata/G1.go",
+
+ "testdata/H.template",
+ "testdata/H1.go",
+
+ "testdata/bad_type.template",
+ "testdata/no_before.template",
+ "testdata/no_after_return.template",
+ "testdata/type_mismatch.template",
+ "testdata/expr_type_mismatch.template",
+ } {
+ pkgname := strings.TrimSuffix(filepath.Base(filename), ".go")
+ conf.CreateFromFilenames(pkgname, filename)
+ }
+ iprog, err := conf.Load()
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ var xform *eg.Transformer
+ for _, info := range iprog.Created {
+ file := info.Files[0]
+ filename := iprog.Fset.File(file.Pos()).Name() // foo.go
+
+ if strings.HasSuffix(filename, "template") {
+ // a new template
+ shouldFail, _ := info.Pkg.Scope().Lookup("shouldFail").(*types.Const)
+ xform, err = eg.NewTransformer(iprog.Fset, info, *verboseFlag)
+ if err != nil {
+ if shouldFail == nil {
+ t.Errorf("NewTransformer(%s): %s", filename, err)
+ } else if want := exact.StringVal(shouldFail.Val()); !strings.Contains(err.Error(), want) {
+ t.Errorf("NewTransformer(%s): got error %q, want error %q", filename, err, want)
+ }
+ } else if shouldFail != nil {
+ t.Errorf("NewTransformer(%s) succeeded unexpectedly; want error %q",
+ filename, shouldFail.Val())
+ }
+ continue
+ }
+
+ if xform == nil {
+ t.Errorf("%s: no previous template", filename)
+ continue
+ }
+
+ // apply previous template to this package
+ n := xform.Transform(&info.Info, info.Pkg, file)
+ if n == 0 {
+ t.Errorf("%s: no matches", filename)
+ continue
+ }
+
+ got := filename + "t" // foo.got
+ golden := filename + "lden" // foo.golden
+
+ // Write actual output to foo.got.
+ if err := eg.WriteAST(iprog.Fset, got, file); err != nil {
+ t.Error(err)
+ }
+ defer os.Remove(got)
+
+ // Compare foo.got with foo.golden.
+ var cmd *exec.Cmd
+ switch runtime.GOOS {
+ case "plan9":
+ cmd = exec.Command("/bin/diff", "-c", golden, got)
+ default:
+ cmd = exec.Command("/usr/bin/diff", "-u", golden, got)
+ }
+ buf := new(bytes.Buffer)
+ cmd.Stdout = buf
+ cmd.Stderr = os.Stderr
+ if err := cmd.Run(); err != nil {
+ t.Errorf("eg tests for %s failed: %s.\n%s\n", filename, err, buf)
+
+ if *updateFlag {
+ t.Logf("Updating %s...", golden)
+ if err := exec.Command("/bin/cp", got, golden).Run(); err != nil {
+ t.Errorf("Update failed: %s", err)
+ }
+ }
+ }
+ }
+}
diff --git a/refactor/eg/match.go b/refactor/eg/match.go
new file mode 100644
index 0000000..d8590d4
--- /dev/null
+++ b/refactor/eg/match.go
@@ -0,0 +1,246 @@
+package eg
+
+import (
+ "fmt"
+ "go/ast"
+ "go/token"
+ "log"
+ "os"
+ "reflect"
+
+ "golang.org/x/tools/go/ast/astutil"
+ "golang.org/x/tools/go/exact"
+ "golang.org/x/tools/go/loader"
+ "golang.org/x/tools/go/types"
+)
+
+// matchExpr reports whether pattern x matches y.
+//
+// If tr.allowWildcards, Idents in x that refer to parameters are
+// treated as wildcards, and match any y that is assignable to the
+// parameter type; matchExpr records this correspondence in tr.env.
+// Otherwise, matchExpr simply reports whether the two trees are
+// equivalent.
+//
+// A wildcard appearing more than once in the pattern must
+// consistently match the same tree.
+//
+func (tr *Transformer) matchExpr(x, y ast.Expr) bool {
+ if x == nil && y == nil {
+ return true
+ }
+ if x == nil || y == nil {
+ return false
+ }
+ x = unparen(x)
+ y = unparen(y)
+
+ // Is x a wildcard? (a reference to a 'before' parameter)
+ if xobj, ok := tr.wildcardObj(x); ok {
+ return tr.matchWildcard(xobj, y)
+ }
+
+ // Object identifiers (including pkg-qualified ones)
+ // are handled semantically, not syntactically.
+ xobj := isRef(x, &tr.info)
+ yobj := isRef(y, &tr.info)
+ if xobj != nil {
+ return xobj == yobj
+ }
+ if yobj != nil {
+ return false
+ }
+
+ // TODO(adonovan): audit: we cannot assume these ast.Exprs
+ // contain non-nil pointers. e.g. ImportSpec.Name may be a
+ // nil *ast.Ident.
+
+ if reflect.TypeOf(x) != reflect.TypeOf(y) {
+ return false
+ }
+ switch x := x.(type) {
+ case *ast.Ident:
+ log.Fatalf("unexpected Ident: %s", astString(tr.fset, x))
+
+ case *ast.BasicLit:
+ y := y.(*ast.BasicLit)
+ xval := exact.MakeFromLiteral(x.Value, x.Kind)
+ yval := exact.MakeFromLiteral(y.Value, y.Kind)
+ return exact.Compare(xval, token.EQL, yval)
+
+ case *ast.FuncLit:
+ // func literals (and thus statement syntax) never match.
+ return false
+
+ case *ast.CompositeLit:
+ y := y.(*ast.CompositeLit)
+ return (x.Type == nil) == (y.Type == nil) &&
+ (x.Type == nil || tr.matchType(x.Type, y.Type)) &&
+ tr.matchExprs(x.Elts, y.Elts)
+
+ case *ast.SelectorExpr:
+ y := y.(*ast.SelectorExpr)
+ return tr.matchSelectorExpr(x, y) &&
+ tr.info.Selections[x].Obj() == tr.info.Selections[y].Obj()
+
+ case *ast.IndexExpr:
+ y := y.(*ast.IndexExpr)
+ return tr.matchExpr(x.X, y.X) &&
+ tr.matchExpr(x.Index, y.Index)
+
+ case *ast.SliceExpr:
+ y := y.(*ast.SliceExpr)
+ return tr.matchExpr(x.X, y.X) &&
+ tr.matchExpr(x.Low, y.Low) &&
+ tr.matchExpr(x.High, y.High) &&
+ tr.matchExpr(x.Max, y.Max) &&
+ x.Slice3 == y.Slice3
+
+ case *ast.TypeAssertExpr:
+ y := y.(*ast.TypeAssertExpr)
+ return tr.matchExpr(x.X, y.X) &&
+ tr.matchType(x.Type, y.Type)
+
+ case *ast.CallExpr:
+ y := y.(*ast.CallExpr)
+ match := tr.matchExpr // function call
+ if tr.info.Types[x.Fun].IsType() {
+ match = tr.matchType // type conversion
+ }
+ return x.Ellipsis.IsValid() == y.Ellipsis.IsValid() &&
+ match(x.Fun, y.Fun) &&
+ tr.matchExprs(x.Args, y.Args)
+
+ case *ast.StarExpr:
+ y := y.(*ast.StarExpr)
+ return tr.matchExpr(x.X, y.X)
+
+ case *ast.UnaryExpr:
+ y := y.(*ast.UnaryExpr)
+ return x.Op == y.Op &&
+ tr.matchExpr(x.X, y.X)
+
+ case *ast.BinaryExpr:
+ y := y.(*ast.BinaryExpr)
+ return x.Op == y.Op &&
+ tr.matchExpr(x.X, y.X) &&
+ tr.matchExpr(x.Y, y.Y)
+
+ case *ast.KeyValueExpr:
+ y := y.(*ast.KeyValueExpr)
+ return tr.matchExpr(x.Key, y.Key) &&
+ tr.matchExpr(x.Value, y.Value)
+ }
+
+ panic(fmt.Sprintf("unhandled AST node type: %T", x))
+}
+
+func (tr *Transformer) matchExprs(xx, yy []ast.Expr) bool {
+ if len(xx) != len(yy) {
+ return false
+ }
+ for i := range xx {
+ if !tr.matchExpr(xx[i], yy[i]) {
+ return false
+ }
+ }
+ return true
+}
+
+// matchType reports whether the two type ASTs denote identical types.
+func (tr *Transformer) matchType(x, y ast.Expr) bool {
+ tx := tr.info.Types[x].Type
+ ty := tr.info.Types[y].Type
+ return types.Identical(tx, ty)
+}
+
+func (tr *Transformer) wildcardObj(x ast.Expr) (*types.Var, bool) {
+ if x, ok := x.(*ast.Ident); ok && x != nil && tr.allowWildcards {
+ if xobj, ok := tr.info.Uses[x].(*types.Var); ok && tr.wildcards[xobj] {
+ return xobj, true
+ }
+ }
+ return nil, false
+}
+
+func (tr *Transformer) matchSelectorExpr(x, y *ast.SelectorExpr) bool {
+ if xobj, ok := tr.wildcardObj(x.X); ok {
+ field := x.Sel.Name
+ yt := tr.info.TypeOf(y.X)
+ o, _, _ := types.LookupFieldOrMethod(yt, true, tr.currentPkg, field)
+ if o != nil {
+ tr.env[xobj.Name()] = y.X // record binding
+ return true
+ }
+ }
+ return tr.matchExpr(x.X, y.X)
+}
+
+func (tr *Transformer) matchWildcard(xobj *types.Var, y ast.Expr) bool {
+ name := xobj.Name()
+
+ if tr.verbose {
+ fmt.Fprintf(os.Stderr, "%s: wildcard %s -> %s?: ",
+ tr.fset.Position(y.Pos()), name, astString(tr.fset, y))
+ }
+
+ // Check that y is assignable to the declared type of the param.
+ yt := tr.info.TypeOf(y)
+ if yt == nil {
+ // y has no type.
+ // Perhaps it is an *ast.Ellipsis in [...]T{}, or
+ // an *ast.KeyValueExpr in T{k: v}.
+ // Clearly these pseudo-expressions cannot match a
+ // wildcard, but it would nice if we had a way to ignore
+ // the difference between T{v} and T{k:v} for structs.
+ return false
+ }
+ if !types.AssignableTo(yt, xobj.Type()) {
+ if tr.verbose {
+ fmt.Fprintf(os.Stderr, "%s not assignable to %s\n", yt, xobj.Type())
+ }
+ return false
+ }
+
+ // A wildcard matches any expression.
+ // If it appears multiple times in the pattern, it must match
+ // the same expression each time.
+ if old, ok := tr.env[name]; ok {
+ // found existing binding
+ tr.allowWildcards = false
+ r := tr.matchExpr(old, y)
+ if tr.verbose {
+ fmt.Fprintf(os.Stderr, "%t secondary match, primary was %s\n",
+ r, astString(tr.fset, old))
+ }
+ tr.allowWildcards = true
+ return r
+ }
+
+ if tr.verbose {
+ fmt.Fprintf(os.Stderr, "primary match\n")
+ }
+
+ tr.env[name] = y // record binding
+ return true
+}
+
+// -- utilities --------------------------------------------------------
+
+func unparen(e ast.Expr) ast.Expr { return astutil.Unparen(e) }
+
+// isRef returns the object referred to by this (possibly qualified)
+// identifier, or nil if the node is not a referring identifier.
+func isRef(n ast.Node, info *loader.PackageInfo) types.Object {
+ switch n := n.(type) {
+ case *ast.Ident:
+ return info.Uses[n]
+
+ case *ast.SelectorExpr:
+ if _, ok := info.Selections[n]; !ok {
+ // qualified ident
+ return info.Uses[n.Sel]
+ }
+ }
+ return nil
+}
diff --git a/refactor/eg/rewrite.go b/refactor/eg/rewrite.go
new file mode 100644
index 0000000..db9c693
--- /dev/null
+++ b/refactor/eg/rewrite.go
@@ -0,0 +1,340 @@
+package eg
+
+// This file defines the AST rewriting pass.
+// Most of it was plundered directly from
+// $GOROOT/src/cmd/gofmt/rewrite.go (after convergent evolution).
+
+import (
+ "fmt"
+ "go/ast"
+ "go/token"
+ "os"
+ "reflect"
+ "sort"
+ "strconv"
+ "strings"
+
+ "golang.org/x/tools/go/ast/astutil"
+ "golang.org/x/tools/go/types"
+)
+
+// Transform applies the transformation to the specified parsed file,
+// whose type information is supplied in info, and returns the number
+// of replacements that were made.
+//
+// It mutates the AST in place (the identity of the root node is
+// unchanged), and may add nodes for which no type information is
+// available in info.
+//
+// Derived from rewriteFile in $GOROOT/src/cmd/gofmt/rewrite.go.
+//
+func (tr *Transformer) Transform(info *types.Info, pkg *types.Package, file *ast.File) int {
+ if !tr.seenInfos[info] {
+ tr.seenInfos[info] = true
+ mergeTypeInfo(&tr.info.Info, info)
+ }
+ tr.currentPkg = pkg
+ tr.nsubsts = 0
+
+ if tr.verbose {
+ fmt.Fprintf(os.Stderr, "before: %s\n", astString(tr.fset, tr.before))
+ fmt.Fprintf(os.Stderr, "after: %s\n", astString(tr.fset, tr.after))
+ }
+
+ var f func(rv reflect.Value) reflect.Value
+ f = func(rv reflect.Value) reflect.Value {
+ // don't bother if val is invalid to start with
+ if !rv.IsValid() {
+ return reflect.Value{}
+ }
+
+ rv = apply(f, rv)
+
+ e := rvToExpr(rv)
+ if e != nil {
+ savedEnv := tr.env
+ tr.env = make(map[string]ast.Expr) // inefficient! Use a slice of k/v pairs
+
+ if tr.matchExpr(tr.before, e) {
+ if tr.verbose {
+ fmt.Fprintf(os.Stderr, "%s matches %s",
+ astString(tr.fset, tr.before), astString(tr.fset, e))
+ if len(tr.env) > 0 {
+ fmt.Fprintf(os.Stderr, " with:")
+ for name, ast := range tr.env {
+ fmt.Fprintf(os.Stderr, " %s->%s",
+ name, astString(tr.fset, ast))
+ }
+ }
+ fmt.Fprintf(os.Stderr, "\n")
+ }
+ tr.nsubsts++
+
+ // Clone the replacement tree, performing parameter substitution.
+ // We update all positions to n.Pos() to aid comment placement.
+ rv = tr.subst(tr.env, reflect.ValueOf(tr.after),
+ reflect.ValueOf(e.Pos()))
+ }
+ tr.env = savedEnv
+ }
+
+ return rv
+ }
+ file2 := apply(f, reflect.ValueOf(file)).Interface().(*ast.File)
+
+ // By construction, the root node is unchanged.
+ if file != file2 {
+ panic("BUG")
+ }
+
+ // Add any necessary imports.
+ // TODO(adonovan): remove no-longer needed imports too.
+ if tr.nsubsts > 0 {
+ pkgs := make(map[string]*types.Package)
+ for obj := range tr.importedObjs {
+ pkgs[obj.Pkg().Path()] = obj.Pkg()
+ }
+
+ for _, imp := range file.Imports {
+ path, _ := strconv.Unquote(imp.Path.Value)
+ delete(pkgs, path)
+ }
+ delete(pkgs, pkg.Path()) // don't import self
+
+ // NB: AddImport may completely replace the AST!
+ // It thus renders info and tr.info no longer relevant to file.
+ var paths []string
+ for path := range pkgs {
+ paths = append(paths, path)
+ }
+ sort.Strings(paths)
+ for _, path := range paths {
+ astutil.AddImport(tr.fset, file, path)
+ }
+ }
+
+ tr.currentPkg = nil
+
+ return tr.nsubsts
+}
+
+// setValue is a wrapper for x.SetValue(y); it protects
+// the caller from panics if x cannot be changed to y.
+func setValue(x, y reflect.Value) {
+ // don't bother if y is invalid to start with
+ if !y.IsValid() {
+ return
+ }
+ defer func() {
+ if x := recover(); x != nil {
+ if s, ok := x.(string); ok &&
+ (strings.Contains(s, "type mismatch") || strings.Contains(s, "not assignable")) {
+ // x cannot be set to y - ignore this rewrite
+ return
+ }
+ panic(x)
+ }
+ }()
+ x.Set(y)
+}
+
+// Values/types for special cases.
+var (
+ objectPtrNil = reflect.ValueOf((*ast.Object)(nil))
+ scopePtrNil = reflect.ValueOf((*ast.Scope)(nil))
+
+ identType = reflect.TypeOf((*ast.Ident)(nil))
+ selectorExprType = reflect.TypeOf((*ast.SelectorExpr)(nil))
+ objectPtrType = reflect.TypeOf((*ast.Object)(nil))
+ positionType = reflect.TypeOf(token.NoPos)
+ callExprType = reflect.TypeOf((*ast.CallExpr)(nil))
+ scopePtrType = reflect.TypeOf((*ast.Scope)(nil))
+)
+
+// apply replaces each AST field x in val with f(x), returning val.
+// To avoid extra conversions, f operates on the reflect.Value form.
+func apply(f func(reflect.Value) reflect.Value, val reflect.Value) reflect.Value {
+ if !val.IsValid() {
+ return reflect.Value{}
+ }
+
+ // *ast.Objects introduce cycles and are likely incorrect after
+ // rewrite; don't follow them but replace with nil instead
+ if val.Type() == objectPtrType {
+ return objectPtrNil
+ }
+
+ // similarly for scopes: they are likely incorrect after a rewrite;
+ // replace them with nil
+ if val.Type() == scopePtrType {
+ return scopePtrNil
+ }
+
+ switch v := reflect.Indirect(val); v.Kind() {
+ case reflect.Slice:
+ for i := 0; i < v.Len(); i++ {
+ e := v.Index(i)
+ setValue(e, f(e))
+ }
+ case reflect.Struct:
+ for i := 0; i < v.NumField(); i++ {
+ e := v.Field(i)
+ setValue(e, f(e))
+ }
+ case reflect.Interface:
+ e := v.Elem()
+ setValue(v, f(e))
+ }
+ return val
+}
+
+// subst returns a copy of (replacement) pattern with values from env
+// substituted in place of wildcards and pos used as the position of
+// tokens from the pattern. if env == nil, subst returns a copy of
+// pattern and doesn't change the line number information.
+func (tr *Transformer) subst(env map[string]ast.Expr, pattern, pos reflect.Value) reflect.Value {
+ if !pattern.IsValid() {
+ return reflect.Value{}
+ }
+
+ // *ast.Objects introduce cycles and are likely incorrect after
+ // rewrite; don't follow them but replace with nil instead
+ if pattern.Type() == objectPtrType {
+ return objectPtrNil
+ }
+
+ // similarly for scopes: they are likely incorrect after a rewrite;
+ // replace them with nil
+ if pattern.Type() == scopePtrType {
+ return scopePtrNil
+ }
+
+ // Wildcard gets replaced with map value.
+ if env != nil && pattern.Type() == identType {
+ id := pattern.Interface().(*ast.Ident)
+ if old, ok := env[id.Name]; ok {
+ return tr.subst(nil, reflect.ValueOf(old), reflect.Value{})
+ }
+ }
+
+ // Emit qualified identifiers in the pattern by appropriate
+ // (possibly qualified) identifier in the input.
+ //
+ // The template cannot contain dot imports, so all identifiers
+ // for imported objects are explicitly qualified.
+ //
+ // We assume (unsoundly) that there are no dot or named
+ // imports in the input code, nor are any imported package
+ // names shadowed, so the usual normal qualified identifier
+ // syntax may be used.
+ // TODO(adonovan): fix: avoid this assumption.
+ //
+ // A refactoring may be applied to a package referenced by the
+ // template. Objects belonging to the current package are
+ // denoted by unqualified identifiers.
+ //
+ if tr.importedObjs != nil && pattern.Type() == selectorExprType {
+ obj := isRef(pattern.Interface().(*ast.SelectorExpr), &tr.info)
+ if obj != nil {
+ if sel, ok := tr.importedObjs[obj]; ok {
+ var id ast.Expr
+ if obj.Pkg() == tr.currentPkg {
+ id = sel.Sel // unqualified
+ } else {
+ id = sel // pkg-qualified
+ }
+
+ // Return a clone of id.
+ saved := tr.importedObjs
+ tr.importedObjs = nil // break cycle
+ r := tr.subst(nil, reflect.ValueOf(id), pos)
+ tr.importedObjs = saved
+ return r
+ }
+ }
+ }
+
+ if pos.IsValid() && pattern.Type() == positionType {
+ // use new position only if old position was valid in the first place
+ if old := pattern.Interface().(token.Pos); !old.IsValid() {
+ return pattern
+ }
+ return pos
+ }
+
+ // Otherwise copy.
+ switch p := pattern; p.Kind() {
+ case reflect.Slice:
+ v := reflect.MakeSlice(p.Type(), p.Len(), p.Len())
+ for i := 0; i < p.Len(); i++ {
+ v.Index(i).Set(tr.subst(env, p.Index(i), pos))
+ }
+ return v
+
+ case reflect.Struct:
+ v := reflect.New(p.Type()).Elem()
+ for i := 0; i < p.NumField(); i++ {
+ v.Field(i).Set(tr.subst(env, p.Field(i), pos))
+ }
+ return v
+
+ case reflect.Ptr:
+ v := reflect.New(p.Type()).Elem()
+ if elem := p.Elem(); elem.IsValid() {
+ v.Set(tr.subst(env, elem, pos).Addr())
+ }
+
+ // Duplicate type information for duplicated ast.Expr.
+ // All ast.Node implementations are *structs,
+ // so this case catches them all.
+ if e := rvToExpr(v); e != nil {
+ updateTypeInfo(&tr.info.Info, e, p.Interface().(ast.Expr))
+ }
+ return v
+
+ case reflect.Interface:
+ v := reflect.New(p.Type()).Elem()
+ if elem := p.Elem(); elem.IsValid() {
+ v.Set(tr.subst(env, elem, pos))
+ }
+ return v
+ }
+
+ return pattern
+}
+
+// -- utilities -------------------------------------------------------
+
+func rvToExpr(rv reflect.Value) ast.Expr {
+ if rv.CanInterface() {
+ if e, ok := rv.Interface().(ast.Expr); ok {
+ return e
+ }
+ }
+ return nil
+}
+
+// updateTypeInfo duplicates type information for the existing AST old
+// so that it also applies to duplicated AST new.
+func updateTypeInfo(info *types.Info, new, old ast.Expr) {
+ switch new := new.(type) {
+ case *ast.Ident:
+ orig := old.(*ast.Ident)
+ if obj, ok := info.Defs[orig]; ok {
+ info.Defs[new] = obj
+ }
+ if obj, ok := info.Uses[orig]; ok {
+ info.Uses[new] = obj
+ }
+
+ case *ast.SelectorExpr:
+ orig := old.(*ast.SelectorExpr)
+ if sel, ok := info.Selections[orig]; ok {
+ info.Selections[new] = sel
+ }
+ }
+
+ if tv, ok := info.Types[old]; ok {
+ info.Types[new] = tv
+ }
+}
diff --git a/refactor/eg/testdata/A.template b/refactor/eg/testdata/A.template
new file mode 100644
index 0000000..f611961
--- /dev/null
+++ b/refactor/eg/testdata/A.template
@@ -0,0 +1,13 @@
+// +build ignore
+
+package template
+
+// Basic test of type-aware expression refactoring.
+
+import (
+ "errors"
+ "fmt"
+)
+
+func before(s string) error { return fmt.Errorf("%s", s) }
+func after(s string) error { return errors.New(s) }
diff --git a/refactor/eg/testdata/A1.go b/refactor/eg/testdata/A1.go
new file mode 100644
index 0000000..9e65eb3
--- /dev/null
+++ b/refactor/eg/testdata/A1.go
@@ -0,0 +1,51 @@
+// +build ignore
+
+package A1
+
+import (
+ . "fmt"
+ myfmt "fmt"
+ "os"
+ "strings"
+)
+
+func example(n int) {
+ x := "foo" + strings.Repeat("\t", n)
+ // Match, despite named import.
+ myfmt.Errorf("%s", x)
+
+ // Match, despite dot import.
+ Errorf("%s", x)
+
+ // Match: multiple matches in same function are possible.
+ myfmt.Errorf("%s", x)
+
+ // No match: wildcarded operand has the wrong type.
+ myfmt.Errorf("%s", 3)
+
+ // No match: function operand doesn't match.
+ myfmt.Printf("%s", x)
+
+ // No match again, dot import.
+ Printf("%s", x)
+
+ // Match.
+ myfmt.Fprint(os.Stderr, myfmt.Errorf("%s", x+"foo"))
+
+ // No match: though this literally matches the template,
+ // fmt doesn't resolve to a package here.
+ var fmt struct{ Errorf func(string, string) }
+ fmt.Errorf("%s", x)
+
+ // Recursive matching:
+
+ // Match: both matches are well-typed, so both succeed.
+ myfmt.Errorf("%s", myfmt.Errorf("%s", x+"foo").Error())
+
+ // Outer match succeeds, inner doesn't: 3 has wrong type.
+ myfmt.Errorf("%s", myfmt.Errorf("%s", 3).Error())
+
+ // Inner match succeeds, outer doesn't: the inner replacement
+ // has the wrong type (error not string).
+ myfmt.Errorf("%s", myfmt.Errorf("%s", x+"foo"))
+}
diff --git a/refactor/eg/testdata/A1.golden b/refactor/eg/testdata/A1.golden
new file mode 100644
index 0000000..7eb2934
--- /dev/null
+++ b/refactor/eg/testdata/A1.golden
@@ -0,0 +1,52 @@
+// +build ignore
+
+package A1
+
+import (
+ "errors"
+ . "fmt"
+ myfmt "fmt"
+ "os"
+ "strings"
+)
+
+func example(n int) {
+ x := "foo" + strings.Repeat("\t", n)
+ // Match, despite named import.
+ errors.New(x)
+
+ // Match, despite dot import.
+ errors.New(x)
+
+ // Match: multiple matches in same function are possible.
+ errors.New(x)
+
+ // No match: wildcarded operand has the wrong type.
+ myfmt.Errorf("%s", 3)
+
+ // No match: function operand doesn't match.
+ myfmt.Printf("%s", x)
+
+ // No match again, dot import.
+ Printf("%s", x)
+
+ // Match.
+ myfmt.Fprint(os.Stderr, errors.New(x+"foo"))
+
+ // No match: though this literally matches the template,
+ // fmt doesn't resolve to a package here.
+ var fmt struct{ Errorf func(string, string) }
+ fmt.Errorf("%s", x)
+
+ // Recursive matching:
+
+ // Match: both matches are well-typed, so both succeed.
+ errors.New(errors.New(x + "foo").Error())
+
+ // Outer match succeeds, inner doesn't: 3 has wrong type.
+ errors.New(myfmt.Errorf("%s", 3).Error())
+
+ // Inner match succeeds, outer doesn't: the inner replacement
+ // has the wrong type (error not string).
+ myfmt.Errorf("%s", errors.New(x+"foo"))
+}
diff --git a/refactor/eg/testdata/A2.go b/refactor/eg/testdata/A2.go
new file mode 100644
index 0000000..3ae29ad
--- /dev/null
+++ b/refactor/eg/testdata/A2.go
@@ -0,0 +1,12 @@
+// +build ignore
+
+package A2
+
+// This refactoring causes addition of "errors" import.
+// TODO(adonovan): fix: it should also remove "fmt".
+
+import myfmt "fmt"
+
+func example(n int) {
+ myfmt.Errorf("%s", "")
+}
diff --git a/refactor/eg/testdata/A2.golden b/refactor/eg/testdata/A2.golden
new file mode 100644
index 0000000..b6e3a6d
--- /dev/null
+++ b/refactor/eg/testdata/A2.golden
@@ -0,0 +1,15 @@
+// +build ignore
+
+package A2
+
+// This refactoring causes addition of "errors" import.
+// TODO(adonovan): fix: it should also remove "fmt".
+
+import (
+ "errors"
+ myfmt "fmt"
+)
+
+func example(n int) {
+ errors.New("")
+}
diff --git a/refactor/eg/testdata/B.template b/refactor/eg/testdata/B.template
new file mode 100644
index 0000000..c16627b
--- /dev/null
+++ b/refactor/eg/testdata/B.template
@@ -0,0 +1,9 @@
+package template
+
+// Basic test of expression refactoring.
+// (Types are not important in this case; it could be done with gofmt -r.)
+
+import "time"
+
+func before(t time.Time) time.Duration { return time.Now().Sub(t) }
+func after(t time.Time) time.Duration { return time.Since(t) }
diff --git a/refactor/eg/testdata/B1.go b/refactor/eg/testdata/B1.go
new file mode 100644
index 0000000..8b52546
--- /dev/null
+++ b/refactor/eg/testdata/B1.go
@@ -0,0 +1,17 @@
+// +build ignore
+
+package B1
+
+import "time"
+
+var startup = time.Now()
+
+func example() time.Duration {
+ before := time.Now()
+ time.Sleep(1)
+ return time.Now().Sub(before)
+}
+
+func msSinceStartup() int64 {
+ return int64(time.Now().Sub(startup) / time.Millisecond)
+}
diff --git a/refactor/eg/testdata/B1.golden b/refactor/eg/testdata/B1.golden
new file mode 100644
index 0000000..4d4da21
--- /dev/null
+++ b/refactor/eg/testdata/B1.golden
@@ -0,0 +1,17 @@
+// +build ignore
+
+package B1
+
+import "time"
+
+var startup = time.Now()
+
+func example() time.Duration {
+ before := time.Now()
+ time.Sleep(1)
+ return time.Since(before)
+}
+
+func msSinceStartup() int64 {
+ return int64(time.Since(startup) / time.Millisecond)
+}
diff --git a/refactor/eg/testdata/C.template b/refactor/eg/testdata/C.template
new file mode 100644
index 0000000..f6f94d4
--- /dev/null
+++ b/refactor/eg/testdata/C.template
@@ -0,0 +1,10 @@
+package template
+
+// Test of repeated use of wildcard in pattern.
+
+// NB: multiple patterns would be required to handle variants such as
+// s[:len(s)], s[x:len(s)], etc, since a wildcard can't match nothing at all.
+// TODO(adonovan): support multiple templates in a single pass.
+
+func before(s string) string { return s[:len(s)] }
+func after(s string) string { return s }
diff --git a/refactor/eg/testdata/C1.go b/refactor/eg/testdata/C1.go
new file mode 100644
index 0000000..523b388
--- /dev/null
+++ b/refactor/eg/testdata/C1.go
@@ -0,0 +1,22 @@
+// +build ignore
+
+package C1
+
+import "strings"
+
+func example() {
+ x := "foo"
+ println(x[:len(x)])
+
+ // Match, but the transformation is not sound w.r.t. possible side effects.
+ println(strings.Repeat("*", 3)[:len(strings.Repeat("*", 3))])
+
+ // No match, since second use of wildcard doesn't match first.
+ println(strings.Repeat("*", 3)[:len(strings.Repeat("*", 2))])
+
+ // Recursive match demonstrating bottom-up rewrite:
+ // only after the inner replacement occurs does the outer syntax match.
+ println((x[:len(x)])[:len(x[:len(x)])])
+ // -> (x[:len(x)])
+ // -> x
+}
diff --git a/refactor/eg/testdata/C1.golden b/refactor/eg/testdata/C1.golden
new file mode 100644
index 0000000..ae7759d
--- /dev/null
+++ b/refactor/eg/testdata/C1.golden
@@ -0,0 +1,22 @@
+// +build ignore
+
+package C1
+
+import "strings"
+
+func example() {
+ x := "foo"
+ println(x)
+
+ // Match, but the transformation is not sound w.r.t. possible side effects.
+ println(strings.Repeat("*", 3))
+
+ // No match, since second use of wildcard doesn't match first.
+ println(strings.Repeat("*", 3)[:len(strings.Repeat("*", 2))])
+
+ // Recursive match demonstrating bottom-up rewrite:
+ // only after the inner replacement occurs does the outer syntax match.
+ println(x)
+ // -> (x[:len(x)])
+ // -> x
+}
diff --git a/refactor/eg/testdata/D.template b/refactor/eg/testdata/D.template
new file mode 100644
index 0000000..6d3b6fe
--- /dev/null
+++ b/refactor/eg/testdata/D.template
@@ -0,0 +1,8 @@
+package template
+
+import "fmt"
+
+// Test of semantic (not syntactic) matching of basic literals.
+
+func before() (int, error) { return fmt.Println(123, "a") }
+func after() (int, error) { return fmt.Println(456, "!") }
diff --git a/refactor/eg/testdata/D1.go b/refactor/eg/testdata/D1.go
new file mode 100644
index 0000000..ae0a806
--- /dev/null
+++ b/refactor/eg/testdata/D1.go
@@ -0,0 +1,12 @@
+// +build ignore
+
+package D1
+
+import "fmt"
+
+func example() {
+ fmt.Println(123, "a") // match
+ fmt.Println(0x7b, `a`) // match
+ fmt.Println(0173, "\x61") // match
+ fmt.Println(100+20+3, "a"+"") // no match: constant expressions, but not basic literals
+}
diff --git a/refactor/eg/testdata/D1.golden b/refactor/eg/testdata/D1.golden
new file mode 100644
index 0000000..2932652
--- /dev/null
+++ b/refactor/eg/testdata/D1.golden
@@ -0,0 +1,12 @@
+// +build ignore
+
+package D1
+
+import "fmt"
+
+func example() {
+ fmt.Println(456, "!") // match
+ fmt.Println(456, "!") // match
+ fmt.Println(456, "!") // match
+ fmt.Println(100+20+3, "a"+"") // no match: constant expressions, but not basic literals
+}
diff --git a/refactor/eg/testdata/E.template b/refactor/eg/testdata/E.template
new file mode 100644
index 0000000..4bbbd11
--- /dev/null
+++ b/refactor/eg/testdata/E.template
@@ -0,0 +1,12 @@
+package template
+
+import (
+ "fmt"
+ "log"
+ "os"
+)
+
+// Replace call to void function by call to non-void function.
+
+func before(x interface{}) { log.Fatal(x) }
+func after(x interface{}) { fmt.Fprintf(os.Stderr, "warning: %v", x) }
diff --git a/refactor/eg/testdata/E1.go b/refactor/eg/testdata/E1.go
new file mode 100644
index 0000000..3ea1793
--- /dev/null
+++ b/refactor/eg/testdata/E1.go
@@ -0,0 +1,9 @@
+// +build ignore
+
+package E1
+
+import "log"
+
+func example() {
+ log.Fatal("oops") // match
+}
diff --git a/refactor/eg/testdata/E1.golden b/refactor/eg/testdata/E1.golden
new file mode 100644
index 0000000..796364f
--- /dev/null
+++ b/refactor/eg/testdata/E1.golden
@@ -0,0 +1,13 @@
+// +build ignore
+
+package E1
+
+import (
+ "fmt"
+ "log"
+ "os"
+)
+
+func example() {
+ fmt.Fprintf(os.Stderr, "warning: %v", "oops") // match
+}
diff --git a/refactor/eg/testdata/F.template b/refactor/eg/testdata/F.template
new file mode 100644
index 0000000..21e1bd2
--- /dev/null
+++ b/refactor/eg/testdata/F.template
@@ -0,0 +1,8 @@
+package templates
+
+// Test
+
+import "sync"
+
+func before(s sync.RWMutex) { s.Lock() }
+func after(s sync.RWMutex) { s.RLock() }
\ No newline at end of file
diff --git a/refactor/eg/testdata/F1.go b/refactor/eg/testdata/F1.go
new file mode 100644
index 0000000..2258abd
--- /dev/null
+++ b/refactor/eg/testdata/F1.go
@@ -0,0 +1,48 @@
+// +build ignore
+
+package F1
+
+import "sync"
+
+func example(n int) {
+ var x struct {
+ mutex sync.RWMutex
+ }
+
+ var y struct {
+ sync.RWMutex
+ }
+
+ type l struct {
+ sync.RWMutex
+ }
+
+ var z struct {
+ l
+ }
+
+ var a struct {
+ *l
+ }
+
+ var b struct{ Lock func() }
+
+ // Match
+ x.mutex.Lock()
+
+ // Match
+ y.Lock()
+
+ // Match indirect
+ z.Lock()
+
+ // Should be no match however currently matches due to:
+ // https://golang.org/issue/8584
+ // Will start failing when this is fixed then just change golden to
+ // No match pointer indirect
+ // a.Lock()
+ a.Lock()
+
+ // No match
+ b.Lock()
+}
diff --git a/refactor/eg/testdata/F1.golden b/refactor/eg/testdata/F1.golden
new file mode 100644
index 0000000..5ffda69
--- /dev/null
+++ b/refactor/eg/testdata/F1.golden
@@ -0,0 +1,48 @@
+// +build ignore
+
+package F1
+
+import "sync"
+
+func example(n int) {
+ var x struct {
+ mutex sync.RWMutex
+ }
+
+ var y struct {
+ sync.RWMutex
+ }
+
+ type l struct {
+ sync.RWMutex
+ }
+
+ var z struct {
+ l
+ }
+
+ var a struct {
+ *l
+ }
+
+ var b struct{ Lock func() }
+
+ // Match
+ x.mutex.RLock()
+
+ // Match
+ y.RLock()
+
+ // Match indirect
+ z.RLock()
+
+ // Should be no match however currently matches due to:
+ // https://golang.org/issue/8584
+ // Will start failing when this is fixed then just change golden to
+ // No match pointer indirect
+ // a.Lock()
+ a.RLock()
+
+ // No match
+ b.Lock()
+}
diff --git a/refactor/eg/testdata/G.template b/refactor/eg/testdata/G.template
new file mode 100644
index 0000000..69d84fe
--- /dev/null
+++ b/refactor/eg/testdata/G.template
@@ -0,0 +1,10 @@
+package templates
+
+import (
+ "go/ast" // defines many unencapsulated structs
+ "go/token"
+)
+
+func before(from, to token.Pos) ast.BadExpr { return ast.BadExpr{From: from, To: to} }
+func after(from, to token.Pos) ast.BadExpr { return ast.BadExpr{from, to} }
+
\ No newline at end of file
diff --git a/refactor/eg/testdata/G1.go b/refactor/eg/testdata/G1.go
new file mode 100644
index 0000000..07aaff9
--- /dev/null
+++ b/refactor/eg/testdata/G1.go
@@ -0,0 +1,12 @@
+// +build ignore
+
+package G1
+
+import "go/ast"
+
+func example() {
+ _ = ast.BadExpr{From: 123, To: 456} // match
+ _ = ast.BadExpr{123, 456} // no match
+ _ = ast.BadExpr{From: 123} // no match
+ _ = ast.BadExpr{To: 456} // no match
+}
diff --git a/refactor/eg/testdata/G1.golden b/refactor/eg/testdata/G1.golden
new file mode 100644
index 0000000..c93c53f
--- /dev/null
+++ b/refactor/eg/testdata/G1.golden
@@ -0,0 +1,12 @@
+// +build ignore
+
+package G1
+
+import "go/ast"
+
+func example() {
+ _ = ast.BadExpr{123, 456} // match
+ _ = ast.BadExpr{123, 456} // no match
+ _ = ast.BadExpr{From: 123} // no match
+ _ = ast.BadExpr{To: 456} // no match
+}
diff --git a/refactor/eg/testdata/H.template b/refactor/eg/testdata/H.template
new file mode 100644
index 0000000..fa6f802
--- /dev/null
+++ b/refactor/eg/testdata/H.template
@@ -0,0 +1,9 @@
+package templates
+
+import (
+ "go/ast" // defines many unencapsulated structs
+ "go/token"
+)
+
+func before(from, to token.Pos) ast.BadExpr { return ast.BadExpr{from, to} }
+func after(from, to token.Pos) ast.BadExpr { return ast.BadExpr{From: from, To: to} }
diff --git a/refactor/eg/testdata/H1.go b/refactor/eg/testdata/H1.go
new file mode 100644
index 0000000..ef4291c
--- /dev/null
+++ b/refactor/eg/testdata/H1.go
@@ -0,0 +1,12 @@
+// +build ignore
+
+package H1
+
+import "go/ast"
+
+func example() {
+ _ = ast.BadExpr{From: 123, To: 456} // no match
+ _ = ast.BadExpr{123, 456} // match
+ _ = ast.BadExpr{From: 123} // no match
+ _ = ast.BadExpr{To: 456} // no match
+}
diff --git a/refactor/eg/testdata/H1.golden b/refactor/eg/testdata/H1.golden
new file mode 100644
index 0000000..a1e5961
--- /dev/null
+++ b/refactor/eg/testdata/H1.golden
@@ -0,0 +1,12 @@
+// +build ignore
+
+package H1
+
+import "go/ast"
+
+func example() {
+ _ = ast.BadExpr{From: 123, To: 456} // no match
+ _ = ast.BadExpr{From: 123, To: 456} // match
+ _ = ast.BadExpr{From: 123} // no match
+ _ = ast.BadExpr{To: 456} // no match
+}
diff --git a/refactor/eg/testdata/bad_type.template b/refactor/eg/testdata/bad_type.template
new file mode 100644
index 0000000..6d53d7e
--- /dev/null
+++ b/refactor/eg/testdata/bad_type.template
@@ -0,0 +1,8 @@
+package template
+
+// Test in which replacement has a different type.
+
+const shouldFail = "int is not a safe replacement for string"
+
+func before() interface{} { return "three" }
+func after() interface{} { return 3 }
diff --git a/refactor/eg/testdata/expr_type_mismatch.template b/refactor/eg/testdata/expr_type_mismatch.template
new file mode 100644
index 0000000..2c5c3f0
--- /dev/null
+++ b/refactor/eg/testdata/expr_type_mismatch.template
@@ -0,0 +1,15 @@
+package template
+
+import (
+ "crypto/x509"
+ "fmt"
+)
+
+// This test demonstrates a false negative: according to the language
+// rules this replacement should be ok, but types.Assignable doesn't work
+// in the expected way (elementwise assignability) for tuples.
+// Perhaps that's even a type-checker bug?
+const shouldFail = "(n int, err error) is not a safe replacement for (key interface{}, err error)"
+
+func before() (interface{}, error) { return x509.ParsePKCS8PrivateKey(nil) }
+func after() (interface{}, error) { return fmt.Print() }
diff --git a/refactor/eg/testdata/no_after_return.template b/refactor/eg/testdata/no_after_return.template
new file mode 100644
index 0000000..536b01e
--- /dev/null
+++ b/refactor/eg/testdata/no_after_return.template
@@ -0,0 +1,6 @@
+package template
+
+const shouldFail = "after: must contain a single statement"
+
+func before() int { return 0 }
+func after() int { println(); return 0 }
diff --git a/refactor/eg/testdata/no_before.template b/refactor/eg/testdata/no_before.template
new file mode 100644
index 0000000..9205e66
--- /dev/null
+++ b/refactor/eg/testdata/no_before.template
@@ -0,0 +1,5 @@
+package template
+
+const shouldFail = "no 'before' func found in template"
+
+func Before() {}
diff --git a/refactor/eg/testdata/type_mismatch.template b/refactor/eg/testdata/type_mismatch.template
new file mode 100644
index 0000000..787c9a7
--- /dev/null
+++ b/refactor/eg/testdata/type_mismatch.template
@@ -0,0 +1,6 @@
+package template
+
+const shouldFail = "different signatures"
+
+func before() int { return 0 }
+func after() string { return "" }
diff --git a/refactor/importgraph/graph.go b/refactor/importgraph/graph.go
new file mode 100644
index 0000000..8ad8014
--- /dev/null
+++ b/refactor/importgraph/graph.go
@@ -0,0 +1,128 @@
+// 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 importgraph computes the forward and reverse import
+// dependency graphs for all packages in a Go workspace.
+package importgraph // import "golang.org/x/tools/refactor/importgraph"
+
+import (
+ "go/build"
+ "sync"
+
+ "golang.org/x/tools/go/buildutil"
+)
+
+// A Graph is an import dependency graph, either forward or reverse.
+//
+// The graph maps each node (a package import path) to the set of its
+// successors in the graph. For a forward graph, this is the set of
+// imported packages (prerequisites); for a reverse graph, it is the set
+// of importing packages (clients).
+//
+type Graph map[string]map[string]bool
+
+func (g Graph) addEdge(from, to string) {
+ edges := g[from]
+ if edges == nil {
+ edges = make(map[string]bool)
+ g[from] = edges
+ }
+ edges[to] = true
+}
+
+// Search returns all the nodes of the graph reachable from
+// any of the specified roots, by following edges forwards.
+// Relationally, this is the reflexive transitive closure.
+func (g Graph) Search(roots ...string) map[string]bool {
+ seen := make(map[string]bool)
+ var visit func(x string)
+ visit = func(x string) {
+ if !seen[x] {
+ seen[x] = true
+ for y := range g[x] {
+ visit(y)
+ }
+ }
+ }
+ for _, root := range roots {
+ visit(root)
+ }
+ return seen
+}
+
+// Build scans the specified Go workspace and builds the forward and
+// reverse import dependency graphs for all its packages.
+// It also returns a mapping from import paths to errors for packages
+// whose loading was not entirely successful.
+// A package may appear in the graph and in the errors mapping.
+func Build(ctxt *build.Context) (forward, reverse Graph, errors map[string]error) {
+ type importEdge struct {
+ from, to string
+ }
+ type pathError struct {
+ path string
+ err error
+ }
+
+ ch := make(chan interface{})
+
+ var wg sync.WaitGroup
+ buildutil.ForEachPackage(ctxt, func(path string, err error) {
+ wg.Add(1)
+ go func() {
+ defer wg.Done()
+ if err != nil {
+ ch <- pathError{path, err}
+ return
+ }
+
+ bp, err := ctxt.Import(path, "", 0)
+ if err != nil {
+ if _, ok := err.(*build.NoGoError); ok {
+ // empty directory is not an error
+ } else {
+ ch <- pathError{path, err}
+ }
+ // Even in error cases, Import usually returns a package.
+ }
+ if bp != nil {
+ for _, imp := range bp.Imports {
+ ch <- importEdge{path, imp}
+ }
+ for _, imp := range bp.TestImports {
+ ch <- importEdge{path, imp}
+ }
+ for _, imp := range bp.XTestImports {
+ ch <- importEdge{path, imp}
+ }
+ }
+ }()
+ })
+ go func() {
+ wg.Wait()
+ close(ch)
+ }()
+
+ forward = make(Graph)
+ reverse = make(Graph)
+
+ for e := range ch {
+ switch e := e.(type) {
+ case pathError:
+ if errors == nil {
+ errors = make(map[string]error)
+ }
+ errors[e.path] = e.err
+
+ case importEdge:
+ if e.to == "C" {
+ continue // "C" is fake
+ }
+ forward.addEdge(e.from, e.to)
+ reverse.addEdge(e.to, e.from)
+ }
+ }
+
+ return forward, reverse, errors
+}
diff --git a/refactor/importgraph/graph_test.go b/refactor/importgraph/graph_test.go
new file mode 100644
index 0000000..a486c26
--- /dev/null
+++ b/refactor/importgraph/graph_test.go
@@ -0,0 +1,103 @@
+// 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.
+
+// Incomplete std lib sources on Android.
+
+// +build !android
+
+package importgraph_test
+
+import (
+ "go/build"
+ "runtime"
+ "sort"
+ "testing"
+
+ "golang.org/x/tools/refactor/importgraph"
+
+ _ "crypto/hmac" // just for test, below
+)
+
+const this = "golang.org/x/tools/refactor/importgraph"
+
+func TestBuild(t *testing.T) {
+ saved := runtime.GOMAXPROCS(8) // Build is highly parallel
+ defer runtime.GOMAXPROCS(saved)
+
+ forward, reverse, errors := importgraph.Build(&build.Default)
+
+ // Test direct edges.
+ // We throw in crypto/hmac to prove that external test files
+ // (such as this one) are inspected.
+ for _, p := range []string{"go/build", "runtime", "testing", "crypto/hmac"} {
+ if !forward[this][p] {
+ t.Errorf("forward[importgraph][%s] not found", p)
+ }
+ if !reverse[p][this] {
+ t.Errorf("reverse[%s][importgraph] not found", p)
+ }
+ }
+
+ // Test non-existent direct edges
+ for _, p := range []string{"fmt", "errors", "reflect"} {
+ if forward[this][p] {
+ t.Errorf("unexpected: forward[importgraph][%s] found", p)
+ }
+ if reverse[p][this] {
+ t.Errorf("unexpected: reverse[%s][importgraph] found", p)
+ }
+ }
+
+ // Test Search is reflexive.
+ if !forward.Search(this)[this] {
+ t.Errorf("irreflexive: forward.Search(importgraph)[importgraph] not found")
+ }
+ if !reverse.Search(this)[this] {
+ t.Errorf("irrefexive: reverse.Search(importgraph)[importgraph] not found")
+ }
+
+ // Test Search is transitive. (There is no direct edge to these packages.)
+ for _, p := range []string{"errors", "reflect", "unsafe"} {
+ if !forward.Search(this)[p] {
+ t.Errorf("intransitive: forward.Search(importgraph)[%s] not found", p)
+ }
+ if !reverse.Search(p)[this] {
+ t.Errorf("intransitive: reverse.Search(%s)[importgraph] not found", p)
+ }
+ }
+
+ // Test strongly-connected components. Because A's external
+ // test package can depend on B, and vice versa, most of the
+ // standard libraries are mutually dependent when their external
+ // tests are considered.
+ //
+ // For any nodes x, y in the same SCC, y appears in the results
+ // of both forward and reverse searches starting from x
+ if !forward.Search("fmt")["io"] ||
+ !forward.Search("io")["fmt"] ||
+ !reverse.Search("fmt")["io"] ||
+ !reverse.Search("io")["fmt"] {
+ t.Errorf("fmt and io are not mutually reachable despite being in the same SCC")
+ }
+
+ // debugging
+ if false {
+ for path, err := range errors {
+ t.Logf("%s: %s", path, err)
+ }
+ printSorted := func(direction string, g importgraph.Graph, start string) {
+ t.Log(direction)
+ var pkgs []string
+ for pkg := range g.Search(start) {
+ pkgs = append(pkgs, pkg)
+ }
+ sort.Strings(pkgs)
+ for _, pkg := range pkgs {
+ t.Logf("\t%s", pkg)
+ }
+ }
+ printSorted("forward", forward, this)
+ printSorted("reverse", reverse, this)
+ }
+}
diff --git a/refactor/lexical/lexical.go b/refactor/lexical/lexical.go
new file mode 100644
index 0000000..c6567e4
--- /dev/null
+++ b/refactor/lexical/lexical.go
@@ -0,0 +1,763 @@
+// Package lexical computes the structure of the lexical environment,
+// including the definition of and references to all universal,
+// package-level, file-level and function-local entities. It does not
+// record qualified identifiers, labels, struct fields, or methods.
+//
+// It is intended for renaming and refactoring tools, which need a more
+// precise understanding of identifier resolution than is available from
+// the output of the type-checker alone.
+//
+// THIS INTERFACE IS EXPERIMENTAL AND MAY CHANGE OR BE REMOVED IN FUTURE.
+//
+package lexical // import "golang.org/x/tools/refactor/lexical"
+
+// OVERVIEW
+//
+// As we traverse the AST, we build a "spaghetti stack" of Blocks,
+// i.e. a tree with parent edges pointing to the root. Each time we
+// visit an identifier that's a reference into the lexical environment,
+// we create and save an Environment, which captures the current mapping
+// state of the Block; these are saved for the client.
+//
+// We don't bother recording non-lexical references.
+
+// TODO(adonovan):
+// - make it robust against syntax errors. Audit all type assertions, etc.
+// - better still, after the Go 1.4 thaw, move this into go/types.
+// I don't think it need be a big change since the visitor is already there;
+// we just need to records Environments. lexical.Block is analogous
+// to types.Scope.
+
+import (
+ "fmt"
+ "go/ast"
+ "go/token"
+ "os"
+ "strconv"
+
+ "golang.org/x/tools/go/types"
+)
+
+const trace = false
+
+var logf = func(format string, args ...interface{}) {
+ fmt.Fprintf(os.Stderr, format, args...)
+}
+
+// A Block is a level of the lexical environment, a tree of blocks.
+// It maps names to objects.
+//
+type Block struct {
+ kind string // one of universe package file func block if switch typeswitch case for range
+ syntax ast.Node // syntax declaring the block (nil for universe and package) [needed?]
+
+ parent Environment
+ bindings []types.Object // bindings in lexical order
+ index map[string]int // maps a name to the index of its binding, for fast lookup
+}
+
+// An Environment is a snapshot of a Block taken at a certain lexical
+// position. It may contain bindings for fewer names than the
+// (completed) block, or different bindings for names that are
+// re-defined later in the block.
+//
+// For example, the lexical Block for the function f below contains a
+// binding for the local var x, but the Environments captured by at the
+// two print(x) calls differ: the first contains this binding, the
+// second does not. The first Environment contains a different binding
+// for x: the string var defined in the package block, an ancestor.
+//
+// var x string
+// func f() {
+// print(x)
+// x := 1
+// print(x)
+// }
+//
+type Environment struct {
+ block *Block
+ nbindings int // length of prefix of block.bindings that's visible
+}
+
+// Depth returns the depth of this block in the block tree.
+// The universal block has depth 1, a package block 2, a file block 3, etc.
+func (b *Block) Depth() int {
+ if b == nil {
+ return 0
+ }
+ return 1 + b.parent.block.Depth()
+}
+
+// env returns an Environment that is a snapshot of b's current state.
+func (b *Block) env() Environment {
+ return Environment{b, len(b.bindings)}
+}
+
+// Lookup returns the definition of name in the environment specified by
+// env, and the Block that defines it, which may be an ancestor.
+func (env Environment) Lookup(name string) (types.Object, *Block) {
+ if env.block == nil {
+ return nil, nil
+ }
+ return lookup(env.block, name, env.nbindings)
+}
+
+// nbindings specifies what prefix of b.bindings should be considered visible.
+func lookup(b *Block, name string, nbindings int) (types.Object, *Block) {
+ if b == nil {
+ return nil, nil
+ }
+ if i, ok := b.index[name]; ok && i < nbindings {
+ return b.bindings[i], b
+ }
+
+ parent := b.parent
+ if parent.block == nil {
+ return nil, nil
+ }
+ return lookup(parent.block, name, parent.nbindings)
+}
+
+// Lookup returns the definition of name in the environment specified by
+// b, and the Block that defines it, which may be an ancestor.
+func (b *Block) Lookup(name string) (types.Object, *Block) {
+ return b.env().Lookup(name)
+}
+
+// Block returns the block of which this environment is a partial view.
+func (env Environment) Block() *Block {
+ return env.block
+}
+
+func (env Environment) String() string {
+ return fmt.Sprintf("%s:%d", env.block, env.nbindings)
+}
+
+func (b *Block) String() string {
+ var s string
+ if b.parent.block != nil {
+ s = b.parent.block.String()
+ s += "."
+ }
+ return s + b.kind
+}
+
+var universe = &Block{kind: "universe", index: make(map[string]int)}
+
+func init() {
+ for i, name := range types.Universe.Names() {
+ obj := types.Universe.Lookup(name)
+ universe.bindings = append(universe.bindings, obj)
+ universe.index[name] = i
+ }
+}
+
+// -- resolver ---------------------------------------------------------
+
+// A Reference provides the lexical environment for a given reference to
+// an object in lexical scope.
+type Reference struct {
+ Id *ast.Ident
+ Env Environment
+}
+
+// resolver holds the state of the identifier resolution visitation:
+// the package information, the result, and the current block.
+type resolver struct {
+ fset *token.FileSet
+ imports map[string]*types.Package
+ pkg *types.Package
+ info *types.Info
+
+ // visitor state
+ block *Block
+
+ result *Info
+}
+
+func (r *resolver) setBlock(kind string, syntax ast.Node) *Block {
+ b := &Block{
+ kind: kind,
+ syntax: syntax,
+ parent: r.block.env(),
+ index: make(map[string]int),
+ }
+ if syntax != nil {
+ r.result.Blocks[syntax] = b
+ }
+ r.block = b
+ return b
+}
+
+func (r *resolver) qualifier(pkg *types.Package) string {
+ if pkg == r.pkg {
+ return "" // unqualified intra-package reference
+ }
+ return pkg.Path()
+}
+
+func (r *resolver) use(id *ast.Ident, env Environment) {
+ if id.Name == "_" {
+ return // an error
+ }
+ obj, _ := env.Lookup(id.Name)
+ if obj == nil {
+ logf("%s: lookup of %s failed\n", r.fset.Position(id.Pos()), id.Name)
+ } else if want := r.info.Uses[id]; obj != want {
+ // sanity check against go/types resolver
+ logf("%s: internal error: lookup of %s yielded wrong object: got %v (%s), want %v\n",
+ r.fset.Position(id.Pos()), id.Name, types.ObjectString(obj, r.qualifier),
+ r.fset.Position(obj.Pos()),
+ want)
+ }
+ if trace {
+ logf("use %s = %v in %s\n", id.Name, types.ObjectString(obj, r.qualifier), env)
+ }
+
+ r.result.Refs[obj] = append(r.result.Refs[obj], Reference{id, env})
+}
+
+func (r *resolver) define(b *Block, id *ast.Ident) {
+ obj := r.info.Defs[id]
+ if obj == nil {
+ logf("%s: internal error: not a defining ident: %s\n",
+ r.fset.Position(id.Pos()), id.Name)
+ panic(id)
+ }
+ r.defineObject(b, id.Name, obj)
+
+ // Objects (other than PkgName) defined at file scope
+ // are also defined in the enclosing package scope.
+ if _, ok := b.syntax.(*ast.File); ok {
+ switch obj.(type) {
+ default:
+ r.defineObject(b.parent.block, id.Name, obj)
+ case nil, *types.PkgName:
+ }
+ }
+}
+
+// Used for implicit objects created by some ImportSpecs and CaseClauses.
+func (r *resolver) defineImplicit(b *Block, n ast.Node, name string) {
+ obj := r.info.Implicits[n]
+ if obj == nil {
+ logf("%s: internal error: not an implicit definition: %T\n",
+ r.fset.Position(n.Pos()), n)
+ }
+ r.defineObject(b, name, obj)
+}
+
+func (r *resolver) defineObject(b *Block, name string, obj types.Object) {
+ if obj.Name() == "_" {
+ return
+ }
+ i := len(b.bindings)
+ b.bindings = append(b.bindings, obj)
+ b.index[name] = i
+ if trace {
+ logf("def %s = %s in %s\n", name, types.ObjectString(obj, r.qualifier), b)
+ }
+ r.result.Defs[obj] = b
+}
+
+func (r *resolver) function(recv *ast.FieldList, typ *ast.FuncType, body *ast.BlockStmt, syntax ast.Node) {
+ // Use all signature types in enclosing block.
+ r.expr(typ)
+ r.fieldList(recv, false)
+
+ savedBlock := r.block // save
+ r.setBlock("func", syntax)
+
+ // Define all parameters/results, and visit the body, within the func block.
+ r.fieldList(typ.Params, true)
+ r.fieldList(typ.Results, true)
+ r.fieldList(recv, true)
+ if body != nil {
+ r.stmtList(body.List)
+ }
+
+ r.block = savedBlock // restore
+}
+
+func (r *resolver) fieldList(list *ast.FieldList, def bool) {
+ if list != nil {
+ for _, f := range list.List {
+ if def {
+ for _, id := range f.Names {
+ r.define(r.block, id)
+ }
+ } else {
+ r.expr(f.Type)
+ }
+ }
+ }
+}
+
+func (r *resolver) exprList(list []ast.Expr) {
+ for _, x := range list {
+ r.expr(x)
+ }
+}
+
+func (r *resolver) expr(n ast.Expr) {
+ switch n := n.(type) {
+ case *ast.BadExpr:
+ case *ast.BasicLit:
+ // no-op
+
+ case *ast.Ident:
+ r.use(n, r.block.env())
+
+ case *ast.Ellipsis:
+ if n.Elt != nil {
+ r.expr(n.Elt)
+ }
+
+ case *ast.FuncLit:
+ r.function(nil, n.Type, n.Body, n)
+
+ case *ast.CompositeLit:
+ if n.Type != nil {
+ r.expr(n.Type)
+ }
+ tv := r.info.Types[n]
+ if _, ok := deref(tv.Type).Underlying().(*types.Struct); ok {
+ for _, elt := range n.Elts {
+ if kv, ok := elt.(*ast.KeyValueExpr); ok {
+ r.expr(kv.Value)
+
+ // Also uses field kv.Key (non-lexical)
+ // id := kv.Key.(*ast.Ident)
+ // obj := r.info.Uses[id]
+ // logf("use %s = %v (field)\n",
+ // id.Name, types.ObjectString(obj, r.qualifier))
+ // TODO make a fake FieldVal selection?
+ } else {
+ r.expr(elt)
+ }
+ }
+ } else {
+ r.exprList(n.Elts)
+ }
+
+ case *ast.ParenExpr:
+ r.expr(n.X)
+
+ case *ast.SelectorExpr:
+ r.expr(n.X)
+
+ // Non-lexical reference to field/method, or qualified identifier.
+ // if sel, ok := r.info.Selections[n]; ok { // selection
+ // switch sel.Kind() {
+ // case types.FieldVal:
+ // logf("use %s = %v (field)\n",
+ // n.Sel.Name, types.ObjectString(sel.Obj(), r.qualifier))
+ // case types.MethodExpr, types.MethodVal:
+ // logf("use %s = %v (method)\n",
+ // n.Sel.Name, types.ObjectString(sel.Obj(), r.qualifier))
+ // }
+ // } else { // qualified identifier
+ // obj := r.info.Uses[n.Sel]
+ // logf("use %s = %v (qualified)\n", n.Sel.Name, obj)
+ // }
+
+ case *ast.IndexExpr:
+ r.expr(n.X)
+ r.expr(n.Index)
+
+ case *ast.SliceExpr:
+ r.expr(n.X)
+ if n.Low != nil {
+ r.expr(n.Low)
+ }
+ if n.High != nil {
+ r.expr(n.High)
+ }
+ if n.Max != nil {
+ r.expr(n.Max)
+ }
+
+ case *ast.TypeAssertExpr:
+ r.expr(n.X)
+ if n.Type != nil {
+ r.expr(n.Type)
+ }
+
+ case *ast.CallExpr:
+ r.expr(n.Fun)
+ r.exprList(n.Args)
+
+ case *ast.StarExpr:
+ r.expr(n.X)
+
+ case *ast.UnaryExpr:
+ r.expr(n.X)
+
+ case *ast.BinaryExpr:
+ r.expr(n.X)
+ r.expr(n.Y)
+
+ case *ast.KeyValueExpr:
+ r.expr(n.Key)
+ r.expr(n.Value)
+
+ case *ast.ArrayType:
+ if n.Len != nil {
+ r.expr(n.Len)
+ }
+ r.expr(n.Elt)
+
+ case *ast.StructType:
+ // Use all the type names, but don't define any fields.
+ r.fieldList(n.Fields, false)
+
+ case *ast.FuncType:
+ // Use all the type names, but don't define any vars.
+ r.fieldList(n.Params, false)
+ r.fieldList(n.Results, false)
+
+ case *ast.InterfaceType:
+ // Use all the type names, but don't define any methods.
+ r.fieldList(n.Methods, false)
+
+ case *ast.MapType:
+ r.expr(n.Key)
+ r.expr(n.Value)
+
+ case *ast.ChanType:
+ r.expr(n.Value)
+
+ default:
+ panic(n)
+ }
+}
+
+func (r *resolver) stmtList(list []ast.Stmt) {
+ for _, s := range list {
+ r.stmt(s)
+ }
+}
+
+func (r *resolver) stmt(n ast.Stmt) {
+ switch n := n.(type) {
+ case *ast.BadStmt:
+ case *ast.EmptyStmt:
+ // nothing to do
+
+ case *ast.DeclStmt:
+ decl := n.Decl.(*ast.GenDecl)
+ for _, spec := range decl.Specs {
+ switch spec := spec.(type) {
+ case *ast.ValueSpec: // const or var
+ if spec.Type != nil {
+ r.expr(spec.Type)
+ }
+ r.exprList(spec.Values)
+ for _, name := range spec.Names {
+ r.define(r.block, name)
+ }
+
+ case *ast.TypeSpec:
+ r.define(r.block, spec.Name)
+ r.expr(spec.Type)
+ }
+ }
+
+ case *ast.LabeledStmt:
+ // Also defines label n.Label (non-lexical)
+ r.stmt(n.Stmt)
+
+ case *ast.ExprStmt:
+ r.expr(n.X)
+
+ case *ast.SendStmt:
+ r.expr(n.Chan)
+ r.expr(n.Value)
+
+ case *ast.IncDecStmt:
+ r.expr(n.X)
+
+ case *ast.AssignStmt:
+ if n.Tok == token.DEFINE {
+ r.exprList(n.Rhs)
+ for _, lhs := range n.Lhs {
+ id := lhs.(*ast.Ident)
+ if _, ok := r.info.Defs[id]; ok {
+ r.define(r.block, id)
+ } else {
+ r.use(id, r.block.env())
+ }
+ }
+ } else { // ASSIGN
+ r.exprList(n.Lhs)
+ r.exprList(n.Rhs)
+ }
+
+ case *ast.GoStmt:
+ r.expr(n.Call)
+
+ case *ast.DeferStmt:
+ r.expr(n.Call)
+
+ case *ast.ReturnStmt:
+ r.exprList(n.Results)
+
+ case *ast.BranchStmt:
+ if n.Label != nil {
+ // Also uses label n.Label (non-lexical)
+ }
+
+ case *ast.SelectStmt:
+ r.stmtList(n.Body.List)
+
+ case *ast.BlockStmt: // (explicit blocks only)
+ savedBlock := r.block // save
+ r.setBlock("block", n)
+ r.stmtList(n.List)
+ r.block = savedBlock // restore
+
+ case *ast.IfStmt:
+ savedBlock := r.block // save
+ r.setBlock("if", n)
+ if n.Init != nil {
+ r.stmt(n.Init)
+ }
+ r.expr(n.Cond)
+ r.stmt(n.Body) // new block
+ if n.Else != nil {
+ r.stmt(n.Else)
+ }
+ r.block = savedBlock // restore
+
+ case *ast.CaseClause:
+ savedBlock := r.block // save
+ r.setBlock("case", n)
+ if obj, ok := r.info.Implicits[n]; ok {
+ // e.g.
+ // switch y := x.(type) {
+ // case T: // we declare an implicit 'var y T' in this block
+ // }
+ r.defineImplicit(r.block, n, obj.Name())
+ }
+ r.exprList(n.List)
+ r.stmtList(n.Body)
+ r.block = savedBlock // restore
+
+ case *ast.SwitchStmt:
+ savedBlock := r.block // save
+ r.setBlock("switch", n)
+ if n.Init != nil {
+ r.stmt(n.Init)
+ }
+ if n.Tag != nil {
+ r.expr(n.Tag)
+ }
+ r.stmtList(n.Body.List)
+ r.block = savedBlock // restore
+
+ case *ast.TypeSwitchStmt:
+ savedBlock := r.block // save
+ r.setBlock("typeswitch", n)
+ if n.Init != nil {
+ r.stmt(n.Init)
+ }
+ if assign, ok := n.Assign.(*ast.AssignStmt); ok { // y := x.(type)
+ r.expr(assign.Rhs[0]) // skip y: not a defining ident
+ } else {
+ r.stmt(n.Assign)
+ }
+ r.stmtList(n.Body.List)
+ r.block = savedBlock // restore
+
+ case *ast.CommClause:
+ savedBlock := r.block // save
+ r.setBlock("case", n)
+ if n.Comm != nil {
+ r.stmt(n.Comm)
+ }
+ r.stmtList(n.Body)
+ r.block = savedBlock // restore
+
+ case *ast.ForStmt:
+ savedBlock := r.block // save
+ r.setBlock("for", n)
+ if n.Init != nil {
+ r.stmt(n.Init)
+ }
+ if n.Cond != nil {
+ r.expr(n.Cond)
+ }
+ if n.Post != nil {
+ r.stmt(n.Post)
+ }
+ r.stmt(n.Body)
+ r.block = savedBlock // restore
+
+ case *ast.RangeStmt:
+ r.expr(n.X)
+ savedBlock := r.block // save
+ r.setBlock("range", n)
+ if n.Tok == token.DEFINE {
+ if n.Key != nil {
+ r.define(r.block, n.Key.(*ast.Ident))
+ }
+ if n.Value != nil {
+ r.define(r.block, n.Value.(*ast.Ident))
+ }
+ } else {
+ if n.Key != nil {
+ r.expr(n.Key)
+ }
+ if n.Value != nil {
+ r.expr(n.Value)
+ }
+ }
+ r.stmt(n.Body)
+ r.block = savedBlock // restore
+
+ default:
+ panic(n)
+ }
+}
+
+func (r *resolver) doImport(s *ast.ImportSpec, fileBlock *Block) {
+ path, _ := strconv.Unquote(s.Path.Value)
+ pkg := r.imports[path]
+ if s.Name == nil { // normal
+ r.defineImplicit(fileBlock, s, pkg.Name())
+ } else if s.Name.Name == "." { // dot import
+ for _, name := range pkg.Scope().Names() {
+ if ast.IsExported(name) {
+ obj := pkg.Scope().Lookup(name)
+ r.defineObject(fileBlock, name, obj)
+ }
+ }
+ } else { // renaming import
+ r.define(fileBlock, s.Name)
+ }
+}
+
+func (r *resolver) doPackage(pkg *types.Package, files []*ast.File) {
+ r.block = universe
+ r.result.Blocks[nil] = universe
+
+ r.result.PackageBlock = r.setBlock("package", nil)
+
+ var fileBlocks []*Block
+
+ // 1. Insert all package-level objects into file and package blocks.
+ // (PkgName objects are only inserted into file blocks.)
+ for _, f := range files {
+ r.block = r.result.PackageBlock
+ fileBlock := r.setBlock("file", f) // package is not yet visible to file
+ fileBlocks = append(fileBlocks, fileBlock)
+
+ for _, d := range f.Decls {
+ switch d := d.(type) {
+ case *ast.GenDecl:
+ for _, s := range d.Specs {
+ switch s := s.(type) {
+ case *ast.ImportSpec:
+ r.doImport(s, fileBlock)
+
+ case *ast.ValueSpec: // const or var
+ for _, name := range s.Names {
+ r.define(r.result.PackageBlock, name)
+ }
+
+ case *ast.TypeSpec:
+ r.define(r.result.PackageBlock, s.Name)
+ }
+ }
+
+ case *ast.FuncDecl:
+ if d.Recv == nil { // function
+ if d.Name.Name != "init" {
+ r.define(r.result.PackageBlock, d.Name)
+ }
+ }
+ }
+ }
+ }
+
+ // 2. Now resolve bodies of GenDecls and FuncDecls.
+ for i, f := range files {
+ fileBlock := fileBlocks[i]
+ fileBlock.parent = r.result.PackageBlock.env() // make entire package visible to this file
+
+ for _, d := range f.Decls {
+ r.block = fileBlock
+
+ switch d := d.(type) {
+ case *ast.GenDecl:
+ for _, s := range d.Specs {
+ switch s := s.(type) {
+ case *ast.ValueSpec: // const or var
+ if s.Type != nil {
+ r.expr(s.Type)
+ }
+ r.exprList(s.Values)
+
+ case *ast.TypeSpec:
+ r.expr(s.Type)
+ }
+ }
+
+ case *ast.FuncDecl:
+ r.function(d.Recv, d.Type, d.Body, d)
+ }
+ }
+ }
+
+ r.block = nil
+}
+
+// An Info contains the lexical reference structure of a package.
+type Info struct {
+ Defs map[types.Object]*Block // maps each object to its defining lexical block
+ Refs map[types.Object][]Reference // maps each object to the set of references to it
+ Blocks map[ast.Node]*Block // maps declaring syntax to block; nil => universe
+ PackageBlock *Block // the package-level lexical block
+}
+
+// Structure computes the structure of the lexical environment of the
+// package specified by (pkg, info, files).
+//
+// The info.{Types,Defs,Uses,Implicits} maps must have been populated
+// by the type-checker
+//
+// fset is used for logging.
+//
+func Structure(fset *token.FileSet, pkg *types.Package, info *types.Info, files []*ast.File) *Info {
+ r := resolver{
+ fset: fset,
+ imports: make(map[string]*types.Package),
+ result: &Info{
+ Defs: make(map[types.Object]*Block),
+ Refs: make(map[types.Object][]Reference),
+ Blocks: make(map[ast.Node]*Block),
+ },
+ pkg: pkg,
+ info: info,
+ }
+
+ // Build import map for just this package.
+ r.imports["unsafe"] = types.Unsafe
+ for _, imp := range pkg.Imports() {
+ r.imports[imp.Path()] = imp
+ }
+
+ r.doPackage(pkg, files)
+
+ return r.result
+}
+
+// -- Plundered from golang.org/x/tools/go/ssa -----------------
+
+// deref returns a pointer's element type; otherwise it returns typ.
+func deref(typ types.Type) types.Type {
+ if p, ok := typ.Underlying().(*types.Pointer); ok {
+ return p.Elem()
+ }
+ return typ
+}
diff --git a/refactor/lexical/lexical_test.go b/refactor/lexical/lexical_test.go
new file mode 100644
index 0000000..77287a4
--- /dev/null
+++ b/refactor/lexical/lexical_test.go
@@ -0,0 +1,53 @@
+// 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.
+
+// Incomplete std lib sources on Android.
+
+// +build !android
+
+package lexical
+
+import (
+ "go/build"
+ "testing"
+
+ "golang.org/x/tools/go/buildutil"
+ "golang.org/x/tools/go/loader"
+)
+
+func TestStdlib(t *testing.T) {
+ defer func(saved func(format string, args ...interface{})) {
+ logf = saved
+ }(logf)
+ logf = t.Errorf
+
+ ctxt := build.Default // copy
+
+ // Enumerate $GOROOT packages.
+ saved := ctxt.GOPATH
+ ctxt.GOPATH = "" // disable GOPATH during AllPackages
+ pkgs := buildutil.AllPackages(&ctxt)
+ ctxt.GOPATH = saved
+
+ // Throw in a number of go.tools packages too.
+ pkgs = append(pkgs,
+ "golang.org/x/tools/cmd/godoc",
+ "golang.org/x/tools/refactor/lexical")
+
+ // Load, parse and type-check the program.
+ conf := loader.Config{Build: &ctxt}
+ for _, path := range pkgs {
+ conf.ImportWithTests(path)
+ }
+ iprog, err := conf.Load()
+ if err != nil {
+ t.Fatalf("Load failed: %v", err)
+ }
+
+ // This test ensures that Structure doesn't panic and that
+ // its internal sanity-checks against go/types don't fail.
+ for pkg, info := range iprog.AllPackages {
+ _ = Structure(iprog.Fset, pkg, &info.Info, info.Files)
+ }
+}
diff --git a/refactor/rename/check.go b/refactor/rename/check.go
new file mode 100644
index 0000000..017a604
--- /dev/null
+++ b/refactor/rename/check.go
@@ -0,0 +1,737 @@
+// 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 rename
+
+// This file defines the safety checks for each kind of renaming.
+
+import (
+ "fmt"
+ "go/ast"
+ "go/token"
+
+ "golang.org/x/tools/go/loader"
+ "golang.org/x/tools/go/types"
+ "golang.org/x/tools/refactor/lexical"
+ "golang.org/x/tools/refactor/satisfy"
+)
+
+// errorf reports an error (e.g. conflict) and prevents file modification.
+func (r *renamer) errorf(pos token.Pos, format string, args ...interface{}) {
+ r.hadConflicts = true
+ reportError(r.iprog.Fset.Position(pos), fmt.Sprintf(format, args...))
+}
+
+// check performs safety checks of the renaming of the 'from' object to r.to.
+func (r *renamer) check(from types.Object) {
+ if r.objsToUpdate[from] {
+ return
+ }
+ r.objsToUpdate[from] = true
+
+ // NB: order of conditions is important.
+ if from_, ok := from.(*types.PkgName); ok {
+ r.checkInFileBlock(from_)
+ } else if from_, ok := from.(*types.Label); ok {
+ r.checkLabel(from_)
+ } else if isPackageLevel(from) {
+ r.checkInPackageBlock(from)
+ } else if v, ok := from.(*types.Var); ok && v.IsField() {
+ r.checkStructField(v)
+ } else if f, ok := from.(*types.Func); ok && recv(f) != nil {
+ r.checkMethod(f)
+ } else if isLocal(from) {
+ r.checkInLocalScope(from)
+ } else {
+ r.errorf(from.Pos(), "unexpected %s object %q (please report a bug)\n",
+ objectKind(from), from)
+ }
+}
+
+// checkInFileBlock performs safety checks for renames of objects in the file block,
+// i.e. imported package names.
+func (r *renamer) checkInFileBlock(from *types.PkgName) {
+ // Check import name is not "init".
+ if r.to == "init" {
+ r.errorf(from.Pos(), "%q is not a valid imported package name", r.to)
+ }
+
+ // Check for conflicts between file and package block.
+ if prev := from.Pkg().Scope().Lookup(r.to); prev != nil {
+ r.errorf(from.Pos(), "renaming this %s %q to %q would conflict",
+ objectKind(from), from.Name(), r.to)
+ r.errorf(prev.Pos(), "\twith this package member %s",
+ objectKind(prev))
+ return // since checkInPackageBlock would report redundant errors
+ }
+
+ // Check for conflicts in lexical scope.
+ r.checkInLexicalScope(from, r.packages[from.Pkg()])
+
+ // Finally, modify ImportSpec syntax to add or remove the Name as needed.
+ info, path, _ := r.iprog.PathEnclosingInterval(from.Pos(), from.Pos())
+ if from.Imported().Name() == r.to {
+ // ImportSpec.Name not needed
+ path[1].(*ast.ImportSpec).Name = nil
+ } else {
+ // ImportSpec.Name needed
+ if spec := path[1].(*ast.ImportSpec); spec.Name == nil {
+ spec.Name = &ast.Ident{NamePos: spec.Path.Pos(), Name: r.to}
+ info.Defs[spec.Name] = from
+ }
+ }
+}
+
+// checkInPackageBlock performs safety checks for renames of
+// func/var/const/type objects in the package block.
+func (r *renamer) checkInPackageBlock(from types.Object) {
+ // Check that there are no references to the name from another
+ // package if the renaming would make it unexported.
+ if ast.IsExported(from.Name()) && !ast.IsExported(r.to) {
+ for pkg, info := range r.packages {
+ if pkg == from.Pkg() {
+ continue
+ }
+ if id := someUse(info, from); id != nil &&
+ !r.checkExport(id, pkg, from) {
+ break
+ }
+ }
+ }
+
+ info := r.packages[from.Pkg()]
+ lexinfo := lexical.Structure(r.iprog.Fset, from.Pkg(), &info.Info, info.Files)
+
+ // Check that in the package block, "init" is a function, and never referenced.
+ if r.to == "init" {
+ kind := objectKind(from)
+ if kind == "func" {
+ // Reject if intra-package references to it exist.
+ if refs := lexinfo.Refs[from]; len(refs) > 0 {
+ r.errorf(from.Pos(),
+ "renaming this func %q to %q would make it a package initializer",
+ from.Name(), r.to)
+ r.errorf(refs[0].Id.Pos(), "\tbut references to it exist")
+ }
+ } else {
+ r.errorf(from.Pos(), "you cannot have a %s at package level named %q",
+ kind, r.to)
+ }
+ }
+
+ // Check for conflicts between package block and all file blocks.
+ for _, f := range info.Files {
+ if prev, b := lexinfo.Blocks[f].Lookup(r.to); b == lexinfo.Blocks[f] {
+ r.errorf(from.Pos(), "renaming this %s %q to %q would conflict",
+ objectKind(from), from.Name(), r.to)
+ r.errorf(prev.Pos(), "\twith this %s",
+ objectKind(prev))
+ return // since checkInPackageBlock would report redundant errors
+ }
+ }
+
+ // Check for conflicts in lexical scope.
+ if from.Exported() {
+ for _, info := range r.packages {
+ r.checkInLexicalScope(from, info)
+ }
+ } else {
+ r.checkInLexicalScope(from, info)
+ }
+}
+
+func (r *renamer) checkInLocalScope(from types.Object) {
+ info := r.packages[from.Pkg()]
+
+ // Is this object an implicit local var for a type switch?
+ // Each case has its own var, whose position is the decl of y,
+ // but Ident in that decl does not appear in the Uses map.
+ //
+ // switch y := x.(type) { // Defs[Ident(y)] is undefined
+ // case int: print(y) // Implicits[CaseClause(int)] = Var(y_int)
+ // case string: print(y) // Implicits[CaseClause(string)] = Var(y_string)
+ // }
+ //
+ var isCaseVar bool
+ for syntax, obj := range info.Implicits {
+ if _, ok := syntax.(*ast.CaseClause); ok && obj.Pos() == from.Pos() {
+ isCaseVar = true
+ r.check(obj)
+ }
+ }
+
+ r.checkInLexicalScope(from, info)
+
+ // Finally, if this was a type switch, change the variable y.
+ if isCaseVar {
+ _, path, _ := r.iprog.PathEnclosingInterval(from.Pos(), from.Pos())
+ path[0].(*ast.Ident).Name = r.to // path is [Ident AssignStmt TypeSwitchStmt...]
+ }
+}
+
+// checkInLexicalScope performs safety checks that a renaming does not
+// change the lexical reference structure of the specified package.
+//
+// For objects in lexical scope, there are three kinds of conflicts:
+// same-, sub-, and super-block conflicts. We will illustrate all three
+// using this example:
+//
+// var x int
+// var z int
+//
+// func f(y int) {
+// print(x)
+// print(y)
+// }
+//
+// Renaming x to z encounters a SAME-BLOCK CONFLICT, because an object
+// with the new name already exists, defined in the same lexical block
+// as the old object.
+//
+// Renaming x to y encounters a SUB-BLOCK CONFLICT, because there exists
+// a reference to x from within (what would become) a hole in its scope.
+// The definition of y in an (inner) sub-block would cast a shadow in
+// the scope of the renamed variable.
+//
+// Renaming y to x encounters a SUPER-BLOCK CONFLICT. This is the
+// converse situation: there is an existing definition of the new name
+// (x) in an (enclosing) super-block, and the renaming would create a
+// hole in its scope, within which there exist references to it. The
+// new name casts a shadow in scope of the existing definition of x in
+// the super-block.
+//
+// Removing the old name (and all references to it) is always safe, and
+// requires no checks.
+//
+func (r *renamer) checkInLexicalScope(from types.Object, info *loader.PackageInfo) {
+ lexinfo := lexical.Structure(r.iprog.Fset, info.Pkg, &info.Info, info.Files)
+
+ b := lexinfo.Defs[from] // the block defining the 'from' object
+ if b != nil {
+ to, toBlock := b.Lookup(r.to)
+ if toBlock == b {
+ // same-block conflict
+ r.errorf(from.Pos(), "renaming this %s %q to %q",
+ objectKind(from), from.Name(), r.to)
+ r.errorf(to.Pos(), "\tconflicts with %s in same block",
+ objectKind(to))
+ return
+ } else if toBlock != nil {
+ // Check for super-block conflict.
+ // The name r.to is defined in a superblock.
+ // Is that name referenced from within this block?
+ for _, ref := range lexinfo.Refs[to] {
+ if obj, _ := ref.Env.Lookup(from.Name()); obj == from {
+ // super-block conflict
+ r.errorf(from.Pos(), "renaming this %s %q to %q",
+ objectKind(from), from.Name(), r.to)
+ r.errorf(ref.Id.Pos(), "\twould shadow this reference")
+ r.errorf(to.Pos(), "\tto the %s declared here",
+ objectKind(to))
+ return
+ }
+ }
+ }
+ }
+
+ // Check for sub-block conflict.
+ // Is there an intervening definition of r.to between
+ // the block defining 'from' and some reference to it?
+ for _, ref := range lexinfo.Refs[from] {
+ // TODO(adonovan): think about dot imports.
+ // (Is b == fromBlock an invariant?)
+ _, fromBlock := ref.Env.Lookup(from.Name())
+ fromDepth := fromBlock.Depth()
+
+ to, toBlock := ref.Env.Lookup(r.to)
+ if to != nil {
+ // sub-block conflict
+ if toBlock.Depth() > fromDepth {
+ r.errorf(from.Pos(), "renaming this %s %q to %q",
+ objectKind(from), from.Name(), r.to)
+ r.errorf(ref.Id.Pos(), "\twould cause this reference to become shadowed")
+ r.errorf(to.Pos(), "\tby this intervening %s definition",
+ objectKind(to))
+ return
+ }
+ }
+ }
+
+ // Renaming a type that is used as an embedded field
+ // requires renaming the field too. e.g.
+ // type T int // if we rename this to U..
+ // var s struct {T}
+ // print(s.T) // ...this must change too
+ if _, ok := from.(*types.TypeName); ok {
+ for id, obj := range info.Uses {
+ if obj == from {
+ if field := info.Defs[id]; field != nil {
+ r.check(field)
+ }
+ }
+ }
+ }
+}
+
+func (r *renamer) checkLabel(label *types.Label) {
+ // Check there are no identical labels in the function's label block.
+ // (Label blocks don't nest, so this is easy.)
+ if prev := label.Parent().Lookup(r.to); prev != nil {
+ r.errorf(label.Pos(), "renaming this label %q to %q", label.Name(), prev.Name())
+ r.errorf(prev.Pos(), "\twould conflict with this one")
+ }
+}
+
+// checkStructField checks that the field renaming will not cause
+// conflicts at its declaration, or ambiguity or changes to any selection.
+func (r *renamer) checkStructField(from *types.Var) {
+ // Check that the struct declaration is free of field conflicts,
+ // and field/method conflicts.
+
+ // go/types offers no easy way to get from a field (or interface
+ // method) to its declaring struct (or interface), so we must
+ // ascend the AST.
+ info, path, _ := r.iprog.PathEnclosingInterval(from.Pos(), from.Pos())
+ // path matches this pattern:
+ // [Ident SelectorExpr? StarExpr? Field FieldList StructType ParenExpr* ... File]
+
+ // Ascend to FieldList.
+ var i int
+ for {
+ if _, ok := path[i].(*ast.FieldList); ok {
+ break
+ }
+ i++
+ }
+ i++
+ tStruct := path[i].(*ast.StructType)
+ i++
+ // Ascend past parens (unlikely).
+ for {
+ _, ok := path[i].(*ast.ParenExpr)
+ if !ok {
+ break
+ }
+ i++
+ }
+ if spec, ok := path[i].(*ast.TypeSpec); ok {
+ // This struct is also a named type.
+ // We must check for direct (non-promoted) field/field
+ // and method/field conflicts.
+ named := info.Defs[spec.Name].Type()
+ prev, indices, _ := types.LookupFieldOrMethod(named, true, info.Pkg, r.to)
+ if len(indices) == 1 {
+ r.errorf(from.Pos(), "renaming this field %q to %q",
+ from.Name(), r.to)
+ r.errorf(prev.Pos(), "\twould conflict with this %s",
+ objectKind(prev))
+ return // skip checkSelections to avoid redundant errors
+ }
+ } else {
+ // This struct is not a named type.
+ // We need only check for direct (non-promoted) field/field conflicts.
+ T := info.Types[tStruct].Type.Underlying().(*types.Struct)
+ for i := 0; i < T.NumFields(); i++ {
+ if prev := T.Field(i); prev.Name() == r.to {
+ r.errorf(from.Pos(), "renaming this field %q to %q",
+ from.Name(), r.to)
+ r.errorf(prev.Pos(), "\twould conflict with this field")
+ return // skip checkSelections to avoid redundant errors
+ }
+ }
+ }
+
+ // Renaming an anonymous field requires renaming the type too. e.g.
+ // print(s.T) // if we rename T to U,
+ // type T int // this and
+ // var s struct {T} // this must change too.
+ if from.Anonymous() {
+ if named, ok := from.Type().(*types.Named); ok {
+ r.check(named.Obj())
+ } else if named, ok := deref(from.Type()).(*types.Named); ok {
+ r.check(named.Obj())
+ }
+ }
+
+ // Check integrity of existing (field and method) selections.
+ r.checkSelections(from)
+}
+
+// checkSelection checks that all uses and selections that resolve to
+// the specified object would continue to do so after the renaming.
+func (r *renamer) checkSelections(from types.Object) {
+ for pkg, info := range r.packages {
+ if id := someUse(info, from); id != nil {
+ if !r.checkExport(id, pkg, from) {
+ return
+ }
+ }
+
+ for syntax, sel := range info.Selections {
+ // There may be extant selections of only the old
+ // name or only the new name, so we must check both.
+ // (If neither, the renaming is sound.)
+ //
+ // In both cases, we wish to compare the lengths
+ // of the implicit field path (Selection.Index)
+ // to see if the renaming would change it.
+ //
+ // If a selection that resolves to 'from', when renamed,
+ // would yield a path of the same or shorter length,
+ // this indicates ambiguity or a changed referent,
+ // analogous to same- or sub-block lexical conflict.
+ //
+ // If a selection using the name 'to' would
+ // yield a path of the same or shorter length,
+ // this indicates ambiguity or shadowing,
+ // analogous to same- or super-block lexical conflict.
+
+ // TODO(adonovan): fix: derive from Types[syntax.X].Mode
+ // TODO(adonovan): test with pointer, value, addressable value.
+ isAddressable := true
+
+ if sel.Obj() == from {
+ if obj, indices, _ := types.LookupFieldOrMethod(sel.Recv(), isAddressable, from.Pkg(), r.to); obj != nil {
+ // Renaming this existing selection of
+ // 'from' may block access to an existing
+ // type member named 'to'.
+ delta := len(indices) - len(sel.Index())
+ if delta > 0 {
+ continue // no ambiguity
+ }
+ r.selectionConflict(from, delta, syntax, obj)
+ return
+ }
+
+ } else if sel.Obj().Name() == r.to {
+ if obj, indices, _ := types.LookupFieldOrMethod(sel.Recv(), isAddressable, from.Pkg(), from.Name()); obj == from {
+ // Renaming 'from' may cause this existing
+ // selection of the name 'to' to change
+ // its meaning.
+ delta := len(indices) - len(sel.Index())
+ if delta > 0 {
+ continue // no ambiguity
+ }
+ r.selectionConflict(from, -delta, syntax, sel.Obj())
+ return
+ }
+ }
+ }
+ }
+}
+
+func (r *renamer) selectionConflict(from types.Object, delta int, syntax *ast.SelectorExpr, obj types.Object) {
+ r.errorf(from.Pos(), "renaming this %s %q to %q",
+ objectKind(from), from.Name(), r.to)
+
+ switch {
+ case delta < 0:
+ // analogous to sub-block conflict
+ r.errorf(syntax.Sel.Pos(),
+ "\twould change the referent of this selection")
+ r.errorf(obj.Pos(), "\tof this %s", objectKind(obj))
+ case delta == 0:
+ // analogous to same-block conflict
+ r.errorf(syntax.Sel.Pos(),
+ "\twould make this reference ambiguous")
+ r.errorf(obj.Pos(), "\twith this %s", objectKind(obj))
+ case delta > 0:
+ // analogous to super-block conflict
+ r.errorf(syntax.Sel.Pos(),
+ "\twould shadow this selection")
+ r.errorf(obj.Pos(), "\tof the %s declared here",
+ objectKind(obj))
+ }
+}
+
+// checkMethod performs safety checks for renaming a method.
+// There are three hazards:
+// - declaration conflicts
+// - selection ambiguity/changes
+// - entailed renamings of assignable concrete/interface types.
+// We reject renamings initiated at concrete methods if it would
+// change the assignability relation. For renamings of abstract
+// methods, we rename all methods transitively coupled to it via
+// assignability.
+func (r *renamer) checkMethod(from *types.Func) {
+ // e.g. error.Error
+ if from.Pkg() == nil {
+ r.errorf(from.Pos(), "you cannot rename built-in method %s", from)
+ return
+ }
+
+ // ASSIGNABILITY: We reject renamings of concrete methods that
+ // would break a 'satisfy' constraint; but renamings of abstract
+ // methods are allowed to proceed, and we rename affected
+ // concrete and abstract methods as necessary. It is the
+ // initial method that determines the policy.
+
+ // Check for conflict at point of declaration.
+ // Check to ensure preservation of assignability requirements.
+ R := recv(from).Type()
+ if isInterface(R) {
+ // Abstract method
+
+ // declaration
+ prev, _, _ := types.LookupFieldOrMethod(R, false, from.Pkg(), r.to)
+ if prev != nil {
+ r.errorf(from.Pos(), "renaming this interface method %q to %q",
+ from.Name(), r.to)
+ r.errorf(prev.Pos(), "\twould conflict with this method")
+ return
+ }
+
+ // Check all interfaces that embed this one for
+ // declaration conflicts too.
+ for _, info := range r.packages {
+ // Start with named interface types (better errors)
+ for _, obj := range info.Defs {
+ if obj, ok := obj.(*types.TypeName); ok && isInterface(obj.Type()) {
+ f, _, _ := types.LookupFieldOrMethod(
+ obj.Type(), false, from.Pkg(), from.Name())
+ if f == nil {
+ continue
+ }
+ t, _, _ := types.LookupFieldOrMethod(
+ obj.Type(), false, from.Pkg(), r.to)
+ if t == nil {
+ continue
+ }
+ r.errorf(from.Pos(), "renaming this interface method %q to %q",
+ from.Name(), r.to)
+ r.errorf(t.Pos(), "\twould conflict with this method")
+ r.errorf(obj.Pos(), "\tin named interface type %q", obj.Name())
+ }
+ }
+
+ // Now look at all literal interface types (includes named ones again).
+ for e, tv := range info.Types {
+ if e, ok := e.(*ast.InterfaceType); ok {
+ _ = e
+ _ = tv.Type.(*types.Interface)
+ // TODO(adonovan): implement same check as above.
+ }
+ }
+ }
+
+ // assignability
+ //
+ // Find the set of concrete or abstract methods directly
+ // coupled to abstract method 'from' by some
+ // satisfy.Constraint, and rename them too.
+ for key := range r.satisfy() {
+ // key = (lhs, rhs) where lhs is always an interface.
+
+ lsel := r.msets.MethodSet(key.LHS).Lookup(from.Pkg(), from.Name())
+ if lsel == nil {
+ continue
+ }
+ rmethods := r.msets.MethodSet(key.RHS)
+ rsel := rmethods.Lookup(from.Pkg(), from.Name())
+ if rsel == nil {
+ continue
+ }
+
+ // If both sides have a method of this name,
+ // and one of them is m, the other must be coupled.
+ var coupled *types.Func
+ switch from {
+ case lsel.Obj():
+ coupled = rsel.Obj().(*types.Func)
+ case rsel.Obj():
+ coupled = lsel.Obj().(*types.Func)
+ default:
+ continue
+ }
+
+ // We must treat concrete-to-interface
+ // constraints like an implicit selection C.f of
+ // each interface method I.f, and check that the
+ // renaming leaves the selection unchanged and
+ // unambiguous.
+ //
+ // Fun fact: the implicit selection of C.f
+ // type I interface{f()}
+ // type C struct{I}
+ // func (C) g()
+ // var _ I = C{} // here
+ // yields abstract method I.f. This can make error
+ // messages less than obvious.
+ //
+ if !isInterface(key.RHS) {
+ // The logic below was derived from checkSelections.
+
+ rtosel := rmethods.Lookup(from.Pkg(), r.to)
+ if rtosel != nil {
+ rto := rtosel.Obj().(*types.Func)
+ delta := len(rsel.Index()) - len(rtosel.Index())
+ if delta < 0 {
+ continue // no ambiguity
+ }
+
+ // TODO(adonovan): record the constraint's position.
+ keyPos := token.NoPos
+
+ r.errorf(from.Pos(), "renaming this method %q to %q",
+ from.Name(), r.to)
+ if delta == 0 {
+ // analogous to same-block conflict
+ r.errorf(keyPos, "\twould make the %s method of %s invoked via interface %s ambiguous",
+ r.to, key.RHS, key.LHS)
+ r.errorf(rto.Pos(), "\twith (%s).%s",
+ recv(rto).Type(), r.to)
+ } else {
+ // analogous to super-block conflict
+ r.errorf(keyPos, "\twould change the %s method of %s invoked via interface %s",
+ r.to, key.RHS, key.LHS)
+ r.errorf(coupled.Pos(), "\tfrom (%s).%s",
+ recv(coupled).Type(), r.to)
+ r.errorf(rto.Pos(), "\tto (%s).%s",
+ recv(rto).Type(), r.to)
+ }
+ return // one error is enough
+ }
+ }
+
+ if !r.changeMethods {
+ // This should be unreachable.
+ r.errorf(from.Pos(), "internal error: during renaming of abstract method %s", from)
+ r.errorf(coupled.Pos(), "\tchangedMethods=false, coupled method=%s", coupled)
+ r.errorf(from.Pos(), "\tPlease file a bug report")
+ return
+ }
+
+ // Rename the coupled method to preserve assignability.
+ r.check(coupled)
+ }
+ } else {
+ // Concrete method
+
+ // declaration
+ prev, indices, _ := types.LookupFieldOrMethod(R, true, from.Pkg(), r.to)
+ if prev != nil && len(indices) == 1 {
+ r.errorf(from.Pos(), "renaming this method %q to %q",
+ from.Name(), r.to)
+ r.errorf(prev.Pos(), "\twould conflict with this %s",
+ objectKind(prev))
+ return
+ }
+
+ // assignability
+ //
+ // Find the set of abstract methods coupled to concrete
+ // method 'from' by some satisfy.Constraint, and rename
+ // them too.
+ //
+ // Coupling may be indirect, e.g. I.f <-> C.f via type D.
+ //
+ // type I interface {f()}
+ // type C int
+ // type (C) f()
+ // type D struct{C}
+ // var _ I = D{}
+ //
+ for key := range r.satisfy() {
+ // key = (lhs, rhs) where lhs is always an interface.
+ if isInterface(key.RHS) {
+ continue
+ }
+ rsel := r.msets.MethodSet(key.RHS).Lookup(from.Pkg(), from.Name())
+ if rsel == nil || rsel.Obj() != from {
+ continue // rhs does not have the method
+ }
+ lsel := r.msets.MethodSet(key.LHS).Lookup(from.Pkg(), from.Name())
+ if lsel == nil {
+ continue
+ }
+ imeth := lsel.Obj().(*types.Func)
+
+ // imeth is the abstract method (e.g. I.f)
+ // and key.RHS is the concrete coupling type (e.g. D).
+ if !r.changeMethods {
+ r.errorf(from.Pos(), "renaming this method %q to %q",
+ from.Name(), r.to)
+ var pos token.Pos
+ var iface string
+
+ I := recv(imeth).Type()
+ if named, ok := I.(*types.Named); ok {
+ pos = named.Obj().Pos()
+ iface = "interface " + named.Obj().Name()
+ } else {
+ pos = from.Pos()
+ iface = I.String()
+ }
+ r.errorf(pos, "\twould make %s no longer assignable to %s",
+ key.RHS, iface)
+ r.errorf(imeth.Pos(), "\t(rename %s.%s if you intend to change both types)",
+ I, from.Name())
+ return // one error is enough
+ }
+
+ // Rename the coupled interface method to preserve assignability.
+ r.check(imeth)
+ }
+ }
+
+ // Check integrity of existing (field and method) selections.
+ // We skip this if there were errors above, to avoid redundant errors.
+ r.checkSelections(from)
+}
+
+func (r *renamer) checkExport(id *ast.Ident, pkg *types.Package, from types.Object) bool {
+ // Reject cross-package references if r.to is unexported.
+ // (Such references may be qualified identifiers or field/method
+ // selections.)
+ if !ast.IsExported(r.to) && pkg != from.Pkg() {
+ r.errorf(from.Pos(),
+ "renaming this %s %q to %q would make it unexported",
+ objectKind(from), from.Name(), r.to)
+ r.errorf(id.Pos(), "\tbreaking references from packages such as %q",
+ pkg.Path())
+ return false
+ }
+ return true
+}
+
+// satisfy returns the set of interface satisfaction constraints.
+func (r *renamer) satisfy() map[satisfy.Constraint]bool {
+ if r.satisfyConstraints == nil {
+ // Compute on demand: it's expensive.
+ var f satisfy.Finder
+ for _, info := range r.packages {
+ f.Find(&info.Info, info.Files)
+ }
+ r.satisfyConstraints = f.Result
+ }
+ return r.satisfyConstraints
+}
+
+// -- helpers ----------------------------------------------------------
+
+// recv returns the method's receiver.
+func recv(meth *types.Func) *types.Var {
+ return meth.Type().(*types.Signature).Recv()
+}
+
+// someUse returns an arbitrary use of obj within info.
+func someUse(info *loader.PackageInfo, obj types.Object) *ast.Ident {
+ for id, o := range info.Uses {
+ if o == obj {
+ return id
+ }
+ }
+ return nil
+}
+
+// -- Plundered from golang.org/x/tools/go/ssa -----------------
+
+func isInterface(T types.Type) bool { return types.IsInterface(T) }
+
+func deref(typ types.Type) types.Type {
+ if p, _ := typ.(*types.Pointer); p != nil {
+ return p.Elem()
+ }
+ return typ
+}
diff --git a/refactor/rename/mvpkg.go b/refactor/rename/mvpkg.go
new file mode 100644
index 0000000..bb0d9b0
--- /dev/null
+++ b/refactor/rename/mvpkg.go
@@ -0,0 +1,343 @@
+// 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.
+
+// This file contains the implementation of the 'gomvpkg' command
+// whose main function is in golang.org/x/tools/cmd/gomvpkg.
+
+package rename
+
+// TODO(matloob):
+// - think about what happens if the package is moving across version control systems.
+// - think about windows, which uses "\" as its directory separator.
+// - dot imports are not supported. Make sure it's clearly documented.
+
+import (
+ "bytes"
+ "fmt"
+ "go/ast"
+ "go/build"
+ "log"
+ "os"
+ "os/exec"
+ "path"
+ "path/filepath"
+ "regexp"
+ "runtime"
+ "strconv"
+ "strings"
+ "text/template"
+
+ "golang.org/x/tools/go/buildutil"
+ "golang.org/x/tools/go/loader"
+ "golang.org/x/tools/refactor/importgraph"
+)
+
+// Move, given a package path and a destination package path, will try
+// to move the given package to the new path. The Move function will
+// first check for any conflicts preventing the move, such as a
+// package already existing at the destination package path. If the
+// move can proceed, it builds an import graph to find all imports of
+// the packages whose paths need to be renamed. This includes uses of
+// the subpackages of the package to be moved as those packages will
+// also need to be moved. It then renames all imports to point to the
+// new paths, and then moves the packages to their new paths.
+func Move(ctxt *build.Context, from, to, moveTmpl string) error {
+ srcDir, err := srcDir(ctxt, from)
+ if err != nil {
+ return err
+ }
+
+ // This should be the only place in the program that constructs
+ // file paths.
+ // TODO(matloob): test on Microsoft Windows.
+ fromDir := buildutil.JoinPath(ctxt, srcDir, filepath.FromSlash(from))
+ toDir := buildutil.JoinPath(ctxt, srcDir, filepath.FromSlash(to))
+ toParent := filepath.Dir(toDir)
+ if !buildutil.IsDir(ctxt, toParent) {
+ return fmt.Errorf("parent directory does not exist for path %s", toDir)
+ }
+
+ // Build the import graph and figure out which packages to update.
+ fwd, rev, errors := importgraph.Build(ctxt)
+ if len(errors) > 0 {
+ // With a large GOPATH tree, errors are inevitable.
+ // Report them but proceed.
+ fmt.Fprintf(os.Stderr, "While scanning Go workspace:\n")
+ for path, err := range errors {
+ fmt.Fprintf(os.Stderr, "Package %q: %s.\n", path, err)
+ }
+ }
+
+ // Determine the affected packages---the set of packages whose import
+ // statements need updating.
+ affectedPackages := map[string]bool{from: true}
+ destinations := map[string]string{} // maps old dir to new dir
+ for pkg := range subpackages(ctxt, srcDir, from) {
+ for r := range rev[pkg] {
+ affectedPackages[r] = true
+ }
+ destinations[pkg] = strings.Replace(pkg,
+ // Ensure directories have a trailing "/".
+ filepath.Join(from, ""), filepath.Join(to, ""), 1)
+ }
+
+ // Load all the affected packages.
+ iprog, err := loadProgram(ctxt, affectedPackages)
+ if err != nil {
+ return err
+ }
+
+ // Prepare the move command, if one was supplied.
+ var cmd string
+ if moveTmpl != "" {
+ if cmd, err = moveCmd(moveTmpl, fromDir, toDir); err != nil {
+ return err
+ }
+ }
+
+ m := mover{
+ ctxt: ctxt,
+ fwd: fwd,
+ rev: rev,
+ iprog: iprog,
+ from: from,
+ to: to,
+ fromDir: fromDir,
+ toDir: toDir,
+ affectedPackages: affectedPackages,
+ destinations: destinations,
+ cmd: cmd,
+ }
+
+ if err := m.checkValid(); err != nil {
+ return err
+ }
+
+ m.move()
+
+ return nil
+}
+
+// srcDir returns the absolute path of the srcdir containing pkg.
+func srcDir(ctxt *build.Context, pkg string) (string, error) {
+ for _, srcDir := range ctxt.SrcDirs() {
+ path := buildutil.JoinPath(ctxt, srcDir, pkg)
+ if buildutil.IsDir(ctxt, path) {
+ return srcDir, nil
+ }
+ }
+ return "", fmt.Errorf("src dir not found for package: %s", pkg)
+}
+
+// subpackages returns the set of packages in the given srcDir whose
+// import paths start with dir.
+func subpackages(ctxt *build.Context, srcDir string, dir string) map[string]bool {
+ subs := map[string]bool{dir: true}
+
+ // Find all packages under srcDir whose import paths start with dir.
+ buildutil.ForEachPackage(ctxt, func(pkg string, err error) {
+ if err != nil {
+ log.Fatalf("unexpected error in ForEachPackage: %v", err)
+ }
+
+ if !strings.HasPrefix(pkg, path.Join(dir, "")) {
+ return
+ }
+
+ p, err := ctxt.Import(pkg, "", build.FindOnly)
+ if err != nil {
+ log.Fatalf("unexpected: package %s can not be located by build context: %s", pkg, err)
+ }
+ if p.SrcRoot == "" {
+ log.Fatalf("unexpected: could not determine srcDir for package %s: %s", pkg, err)
+ }
+ if p.SrcRoot != srcDir {
+ return
+ }
+
+ subs[pkg] = true
+ })
+
+ return subs
+}
+
+type mover struct {
+ // iprog contains all packages whose contents need to be updated
+ // with new package names or import paths.
+ iprog *loader.Program
+ ctxt *build.Context
+ // fwd and rev are the forward and reverse import graphs
+ fwd, rev importgraph.Graph
+ // from and to are the source and destination import
+ // paths. fromDir and toDir are the source and destination
+ // absolute paths that package source files will be moved between.
+ from, to, fromDir, toDir string
+ // affectedPackages is the set of all packages whose contents need
+ // to be updated to reflect new package names or import paths.
+ affectedPackages map[string]bool
+ // destinations maps each subpackage to be moved to its
+ // destination path.
+ destinations map[string]string
+ // cmd, if not empty, will be executed to move fromDir to toDir.
+ cmd string
+}
+
+func (m *mover) checkValid() error {
+ const prefix = "invalid move destination"
+
+ match, err := regexp.MatchString("^[_\\pL][_\\pL\\p{Nd}]*$", path.Base(m.to))
+ if err != nil {
+ panic("regexp.MatchString failed")
+ }
+ if !match {
+ return fmt.Errorf("%s: %s; gomvpkg does not support move destinations "+
+ "whose base names are not valid go identifiers", prefix, m.to)
+ }
+
+ if buildutil.FileExists(m.ctxt, m.toDir) {
+ return fmt.Errorf("%s: %s conflicts with file %s", prefix, m.to, m.toDir)
+ }
+ if buildutil.IsDir(m.ctxt, m.toDir) {
+ return fmt.Errorf("%s: %s conflicts with directory %s", prefix, m.to, m.toDir)
+ }
+
+ for _, toSubPkg := range m.destinations {
+ if _, err := m.ctxt.Import(toSubPkg, "", build.FindOnly); err == nil {
+ return fmt.Errorf("%s: %s; package or subpackage %s already exists",
+ prefix, m.to, toSubPkg)
+ }
+ }
+
+ return nil
+}
+
+// moveCmd produces the version control move command used to move fromDir to toDir by
+// executing the given template.
+func moveCmd(moveTmpl, fromDir, toDir string) (string, error) {
+ tmpl, err := template.New("movecmd").Parse(moveTmpl)
+ if err != nil {
+ return "", err
+ }
+
+ var buf bytes.Buffer
+ err = tmpl.Execute(&buf, struct {
+ Src string
+ Dst string
+ }{fromDir, toDir})
+ return buf.String(), err
+}
+
+func (m *mover) move() error {
+ filesToUpdate := make(map[*ast.File]bool)
+
+ // Change the moved package's "package" declaration to its new base name.
+ pkg, ok := m.iprog.Imported[m.from]
+ if !ok {
+ log.Fatalf("unexpected: package %s is not in import map", m.from)
+ }
+ newName := filepath.Base(m.to)
+ for _, f := range pkg.Files {
+ f.Name.Name = newName // change package decl
+ filesToUpdate[f] = true
+ }
+
+ // Look through the external test packages (m.iprog.Created contains the external test packages).
+ for _, info := range m.iprog.Created {
+ // Change the "package" declaration of the external test package.
+ if info.Pkg.Path() == m.from+"_test" {
+ for _, f := range info.Files {
+ f.Name.Name = newName + "_test" // change package decl
+ filesToUpdate[f] = true
+ }
+ }
+
+ // Mark all the loaded external test packages, which import the "from" package,
+ // as affected packages and update the imports.
+ for _, imp := range info.Pkg.Imports() {
+ if imp.Path() == m.from {
+ m.affectedPackages[info.Pkg.Path()] = true
+ m.iprog.Imported[info.Pkg.Path()] = info
+ if err := importName(m.iprog, info, m.from, path.Base(m.from), newName); err != nil {
+ return err
+ }
+ }
+ }
+ }
+
+ // Update imports of that package to use the new import name.
+ // None of the subpackages will change their name---only the from package
+ // itself will.
+ for p := range m.rev[m.from] {
+ if err := importName(m.iprog, m.iprog.Imported[p], m.from, path.Base(m.from), newName); err != nil {
+ return err
+ }
+ }
+
+ // Update import paths for all imports by affected packages.
+ for ap := range m.affectedPackages {
+ info, ok := m.iprog.Imported[ap]
+ if !ok {
+ log.Fatalf("unexpected: package %s is not in import map", ap)
+ }
+ for _, f := range info.Files {
+ for _, imp := range f.Imports {
+ importPath, _ := strconv.Unquote(imp.Path.Value)
+ if newPath, ok := m.destinations[importPath]; ok {
+ imp.Path.Value = strconv.Quote(newPath)
+
+ oldName := path.Base(importPath)
+ if imp.Name != nil {
+ oldName = imp.Name.Name
+ }
+
+ newName := path.Base(newPath)
+ if imp.Name == nil && oldName != newName {
+ imp.Name = ast.NewIdent(oldName)
+ } else if imp.Name == nil || imp.Name.Name == newName {
+ imp.Name = nil
+ }
+ filesToUpdate[f] = true
+ }
+ }
+ }
+ }
+
+ for f := range filesToUpdate {
+ tokenFile := m.iprog.Fset.File(f.Pos())
+ rewriteFile(m.iprog.Fset, f, tokenFile.Name())
+ }
+
+ // Move the directories.
+ // If either the fromDir or toDir are contained under version control it is
+ // the user's responsibility to provide a custom move command that updates
+ // version control to reflect the move.
+ // TODO(matloob): If the parent directory of toDir does not exist, create it.
+ // For now, it's required that it does exist.
+
+ if m.cmd != "" {
+ // TODO(matloob): Verify that the windows and plan9 cases are correct.
+ var cmd *exec.Cmd
+ switch runtime.GOOS {
+ case "windows":
+ cmd = exec.Command("cmd", "/c", m.cmd)
+ case "plan9":
+ cmd = exec.Command("rc", "-c", m.cmd)
+ default:
+ cmd = exec.Command("sh", "-c", m.cmd)
+ }
+ cmd.Stderr = os.Stderr
+ cmd.Stdout = os.Stdout
+ if err := cmd.Run(); err != nil {
+ return fmt.Errorf("version control system's move command failed: %v", err)
+ }
+
+ return nil
+ }
+
+ return moveDirectory(m.fromDir, m.toDir)
+}
+
+var moveDirectory = func(from, to string) error {
+ return os.Rename(from, to)
+}
diff --git a/refactor/rename/mvpkg_test.go b/refactor/rename/mvpkg_test.go
new file mode 100644
index 0000000..61fa354
--- /dev/null
+++ b/refactor/rename/mvpkg_test.go
@@ -0,0 +1,316 @@
+// 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.
+
+package rename
+
+import (
+ "bytes"
+ "fmt"
+ "go/ast"
+ "go/build"
+ "go/format"
+ "go/token"
+ "io/ioutil"
+ "path/filepath"
+ "regexp"
+ "strings"
+ "testing"
+
+ "golang.org/x/tools/go/buildutil"
+)
+
+func TestErrors(t *testing.T) {
+ tests := []struct {
+ ctxt *build.Context
+ from, to string
+ want string // regexp to match error, or "OK"
+ }{
+ // Simple example.
+ {
+ ctxt: fakeContext(map[string][]string{
+ "foo": {`package foo; type T int`},
+ "bar": {`package bar`},
+ "main": {`package main
+
+import "foo"
+
+var _ foo.T
+`},
+ }),
+ from: "foo", to: "bar",
+ want: `invalid move destination: bar conflicts with directory .go.src.bar`,
+ },
+ // Subpackage already exists.
+ {
+ ctxt: fakeContext(map[string][]string{
+ "foo": {`package foo; type T int`},
+ "foo/sub": {`package sub`},
+ "bar/sub": {`package sub`},
+ "main": {`package main
+
+import "foo"
+
+var _ foo.T
+`},
+ }),
+ from: "foo", to: "bar",
+ want: "invalid move destination: bar; package or subpackage bar/sub already exists",
+ },
+ // Invalid base name.
+ {
+ ctxt: fakeContext(map[string][]string{
+ "foo": {`package foo; type T int`},
+ "main": {`package main
+
+import "foo"
+
+var _ foo.T
+`},
+ }),
+ from: "foo", to: "bar-v2.0",
+ want: "invalid move destination: bar-v2.0; gomvpkg does not " +
+ "support move destinations whose base names are not valid " +
+ "go identifiers",
+ },
+ }
+
+ for _, test := range tests {
+ ctxt := test.ctxt
+
+ got := make(map[string]string)
+ rewriteFile = func(fset *token.FileSet, f *ast.File, orig string) error {
+ var out bytes.Buffer
+ if err := format.Node(&out, fset, f); err != nil {
+ return err
+ }
+ got[orig] = out.String()
+ return nil
+ }
+ moveDirectory = func(from, to string) error {
+ for path, contents := range got {
+ if strings.HasPrefix(path, from) {
+ newPath := strings.Replace(path, from, to, 1)
+ delete(got, path)
+ got[newPath] = contents
+ }
+ }
+ return nil
+ }
+
+ err := Move(ctxt, test.from, test.to, "")
+ prefix := fmt.Sprintf("-from %q -to %q", test.from, test.to)
+ if err == nil {
+ t.Errorf("%s: nil error. Expected error: %s", prefix, test.want)
+ continue
+ }
+ matched, err2 := regexp.MatchString(test.want, err.Error())
+ if err2 != nil {
+ t.Errorf("regexp.MatchString failed %s", err2)
+ continue
+ }
+ if !matched {
+ t.Errorf("%s: conflict does not match expectation:\n"+
+ "Error: %q\n"+
+ "Pattern: %q",
+ prefix, err.Error(), test.want)
+ }
+ }
+}
+
+func TestMoves(t *testing.T) {
+ tests := []struct {
+ ctxt *build.Context
+ from, to string
+ want map[string]string
+ }{
+ // Simple example.
+ {
+ ctxt: fakeContext(map[string][]string{
+ "foo": {`package foo; type T int`},
+ "main": {`package main
+
+import "foo"
+
+var _ foo.T
+`},
+ }),
+ from: "foo", to: "bar",
+ want: map[string]string{
+ "/go/src/main/0.go": `package main
+
+import "bar"
+
+var _ bar.T
+`,
+ "/go/src/bar/0.go": `package bar
+
+type T int
+`,
+ },
+ },
+
+ // Example with subpackage.
+ {
+ ctxt: fakeContext(map[string][]string{
+ "foo": {`package foo; type T int`},
+ "foo/sub": {`package sub; type T int`},
+ "main": {`package main
+
+import "foo"
+import "foo/sub"
+
+var _ foo.T
+var _ sub.T
+`},
+ }),
+ from: "foo", to: "bar",
+ want: map[string]string{
+ "/go/src/main/0.go": `package main
+
+import "bar"
+import "bar/sub"
+
+var _ bar.T
+var _ sub.T
+`,
+ "/go/src/bar/0.go": `package bar
+
+type T int
+`,
+ "/go/src/bar/sub/0.go": `package sub; type T int`,
+ },
+ },
+
+ // References into subpackages
+ {
+ ctxt: fakeContext(map[string][]string{
+ "foo": {`package foo; import "foo/a"; var _ a.T`},
+ "foo/a": {`package a; type T int`},
+ "foo/b": {`package b; import "foo/a"; var _ a.T`},
+ }),
+ from: "foo", to: "bar",
+ want: map[string]string{
+ "/go/src/bar/0.go": `package bar
+
+import "bar/a"
+
+var _ a.T
+`,
+ "/go/src/bar/a/0.go": `package a; type T int`,
+ "/go/src/bar/b/0.go": `package b
+
+import "bar/a"
+
+var _ a.T
+`,
+ },
+ },
+
+ // External test packages
+ {
+ ctxt: buildutil.FakeContext(map[string]map[string]string{
+ "foo": {
+ "0.go": `package foo; type T int`,
+ "0_test.go": `package foo_test; import "foo"; var _ foo.T`,
+ },
+ "baz": {
+ "0_test.go": `package baz_test; import "foo"; var _ foo.T`,
+ },
+ }),
+ from: "foo", to: "bar",
+ want: map[string]string{
+ "/go/src/bar/0.go": `package bar
+
+type T int
+`,
+ "/go/src/bar/0_test.go": `package bar_test
+
+import "bar"
+
+var _ bar.T
+`,
+ "/go/src/baz/0_test.go": `package baz_test
+
+import "bar"
+
+var _ bar.T
+`,
+ },
+ },
+ }
+
+ for _, test := range tests {
+ ctxt := test.ctxt
+
+ got := make(map[string]string)
+ // Populate got with starting file set. rewriteFile and moveDirectory
+ // will mutate got to produce resulting file set.
+ buildutil.ForEachPackage(ctxt, func(importPath string, err error) {
+ if err != nil {
+ return
+ }
+ path := filepath.Join("/go/src", importPath, "0.go")
+ if !buildutil.FileExists(ctxt, path) {
+ return
+ }
+ f, err := ctxt.OpenFile(path)
+ if err != nil {
+ t.Errorf("unexpected error opening file: %s", err)
+ return
+ }
+ bytes, err := ioutil.ReadAll(f)
+ f.Close()
+ if err != nil {
+ t.Errorf("unexpected error reading file: %s", err)
+ return
+ }
+ got[path] = string(bytes)
+ })
+ rewriteFile = func(fset *token.FileSet, f *ast.File, orig string) error {
+ var out bytes.Buffer
+ if err := format.Node(&out, fset, f); err != nil {
+ return err
+ }
+ got[orig] = out.String()
+ return nil
+ }
+ moveDirectory = func(from, to string) error {
+ for path, contents := range got {
+ if strings.HasPrefix(path, from) {
+ newPath := strings.Replace(path, from, to, 1)
+ delete(got, path)
+ got[newPath] = contents
+ }
+ }
+ return nil
+ }
+
+ err := Move(ctxt, test.from, test.to, "")
+ prefix := fmt.Sprintf("-from %q -to %q", test.from, test.to)
+ if err != nil {
+ t.Errorf("%s: unexpected error: %s", prefix, err)
+ continue
+ }
+
+ for file, wantContent := range test.want {
+ k := filepath.FromSlash(file)
+ gotContent, ok := got[k]
+ delete(got, k)
+ if !ok {
+ // TODO(matloob): some testcases might have files that won't be
+ // rewritten
+ t.Errorf("%s: file %s not rewritten", prefix, file)
+ continue
+ }
+ if gotContent != wantContent {
+ t.Errorf("%s: rewritten file %s does not match expectation; got <<<%s>>>\n"+
+ "want <<<%s>>>", prefix, file, gotContent, wantContent)
+ }
+ }
+ // got should now be empty
+ for file := range got {
+ t.Errorf("%s: unexpected rewrite of file %s", prefix, file)
+ }
+ }
+}
diff --git a/refactor/rename/rename.el b/refactor/rename/rename.el
new file mode 100644
index 0000000..139bb47
--- /dev/null
+++ b/refactor/rename/rename.el
@@ -0,0 +1,96 @@
+;;; 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.
+;;;
+;;; Integration of the 'gorename' tool into Emacs.
+;;;
+;;; To install:
+;;; % go get golang.org/x/tools/cmd/gorename
+;;; % go build golang.org/x/tools/cmd/gorename
+;;; % mv gorename $HOME/bin/ # or elsewhere on $PATH
+;;;
+;;; The go-rename-command variable can be customized to specify an
+;;; alternative location for the installed command.
+
+(require 'compile)
+(require 'go-mode)
+(require 'thingatpt)
+
+(defgroup go-rename nil
+ "Options specific to the Go rename."
+ :group 'go)
+
+(defcustom go-rename-command "gorename"
+ "The `gorename' command; by the default, $PATH is searched."
+ :type 'string
+ :group 'go-rename)
+
+(defun go-rename (new-name &optional force)
+ "Rename the entity denoted by the identifier at point, using
+the `gorename' tool. With FORCE, call `gorename' with the
+`-force' flag."
+ (interactive (list (read-string "New name: " (thing-at-point 'symbol))
+ current-prefix-arg))
+ (if (not buffer-file-name)
+ (error "Cannot use go-rename on a buffer without a file name"))
+ ;; It's not sufficient to save the current buffer if modified,
+ ;; 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 current buffer before invoking go-rename"))
+ ;; Prompt-save all other modified Go buffers, since they might get written.
+ (save-some-buffers nil #'(lambda ()
+ (and (buffer-file-name)
+ (string= (file-name-extension (buffer-file-name)) ".go"))))
+ (let* ((posflag (format "-offset=%s:#%d"
+ buffer-file-name
+ (1- (go--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) ":")))
+ success)
+ (with-current-buffer (get-buffer-create "*go-rename*")
+ (setq buffer-read-only nil)
+ (erase-buffer)
+ (let ((args (append (list go-rename-command nil t nil posflag "-to" new-name) (if force '("-force")))))
+ ;; Log the command to *Messages*, for debugging.
+ (message "Command: %s:" args)
+ (message "Running gorename...")
+ ;; Use dynamic binding to modify/restore the environment
+ (setq success (zerop (let ((process-environment (list* goroot-env gopath-env process-environment)))
+ (apply #'call-process args))))
+ (insert "\n")
+ (compilation-mode)
+ (setq compilation-error-screen-columns nil)
+
+ ;; On success, print the one-line result in the message bar,
+ ;; and hide the *go-rename* buffer.
+ (if success
+ (progn
+ (message "%s" (go--buffer-string-no-trailing-space))
+ (gofmt--kill-error-buffer (current-buffer)))
+ ;; failure
+ (let ((w (display-buffer (current-buffer))))
+ (message "gorename exited")
+ (shrink-window-if-larger-than-buffer w)
+ (set-window-point w (point-min)))))))
+
+ ;; Reload the modified files, saving line/col.
+ ;; (Don't restore the point since the text has changed.)
+ ;;
+ ;; TODO(adonovan): should we also do this for all other files
+ ;; that were updated (the tool can print them)?
+ (let ((line (line-number-at-pos))
+ (col (current-column)))
+ (revert-buffer t t t) ; safe, because we just saved it
+ (goto-char (point-min))
+ (forward-line (1- line))
+ (forward-char col)))
+
+
+(defun go--buffer-string-no-trailing-space ()
+ (replace-regexp-in-string "[\t\n ]*\\'"
+ ""
+ (buffer-substring (point-min) (point-max))))
+
+(provide 'go-rename)
diff --git a/refactor/rename/rename.go b/refactor/rename/rename.go
new file mode 100644
index 0000000..a028c21
--- /dev/null
+++ b/refactor/rename/rename.go
@@ -0,0 +1,475 @@
+// 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 rename contains the implementation of the 'gorename' command
+// whose main function is in golang.org/x/tools/cmd/gorename.
+// See the Usage constant for the command documentation.
+package rename // import "golang.org/x/tools/refactor/rename"
+
+import (
+ "bytes"
+ "errors"
+ "fmt"
+ "go/ast"
+ "go/build"
+ "go/format"
+ "go/parser"
+ "go/token"
+ "io/ioutil"
+ "os"
+ "path"
+ "sort"
+ "strconv"
+ "strings"
+
+ "golang.org/x/tools/go/loader"
+ "golang.org/x/tools/go/types"
+ "golang.org/x/tools/go/types/typeutil"
+ "golang.org/x/tools/refactor/importgraph"
+ "golang.org/x/tools/refactor/satisfy"
+)
+
+const Usage = `gorename: precise type-safe renaming of identifiers in Go source code.
+
+Usage:
+
+ gorename (-from <spec> | -offset <file>:#<byte-offset>) -to <name> [-force]
+
+You must specify the object (named entity) to rename using the -offset
+or -from flag. Exactly one must be specified.
+
+Flags:
+
+-offset specifies the filename and byte offset of an identifier to rename.
+ This form is intended for use by text editors.
+
+-from specifies the object to rename using a query notation;
+ This form is intended for interactive use at the command line.
+ A legal -from query has one of the following forms:
+
+ "encoding/json".Decoder.Decode method of package-level named type
+ (*"encoding/json".Decoder).Decode ditto, alternative syntax
+ "encoding/json".Decoder.buf field of package-level named struct type
+ "encoding/json".HTMLEscape package member (const, func, var, type)
+ "encoding/json".Decoder.Decode::x local object x within a method
+ "encoding/json".HTMLEscape::x local object x within a function
+ "encoding/json"::x object x anywhere within a package
+ json.go::x object x within file json.go
+
+ Double-quotes must be escaped when writing a shell command.
+ Quotes may be omitted for single-segment import paths such as "fmt".
+
+ For methods, the parens and '*' on the receiver type are both
+ optional.
+
+ It is an error if one of the ::x queries matches multiple
+ objects.
+
+-to the new name.
+
+-force causes the renaming to proceed even if conflicts were reported.
+ The resulting program may be ill-formed, or experience a change
+ in behaviour.
+
+ WARNING: this flag may even cause the renaming tool to crash.
+ (In due course this bug will be fixed by moving certain
+ analyses into the type-checker.)
+
+-dryrun causes the tool to report conflicts but not update any files.
+
+-v enables verbose logging.
+
+gorename automatically computes the set of packages that might be
+affected. For a local renaming, this is just the package specified by
+-from or -offset, but for a potentially exported name, gorename scans
+the workspace ($GOROOT and $GOPATH).
+
+gorename rejects renamings of concrete methods that would change the
+assignability relation between types and interfaces. If the interface
+change was intentional, initiate the renaming at the interface method.
+
+gorename rejects any renaming that would create a conflict at the point
+of declaration, or a reference conflict (ambiguity or shadowing), or
+anything else that could cause the resulting program not to compile.
+
+
+Examples:
+
+% gorename -offset file.go:#123 -to foo
+
+ Rename the object whose identifier is at byte offset 123 within file file.go.
+
+% gorename -from \"bytes\".Buffer.Len' -to Size
+
+ Rename the "Len" method of the *bytes.Buffer type to "Size".
+
+---- TODO ----
+
+Correctness:
+- handle dot imports correctly
+- document limitations (reflection, 'implements' algorithm).
+- sketch a proof of exhaustiveness.
+
+Features:
+- support running on packages specified as *.go files on the command line
+- support running on programs containing errors (loader.Config.AllowErrors)
+- allow users to specify a scope other than "global" (to avoid being
+ stuck by neglected packages in $GOPATH that don't build).
+- support renaming the package clause (no object)
+- support renaming an import path (no ident or object)
+ (requires filesystem + SCM updates).
+- detect and reject edits to autogenerated files (cgo, protobufs)
+ and optionally $GOROOT packages.
+- report all conflicts, or at least all qualitatively distinct ones.
+ Sometimes we stop to avoid redundancy, but
+ it may give a disproportionate sense of safety in -force mode.
+- support renaming all instances of a pattern, e.g.
+ all receiver vars of a given type,
+ all local variables of a given type,
+ all PkgNames for a given package.
+- emit JSON output for other editors and tools.
+`
+
+var (
+ // Force enables patching of the source files even if conflicts were reported.
+ // The resulting program may be ill-formed.
+ // It may even cause gorename to crash. TODO(adonovan): fix that.
+ Force bool
+
+ // DryRun causes the tool to report conflicts but not update any files.
+ DryRun bool
+
+ // ConflictError is returned by Main when it aborts the renaming due to conflicts.
+ // (It is distinguished because the interesting errors are the conflicts themselves.)
+ ConflictError = errors.New("renaming aborted due to conflicts")
+
+ // Verbose enables extra logging.
+ Verbose bool
+)
+
+type renamer struct {
+ iprog *loader.Program
+ objsToUpdate map[types.Object]bool
+ hadConflicts bool
+ to string
+ satisfyConstraints map[satisfy.Constraint]bool
+ packages map[*types.Package]*loader.PackageInfo // subset of iprog.AllPackages to inspect
+ msets typeutil.MethodSetCache
+ changeMethods bool
+}
+
+var reportError = func(posn token.Position, message string) {
+ fmt.Fprintf(os.Stderr, "%s: %s\n", posn, message)
+}
+
+// importName renames imports of the package with the given path in
+// the given package. If fromName is not empty, only imports as
+// fromName will be renamed. If the renaming would lead to a conflict,
+// the file is left unchanged.
+func importName(iprog *loader.Program, info *loader.PackageInfo, fromPath, fromName, to string) error {
+ for _, f := range info.Files {
+ var from types.Object
+ for _, imp := range f.Imports {
+ importPath, _ := strconv.Unquote(imp.Path.Value)
+ importName := path.Base(importPath)
+ if imp.Name != nil {
+ importName = imp.Name.Name
+ }
+ if importPath == fromPath && (fromName == "" || importName == fromName) {
+ from = info.Implicits[imp]
+ break
+ }
+ }
+ if from == nil {
+ continue
+ }
+ r := renamer{
+ iprog: iprog,
+ objsToUpdate: make(map[types.Object]bool),
+ to: to,
+ packages: map[*types.Package]*loader.PackageInfo{info.Pkg: info},
+ }
+ r.check(from)
+ if r.hadConflicts {
+ continue // ignore errors; leave the existing name
+ }
+ if err := r.update(); err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+func Main(ctxt *build.Context, offsetFlag, fromFlag, to string) error {
+ // -- Parse the -from or -offset specifier ----------------------------
+
+ if (offsetFlag == "") == (fromFlag == "") {
+ return fmt.Errorf("exactly one of the -from and -offset flags must be specified")
+ }
+
+ if !isValidIdentifier(to) {
+ return fmt.Errorf("-to %q: not a valid identifier", to)
+ }
+
+ var spec *spec
+ var err error
+ if fromFlag != "" {
+ spec, err = parseFromFlag(ctxt, fromFlag)
+ } else {
+ spec, err = parseOffsetFlag(ctxt, offsetFlag)
+ }
+ if err != nil {
+ return err
+ }
+
+ if spec.fromName == to {
+ return fmt.Errorf("the old and new names are the same: %s", to)
+ }
+
+ // -- Load the program consisting of the initial package -------------
+
+ iprog, err := loadProgram(ctxt, map[string]bool{spec.pkg: true})
+ if err != nil {
+ return err
+ }
+
+ fromObjects, err := findFromObjects(iprog, spec)
+ if err != nil {
+ return err
+ }
+
+ // -- Load a larger program, for global renamings ---------------------
+
+ if requiresGlobalRename(fromObjects, to) {
+ // For a local refactoring, we needn't load more
+ // packages, but if the renaming affects the package's
+ // API, we we must load all packages that depend on the
+ // package defining the object, plus their tests.
+
+ if Verbose {
+ fmt.Fprintln(os.Stderr, "Potentially global renaming; scanning workspace...")
+ }
+
+ // Scan the workspace and build the import graph.
+ _, rev, errors := importgraph.Build(ctxt)
+ if len(errors) > 0 {
+ // With a large GOPATH tree, errors are inevitable.
+ // Report them but proceed.
+ fmt.Fprintf(os.Stderr, "While scanning Go workspace:\n")
+ for path, err := range errors {
+ fmt.Fprintf(os.Stderr, "Package %q: %s.\n", path, err)
+ }
+ }
+
+ // Enumerate the set of potentially affected packages.
+ affectedPackages := make(map[string]bool)
+ for _, obj := range fromObjects {
+ // External test packages are never imported,
+ // so they will never appear in the graph.
+ for path := range rev.Search(obj.Pkg().Path()) {
+ affectedPackages[path] = true
+ }
+ }
+
+ // TODO(adonovan): allow the user to specify the scope,
+ // or -ignore patterns? Computing the scope when we
+ // don't (yet) support inputs containing errors can make
+ // the tool rather brittle.
+
+ // Re-load the larger program.
+ iprog, err = loadProgram(ctxt, affectedPackages)
+ if err != nil {
+ return err
+ }
+
+ fromObjects, err = findFromObjects(iprog, spec)
+ if err != nil {
+ return err
+ }
+ }
+
+ // -- Do the renaming -------------------------------------------------
+
+ r := renamer{
+ iprog: iprog,
+ objsToUpdate: make(map[types.Object]bool),
+ to: to,
+ packages: make(map[*types.Package]*loader.PackageInfo),
+ }
+
+ // A renaming initiated at an interface method indicates the
+ // intention to rename abstract and concrete methods as needed
+ // to preserve assignability.
+ for _, obj := range fromObjects {
+ if obj, ok := obj.(*types.Func); ok {
+ recv := obj.Type().(*types.Signature).Recv()
+ if recv != nil && isInterface(recv.Type().Underlying()) {
+ r.changeMethods = true
+ break
+ }
+ }
+ }
+
+ // Only the initially imported packages (iprog.Imported) and
+ // their external tests (iprog.Created) should be inspected or
+ // modified, as only they have type-checked functions bodies.
+ // The rest are just dependencies, needed only for package-level
+ // type information.
+ for _, info := range iprog.Imported {
+ r.packages[info.Pkg] = info
+ }
+ for _, info := range iprog.Created { // (tests)
+ r.packages[info.Pkg] = info
+ }
+
+ for _, from := range fromObjects {
+ r.check(from)
+ }
+ if r.hadConflicts && !Force {
+ return ConflictError
+ }
+ if DryRun {
+ // TODO(adonovan): print the delta?
+ return nil
+ }
+ return r.update()
+}
+
+// loadProgram loads the specified set of packages (plus their tests)
+// and all their dependencies, from source, through the specified build
+// context. Only packages in pkgs will have their functions bodies typechecked.
+func loadProgram(ctxt *build.Context, pkgs map[string]bool) (*loader.Program, error) {
+ conf := loader.Config{
+ Build: ctxt,
+ ParserMode: parser.ParseComments,
+
+ // TODO(adonovan): enable this. Requires making a lot of code more robust!
+ AllowErrors: false,
+ }
+
+ // Optimization: don't type-check the bodies of functions in our
+ // dependencies, since we only need exported package members.
+ conf.TypeCheckFuncBodies = func(p string) bool {
+ return pkgs[p] || pkgs[strings.TrimSuffix(p, "_test")]
+ }
+
+ if Verbose {
+ var list []string
+ for pkg := range pkgs {
+ list = append(list, pkg)
+ }
+ sort.Strings(list)
+ for _, pkg := range list {
+ fmt.Fprintf(os.Stderr, "Loading package: %s\n", pkg)
+ }
+ }
+
+ for pkg := range pkgs {
+ conf.ImportWithTests(pkg)
+ }
+ return conf.Load()
+}
+
+// requiresGlobalRename reports whether this renaming could potentially
+// affect other packages in the Go workspace.
+func requiresGlobalRename(fromObjects []types.Object, to string) bool {
+ var tfm bool
+ for _, from := range fromObjects {
+ if from.Exported() {
+ return true
+ }
+ switch objectKind(from) {
+ case "type", "field", "method":
+ tfm = true
+ }
+ }
+ if ast.IsExported(to) && tfm {
+ // A global renaming may be necessary even if we're
+ // exporting a previous unexported name, since if it's
+ // the name of a type, field or method, this could
+ // change selections in other packages.
+ // (We include "type" in this list because a type
+ // used as an embedded struct field entails a field
+ // renaming.)
+ return true
+ }
+ return false
+}
+
+// update updates the input files.
+func (r *renamer) update() error {
+ // We use token.File, not filename, since a file may appear to
+ // belong to multiple packages and be parsed more than once.
+ // token.File captures this distinction; filename does not.
+ var nidents int
+ var filesToUpdate = make(map[*token.File]bool)
+ for _, info := range r.packages {
+ // Mutate the ASTs and note the filenames.
+ for id, obj := range info.Defs {
+ if r.objsToUpdate[obj] {
+ nidents++
+ id.Name = r.to
+ filesToUpdate[r.iprog.Fset.File(id.Pos())] = true
+ }
+ }
+ for id, obj := range info.Uses {
+ if r.objsToUpdate[obj] {
+ nidents++
+ id.Name = r.to
+ filesToUpdate[r.iprog.Fset.File(id.Pos())] = true
+ }
+ }
+ }
+
+ // TODO(adonovan): don't rewrite cgo + generated files.
+ var nerrs, npkgs int
+ for _, info := range r.packages {
+ first := true
+ for _, f := range info.Files {
+ tokenFile := r.iprog.Fset.File(f.Pos())
+ if filesToUpdate[tokenFile] {
+ if first {
+ npkgs++
+ first = false
+ if Verbose {
+ fmt.Fprintf(os.Stderr, "Updating package %s\n",
+ info.Pkg.Path())
+ }
+ }
+ if err := rewriteFile(r.iprog.Fset, f, tokenFile.Name()); err != nil {
+ fmt.Fprintf(os.Stderr, "gorename: %s\n", err)
+ nerrs++
+ }
+ }
+ }
+ }
+ fmt.Fprintf(os.Stderr, "Renamed %d occurrence%s in %d file%s in %d package%s.\n",
+ nidents, plural(nidents),
+ len(filesToUpdate), plural(len(filesToUpdate)),
+ npkgs, plural(npkgs))
+ if nerrs > 0 {
+ return fmt.Errorf("failed to rewrite %d file%s", nerrs, plural(nerrs))
+ }
+ return nil
+}
+
+func plural(n int) string {
+ if n != 1 {
+ return "s"
+ }
+ return ""
+}
+
+var rewriteFile = func(fset *token.FileSet, f *ast.File, filename string) (err error) {
+ // TODO(adonovan): print packages and filenames in a form useful
+ // to editors (so they can reload files).
+ if Verbose {
+ fmt.Fprintf(os.Stderr, "\t%s\n", filename)
+ }
+ var buf bytes.Buffer
+ if err := format.Node(&buf, fset, f); err != nil {
+ return fmt.Errorf("failed to pretty-print syntax tree: %v", err)
+ }
+ return ioutil.WriteFile(filename, buf.Bytes(), 0644)
+}
diff --git a/refactor/rename/rename_test.go b/refactor/rename/rename_test.go
new file mode 100644
index 0000000..1d282a1
--- /dev/null
+++ b/refactor/rename/rename_test.go
@@ -0,0 +1,1040 @@
+// 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 rename
+
+import (
+ "bytes"
+ "fmt"
+ "go/ast"
+ "go/build"
+ "go/format"
+ "go/token"
+ "path/filepath"
+ "regexp"
+ "strings"
+ "testing"
+
+ "golang.org/x/tools/go/buildutil"
+)
+
+// TODO(adonovan): test reported source positions, somehow.
+
+func TestConflicts(t *testing.T) {
+ defer func(savedDryRun bool, savedReportError func(token.Position, string)) {
+ DryRun = savedDryRun
+ reportError = savedReportError
+ }(DryRun, reportError)
+ DryRun = true
+
+ var ctxt *build.Context
+ for _, test := range []struct {
+ ctxt *build.Context // nil => use previous
+ offset, from, to string // values of the -offset/-from and -to flags
+ want string // regexp to match conflict errors, or "OK"
+ }{
+ // init() checks
+ {
+ ctxt: fakeContext(map[string][]string{
+ "fmt": {`package fmt; type Stringer interface { String() }`},
+ "main": {`
+package main
+
+import foo "fmt"
+
+var v foo.Stringer
+
+func f() { v.String(); f() }
+`,
+ `package main; var w int`},
+ }),
+ from: "main.v", to: "init",
+ want: `you cannot have a var at package level named "init"`,
+ },
+ {
+ from: "main.f", to: "init",
+ want: `renaming this func "f" to "init" would make it a package initializer.*` +
+ `but references to it exist`,
+ },
+ {
+ from: "/go/src/main/0.go::foo", to: "init",
+ want: `"init" is not a valid imported package name`,
+ },
+
+ // Export checks
+ {
+ from: "fmt.Stringer", to: "stringer",
+ want: `renaming this type "Stringer" to "stringer" would make it unexported.*` +
+ `breaking references from packages such as "main"`,
+ },
+ {
+ from: "(fmt.Stringer).String", to: "string",
+ want: `renaming this method "String" to "string" would make it unexported.*` +
+ `breaking references from packages such as "main"`,
+ },
+
+ // Lexical scope checks
+ {
+ // file/package conflict, same file
+ from: "main.v", to: "foo",
+ want: `renaming this var "v" to "foo" would conflict.*` +
+ `with this imported package name`,
+ },
+ {
+ // file/package conflict, same file
+ from: "main::foo", to: "v",
+ want: `renaming this imported package name "foo" to "v" would conflict.*` +
+ `with this package member var`,
+ },
+ {
+ // file/package conflict, different files
+ from: "main.w", to: "foo",
+ want: `renaming this var "w" to "foo" would conflict.*` +
+ `with this imported package name`,
+ },
+ {
+ // file/package conflict, different files
+ from: "main::foo", to: "w",
+ want: `renaming this imported package name "foo" to "w" would conflict.*` +
+ `with this package member var`,
+ },
+ {
+ ctxt: main(`
+package main
+
+var x, z int
+
+func f(y int) {
+ print(x)
+ print(y)
+}
+
+func g(w int) {
+ print(x)
+ x := 1
+ print(x)
+}`),
+ from: "main.x", to: "y",
+ want: `renaming this var "x" to "y".*` +
+ `would cause this reference to become shadowed.*` +
+ `by this intervening var definition`,
+ },
+ {
+ from: "main.g::x", to: "w",
+ want: `renaming this var "x" to "w".*` +
+ `conflicts with var in same block`,
+ },
+ {
+ from: "main.f::y", to: "x",
+ want: `renaming this var "y" to "x".*` +
+ `would shadow this reference.*` +
+ `to the var declared here`,
+ },
+ {
+ from: "main.g::w", to: "x",
+ want: `renaming this var "w" to "x".*` +
+ `conflicts with var in same block`,
+ },
+ {
+ from: "main.z", to: "y", want: "OK",
+ },
+
+ // Label checks
+ {
+ ctxt: main(`
+package main
+
+func f() {
+foo:
+ goto foo
+bar:
+ goto bar
+ func(x int) {
+ wiz:
+ goto wiz
+ }(0)
+}
+`),
+ from: "main.f::foo", to: "bar",
+ want: `renaming this label "foo" to "bar".*` +
+ `would conflict with this one`,
+ },
+ {
+ from: "main.f::foo", to: "wiz", want: "OK",
+ },
+ {
+ from: "main.f::wiz", to: "x", want: "OK",
+ },
+ {
+ from: "main.f::x", to: "wiz", want: "OK",
+ },
+ {
+ from: "main.f::wiz", to: "foo", want: "OK",
+ },
+
+ // Struct fields
+ {
+ ctxt: main(`
+package main
+
+type U struct { u int }
+type V struct { v int }
+
+func (V) x() {}
+
+type W (struct {
+ U
+ V
+ w int
+})
+
+func f() {
+ var w W
+ print(w.u) // NB: there is no selection of w.v
+ var _ struct { yy, zz int }
+}
+`),
+ // field/field conflict in named struct declaration
+ from: "(main.W).U", to: "w",
+ want: `renaming this field "U" to "w".*` +
+ `would conflict with this field`,
+ },
+ {
+ // rename type used as embedded field
+ // => rename field
+ // => field/field conflict
+ // This is an entailed renaming;
+ // it would be nice if we checked source positions.
+ from: "main.U", to: "w",
+ want: `renaming this field "U" to "w".*` +
+ `would conflict with this field`,
+ },
+ {
+ // field/field conflict in unnamed struct declaration
+ from: "main.f::zz", to: "yy",
+ want: `renaming this field "zz" to "yy".*` +
+ `would conflict with this field`,
+ },
+
+ // Now we test both directions of (u,v) (u,w) (v,w) (u,x) (v,x).
+ // Too bad we don't test position info...
+ {
+ // field/field ambiguity at same promotion level ('from' selection)
+ from: "(main.U).u", to: "v",
+ want: `renaming this field "u" to "v".*` +
+ `would make this reference ambiguous.*` +
+ `with this field`,
+ },
+ {
+ // field/field ambiguity at same promotion level ('to' selection)
+ from: "(main.V).v", to: "u",
+ want: `renaming this field "v" to "u".*` +
+ `would make this reference ambiguous.*` +
+ `with this field`,
+ },
+ {
+ // field/method conflict at different promotion level ('from' selection)
+ from: "(main.U).u", to: "w",
+ want: `renaming this field "u" to "w".*` +
+ `would change the referent of this selection.*` +
+ `of this field`,
+ },
+ {
+ // field/field shadowing at different promotion levels ('to' selection)
+ from: "(main.W).w", to: "u",
+ want: `renaming this field "w" to "u".*` +
+ `would shadow this selection.*` +
+ `of the field declared here`,
+ },
+ {
+ from: "(main.V).v", to: "w",
+ want: "OK", // since no selections are made ambiguous
+ },
+ {
+ from: "(main.W).w", to: "v",
+ want: "OK", // since no selections are made ambiguous
+ },
+ {
+ // field/method ambiguity at same promotion level ('from' selection)
+ from: "(main.U).u", to: "x",
+ want: `renaming this field "u" to "x".*` +
+ `would make this reference ambiguous.*` +
+ `with this method`,
+ },
+ {
+ // field/field ambiguity at same promotion level ('to' selection)
+ from: "(main.V).x", to: "u",
+ want: `renaming this method "x" to "u".*` +
+ `would make this reference ambiguous.*` +
+ `with this field`,
+ },
+ {
+ // field/method conflict at named struct declaration
+ from: "(main.V).v", to: "x",
+ want: `renaming this field "v" to "x".*` +
+ `would conflict with this method`,
+ },
+ {
+ // field/method conflict at named struct declaration
+ from: "(main.V).x", to: "v",
+ want: `renaming this method "x" to "v".*` +
+ `would conflict with this field`,
+ },
+
+ // Methods
+ {
+ ctxt: main(`
+package main
+type C int
+func (C) f()
+func (C) g()
+type D int
+func (*D) f()
+func (*D) g()
+type I interface { f(); g() }
+type J interface { I; h() }
+var _ I = new(D)
+var _ interface {f()} = C(0)
+`),
+ from: "(main.I).f", to: "g",
+ want: `renaming this interface method "f" to "g".*` +
+ `would conflict with this method`,
+ },
+ {
+ from: `("main".I).f`, to: "h", // NB: exercises quoted import paths too
+ want: `renaming this interface method "f" to "h".*` +
+ `would conflict with this method.*` +
+ `in named interface type "J"`,
+ },
+ {
+ // type J interface { h; h() } is not a conflict, amusingly.
+ from: "main.I", to: "h",
+ want: `OK`,
+ },
+ {
+ from: "(main.J).h", to: "f",
+ want: `renaming this interface method "h" to "f".*` +
+ `would conflict with this method`,
+ },
+ {
+ from: "(main.C).f", to: "e",
+ want: `renaming this method "f" to "e".*` +
+ `would make main.C no longer assignable to interface{f..}.*` +
+ `(rename interface{f..}.f if you intend to change both types)`,
+ },
+ {
+ from: "(main.D).g", to: "e",
+ want: `renaming this method "g" to "e".*` +
+ `would make \*main.D no longer assignable to interface I.*` +
+ `(rename main.I.g if you intend to change both types)`,
+ },
+ {
+ from: "(main.I).f", to: "e",
+ want: `OK`,
+ },
+ // Indirect C/I method coupling via another concrete type D.
+ {
+ ctxt: main(`
+package main
+type I interface { f() }
+type C int
+func (C) f()
+type D struct{C}
+var _ I = D{}
+`),
+ from: "(main.C).f", to: "F",
+ want: `renaming this method "f" to "F".*` +
+ `would make main.D no longer assignable to interface I.*` +
+ `(rename main.I.f if you intend to change both types)`,
+ },
+ // Renaming causes promoted method to become shadowed; C no longer satisfies I.
+ {
+ ctxt: main(`
+package main
+type I interface { f() }
+type C struct { I }
+func (C) g() int
+var _ I = C{}
+`),
+ from: "main.I.f", to: "g",
+ want: `renaming this method "f" to "g".*` +
+ `would change the g method of main.C invoked via interface main.I.*` +
+ `from \(main.I\).g.*` +
+ `to \(main.C\).g`,
+ },
+ // Renaming causes promoted method to become ambiguous; C no longer satisfies I.
+ {
+ ctxt: main(`
+package main
+type I interface{f()}
+type C int
+func (C) f()
+type D int
+func (D) g()
+type E struct{C;D}
+var _ I = E{}
+`),
+ from: "main.I.f", to: "g",
+ want: `renaming this method "f" to "g".*` +
+ `would make the g method of main.E invoked via interface main.I ambiguous.*` +
+ `with \(main.D\).g`,
+ },
+ } {
+ var conflicts []string
+ reportError = func(posn token.Position, message string) {
+ conflicts = append(conflicts, message)
+ }
+ if test.ctxt != nil {
+ ctxt = test.ctxt
+ }
+ err := Main(ctxt, test.offset, test.from, test.to)
+ var prefix string
+ if test.offset == "" {
+ prefix = fmt.Sprintf("-from %q -to %q", test.from, test.to)
+ } else {
+ prefix = fmt.Sprintf("-offset %q -to %q", test.offset, test.to)
+ }
+ if err == ConflictError {
+ got := strings.Join(conflicts, "\n")
+ if false {
+ t.Logf("%s: %s", prefix, got)
+ }
+ pattern := "(?s:" + test.want + ")" // enable multi-line matching
+ if !regexp.MustCompile(pattern).MatchString(got) {
+ t.Errorf("%s: conflict does not match pattern:\n"+
+ "Conflict:\t%s\n"+
+ "Pattern: %s",
+ prefix, got, test.want)
+ }
+ } else if err != nil {
+ t.Errorf("%s: unexpected error: %s", prefix, err)
+ } else if test.want != "OK" {
+ t.Errorf("%s: unexpected success, want conflicts matching:\n%s",
+ prefix, test.want)
+ }
+ }
+}
+
+func TestRewrites(t *testing.T) {
+ defer func(savedRewriteFile func(*token.FileSet, *ast.File, string) error) {
+ rewriteFile = savedRewriteFile
+ }(rewriteFile)
+
+ var ctxt *build.Context
+ for _, test := range []struct {
+ ctxt *build.Context // nil => use previous
+ offset, from, to string // values of the -from/-offset and -to flags
+ want map[string]string // contents of updated files
+ }{
+ // Elimination of renaming import.
+ {
+ ctxt: fakeContext(map[string][]string{
+ "foo": {`package foo; type T int`},
+ "main": {`package main
+
+import foo2 "foo"
+
+var _ foo2.T
+`},
+ }),
+ from: "main::foo2", to: "foo",
+ want: map[string]string{
+ "/go/src/main/0.go": `package main
+
+import "foo"
+
+var _ foo.T
+`,
+ },
+ },
+ // Introduction of renaming import.
+ {
+ ctxt: fakeContext(map[string][]string{
+ "foo": {`package foo; type T int`},
+ "main": {`package main
+
+import "foo"
+
+var _ foo.T
+`},
+ }),
+ offset: "/go/src/main/0.go:#36", to: "foo2", // the "foo" in foo.T
+ want: map[string]string{
+ "/go/src/main/0.go": `package main
+
+import foo2 "foo"
+
+var _ foo2.T
+`,
+ },
+ },
+ // Renaming of package-level member.
+ {
+ from: "foo.T", to: "U",
+ want: map[string]string{
+ "/go/src/main/0.go": `package main
+
+import "foo"
+
+var _ foo.U
+`,
+ "/go/src/foo/0.go": `package foo
+
+type U int
+`,
+ },
+ },
+ // Label renamings.
+ {
+ ctxt: main(`package main
+func f() {
+loop:
+ loop := 0
+ go func() {
+ loop:
+ goto loop
+ }()
+ loop++
+ goto loop
+}
+`),
+ offset: "/go/src/main/0.go:#25", to: "loop2", // def of outer label "loop"
+ want: map[string]string{
+ "/go/src/main/0.go": `package main
+
+func f() {
+loop2:
+ loop := 0
+ go func() {
+ loop:
+ goto loop
+ }()
+ loop++
+ goto loop2
+}
+`,
+ },
+ },
+ {
+ offset: "/go/src/main/0.go:#70", to: "loop2", // ref to inner label "loop"
+ want: map[string]string{
+ "/go/src/main/0.go": `package main
+
+func f() {
+loop:
+ loop := 0
+ go func() {
+ loop2:
+ goto loop2
+ }()
+ loop++
+ goto loop
+}
+`,
+ },
+ },
+ // Renaming of type used as embedded field.
+ {
+ ctxt: main(`package main
+
+type T int
+type U struct { T }
+
+var _ = U{}.T
+`),
+ from: "main.T", to: "T2",
+ want: map[string]string{
+ "/go/src/main/0.go": `package main
+
+type T2 int
+type U struct{ T2 }
+
+var _ = U{}.T2
+`,
+ },
+ },
+ // Renaming of embedded field.
+ {
+ ctxt: main(`package main
+
+type T int
+type U struct { T }
+
+var _ = U{}.T
+`),
+ offset: "/go/src/main/0.go:#58", to: "T2", // T in "U{}.T"
+ want: map[string]string{
+ "/go/src/main/0.go": `package main
+
+type T2 int
+type U struct{ T2 }
+
+var _ = U{}.T2
+`,
+ },
+ },
+ // Renaming of pointer embedded field.
+ {
+ ctxt: main(`package main
+
+type T int
+type U struct { *T }
+
+var _ = U{}.T
+`),
+ offset: "/go/src/main/0.go:#59", to: "T2", // T in "U{}.T"
+ want: map[string]string{
+ "/go/src/main/0.go": `package main
+
+type T2 int
+type U struct{ *T2 }
+
+var _ = U{}.T2
+`,
+ },
+ },
+
+ // Lexical scope tests.
+ {
+ ctxt: main(`package main
+
+var y int
+
+func f() {
+ print(y)
+ y := ""
+ print(y)
+}
+`),
+ from: "main.y", to: "x",
+ want: map[string]string{
+ "/go/src/main/0.go": `package main
+
+var x int
+
+func f() {
+ print(x)
+ y := ""
+ print(y)
+}
+`,
+ },
+ },
+ {
+ from: "main.f::y", to: "x",
+ want: map[string]string{
+ "/go/src/main/0.go": `package main
+
+var y int
+
+func f() {
+ print(y)
+ x := ""
+ print(x)
+}
+`,
+ },
+ },
+ // Renaming of typeswitch vars (a corner case).
+ {
+ ctxt: main(`package main
+
+func f(z interface{}) {
+ switch y := z.(type) {
+ case int:
+ print(y)
+ default:
+ print(y)
+ }
+}
+`),
+ offset: "/go/src/main/0.go:#46", to: "x", // def of y
+ want: map[string]string{
+ "/go/src/main/0.go": `package main
+
+func f(z interface{}) {
+ switch x := z.(type) {
+ case int:
+ print(x)
+ default:
+ print(x)
+ }
+}
+`},
+ },
+ {
+ offset: "/go/src/main/0.go:#81", to: "x", // ref of y in case int
+ want: map[string]string{
+ "/go/src/main/0.go": `package main
+
+func f(z interface{}) {
+ switch x := z.(type) {
+ case int:
+ print(x)
+ default:
+ print(x)
+ }
+}
+`},
+ },
+ {
+ offset: "/go/src/main/0.go:#102", to: "x", // ref of y in default case
+ want: map[string]string{
+ "/go/src/main/0.go": `package main
+
+func f(z interface{}) {
+ switch x := z.(type) {
+ case int:
+ print(x)
+ default:
+ print(x)
+ }
+}
+`},
+ },
+
+ // Renaming of embedded field that is a qualified reference.
+ // (Regression test for bug 8924.)
+ {
+ ctxt: fakeContext(map[string][]string{
+ "foo": {`package foo; type T int`},
+ "main": {`package main
+
+import "foo"
+
+type _ struct{ *foo.T }
+`},
+ }),
+ offset: "/go/src/main/0.go:#48", to: "U", // the "T" in *foo.T
+ want: map[string]string{
+ "/go/src/foo/0.go": `package foo
+
+type U int
+`,
+ "/go/src/main/0.go": `package main
+
+import "foo"
+
+type _ struct{ *foo.U }
+`,
+ },
+ },
+
+ // Interface method renaming.
+ {
+ ctxt: fakeContext(map[string][]string{
+ "main": {`
+package main
+type I interface { f() }
+type J interface { f(); g() }
+type A int
+func (A) f()
+type B int
+func (B) f()
+func (B) g()
+type C int
+func (C) f()
+func (C) g()
+var _, _ I = A(0), B(0)
+var _, _ J = B(0), C(0)
+`,
+ },
+ }),
+ offset: "/go/src/main/0.go:#33", to: "F", // abstract method I.f
+ want: map[string]string{
+ "/go/src/main/0.go": `package main
+
+type I interface {
+ F()
+}
+type J interface {
+ F()
+ g()
+}
+type A int
+
+func (A) F()
+
+type B int
+
+func (B) F()
+func (B) g()
+
+type C int
+
+func (C) F()
+func (C) g()
+
+var _, _ I = A(0), B(0)
+var _, _ J = B(0), C(0)
+`,
+ },
+ },
+ {
+ offset: "/go/src/main/0.go:#58", to: "F", // abstract method J.f
+ want: map[string]string{
+ "/go/src/main/0.go": `package main
+
+type I interface {
+ F()
+}
+type J interface {
+ F()
+ g()
+}
+type A int
+
+func (A) F()
+
+type B int
+
+func (B) F()
+func (B) g()
+
+type C int
+
+func (C) F()
+func (C) g()
+
+var _, _ I = A(0), B(0)
+var _, _ J = B(0), C(0)
+`,
+ },
+ },
+ {
+ offset: "/go/src/main/0.go:#63", to: "G", // abstract method J.g
+ want: map[string]string{
+ "/go/src/main/0.go": `package main
+
+type I interface {
+ f()
+}
+type J interface {
+ f()
+ G()
+}
+type A int
+
+func (A) f()
+
+type B int
+
+func (B) f()
+func (B) G()
+
+type C int
+
+func (C) f()
+func (C) G()
+
+var _, _ I = A(0), B(0)
+var _, _ J = B(0), C(0)
+`,
+ },
+ },
+ // Indirect coupling of I.f to C.f from D->I assignment and anonymous field of D.
+ {
+ ctxt: fakeContext(map[string][]string{
+ "main": {`
+package main
+type I interface { f() }
+type C int
+func (C) f()
+type D struct{C}
+var _ I = D{}
+`,
+ },
+ }),
+ offset: "/go/src/main/0.go:#33", to: "F", // abstract method I.f
+ want: map[string]string{
+ "/go/src/main/0.go": `package main
+
+type I interface {
+ F()
+}
+type C int
+
+func (C) F()
+
+type D struct{ C }
+
+var _ I = D{}
+`,
+ },
+ },
+ // Interface embedded in struct. No conflict if C need not satisfy I.
+ {
+ ctxt: fakeContext(map[string][]string{
+ "main": {`
+package main
+type I interface {f()}
+type C struct{I}
+func (C) g() int
+var _ int = C{}.g()
+`,
+ },
+ }),
+ offset: "/go/src/main/0.go:#32", to: "g", // abstract method I.f
+ want: map[string]string{
+ "/go/src/main/0.go": `package main
+
+type I interface {
+ g()
+}
+type C struct{ I }
+
+func (C) g() int
+
+var _ int = C{}.g()
+`,
+ },
+ },
+ // A type assertion causes method coupling iff signatures match.
+ {
+ ctxt: fakeContext(map[string][]string{
+ "main": {`package main
+type I interface{f()}
+type J interface{f()}
+var _ = I(nil).(J)
+`,
+ },
+ }),
+ offset: "/go/src/main/0.go:#30", to: "g", // abstract method I.f
+ want: map[string]string{
+ "/go/src/main/0.go": `package main
+
+type I interface {
+ g()
+}
+type J interface {
+ g()
+}
+
+var _ = I(nil).(J)
+`,
+ },
+ },
+ // Impossible type assertion: no method coupling.
+ {
+ ctxt: fakeContext(map[string][]string{
+ "main": {`package main
+type I interface{f()}
+type J interface{f()int}
+var _ = I(nil).(J)
+`,
+ },
+ }),
+ offset: "/go/src/main/0.go:#30", to: "g", // abstract method I.f
+ want: map[string]string{
+ "/go/src/main/0.go": `package main
+
+type I interface {
+ g()
+}
+type J interface {
+ f() int
+}
+
+var _ = I(nil).(J)
+`,
+ },
+ },
+ // Impossible type assertion: no method coupling C.f<->J.f.
+ {
+ ctxt: fakeContext(map[string][]string{
+ "main": {`package main
+type I interface{f()}
+type C int
+func (C) f()
+type J interface{f()int}
+var _ = I(C(0)).(J)
+`,
+ },
+ }),
+ offset: "/go/src/main/0.go:#30", to: "g", // abstract method I.f
+ want: map[string]string{
+ "/go/src/main/0.go": `package main
+
+type I interface {
+ g()
+}
+type C int
+
+func (C) g()
+
+type J interface {
+ f() int
+}
+
+var _ = I(C(0)).(J)
+`,
+ },
+ },
+ } {
+ if test.ctxt != nil {
+ ctxt = test.ctxt
+ }
+
+ got := make(map[string]string)
+ rewriteFile = func(fset *token.FileSet, f *ast.File, orig string) error {
+ var out bytes.Buffer
+ if err := format.Node(&out, fset, f); err != nil {
+ return err
+ }
+ got[filepath.ToSlash(orig)] = out.String()
+ return nil
+ }
+
+ err := Main(ctxt, test.offset, test.from, test.to)
+ var prefix string
+ if test.offset == "" {
+ prefix = fmt.Sprintf("-from %q -to %q", test.from, test.to)
+ } else {
+ prefix = fmt.Sprintf("-offset %q -to %q", test.offset, test.to)
+ }
+ if err != nil {
+ t.Errorf("%s: unexpected error: %s", prefix, err)
+ continue
+ }
+
+ for file, wantContent := range test.want {
+ gotContent, ok := got[file]
+ delete(got, file)
+ if !ok {
+ t.Errorf("%s: file %s not rewritten", prefix, file)
+ continue
+ }
+ if gotContent != wantContent {
+ t.Errorf("%s: rewritten file %s does not match expectation; got <<<%s>>>\n"+
+ "want <<<%s>>>", prefix, file, gotContent, wantContent)
+ }
+ }
+ // got should now be empty
+ for file := range got {
+ t.Errorf("%s: unexpected rewrite of file %s", prefix, file)
+ }
+ }
+}
+
+// ---------------------------------------------------------------------
+
+// Simplifying wrapper around buildutil.FakeContext for packages whose
+// filenames are sequentially numbered (%d.go). pkgs maps a package
+// import path to its list of file contents.
+func fakeContext(pkgs map[string][]string) *build.Context {
+ pkgs2 := make(map[string]map[string]string)
+ for path, files := range pkgs {
+ filemap := make(map[string]string)
+ for i, contents := range files {
+ filemap[fmt.Sprintf("%d.go", i)] = contents
+ }
+ pkgs2[path] = filemap
+ }
+ return buildutil.FakeContext(pkgs2)
+}
+
+// helper for single-file main packages with no imports.
+func main(content string) *build.Context {
+ return fakeContext(map[string][]string{"main": {content}})
+}
diff --git a/refactor/rename/spec.go b/refactor/rename/spec.go
new file mode 100644
index 0000000..3c73653
--- /dev/null
+++ b/refactor/rename/spec.go
@@ -0,0 +1,549 @@
+// 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 rename
+
+// This file contains logic related to specifying a renaming: parsing of
+// the flags as a form of query, and finding the object(s) it denotes.
+// See Usage for flag details.
+
+import (
+ "bytes"
+ "fmt"
+ "go/ast"
+ "go/build"
+ "go/parser"
+ "go/token"
+ "os"
+ "path/filepath"
+ "strconv"
+ "strings"
+
+ "golang.org/x/tools/go/buildutil"
+ "golang.org/x/tools/go/loader"
+ "golang.org/x/tools/go/types"
+)
+
+// A spec specifies an entity to rename.
+//
+// It is populated from an -offset flag or -from query;
+// see Usage for the allowed -from query forms.
+//
+type spec struct {
+ // pkg is the package containing the position
+ // specified by the -from or -offset flag.
+ // If filename == "", our search for the 'from' entity
+ // is restricted to this package.
+ pkg string
+
+ // The original name of the entity being renamed.
+ // If the query had a ::from component, this is that;
+ // otherwise it's the last segment, e.g.
+ // (encoding/json.Decoder).from
+ // encoding/json.from
+ fromName string
+
+ // -- The remaining fields are private to this file. All are optional. --
+
+ // The query's ::x suffix, if any.
+ searchFor string
+
+ // e.g. "Decoder" in "(encoding/json.Decoder).fieldOrMethod"
+ // or "encoding/json.Decoder
+ pkgMember string
+
+ // e.g. fieldOrMethod in "(encoding/json.Decoder).fieldOrMethod"
+ typeMember string
+
+ // Restricts the query to this file.
+ // Implied by -from="file.go::x" and -offset flags.
+ filename string
+
+ // Byte offset of the 'from' identifier within the file named 'filename'.
+ // -offset mode only.
+ offset int
+}
+
+// parseFromFlag interprets the "-from" flag value as a renaming specification.
+// See Usage in rename.go for valid formats.
+func parseFromFlag(ctxt *build.Context, fromFlag string) (*spec, error) {
+ var spec spec
+ var main string // sans "::x" suffix
+ switch parts := strings.Split(fromFlag, "::"); len(parts) {
+ case 1:
+ main = parts[0]
+ case 2:
+ main = parts[0]
+ spec.searchFor = parts[1]
+ if parts[1] == "" {
+ // error
+ }
+ default:
+ return nil, fmt.Errorf("-from %q: invalid identifier specification (see -help for formats)", fromFlag)
+ }
+
+ if strings.HasSuffix(main, ".go") {
+ // main is "filename.go"
+ if spec.searchFor == "" {
+ return nil, fmt.Errorf("-from: filename %q must have a ::name suffix", main)
+ }
+ spec.filename = main
+ if !buildutil.FileExists(ctxt, spec.filename) {
+ return nil, fmt.Errorf("no such file: %s", spec.filename)
+ }
+
+ bp, err := buildutil.ContainingPackage(ctxt, wd, spec.filename)
+ if err != nil {
+ return nil, err
+ }
+ spec.pkg = bp.ImportPath
+
+ } else {
+ // main is one of:
+ // "importpath"
+ // "importpath".member
+ // (*"importpath".type).fieldormethod (parens and star optional)
+ if err := parseObjectSpec(&spec, main); err != nil {
+ return nil, err
+ }
+ }
+
+ if spec.searchFor != "" {
+ spec.fromName = spec.searchFor
+ }
+
+ // Sanitize the package.
+ // TODO(adonovan): test with relative packages. May need loader changes.
+ bp, err := ctxt.Import(spec.pkg, ".", build.FindOnly)
+ if err != nil {
+ return nil, fmt.Errorf("can't find package %q", spec.pkg)
+ }
+ spec.pkg = bp.ImportPath
+
+ if !isValidIdentifier(spec.fromName) {
+ return nil, fmt.Errorf("-from: invalid identifier %q", spec.fromName)
+ }
+
+ if Verbose {
+ fmt.Fprintf(os.Stderr, "-from spec: %+v\n", spec)
+ }
+
+ return &spec, nil
+}
+
+// parseObjectSpec parses main as one of the non-filename forms of
+// object specification.
+func parseObjectSpec(spec *spec, main string) error {
+ // Parse main as a Go expression, albeit a strange one.
+ e, _ := parser.ParseExpr(main)
+
+ if pkg := parseImportPath(e); pkg != "" {
+ // e.g. bytes or "encoding/json": a package
+ spec.pkg = pkg
+ if spec.searchFor == "" {
+ return fmt.Errorf("-from %q: package import path %q must have a ::name suffix",
+ main, main)
+ }
+ return nil
+ }
+
+ if e, ok := e.(*ast.SelectorExpr); ok {
+ x := unparen(e.X)
+
+ // Strip off star constructor, if any.
+ if star, ok := x.(*ast.StarExpr); ok {
+ x = star.X
+ }
+
+ if pkg := parseImportPath(x); pkg != "" {
+ // package member e.g. "encoding/json".HTMLEscape
+ spec.pkg = pkg // e.g. "encoding/json"
+ spec.pkgMember = e.Sel.Name // e.g. "HTMLEscape"
+ spec.fromName = e.Sel.Name
+ return nil
+ }
+
+ if x, ok := x.(*ast.SelectorExpr); ok {
+ // field/method of type e.g. ("encoding/json".Decoder).Decode
+ y := unparen(x.X)
+ if pkg := parseImportPath(y); pkg != "" {
+ spec.pkg = pkg // e.g. "encoding/json"
+ spec.pkgMember = x.Sel.Name // e.g. "Decoder"
+ spec.typeMember = e.Sel.Name // e.g. "Decode"
+ spec.fromName = e.Sel.Name
+ return nil
+ }
+ }
+ }
+
+ return fmt.Errorf("-from %q: invalid expression", main)
+}
+
+// parseImportPath returns the import path of the package denoted by e.
+// Any import path may be represented as a string literal;
+// single-segment import paths (e.g. "bytes") may also be represented as
+// ast.Ident. parseImportPath returns "" for all other expressions.
+func parseImportPath(e ast.Expr) string {
+ switch e := e.(type) {
+ case *ast.Ident:
+ return e.Name // e.g. bytes
+
+ case *ast.BasicLit:
+ if e.Kind == token.STRING {
+ pkgname, _ := strconv.Unquote(e.Value)
+ return pkgname // e.g. "encoding/json"
+ }
+ }
+ return ""
+}
+
+// parseOffsetFlag interprets the "-offset" flag value as a renaming specification.
+func parseOffsetFlag(ctxt *build.Context, offsetFlag string) (*spec, error) {
+ var spec spec
+ // Validate -offset, e.g. file.go:#123
+ parts := strings.Split(offsetFlag, ":#")
+ if len(parts) != 2 {
+ return nil, fmt.Errorf("-offset %q: invalid offset specification", offsetFlag)
+ }
+
+ spec.filename = parts[0]
+ if !buildutil.FileExists(ctxt, spec.filename) {
+ return nil, fmt.Errorf("no such file: %s", spec.filename)
+ }
+
+ bp, err := buildutil.ContainingPackage(ctxt, wd, spec.filename)
+ if err != nil {
+ return nil, err
+ }
+ spec.pkg = bp.ImportPath
+
+ for _, r := range parts[1] {
+ if !isDigit(r) {
+ return nil, fmt.Errorf("-offset %q: non-numeric offset", offsetFlag)
+ }
+ }
+ spec.offset, err = strconv.Atoi(parts[1])
+ if err != nil {
+ return nil, fmt.Errorf("-offset %q: non-numeric offset", offsetFlag)
+ }
+
+ // Parse the file and check there's an identifier at that offset.
+ fset := token.NewFileSet()
+ f, err := buildutil.ParseFile(fset, ctxt, nil, wd, spec.filename, parser.ParseComments)
+ if err != nil {
+ return nil, fmt.Errorf("-offset %q: cannot parse file: %s", offsetFlag, err)
+ }
+
+ id := identAtOffset(fset, f, spec.offset)
+ if id == nil {
+ return nil, fmt.Errorf("-offset %q: no identifier at this position", offsetFlag)
+ }
+
+ spec.fromName = id.Name
+
+ return &spec, nil
+}
+
+var wd = func() string {
+ wd, err := os.Getwd()
+ if err != nil {
+ panic("cannot get working directory: " + err.Error())
+ }
+ return wd
+}()
+
+// For source trees built with 'go build', the -from or -offset
+// spec identifies exactly one initial 'from' object to rename ,
+// but certain proprietary build systems allow a single file to
+// appear in multiple packages (e.g. the test package contains a
+// copy of its library), so there may be multiple objects for
+// the same source entity.
+
+func findFromObjects(iprog *loader.Program, spec *spec) ([]types.Object, error) {
+ if spec.filename != "" {
+ return findFromObjectsInFile(iprog, spec)
+ }
+
+ // Search for objects defined in specified package.
+
+ // TODO(adonovan): the iprog.ImportMap has an entry {"main": ...}
+ // for main packages, even though that's not an import path.
+ // Seems like a bug.
+ //
+ // pkgObj := iprog.ImportMap[spec.pkg]
+ // if pkgObj == nil {
+ // return fmt.Errorf("cannot find package %s", spec.pkg) // can't happen?
+ // }
+
+ // Workaround: lookup by value.
+ var pkgObj *types.Package
+ for pkg := range iprog.AllPackages {
+ if pkg.Path() == spec.pkg {
+ pkgObj = pkg
+ break
+ }
+ }
+ info := iprog.AllPackages[pkgObj]
+
+ objects, err := findObjects(info, spec)
+ if err != nil {
+ return nil, err
+ }
+ if len(objects) > 1 {
+ // ambiguous "*" scope query
+ return nil, ambiguityError(iprog.Fset, objects)
+ }
+ return objects, nil
+}
+
+func findFromObjectsInFile(iprog *loader.Program, spec *spec) ([]types.Object, error) {
+ var fromObjects []types.Object
+ for _, info := range iprog.AllPackages {
+ // restrict to specified filename
+ // NB: under certain proprietary build systems, a given
+ // filename may appear in multiple packages.
+ for _, f := range info.Files {
+ thisFile := iprog.Fset.File(f.Pos())
+ if !sameFile(thisFile.Name(), spec.filename) {
+ continue
+ }
+ // This package contains the query file.
+
+ if spec.offset != 0 {
+ // Search for a specific ident by file/offset.
+ id := identAtOffset(iprog.Fset, f, spec.offset)
+ if id == nil {
+ // can't happen?
+ return nil, fmt.Errorf("identifier not found")
+ }
+ obj := info.Uses[id]
+ if obj == nil {
+ obj = info.Defs[id]
+ if obj == nil {
+ // Ident without Object.
+
+ // Package clause?
+ pos := thisFile.Pos(spec.offset)
+ _, path, _ := iprog.PathEnclosingInterval(pos, pos)
+ if len(path) == 2 { // [Ident File]
+ // TODO(adonovan): support this case.
+ return nil, fmt.Errorf("cannot rename %q: renaming package clauses is not yet supported",
+ path[1].(*ast.File).Name.Name)
+ }
+
+ // Implicit y in "switch y := x.(type) {"?
+ if obj := typeSwitchVar(&info.Info, path); obj != nil {
+ return []types.Object{obj}, nil
+ }
+
+ // Probably a type error.
+ return nil, fmt.Errorf("cannot find object for %q", id.Name)
+ }
+ }
+ if obj.Pkg() == nil {
+ return nil, fmt.Errorf("cannot rename predeclared identifiers (%s)", obj)
+
+ }
+
+ fromObjects = append(fromObjects, obj)
+ } else {
+ // do a package-wide query
+ objects, err := findObjects(info, spec)
+ if err != nil {
+ return nil, err
+ }
+
+ // filter results: only objects defined in thisFile
+ var filtered []types.Object
+ for _, obj := range objects {
+ if iprog.Fset.File(obj.Pos()) == thisFile {
+ filtered = append(filtered, obj)
+ }
+ }
+ if len(filtered) == 0 {
+ return nil, fmt.Errorf("no object %q declared in file %s",
+ spec.fromName, spec.filename)
+ } else if len(filtered) > 1 {
+ return nil, ambiguityError(iprog.Fset, filtered)
+ }
+ fromObjects = append(fromObjects, filtered[0])
+ }
+ break
+ }
+ }
+ if len(fromObjects) == 0 {
+ // can't happen?
+ return nil, fmt.Errorf("file %s was not part of the loaded program", spec.filename)
+ }
+ return fromObjects, nil
+}
+
+func typeSwitchVar(info *types.Info, path []ast.Node) types.Object {
+ if len(path) > 3 {
+ // [Ident AssignStmt TypeSwitchStmt...]
+ if sw, ok := path[2].(*ast.TypeSwitchStmt); ok {
+ // choose the first case.
+ if len(sw.Body.List) > 0 {
+ obj := info.Implicits[sw.Body.List[0].(*ast.CaseClause)]
+ if obj != nil {
+ return obj
+ }
+ }
+ }
+ }
+ return nil
+}
+
+// On success, findObjects returns the list of objects named
+// spec.fromName matching the spec. On success, the result has exactly
+// one element unless spec.searchFor!="", in which case it has at least one
+// element.
+//
+func findObjects(info *loader.PackageInfo, spec *spec) ([]types.Object, error) {
+ if spec.pkgMember == "" {
+ if spec.searchFor == "" {
+ panic(spec)
+ }
+ objects := searchDefs(&info.Info, spec.searchFor)
+ if objects == nil {
+ return nil, fmt.Errorf("no object %q declared in package %q",
+ spec.searchFor, info.Pkg.Path())
+ }
+ return objects, nil
+ }
+
+ pkgMember := info.Pkg.Scope().Lookup(spec.pkgMember)
+ if pkgMember == nil {
+ return nil, fmt.Errorf("package %q has no member %q",
+ info.Pkg.Path(), spec.pkgMember)
+ }
+
+ var searchFunc *types.Func
+ if spec.typeMember == "" {
+ // package member
+ if spec.searchFor == "" {
+ return []types.Object{pkgMember}, nil
+ }
+
+ // Search within pkgMember, which must be a function.
+ searchFunc, _ = pkgMember.(*types.Func)
+ if searchFunc == nil {
+ return nil, fmt.Errorf("cannot search for %q within %s %q",
+ spec.searchFor, objectKind(pkgMember), pkgMember)
+ }
+ } else {
+ // field/method of type
+ // e.g. (encoding/json.Decoder).Decode
+ // or ::x within it.
+
+ tName, _ := pkgMember.(*types.TypeName)
+ if tName == nil {
+ return nil, fmt.Errorf("%s.%s is a %s, not a type",
+ info.Pkg.Path(), pkgMember.Name(), objectKind(pkgMember))
+ }
+
+ // search within named type.
+ obj, _, _ := types.LookupFieldOrMethod(tName.Type(), true, info.Pkg, spec.typeMember)
+ if obj == nil {
+ return nil, fmt.Errorf("cannot find field or method %q of %s %s.%s",
+ spec.typeMember, typeKind(tName.Type()), info.Pkg.Path(), tName.Name())
+ }
+
+ if spec.searchFor == "" {
+ return []types.Object{obj}, nil
+ }
+
+ searchFunc, _ = obj.(*types.Func)
+ if searchFunc == nil {
+ return nil, fmt.Errorf("cannot search for local name %q within %s (%s.%s).%s; need a function",
+ spec.searchFor, objectKind(obj), info.Pkg.Path(), tName.Name(),
+ obj.Name())
+ }
+ if isInterface(tName.Type()) {
+ return nil, fmt.Errorf("cannot search for local name %q within abstract method (%s.%s).%s",
+ spec.searchFor, info.Pkg.Path(), tName.Name(), searchFunc.Name())
+ }
+ }
+
+ // -- search within function or method --
+
+ decl := funcDecl(info, searchFunc)
+ if decl == nil {
+ return nil, fmt.Errorf("cannot find syntax for %s", searchFunc) // can't happen?
+ }
+
+ var objects []types.Object
+ for _, obj := range searchDefs(&info.Info, spec.searchFor) {
+ // We use positions, not scopes, to determine whether
+ // the obj is within searchFunc. This is clumsy, but the
+ // alternative, using the types.Scope tree, doesn't
+ // account for non-lexical objects like fields and
+ // interface methods.
+ if decl.Pos() <= obj.Pos() && obj.Pos() < decl.End() && obj != searchFunc {
+ objects = append(objects, obj)
+ }
+ }
+ if objects == nil {
+ return nil, fmt.Errorf("no local definition of %q within %s",
+ spec.searchFor, searchFunc)
+ }
+ return objects, nil
+}
+
+func funcDecl(info *loader.PackageInfo, fn *types.Func) *ast.FuncDecl {
+ for _, f := range info.Files {
+ for _, d := range f.Decls {
+ if d, ok := d.(*ast.FuncDecl); ok && info.Defs[d.Name] == fn {
+ return d
+ }
+ }
+ }
+ return nil
+}
+
+func searchDefs(info *types.Info, name string) []types.Object {
+ var objects []types.Object
+ for id, obj := range info.Defs {
+ if obj == nil {
+ // e.g. blank ident.
+ // TODO(adonovan): but also implicit y in
+ // switch y := x.(type)
+ // Needs some thought.
+ continue
+ }
+ if id.Name == name {
+ objects = append(objects, obj)
+ }
+ }
+ return objects
+}
+
+func identAtOffset(fset *token.FileSet, f *ast.File, offset int) *ast.Ident {
+ var found *ast.Ident
+ ast.Inspect(f, func(n ast.Node) bool {
+ if id, ok := n.(*ast.Ident); ok {
+ idpos := fset.Position(id.Pos()).Offset
+ if idpos <= offset && offset < idpos+len(id.Name) {
+ found = id
+ }
+ }
+ return found == nil // keep traversing only until found
+ })
+ return found
+}
+
+// ambiguityError returns an error describing an ambiguous "*" scope query.
+func ambiguityError(fset *token.FileSet, objects []types.Object) error {
+ var buf bytes.Buffer
+ for i, obj := range objects {
+ if i > 0 {
+ buf.WriteString(", ")
+ }
+ posn := fset.Position(obj.Pos())
+ fmt.Fprintf(&buf, "%s at %s:%d",
+ objectKind(obj), filepath.Base(posn.Filename), posn.Column)
+ }
+ return fmt.Errorf("ambiguous specifier %s matches %s",
+ objects[0].Name(), buf.String())
+}
diff --git a/refactor/rename/util.go b/refactor/rename/util.go
new file mode 100644
index 0000000..def9399
--- /dev/null
+++ b/refactor/rename/util.go
@@ -0,0 +1,104 @@
+// 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 rename
+
+import (
+ "go/ast"
+ "os"
+ "path/filepath"
+ "reflect"
+ "runtime"
+ "strings"
+ "unicode"
+
+ "golang.org/x/tools/go/ast/astutil"
+ "golang.org/x/tools/go/types"
+)
+
+func objectKind(obj types.Object) string {
+ switch obj := obj.(type) {
+ case *types.PkgName:
+ return "imported package name"
+ case *types.TypeName:
+ return "type"
+ case *types.Var:
+ if obj.IsField() {
+ return "field"
+ }
+ case *types.Func:
+ if obj.Type().(*types.Signature).Recv() != nil {
+ return "method"
+ }
+ }
+ // label, func, var, const
+ return strings.ToLower(strings.TrimPrefix(reflect.TypeOf(obj).String(), "*types."))
+}
+
+func typeKind(T types.Type) string {
+ return strings.ToLower(strings.TrimPrefix(reflect.TypeOf(T.Underlying()).String(), "*types."))
+}
+
+// NB: for renamings, blank is not considered valid.
+func isValidIdentifier(id string) bool {
+ if id == "" || id == "_" {
+ return false
+ }
+ for i, r := range id {
+ if !isLetter(r) && (i == 0 || !isDigit(r)) {
+ return false
+ }
+ }
+ return true
+}
+
+// isLocal reports whether obj is local to some function.
+// Precondition: not a struct field or interface method.
+func isLocal(obj types.Object) bool {
+ // [... 5=stmt 4=func 3=file 2=pkg 1=universe]
+ var depth int
+ for scope := obj.Parent(); scope != nil; scope = scope.Parent() {
+ depth++
+ }
+ return depth >= 4
+}
+
+func isPackageLevel(obj types.Object) bool {
+ return obj.Pkg().Scope().Lookup(obj.Name()) == obj
+}
+
+// -- Plundered from go/scanner: ---------------------------------------
+
+func isLetter(ch rune) bool {
+ return 'a' <= ch && ch <= 'z' || 'A' <= ch && ch <= 'Z' || ch == '_' || ch >= 0x80 && unicode.IsLetter(ch)
+}
+
+func isDigit(ch rune) bool {
+ return '0' <= ch && ch <= '9' || ch >= 0x80 && unicode.IsDigit(ch)
+}
+
+// -- Plundered from golang.org/x/tools/oracle -----------------
+
+// sameFile returns true if x and y have the same basename and denote
+// the same file.
+//
+func sameFile(x, y string) bool {
+ if runtime.GOOS == "windows" {
+ x = filepath.ToSlash(x)
+ y = filepath.ToSlash(y)
+ }
+ if x == y {
+ return true
+ }
+ if filepath.Base(x) == filepath.Base(y) { // (optimisation)
+ if xi, err := os.Stat(x); err == nil {
+ if yi, err := os.Stat(y); err == nil {
+ return os.SameFile(xi, yi)
+ }
+ }
+ }
+ return false
+}
+
+func unparen(e ast.Expr) ast.Expr { return astutil.Unparen(e) }
diff --git a/refactor/satisfy/find.go b/refactor/satisfy/find.go
new file mode 100644
index 0000000..acbcf62
--- /dev/null
+++ b/refactor/satisfy/find.go
@@ -0,0 +1,705 @@
+// 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 satisfy inspects the type-checked ASTs of Go packages and
+// reports the set of discovered type constraints of the form (lhs, rhs
+// Type) where lhs is a non-trivial interface, rhs satisfies this
+// interface, and this fact is necessary for the package to be
+// well-typed.
+//
+// THIS PACKAGE IS EXPERIMENTAL AND MAY CHANGE AT ANY TIME.
+//
+// It is provided only for the gorename tool. Ideally this
+// functionality will become part of the type-checker in due course,
+// since it is computing it anyway, and it is robust for ill-typed
+// inputs, which this package is not.
+//
+package satisfy // import "golang.org/x/tools/refactor/satisfy"
+
+// NOTES:
+//
+// We don't care about numeric conversions, so we don't descend into
+// types or constant expressions. This is unsound because
+// constant expressions can contain arbitrary statements, e.g.
+// const x = len([1]func(){func() {
+// ...
+// }})
+//
+// TODO(adonovan): make this robust against ill-typed input.
+// Or move it into the type-checker.
+//
+// Assignability conversions are possible in the following places:
+// - in assignments y = x, y := x, var y = x.
+// - from call argument types to formal parameter types
+// - in append and delete calls
+// - from return operands to result parameter types
+// - in composite literal T{k:v}, from k and v to T's field/element/key type
+// - in map[key] from key to the map's key type
+// - in comparisons x==y and switch x { case y: }.
+// - in explicit conversions T(x)
+// - in sends ch <- x, from x to the channel element type
+// - in type assertions x.(T) and switch x.(type) { case T: }
+//
+// The results of this pass provide information equivalent to the
+// ssa.MakeInterface and ssa.ChangeInterface instructions.
+
+import (
+ "fmt"
+ "go/ast"
+ "go/token"
+
+ "golang.org/x/tools/go/ast/astutil"
+ "golang.org/x/tools/go/types"
+ "golang.org/x/tools/go/types/typeutil"
+)
+
+// A Constraint records the fact that the RHS type does and must
+// satisify the LHS type, which is an interface.
+// The names are suggestive of an assignment statement LHS = RHS.
+type Constraint struct {
+ LHS, RHS types.Type
+}
+
+// A Finder inspects the type-checked ASTs of Go packages and
+// accumulates the set of type constraints (x, y) such that x is
+// assignable to y, y is an interface, and both x and y have methods.
+//
+// In other words, it returns the subset of the "implements" relation
+// that is checked during compilation of a package. Refactoring tools
+// will need to preserve at least this part of the relation to ensure
+// continued compilation.
+//
+type Finder struct {
+ Result map[Constraint]bool
+ msetcache typeutil.MethodSetCache
+
+ // per-Find state
+ info *types.Info
+ sig *types.Signature
+}
+
+// Find inspects a single package, populating Result with its pairs of
+// constrained types.
+//
+// The result is non-canonical and thus may contain duplicates (but this
+// tends to preserves names of interface types better).
+//
+// The package must be free of type errors, and
+// info.{Defs,Uses,Selections,Types} must have been populated by the
+// type-checker.
+//
+func (f *Finder) Find(info *types.Info, files []*ast.File) {
+ if f.Result == nil {
+ f.Result = make(map[Constraint]bool)
+ }
+
+ f.info = info
+ for _, file := range files {
+ for _, d := range file.Decls {
+ switch d := d.(type) {
+ case *ast.GenDecl:
+ if d.Tok == token.VAR { // ignore consts
+ for _, spec := range d.Specs {
+ f.valueSpec(spec.(*ast.ValueSpec))
+ }
+ }
+
+ case *ast.FuncDecl:
+ if d.Body != nil {
+ f.sig = f.info.Defs[d.Name].Type().(*types.Signature)
+ f.stmt(d.Body)
+ f.sig = nil
+ }
+ }
+ }
+ }
+ f.info = nil
+}
+
+var (
+ tInvalid = types.Typ[types.Invalid]
+ tUntypedBool = types.Typ[types.UntypedBool]
+ tUntypedNil = types.Typ[types.UntypedNil]
+)
+
+// exprN visits an expression in a multi-value context.
+func (f *Finder) exprN(e ast.Expr) types.Type {
+ typ := f.info.Types[e].Type.(*types.Tuple)
+ switch e := e.(type) {
+ case *ast.ParenExpr:
+ return f.exprN(e.X)
+
+ case *ast.CallExpr:
+ // x, err := f(args)
+ sig := f.expr(e.Fun).Underlying().(*types.Signature)
+ f.call(sig, e.Args)
+
+ case *ast.IndexExpr:
+ // y, ok := x[i]
+ x := f.expr(e.X)
+ f.assign(f.expr(e.Index), x.Underlying().(*types.Map).Key())
+
+ case *ast.TypeAssertExpr:
+ // y, ok := x.(T)
+ f.typeAssert(f.expr(e.X), typ.At(0).Type())
+
+ case *ast.UnaryExpr: // must be receive <-
+ // y, ok := <-x
+ f.expr(e.X)
+
+ default:
+ panic(e)
+ }
+ return typ
+}
+
+func (f *Finder) call(sig *types.Signature, args []ast.Expr) {
+ if len(args) == 0 {
+ return
+ }
+
+ // Ellipsis call? e.g. f(x, y, z...)
+ if _, ok := args[len(args)-1].(*ast.Ellipsis); ok {
+ for i, arg := range args {
+ // The final arg is a slice, and so is the final param.
+ f.assign(sig.Params().At(i).Type(), f.expr(arg))
+ }
+ return
+ }
+
+ var argtypes []types.Type
+
+ // Gather the effective actual parameter types.
+ if tuple, ok := f.info.Types[args[0]].Type.(*types.Tuple); ok {
+ // f(g()) call where g has multiple results?
+ f.expr(args[0])
+ // unpack the tuple
+ for i := 0; i < tuple.Len(); i++ {
+ argtypes = append(argtypes, tuple.At(i).Type())
+ }
+ } else {
+ for _, arg := range args {
+ argtypes = append(argtypes, f.expr(arg))
+ }
+ }
+
+ // Assign the actuals to the formals.
+ if !sig.Variadic() {
+ for i, argtype := range argtypes {
+ f.assign(sig.Params().At(i).Type(), argtype)
+ }
+ } else {
+ // The first n-1 parameters are assigned normally.
+ nnormals := sig.Params().Len() - 1
+ for i, argtype := range argtypes[:nnormals] {
+ f.assign(sig.Params().At(i).Type(), argtype)
+ }
+ // Remaining args are assigned to elements of varargs slice.
+ tElem := sig.Params().At(nnormals).Type().(*types.Slice).Elem()
+ for i := nnormals; i < len(argtypes); i++ {
+ f.assign(tElem, argtypes[i])
+ }
+ }
+}
+
+func (f *Finder) builtin(obj *types.Builtin, sig *types.Signature, args []ast.Expr, T types.Type) types.Type {
+ switch obj.Name() {
+ case "make", "new":
+ // skip the type operand
+ for _, arg := range args[1:] {
+ f.expr(arg)
+ }
+
+ case "append":
+ s := f.expr(args[0])
+ if _, ok := args[len(args)-1].(*ast.Ellipsis); ok && len(args) == 2 {
+ // append(x, y...) including append([]byte, "foo"...)
+ f.expr(args[1])
+ } else {
+ // append(x, y, z)
+ tElem := s.Underlying().(*types.Slice).Elem()
+ for _, arg := range args[1:] {
+ f.assign(tElem, f.expr(arg))
+ }
+ }
+
+ case "delete":
+ m := f.expr(args[0])
+ k := f.expr(args[1])
+ f.assign(m.Underlying().(*types.Map).Key(), k)
+
+ default:
+ // ordinary call
+ f.call(sig, args)
+ }
+
+ return T
+}
+
+func (f *Finder) extract(tuple types.Type, i int) types.Type {
+ if tuple, ok := tuple.(*types.Tuple); ok && i < tuple.Len() {
+ return tuple.At(i).Type()
+ }
+ return tInvalid
+}
+
+func (f *Finder) valueSpec(spec *ast.ValueSpec) {
+ var T types.Type
+ if spec.Type != nil {
+ T = f.info.Types[spec.Type].Type
+ }
+ switch len(spec.Values) {
+ case len(spec.Names): // e.g. var x, y = f(), g()
+ for _, value := range spec.Values {
+ v := f.expr(value)
+ if T != nil {
+ f.assign(T, v)
+ }
+ }
+
+ case 1: // e.g. var x, y = f()
+ tuple := f.exprN(spec.Values[0])
+ for i := range spec.Names {
+ if T != nil {
+ f.assign(T, f.extract(tuple, i))
+ }
+ }
+ }
+}
+
+// assign records pairs of distinct types that are related by
+// assignability, where the left-hand side is an interface and both
+// sides have methods.
+//
+// It should be called for all assignability checks, type assertions,
+// explicit conversions and comparisons between two types, unless the
+// types are uninteresting (e.g. lhs is a concrete type, or the empty
+// interface; rhs has no methods).
+//
+func (f *Finder) assign(lhs, rhs types.Type) {
+ if types.Identical(lhs, rhs) {
+ return
+ }
+ if !isInterface(lhs) {
+ return
+ }
+
+ if f.msetcache.MethodSet(lhs).Len() == 0 {
+ return
+ }
+ if f.msetcache.MethodSet(rhs).Len() == 0 {
+ return
+ }
+ // record the pair
+ f.Result[Constraint{lhs, rhs}] = true
+}
+
+// typeAssert must be called for each type assertion x.(T) where x has
+// interface type I.
+func (f *Finder) typeAssert(I, T types.Type) {
+ // Type assertions are slightly subtle, because they are allowed
+ // to be "impossible", e.g.
+ //
+ // var x interface{f()}
+ // _ = x.(interface{f()int}) // legal
+ //
+ // (In hindsight, the language spec should probably not have
+ // allowed this, but it's too late to fix now.)
+ //
+ // This means that a type assert from I to T isn't exactly a
+ // constraint that T is assignable to I, but for a refactoring
+ // tool it is a conditional constraint that, if T is assignable
+ // to I before a refactoring, it should remain so after.
+
+ if types.AssignableTo(T, I) {
+ f.assign(I, T)
+ }
+}
+
+// compare must be called for each comparison x==y.
+func (f *Finder) compare(x, y types.Type) {
+ if types.AssignableTo(x, y) {
+ f.assign(y, x)
+ } else if types.AssignableTo(y, x) {
+ f.assign(x, y)
+ }
+}
+
+// expr visits a true expression (not a type or defining ident)
+// and returns its type.
+func (f *Finder) expr(e ast.Expr) types.Type {
+ tv := f.info.Types[e]
+ if tv.Value != nil {
+ return tv.Type // prune the descent for constants
+ }
+
+ // tv.Type may be nil for an ast.Ident.
+
+ switch e := e.(type) {
+ case *ast.BadExpr, *ast.BasicLit:
+ // no-op
+
+ case *ast.Ident:
+ // (referring idents only)
+ if obj, ok := f.info.Uses[e]; ok {
+ return obj.Type()
+ }
+ if e.Name == "_" { // e.g. "for _ = range x"
+ return tInvalid
+ }
+ panic("undefined ident: " + e.Name)
+
+ case *ast.Ellipsis:
+ if e.Elt != nil {
+ f.expr(e.Elt)
+ }
+
+ case *ast.FuncLit:
+ saved := f.sig
+ f.sig = tv.Type.(*types.Signature)
+ f.stmt(e.Body)
+ f.sig = saved
+
+ case *ast.CompositeLit:
+ switch T := deref(tv.Type).Underlying().(type) {
+ case *types.Struct:
+ for i, elem := range e.Elts {
+ if kv, ok := elem.(*ast.KeyValueExpr); ok {
+ f.assign(f.info.Uses[kv.Key.(*ast.Ident)].Type(), f.expr(kv.Value))
+ } else {
+ f.assign(T.Field(i).Type(), f.expr(elem))
+ }
+ }
+
+ case *types.Map:
+ for _, elem := range e.Elts {
+ elem := elem.(*ast.KeyValueExpr)
+ f.assign(T.Key(), f.expr(elem.Key))
+ f.assign(T.Elem(), f.expr(elem.Value))
+ }
+
+ case *types.Array, *types.Slice:
+ tElem := T.(interface {
+ Elem() types.Type
+ }).Elem()
+ for _, elem := range e.Elts {
+ if kv, ok := elem.(*ast.KeyValueExpr); ok {
+ // ignore the key
+ f.assign(tElem, f.expr(kv.Value))
+ } else {
+ f.assign(tElem, f.expr(elem))
+ }
+ }
+
+ default:
+ panic("unexpected composite literal type: " + tv.Type.String())
+ }
+
+ case *ast.ParenExpr:
+ f.expr(e.X)
+
+ case *ast.SelectorExpr:
+ if _, ok := f.info.Selections[e]; ok {
+ f.expr(e.X) // selection
+ } else {
+ return f.info.Uses[e.Sel].Type() // qualified identifier
+ }
+
+ case *ast.IndexExpr:
+ x := f.expr(e.X)
+ i := f.expr(e.Index)
+ if ux, ok := x.Underlying().(*types.Map); ok {
+ f.assign(ux.Key(), i)
+ }
+
+ case *ast.SliceExpr:
+ f.expr(e.X)
+ if e.Low != nil {
+ f.expr(e.Low)
+ }
+ if e.High != nil {
+ f.expr(e.High)
+ }
+ if e.Max != nil {
+ f.expr(e.Max)
+ }
+
+ case *ast.TypeAssertExpr:
+ x := f.expr(e.X)
+ f.typeAssert(x, f.info.Types[e.Type].Type)
+
+ case *ast.CallExpr:
+ if tvFun := f.info.Types[e.Fun]; tvFun.IsType() {
+ // conversion
+ arg0 := f.expr(e.Args[0])
+ f.assign(tvFun.Type, arg0)
+ } else {
+ // function call
+ if id, ok := unparen(e.Fun).(*ast.Ident); ok {
+ if obj, ok := f.info.Uses[id].(*types.Builtin); ok {
+ sig := f.info.Types[id].Type.(*types.Signature)
+ return f.builtin(obj, sig, e.Args, tv.Type)
+ }
+ }
+ // ordinary call
+ f.call(f.expr(e.Fun).Underlying().(*types.Signature), e.Args)
+ }
+
+ case *ast.StarExpr:
+ f.expr(e.X)
+
+ case *ast.UnaryExpr:
+ f.expr(e.X)
+
+ case *ast.BinaryExpr:
+ x := f.expr(e.X)
+ y := f.expr(e.Y)
+ if e.Op == token.EQL || e.Op == token.NEQ {
+ f.compare(x, y)
+ }
+
+ case *ast.KeyValueExpr:
+ f.expr(e.Key)
+ f.expr(e.Value)
+
+ case *ast.ArrayType,
+ *ast.StructType,
+ *ast.FuncType,
+ *ast.InterfaceType,
+ *ast.MapType,
+ *ast.ChanType:
+ panic(e)
+ }
+
+ if tv.Type == nil {
+ panic(fmt.Sprintf("no type for %T", e))
+ }
+
+ return tv.Type
+}
+
+func (f *Finder) stmt(s ast.Stmt) {
+ switch s := s.(type) {
+ case *ast.BadStmt,
+ *ast.EmptyStmt,
+ *ast.BranchStmt:
+ // no-op
+
+ case *ast.DeclStmt:
+ d := s.Decl.(*ast.GenDecl)
+ if d.Tok == token.VAR { // ignore consts
+ for _, spec := range d.Specs {
+ f.valueSpec(spec.(*ast.ValueSpec))
+ }
+ }
+
+ case *ast.LabeledStmt:
+ f.stmt(s.Stmt)
+
+ case *ast.ExprStmt:
+ f.expr(s.X)
+
+ case *ast.SendStmt:
+ ch := f.expr(s.Chan)
+ val := f.expr(s.Value)
+ f.assign(ch.Underlying().(*types.Chan).Elem(), val)
+
+ case *ast.IncDecStmt:
+ f.expr(s.X)
+
+ case *ast.AssignStmt:
+ switch s.Tok {
+ case token.ASSIGN, token.DEFINE:
+ // y := x or y = x
+ var rhsTuple types.Type
+ if len(s.Lhs) != len(s.Rhs) {
+ rhsTuple = f.exprN(s.Rhs[0])
+ }
+ for i := range s.Lhs {
+ var lhs, rhs types.Type
+ if rhsTuple == nil {
+ rhs = f.expr(s.Rhs[i]) // 1:1 assignment
+ } else {
+ rhs = f.extract(rhsTuple, i) // n:1 assignment
+ }
+
+ if id, ok := s.Lhs[i].(*ast.Ident); ok {
+ if id.Name != "_" {
+ if obj, ok := f.info.Defs[id]; ok {
+ lhs = obj.Type() // definition
+ }
+ }
+ }
+ if lhs == nil {
+ lhs = f.expr(s.Lhs[i]) // assignment
+ }
+ f.assign(lhs, rhs)
+ }
+
+ default:
+ // y op= x
+ f.expr(s.Lhs[0])
+ f.expr(s.Rhs[0])
+ }
+
+ case *ast.GoStmt:
+ f.expr(s.Call)
+
+ case *ast.DeferStmt:
+ f.expr(s.Call)
+
+ case *ast.ReturnStmt:
+ formals := f.sig.Results()
+ switch len(s.Results) {
+ case formals.Len(): // 1:1
+ for i, result := range s.Results {
+ f.assign(formals.At(i).Type(), f.expr(result))
+ }
+
+ case 1: // n:1
+ tuple := f.exprN(s.Results[0])
+ for i := 0; i < formals.Len(); i++ {
+ f.assign(formals.At(i).Type(), f.extract(tuple, i))
+ }
+ }
+
+ case *ast.SelectStmt:
+ f.stmt(s.Body)
+
+ case *ast.BlockStmt:
+ for _, s := range s.List {
+ f.stmt(s)
+ }
+
+ case *ast.IfStmt:
+ if s.Init != nil {
+ f.stmt(s.Init)
+ }
+ f.expr(s.Cond)
+ f.stmt(s.Body)
+ if s.Else != nil {
+ f.stmt(s.Else)
+ }
+
+ case *ast.SwitchStmt:
+ if s.Init != nil {
+ f.stmt(s.Init)
+ }
+ var tag types.Type = tUntypedBool
+ if s.Tag != nil {
+ tag = f.expr(s.Tag)
+ }
+ for _, cc := range s.Body.List {
+ cc := cc.(*ast.CaseClause)
+ for _, cond := range cc.List {
+ f.compare(tag, f.info.Types[cond].Type)
+ }
+ for _, s := range cc.Body {
+ f.stmt(s)
+ }
+ }
+
+ case *ast.TypeSwitchStmt:
+ if s.Init != nil {
+ f.stmt(s.Init)
+ }
+ var I types.Type
+ switch ass := s.Assign.(type) {
+ case *ast.ExprStmt: // x.(type)
+ I = f.expr(unparen(ass.X).(*ast.TypeAssertExpr).X)
+ case *ast.AssignStmt: // y := x.(type)
+ I = f.expr(unparen(ass.Rhs[0]).(*ast.TypeAssertExpr).X)
+ }
+ for _, cc := range s.Body.List {
+ cc := cc.(*ast.CaseClause)
+ for _, cond := range cc.List {
+ tCase := f.info.Types[cond].Type
+ if tCase != tUntypedNil {
+ f.typeAssert(I, tCase)
+ }
+ }
+ for _, s := range cc.Body {
+ f.stmt(s)
+ }
+ }
+
+ case *ast.CommClause:
+ if s.Comm != nil {
+ f.stmt(s.Comm)
+ }
+ for _, s := range s.Body {
+ f.stmt(s)
+ }
+
+ case *ast.ForStmt:
+ if s.Init != nil {
+ f.stmt(s.Init)
+ }
+ if s.Cond != nil {
+ f.expr(s.Cond)
+ }
+ if s.Post != nil {
+ f.stmt(s.Post)
+ }
+ f.stmt(s.Body)
+
+ case *ast.RangeStmt:
+ x := f.expr(s.X)
+ // No conversions are involved when Tok==DEFINE.
+ if s.Tok == token.ASSIGN {
+ if s.Key != nil {
+ k := f.expr(s.Key)
+ var xelem types.Type
+ // keys of array, *array, slice, string aren't interesting
+ switch ux := x.Underlying().(type) {
+ case *types.Chan:
+ xelem = ux.Elem()
+ case *types.Map:
+ xelem = ux.Key()
+ }
+ if xelem != nil {
+ f.assign(xelem, k)
+ }
+ }
+ if s.Value != nil {
+ val := f.expr(s.Value)
+ var xelem types.Type
+ // values of strings aren't interesting
+ switch ux := x.Underlying().(type) {
+ case *types.Array:
+ xelem = ux.Elem()
+ case *types.Chan:
+ xelem = ux.Elem()
+ case *types.Map:
+ xelem = ux.Elem()
+ case *types.Pointer: // *array
+ xelem = deref(ux).(*types.Array).Elem()
+ case *types.Slice:
+ xelem = ux.Elem()
+ }
+ if xelem != nil {
+ f.assign(xelem, val)
+ }
+ }
+ }
+ f.stmt(s.Body)
+
+ default:
+ panic(s)
+ }
+}
+
+// -- Plundered from golang.org/x/tools/go/ssa -----------------
+
+// deref returns a pointer's element type; otherwise it returns typ.
+func deref(typ types.Type) types.Type {
+ if p, ok := typ.Underlying().(*types.Pointer); ok {
+ return p.Elem()
+ }
+ return typ
+}
+
+func unparen(e ast.Expr) ast.Expr { return astutil.Unparen(e) }
+
+func isInterface(T types.Type) bool { return types.IsInterface(T) }