func (l *Loader) Delims(left, right string) {
	l.mu.Lock()
	defer l.mu.Unlock()
	l.leftDelim = left
	l.rightDelim = right
}
Delims sets the action delimiters to the specified strings.
package config
import (
	"bytes"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"os"
	"strings"
	"sync"
	"text/template"
	"github.com/BurntSushi/toml"
	"github.com/pkg/errors"
	"gopkg.in/yaml.v2"
)
func init() {
	defaultLoader = New()
}
type customFunc func(data []byte) ([]byte, error)
type unmarshaler func([]byte, interface{}) error
func ReadWithEnv(configPath string) ([]byte, error) {
	return defaultLoader.ReadWithEnv(configPath)
}
func ReadWithEnvBytes(b []byte) ([]byte, error) {
	return defaultLoader.ReadWithEnvBytes(b)
}
func Load(conf interface{}, configPaths ...string) error {
	return defaultLoader.Load(conf, configPaths...)
}
func LoadJSON(conf interface{}, configPaths ...string) error {
	return defaultLoader.LoadJSON(conf, configPaths...)
}
func LoadTOML(conf interface{}, configPaths ...string) error {
	return defaultLoader.LoadTOML(conf, configPaths...)
}
func LoadBytes(conf interface{}, src []byte) error {
	return defaultLoader.LoadBytes(conf, src)
}
func LoadJSONBytes(conf interface{}, src []byte) error {
	return defaultLoader.LoadJSONBytes(conf, src)
}
func LoadTOMLBytes(conf interface{}, src []byte) error {
	return defaultLoader.LoadTOMLBytes(conf, src)
}
func LoadWithEnv(conf interface{}, configPaths ...string) error {
	return defaultLoader.LoadWithEnv(conf, configPaths...)
}
func LoadWithEnvJSON(conf interface{}, configPaths ...string) error {
	return defaultLoader.LoadWithEnvJSON(conf, configPaths...)
}
func LoadWithEnvTOML(conf interface{}, configPaths ...string) error {
	return defaultLoader.LoadWithEnvTOML(conf, configPaths...)
}
func LoadWithEnvBytes(conf interface{}, src []byte) error {
	return defaultLoader.LoadWithEnvBytes(conf, src)
}
func LoadWithEnvJSONBytes(conf interface{}, src []byte) error {
	return defaultLoader.LoadWithEnvJSONBytes(conf, src)
}
func LoadWithEnvTOMLBytes(conf interface{}, src []byte) error {
	return defaultLoader.LoadWithEnvTOMLBytes(conf, src)
}
var Marshal = yaml.Marshal
func MarshalJSON(v interface{}) ([]byte, error) {
	return json.MarshalIndent(v, "", "  ")
}
func loadWithFunc(conf interface{}, configPaths []string, custom customFunc, unmarshal unmarshaler) error {
	for _, configPath := range configPaths {
		err := loadConfig(conf, configPath, custom, unmarshal)
		if err != nil {
			return err
		}
	}
	return nil
}
func loadConfig(conf interface{}, configPath string, custom customFunc, unmarshal unmarshaler) error {
	data, err := ioutil.ReadFile(configPath)
	if err != nil {
		return errors.Wrapf(err, "%s read failed", configPath)
	}
	if err := loadConfigBytes(conf, data, custom, unmarshal); err != nil {
		return errors.Wrapf(err, "%s load failed", configPath)
	}
	return nil
}
func loadConfigBytes(conf interface{}, data []byte, custom customFunc, unmarshal unmarshaler) error {
	data, err := readConfigBytes(data, custom)
	if err != nil {
		return err
	}
	if err := unmarshal(data, conf); err != nil {
		return errors.Wrap(err, "parse failed")
	}
	return nil
}
func readConfigBytes(data []byte, custom customFunc) ([]byte, error) {
	if custom == nil {
		return data, nil
	}
	data, err := custom(data)
	if err != nil {
		if strings.Contains(err.Error(), "must_env: environment variable") {
			panic(err)
		}
		return nil, err
	}
	return data, nil
}
func Delims(left, right string) {
	defaultLoader.Delims(left, right)
}
func Funcs(funcMap template.FuncMap) {
	defaultLoader.Funcs(funcMap)
}
var defaultLoader *Loader
type Loader struct {
	Data interface{}
	mu         sync.Mutex
	leftDelim  string
	rightDelim string
	funcMap    template.FuncMap
}
var DefaultFuncMap = template.FuncMap{
	"env": func(keys ...string) string {
		v := ""
		for _, k := range keys {
			v = os.Getenv(k)
			if v != "" {
				return v
			}
			v = k
		}
		return v
	},
	"must_env": func(key string) string {
		if v, ok := os.LookupEnv(key); ok {
			return v
		}
		panic(fmt.Sprintf("environment variable %s is not defined", key))
	},
	"json_escape": func(s string) string {
		b, _ := json.Marshal(s)         
		return string(b[1 : len(b)-1])  
	},
}
func New() *Loader {
	l := &Loader{
		funcMap: make(template.FuncMap, len(DefaultFuncMap)),
	}
	l.Funcs(DefaultFuncMap)
	return l
}
func (l *Loader) newTemplate() *template.Template {
	l.mu.Lock()
	defer l.mu.Unlock()
	tmpl := template.New("conf").Funcs(l.funcMap)
	if l.leftDelim != "" && l.rightDelim != "" {
		tmpl.Delims(l.leftDelim, l.rightDelim)
	}
	return tmpl
}
func (l *Loader) replacer(data []byte) ([]byte, error) {
	t, err := l.newTemplate().Parse(string(data))
	if err != nil {
		return nil, errors.Wrap(err, "config parse by template failed")
	}
	buf := &bytes.Buffer{}
	if err = t.Execute(buf, l.Data); err != nil {
		return nil, errors.Wrap(err, "template attach failed")
	}
	return buf.Bytes(), nil
}
func (l *Loader) Load(conf interface{}, configPaths ...string) error {
	return loadWithFunc(conf, configPaths, nil, yaml.Unmarshal)
}
func (l *Loader) LoadJSON(conf interface{}, configPaths ...string) error {
	return loadWithFunc(conf, configPaths, nil, json.Unmarshal)
}
func (l *Loader) LoadTOML(conf interface{}, configPaths ...string) error {
	return loadWithFunc(conf, configPaths, nil, toml.Unmarshal)
}
func (l *Loader) LoadBytes(conf interface{}, src []byte) error {
	return loadConfigBytes(conf, src, nil, yaml.Unmarshal)
}
func (l *Loader) LoadJSONBytes(conf interface{}, src []byte) error {
	return loadConfigBytes(conf, src, nil, json.Unmarshal)
}
func (l *Loader) LoadTOMLBytes(conf interface{}, src []byte) error {
	return loadConfigBytes(conf, src, nil, toml.Unmarshal)
}
func (l *Loader) LoadWithEnv(conf interface{}, configPaths ...string) error {
	return loadWithFunc(conf, configPaths, l.replacer, yaml.Unmarshal)
}
func (l *Loader) LoadWithEnvJSON(conf interface{}, configPaths ...string) error {
	return loadWithFunc(conf, configPaths, l.replacer, json.Unmarshal)
}
func (l *Loader) LoadWithEnvTOML(conf interface{}, configPaths ...string) error {
	return loadWithFunc(conf, configPaths, l.replacer, toml.Unmarshal)
}
func (l *Loader) LoadWithEnvBytes(conf interface{}, src []byte) error {
	return loadConfigBytes(conf, src, l.replacer, yaml.Unmarshal)
}
func (l *Loader) LoadWithEnvJSONBytes(conf interface{}, src []byte) error {
	return loadConfigBytes(conf, src, l.replacer, json.Unmarshal)
}
func (l *Loader) LoadWithEnvTOMLBytes(conf interface{}, src []byte) error {
	return loadConfigBytes(conf, src, l.replacer, toml.Unmarshal)
}