func MapContains(haystack, needle map[string]string) bool {
	if len(haystack) < len(needle) {
		return false
	}
	for k, v := range needle {
		v2, ok := haystack[k]
		if !ok || v2 != v {
			return false
		}
	}
	return true
}
MapContains returns true if and only if haystack contains all the keys from the needle with matching corresponding values
package util
import (
	"crypto/hmac"
	"crypto/md5"  
	cryptoRand "crypto/rand"
	"crypto/sha256"
	"encoding/base64"
	"encoding/hex"
	"fmt"
	"math/big"
	"math/rand"
	"reflect"
	"regexp"
	"sort"
	"strings"
	"time"
	"github.com/motomux/pretty"
	resource "k8s.io/apimachinery/pkg/api/resource"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"github.com/zalando/postgres-operator/pkg/spec"
	"golang.org/x/crypto/pbkdf2"
)
const (
	md5prefix         = "md5"
	scramsha256prefix = "SCRAM-SHA-256"
	saltlength        = 16
	iterations        = 4096
)
var passwordChars = []byte("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789")
func init() {
	rand.Seed(time.Now().Unix())
}
func True() *bool {
	b := true
	return &b
}
func False() *bool {
	b := false
	return &b
}
func RandomPassword(n int) string {
	b := make([]byte, n)
	for i := range b {
		maxN := big.NewInt(int64(len(passwordChars)))
		if n, err := cryptoRand.Int(cryptoRand.Reader, maxN); err != nil {
			panic(fmt.Errorf("Unable to generate secure, random password: %v", err))
		} else {
			b[i] = passwordChars[n.Int64()]
		}
	}
	return string(b)
}
func NameFromMeta(meta metav1.ObjectMeta) spec.NamespacedName {
	return spec.NamespacedName{
		Namespace: meta.Namespace,
		Name:      meta.Name,
	}
}
type Hasher func(user spec.PgUser) string
type Random func(n int) string
type Encryptor struct {
	encrypt Hasher
	random  Random
}
func NewEncryptor(encryption string) *Encryptor {
	e := Encryptor{random: RandomPassword}
	m := map[string]Hasher{
		"md5":           e.PGUserPasswordMD5,
		"scram-sha-256": e.PGUserPasswordScramSHA256,
	}
	hasher, ok := m[encryption]
	if !ok {
		hasher = e.PGUserPasswordMD5
	}
	e.encrypt = hasher
	return &e
}
func (e *Encryptor) PGUserPassword(user spec.PgUser) string {
	if (len(user.Password) == md5.Size*2+len(md5prefix) && user.Password[:3] == md5prefix) ||
		(len(user.Password) > len(scramsha256prefix) && user.Password[:len(scramsha256prefix)] == scramsha256prefix) || user.Password == "" {
		return user.Password
	}
	return e.encrypt(user)
}
func (e *Encryptor) PGUserPasswordMD5(user spec.PgUser) string {
	s := md5.Sum([]byte(user.Password + user.Name))  
	return md5prefix + hex.EncodeToString(s[:])
}
func (e *Encryptor) PGUserPasswordScramSHA256(user spec.PgUser) string {
	salt := []byte(e.random(saltlength))
	key := pbkdf2.Key([]byte(user.Password), salt, iterations, 32, sha256.New)
	mac := hmac.New(sha256.New, key)
	mac.Write([]byte("Server Key"))
	serverKey := mac.Sum(nil)
	mac = hmac.New(sha256.New, key)
	mac.Write([]byte("Client Key"))
	clientKey := mac.Sum(nil)
	storedKey := sha256.Sum256(clientKey)
	pass := fmt.Sprintf("%s$%v:%s$%s:%s",
		scramsha256prefix,
		iterations,
		base64.StdEncoding.EncodeToString(salt),
		base64.StdEncoding.EncodeToString(storedKey[:]),
		base64.StdEncoding.EncodeToString(serverKey),
	)
	return pass
}
func Diff(a, b interface{}) []string {
	return pretty.Diff(a, b)
}
func PrettyDiff(a, b interface{}) string {
	return strings.Join(Diff(a, b), "\n")
}
func IsEqualIgnoreOrder(a, b []string) bool {
	if len(a) != len(b) {
		return false
	}
	a_copy := make([]string, len(a))
	b_copy := make([]string, len(b))
	copy(a_copy, a)
	copy(b_copy, b)
	sort.Strings(a_copy)
	sort.Strings(b_copy)
	return reflect.DeepEqual(a_copy, b_copy)
}
func StringSliceReplaceElement(s []string, a, b string) (result []string) {
	tmp := make([]string, 0, len(s))
	for _, str := range s {
		if str == a {
			str = b
		}
		tmp = append(tmp, str)
	}
	return tmp
}
func SubstractStringSlices(a []string, b []string) (result []string, equal bool) {
OUTER:
	for _, vala := range a {
		for _, valb := range b {
			if vala == valb {
				continue OUTER
			}
		}
		result = append(result, vala)
	}
	return result, len(result) == 0
}
func FindNamedStringSubmatch(r *regexp.Regexp, s string) map[string]string {
	matches := r.FindStringSubmatch(s)
	grNames := r.SubexpNames()
	if matches == nil {
		return nil
	}
	groupMatches := 0
	res := make(map[string]string, len(grNames))
	for i, n := range grNames {
		if n == "" {
			continue
		}
		res[n] = matches[i]
		groupMatches++
	}
	if groupMatches == 0 {
		return nil
	}
	return res
}
func SliceContains(slice interface{}, item interface{}) bool {
	s := reflect.ValueOf(slice)
	if s.Kind() != reflect.Slice {
		panic("Invalid data-type")
	}
	for i := 0; i < s.Len(); i++ {
		if s.Index(i).Interface() == item {
			return true
		}
	}
	return false
}