func (i *Include) Pos() Position {
	return i.position
}
Pos returns the position of the Include directive in the larger file.
package ssh_config
import (
	"bytes"
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	osuser "os/user"
	"path/filepath"
	"regexp"
	"runtime"
	"strings"
	"sync"
)
const version = "1.0"
var _ = version
type configFinder func() string
type UserSettings struct {
	IgnoreErrors       bool
	systemConfig       *Config
	systemConfigFinder configFinder
	userConfig         *Config
	userConfigFinder   configFinder
	loadConfigs        sync.Once
	onceErr            error
}
func homedir() string {
	user, err := osuser.Current()
	if err == nil {
		return user.HomeDir
	} else {
		return os.Getenv("HOME")
	}
}
func userConfigFinder() string {
	return filepath.Join(homedir(), ".ssh", "config")
}
var DefaultUserSettings = &UserSettings{
	IgnoreErrors:       false,
	systemConfigFinder: systemConfigFinder,
	userConfigFinder:   userConfigFinder,
}
func systemConfigFinder() string {
	return filepath.Join("/", "etc", "ssh", "ssh_config")
}
func findVal(c *Config, alias, key string) (string, error) {
	if c == nil {
		return "", nil
	}
	val, err := c.Get(alias, key)
	if err != nil || val == "" {
		return "", err
	}
	if err := validate(key, val); err != nil {
		return "", err
	}
	return val, nil
}
func findAll(c *Config, alias, key string) ([]string, error) {
	if c == nil {
		return nil, nil
	}
	return c.GetAll(alias, key)
}
func Get(alias, key string) string {
	return DefaultUserSettings.Get(alias, key)
}
func GetAll(alias, key string) []string {
	return DefaultUserSettings.GetAll(alias, key)
}
func GetStrict(alias, key string) (string, error) {
	return DefaultUserSettings.GetStrict(alias, key)
}
func GetAllStrict(alias, key string) ([]string, error) {
	return DefaultUserSettings.GetAllStrict(alias, key)
}
func (u *UserSettings) Get(alias, key string) string {
	val, err := u.GetStrict(alias, key)
	if err != nil {
		return ""
	}
	return val
}
func (u *UserSettings) GetAll(alias, key string) []string {
	val, _ := u.GetAllStrict(alias, key)
	return val
}
func (u *UserSettings) GetStrict(alias, key string) (string, error) {
	u.doLoadConfigs()
	if u.onceErr != nil && u.IgnoreErrors == false {
		return "", u.onceErr
	}
	val, err := findVal(u.userConfig, alias, key)
	if err != nil || val != "" {
		return val, err
	}
	val2, err2 := findVal(u.systemConfig, alias, key)
	if err2 != nil || val2 != "" {
		return val2, err2
	}
	return Default(key), nil
}
func (u *UserSettings) GetAllStrict(alias, key string) ([]string, error) {
	u.doLoadConfigs()
	if u.onceErr != nil && u.IgnoreErrors == false {
		return nil, u.onceErr
	}
	val, err := findAll(u.userConfig, alias, key)
	if err != nil || val != nil {
		return val, err
	}
	val2, err2 := findAll(u.systemConfig, alias, key)
	if err2 != nil || val2 != nil {
		return val2, err2
	}
	if def := Default(key); def != "" {
		return []string{def}, nil
	}
	return []string{}, nil
}
func (u *UserSettings) doLoadConfigs() {
	u.loadConfigs.Do(func() {
		var filename string
		if u.userConfigFinder == nil {
			filename = userConfigFinder()
		} else {
			filename = u.userConfigFinder()
		}
		var err error
		u.userConfig, err = parseFile(filename)
		if err != nil && os.IsNotExist(err) == false {
			u.onceErr = err
			return
		}
		if u.systemConfigFinder == nil {
			filename = systemConfigFinder()
		} else {
			filename = u.systemConfigFinder()
		}
		u.systemConfig, err = parseFile(filename)
		if err != nil && os.IsNotExist(err) == false {
			u.onceErr = err
			return
		}
	})
}
func parseFile(filename string) (*Config, error) {
	return parseWithDepth(filename, 0)
}
func parseWithDepth(filename string, depth uint8) (*Config, error) {
	b, err := ioutil.ReadFile(filename)
	if err != nil {
		return nil, err
	}
	return decodeBytes(b, isSystem(filename), depth)
}
func isSystem(filename string) bool {
	return strings.HasPrefix(filepath.Clean(filename), "/etc/ssh")
}
func Decode(r io.Reader) (*Config, error) {
	b, err := ioutil.ReadAll(r)
	if err != nil {
		return nil, err
	}
	return decodeBytes(b, false, 0)
}
func decodeBytes(b []byte, system bool, depth uint8) (c *Config, err error) {
	defer func() {
		if r := recover(); r != nil {
			if _, ok := r.(runtime.Error); ok {
				panic(r)
			}
			if e, ok := r.(error); ok && e == ErrDepthExceeded {
				err = e
				return
			}
			err = errors.New(r.(string))
		}
	}()
	c = parseSSH(lexSSH(b), system, depth)
	return c, err
}
type Config struct {
	Hosts    []*Host
	depth    uint8
	position Position
}
func (c *Config) Get(alias, key string) (string, error) {
	lowerKey := strings.ToLower(key)
	for _, host := range c.Hosts {
		if !host.Matches(alias) {
			continue
		}
		for _, node := range host.Nodes {
			switch t := node.(type) {
			case *Empty:
				continue
			case *KV:
				lkey := strings.ToLower(t.Key)
				if lkey == "match" {
					panic("can't handle Match directives")
				}
				if lkey == lowerKey {
					return t.Value, nil
				}
			case *Include:
				val := t.Get(alias, key)
				if val != "" {
					return val, nil
				}
			default:
				return "", fmt.Errorf("unknown Node type %v", t)
			}
		}
	}
	return "", nil
}
func (c *Config) GetAll(alias, key string) ([]string, error) {
	lowerKey := strings.ToLower(key)
	all := []string(nil)
	for _, host := range c.Hosts {
		if !host.Matches(alias) {
			continue
		}
		for _, node := range host.Nodes {
			switch t := node.(type) {
			case *Empty:
				continue
			case *KV:
				lkey := strings.ToLower(t.Key)
				if lkey == "match" {
					panic("can't handle Match directives")
				}
				if lkey == lowerKey {
					all = append(all, t.Value)
				}
			case *Include:
				val, _ := t.GetAll(alias, key)
				if len(val) > 0 {
					all = append(all, val...)
				}
			default:
				return nil, fmt.Errorf("unknown Node type %v", t)
			}
		}
	}
	return all, nil
}
func (c Config) String() string {
	return marshal(c).String()
}
func (c Config) MarshalText() ([]byte, error) {
	return marshal(c).Bytes(), nil
}
func marshal(c Config) *bytes.Buffer {
	var buf bytes.Buffer
	for i := range c.Hosts {
		buf.WriteString(c.Hosts[i].String())
	}
	return &buf
}
type Pattern struct {
	str   string  
	regex *regexp.Regexp
	not   bool  
}
func (p Pattern) String() string {
	return p.str
}
var specialBytes = []byte(`\.+()|[]{}^$`)
func special(b byte) bool {
	return bytes.IndexByte(specialBytes, b) >= 0
}
func NewPattern(s string) (*Pattern, error) {
	if s == "" {
		return nil, errors.New("ssh_config: empty pattern")
	}
	negated := false
	if s[0] == '!' {
		negated = true
		s = s[1:]
	}
	var buf bytes.Buffer
	buf.WriteByte('^')
	for i := 0; i < len(s); i++ {
		switch b := s[i]; b {
		case '*':
			buf.WriteString(".*")
		case '?':
			buf.WriteString(".?")
		default:
			if special(b) {
				buf.WriteByte('\\')
			}
			buf.WriteByte(b)
		}
	}
	buf.WriteByte('$')
	r, err := regexp.Compile(buf.String())
	if err != nil {
		return nil, err
	}
	return &Pattern{str: s, regex: r, not: negated}, nil
}
type Host struct {
	Patterns []*Pattern
	Nodes []Node
	EOLComment   string
	hasEquals    bool
	leadingSpace int  
	implicit bool
}
func (h *Host) Matches(alias string) bool {
	found := false
	for i := range h.Patterns {
		if h.Patterns[i].regex.MatchString(alias) {
			if h.Patterns[i].not {
				return false
			}
			found = true
		}
	}
	return found
}
func (h *Host) String() string {
	var buf bytes.Buffer
	if h.implicit == false {
		buf.WriteString(strings.Repeat(" ", int(h.leadingSpace)))
		buf.WriteString("Host")
		if h.hasEquals {
			buf.WriteString(" = ")
		} else {
			buf.WriteString(" ")
		}
		for i, pat := range h.Patterns {
			buf.WriteString(pat.String())
			if i < len(h.Patterns)-1 {
				buf.WriteString(" ")
			}
		}
		if h.EOLComment != "" {
			buf.WriteString(" #")
			buf.WriteString(h.EOLComment)
		}
		buf.WriteByte('\n')
	}
	for i := range h.Nodes {
		buf.WriteString(h.Nodes[i].String())
		buf.WriteByte('\n')
	}
	return buf.String()
}
type Node interface {
	Pos() Position
	String() string
}
type KV struct {
	Key          string
	Value        string
	Comment      string
	hasEquals    bool
	leadingSpace int  
	position     Position
}
func (k *KV) Pos() Position {
	return k.position
}
func (k *KV) String() string {
	if k == nil {
		return ""
	}
	equals := " "
	if k.hasEquals {
		equals = " = "
	}
	line := fmt.Sprintf("%s%s%s%s", strings.Repeat(" ", int(k.leadingSpace)), k.Key, equals, k.Value)
	if k.Comment != "" {
		line += " #" + k.Comment
	}
	return line
}
type Empty struct {
	Comment      string
	leadingSpace int  
	position     Position
}
func (e *Empty) Pos() Position {
	return e.position
}
func (e *Empty) String() string {
	if e == nil {
		return ""
	}
	if e.Comment == "" {
		return ""
	}
	return fmt.Sprintf("%s#%s", strings.Repeat(" ", int(e.leadingSpace)), e.Comment)
}
type Include struct {
	Comment string
	directives []string
	mu sync.Mutex
	matches []string
	files        map[string]*Config
	leadingSpace int
	position     Position
	depth        uint8
	hasEquals    bool
}
const maxRecurseDepth = 5
var ErrDepthExceeded = errors.New("ssh_config: max recurse depth exceeded")
func removeDups(arr []string) []string {
	encountered := make(map[string]bool, len(arr))
	result := make([]string, 0)
	for v := range arr {
		if encountered[arr[v]] == false {
			encountered[arr[v]] = true
			result = append(result, arr[v])
		}
	}
	return result
}
func NewInclude(directives []string, hasEquals bool, pos Position, comment string, system bool, depth uint8) (*Include, error) {
	if depth > maxRecurseDepth {
		return nil, ErrDepthExceeded
	}
	inc := &Include{
		Comment:      comment,
		directives:   directives,
		files:        make(map[string]*Config),
		position:     pos,
		leadingSpace: pos.Col - 1,
		depth:        depth,
		hasEquals:    hasEquals,
	}
	matches := make([]string, 0)
	for i := range directives {
		var path string
		if filepath.IsAbs(directives[i]) {
			path = directives[i]
		} else if system {
			path = filepath.Join("/etc/ssh", directives[i])
		} else {
			path = filepath.Join(homedir(), ".ssh", directives[i])
		}
		theseMatches, err := filepath.Glob(path)
		if err != nil {
			return nil, err
		}
		matches = append(matches, theseMatches...)
	}
	matches = removeDups(matches)
	inc.matches = matches
	for i := range matches {
		config, err := parseWithDepth(matches[i], depth)
		if err != nil {
			return nil, err
		}
		inc.files[matches[i]] = config
	}
	return inc, nil
}