func (ic byImportCount) top(n int) []Ident {
	if len(ic.Idents) > n {
		return ic.Idents[:n]
	}
	return ic.Idents
}
top returns the top n identifiers.
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"
)
type comparer func(x, y interface{}) bool
type interfaceSlice struct {
	slice []interface{}
	less  comparer
}
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] }
func (h RunList) reduce(less comparer, newRun func(h RunList) interface{}) RunList {
	if len(h) == 0 {
		return nil
	}
	h.sort(less)
	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]  
		}
	}
	if i < len(h) {
		hh = append(hh, newRun(h[i:]))
	}
	return hh
}
const removeDuplicates = true
type KindRun []SpotInfo
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] }
func lessKind(x, y interface{}) bool { return x.(SpotInfo).Kind() < y.(SpotInfo).Kind() }
func newKindRun(h RunList) interface{} {
	run := make(KindRun, len(h))
	for i, x := range h {
		run[i] = x.(SpotInfo)
	}
	sort.Sort(run)
	if removeDuplicates {
		k := 0
		prev := SpotInfo(1<<32 - 1)  
		for _, x := range run {
			if x != prev {
				run[k] = x
				k++
				prev = x
			}
		}
		run = run[0:k]
	}
	return run
}
type Pak struct {
	Path string  
	Name string  
}
func (p *Pak) less(q *Pak) bool {
	return p.Name < q.Name || p.Name == q.Name && p.Path < q.Path
}
type File struct {
	Name string  
	Pak  *Pak    
}
func (f *File) Path() string {
	return pathpkg.Join(f.Pak.Path, f.Name)
}
type Spot struct {
	File *File
	Info SpotInfo
}
type FileRun struct {
	File   *File
	Groups []KindRun
}
func lessSpot(x, y interface{}) bool {
	fx := x.(Spot).File
	fy := y.(Spot).File
	px := fx.Pak.Path
	py := fy.Pak.Path
	return px < py || px == py && fx.Name < fy.Name
}
func newFileRun(h RunList) interface{} {
	file := h[0].(Spot).File
	h1 := make(RunList, len(h))
	for i, x := range h {
		h1[i] = x.(Spot).Info
	}
	h2 := h1.reduce(lessKind, newKindRun)
	groups := make([]KindRun, len(h2))
	for i, x := range h2 {
		groups[i] = x.(KindRun)
	}
	return &FileRun{file, groups}
}
type PakRun struct {
	Pak   *Pak
	Files []*FileRun
}
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] }
func lessFileRun(x, y interface{}) bool {
	return x.(*FileRun).File.Pak.less(y.(*FileRun).File.Pak)
}
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)  
	return run
}
type HitList []*PakRun
func lessPakRun(x, y interface{}) bool { return x.(*PakRun).Pak.less(y.(*PakRun).Pak) }
func reduce(h0 RunList) HitList {
	h1 := h0.reduce(lessSpot, newFileRun)
	h2 := h1.reduce(lessFileRun, newPakRun)
	h2.sort(lessPakRun)
	h := make(HitList, len(h2))
	for i, p := range h2 {
		h[i] = p.(*PakRun)
	}
	return h
}
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
}
type wordPair struct {
	canon string  
	alt   string  
}
type AltWords struct {
	Canon string    
	Alts  []string  
}
func lessWordPair(x, y interface{}) bool { return x.(*wordPair).canon < y.(*wordPair).canon }
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
}
type Ident struct {
	Path    string  
	Package string  
	Name    string  
	Doc     string  
}
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()
}
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
}