func coalesceGlobals(dest, src map[string]interface{}, chartName string) map[string]interface{} {
	var dg, sg map[string]interface{}
	if destglob, ok := dest[GlobalKey]; !ok {
		dg = map[string]interface{}{}
	} else if dg, ok = destglob.(map[string]interface{}); !ok {
		log.Printf("Warning: Skipping globals for chart '%s' because destination '%s' is not a table.", chartName, GlobalKey)
		return dg
	}
	if srcglob, ok := src[GlobalKey]; !ok {
		sg = map[string]interface{}{}
	} else if sg, ok = srcglob.(map[string]interface{}); !ok {
		log.Printf("Warning: skipping globals for chart '%s' because source '%s' is not a table.", chartName, GlobalKey)
		return dg
	}
	rv := make(map[string]interface{})
	for k, v := range dest {
		rv[k] = v
	}
	rv[GlobalKey] = coalesceTables(sg, dg, chartName)
	return rv
}
coalesceGlobals copies the globals out of src and merges them into dest.

For convenience, returns dest.
package chartutil
import (
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"strings"
	"github.com/ghodss/yaml"
	"github.com/golang/protobuf/ptypes/timestamp"
	"k8s.io/helm/pkg/proto/hapi/chart"
)
type ErrNoTable error
type ErrNoValue error
const GlobalKey = "global"
type Values map[string]interface{}
func (v Values) YAML() (string, error) {
	b, err := yaml.Marshal(v)
	return string(b), err
}
func (v Values) Table(name string) (Values, error) {
	names := strings.Split(name, ".")
	table := v
	var err error
	for _, n := range names {
		table, err = tableLookup(table, n)
		if err != nil {
			return table, err
		}
	}
	return table, err
}
func (v Values) AsMap() map[string]interface{} {
	if v == nil || len(v) == 0 {
		return map[string]interface{}{}
	}
	return v
}
func (v Values) Encode(w io.Writer) error {
	out, err := yaml.Marshal(v)
	if err != nil {
		return err
	}
	_, err = w.Write(out)
	return err
}
func (v Values) MergeInto(src Values) {
	for key, srcVal := range src {
		destVal, found := v[key]
		if found && istable(srcVal) && istable(destVal) {
			destMap := destVal.(map[string]interface{})
			srcMap := srcVal.(map[string]interface{})
			Values(destMap).MergeInto(Values(srcMap))
		} else {
			v[key] = srcVal
		}
	}
}
func tableLookup(v Values, simple string) (Values, error) {
	v2, ok := v[simple]
	if !ok {
		return v, ErrNoTable(fmt.Errorf("no table named %q (%v)", simple, v))
	}
	if vv, ok := v2.(map[string]interface{}); ok {
		return vv, nil
	}
	if vv, ok := v2.(Values); ok {
		return vv, nil
	}
	var e ErrNoTable = fmt.Errorf("no table named %q", simple)
	return map[string]interface{}{}, e
}
func ReadValues(data []byte) (vals Values, err error) {
	err = yaml.Unmarshal(data, &vals)
	if len(vals) == 0 {
		vals = Values{}
	}
	return
}
func ReadValuesFile(filename string) (Values, error) {
	data, err := ioutil.ReadFile(filename)
	if err != nil {
		return map[string]interface{}{}, err
	}
	return ReadValues(data)
}
func CoalesceValues(chrt *chart.Chart, vals *chart.Config) (Values, error) {
	cvals := Values{}
	if vals != nil {
		evals, err := ReadValues([]byte(vals.Raw))
		if err != nil {
			return cvals, err
		}
		return coalesce(chrt, evals)
	}
	return coalesceDeps(chrt, cvals)
}
func coalesce(ch *chart.Chart, dest map[string]interface{}) (map[string]interface{}, error) {
	var err error
	dest, err = coalesceValues(ch, dest)
	if err != nil {
		return dest, err
	}
	return coalesceDeps(ch, dest)
}
func coalesceDeps(chrt *chart.Chart, dest map[string]interface{}) (map[string]interface{}, error) {
	for _, subchart := range chrt.Dependencies {
		if c, ok := dest[subchart.Metadata.Name]; !ok {
			dest[subchart.Metadata.Name] = map[string]interface{}{}
		} else if !istable(c) {
			return dest, fmt.Errorf("type mismatch on %s: %t", subchart.Metadata.Name, c)
		}
		if dv, ok := dest[subchart.Metadata.Name]; ok {
			dvmap := dv.(map[string]interface{})
			dvmap = coalesceGlobals(dvmap, dest, chrt.Metadata.Name)
			var err error
			dest[subchart.Metadata.Name], err = coalesce(subchart, dvmap)
			if err != nil {
				return dest, err
			}
		}
	}
	return dest, nil
}