func equalHelper(a interface{}, b interface{}, options *Options) interface{} {
	if Str(a) == Str(b) {
		return options.Fn()
	}
	return ""
}
#equal helper
Ref: https://github.com/aymerick/raymond/issues/7
package raymond
import (
	"fmt"
	"log"
	"reflect"
	"sync"
)
type Options struct {
	eval *evalVisitor
	params []interface{}
	hash   map[string]interface{}
}
var helpers = make(map[string]reflect.Value)
var helpersMutex sync.RWMutex
func init() {
	RegisterHelper("if", ifHelper)
	RegisterHelper("unless", unlessHelper)
	RegisterHelper("with", withHelper)
	RegisterHelper("each", eachHelper)
	RegisterHelper("log", logHelper)
	RegisterHelper("lookup", lookupHelper)
	RegisterHelper("equal", equalHelper)
}
func RegisterHelper(name string, helper interface{}) {
	helpersMutex.Lock()
	defer helpersMutex.Unlock()
	if helpers[name] != zero {
		panic(fmt.Errorf("Helper already registered: %s", name))
	}
	val := reflect.ValueOf(helper)
	ensureValidHelper(name, val)
	helpers[name] = val
}
func RegisterHelpers(helpers map[string]interface{}) {
	for name, helper := range helpers {
		RegisterHelper(name, helper)
	}
}
func RemoveHelper(name string) {
	helpersMutex.Lock()
	defer helpersMutex.Unlock()
	delete(helpers, name)
}
func RemoveAllHelpers() {
	helpersMutex.Lock()
	defer helpersMutex.Unlock()
	helpers = make(map[string]reflect.Value)
}
func ensureValidHelper(name string, funcValue reflect.Value) {
	if funcValue.Kind() != reflect.Func {
		panic(fmt.Errorf("Helper must be a function: %s", name))
	}
	funcType := funcValue.Type()
	if funcType.NumOut() != 1 {
		panic(fmt.Errorf("Helper function must return a string or a SafeString: %s", name))
	}
}
func findHelper(name string) reflect.Value {
	helpersMutex.RLock()
	defer helpersMutex.RUnlock()
	return helpers[name]
}
func newOptions(eval *evalVisitor, params []interface{}, hash map[string]interface{}) *Options {
	return &Options{
		eval:   eval,
		params: params,
		hash:   hash,
	}
}
func newEmptyOptions(eval *evalVisitor) *Options {
	return &Options{
		eval: eval,
		hash: make(map[string]interface{}),
	}
}
func (options *Options) Value(name string) interface{} {
	value := options.eval.evalField(options.eval.curCtx(), name, false)
	if !value.IsValid() {
		return nil
	}
	return value.Interface()
}
func (options *Options) ValueStr(name string) string {
	return Str(options.Value(name))
}
func (options *Options) Ctx() interface{} {
	return options.eval.curCtx().Interface()
}
func (options *Options) HashProp(name string) interface{} {
	return options.hash[name]
}
func (options *Options) HashStr(name string) string {
	return Str(options.hash[name])
}
func (options *Options) Hash() map[string]interface{} {
	return options.hash
}
func (options *Options) Param(pos int) interface{} {
	if len(options.params) > pos {
		return options.params[pos]
	}
	return nil
}
func (options *Options) ParamStr(pos int) string {
	return Str(options.Param(pos))
}
func (options *Options) Params() []interface{} {
	return options.params
}
func (options *Options) Data(name string) interface{} {
	return options.eval.dataFrame.Get(name)
}
func (options *Options) DataStr(name string) string {
	return Str(options.eval.dataFrame.Get(name))
}
func (options *Options) DataFrame() *DataFrame {
	return options.eval.dataFrame
}
func (options *Options) NewDataFrame() *DataFrame {
	return options.eval.dataFrame.Copy()
}
func (options *Options) newIterDataFrame(length int, i int, key interface{}) *DataFrame {
	return options.eval.dataFrame.newIterDataFrame(length, i, key)
}
func (options *Options) evalBlock(ctx interface{}, data *DataFrame, key interface{}) string {
	result := ""
	if block := options.eval.curBlock(); (block != nil) && (block.Program != nil) {
		result = options.eval.evalProgram(block.Program, ctx, data, key)
	}
	return result
}
func (options *Options) Fn() string {
	return options.evalBlock(nil, nil, nil)
}
func (options *Options) FnCtxData(ctx interface{}, data *DataFrame) string {
	return options.evalBlock(ctx, data, nil)
}
func (options *Options) FnWith(ctx interface{}) string {
	return options.evalBlock(ctx, nil, nil)
}
func (options *Options) FnData(data *DataFrame) string {
	return options.evalBlock(nil, data, nil)
}
func (options *Options) Inverse() string {
	result := ""
	if block := options.eval.curBlock(); (block != nil) && (block.Inverse != nil) {
		result, _ = block.Inverse.Accept(options.eval).(string)
	}
	return result
}
func (options *Options) Eval(ctx interface{}, field string) interface{} {
	if ctx == nil {
		return nil
	}
	if field == "" {
		return nil
	}
	val := options.eval.evalField(reflect.ValueOf(ctx), field, false)
	if !val.IsValid() {
		return nil
	}
	return val.Interface()
}
func (options *Options) isIncludableZero() bool {
	b, ok := options.HashProp("includeZero").(bool)
	if ok && b {
		nb, ok := options.Param(0).(int)
		if ok && nb == 0 {
			return true
		}
	}
	return false
}
func ifHelper(conditional interface{}, options *Options) interface{} {
	if options.isIncludableZero() || IsTrue(conditional) {
		return options.Fn()
	}
	return options.Inverse()
}
func unlessHelper(conditional interface{}, options *Options) interface{} {
	if options.isIncludableZero() || IsTrue(conditional) {
		return options.Inverse()
	}
	return options.Fn()
}
func withHelper(context interface{}, options *Options) interface{} {
	if IsTrue(context) {
		return options.FnWith(context)
	}
	return options.Inverse()
}
func eachHelper(context interface{}, options *Options) interface{} {
	if !IsTrue(context) {
		return options.Inverse()
	}
	result := ""
	val := reflect.ValueOf(context)
	switch val.Kind() {
	case reflect.Array, reflect.Slice:
		for i := 0; i < val.Len(); i++ {
			data := options.newIterDataFrame(val.Len(), i, nil)
			result += options.evalBlock(val.Index(i).Interface(), data, i)
		}
	case reflect.Map:
		keys := val.MapKeys()
		for i := 0; i < len(keys); i++ {
			key := keys[i].Interface()
			ctx := val.MapIndex(keys[i]).Interface()
			data := options.newIterDataFrame(len(keys), i, key)
			result += options.evalBlock(ctx, data, key)
		}
	case reflect.Struct:
		var exportedFields []int
		for i := 0; i < val.NumField(); i++ {
			if tField := val.Type().Field(i); tField.PkgPath == "" {
				exportedFields = append(exportedFields, i)
			}
		}
		for i, fieldIndex := range exportedFields {
			key := val.Type().Field(fieldIndex).Name
			ctx := val.Field(fieldIndex).Interface()
			data := options.newIterDataFrame(len(exportedFields), i, key)
			result += options.evalBlock(ctx, data, key)
		}
	}
	return result
}
func logHelper(message string) interface{} {
	log.Print(message)
	return ""
}
func lookupHelper(obj interface{}, field string, options *Options) interface{} {
	return Str(options.Eval(obj, field))
}