func (c *IniConfigContainer) Int64(key string) (int64, error) {
	return strconv.ParseInt(c.getdata(key), 10, 64)
}
Int64 returns the int64 value for a given key.
package config
import (
	"bufio"
	"bytes"
	"errors"
	"io"
	"io/ioutil"
	"os"
	"os/user"
	"path/filepath"
	"strconv"
	"strings"
	"sync"
)
var (
	defaultSection = "default"    
	bNumComment    = []byte{'#'}  
	bSemComment    = []byte{';'}  
	bEmpty         = []byte{}
	bEqual         = []byte{'='}  
	bDQuote        = []byte{'"'}  
	sectionStart   = []byte{'['}  
	sectionEnd     = []byte{']'}  
	lineBreak      = "\n"
)
type IniConfig struct {
}
func (ini *IniConfig) Parse(name string) (Configer, error) {
	return ini.parseFile(name)
}
func (ini *IniConfig) parseFile(name string) (*IniConfigContainer, error) {
	data, err := ioutil.ReadFile(name)
	if err != nil {
		return nil, err
	}
	return ini.parseData(filepath.Dir(name), data)
}
func (ini *IniConfig) parseData(dir string, data []byte) (*IniConfigContainer, error) {
	cfg := &IniConfigContainer{
		data:           make(map[string]map[string]string),
		sectionComment: make(map[string]string),
		keyComment:     make(map[string]string),
		RWMutex:        sync.RWMutex{},
	}
	cfg.Lock()
	defer cfg.Unlock()
	var comment bytes.Buffer
	buf := bufio.NewReader(bytes.NewBuffer(data))
	head, err := buf.Peek(3)
	if err == nil && head[0] == 239 && head[1] == 187 && head[2] == 191 {
		for i := 1; i <= 3; i++ {
			buf.ReadByte()
		}
	}
	section := defaultSection
	tmpBuf := bytes.NewBuffer(nil)
	for {
		tmpBuf.Reset()
		shouldBreak := false
		for {
			tmp, isPrefix, err := buf.ReadLine()
			if err == io.EOF {
				shouldBreak = true
				break
			}
			if _, ok := err.(*os.PathError); ok {
				return nil, err
			}
			tmpBuf.Write(tmp)
			if isPrefix {
				continue
			}
			if !isPrefix {
				break
			}
		}
		if shouldBreak {
			break
		}
		line := tmpBuf.Bytes()
		line = bytes.TrimSpace(line)
		if bytes.Equal(line, bEmpty) {
			continue
		}
		var bComment []byte
		switch {
		case bytes.HasPrefix(line, bNumComment):
			bComment = bNumComment
		case bytes.HasPrefix(line, bSemComment):
			bComment = bSemComment
		}
		if bComment != nil {
			line = bytes.TrimLeft(line, string(bComment))
			if comment.Len() > 0 {
				comment.WriteByte('\n')
			}
			comment.Write(line)
			continue
		}
		if bytes.HasPrefix(line, sectionStart) && bytes.HasSuffix(line, sectionEnd) {
			section = strings.ToLower(string(line[1 : len(line)-1]))  
			if comment.Len() > 0 {
				cfg.sectionComment[section] = comment.String()
				comment.Reset()
			}
			if _, ok := cfg.data[section]; !ok {
				cfg.data[section] = make(map[string]string)
			}
			continue
		}
		if _, ok := cfg.data[section]; !ok {
			cfg.data[section] = make(map[string]string)
		}
		keyValue := bytes.SplitN(line, bEqual, 2)
		key := string(bytes.TrimSpace(keyValue[0]))  
		key = strings.ToLower(key)
		if len(keyValue) == 1 && strings.HasPrefix(key, "include") {
			includefiles := strings.Fields(key)
			if includefiles[0] == "include" && len(includefiles) == 2 {
				otherfile := strings.Trim(includefiles[1], "\"")
				if !filepath.IsAbs(otherfile) {
					otherfile = filepath.Join(dir, otherfile)
				}
				i, err := ini.parseFile(otherfile)
				if err != nil {
					return nil, err
				}
				for sec, dt := range i.data {
					if _, ok := cfg.data[sec]; !ok {
						cfg.data[sec] = make(map[string]string)
					}
					for k, v := range dt {
						cfg.data[sec][k] = v
					}
				}
				for sec, comm := range i.sectionComment {
					cfg.sectionComment[sec] = comm
				}
				for k, comm := range i.keyComment {
					cfg.keyComment[k] = comm
				}
				continue
			}
		}
		if len(keyValue) != 2 {
			return nil, errors.New("read the content error: \"" + string(line) + "\", should key = val")
		}
		val := bytes.TrimSpace(keyValue[1])
		if bytes.HasPrefix(val, bDQuote) {
			val = bytes.Trim(val, `"`)
		}
		cfg.data[section][key] = ExpandValueEnv(string(val))
		if comment.Len() > 0 {
			cfg.keyComment[section+"."+key] = comment.String()
			comment.Reset()
		}
	}
	return cfg, nil
}
// ParseData parse ini the data
// When include other.conf,other.conf is either absolute directory
// or under beego in default temporary directory(/tmp/beego[-username]).
func (ini *IniConfig) ParseData(data []byte) (Configer, error) {
	dir := "beego"
	currentUser, err := user.Current()
	if err == nil {
		dir = "beego-" + currentUser.Username
	}
	dir = filepath.Join(os.TempDir(), dir)
	if err = os.MkdirAll(dir, os.ModePerm); err != nil {
		return nil, err
	}
	return ini.parseData(dir, data)
}
type IniConfigContainer struct {
	data           map[string]map[string]string  
	sectionComment map[string]string             
	keyComment     map[string]string             
	sync.RWMutex
}
func (c *IniConfigContainer) Bool(key string) (bool, error) {
	return ParseBool(c.getdata(key))
}
func (c *IniConfigContainer) DefaultBool(key string, defaultval bool) bool {
	v, err := c.Bool(key)
	if err != nil {
		return defaultval
	}
	return v
}
func (c *IniConfigContainer) Int(key string) (int, error) {
	return strconv.Atoi(c.getdata(key))
}
func (c *IniConfigContainer) DefaultInt(key string, defaultval int) int {
	v, err := c.Int(key)
	if err != nil {
		return defaultval
	}
	return v
}