func (yc *YCfg) Delete(key string) {
	delete(yc.tree, key)
}
Delete deletes all entries with the specified key.
package ycfg
import (
	"fmt"
	"strings"
	"github.com/spf13/cast"
	"mynewt.apache.org/newt/newt/parse"
	"mynewt.apache.org/newt/util"
	"mynewt.apache.org/newt/yaml"
)
type YCfg struct {
	name string
	tree YCfgTree
}
type YCfgEntry struct {
	Value interface{}
	Expr  *parse.Node
}
type YCfgNode struct {
	Overwrite bool
	Name      string
	Value     interface{}
	Children  YCfgTree
	Parent    *YCfgNode
	FileInfo  *util.FileInfo
}
type YCfgTree map[string]*YCfgNode
func (yc *YCfg) Tree() YCfgTree {
	return yc.tree
}
func NewYCfgNode() *YCfgNode {
	return &YCfgNode{Children: YCfgTree{}}
}
func (node *YCfgNode) addChild(name string) (*YCfgNode, error) {
	if node.Children == nil {
		node.Children = YCfgTree{}
	}
	if node.Children[name] != nil {
		return nil, fmt.Errorf("Duplicate YCfgNode: %s", name)
	}
	child := NewYCfgNode()
	child.Name = name
	child.Parent = node
	node.Children[name] = child
	return child, nil
}
func (yc *YCfg) ReplaceFromFile(key string, val interface{},
	fileInfo *util.FileInfo) error {
	elems := strings.Split(key, ".")
	if len(elems) == 0 {
		return fmt.Errorf("Invalid ycfg key: \"\"")
	}
	var overwrite bool
	if elems[len(elems)-1] == "OVERWRITE" {
		overwrite = true
		elems = elems[:len(elems)-1]
	}
	var parent *YCfgNode
	for i, e := range elems {
		var parentChildren YCfgTree
		if parent == nil {
			parentChildren = yc.tree
		} else {
			if parent.Children == nil {
				parent.Children = YCfgTree{}
			}
			parentChildren = parent.Children
		}
		child := parentChildren[e]
		if child == nil {
			var err error
			if parent != nil {
				child, err = parent.addChild(e)
				if err != nil {
					return err
				}
			} else {
				child = NewYCfgNode()
				child.Name = e
				parentChildren[e] = child
			}
		}
		if i == len(elems)-1 {
			child.Overwrite = overwrite
			child.Value = val
		}
		child.FileInfo = fileInfo
		parent = child
	}
	return nil
}
func (yc *YCfg) MergeFromFile(key string, val interface{},
	fileInfo *util.FileInfo) error {
	node := yc.find(key)
	if node == nil || node.Value == nil {
		return yc.ReplaceFromFile(key, val, fileInfo)
	}
	if s, ok := val.(string); ok && s == "" {
		val = nil
	}
	if val == nil {
		return nil
	}
	mergeErr := func() error {
		return util.FmtNewtError(
			"can't merge type %T into cfg node \"%s\"; node type: %T",
			val, key, node.Value)
	}
	switch nodeVal := node.Value.(type) {
	case map[interface{}]interface{}:
		newVal, ok := val.(map[interface{}]interface{})
		if !ok {
			return mergeErr()
		}
		for k, v := range newVal {
			nodeVal[k] = v
		}
	case []interface{}:
		newVal, ok := val.([]interface{})
		if !ok {
			return mergeErr()
		}
		node.Value = append(nodeVal, newVal...)
	default:
		return mergeErr()
	}
	return nil
}
func (yc *YCfg) Replace(key string, val interface{}) error {
	return yc.ReplaceFromFile(key, val, nil)
}
func NewYCfg(name string) YCfg {
	return YCfg{
		name: name,
		tree: YCfgTree{},
	}
}
func (yc *YCfg) find(key string) *YCfgNode {
	elems := strings.Split(key, ".")
	if len(elems) == 0 {
		return nil
	}
	cur := &YCfgNode{
		Children: yc.tree,
	}
	for _, e := range elems {
		if cur.Children == nil {
			return nil
		}
		cur = cur.Children[e]
		if cur == nil {
			return nil
		}
	}
	return cur
}
func (yc *YCfg) HasKey(key string) bool {
	return yc.find(key) != nil
}
func (yc *YCfg) Get(key string,
	settings map[string]string) ([]YCfgEntry, error) {
	node := yc.find(key)
	if node == nil {
		return nil, nil
	}
	entries := []YCfgEntry{}
	if node.Value != nil {
		entry := YCfgEntry{Value: node.Value}
		entries = append(entries, entry)
	}
	var errLines []string
	for _, child := range node.Children {
		expr, err := parse.LexAndParse(child.Name)
		if err != nil {
			errLines = append(errLines,
				fmt.Sprintf("%s: %s", yc.name, err.Error()))
			continue
		}
		val, err := parse.Eval(expr, settings)
		if err != nil {
			errLines = append(errLines,
				fmt.Sprintf("%s: %s", yc.name, err.Error()))
			continue
		}
		if val {
			entry := YCfgEntry{
				Value: child.Value,
				Expr:  expr,
			}
			if child.Overwrite {
				entries = []YCfgEntry{entry}
				break
			}
			entries = append(entries, entry)
		}
	}
	if len(errLines) > 0 {
		return entries, util.NewNewtError(strings.Join(errLines, "\n"))
	} else {
		return entries, nil
	}
}
func (yc *YCfg) GetSlice(key string, settings map[string]string) ([]YCfgEntry, error) {
	sliceEntries, getErr := yc.Get(key, settings)
	if len(sliceEntries) == 0 {
		return nil, getErr
	}
	result := []YCfgEntry{}
	for _, sliceEntry := range sliceEntries {
		if sliceEntry.Value != nil {
			slice, err := cast.ToSliceE(sliceEntry.Value)
			if err != nil {
				slice = []interface{}{sliceEntry.Value}
			}
			for _, v := range slice {
				entry := YCfgEntry{
					Value: v,
					Expr:  sliceEntry.Expr,
				}
				result = append(result, entry)
			}
		}
	}
	return result, getErr
}
func (yc *YCfg) GetValSlice(
	key string, settings map[string]string) ([]interface{}, error) {
	entries, getErr := yc.GetSlice(key, settings)
	if len(entries) == 0 {
		return nil, getErr
	}
	vals := make([]interface{}, len(entries))
	for i, e := range entries {
		vals[i] = e.Value
	}
	return vals, getErr
}
func (yc *YCfg) GetStringSlice(key string,
	settings map[string]string) ([]YCfgEntry, error) {
	sliceEntries, getErr := yc.Get(key, settings)
	if len(sliceEntries) == 0 {
		return nil, getErr
	}
	result := []YCfgEntry{}
	for _, sliceEntry := range sliceEntries {
		if sliceEntry.Value != nil {
			slice, err := cast.ToStringSliceE(sliceEntry.Value)
			if err != nil {
				slice = []string{cast.ToString(sliceEntry.Value)}
			}
			for _, v := range slice {
				entry := YCfgEntry{
					Value: v,
					Expr:  sliceEntry.Expr,
				}
				result = append(result, entry)
			}
		}
	}
	return result, getErr
}
func (yc *YCfg) GetValStringSlice(
	key string, settings map[string]string) ([]string, error) {
	entries, getErr := yc.GetStringSlice(key, settings)
	if len(entries) == 0 {
		return nil, getErr
	}
	vals := make([]string, len(entries))
	for i, e := range entries {
		if e.Value != nil {
			vals[i] = cast.ToString(e.Value)
		}
	}
	return vals, getErr
}
func (yc *YCfg) GetValStringSliceNonempty(
	key string, settings map[string]string) ([]string, error) {
	strs, getErr := yc.GetValStringSlice(key, settings)
	filtered := make([]string, 0, len(strs))
	for _, s := range strs {
		if s != "" {
			filtered = append(filtered, s)
		}
	}
	return filtered, getErr
}
func (yc *YCfg) GetStringMap(
	key string, settings map[string]string) (map[string]YCfgEntry, error) {
	mapEntries, getErr := yc.Get(key, settings)
	if len(mapEntries) == 0 {
		return nil, getErr
	}
	result := map[string]YCfgEntry{}
	for _, mapEntry := range mapEntries {
		for k, v := range cast.ToStringMap(mapEntry.Value) {
			entry := YCfgEntry{
				Value: v,
				Expr:  mapEntry.Expr,
			}
			result[k] = entry
		}
	}
	return result, getErr
}
func (yc *YCfg) GetValStringMap(
	key string, settings map[string]string) (map[string]interface{}, error) {
	entryMap, getErr := yc.GetStringMap(key, settings)
	smap := make(map[string]interface{}, len(entryMap))
	for k, v := range entryMap {
		if v.Value != nil {
			smap[k] = v.Value
		}
	}
	return smap, getErr
}
func (yc *YCfg) GetFirst(key string,
	settings map[string]string) (YCfgEntry, bool, error) {
	entries, getErr := yc.Get(key, settings)
	if len(entries) == 0 {
		return YCfgEntry{}, false, getErr
	}
	return entries[0], true, getErr
}
func (yc *YCfg) GetFirstVal(key string,
	settings map[string]string) (interface{}, error) {
	entry, ok, getErr := yc.GetFirst(key, settings)
	if !ok {
		return nil, getErr
	}
	return entry.Value, getErr
}
func (yc *YCfg) GetValString(key string,
	settings map[string]string) (string, error) {
	entry, ok, getErr := yc.GetFirst(key, settings)
	if !ok {
		return "", getErr
	} else {
		return cast.ToString(entry.Value), getErr
	}
}
func (yc *YCfg) GetValInt(key string, settings map[string]string) (int, error) {
	entry, ok, getErr := yc.GetFirst(key, settings)
	if !ok {
		return 0, getErr
	} else {
		return cast.ToInt(entry.Value), getErr
	}
}
func (yc *YCfg) GetValBoolDflt(key string, settings map[string]string,
	dflt bool) (bool, error) {
	entry, ok, getErr := yc.GetFirst(key, settings)
	if !ok {
		return dflt, getErr
	} else {
		return cast.ToBool(entry.Value), getErr
	}
}
func (yc *YCfg) GetValBool(key string,
	settings map[string]string) (bool, error) {
	return yc.GetValBoolDflt(key, settings, false)
}
func (yc *YCfg) GetStringMapString(key string,
	settings map[string]string) (map[string]YCfgEntry, error) {
	mapEntries, getErr := yc.Get(key, settings)
	if len(mapEntries) == 0 {
		return nil, getErr
	}
	result := map[string]YCfgEntry{}
	for _, mapEntry := range mapEntries {
		for k, v := range cast.ToStringMapString(mapEntry.Value) {
			entry := YCfgEntry{
				Value: v,
				Expr:  mapEntry.Expr,
			}
			result[k] = entry
		}
	}
	return result, getErr
}
func (yc *YCfg) GetValStringMapString(key string,
	settings map[string]string) (map[string]string, error) {
	entryMap, getErr := yc.GetStringMapString(key, settings)
	valMap := make(map[string]string, len(entryMap))
	for k, v := range entryMap {
		if v.Value != nil {
			valMap[k] = cast.ToString(v.Value)
		}
	}
	return valMap, getErr
}
func (node *YCfgNode) FullName() string {
	tokens := []string{}
	for n := node; n != nil; n = n.Parent {
		tokens = append(tokens, n.Name)
	}
	last := len(tokens) - 1
	for i := 0; i < len(tokens)/2; i++ {
		tokens[i], tokens[last-i] = tokens[last-i], tokens[i]
	}
	return strings.Join(tokens, ".")
}