| // Copyright © 2014 Steve Francia <spf@spf13.com>. | 
 | // | 
 | // Use of this source code is governed by an MIT-style | 
 | // license that can be found in the LICENSE file. | 
 |  | 
 | // Viper is a application configuration system. | 
 | // It believes that applications can be configured a variety of ways | 
 | // via flags, ENVIRONMENT variables, configuration files retrieved | 
 | // from the file system, or a remote key/value store. | 
 |  | 
 | // Each item takes precedence over the item below it: | 
 |  | 
 | // overrides | 
 | // flag | 
 | // env | 
 | // config | 
 | // key/value store | 
 | // default | 
 |  | 
 | package viper | 
 |  | 
 | import ( | 
 | 	"bytes" | 
 | 	"fmt" | 
 | 	"io" | 
 | 	"log" | 
 | 	"os" | 
 | 	"path/filepath" | 
 | 	"reflect" | 
 | 	"strings" | 
 | 	"time" | 
 |  | 
 | 	"github.com/fsnotify/fsnotify" | 
 | 	"github.com/mitchellh/mapstructure" | 
 | 	"github.com/spf13/afero" | 
 | 	"github.com/spf13/cast" | 
 | 	jww "github.com/spf13/jwalterweatherman" | 
 | 	"github.com/spf13/pflag" | 
 | ) | 
 |  | 
 | var v *Viper | 
 |  | 
 | func init() { | 
 | 	v = New() | 
 | } | 
 |  | 
 | type remoteConfigFactory interface { | 
 | 	Get(rp RemoteProvider) (io.Reader, error) | 
 | 	Watch(rp RemoteProvider) (io.Reader, error) | 
 | } | 
 |  | 
 | // RemoteConfig is optional, see the remote package | 
 | var RemoteConfig remoteConfigFactory | 
 |  | 
 | // UnsupportedConfigError denotes encountering an unsupported | 
 | // configuration filetype. | 
 | type UnsupportedConfigError string | 
 |  | 
 | // Error returns the formatted configuration error. | 
 | func (str UnsupportedConfigError) Error() string { | 
 | 	return fmt.Sprintf("Unsupported Config Type %q", string(str)) | 
 | } | 
 |  | 
 | // UnsupportedRemoteProviderError denotes encountering an unsupported remote | 
 | // provider. Currently only etcd and Consul are | 
 | // supported. | 
 | type UnsupportedRemoteProviderError string | 
 |  | 
 | // Error returns the formatted remote provider error. | 
 | func (str UnsupportedRemoteProviderError) Error() string { | 
 | 	return fmt.Sprintf("Unsupported Remote Provider Type %q", string(str)) | 
 | } | 
 |  | 
 | // RemoteConfigError denotes encountering an error while trying to | 
 | // pull the configuration from the remote provider. | 
 | type RemoteConfigError string | 
 |  | 
 | // Error returns the formatted remote provider error | 
 | func (rce RemoteConfigError) Error() string { | 
 | 	return fmt.Sprintf("Remote Configurations Error: %s", string(rce)) | 
 | } | 
 |  | 
 | // ConfigFileNotFoundError denotes failing to find configuration file. | 
 | type ConfigFileNotFoundError struct { | 
 | 	name, locations string | 
 | } | 
 |  | 
 | // Error returns the formatted configuration error. | 
 | func (fnfe ConfigFileNotFoundError) Error() string { | 
 | 	return fmt.Sprintf("Config File %q Not Found in %q", fnfe.name, fnfe.locations) | 
 | } | 
 |  | 
 | // Viper is a prioritized configuration registry. It | 
 | // maintains a set of configuration sources, fetches | 
 | // values to populate those, and provides them according | 
 | // to the source's priority. | 
 | // The priority of the sources is the following: | 
 | // 1. overrides | 
 | // 2. flags | 
 | // 3. env. variables | 
 | // 4. config file | 
 | // 5. key/value store | 
 | // 6. defaults | 
 | // | 
 | // For example, if values from the following sources were loaded: | 
 | // | 
 | //  Defaults : { | 
 | //  	"secret": "", | 
 | //  	"user": "default", | 
 | //  	"endpoint": "https://localhost" | 
 | //  } | 
 | //  Config : { | 
 | //  	"user": "root" | 
 | //  	"secret": "defaultsecret" | 
 | //  } | 
 | //  Env : { | 
 | //  	"secret": "somesecretkey" | 
 | //  } | 
 | // | 
 | // The resulting config will have the following values: | 
 | // | 
 | //	{ | 
 | //		"secret": "somesecretkey", | 
 | //		"user": "root", | 
 | //		"endpoint": "https://localhost" | 
 | //	} | 
 | type Viper struct { | 
 | 	// Delimiter that separates a list of keys | 
 | 	// used to access a nested value in one go | 
 | 	keyDelim string | 
 |  | 
 | 	// A set of paths to look for the config file in | 
 | 	configPaths []string | 
 |  | 
 | 	// The filesystem to read config from. | 
 | 	fs afero.Fs | 
 |  | 
 | 	// A set of remote providers to search for the configuration | 
 | 	remoteProviders []*defaultRemoteProvider | 
 |  | 
 | 	// Name of file to look for inside the path | 
 | 	configName string | 
 | 	configFile string | 
 | 	configType string | 
 | 	envPrefix  string | 
 |  | 
 | 	automaticEnvApplied bool | 
 | 	envKeyReplacer      *strings.Replacer | 
 |  | 
 | 	config         map[string]interface{} | 
 | 	override       map[string]interface{} | 
 | 	defaults       map[string]interface{} | 
 | 	kvstore        map[string]interface{} | 
 | 	pflags         map[string]FlagValue | 
 | 	env            map[string]string | 
 | 	aliases        map[string]string | 
 | 	typeByDefValue bool | 
 |  | 
 | 	onConfigChange func(fsnotify.Event) | 
 | } | 
 |  | 
 | // New returns an initialized Viper instance. | 
 | func New() *Viper { | 
 | 	v := new(Viper) | 
 | 	v.keyDelim = "." | 
 | 	v.configName = "config" | 
 | 	v.fs = afero.NewOsFs() | 
 | 	v.config = make(map[string]interface{}) | 
 | 	v.override = make(map[string]interface{}) | 
 | 	v.defaults = make(map[string]interface{}) | 
 | 	v.kvstore = make(map[string]interface{}) | 
 | 	v.pflags = make(map[string]FlagValue) | 
 | 	v.env = make(map[string]string) | 
 | 	v.aliases = make(map[string]string) | 
 | 	v.typeByDefValue = false | 
 |  | 
 | 	return v | 
 | } | 
 |  | 
 | // Intended for testing, will reset all to default settings. | 
 | // In the public interface for the viper package so applications | 
 | // can use it in their testing as well. | 
 | func Reset() { | 
 | 	v = New() | 
 | 	SupportedExts = []string{"json", "toml", "yaml", "yml", "hcl"} | 
 | 	SupportedRemoteProviders = []string{"etcd", "consul"} | 
 | } | 
 |  | 
 | type defaultRemoteProvider struct { | 
 | 	provider      string | 
 | 	endpoint      string | 
 | 	path          string | 
 | 	secretKeyring string | 
 | } | 
 |  | 
 | func (rp defaultRemoteProvider) Provider() string { | 
 | 	return rp.provider | 
 | } | 
 |  | 
 | func (rp defaultRemoteProvider) Endpoint() string { | 
 | 	return rp.endpoint | 
 | } | 
 |  | 
 | func (rp defaultRemoteProvider) Path() string { | 
 | 	return rp.path | 
 | } | 
 |  | 
 | func (rp defaultRemoteProvider) SecretKeyring() string { | 
 | 	return rp.secretKeyring | 
 | } | 
 |  | 
 | // RemoteProvider stores the configuration necessary | 
 | // to connect to a remote key/value store. | 
 | // Optional secretKeyring to unencrypt encrypted values | 
 | // can be provided. | 
 | type RemoteProvider interface { | 
 | 	Provider() string | 
 | 	Endpoint() string | 
 | 	Path() string | 
 | 	SecretKeyring() string | 
 | } | 
 |  | 
 | // SupportedExts are universally supported extensions. | 
 | var SupportedExts = []string{"json", "toml", "yaml", "yml", "properties", "props", "prop", "hcl"} | 
 |  | 
 | // SupportedRemoteProviders are universally supported remote providers. | 
 | var SupportedRemoteProviders = []string{"etcd", "consul"} | 
 |  | 
 | func OnConfigChange(run func(in fsnotify.Event)) { v.OnConfigChange(run) } | 
 | func (v *Viper) OnConfigChange(run func(in fsnotify.Event)) { | 
 | 	v.onConfigChange = run | 
 | } | 
 |  | 
 | func WatchConfig() { v.WatchConfig() } | 
 | func (v *Viper) WatchConfig() { | 
 | 	go func() { | 
 | 		watcher, err := fsnotify.NewWatcher() | 
 | 		if err != nil { | 
 | 			log.Fatal(err) | 
 | 		} | 
 | 		defer watcher.Close() | 
 |  | 
 | 		// we have to watch the entire directory to pick up renames/atomic saves in a cross-platform way | 
 | 		filename, err := v.getConfigFile() | 
 | 		if err != nil { | 
 | 			log.Println("error:", err) | 
 | 			return | 
 | 		} | 
 |  | 
 | 		configFile := filepath.Clean(filename) | 
 | 		configDir, _ := filepath.Split(configFile) | 
 |  | 
 | 		done := make(chan bool) | 
 | 		go func() { | 
 | 			for { | 
 | 				select { | 
 | 				case event := <-watcher.Events: | 
 | 					// we only care about the config file | 
 | 					if filepath.Clean(event.Name) == configFile { | 
 | 						if event.Op&fsnotify.Write == fsnotify.Write || event.Op&fsnotify.Create == fsnotify.Create { | 
 | 							err := v.ReadInConfig() | 
 | 							if err != nil { | 
 | 								log.Println("error:", err) | 
 | 							} | 
 | 							v.onConfigChange(event) | 
 | 						} | 
 | 					} | 
 | 				case err := <-watcher.Errors: | 
 | 					log.Println("error:", err) | 
 | 				} | 
 | 			} | 
 | 		}() | 
 |  | 
 | 		watcher.Add(configDir) | 
 | 		<-done | 
 | 	}() | 
 | } | 
 |  | 
 | // SetConfigFile explicitly defines the path, name and extension of the config file | 
 | // Viper will use this and not check any of the config paths | 
 | func SetConfigFile(in string) { v.SetConfigFile(in) } | 
 | func (v *Viper) SetConfigFile(in string) { | 
 | 	if in != "" { | 
 | 		v.configFile = in | 
 | 	} | 
 | } | 
 |  | 
 | // SetEnvPrefix defines a prefix that ENVIRONMENT variables will use. | 
 | // E.g. if your prefix is "spf", the env registry | 
 | // will look for env. variables that start with "SPF_" | 
 | func SetEnvPrefix(in string) { v.SetEnvPrefix(in) } | 
 | func (v *Viper) SetEnvPrefix(in string) { | 
 | 	if in != "" { | 
 | 		v.envPrefix = in | 
 | 	} | 
 | } | 
 |  | 
 | func (v *Viper) mergeWithEnvPrefix(in string) string { | 
 | 	if v.envPrefix != "" { | 
 | 		return strings.ToUpper(v.envPrefix + "_" + in) | 
 | 	} | 
 |  | 
 | 	return strings.ToUpper(in) | 
 | } | 
 |  | 
 | // TODO: should getEnv logic be moved into find(). Can generalize the use of | 
 | // rewriting keys many things, Ex: Get('someKey') -> some_key | 
 | // (cammel case to snake case for JSON keys perhaps) | 
 |  | 
 | // getEnv is a wrapper around os.Getenv which replaces characters in the original | 
 | // key. This allows env vars which have different keys then the config object | 
 | // keys | 
 | func (v *Viper) getEnv(key string) string { | 
 | 	if v.envKeyReplacer != nil { | 
 | 		key = v.envKeyReplacer.Replace(key) | 
 | 	} | 
 | 	return os.Getenv(key) | 
 | } | 
 |  | 
 | // ConfigFileUsed returns the file used to populate the config registry | 
 | func ConfigFileUsed() string            { return v.ConfigFileUsed() } | 
 | func (v *Viper) ConfigFileUsed() string { return v.configFile } | 
 |  | 
 | // AddConfigPath adds a path for Viper to search for the config file in. | 
 | // Can be called multiple times to define multiple search paths. | 
 | func AddConfigPath(in string) { v.AddConfigPath(in) } | 
 | func (v *Viper) AddConfigPath(in string) { | 
 | 	if in != "" { | 
 | 		absin := absPathify(in) | 
 | 		jww.INFO.Println("adding", absin, "to paths to search") | 
 | 		if !stringInSlice(absin, v.configPaths) { | 
 | 			v.configPaths = append(v.configPaths, absin) | 
 | 		} | 
 | 	} | 
 | } | 
 |  | 
 | // AddRemoteProvider adds a remote configuration source. | 
 | // Remote Providers are searched in the order they are added. | 
 | // provider is a string value, "etcd" or "consul" are currently supported. | 
 | // endpoint is the url.  etcd requires http://ip:port  consul requires ip:port | 
 | // path is the path in the k/v store to retrieve configuration | 
 | // To retrieve a config file called myapp.json from /configs/myapp.json | 
 | // you should set path to /configs and set config name (SetConfigName()) to | 
 | // "myapp" | 
 | func AddRemoteProvider(provider, endpoint, path string) error { | 
 | 	return v.AddRemoteProvider(provider, endpoint, path) | 
 | } | 
 | func (v *Viper) AddRemoteProvider(provider, endpoint, path string) error { | 
 | 	if !stringInSlice(provider, SupportedRemoteProviders) { | 
 | 		return UnsupportedRemoteProviderError(provider) | 
 | 	} | 
 | 	if provider != "" && endpoint != "" { | 
 | 		jww.INFO.Printf("adding %s:%s to remote provider list", provider, endpoint) | 
 | 		rp := &defaultRemoteProvider{ | 
 | 			endpoint: endpoint, | 
 | 			provider: provider, | 
 | 			path:     path, | 
 | 		} | 
 | 		if !v.providerPathExists(rp) { | 
 | 			v.remoteProviders = append(v.remoteProviders, rp) | 
 | 		} | 
 | 	} | 
 | 	return nil | 
 | } | 
 |  | 
 | // AddSecureRemoteProvider adds a remote configuration source. | 
 | // Secure Remote Providers are searched in the order they are added. | 
 | // provider is a string value, "etcd" or "consul" are currently supported. | 
 | // endpoint is the url.  etcd requires http://ip:port  consul requires ip:port | 
 | // secretkeyring is the filepath to your openpgp secret keyring.  e.g. /etc/secrets/myring.gpg | 
 | // path is the path in the k/v store to retrieve configuration | 
 | // To retrieve a config file called myapp.json from /configs/myapp.json | 
 | // you should set path to /configs and set config name (SetConfigName()) to | 
 | // "myapp" | 
 | // Secure Remote Providers are implemented with github.com/xordataexchange/crypt | 
 | func AddSecureRemoteProvider(provider, endpoint, path, secretkeyring string) error { | 
 | 	return v.AddSecureRemoteProvider(provider, endpoint, path, secretkeyring) | 
 | } | 
 |  | 
 | func (v *Viper) AddSecureRemoteProvider(provider, endpoint, path, secretkeyring string) error { | 
 | 	if !stringInSlice(provider, SupportedRemoteProviders) { | 
 | 		return UnsupportedRemoteProviderError(provider) | 
 | 	} | 
 | 	if provider != "" && endpoint != "" { | 
 | 		jww.INFO.Printf("adding %s:%s to remote provider list", provider, endpoint) | 
 | 		rp := &defaultRemoteProvider{ | 
 | 			endpoint:      endpoint, | 
 | 			provider:      provider, | 
 | 			path:          path, | 
 | 			secretKeyring: secretkeyring, | 
 | 		} | 
 | 		if !v.providerPathExists(rp) { | 
 | 			v.remoteProviders = append(v.remoteProviders, rp) | 
 | 		} | 
 | 	} | 
 | 	return nil | 
 | } | 
 |  | 
 | func (v *Viper) providerPathExists(p *defaultRemoteProvider) bool { | 
 | 	for _, y := range v.remoteProviders { | 
 | 		if reflect.DeepEqual(y, p) { | 
 | 			return true | 
 | 		} | 
 | 	} | 
 | 	return false | 
 | } | 
 |  | 
 | // searchMap recursively searches for a value for path in source map. | 
 | // Returns nil if not found. | 
 | // Note: This assumes that the path entries and map keys are lower cased. | 
 | func (v *Viper) searchMap(source map[string]interface{}, path []string) interface{} { | 
 | 	if len(path) == 0 { | 
 | 		return source | 
 | 	} | 
 |  | 
 | 	next, ok := source[path[0]] | 
 | 	if ok { | 
 | 		// Fast path | 
 | 		if len(path) == 1 { | 
 | 			return next | 
 | 		} | 
 |  | 
 | 		// Nested case | 
 | 		switch next.(type) { | 
 | 		case map[interface{}]interface{}: | 
 | 			return v.searchMap(cast.ToStringMap(next), path[1:]) | 
 | 		case map[string]interface{}: | 
 | 			// Type assertion is safe here since it is only reached | 
 | 			// if the type of `next` is the same as the type being asserted | 
 | 			return v.searchMap(next.(map[string]interface{}), path[1:]) | 
 | 		default: | 
 | 			// got a value but nested key expected, return "nil" for not found | 
 | 			return nil | 
 | 		} | 
 | 	} | 
 | 	return nil | 
 | } | 
 |  | 
 | // searchMapWithPathPrefixes recursively searches for a value for path in source map. | 
 | // | 
 | // While searchMap() considers each path element as a single map key, this | 
 | // function searches for, and prioritizes, merged path elements. | 
 | // e.g., if in the source, "foo" is defined with a sub-key "bar", and "foo.bar" | 
 | // is also defined, this latter value is returned for path ["foo", "bar"]. | 
 | // | 
 | // This should be useful only at config level (other maps may not contain dots | 
 | // in their keys). | 
 | // | 
 | // Note: This assumes that the path entries and map keys are lower cased. | 
 | func (v *Viper) searchMapWithPathPrefixes(source map[string]interface{}, path []string) interface{} { | 
 | 	if len(path) == 0 { | 
 | 		return source | 
 | 	} | 
 |  | 
 | 	// search for path prefixes, starting from the longest one | 
 | 	for i := len(path); i > 0; i-- { | 
 | 		prefixKey := strings.ToLower(strings.Join(path[0:i], v.keyDelim)) | 
 |  | 
 | 		next, ok := source[prefixKey] | 
 | 		if ok { | 
 | 			// Fast path | 
 | 			if i == len(path) { | 
 | 				return next | 
 | 			} | 
 |  | 
 | 			// Nested case | 
 | 			var val interface{} | 
 | 			switch next.(type) { | 
 | 			case map[interface{}]interface{}: | 
 | 				val = v.searchMapWithPathPrefixes(cast.ToStringMap(next), path[i:]) | 
 | 			case map[string]interface{}: | 
 | 				// Type assertion is safe here since it is only reached | 
 | 				// if the type of `next` is the same as the type being asserted | 
 | 				val = v.searchMapWithPathPrefixes(next.(map[string]interface{}), path[i:]) | 
 | 			default: | 
 | 				// got a value but nested key expected, do nothing and look for next prefix | 
 | 			} | 
 | 			if val != nil { | 
 | 				return val | 
 | 			} | 
 | 		} | 
 | 	} | 
 |  | 
 | 	// not found | 
 | 	return nil | 
 | } | 
 |  | 
 | // isPathShadowedInDeepMap makes sure the given path is not shadowed somewhere | 
 | // on its path in the map. | 
 | // e.g., if "foo.bar" has a value in the given map, it “shadows” | 
 | //       "foo.bar.baz" in a lower-priority map | 
 | func (v *Viper) isPathShadowedInDeepMap(path []string, m map[string]interface{}) string { | 
 | 	var parentVal interface{} | 
 | 	for i := 1; i < len(path); i++ { | 
 | 		parentVal = v.searchMap(m, path[0:i]) | 
 | 		if parentVal == nil { | 
 | 			// not found, no need to add more path elements | 
 | 			return "" | 
 | 		} | 
 | 		switch parentVal.(type) { | 
 | 		case map[interface{}]interface{}: | 
 | 			continue | 
 | 		case map[string]interface{}: | 
 | 			continue | 
 | 		default: | 
 | 			// parentVal is a regular value which shadows "path" | 
 | 			return strings.Join(path[0:i], v.keyDelim) | 
 | 		} | 
 | 	} | 
 | 	return "" | 
 | } | 
 |  | 
 | // isPathShadowedInFlatMap makes sure the given path is not shadowed somewhere | 
 | // in a sub-path of the map. | 
 | // e.g., if "foo.bar" has a value in the given map, it “shadows” | 
 | //       "foo.bar.baz" in a lower-priority map | 
 | func (v *Viper) isPathShadowedInFlatMap(path []string, mi interface{}) string { | 
 | 	// unify input map | 
 | 	var m map[string]interface{} | 
 | 	switch mi.(type) { | 
 | 	case map[string]string, map[string]FlagValue: | 
 | 		m = cast.ToStringMap(mi) | 
 | 	default: | 
 | 		return "" | 
 | 	} | 
 |  | 
 | 	// scan paths | 
 | 	var parentKey string | 
 | 	for i := 1; i < len(path); i++ { | 
 | 		parentKey = strings.Join(path[0:i], v.keyDelim) | 
 | 		if _, ok := m[parentKey]; ok { | 
 | 			return parentKey | 
 | 		} | 
 | 	} | 
 | 	return "" | 
 | } | 
 |  | 
 | // isPathShadowedInAutoEnv makes sure the given path is not shadowed somewhere | 
 | // in the environment, when automatic env is on. | 
 | // e.g., if "foo.bar" has a value in the environment, it “shadows” | 
 | //       "foo.bar.baz" in a lower-priority map | 
 | func (v *Viper) isPathShadowedInAutoEnv(path []string) string { | 
 | 	var parentKey string | 
 | 	var val string | 
 | 	for i := 1; i < len(path); i++ { | 
 | 		parentKey = strings.Join(path[0:i], v.keyDelim) | 
 | 		if val = v.getEnv(v.mergeWithEnvPrefix(parentKey)); val != "" { | 
 | 			return parentKey | 
 | 		} | 
 | 	} | 
 | 	return "" | 
 | } | 
 |  | 
 | // SetTypeByDefaultValue enables or disables the inference of a key value's | 
 | // type when the Get function is used based upon a key's default value as | 
 | // opposed to the value returned based on the normal fetch logic. | 
 | // | 
 | // For example, if a key has a default value of []string{} and the same key | 
 | // is set via an environment variable to "a b c", a call to the Get function | 
 | // would return a string slice for the key if the key's type is inferred by | 
 | // the default value and the Get function would return: | 
 | // | 
 | //   []string {"a", "b", "c"} | 
 | // | 
 | // Otherwise the Get function would return: | 
 | // | 
 | //   "a b c" | 
 | func SetTypeByDefaultValue(enable bool) { v.SetTypeByDefaultValue(enable) } | 
 | func (v *Viper) SetTypeByDefaultValue(enable bool) { | 
 | 	v.typeByDefValue = enable | 
 | } | 
 |  | 
 | // GetViper gets the global Viper instance. | 
 | func GetViper() *Viper { | 
 | 	return v | 
 | } | 
 |  | 
 | // Get can retrieve any value given the key to use. | 
 | // Get is case-insensitive for a key. | 
 | // Get has the behavior of returning the value associated with the first | 
 | // place from where it is set. Viper will check in the following order: | 
 | // override, flag, env, config file, key/value store, default | 
 | // | 
 | // Get returns an interface. For a specific value use one of the Get____ methods. | 
 | func Get(key string) interface{} { return v.Get(key) } | 
 | func (v *Viper) Get(key string) interface{} { | 
 | 	lcaseKey := strings.ToLower(key) | 
 | 	val := v.find(lcaseKey) | 
 | 	if val == nil { | 
 | 		return nil | 
 | 	} | 
 |  | 
 | 	valType := val | 
 | 	if v.typeByDefValue { | 
 | 		// TODO(bep) this branch isn't covered by a single test. | 
 | 		path := strings.Split(lcaseKey, v.keyDelim) | 
 | 		defVal := v.searchMap(v.defaults, path) | 
 | 		if defVal != nil { | 
 | 			valType = defVal | 
 | 		} | 
 | 	} | 
 |  | 
 | 	switch valType.(type) { | 
 | 	case bool: | 
 | 		return cast.ToBool(val) | 
 | 	case string: | 
 | 		return cast.ToString(val) | 
 | 	case int64, int32, int16, int8, int: | 
 | 		return cast.ToInt(val) | 
 | 	case float64, float32: | 
 | 		return cast.ToFloat64(val) | 
 | 	case time.Time: | 
 | 		return cast.ToTime(val) | 
 | 	case time.Duration: | 
 | 		return cast.ToDuration(val) | 
 | 	case []string: | 
 | 		return cast.ToStringSlice(val) | 
 | 	} | 
 | 	return val | 
 | } | 
 |  | 
 | // Sub returns new Viper instance representing a sub tree of this instance. | 
 | // Sub is case-insensitive for a key. | 
 | func Sub(key string) *Viper { return v.Sub(key) } | 
 | func (v *Viper) Sub(key string) *Viper { | 
 | 	subv := New() | 
 | 	data := v.Get(key) | 
 | 	if data == nil { | 
 | 		return nil | 
 | 	} | 
 |  | 
 | 	if reflect.TypeOf(data).Kind() == reflect.Map { | 
 | 		subv.config = cast.ToStringMap(data) | 
 | 		return subv | 
 | 	} | 
 | 	return nil | 
 | } | 
 |  | 
 | // GetString returns the value associated with the key as a string. | 
 | func GetString(key string) string { return v.GetString(key) } | 
 | func (v *Viper) GetString(key string) string { | 
 | 	return cast.ToString(v.Get(key)) | 
 | } | 
 |  | 
 | // GetBool returns the value associated with the key as a boolean. | 
 | func GetBool(key string) bool { return v.GetBool(key) } | 
 | func (v *Viper) GetBool(key string) bool { | 
 | 	return cast.ToBool(v.Get(key)) | 
 | } | 
 |  | 
 | // GetInt returns the value associated with the key as an integer. | 
 | func GetInt(key string) int { return v.GetInt(key) } | 
 | func (v *Viper) GetInt(key string) int { | 
 | 	return cast.ToInt(v.Get(key)) | 
 | } | 
 |  | 
 | // GetInt64 returns the value associated with the key as an integer. | 
 | func GetInt64(key string) int64 { return v.GetInt64(key) } | 
 | func (v *Viper) GetInt64(key string) int64 { | 
 | 	return cast.ToInt64(v.Get(key)) | 
 | } | 
 |  | 
 | // GetFloat64 returns the value associated with the key as a float64. | 
 | func GetFloat64(key string) float64 { return v.GetFloat64(key) } | 
 | func (v *Viper) GetFloat64(key string) float64 { | 
 | 	return cast.ToFloat64(v.Get(key)) | 
 | } | 
 |  | 
 | // GetTime returns the value associated with the key as time. | 
 | func GetTime(key string) time.Time { return v.GetTime(key) } | 
 | func (v *Viper) GetTime(key string) time.Time { | 
 | 	return cast.ToTime(v.Get(key)) | 
 | } | 
 |  | 
 | // GetDuration returns the value associated with the key as a duration. | 
 | func GetDuration(key string) time.Duration { return v.GetDuration(key) } | 
 | func (v *Viper) GetDuration(key string) time.Duration { | 
 | 	return cast.ToDuration(v.Get(key)) | 
 | } | 
 |  | 
 | // GetStringSlice returns the value associated with the key as a slice of strings. | 
 | func GetStringSlice(key string) []string { return v.GetStringSlice(key) } | 
 | func (v *Viper) GetStringSlice(key string) []string { | 
 | 	return cast.ToStringSlice(v.Get(key)) | 
 | } | 
 |  | 
 | // GetStringMap returns the value associated with the key as a map of interfaces. | 
 | func GetStringMap(key string) map[string]interface{} { return v.GetStringMap(key) } | 
 | func (v *Viper) GetStringMap(key string) map[string]interface{} { | 
 | 	return cast.ToStringMap(v.Get(key)) | 
 | } | 
 |  | 
 | // GetStringMapString returns the value associated with the key as a map of strings. | 
 | func GetStringMapString(key string) map[string]string { return v.GetStringMapString(key) } | 
 | func (v *Viper) GetStringMapString(key string) map[string]string { | 
 | 	return cast.ToStringMapString(v.Get(key)) | 
 | } | 
 |  | 
 | // GetStringMapStringSlice returns the value associated with the key as a map to a slice of strings. | 
 | func GetStringMapStringSlice(key string) map[string][]string { return v.GetStringMapStringSlice(key) } | 
 | func (v *Viper) GetStringMapStringSlice(key string) map[string][]string { | 
 | 	return cast.ToStringMapStringSlice(v.Get(key)) | 
 | } | 
 |  | 
 | // GetSizeInBytes returns the size of the value associated with the given key | 
 | // in bytes. | 
 | func GetSizeInBytes(key string) uint { return v.GetSizeInBytes(key) } | 
 | func (v *Viper) GetSizeInBytes(key string) uint { | 
 | 	sizeStr := cast.ToString(v.Get(key)) | 
 | 	return parseSizeInBytes(sizeStr) | 
 | } | 
 |  | 
 | // UnmarshalKey takes a single key and unmarshals it into a Struct. | 
 | func UnmarshalKey(key string, rawVal interface{}) error { return v.UnmarshalKey(key, rawVal) } | 
 | func (v *Viper) UnmarshalKey(key string, rawVal interface{}) error { | 
 | 	return mapstructure.Decode(v.Get(key), rawVal) | 
 | } | 
 |  | 
 | // Unmarshal unmarshals the config into a Struct. Make sure that the tags | 
 | // on the fields of the structure are properly set. | 
 | func Unmarshal(rawVal interface{}) error { return v.Unmarshal(rawVal) } | 
 | func (v *Viper) Unmarshal(rawVal interface{}) error { | 
 | 	err := decode(v.AllSettings(), defaultDecoderConfig(rawVal)) | 
 |  | 
 | 	if err != nil { | 
 | 		return err | 
 | 	} | 
 |  | 
 | 	v.insensitiviseMaps() | 
 |  | 
 | 	return nil | 
 | } | 
 |  | 
 | // defaultDecoderConfig returns default mapsstructure.DecoderConfig with suppot | 
 | // of time.Duration values | 
 | func defaultDecoderConfig(output interface{}) *mapstructure.DecoderConfig { | 
 | 	return &mapstructure.DecoderConfig{ | 
 | 		Metadata:         nil, | 
 | 		Result:           output, | 
 | 		WeaklyTypedInput: true, | 
 | 		DecodeHook:       mapstructure.StringToTimeDurationHookFunc(), | 
 | 	} | 
 | } | 
 |  | 
 | // A wrapper around mapstructure.Decode that mimics the WeakDecode functionality | 
 | func decode(input interface{}, config *mapstructure.DecoderConfig) error { | 
 | 	decoder, err := mapstructure.NewDecoder(config) | 
 | 	if err != nil { | 
 | 		return err | 
 | 	} | 
 | 	return decoder.Decode(input) | 
 | } | 
 |  | 
 | // UnmarshalExact unmarshals the config into a Struct, erroring if a field is nonexistent | 
 | // in the destination struct. | 
 | func (v *Viper) UnmarshalExact(rawVal interface{}) error { | 
 | 	config := defaultDecoderConfig(rawVal) | 
 | 	config.ErrorUnused = true | 
 |  | 
 | 	err := decode(v.AllSettings(), config) | 
 |  | 
 | 	if err != nil { | 
 | 		return err | 
 | 	} | 
 |  | 
 | 	v.insensitiviseMaps() | 
 |  | 
 | 	return nil | 
 | } | 
 |  | 
 | // BindPFlags binds a full flag set to the configuration, using each flag's long | 
 | // name as the config key. | 
 | func BindPFlags(flags *pflag.FlagSet) error { return v.BindPFlags(flags) } | 
 | func (v *Viper) BindPFlags(flags *pflag.FlagSet) error { | 
 | 	return v.BindFlagValues(pflagValueSet{flags}) | 
 | } | 
 |  | 
 | // BindPFlag binds a specific key to a pflag (as used by cobra). | 
 | // Example (where serverCmd is a Cobra instance): | 
 | // | 
 | //	 serverCmd.Flags().Int("port", 1138, "Port to run Application server on") | 
 | //	 Viper.BindPFlag("port", serverCmd.Flags().Lookup("port")) | 
 | // | 
 | func BindPFlag(key string, flag *pflag.Flag) error { return v.BindPFlag(key, flag) } | 
 | func (v *Viper) BindPFlag(key string, flag *pflag.Flag) error { | 
 | 	return v.BindFlagValue(key, pflagValue{flag}) | 
 | } | 
 |  | 
 | // BindFlagValues binds a full FlagValue set to the configuration, using each flag's long | 
 | // name as the config key. | 
 | func BindFlagValues(flags FlagValueSet) error { return v.BindFlagValues(flags) } | 
 | func (v *Viper) BindFlagValues(flags FlagValueSet) (err error) { | 
 | 	flags.VisitAll(func(flag FlagValue) { | 
 | 		if err = v.BindFlagValue(flag.Name(), flag); err != nil { | 
 | 			return | 
 | 		} | 
 | 	}) | 
 | 	return nil | 
 | } | 
 |  | 
 | // BindFlagValue binds a specific key to a FlagValue. | 
 | // Example(where serverCmd is a Cobra instance): | 
 | // | 
 | //	 serverCmd.Flags().Int("port", 1138, "Port to run Application server on") | 
 | //	 Viper.BindFlagValue("port", serverCmd.Flags().Lookup("port")) | 
 | // | 
 | func BindFlagValue(key string, flag FlagValue) error { return v.BindFlagValue(key, flag) } | 
 | func (v *Viper) BindFlagValue(key string, flag FlagValue) error { | 
 | 	if flag == nil { | 
 | 		return fmt.Errorf("flag for %q is nil", key) | 
 | 	} | 
 | 	v.pflags[strings.ToLower(key)] = flag | 
 | 	return nil | 
 | } | 
 |  | 
 | // BindEnv binds a Viper key to a ENV variable. | 
 | // ENV variables are case sensitive. | 
 | // If only a key is provided, it will use the env key matching the key, uppercased. | 
 | // EnvPrefix will be used when set when env name is not provided. | 
 | func BindEnv(input ...string) error { return v.BindEnv(input...) } | 
 | func (v *Viper) BindEnv(input ...string) error { | 
 | 	var key, envkey string | 
 | 	if len(input) == 0 { | 
 | 		return fmt.Errorf("BindEnv missing key to bind to") | 
 | 	} | 
 |  | 
 | 	key = strings.ToLower(input[0]) | 
 |  | 
 | 	if len(input) == 1 { | 
 | 		envkey = v.mergeWithEnvPrefix(key) | 
 | 	} else { | 
 | 		envkey = input[1] | 
 | 	} | 
 |  | 
 | 	v.env[key] = envkey | 
 |  | 
 | 	return nil | 
 | } | 
 |  | 
 | // Given a key, find the value. | 
 | // Viper will check in the following order: | 
 | // flag, env, config file, key/value store, default. | 
 | // Viper will check to see if an alias exists first. | 
 | // Note: this assumes a lower-cased key given. | 
 | func (v *Viper) find(lcaseKey string) interface{} { | 
 |  | 
 | 	var ( | 
 | 		val    interface{} | 
 | 		exists bool | 
 | 		path   = strings.Split(lcaseKey, v.keyDelim) | 
 | 		nested = len(path) > 1 | 
 | 	) | 
 |  | 
 | 	// compute the path through the nested maps to the nested value | 
 | 	if nested && v.isPathShadowedInDeepMap(path, castMapStringToMapInterface(v.aliases)) != "" { | 
 | 		return nil | 
 | 	} | 
 |  | 
 | 	// if the requested key is an alias, then return the proper key | 
 | 	lcaseKey = v.realKey(lcaseKey) | 
 | 	path = strings.Split(lcaseKey, v.keyDelim) | 
 | 	nested = len(path) > 1 | 
 |  | 
 | 	// Set() override first | 
 | 	val = v.searchMap(v.override, path) | 
 | 	if val != nil { | 
 | 		return val | 
 | 	} | 
 | 	if nested && v.isPathShadowedInDeepMap(path, v.override) != "" { | 
 | 		return nil | 
 | 	} | 
 |  | 
 | 	// PFlag override next | 
 | 	flag, exists := v.pflags[lcaseKey] | 
 | 	if exists && flag.HasChanged() { | 
 | 		switch flag.ValueType() { | 
 | 		case "int", "int8", "int16", "int32", "int64": | 
 | 			return cast.ToInt(flag.ValueString()) | 
 | 		case "bool": | 
 | 			return cast.ToBool(flag.ValueString()) | 
 | 		case "stringSlice": | 
 | 			s := strings.TrimPrefix(flag.ValueString(), "[") | 
 | 			return strings.TrimSuffix(s, "]") | 
 | 		default: | 
 | 			return flag.ValueString() | 
 | 		} | 
 | 	} | 
 | 	if nested && v.isPathShadowedInFlatMap(path, v.pflags) != "" { | 
 | 		return nil | 
 | 	} | 
 |  | 
 | 	// Env override next | 
 | 	if v.automaticEnvApplied { | 
 | 		// even if it hasn't been registered, if automaticEnv is used, | 
 | 		// check any Get request | 
 | 		if val = v.getEnv(v.mergeWithEnvPrefix(lcaseKey)); val != "" { | 
 | 			return val | 
 | 		} | 
 | 		if nested && v.isPathShadowedInAutoEnv(path) != "" { | 
 | 			return nil | 
 | 		} | 
 | 	} | 
 | 	envkey, exists := v.env[lcaseKey] | 
 | 	if exists { | 
 | 		if val = v.getEnv(envkey); val != "" { | 
 | 			return val | 
 | 		} | 
 | 	} | 
 | 	if nested && v.isPathShadowedInFlatMap(path, v.env) != "" { | 
 | 		return nil | 
 | 	} | 
 |  | 
 | 	// Config file next | 
 | 	val = v.searchMapWithPathPrefixes(v.config, path) | 
 | 	if val != nil { | 
 | 		return val | 
 | 	} | 
 | 	if nested && v.isPathShadowedInDeepMap(path, v.config) != "" { | 
 | 		return nil | 
 | 	} | 
 |  | 
 | 	// K/V store next | 
 | 	val = v.searchMap(v.kvstore, path) | 
 | 	if val != nil { | 
 | 		return val | 
 | 	} | 
 | 	if nested && v.isPathShadowedInDeepMap(path, v.kvstore) != "" { | 
 | 		return nil | 
 | 	} | 
 |  | 
 | 	// Default next | 
 | 	val = v.searchMap(v.defaults, path) | 
 | 	if val != nil { | 
 | 		return val | 
 | 	} | 
 | 	if nested && v.isPathShadowedInDeepMap(path, v.defaults) != "" { | 
 | 		return nil | 
 | 	} | 
 |  | 
 | 	// last chance: if no other value is returned and a flag does exist for the value, | 
 | 	// get the flag's value even if the flag's value has not changed | 
 | 	if flag, exists := v.pflags[lcaseKey]; exists { | 
 | 		switch flag.ValueType() { | 
 | 		case "int", "int8", "int16", "int32", "int64": | 
 | 			return cast.ToInt(flag.ValueString()) | 
 | 		case "bool": | 
 | 			return cast.ToBool(flag.ValueString()) | 
 | 		case "stringSlice": | 
 | 			s := strings.TrimPrefix(flag.ValueString(), "[") | 
 | 			return strings.TrimSuffix(s, "]") | 
 | 		default: | 
 | 			return flag.ValueString() | 
 | 		} | 
 | 	} | 
 | 	// last item, no need to check shadowing | 
 |  | 
 | 	return nil | 
 | } | 
 |  | 
 | // IsSet checks to see if the key has been set in any of the data locations. | 
 | // IsSet is case-insensitive for a key. | 
 | func IsSet(key string) bool { return v.IsSet(key) } | 
 | func (v *Viper) IsSet(key string) bool { | 
 | 	lcaseKey := strings.ToLower(key) | 
 | 	val := v.find(lcaseKey) | 
 | 	return val != nil | 
 | } | 
 |  | 
 | // AutomaticEnv has Viper check ENV variables for all. | 
 | // keys set in config, default & flags | 
 | func AutomaticEnv() { v.AutomaticEnv() } | 
 | func (v *Viper) AutomaticEnv() { | 
 | 	v.automaticEnvApplied = true | 
 | } | 
 |  | 
 | // SetEnvKeyReplacer sets the strings.Replacer on the viper object | 
 | // Useful for mapping an environmental variable to a key that does | 
 | // not match it. | 
 | func SetEnvKeyReplacer(r *strings.Replacer) { v.SetEnvKeyReplacer(r) } | 
 | func (v *Viper) SetEnvKeyReplacer(r *strings.Replacer) { | 
 | 	v.envKeyReplacer = r | 
 | } | 
 |  | 
 | // Aliases provide another accessor for the same key. | 
 | // This enables one to change a name without breaking the application | 
 | func RegisterAlias(alias string, key string) { v.RegisterAlias(alias, key) } | 
 | func (v *Viper) RegisterAlias(alias string, key string) { | 
 | 	v.registerAlias(alias, strings.ToLower(key)) | 
 | } | 
 |  | 
 | func (v *Viper) registerAlias(alias string, key string) { | 
 | 	alias = strings.ToLower(alias) | 
 | 	if alias != key && alias != v.realKey(key) { | 
 | 		_, exists := v.aliases[alias] | 
 |  | 
 | 		if !exists { | 
 | 			// if we alias something that exists in one of the maps to another | 
 | 			// name, we'll never be able to get that value using the original | 
 | 			// name, so move the config value to the new realkey. | 
 | 			if val, ok := v.config[alias]; ok { | 
 | 				delete(v.config, alias) | 
 | 				v.config[key] = val | 
 | 			} | 
 | 			if val, ok := v.kvstore[alias]; ok { | 
 | 				delete(v.kvstore, alias) | 
 | 				v.kvstore[key] = val | 
 | 			} | 
 | 			if val, ok := v.defaults[alias]; ok { | 
 | 				delete(v.defaults, alias) | 
 | 				v.defaults[key] = val | 
 | 			} | 
 | 			if val, ok := v.override[alias]; ok { | 
 | 				delete(v.override, alias) | 
 | 				v.override[key] = val | 
 | 			} | 
 | 			v.aliases[alias] = key | 
 | 		} | 
 | 	} else { | 
 | 		jww.WARN.Println("Creating circular reference alias", alias, key, v.realKey(key)) | 
 | 	} | 
 | } | 
 |  | 
 | func (v *Viper) realKey(key string) string { | 
 | 	newkey, exists := v.aliases[key] | 
 | 	if exists { | 
 | 		jww.DEBUG.Println("Alias", key, "to", newkey) | 
 | 		return v.realKey(newkey) | 
 | 	} | 
 | 	return key | 
 | } | 
 |  | 
 | // InConfig checks to see if the given key (or an alias) is in the config file. | 
 | func InConfig(key string) bool { return v.InConfig(key) } | 
 | func (v *Viper) InConfig(key string) bool { | 
 | 	// if the requested key is an alias, then return the proper key | 
 | 	key = v.realKey(key) | 
 |  | 
 | 	_, exists := v.config[key] | 
 | 	return exists | 
 | } | 
 |  | 
 | // SetDefault sets the default value for this key. | 
 | // SetDefault is case-insensitive for a key. | 
 | // Default only used when no value is provided by the user via flag, config or ENV. | 
 | func SetDefault(key string, value interface{}) { v.SetDefault(key, value) } | 
 | func (v *Viper) SetDefault(key string, value interface{}) { | 
 | 	// If alias passed in, then set the proper default | 
 | 	key = v.realKey(strings.ToLower(key)) | 
 | 	value = toCaseInsensitiveValue(value) | 
 |  | 
 | 	path := strings.Split(key, v.keyDelim) | 
 | 	lastKey := strings.ToLower(path[len(path)-1]) | 
 | 	deepestMap := deepSearch(v.defaults, path[0:len(path)-1]) | 
 |  | 
 | 	// set innermost value | 
 | 	deepestMap[lastKey] = value | 
 | } | 
 |  | 
 | // Set sets the value for the key in the override regiser. | 
 | // Set is case-insensitive for a key. | 
 | // Will be used instead of values obtained via | 
 | // flags, config file, ENV, default, or key/value store. | 
 | func Set(key string, value interface{}) { v.Set(key, value) } | 
 | func (v *Viper) Set(key string, value interface{}) { | 
 | 	// If alias passed in, then set the proper override | 
 | 	key = v.realKey(strings.ToLower(key)) | 
 | 	value = toCaseInsensitiveValue(value) | 
 |  | 
 | 	path := strings.Split(key, v.keyDelim) | 
 | 	lastKey := strings.ToLower(path[len(path)-1]) | 
 | 	deepestMap := deepSearch(v.override, path[0:len(path)-1]) | 
 |  | 
 | 	// set innermost value | 
 | 	deepestMap[lastKey] = value | 
 | } | 
 |  | 
 | // ReadInConfig will discover and load the configuration file from disk | 
 | // and key/value stores, searching in one of the defined paths. | 
 | func ReadInConfig() error { return v.ReadInConfig() } | 
 | func (v *Viper) ReadInConfig() error { | 
 | 	jww.INFO.Println("Attempting to read in config file") | 
 | 	filename, err := v.getConfigFile() | 
 | 	if err != nil { | 
 | 		return err | 
 | 	} | 
 |  | 
 | 	if !stringInSlice(v.getConfigType(), SupportedExts) { | 
 | 		return UnsupportedConfigError(v.getConfigType()) | 
 | 	} | 
 |  | 
 | 	file, err := afero.ReadFile(v.fs, filename) | 
 | 	if err != nil { | 
 | 		return err | 
 | 	} | 
 |  | 
 | 	v.config = make(map[string]interface{}) | 
 |  | 
 | 	return v.unmarshalReader(bytes.NewReader(file), v.config) | 
 | } | 
 |  | 
 | // MergeInConfig merges a new configuration with an existing config. | 
 | func MergeInConfig() error { return v.MergeInConfig() } | 
 | func (v *Viper) MergeInConfig() error { | 
 | 	jww.INFO.Println("Attempting to merge in config file") | 
 | 	filename, err := v.getConfigFile() | 
 | 	if err != nil { | 
 | 		return err | 
 | 	} | 
 |  | 
 | 	if !stringInSlice(v.getConfigType(), SupportedExts) { | 
 | 		return UnsupportedConfigError(v.getConfigType()) | 
 | 	} | 
 |  | 
 | 	file, err := afero.ReadFile(v.fs, filename) | 
 | 	if err != nil { | 
 | 		return err | 
 | 	} | 
 |  | 
 | 	return v.MergeConfig(bytes.NewReader(file)) | 
 | } | 
 |  | 
 | // ReadConfig will read a configuration file, setting existing keys to nil if the | 
 | // key does not exist in the file. | 
 | func ReadConfig(in io.Reader) error { return v.ReadConfig(in) } | 
 | func (v *Viper) ReadConfig(in io.Reader) error { | 
 | 	v.config = make(map[string]interface{}) | 
 | 	return v.unmarshalReader(in, v.config) | 
 | } | 
 |  | 
 | // MergeConfig merges a new configuration with an existing config. | 
 | func MergeConfig(in io.Reader) error { return v.MergeConfig(in) } | 
 | func (v *Viper) MergeConfig(in io.Reader) error { | 
 | 	if v.config == nil { | 
 | 		v.config = make(map[string]interface{}) | 
 | 	} | 
 | 	cfg := make(map[string]interface{}) | 
 | 	if err := v.unmarshalReader(in, cfg); err != nil { | 
 | 		return err | 
 | 	} | 
 | 	mergeMaps(cfg, v.config, nil) | 
 | 	return nil | 
 | } | 
 |  | 
 | func keyExists(k string, m map[string]interface{}) string { | 
 | 	lk := strings.ToLower(k) | 
 | 	for mk := range m { | 
 | 		lmk := strings.ToLower(mk) | 
 | 		if lmk == lk { | 
 | 			return mk | 
 | 		} | 
 | 	} | 
 | 	return "" | 
 | } | 
 |  | 
 | func castToMapStringInterface( | 
 | 	src map[interface{}]interface{}) map[string]interface{} { | 
 | 	tgt := map[string]interface{}{} | 
 | 	for k, v := range src { | 
 | 		tgt[fmt.Sprintf("%v", k)] = v | 
 | 	} | 
 | 	return tgt | 
 | } | 
 |  | 
 | func castMapStringToMapInterface(src map[string]string) map[string]interface{} { | 
 | 	tgt := map[string]interface{}{} | 
 | 	for k, v := range src { | 
 | 		tgt[k] = v | 
 | 	} | 
 | 	return tgt | 
 | } | 
 |  | 
 | func castMapFlagToMapInterface(src map[string]FlagValue) map[string]interface{} { | 
 | 	tgt := map[string]interface{}{} | 
 | 	for k, v := range src { | 
 | 		tgt[k] = v | 
 | 	} | 
 | 	return tgt | 
 | } | 
 |  | 
 | // mergeMaps merges two maps. The `itgt` parameter is for handling go-yaml's | 
 | // insistence on parsing nested structures as `map[interface{}]interface{}` | 
 | // instead of using a `string` as the key for nest structures beyond one level | 
 | // deep. Both map types are supported as there is a go-yaml fork that uses | 
 | // `map[string]interface{}` instead. | 
 | func mergeMaps( | 
 | 	src, tgt map[string]interface{}, itgt map[interface{}]interface{}) { | 
 | 	for sk, sv := range src { | 
 | 		tk := keyExists(sk, tgt) | 
 | 		if tk == "" { | 
 | 			jww.TRACE.Printf("tk=\"\", tgt[%s]=%v", sk, sv) | 
 | 			tgt[sk] = sv | 
 | 			if itgt != nil { | 
 | 				itgt[sk] = sv | 
 | 			} | 
 | 			continue | 
 | 		} | 
 |  | 
 | 		tv, ok := tgt[tk] | 
 | 		if !ok { | 
 | 			jww.TRACE.Printf("tgt[%s] != ok, tgt[%s]=%v", tk, sk, sv) | 
 | 			tgt[sk] = sv | 
 | 			if itgt != nil { | 
 | 				itgt[sk] = sv | 
 | 			} | 
 | 			continue | 
 | 		} | 
 |  | 
 | 		svType := reflect.TypeOf(sv) | 
 | 		tvType := reflect.TypeOf(tv) | 
 | 		if svType != tvType { | 
 | 			jww.ERROR.Printf( | 
 | 				"svType != tvType; key=%s, st=%v, tt=%v, sv=%v, tv=%v", | 
 | 				sk, svType, tvType, sv, tv) | 
 | 			continue | 
 | 		} | 
 |  | 
 | 		jww.TRACE.Printf("processing key=%s, st=%v, tt=%v, sv=%v, tv=%v", | 
 | 			sk, svType, tvType, sv, tv) | 
 |  | 
 | 		switch ttv := tv.(type) { | 
 | 		case map[interface{}]interface{}: | 
 | 			jww.TRACE.Printf("merging maps (must convert)") | 
 | 			tsv := sv.(map[interface{}]interface{}) | 
 | 			ssv := castToMapStringInterface(tsv) | 
 | 			stv := castToMapStringInterface(ttv) | 
 | 			mergeMaps(ssv, stv, ttv) | 
 | 		case map[string]interface{}: | 
 | 			jww.TRACE.Printf("merging maps") | 
 | 			mergeMaps(sv.(map[string]interface{}), ttv, nil) | 
 | 		default: | 
 | 			jww.TRACE.Printf("setting value") | 
 | 			tgt[tk] = sv | 
 | 			if itgt != nil { | 
 | 				itgt[tk] = sv | 
 | 			} | 
 | 		} | 
 | 	} | 
 | } | 
 |  | 
 | // ReadRemoteConfig attempts to get configuration from a remote source | 
 | // and read it in the remote configuration registry. | 
 | func ReadRemoteConfig() error { return v.ReadRemoteConfig() } | 
 | func (v *Viper) ReadRemoteConfig() error { | 
 | 	return v.getKeyValueConfig() | 
 | } | 
 |  | 
 | func WatchRemoteConfig() error { return v.WatchRemoteConfig() } | 
 | func (v *Viper) WatchRemoteConfig() error { | 
 | 	return v.watchKeyValueConfig() | 
 | } | 
 |  | 
 | // Unmarshall a Reader into a map. | 
 | // Should probably be an unexported function. | 
 | func unmarshalReader(in io.Reader, c map[string]interface{}) error { | 
 | 	return v.unmarshalReader(in, c) | 
 | } | 
 |  | 
 | func (v *Viper) unmarshalReader(in io.Reader, c map[string]interface{}) error { | 
 | 	return unmarshallConfigReader(in, c, v.getConfigType()) | 
 | } | 
 |  | 
 | func (v *Viper) insensitiviseMaps() { | 
 | 	insensitiviseMap(v.config) | 
 | 	insensitiviseMap(v.defaults) | 
 | 	insensitiviseMap(v.override) | 
 | 	insensitiviseMap(v.kvstore) | 
 | } | 
 |  | 
 | // Retrieve the first found remote configuration. | 
 | func (v *Viper) getKeyValueConfig() error { | 
 | 	if RemoteConfig == nil { | 
 | 		return RemoteConfigError("Enable the remote features by doing a blank import of the viper/remote package: '_ github.com/spf13/viper/remote'") | 
 | 	} | 
 |  | 
 | 	for _, rp := range v.remoteProviders { | 
 | 		val, err := v.getRemoteConfig(rp) | 
 | 		if err != nil { | 
 | 			continue | 
 | 		} | 
 | 		v.kvstore = val | 
 | 		return nil | 
 | 	} | 
 | 	return RemoteConfigError("No Files Found") | 
 | } | 
 |  | 
 | func (v *Viper) getRemoteConfig(provider RemoteProvider) (map[string]interface{}, error) { | 
 | 	reader, err := RemoteConfig.Get(provider) | 
 | 	if err != nil { | 
 | 		return nil, err | 
 | 	} | 
 | 	err = v.unmarshalReader(reader, v.kvstore) | 
 | 	return v.kvstore, err | 
 | } | 
 |  | 
 | // Retrieve the first found remote configuration. | 
 | func (v *Viper) watchKeyValueConfig() error { | 
 | 	for _, rp := range v.remoteProviders { | 
 | 		val, err := v.watchRemoteConfig(rp) | 
 | 		if err != nil { | 
 | 			continue | 
 | 		} | 
 | 		v.kvstore = val | 
 | 		return nil | 
 | 	} | 
 | 	return RemoteConfigError("No Files Found") | 
 | } | 
 |  | 
 | func (v *Viper) watchRemoteConfig(provider RemoteProvider) (map[string]interface{}, error) { | 
 | 	reader, err := RemoteConfig.Watch(provider) | 
 | 	if err != nil { | 
 | 		return nil, err | 
 | 	} | 
 | 	err = v.unmarshalReader(reader, v.kvstore) | 
 | 	return v.kvstore, err | 
 | } | 
 |  | 
 | // AllKeys returns all keys holding a value, regardless of where they are set. | 
 | // Nested keys are returned with a v.keyDelim (= ".") separator | 
 | func AllKeys() []string { return v.AllKeys() } | 
 | func (v *Viper) AllKeys() []string { | 
 | 	m := map[string]bool{} | 
 | 	// add all paths, by order of descending priority to ensure correct shadowing | 
 | 	m = v.flattenAndMergeMap(m, castMapStringToMapInterface(v.aliases), "") | 
 | 	m = v.flattenAndMergeMap(m, v.override, "") | 
 | 	m = v.mergeFlatMap(m, castMapFlagToMapInterface(v.pflags)) | 
 | 	m = v.mergeFlatMap(m, castMapStringToMapInterface(v.env)) | 
 | 	m = v.flattenAndMergeMap(m, v.config, "") | 
 | 	m = v.flattenAndMergeMap(m, v.kvstore, "") | 
 | 	m = v.flattenAndMergeMap(m, v.defaults, "") | 
 |  | 
 | 	// convert set of paths to list | 
 | 	a := []string{} | 
 | 	for x := range m { | 
 | 		a = append(a, x) | 
 | 	} | 
 | 	return a | 
 | } | 
 |  | 
 | // flattenAndMergeMap recursively flattens the given map into a map[string]bool | 
 | // of key paths (used as a set, easier to manipulate than a []string): | 
 | // - each path is merged into a single key string, delimited with v.keyDelim (= ".") | 
 | // - if a path is shadowed by an earlier value in the initial shadow map, | 
 | //   it is skipped. | 
 | // The resulting set of paths is merged to the given shadow set at the same time. | 
 | func (v *Viper) flattenAndMergeMap(shadow map[string]bool, m map[string]interface{}, prefix string) map[string]bool { | 
 | 	if shadow != nil && prefix != "" && shadow[prefix] { | 
 | 		// prefix is shadowed => nothing more to flatten | 
 | 		return shadow | 
 | 	} | 
 | 	if shadow == nil { | 
 | 		shadow = make(map[string]bool) | 
 | 	} | 
 |  | 
 | 	var m2 map[string]interface{} | 
 | 	if prefix != "" { | 
 | 		prefix += v.keyDelim | 
 | 	} | 
 | 	for k, val := range m { | 
 | 		fullKey := prefix + k | 
 | 		switch val.(type) { | 
 | 		case map[string]interface{}: | 
 | 			m2 = val.(map[string]interface{}) | 
 | 		case map[interface{}]interface{}: | 
 | 			m2 = cast.ToStringMap(val) | 
 | 		default: | 
 | 			// immediate value | 
 | 			shadow[strings.ToLower(fullKey)] = true | 
 | 			continue | 
 | 		} | 
 | 		// recursively merge to shadow map | 
 | 		shadow = v.flattenAndMergeMap(shadow, m2, fullKey) | 
 | 	} | 
 | 	return shadow | 
 | } | 
 |  | 
 | // mergeFlatMap merges the given maps, excluding values of the second map | 
 | // shadowed by values from the first map. | 
 | func (v *Viper) mergeFlatMap(shadow map[string]bool, m map[string]interface{}) map[string]bool { | 
 | 	// scan keys | 
 | outer: | 
 | 	for k, _ := range m { | 
 | 		path := strings.Split(k, v.keyDelim) | 
 | 		// scan intermediate paths | 
 | 		var parentKey string | 
 | 		for i := 1; i < len(path); i++ { | 
 | 			parentKey = strings.Join(path[0:i], v.keyDelim) | 
 | 			if shadow[parentKey] { | 
 | 				// path is shadowed, continue | 
 | 				continue outer | 
 | 			} | 
 | 		} | 
 | 		// add key | 
 | 		shadow[strings.ToLower(k)] = true | 
 | 	} | 
 | 	return shadow | 
 | } | 
 |  | 
 | // AllSettings merges all settings and returns them as a map[string]interface{}. | 
 | func AllSettings() map[string]interface{} { return v.AllSettings() } | 
 | func (v *Viper) AllSettings() map[string]interface{} { | 
 | 	m := map[string]interface{}{} | 
 | 	// start from the list of keys, and construct the map one value at a time | 
 | 	for _, k := range v.AllKeys() { | 
 | 		value := v.Get(k) | 
 | 		if value == nil { | 
 | 			// should not happen, since AllKeys() returns only keys holding a value, | 
 | 			// check just in case anything changes | 
 | 			continue | 
 | 		} | 
 | 		path := strings.Split(k, v.keyDelim) | 
 | 		lastKey := strings.ToLower(path[len(path)-1]) | 
 | 		deepestMap := deepSearch(m, path[0:len(path)-1]) | 
 | 		// set innermost value | 
 | 		deepestMap[lastKey] = value | 
 | 	} | 
 | 	return m | 
 | } | 
 |  | 
 | // SetFs sets the filesystem to use to read configuration. | 
 | func SetFs(fs afero.Fs) { v.SetFs(fs) } | 
 | func (v *Viper) SetFs(fs afero.Fs) { | 
 | 	v.fs = fs | 
 | } | 
 |  | 
 | // SetConfigName sets name for the config file. | 
 | // Does not include extension. | 
 | func SetConfigName(in string) { v.SetConfigName(in) } | 
 | func (v *Viper) SetConfigName(in string) { | 
 | 	if in != "" { | 
 | 		v.configName = in | 
 | 		v.configFile = "" | 
 | 	} | 
 | } | 
 |  | 
 | // SetConfigType sets the type of the configuration returned by the | 
 | // remote source, e.g. "json". | 
 | func SetConfigType(in string) { v.SetConfigType(in) } | 
 | func (v *Viper) SetConfigType(in string) { | 
 | 	if in != "" { | 
 | 		v.configType = in | 
 | 	} | 
 | } | 
 |  | 
 | func (v *Viper) getConfigType() string { | 
 | 	if v.configType != "" { | 
 | 		return v.configType | 
 | 	} | 
 |  | 
 | 	cf, err := v.getConfigFile() | 
 | 	if err != nil { | 
 | 		return "" | 
 | 	} | 
 |  | 
 | 	ext := filepath.Ext(cf) | 
 |  | 
 | 	if len(ext) > 1 { | 
 | 		return ext[1:] | 
 | 	} | 
 |  | 
 | 	return "" | 
 | } | 
 |  | 
 | func (v *Viper) getConfigFile() (string, error) { | 
 | 	// if explicitly set, then use it | 
 | 	if v.configFile != "" { | 
 | 		return v.configFile, nil | 
 | 	} | 
 |  | 
 | 	cf, err := v.findConfigFile() | 
 | 	if err != nil { | 
 | 		return "", err | 
 | 	} | 
 |  | 
 | 	v.configFile = cf | 
 | 	return v.getConfigFile() | 
 | } | 
 |  | 
 | func (v *Viper) searchInPath(in string) (filename string) { | 
 | 	jww.DEBUG.Println("Searching for config in ", in) | 
 | 	for _, ext := range SupportedExts { | 
 | 		jww.DEBUG.Println("Checking for", filepath.Join(in, v.configName+"."+ext)) | 
 | 		if b, _ := exists(filepath.Join(in, v.configName+"."+ext)); b { | 
 | 			jww.DEBUG.Println("Found: ", filepath.Join(in, v.configName+"."+ext)) | 
 | 			return filepath.Join(in, v.configName+"."+ext) | 
 | 		} | 
 | 	} | 
 |  | 
 | 	return "" | 
 | } | 
 |  | 
 | // Search all configPaths for any config file. | 
 | // Returns the first path that exists (and is a config file). | 
 | func (v *Viper) findConfigFile() (string, error) { | 
 |  | 
 | 	jww.INFO.Println("Searching for config in ", v.configPaths) | 
 |  | 
 | 	for _, cp := range v.configPaths { | 
 | 		file := v.searchInPath(cp) | 
 | 		if file != "" { | 
 | 			return file, nil | 
 | 		} | 
 | 	} | 
 | 	return "", ConfigFileNotFoundError{v.configName, fmt.Sprintf("%s", v.configPaths)} | 
 | } | 
 |  | 
 | // Debug prints all configuration registries for debugging | 
 | // purposes. | 
 | func Debug() { v.Debug() } | 
 | func (v *Viper) Debug() { | 
 | 	fmt.Printf("Aliases:\n%#v\n", v.aliases) | 
 | 	fmt.Printf("Override:\n%#v\n", v.override) | 
 | 	fmt.Printf("PFlags:\n%#v\n", v.pflags) | 
 | 	fmt.Printf("Env:\n%#v\n", v.env) | 
 | 	fmt.Printf("Key/Value Store:\n%#v\n", v.kvstore) | 
 | 	fmt.Printf("Config:\n%#v\n", v.config) | 
 | 	fmt.Printf("Defaults:\n%#v\n", v.defaults) | 
 | } |