func (r *printEventReceiver) EventErr(eventName string, err error) error {
	r.Print(eventName, ", err: ", err)
	return err
}
EventErr receives a notification of an error if one occurs.
package tmeta
import (
	"log"
	"net/url"
	"os"
	"reflect"
	"strings"
	"sync"
	"time"
	"unicode"
	"unicode/utf8"
)
func derefType(t reflect.Type) reflect.Type {
	for t.Kind() == reflect.Ptr {
		t = t.Elem()
	}
	return t
}
func derefValue(v reflect.Value) reflect.Value {
	for v.Kind() == reflect.Ptr {
		v = v.Elem()
	}
	return v
}
func elemDerefType(t reflect.Type) reflect.Type {
	t = derefType(t)
	if t.Kind() == reflect.Slice {
		t = derefType(t.Elem())
	}
	return t
}
type sqlFieldIndexCacheKey struct {
	T reflect.Type
	F string
}
var sqlFieldIndexCacheMU sync.RWMutex
var sqlFieldIndexCache = make(map[sqlFieldIndexCacheKey][]int)
func sqlFieldIndex(t reflect.Type, sqlFieldName string) []int {
	sqlFieldIndexCacheMU.RLock()
	ret, ok := sqlFieldIndexCache[sqlFieldIndexCacheKey{T: t, F: sqlFieldName}]
	sqlFieldIndexCacheMU.RUnlock()
	if ok {
		return ret
	}
	sqlFieldIndexCacheMU.Lock()
	defer sqlFieldIndexCacheMU.Unlock()
	for _, idx := range exportedFieldIndexes(t) {
		sf := t.FieldByIndex(idx)
		sfdb := strings.SplitN(sf.Tag.Get("db"), ",", 2)[0]
		if sfdb == "" || sfdb == "-" {
			continue
		}
		if sfdb == sqlFieldName {
			ret = idx
			break
		}
	}
	sqlFieldIndexCache[sqlFieldIndexCacheKey{T: t, F: sqlFieldName}] = ret
	return ret
}
func sqlFieldValue(v reflect.Value, sqlFieldName string) interface{} {
	t := v.Type()
	idx := sqlFieldIndex(t, sqlFieldName)
	if idx == nil {
		return nil
	}
	f := v.FieldByIndex(idx)
	return f.Interface()
}
func split(src string) (entries []string) {
	if !utf8.ValidString(src) {
		return []string{src}
	}
	entries = []string{}
	var runes [][]rune
	lastClass := 0
	class := 0
	for _, r := range src {
		switch true {
		case unicode.IsLower(r):
			class = 1
		case unicode.IsUpper(r):
			class = 2
		case unicode.IsDigit(r):
			class = 3
		default:
			class = 4
		}
		if class == lastClass {
			runes[len(runes)-1] = append(runes[len(runes)-1], r)
		} else {
			runes = append(runes, []rune{r})
		}
		lastClass = class
	}
	for i := 0; i < len(runes)-1; i++ {
		if unicode.IsUpper(runes[i][0]) && unicode.IsLower(runes[i+1][0]) {
			runes[i+1] = append([]rune{runes[i][len(runes[i])-1]}, runes[i+1]...)
			runes[i] = runes[i][:len(runes[i])-1]
		}
	}
	for _, s := range runes {
		if len(s) > 0 {
			entries = append(entries, string(s))
		}
	}
	return
}
func camelToSnake(s string) string {
	parts := split(s)
	for i := 0; i < len(parts); i++ {
		parts[i] = strings.ToLower(parts[i])
	}
	return strings.Join(parts, "_")
}
func exportedFieldIndexes(t reflect.Type) (ret [][]int) {
	l := t.NumField()
	for i := 0; i < l; i++ {
		f := t.Field(i)
		if f.PkgPath != "" {
			continue
		}
		if f.Anonymous && f.Type.Kind() == reflect.Struct {
			inner := exportedFieldIndexes(f.Type)
			for _, iv := range inner {
				iv2 := append([]int(nil), i)
				iv2 = append(iv2, iv...)
				ret = append(ret, iv2)
			}
			continue
		}
		ret = append(ret, f.Index)
	}
	return
}
func structTagToValues(st string) url.Values {
	ret := make(url.Values)
	parts := strings.Split(st, ",")
	for _, part := range parts {
		kvparts := strings.SplitN(part, "=", 2)
		if len(kvparts) < 2 {
			ret.Set(kvparts[0], "")
		} else {
			ret.Set(kvparts[0], kvparts[1])
		}
	}
	return ret
}
type printEventReceiver struct {
	printer
}
type printer interface {
	Print(v ...interface{})
}
func newPrintEventReceiver(p printer) *printEventReceiver {
	if p == nil {
		p = log.New(os.Stderr, "", log.LstdFlags)
	}
	return &printEventReceiver{
		printer: p,
	}
}
func (r *printEventReceiver) Event(eventName string) {
	r.Print(eventName)
}
func (r *printEventReceiver) EventKv(eventName string, kvs map[string]string) {
	r.Print(eventName, ": ", kvs)
}