func (dir *Directory) lookup(path string) *Directory {
	d := strings.Split(dir.Path, string(filepath.Separator))
	p := strings.Split(path, string(filepath.Separator))
	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
}
lookup looks for the *Directory for a given path, relative to dir.
package docview
import (
	"bytes"
	"go/doc"
	"go/parser"
	"go/token"
	"log"
	"os"
	"path/filepath"
	"strings"
	"unicode"
)
type Directory struct {
	Depth int
	Path  string  
	Name  string
	Text  string        
	Dirs  []*Directory  
}
func isGoFile(f os.FileInfo) bool {
	name := f.Name()
	return !f.IsDir() && !strings.HasPrefix(name, ".") && strings.HasSuffix(name, ".go")
}
func isPkgFile(fi os.FileInfo) bool {
	return isGoFile(fi) &&
		!strings.HasSuffix(fi.Name(), "_test.go")  
}
func isPkgDir(fi os.FileInfo) bool {
	name := fi.Name()
	return fi.IsDir() && len(name) > 0 &&
		name[0] != '_' && name[0] != '.'  
}
func firstSentence(s string) string {
	i := -1  
	j := -1  
	prev := 'A'
	for k, ch := range s {
		k1 := k + 1
		if ch == '.' || ch == '!' || ch == '?' {
			if i < 0 {
				i = k1  
			}
			if k1 < len(s) && s[k1] <= ' ' {
				if j < 0 {
					j = k1  
				}
				if !unicode.IsUpper(prev) {
					j = k1
					break
				}
			}
		}
		prev = ch
	}
	if j < 0 {
		j = i
		if j < 0 {
			j = len(s)
		}
	}
	return s[0:j]
}
type treeBuilder struct {
	pathFilter func(string) bool
	maxDepth   int
}
func (b *treeBuilder) newDirTree(fset *token.FileSet, path, name string, depth int) *Directory {
	if b.pathFilter != nil && !b.pathFilter(path) {
		return nil
	}
	if depth >= b.maxDepth {
		return &Directory{depth, path, name, "", nil}
	}
	list, err := fs.ReadDir(path)
	if err != nil {
		log.Printf("ReadDir(%s): %s", path, err)
	}
	ndirs := 0
	hasPkgFiles := false
	var synopses [4]string  
	for _, d := range list {
		switch {
		case isPkgDir(d):
			ndirs++
		case isPkgFile(d):
			if synopses[0] == "" {
				file, err := parser.ParseFile(fset, filepath.Join(path, d.Name()), nil,
					parser.ParseComments|parser.PackageClauseOnly)
				if err == nil {
					hasPkgFiles = true
					if file.Doc != nil {
						i := -1
						switch file.Name.Name {
						case name:
							i = 0  
						case fakePkgName:
							i = 1  
						case "main":
							i = 2  
						default:
							i = 3  
						}
						if 0 <= i && i < len(synopses) && synopses[i] == "" {
							synopses[i] = doc.Synopsis(file.Doc.Text())
						}
					}
				}
			}
		}
	}
	var dirs []*Directory
	if ndirs > 0 {
		dirs = make([]*Directory, ndirs)
		i := 0
		for _, d := range list {
			if isPkgDir(d) {
				name := d.Name()
				dd := b.newDirTree(fset, filepath.Join(path, name), name, depth+1)
				if dd != nil {
					dirs[i] = dd
					i++
				}
			}
		}
		dirs = dirs[0:i]
	}
	if !hasPkgFiles && len(dirs) == 0 {
		return nil
	}
	synopsis := ""
	for _, synopsis = range synopses {
		if synopsis != "" {
			break
		}
	}
	return &Directory{depth, path, name, synopsis, dirs}
}
func newDirectory(root string, pathFilter func(string) bool, maxDepth int) *Directory {
	d, err := fs.Stat(root)
	switch {
	case err != nil:
		log.Printf("newDirectory(%s): %s", root, err)
		return nil
	case !isPkgDir(d):
		log.Printf("newDirectory(%s): not a package directory", root)
		return nil
	}
	if maxDepth < 0 {
		maxDepth = 1e6  
	}
	b := treeBuilder{pathFilter, maxDepth}
	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
}