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
}
GetStringSlice retrieves all entries with the specified key and coerces
their values to type []string.  The returned []YCfgEntry is formed from the
union of all these slices.  The returned error is a set of warnings just as
in `Get`.
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
}