func interpret(values interface{}) (image.Ref, ImageSetter, bool) {
	switch m := values.(type) {
	case map[string]interface{}:
		return interpretAsContainer(stringMap(m))
	case map[interface{}]interface{}:
		return interpretAsContainer(anyMap(m))
	}
	return image.Ref{}, nil, false
}
interpret gets a value which may contain a description of an image.
package resource
import (
	"fmt"
	"github.com/Jeffail/gabs"
	"sort"
	"strings"
	"github.com/fluxcd/flux/pkg/image"
	"github.com/fluxcd/flux/pkg/resource"
)
const (
	ReleaseContainerName = "chart-image"
	ImageBasePath = "spec.values."
	ImageRegistryPrefix = "registry.fluxcd.io/"
	ImageRepositoryPrefix = "repository.fluxcd.io/"
	ImageTagPrefix = "tag.fluxcd.io/"
)
type ContainerImageMap struct {
	BasePath   string
	Registry   string
	Repository string
	Tag        string
}
func (c ContainerImageMap) RepositoryOnly() bool {
	return c.Repository != "" && c.Registry == "" && c.Tag == ""
}
func (c ContainerImageMap) RepositoryTag() bool {
	return c.Repository != "" && c.Tag != "" && c.Registry == ""
}
func (c ContainerImageMap) RegistryRepository() bool {
	return c.Registry != "" && c.Repository != "" && c.Tag == ""
}
func (c ContainerImageMap) AllDefined() bool {
	return c.Registry != "" && c.Repository != "" && c.Tag != ""
}
func (c ContainerImageMap) GetRegistry() string {
	if c.Registry == "" {
		return c.Registry
	}
	return fmt.Sprintf("%s%s", c.BasePath, c.Registry)
}
func (c ContainerImageMap) GetRepository() string {
	if c.Repository == "" {
		return c.Repository
	}
	return fmt.Sprintf("%s%s", c.BasePath, c.Repository)
}
func (c ContainerImageMap) GetTag() string {
	if c.Tag == "" {
		return c.Tag
	}
	return fmt.Sprintf("%s%s", c.BasePath, c.Tag)
}
func (c ContainerImageMap) MapImageRef(image image.Ref) (map[string]string, bool) {
	m := make(map[string]string)
	switch {
	case c.AllDefined():
		m[c.GetRegistry()] = image.Domain
		m[c.GetRepository()] = image.Image
		m[c.GetTag()] = image.Tag
	case c.RegistryRepository():
		m[c.GetRegistry()] = image.Domain
		m[c.GetRepository()] = image.Image + ":" + image.Tag
	case c.RepositoryTag():
		m[c.GetRepository()] = image.Name.String()
		m[c.GetTag()] = image.Tag
	case c.RepositoryOnly():
		m[c.GetRepository()] = image.String()
	default:
		return m, false
	}
	return m, true
}
type HelmRelease struct {
	baseObject
	Spec struct {
		Values map[string]interface{}
	}
}
type ImageSetter func(image.Ref)
type imageAndSetter struct {
	image  image.Ref
	setter ImageSetter
}
func sorted_containers(containers map[string]imageAndSetter) []string {
	var keys []string
	for k := range containers {
		keys = append(keys, k)
	}
	sort.Slice(keys, func(i, j int) bool {
		if keys[i] == ReleaseContainerName {
			return true
		}
		if keys[j] == ReleaseContainerName {
			return false
		}
		return keys[i] < keys[j]
	})
	return keys
}
func FindHelmReleaseContainers(annotations map[string]string, values map[string]interface{},
	visit func(string, image.Ref, ImageSetter) error) {
	containers := make(map[string]imageAndSetter)
	if image, setter, ok := interpretAsContainer(stringMap(values)); ok {
		containers[ReleaseContainerName] = imageAndSetter{image, setter}
	}
	for k, v := range values {
		if image, setter, ok := interpret(v); ok {
			containers[k] = imageAndSetter{image, setter}
		}
	}
	for k, v := range containerImageMappingsFromAnnotations(annotations) {
		if image, setter, ok := interpretMappedContainerImage(values, v); ok {
			containers[k] = imageAndSetter{image, setter}
		}
	}
	for _, k := range sorted_containers(containers) {
		visit(k, containers[k].image, containers[k].setter)
	}
}
type mapper interface {
	get(string) (interface{}, bool)
	set(string, interface{})
}
type stringMap map[string]interface{}
type anyMap map[interface{}]interface{}
func (m stringMap) get(k string) (interface{}, bool) { v, ok := m[k]; return v, ok }
func (m stringMap) set(k string, v interface{})      { m[k] = v }
func (m anyMap) get(k string) (interface{}, bool) { v, ok := m[k]; return v, ok }
func (m anyMap) set(k string, v interface{})      { m[k] = v }