tpl: split template.go
authorbep <bjorn.erik.pedersen@gmail.com>
Sun, 5 Apr 2015 19:03:16 +0000 (21:03 +0200)
committerbep <bjorn.erik.pedersen@gmail.com>
Sun, 5 Apr 2015 19:03:12 +0000 (21:03 +0200)
The template funcs get their own file. This prevents having to scroll miles to get to the template infrastructure.

tpl/template.go
tpl/template_funcs.go [new file with mode: 0644]
tpl/template_funcs_test.go [new file with mode: 0644]
tpl/template_test.go

index fc7457e554096b5ac40f79482e52d3f7260d8c1d..bc3a57a70e1b1ec8f556aa6381ab02d63e0a1ba0 100644 (file)
@@ -15,30 +15,22 @@ package tpl
 
 import (
        "bytes"
-       "errors"
-       "fmt"
        "github.com/eknkc/amber"
-       "github.com/spf13/cast"
        bp "github.com/spf13/hugo/bufferpool"
        "github.com/spf13/hugo/helpers"
        "github.com/spf13/hugo/hugofs"
        jww "github.com/spf13/jwalterweatherman"
        "github.com/yosssi/ace"
-       "html"
        "html/template"
        "io"
        "io/ioutil"
        "os"
        "path/filepath"
-       "reflect"
-       "sort"
-       "strconv"
        "strings"
 )
 
 var localTemplates *template.Template
 var tmpl Template
-var funcMap template.FuncMap
 
 type Template interface {
        ExecuteTemplate(wr io.Writer, name string, data interface{}) error
@@ -93,1123 +85,6 @@ func New() Template {
        return templates
 }
 
-func Eq(x, y interface{}) bool {
-       normalize := func(v interface{}) interface{} {
-               vv := reflect.ValueOf(v)
-               switch vv.Kind() {
-               case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
-                       return vv.Int()
-               case reflect.Float32, reflect.Float64:
-                       return vv.Float()
-               case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
-                       return vv.Uint()
-               default:
-                       return v
-               }
-       }
-       x = normalize(x)
-       y = normalize(y)
-       return reflect.DeepEqual(x, y)
-}
-
-func Ne(x, y interface{}) bool {
-       return !Eq(x, y)
-}
-
-func Ge(a, b interface{}) bool {
-       left, right := compareGetFloat(a, b)
-       return left >= right
-}
-
-func Gt(a, b interface{}) bool {
-       left, right := compareGetFloat(a, b)
-       return left > right
-}
-
-func Le(a, b interface{}) bool {
-       left, right := compareGetFloat(a, b)
-       return left <= right
-}
-
-func Lt(a, b interface{}) bool {
-       left, right := compareGetFloat(a, b)
-       return left < right
-}
-
-func compareGetFloat(a interface{}, b interface{}) (float64, float64) {
-       var left, right float64
-       var leftStr, rightStr *string
-       var err error
-       av := reflect.ValueOf(a)
-
-       switch av.Kind() {
-       case reflect.Array, reflect.Chan, reflect.Map, reflect.Slice:
-               left = float64(av.Len())
-       case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
-               left = float64(av.Int())
-       case reflect.Float32, reflect.Float64:
-               left = av.Float()
-       case reflect.String:
-               left, err = strconv.ParseFloat(av.String(), 64)
-               if err != nil {
-                       str := av.String()
-                       leftStr = &str
-               }
-       }
-
-       bv := reflect.ValueOf(b)
-
-       switch bv.Kind() {
-       case reflect.Array, reflect.Chan, reflect.Map, reflect.Slice:
-               right = float64(bv.Len())
-       case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
-               right = float64(bv.Int())
-       case reflect.Float32, reflect.Float64:
-               right = bv.Float()
-       case reflect.String:
-               right, err = strconv.ParseFloat(bv.String(), 64)
-               if err != nil {
-                       str := bv.String()
-                       rightStr = &str
-               }
-
-       }
-
-       switch {
-       case leftStr == nil || rightStr == nil:
-       case *leftStr < *rightStr:
-               return 0, 1
-       case *leftStr > *rightStr:
-               return 1, 0
-       default:
-               return 0, 0
-       }
-
-       return left, right
-}
-
-// Slicing in Slicestr is done by specifying a half-open range with
-// two indices, start and end. 1 and 4 creates a slice including elements 1 through 3.
-// The end index can be omitted, it defaults to the string's length.
-func Slicestr(a interface{}, startEnd ...int) (string, error) {
-       aStr, err := cast.ToStringE(a)
-       if err != nil {
-               return "", err
-       }
-
-       if len(startEnd) > 2 {
-               return "", errors.New("too many arguments")
-       }
-
-       if len(startEnd) == 2 {
-               return aStr[startEnd[0]:startEnd[1]], nil
-       } else if len(startEnd) == 1 {
-               return aStr[startEnd[0]:], nil
-       } else {
-               return aStr[:], nil
-       }
-
-}
-
-// Substr extracts parts of a string, beginning at the character at the specified
-// position, and returns the specified number of characters.
-//
-// It normally takes two parameters: start and length.
-// It can also take one parameter: start, i.e. length is omitted, in which case
-// the substring starting from start until the end of the string will be returned.
-//
-// To extract characters from the end of the string, use a negative start number.
-//
-// In addition, borrowing from the extended behavior described at http://php.net/substr,
-// if length is given and is negative, then that many characters will be omitted from
-// the end of string.
-func Substr(a interface{}, nums ...int) (string, error) {
-       aStr, err := cast.ToStringE(a)
-       if err != nil {
-               return "", err
-       }
-
-       var start, length int
-       switch len(nums) {
-       case 1:
-               start = nums[0]
-               length = len(aStr)
-       case 2:
-               start = nums[0]
-               length = nums[1]
-       default:
-               return "", errors.New("too many arguments")
-       }
-
-       if start < -len(aStr) {
-               start = 0
-       }
-       if start > len(aStr) {
-               return "", errors.New(fmt.Sprintf("start position out of bounds for %d-byte string", len(aStr)))
-       }
-
-       var s, e int
-       if start >= 0 && length >= 0 {
-               s = start
-               e = start + length
-       } else if start < 0 && length >= 0 {
-               s = len(aStr) + start - length + 1
-               e = len(aStr) + start + 1
-       } else if start >= 0 && length < 0 {
-               s = start
-               e = len(aStr) + length
-       } else {
-               s = len(aStr) + start
-               e = len(aStr) + length
-       }
-
-       if s > e {
-               return "", errors.New(fmt.Sprintf("calculated start position greater than end position: %d > %d", s, e))
-       }
-       if e > len(aStr) {
-               e = len(aStr)
-       }
-
-       return aStr[s:e], nil
-
-}
-
-func Split(a interface{}, delimiter string) ([]string, error) {
-       aStr, err := cast.ToStringE(a)
-       if err != nil {
-               return []string{}, err
-       }
-       return strings.Split(aStr, delimiter), nil
-}
-
-func Intersect(l1, l2 interface{}) (interface{}, error) {
-       if l1 == nil || l2 == nil {
-               return make([]interface{}, 0), nil
-       }
-
-       l1v := reflect.ValueOf(l1)
-       l2v := reflect.ValueOf(l2)
-
-       switch l1v.Kind() {
-       case reflect.Array, reflect.Slice:
-               switch l2v.Kind() {
-               case reflect.Array, reflect.Slice:
-                       r := reflect.MakeSlice(l1v.Type(), 0, 0)
-                       for i := 0; i < l1v.Len(); i++ {
-                               l1vv := l1v.Index(i)
-                               for j := 0; j < l2v.Len(); j++ {
-                                       l2vv := l2v.Index(j)
-                                       switch l1vv.Kind() {
-                                       case reflect.String:
-                                               if l1vv.Type() == l2vv.Type() && l1vv.String() == l2vv.String() && !In(r, l2vv) {
-                                                       r = reflect.Append(r, l2vv)
-                                               }
-                                       case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
-                                               switch l2vv.Kind() {
-                                               case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
-                                                       if l1vv.Int() == l2vv.Int() && !In(r, l2vv) {
-                                                               r = reflect.Append(r, l2vv)
-                                                       }
-                                               }
-                                       case reflect.Float32, reflect.Float64:
-                                               switch l2vv.Kind() {
-                                               case reflect.Float32, reflect.Float64:
-                                                       if l1vv.Float() == l2vv.Float() && !In(r, l2vv) {
-                                                               r = reflect.Append(r, l2vv)
-                                                       }
-                                               }
-                                       }
-                               }
-                       }
-                       return r.Interface(), nil
-               default:
-                       return nil, errors.New("can't iterate over " + reflect.ValueOf(l2).Type().String())
-               }
-       default:
-               return nil, errors.New("can't iterate over " + reflect.ValueOf(l1).Type().String())
-       }
-}
-
-func In(l interface{}, v interface{}) bool {
-       lv := reflect.ValueOf(l)
-       vv := reflect.ValueOf(v)
-
-       switch lv.Kind() {
-       case reflect.Array, reflect.Slice:
-               for i := 0; i < lv.Len(); i++ {
-                       lvv := lv.Index(i)
-                       switch lvv.Kind() {
-                       case reflect.String:
-                               if vv.Type() == lvv.Type() && vv.String() == lvv.String() {
-                                       return true
-                               }
-                       case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
-                               switch vv.Kind() {
-                               case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
-                                       if vv.Int() == lvv.Int() {
-                                               return true
-                                       }
-                               }
-                       case reflect.Float32, reflect.Float64:
-                               switch vv.Kind() {
-                               case reflect.Float32, reflect.Float64:
-                                       if vv.Float() == lvv.Float() {
-                                               return true
-                                       }
-                               }
-                       }
-               }
-       case reflect.String:
-               if vv.Type() == lv.Type() && strings.Contains(lv.String(), vv.String()) {
-                       return true
-               }
-       }
-       return false
-}
-
-// indirect is taken from 'text/template/exec.go'
-func indirect(v reflect.Value) (rv reflect.Value, isNil bool) {
-       for ; v.Kind() == reflect.Ptr || v.Kind() == reflect.Interface; v = v.Elem() {
-               if v.IsNil() {
-                       return v, true
-               }
-               if v.Kind() == reflect.Interface && v.NumMethod() > 0 {
-                       break
-               }
-       }
-       return v, false
-}
-
-// First is exposed to templates, to iterate over the first N items in a
-// rangeable list.
-func First(limit interface{}, seq interface{}) (interface{}, error) {
-
-       if limit == nil || seq == nil {
-               return nil, errors.New("both limit and seq must be provided")
-       }
-
-       limitv, err := cast.ToIntE(limit)
-
-       if err != nil {
-               return nil, err
-       }
-
-       if limitv < 1 {
-               return nil, errors.New("can't return negative/empty count of items from sequence")
-       }
-
-       seqv := reflect.ValueOf(seq)
-       seqv, isNil := indirect(seqv)
-       if isNil {
-               return nil, errors.New("can't iterate over a nil value")
-       }
-
-       switch seqv.Kind() {
-       case reflect.Array, reflect.Slice, reflect.String:
-               // okay
-       default:
-               return nil, errors.New("can't iterate over " + reflect.ValueOf(seq).Type().String())
-       }
-       if limitv > seqv.Len() {
-               limitv = seqv.Len()
-       }
-       return seqv.Slice(0, limitv).Interface(), nil
-}
-
-var (
-       zero      reflect.Value
-       errorType = reflect.TypeOf((*error)(nil)).Elem()
-)
-
-func evaluateSubElem(obj reflect.Value, elemName string) (reflect.Value, error) {
-       if !obj.IsValid() {
-               return zero, errors.New("can't evaluate an invalid value")
-       }
-       typ := obj.Type()
-       obj, isNil := indirect(obj)
-
-       // first, check whether obj has a method. In this case, obj is
-       // an interface, a struct or its pointer. If obj is a struct,
-       // to check all T and *T method, use obj pointer type Value
-       objPtr := obj
-       if objPtr.Kind() != reflect.Interface && objPtr.CanAddr() {
-               objPtr = objPtr.Addr()
-       }
-       mt, ok := objPtr.Type().MethodByName(elemName)
-       if ok {
-               if mt.PkgPath != "" {
-                       return zero, fmt.Errorf("%s is an unexported method of type %s", elemName, typ)
-               }
-               // struct pointer has one receiver argument and interface doesn't have an argument
-               if mt.Type.NumIn() > 1 || mt.Type.NumOut() == 0 || mt.Type.NumOut() > 2 {
-                       return zero, fmt.Errorf("%s is a method of type %s but doesn't satisfy requirements", elemName, typ)
-               }
-               if mt.Type.NumOut() == 1 && mt.Type.Out(0).Implements(errorType) {
-                       return zero, fmt.Errorf("%s is a method of type %s but doesn't satisfy requirements", elemName, typ)
-               }
-               if mt.Type.NumOut() == 2 && !mt.Type.Out(1).Implements(errorType) {
-                       return zero, fmt.Errorf("%s is a method of type %s but doesn't satisfy requirements", elemName, typ)
-               }
-               res := objPtr.Method(mt.Index).Call([]reflect.Value{})
-               if len(res) == 2 && !res[1].IsNil() {
-                       return zero, fmt.Errorf("error at calling a method %s of type %s: %s", elemName, typ, res[1].Interface().(error))
-               }
-               return res[0], nil
-       }
-
-       // elemName isn't a method so next start to check whether it is
-       // a struct field or a map value. In both cases, it mustn't be
-       // a nil value
-       if isNil {
-               return zero, fmt.Errorf("can't evaluate a nil pointer of type %s by a struct field or map key name %s", typ, elemName)
-       }
-       switch obj.Kind() {
-       case reflect.Struct:
-               ft, ok := obj.Type().FieldByName(elemName)
-               if ok {
-                       if ft.PkgPath != "" {
-                               return zero, fmt.Errorf("%s is an unexported field of struct type %s", elemName, typ)
-                       }
-                       return obj.FieldByIndex(ft.Index), nil
-               }
-               return zero, fmt.Errorf("%s isn't a field of struct type %s", elemName, typ)
-       case reflect.Map:
-               kv := reflect.ValueOf(elemName)
-               if kv.Type().AssignableTo(obj.Type().Key()) {
-                       return obj.MapIndex(kv), nil
-               }
-               return zero, fmt.Errorf("%s isn't a key of map type %s", elemName, typ)
-       }
-       return zero, fmt.Errorf("%s is neither a struct field, a method nor a map element of type %s", elemName, typ)
-}
-
-func checkCondition(v, mv reflect.Value, op string) (bool, error) {
-       if !v.IsValid() || !mv.IsValid() {
-               return false, nil
-       }
-
-       var isNil bool
-       v, isNil = indirect(v)
-       if isNil {
-               return false, nil
-       }
-       mv, isNil = indirect(mv)
-       if isNil {
-               return false, nil
-       }
-
-       var ivp, imvp *int64
-       var svp, smvp *string
-       var ima []int64
-       var sma []string
-       if mv.Type() == v.Type() {
-               switch v.Kind() {
-               case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
-                       iv := v.Int()
-                       ivp = &iv
-                       imv := mv.Int()
-                       imvp = &imv
-               case reflect.String:
-                       sv := v.String()
-                       svp = &sv
-                       smv := mv.String()
-                       smvp = &smv
-               }
-       } else {
-               if mv.Kind() != reflect.Array && mv.Kind() != reflect.Slice {
-                       return false, nil
-               }
-               if mv.Type().Elem() != v.Type() {
-                       return false, nil
-               }
-               switch v.Kind() {
-               case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
-                       iv := v.Int()
-                       ivp = &iv
-                       for i := 0; i < mv.Len(); i++ {
-                               ima = append(ima, mv.Index(i).Int())
-                       }
-               case reflect.String:
-                       sv := v.String()
-                       svp = &sv
-                       for i := 0; i < mv.Len(); i++ {
-                               sma = append(sma, mv.Index(i).String())
-                       }
-               }
-       }
-
-       switch op {
-       case "", "=", "==", "eq":
-               if ivp != nil && imvp != nil {
-                       return *ivp == *imvp, nil
-               } else if svp != nil && smvp != nil {
-                       return *svp == *smvp, nil
-               }
-       case "!=", "<>", "ne":
-               if ivp != nil && imvp != nil {
-                       return *ivp != *imvp, nil
-               } else if svp != nil && smvp != nil {
-                       return *svp != *smvp, nil
-               }
-       case ">=", "ge":
-               if ivp != nil && imvp != nil {
-                       return *ivp >= *imvp, nil
-               } else if svp != nil && smvp != nil {
-                       return *svp >= *smvp, nil
-               }
-       case ">", "gt":
-               if ivp != nil && imvp != nil {
-                       return *ivp > *imvp, nil
-               } else if svp != nil && smvp != nil {
-                       return *svp > *smvp, nil
-               }
-       case "<=", "le":
-               if ivp != nil && imvp != nil {
-                       return *ivp <= *imvp, nil
-               } else if svp != nil && smvp != nil {
-                       return *svp <= *smvp, nil
-               }
-       case "<", "lt":
-               if ivp != nil && imvp != nil {
-                       return *ivp < *imvp, nil
-               } else if svp != nil && smvp != nil {
-                       return *svp < *smvp, nil
-               }
-       case "in", "not in":
-               var r bool
-               if ivp != nil && len(ima) > 0 {
-                       r = In(ima, *ivp)
-               } else if svp != nil {
-                       if len(sma) > 0 {
-                               r = In(sma, *svp)
-                       } else if smvp != nil {
-                               r = In(*smvp, *svp)
-                       }
-               } else {
-                       return false, nil
-               }
-               if op == "not in" {
-                       return !r, nil
-               } else {
-                       return r, nil
-               }
-       default:
-               return false, errors.New("no such an operator")
-       }
-       return false, nil
-}
-
-func Where(seq, key interface{}, args ...interface{}) (r interface{}, err error) {
-       seqv := reflect.ValueOf(seq)
-       kv := reflect.ValueOf(key)
-
-       var mv reflect.Value
-       var op string
-       switch len(args) {
-       case 1:
-               mv = reflect.ValueOf(args[0])
-       case 2:
-               var ok bool
-               if op, ok = args[0].(string); !ok {
-                       return nil, errors.New("operator argument must be string type")
-               }
-               op = strings.TrimSpace(strings.ToLower(op))
-               mv = reflect.ValueOf(args[1])
-       default:
-               return nil, errors.New("can't evaluate the array by no match argument or more than or equal to two arguments")
-       }
-
-       seqv, isNil := indirect(seqv)
-       if isNil {
-               return nil, errors.New("can't iterate over a nil value of type " + reflect.ValueOf(seq).Type().String())
-       }
-
-       var path []string
-       if kv.Kind() == reflect.String {
-               path = strings.Split(strings.Trim(kv.String(), "."), ".")
-       }
-
-       switch seqv.Kind() {
-       case reflect.Array, reflect.Slice:
-               rv := reflect.MakeSlice(seqv.Type(), 0, 0)
-               for i := 0; i < seqv.Len(); i++ {
-                       var vvv reflect.Value
-                       rvv := seqv.Index(i)
-                       if kv.Kind() == reflect.String {
-                               vvv = rvv
-                               for _, elemName := range path {
-                                       vvv, err = evaluateSubElem(vvv, elemName)
-                                       if err != nil {
-                                               return nil, err
-                                       }
-                               }
-                       } else {
-                               vv, _ := indirect(rvv)
-                               if vv.Kind() == reflect.Map && kv.Type().AssignableTo(vv.Type().Key()) {
-                                       vvv = vv.MapIndex(kv)
-                               }
-                       }
-                       if ok, err := checkCondition(vvv, mv, op); ok {
-                               rv = reflect.Append(rv, rvv)
-                       } else if err != nil {
-                               return nil, err
-                       }
-               }
-               return rv.Interface(), nil
-       default:
-               return nil, errors.New("can't iterate over " + reflect.ValueOf(seq).Type().String())
-       }
-}
-
-// Apply, given a map, array, or slice, returns a new slice with the function fname applied over it.
-func Apply(seq interface{}, fname string, args ...interface{}) (interface{}, error) {
-       if seq == nil {
-               return make([]interface{}, 0), nil
-       }
-
-       if fname == "apply" {
-               return nil, errors.New("can't apply myself (no turtles allowed)")
-       }
-
-       seqv := reflect.ValueOf(seq)
-       seqv, isNil := indirect(seqv)
-       if isNil {
-               return nil, errors.New("can't iterate over a nil value")
-       }
-
-       fn, found := funcMap[fname]
-       if !found {
-               return nil, errors.New("can't find function " + fname)
-       }
-
-       fnv := reflect.ValueOf(fn)
-
-       switch seqv.Kind() {
-       case reflect.Array, reflect.Slice:
-               r := make([]interface{}, seqv.Len())
-               for i := 0; i < seqv.Len(); i++ {
-                       vv := seqv.Index(i)
-
-                       vvv, err := applyFnToThis(fnv, vv, args...)
-
-                       if err != nil {
-                               return nil, err
-                       }
-
-                       r[i] = vvv.Interface()
-               }
-
-               return r, nil
-       default:
-               return nil, errors.New("can't apply over " + reflect.ValueOf(seq).Type().String())
-       }
-}
-
-func applyFnToThis(fn, this reflect.Value, args ...interface{}) (reflect.Value, error) {
-       n := make([]reflect.Value, len(args))
-       for i, arg := range args {
-               if arg == "." {
-                       n[i] = this
-               } else {
-                       n[i] = reflect.ValueOf(arg)
-               }
-       }
-
-       res := fn.Call(n)
-
-       if len(res) == 1 || res[1].IsNil() {
-               return res[0], nil
-       } else {
-               return reflect.ValueOf(nil), res[1].Interface().(error)
-       }
-}
-
-func Delimit(seq, delimiter interface{}, last ...interface{}) (template.HTML, error) {
-       d, err := cast.ToStringE(delimiter)
-       if err != nil {
-               return "", err
-       }
-
-       var dLast *string
-       for _, l := range last {
-               dStr, err := cast.ToStringE(l)
-               if err != nil {
-                       dLast = nil
-               }
-               dLast = &dStr
-               break
-       }
-
-       seqv := reflect.ValueOf(seq)
-       seqv, isNil := indirect(seqv)
-       if isNil {
-               return "", errors.New("can't iterate over a nil value")
-       }
-
-       var str string
-       switch seqv.Kind() {
-       case reflect.Map:
-               sortSeq, err := Sort(seq)
-               if err != nil {
-                       return "", err
-               }
-               seqv = reflect.ValueOf(sortSeq)
-               fallthrough
-       case reflect.Array, reflect.Slice, reflect.String:
-               for i := 0; i < seqv.Len(); i++ {
-                       val := seqv.Index(i).Interface()
-                       valStr, err := cast.ToStringE(val)
-                       if err != nil {
-                               continue
-                       }
-                       switch {
-                       case i == seqv.Len()-2 && dLast != nil:
-                               str += valStr + *dLast
-                       case i == seqv.Len()-1:
-                               str += valStr
-                       default:
-                               str += valStr + d
-                       }
-               }
-
-       default:
-               return "", errors.New("can't iterate over " + reflect.ValueOf(seq).Type().String())
-       }
-
-       return template.HTML(str), nil
-}
-
-func Sort(seq interface{}, args ...interface{}) ([]interface{}, error) {
-       seqv := reflect.ValueOf(seq)
-       seqv, isNil := indirect(seqv)
-       if isNil {
-               return nil, errors.New("can't iterate over a nil value")
-       }
-
-       // Create a list of pairs that will be used to do the sort
-       p := pairList{SortAsc: true}
-       p.Pairs = make([]pair, seqv.Len())
-
-       for i, l := range args {
-               dStr, err := cast.ToStringE(l)
-               switch {
-               case i == 0 && err != nil:
-                       p.SortByField = ""
-               case i == 0 && err == nil:
-                       p.SortByField = dStr
-               case i == 1 && err == nil && dStr == "desc":
-                       p.SortAsc = false
-               case i == 1:
-                       p.SortAsc = true
-               }
-       }
-
-       var sorted []interface{}
-       switch seqv.Kind() {
-       case reflect.Array, reflect.Slice:
-               for i := 0; i < seqv.Len(); i++ {
-                       p.Pairs[i].Key = reflect.ValueOf(i)
-                       p.Pairs[i].Value = seqv.Index(i)
-               }
-               if p.SortByField == "" {
-                       p.SortByField = "value"
-               }
-
-       case reflect.Map:
-               keys := seqv.MapKeys()
-               for i := 0; i < seqv.Len(); i++ {
-                       p.Pairs[i].Key = keys[i]
-                       p.Pairs[i].Value = seqv.MapIndex(keys[i])
-               }
-
-       default:
-               return nil, errors.New("can't sort " + reflect.ValueOf(seq).Type().String())
-       }
-       sorted = p.sort()
-       return sorted, nil
-}
-
-// Credit for pair sorting method goes to Andrew Gerrand
-// https://groups.google.com/forum/#!topic/golang-nuts/FT7cjmcL7gw
-// A data structure to hold a key/value pair.
-type pair struct {
-       Key   reflect.Value
-       Value reflect.Value
-}
-
-// A slice of pairs that implements sort.Interface to sort by Value.
-type pairList struct {
-       Pairs       []pair
-       SortByField string
-       SortAsc     bool
-}
-
-func (p pairList) Swap(i, j int) { p.Pairs[i], p.Pairs[j] = p.Pairs[j], p.Pairs[i] }
-func (p pairList) Len() int      { return len(p.Pairs) }
-func (p pairList) Less(i, j int) bool {
-       var truth bool
-       switch {
-       case p.SortByField == "value":
-               iVal := p.Pairs[i].Value
-               jVal := p.Pairs[j].Value
-               truth = Lt(iVal.Interface(), jVal.Interface())
-
-       case p.SortByField != "":
-               if p.Pairs[i].Value.FieldByName(p.SortByField).IsValid() {
-                       iVal := p.Pairs[i].Value.FieldByName(p.SortByField)
-                       jVal := p.Pairs[j].Value.FieldByName(p.SortByField)
-                       truth = Lt(iVal.Interface(), jVal.Interface())
-               }
-       default:
-               iVal := p.Pairs[i].Key
-               jVal := p.Pairs[j].Key
-               truth = Lt(iVal.Interface(), jVal.Interface())
-       }
-       return truth
-}
-
-// sorts a pairList and returns a slice of sorted values
-func (p pairList) sort() []interface{} {
-       if p.SortAsc {
-               sort.Sort(p)
-       } else {
-               sort.Sort(sort.Reverse(p))
-       }
-       sorted := make([]interface{}, len(p.Pairs))
-       for i, v := range p.Pairs {
-               sorted[i] = v.Value.Interface()
-       }
-
-       return sorted
-}
-
-func IsSet(a interface{}, key interface{}) bool {
-       av := reflect.ValueOf(a)
-       kv := reflect.ValueOf(key)
-
-       switch av.Kind() {
-       case reflect.Array, reflect.Chan, reflect.Slice:
-               if int64(av.Len()) > kv.Int() {
-                       return true
-               }
-       case reflect.Map:
-               if kv.Type() == av.Type().Key() {
-                       return av.MapIndex(kv).IsValid()
-               }
-       }
-
-       return false
-}
-
-func ReturnWhenSet(a, k interface{}) interface{} {
-       av, isNil := indirect(reflect.ValueOf(a))
-       if isNil {
-               return ""
-       }
-
-       var avv reflect.Value
-       switch av.Kind() {
-       case reflect.Array, reflect.Slice:
-               index, ok := k.(int)
-               if ok && av.Len() > index {
-                       avv = av.Index(index)
-               }
-       case reflect.Map:
-               kv := reflect.ValueOf(k)
-               if kv.Type().AssignableTo(av.Type().Key()) {
-                       avv = av.MapIndex(kv)
-               }
-       }
-
-       if avv.IsValid() {
-               switch avv.Kind() {
-               case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
-                       return avv.Int()
-               case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
-                       return avv.Uint()
-               case reflect.Float32, reflect.Float64:
-                       return avv.Float()
-               case reflect.String:
-                       return avv.String()
-               }
-       }
-
-       return ""
-}
-
-func Highlight(in interface{}, lang string) template.HTML {
-       var str string
-       av := reflect.ValueOf(in)
-       switch av.Kind() {
-       case reflect.String:
-               str = av.String()
-       }
-
-       return template.HTML(helpers.Highlight(html.UnescapeString(str), lang))
-}
-
-var markdownTrimPrefix = []byte("<p>")
-var markdownTrimSuffix = []byte("</p>\n")
-
-func Markdownify(text string) template.HTML {
-       m := helpers.RenderBytes(&helpers.RenderingContext{Content: []byte(text), PageFmt: "markdown"})
-       m = bytes.TrimPrefix(m, markdownTrimPrefix)
-       m = bytes.TrimSuffix(m, markdownTrimSuffix)
-       return template.HTML(m)
-}
-
-func refPage(page interface{}, ref, methodName string) template.HTML {
-       value := reflect.ValueOf(page)
-
-       method := value.MethodByName(methodName)
-
-       if method.IsValid() && method.Type().NumIn() == 1 && method.Type().NumOut() == 2 {
-               result := method.Call([]reflect.Value{reflect.ValueOf(ref)})
-
-               url, err := result[0], result[1]
-
-               if !err.IsNil() {
-                       jww.ERROR.Printf("%s", err.Interface())
-                       return template.HTML(fmt.Sprintf("%s", err.Interface()))
-               }
-
-               if url.String() == "" {
-                       jww.ERROR.Printf("ref %s could not be found\n", ref)
-                       return template.HTML(ref)
-               }
-
-               return template.HTML(url.String())
-       }
-
-       jww.ERROR.Printf("Can only create references from Page and Node objects.")
-       return template.HTML(ref)
-}
-
-func Ref(page interface{}, ref string) template.HTML {
-       return refPage(page, ref, "Ref")
-}
-
-func RelRef(page interface{}, ref string) template.HTML {
-       return refPage(page, ref, "RelRef")
-}
-
-func Chomp(text interface{}) (string, error) {
-       s, err := cast.ToStringE(text)
-       if err != nil {
-               return "", err
-       }
-
-       return strings.TrimRight(s, "\r\n"), nil
-}
-
-// Trim leading/trailing characters defined by b from a
-func Trim(a interface{}, b string) (string, error) {
-       aStr, err := cast.ToStringE(a)
-       if err != nil {
-               return "", err
-       }
-       return strings.Trim(aStr, b), nil
-}
-
-// Replace all occurences of b with c in a
-func Replace(a, b, c interface{}) (string, error) {
-       aStr, err := cast.ToStringE(a)
-       if err != nil {
-               return "", err
-       }
-       bStr, err := cast.ToStringE(b)
-       if err != nil {
-               return "", err
-       }
-       cStr, err := cast.ToStringE(c)
-       if err != nil {
-               return "", err
-       }
-       return strings.Replace(aStr, bStr, cStr, -1), nil
-}
-
-// DateFormat converts the textual representation of the datetime string into
-// the other form or returns it of the time.Time value. These are formatted
-// with the layout string
-func DateFormat(layout string, v interface{}) (string, error) {
-       t, err := cast.ToTimeE(v)
-       if err != nil {
-               return "", err
-       }
-       return t.Format(layout), nil
-}
-
-func SafeHTML(text string) template.HTML {
-       return template.HTML(text)
-}
-
-// "safeHTMLAttr" is currently disabled, pending further discussion
-// on its use case.  2015-01-19
-func SafeHTMLAttr(text string) template.HTMLAttr {
-       return template.HTMLAttr(text)
-}
-
-func SafeCSS(text string) template.CSS {
-       return template.CSS(text)
-}
-
-func SafeURL(text string) template.URL {
-       return template.URL(text)
-}
-
-func doArithmetic(a, b interface{}, op rune) (interface{}, error) {
-       av := reflect.ValueOf(a)
-       bv := reflect.ValueOf(b)
-       var ai, bi int64
-       var af, bf float64
-       var au, bu uint64
-       switch av.Kind() {
-       case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
-               ai = av.Int()
-               switch bv.Kind() {
-               case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
-                       bi = bv.Int()
-               case reflect.Float32, reflect.Float64:
-                       af = float64(ai) // may overflow
-                       ai = 0
-                       bf = bv.Float()
-               case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
-                       bu = bv.Uint()
-                       if ai >= 0 {
-                               au = uint64(ai)
-                               ai = 0
-                       } else {
-                               bi = int64(bu) // may overflow
-                               bu = 0
-                       }
-               default:
-                       return nil, errors.New("Can't apply the operator to the values")
-               }
-       case reflect.Float32, reflect.Float64:
-               af = av.Float()
-               switch bv.Kind() {
-               case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
-                       bf = float64(bv.Int()) // may overflow
-               case reflect.Float32, reflect.Float64:
-                       bf = bv.Float()
-               case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
-                       bf = float64(bv.Uint()) // may overflow
-               default:
-                       return nil, errors.New("Can't apply the operator to the values")
-               }
-       case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
-               au = av.Uint()
-               switch bv.Kind() {
-               case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
-                       bi = bv.Int()
-                       if bi >= 0 {
-                               bu = uint64(bi)
-                               bi = 0
-                       } else {
-                               ai = int64(au) // may overflow
-                               au = 0
-                       }
-               case reflect.Float32, reflect.Float64:
-                       af = float64(au) // may overflow
-                       au = 0
-                       bf = bv.Float()
-               case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
-                       bu = bv.Uint()
-               default:
-                       return nil, errors.New("Can't apply the operator to the values")
-               }
-       case reflect.String:
-               as := av.String()
-               if bv.Kind() == reflect.String && op == '+' {
-                       bs := bv.String()
-                       return as + bs, nil
-               } else {
-                       return nil, errors.New("Can't apply the operator to the values")
-               }
-       default:
-               return nil, errors.New("Can't apply the operator to the values")
-       }
-
-       switch op {
-       case '+':
-               if ai != 0 || bi != 0 {
-                       return ai + bi, nil
-               } else if af != 0 || bf != 0 {
-                       return af + bf, nil
-               } else if au != 0 || bu != 0 {
-                       return au + bu, nil
-               } else {
-                       return 0, nil
-               }
-       case '-':
-               if ai != 0 || bi != 0 {
-                       return ai - bi, nil
-               } else if af != 0 || bf != 0 {
-                       return af - bf, nil
-               } else if au != 0 || bu != 0 {
-                       return au - bu, nil
-               } else {
-                       return 0, nil
-               }
-       case '*':
-               if ai != 0 || bi != 0 {
-                       return ai * bi, nil
-               } else if af != 0 || bf != 0 {
-                       return af * bf, nil
-               } else if au != 0 || bu != 0 {
-                       return au * bu, nil
-               } else {
-                       return 0, nil
-               }
-       case '/':
-               if bi != 0 {
-                       return ai / bi, nil
-               } else if bf != 0 {
-                       return af / bf, nil
-               } else if bu != 0 {
-                       return au / bu, nil
-               } else {
-                       return nil, errors.New("Can't divide the value by 0")
-               }
-       default:
-               return nil, errors.New("There is no such an operation")
-       }
-}
-
-func Mod(a, b interface{}) (int64, error) {
-       av := reflect.ValueOf(a)
-       bv := reflect.ValueOf(b)
-       var ai, bi int64
-
-       switch av.Kind() {
-       case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
-               ai = av.Int()
-       default:
-               return 0, errors.New("Modulo operator can't be used with non integer value")
-       }
-
-       switch bv.Kind() {
-       case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
-               bi = bv.Int()
-       default:
-               return 0, errors.New("Modulo operator can't be used with non integer value")
-       }
-
-       if bi == 0 {
-               return 0, errors.New("The number can't be divided by zero at modulo operation")
-       }
-
-       return ai % bi, nil
-}
-
-func ModBool(a, b interface{}) (bool, error) {
-       res, err := Mod(a, b)
-       if err != nil {
-               return false, err
-       }
-       return res == int64(0), nil
-}
-
 func Partial(name string, context_list ...interface{}) template.HTML {
        if strings.HasPrefix("partials/", name) {
                name = name[8:]
@@ -1351,8 +226,6 @@ func isBackupFile(path string) bool {
        return path[len(path)-1] == '~'
 }
 
-// TODO(bep) split this file in two => template_funcs.go + tests.
-
 const baseAceFilename = "baseof.ace"
 
 var aceTemplateInnerMarker = []byte("= content")
@@ -1441,82 +314,3 @@ func (t *GoHTMLTemplate) PrintErrors() {
                jww.ERROR.Println(e.err)
        }
 }
-
-func init() {
-       funcMap = template.FuncMap{
-               "urlize":      helpers.URLize,
-               "sanitizeURL": helpers.SanitizeURL,
-               "sanitizeurl": helpers.SanitizeURL,
-               "eq":          Eq,
-               "ne":          Ne,
-               "gt":          Gt,
-               "ge":          Ge,
-               "lt":          Lt,
-               "le":          Le,
-               "in":          In,
-               "slicestr":    Slicestr,
-               "substr":      Substr,
-               "split":       Split,
-               "intersect":   Intersect,
-               "isSet":       IsSet,
-               "isset":       IsSet,
-               "echoParam":   ReturnWhenSet,
-               "safeHTML":    SafeHTML,
-               "safeCSS":     SafeCSS,
-               "safeURL":     SafeURL,
-               "markdownify": Markdownify,
-               "first":       First,
-               "where":       Where,
-               "delimit":     Delimit,
-               "sort":        Sort,
-               "highlight":   Highlight,
-               "add":         func(a, b interface{}) (interface{}, error) { return doArithmetic(a, b, '+') },
-               "sub":         func(a, b interface{}) (interface{}, error) { return doArithmetic(a, b, '-') },
-               "div":         func(a, b interface{}) (interface{}, error) { return doArithmetic(a, b, '/') },
-               "mod":         Mod,
-               "mul":         func(a, b interface{}) (interface{}, error) { return doArithmetic(a, b, '*') },
-               "modBool":     ModBool,
-               "lower":       func(a string) string { return strings.ToLower(a) },
-               "upper":       func(a string) string { return strings.ToUpper(a) },
-               "title":       func(a string) string { return strings.Title(a) },
-               "partial":     Partial,
-               "ref":         Ref,
-               "relref":      RelRef,
-               "apply":       Apply,
-               "chomp":       Chomp,
-               "replace":     Replace,
-               "trim":        Trim,
-               "dateFormat":  DateFormat,
-               "getJSON":     GetJSON,
-               "getCSV":      GetCSV,
-               "seq":         helpers.Seq,
-               "getenv":      func(varName string) string { return os.Getenv(varName) },
-
-               // "getJson" is deprecated. Will be removed in 0.15.
-               "getJson": func(urlParts ...string) interface{} {
-                       helpers.Deprecated("Template", "getJson", "getJSON")
-                       return GetJSON(urlParts...)
-               },
-               // "getJson" is deprecated. Will be removed in 0.15.
-               "getCsv": func(sep string, urlParts ...string) [][]string {
-                       helpers.Deprecated("Template", "getCsv", "getCSV")
-                       return GetCSV(sep, urlParts...)
-               },
-               // "safeHtml" is deprecated. Will be removed in 0.15.
-               "safeHtml": func(text string) template.HTML {
-                       helpers.Deprecated("Template", "safeHtml", "safeHTML")
-                       return SafeHTML(text)
-               },
-               // "safeCss" is deprecated. Will be removed in 0.15.
-               "safeCss": func(text string) template.CSS {
-                       helpers.Deprecated("Template", "safeCss", "safeCSS")
-                       return SafeCSS(text)
-               },
-               // "safeUrl" is deprecated. Will be removed in 0.15.
-               "safeUrl": func(text string) template.URL {
-                       helpers.Deprecated("Template", "safeUrl", "safeURL")
-                       return SafeURL(text)
-               },
-       }
-
-}
diff --git a/tpl/template_funcs.go b/tpl/template_funcs.go
new file mode 100644 (file)
index 0000000..996456f
--- /dev/null
@@ -0,0 +1,1228 @@
+// Copyright Â© 2013-14 Steve Francia <spf@spf13.com>.
+//
+// Licensed under the Simple Public License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+// http://opensource.org/licenses/Simple-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package tpl
+
+import (
+       "bytes"
+       "errors"
+       "fmt"
+       "github.com/spf13/cast"
+       "github.com/spf13/hugo/helpers"
+       jww "github.com/spf13/jwalterweatherman"
+       "html"
+       "html/template"
+       "os"
+       "reflect"
+       "sort"
+       "strconv"
+       "strings"
+)
+
+var funcMap template.FuncMap
+
+func Eq(x, y interface{}) bool {
+       normalize := func(v interface{}) interface{} {
+               vv := reflect.ValueOf(v)
+               switch vv.Kind() {
+               case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+                       return vv.Int()
+               case reflect.Float32, reflect.Float64:
+                       return vv.Float()
+               case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
+                       return vv.Uint()
+               default:
+                       return v
+               }
+       }
+       x = normalize(x)
+       y = normalize(y)
+       return reflect.DeepEqual(x, y)
+}
+
+func Ne(x, y interface{}) bool {
+       return !Eq(x, y)
+}
+
+func Ge(a, b interface{}) bool {
+       left, right := compareGetFloat(a, b)
+       return left >= right
+}
+
+func Gt(a, b interface{}) bool {
+       left, right := compareGetFloat(a, b)
+       return left > right
+}
+
+func Le(a, b interface{}) bool {
+       left, right := compareGetFloat(a, b)
+       return left <= right
+}
+
+func Lt(a, b interface{}) bool {
+       left, right := compareGetFloat(a, b)
+       return left < right
+}
+
+func compareGetFloat(a interface{}, b interface{}) (float64, float64) {
+       var left, right float64
+       var leftStr, rightStr *string
+       var err error
+       av := reflect.ValueOf(a)
+
+       switch av.Kind() {
+       case reflect.Array, reflect.Chan, reflect.Map, reflect.Slice:
+               left = float64(av.Len())
+       case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+               left = float64(av.Int())
+       case reflect.Float32, reflect.Float64:
+               left = av.Float()
+       case reflect.String:
+               left, err = strconv.ParseFloat(av.String(), 64)
+               if err != nil {
+                       str := av.String()
+                       leftStr = &str
+               }
+       }
+
+       bv := reflect.ValueOf(b)
+
+       switch bv.Kind() {
+       case reflect.Array, reflect.Chan, reflect.Map, reflect.Slice:
+               right = float64(bv.Len())
+       case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+               right = float64(bv.Int())
+       case reflect.Float32, reflect.Float64:
+               right = bv.Float()
+       case reflect.String:
+               right, err = strconv.ParseFloat(bv.String(), 64)
+               if err != nil {
+                       str := bv.String()
+                       rightStr = &str
+               }
+
+       }
+
+       switch {
+       case leftStr == nil || rightStr == nil:
+       case *leftStr < *rightStr:
+               return 0, 1
+       case *leftStr > *rightStr:
+               return 1, 0
+       default:
+               return 0, 0
+       }
+
+       return left, right
+}
+
+// Slicing in Slicestr is done by specifying a half-open range with
+// two indices, start and end. 1 and 4 creates a slice including elements 1 through 3.
+// The end index can be omitted, it defaults to the string's length.
+func Slicestr(a interface{}, startEnd ...int) (string, error) {
+       aStr, err := cast.ToStringE(a)
+       if err != nil {
+               return "", err
+       }
+
+       if len(startEnd) > 2 {
+               return "", errors.New("too many arguments")
+       }
+
+       if len(startEnd) == 2 {
+               return aStr[startEnd[0]:startEnd[1]], nil
+       } else if len(startEnd) == 1 {
+               return aStr[startEnd[0]:], nil
+       } else {
+               return aStr[:], nil
+       }
+
+}
+
+// Substr extracts parts of a string, beginning at the character at the specified
+// position, and returns the specified number of characters.
+//
+// It normally takes two parameters: start and length.
+// It can also take one parameter: start, i.e. length is omitted, in which case
+// the substring starting from start until the end of the string will be returned.
+//
+// To extract characters from the end of the string, use a negative start number.
+//
+// In addition, borrowing from the extended behavior described at http://php.net/substr,
+// if length is given and is negative, then that many characters will be omitted from
+// the end of string.
+func Substr(a interface{}, nums ...int) (string, error) {
+       aStr, err := cast.ToStringE(a)
+       if err != nil {
+               return "", err
+       }
+
+       var start, length int
+       switch len(nums) {
+       case 1:
+               start = nums[0]
+               length = len(aStr)
+       case 2:
+               start = nums[0]
+               length = nums[1]
+       default:
+               return "", errors.New("too many arguments")
+       }
+
+       if start < -len(aStr) {
+               start = 0
+       }
+       if start > len(aStr) {
+               return "", errors.New(fmt.Sprintf("start position out of bounds for %d-byte string", len(aStr)))
+       }
+
+       var s, e int
+       if start >= 0 && length >= 0 {
+               s = start
+               e = start + length
+       } else if start < 0 && length >= 0 {
+               s = len(aStr) + start - length + 1
+               e = len(aStr) + start + 1
+       } else if start >= 0 && length < 0 {
+               s = start
+               e = len(aStr) + length
+       } else {
+               s = len(aStr) + start
+               e = len(aStr) + length
+       }
+
+       if s > e {
+               return "", errors.New(fmt.Sprintf("calculated start position greater than end position: %d > %d", s, e))
+       }
+       if e > len(aStr) {
+               e = len(aStr)
+       }
+
+       return aStr[s:e], nil
+
+}
+
+func Split(a interface{}, delimiter string) ([]string, error) {
+       aStr, err := cast.ToStringE(a)
+       if err != nil {
+               return []string{}, err
+       }
+       return strings.Split(aStr, delimiter), nil
+}
+
+func Intersect(l1, l2 interface{}) (interface{}, error) {
+       if l1 == nil || l2 == nil {
+               return make([]interface{}, 0), nil
+       }
+
+       l1v := reflect.ValueOf(l1)
+       l2v := reflect.ValueOf(l2)
+
+       switch l1v.Kind() {
+       case reflect.Array, reflect.Slice:
+               switch l2v.Kind() {
+               case reflect.Array, reflect.Slice:
+                       r := reflect.MakeSlice(l1v.Type(), 0, 0)
+                       for i := 0; i < l1v.Len(); i++ {
+                               l1vv := l1v.Index(i)
+                               for j := 0; j < l2v.Len(); j++ {
+                                       l2vv := l2v.Index(j)
+                                       switch l1vv.Kind() {
+                                       case reflect.String:
+                                               if l1vv.Type() == l2vv.Type() && l1vv.String() == l2vv.String() && !In(r, l2vv) {
+                                                       r = reflect.Append(r, l2vv)
+                                               }
+                                       case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+                                               switch l2vv.Kind() {
+                                               case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+                                                       if l1vv.Int() == l2vv.Int() && !In(r, l2vv) {
+                                                               r = reflect.Append(r, l2vv)
+                                                       }
+                                               }
+                                       case reflect.Float32, reflect.Float64:
+                                               switch l2vv.Kind() {
+                                               case reflect.Float32, reflect.Float64:
+                                                       if l1vv.Float() == l2vv.Float() && !In(r, l2vv) {
+                                                               r = reflect.Append(r, l2vv)
+                                                       }
+                                               }
+                                       }
+                               }
+                       }
+                       return r.Interface(), nil
+               default:
+                       return nil, errors.New("can't iterate over " + reflect.ValueOf(l2).Type().String())
+               }
+       default:
+               return nil, errors.New("can't iterate over " + reflect.ValueOf(l1).Type().String())
+       }
+}
+
+func In(l interface{}, v interface{}) bool {
+       lv := reflect.ValueOf(l)
+       vv := reflect.ValueOf(v)
+
+       switch lv.Kind() {
+       case reflect.Array, reflect.Slice:
+               for i := 0; i < lv.Len(); i++ {
+                       lvv := lv.Index(i)
+                       switch lvv.Kind() {
+                       case reflect.String:
+                               if vv.Type() == lvv.Type() && vv.String() == lvv.String() {
+                                       return true
+                               }
+                       case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+                               switch vv.Kind() {
+                               case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+                                       if vv.Int() == lvv.Int() {
+                                               return true
+                                       }
+                               }
+                       case reflect.Float32, reflect.Float64:
+                               switch vv.Kind() {
+                               case reflect.Float32, reflect.Float64:
+                                       if vv.Float() == lvv.Float() {
+                                               return true
+                                       }
+                               }
+                       }
+               }
+       case reflect.String:
+               if vv.Type() == lv.Type() && strings.Contains(lv.String(), vv.String()) {
+                       return true
+               }
+       }
+       return false
+}
+
+// indirect is taken from 'text/template/exec.go'
+func indirect(v reflect.Value) (rv reflect.Value, isNil bool) {
+       for ; v.Kind() == reflect.Ptr || v.Kind() == reflect.Interface; v = v.Elem() {
+               if v.IsNil() {
+                       return v, true
+               }
+               if v.Kind() == reflect.Interface && v.NumMethod() > 0 {
+                       break
+               }
+       }
+       return v, false
+}
+
+// First is exposed to templates, to iterate over the first N items in a
+// rangeable list.
+func First(limit interface{}, seq interface{}) (interface{}, error) {
+
+       if limit == nil || seq == nil {
+               return nil, errors.New("both limit and seq must be provided")
+       }
+
+       limitv, err := cast.ToIntE(limit)
+
+       if err != nil {
+               return nil, err
+       }
+
+       if limitv < 1 {
+               return nil, errors.New("can't return negative/empty count of items from sequence")
+       }
+
+       seqv := reflect.ValueOf(seq)
+       seqv, isNil := indirect(seqv)
+       if isNil {
+               return nil, errors.New("can't iterate over a nil value")
+       }
+
+       switch seqv.Kind() {
+       case reflect.Array, reflect.Slice, reflect.String:
+               // okay
+       default:
+               return nil, errors.New("can't iterate over " + reflect.ValueOf(seq).Type().String())
+       }
+       if limitv > seqv.Len() {
+               limitv = seqv.Len()
+       }
+       return seqv.Slice(0, limitv).Interface(), nil
+}
+
+var (
+       zero      reflect.Value
+       errorType = reflect.TypeOf((*error)(nil)).Elem()
+)
+
+func evaluateSubElem(obj reflect.Value, elemName string) (reflect.Value, error) {
+       if !obj.IsValid() {
+               return zero, errors.New("can't evaluate an invalid value")
+       }
+       typ := obj.Type()
+       obj, isNil := indirect(obj)
+
+       // first, check whether obj has a method. In this case, obj is
+       // an interface, a struct or its pointer. If obj is a struct,
+       // to check all T and *T method, use obj pointer type Value
+       objPtr := obj
+       if objPtr.Kind() != reflect.Interface && objPtr.CanAddr() {
+               objPtr = objPtr.Addr()
+       }
+       mt, ok := objPtr.Type().MethodByName(elemName)
+       if ok {
+               if mt.PkgPath != "" {
+                       return zero, fmt.Errorf("%s is an unexported method of type %s", elemName, typ)
+               }
+               // struct pointer has one receiver argument and interface doesn't have an argument
+               if mt.Type.NumIn() > 1 || mt.Type.NumOut() == 0 || mt.Type.NumOut() > 2 {
+                       return zero, fmt.Errorf("%s is a method of type %s but doesn't satisfy requirements", elemName, typ)
+               }
+               if mt.Type.NumOut() == 1 && mt.Type.Out(0).Implements(errorType) {
+                       return zero, fmt.Errorf("%s is a method of type %s but doesn't satisfy requirements", elemName, typ)
+               }
+               if mt.Type.NumOut() == 2 && !mt.Type.Out(1).Implements(errorType) {
+                       return zero, fmt.Errorf("%s is a method of type %s but doesn't satisfy requirements", elemName, typ)
+               }
+               res := objPtr.Method(mt.Index).Call([]reflect.Value{})
+               if len(res) == 2 && !res[1].IsNil() {
+                       return zero, fmt.Errorf("error at calling a method %s of type %s: %s", elemName, typ, res[1].Interface().(error))
+               }
+               return res[0], nil
+       }
+
+       // elemName isn't a method so next start to check whether it is
+       // a struct field or a map value. In both cases, it mustn't be
+       // a nil value
+       if isNil {
+               return zero, fmt.Errorf("can't evaluate a nil pointer of type %s by a struct field or map key name %s", typ, elemName)
+       }
+       switch obj.Kind() {
+       case reflect.Struct:
+               ft, ok := obj.Type().FieldByName(elemName)
+               if ok {
+                       if ft.PkgPath != "" {
+                               return zero, fmt.Errorf("%s is an unexported field of struct type %s", elemName, typ)
+                       }
+                       return obj.FieldByIndex(ft.Index), nil
+               }
+               return zero, fmt.Errorf("%s isn't a field of struct type %s", elemName, typ)
+       case reflect.Map:
+               kv := reflect.ValueOf(elemName)
+               if kv.Type().AssignableTo(obj.Type().Key()) {
+                       return obj.MapIndex(kv), nil
+               }
+               return zero, fmt.Errorf("%s isn't a key of map type %s", elemName, typ)
+       }
+       return zero, fmt.Errorf("%s is neither a struct field, a method nor a map element of type %s", elemName, typ)
+}
+
+func checkCondition(v, mv reflect.Value, op string) (bool, error) {
+       if !v.IsValid() || !mv.IsValid() {
+               return false, nil
+       }
+
+       var isNil bool
+       v, isNil = indirect(v)
+       if isNil {
+               return false, nil
+       }
+       mv, isNil = indirect(mv)
+       if isNil {
+               return false, nil
+       }
+
+       var ivp, imvp *int64
+       var svp, smvp *string
+       var ima []int64
+       var sma []string
+       if mv.Type() == v.Type() {
+               switch v.Kind() {
+               case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+                       iv := v.Int()
+                       ivp = &iv
+                       imv := mv.Int()
+                       imvp = &imv
+               case reflect.String:
+                       sv := v.String()
+                       svp = &sv
+                       smv := mv.String()
+                       smvp = &smv
+               }
+       } else {
+               if mv.Kind() != reflect.Array && mv.Kind() != reflect.Slice {
+                       return false, nil
+               }
+               if mv.Type().Elem() != v.Type() {
+                       return false, nil
+               }
+               switch v.Kind() {
+               case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+                       iv := v.Int()
+                       ivp = &iv
+                       for i := 0; i < mv.Len(); i++ {
+                               ima = append(ima, mv.Index(i).Int())
+                       }
+               case reflect.String:
+                       sv := v.String()
+                       svp = &sv
+                       for i := 0; i < mv.Len(); i++ {
+                               sma = append(sma, mv.Index(i).String())
+                       }
+               }
+       }
+
+       switch op {
+       case "", "=", "==", "eq":
+               if ivp != nil && imvp != nil {
+                       return *ivp == *imvp, nil
+               } else if svp != nil && smvp != nil {
+                       return *svp == *smvp, nil
+               }
+       case "!=", "<>", "ne":
+               if ivp != nil && imvp != nil {
+                       return *ivp != *imvp, nil
+               } else if svp != nil && smvp != nil {
+                       return *svp != *smvp, nil
+               }
+       case ">=", "ge":
+               if ivp != nil && imvp != nil {
+                       return *ivp >= *imvp, nil
+               } else if svp != nil && smvp != nil {
+                       return *svp >= *smvp, nil
+               }
+       case ">", "gt":
+               if ivp != nil && imvp != nil {
+                       return *ivp > *imvp, nil
+               } else if svp != nil && smvp != nil {
+                       return *svp > *smvp, nil
+               }
+       case "<=", "le":
+               if ivp != nil && imvp != nil {
+                       return *ivp <= *imvp, nil
+               } else if svp != nil && smvp != nil {
+                       return *svp <= *smvp, nil
+               }
+       case "<", "lt":
+               if ivp != nil && imvp != nil {
+                       return *ivp < *imvp, nil
+               } else if svp != nil && smvp != nil {
+                       return *svp < *smvp, nil
+               }
+       case "in", "not in":
+               var r bool
+               if ivp != nil && len(ima) > 0 {
+                       r = In(ima, *ivp)
+               } else if svp != nil {
+                       if len(sma) > 0 {
+                               r = In(sma, *svp)
+                       } else if smvp != nil {
+                               r = In(*smvp, *svp)
+                       }
+               } else {
+                       return false, nil
+               }
+               if op == "not in" {
+                       return !r, nil
+               } else {
+                       return r, nil
+               }
+       default:
+               return false, errors.New("no such an operator")
+       }
+       return false, nil
+}
+
+func Where(seq, key interface{}, args ...interface{}) (r interface{}, err error) {
+       seqv := reflect.ValueOf(seq)
+       kv := reflect.ValueOf(key)
+
+       var mv reflect.Value
+       var op string
+       switch len(args) {
+       case 1:
+               mv = reflect.ValueOf(args[0])
+       case 2:
+               var ok bool
+               if op, ok = args[0].(string); !ok {
+                       return nil, errors.New("operator argument must be string type")
+               }
+               op = strings.TrimSpace(strings.ToLower(op))
+               mv = reflect.ValueOf(args[1])
+       default:
+               return nil, errors.New("can't evaluate the array by no match argument or more than or equal to two arguments")
+       }
+
+       seqv, isNil := indirect(seqv)
+       if isNil {
+               return nil, errors.New("can't iterate over a nil value of type " + reflect.ValueOf(seq).Type().String())
+       }
+
+       var path []string
+       if kv.Kind() == reflect.String {
+               path = strings.Split(strings.Trim(kv.String(), "."), ".")
+       }
+
+       switch seqv.Kind() {
+       case reflect.Array, reflect.Slice:
+               rv := reflect.MakeSlice(seqv.Type(), 0, 0)
+               for i := 0; i < seqv.Len(); i++ {
+                       var vvv reflect.Value
+                       rvv := seqv.Index(i)
+                       if kv.Kind() == reflect.String {
+                               vvv = rvv
+                               for _, elemName := range path {
+                                       vvv, err = evaluateSubElem(vvv, elemName)
+                                       if err != nil {
+                                               return nil, err
+                                       }
+                               }
+                       } else {
+                               vv, _ := indirect(rvv)
+                               if vv.Kind() == reflect.Map && kv.Type().AssignableTo(vv.Type().Key()) {
+                                       vvv = vv.MapIndex(kv)
+                               }
+                       }
+                       if ok, err := checkCondition(vvv, mv, op); ok {
+                               rv = reflect.Append(rv, rvv)
+                       } else if err != nil {
+                               return nil, err
+                       }
+               }
+               return rv.Interface(), nil
+       default:
+               return nil, errors.New("can't iterate over " + reflect.ValueOf(seq).Type().String())
+       }
+}
+
+// Apply, given a map, array, or slice, returns a new slice with the function fname applied over it.
+func Apply(seq interface{}, fname string, args ...interface{}) (interface{}, error) {
+       if seq == nil {
+               return make([]interface{}, 0), nil
+       }
+
+       if fname == "apply" {
+               return nil, errors.New("can't apply myself (no turtles allowed)")
+       }
+
+       seqv := reflect.ValueOf(seq)
+       seqv, isNil := indirect(seqv)
+       if isNil {
+               return nil, errors.New("can't iterate over a nil value")
+       }
+
+       fn, found := funcMap[fname]
+       if !found {
+               return nil, errors.New("can't find function " + fname)
+       }
+
+       fnv := reflect.ValueOf(fn)
+
+       switch seqv.Kind() {
+       case reflect.Array, reflect.Slice:
+               r := make([]interface{}, seqv.Len())
+               for i := 0; i < seqv.Len(); i++ {
+                       vv := seqv.Index(i)
+
+                       vvv, err := applyFnToThis(fnv, vv, args...)
+
+                       if err != nil {
+                               return nil, err
+                       }
+
+                       r[i] = vvv.Interface()
+               }
+
+               return r, nil
+       default:
+               return nil, errors.New("can't apply over " + reflect.ValueOf(seq).Type().String())
+       }
+}
+
+func applyFnToThis(fn, this reflect.Value, args ...interface{}) (reflect.Value, error) {
+       n := make([]reflect.Value, len(args))
+       for i, arg := range args {
+               if arg == "." {
+                       n[i] = this
+               } else {
+                       n[i] = reflect.ValueOf(arg)
+               }
+       }
+
+       res := fn.Call(n)
+
+       if len(res) == 1 || res[1].IsNil() {
+               return res[0], nil
+       } else {
+               return reflect.ValueOf(nil), res[1].Interface().(error)
+       }
+}
+
+func Delimit(seq, delimiter interface{}, last ...interface{}) (template.HTML, error) {
+       d, err := cast.ToStringE(delimiter)
+       if err != nil {
+               return "", err
+       }
+
+       var dLast *string
+       for _, l := range last {
+               dStr, err := cast.ToStringE(l)
+               if err != nil {
+                       dLast = nil
+               }
+               dLast = &dStr
+               break
+       }
+
+       seqv := reflect.ValueOf(seq)
+       seqv, isNil := indirect(seqv)
+       if isNil {
+               return "", errors.New("can't iterate over a nil value")
+       }
+
+       var str string
+       switch seqv.Kind() {
+       case reflect.Map:
+               sortSeq, err := Sort(seq)
+               if err != nil {
+                       return "", err
+               }
+               seqv = reflect.ValueOf(sortSeq)
+               fallthrough
+       case reflect.Array, reflect.Slice, reflect.String:
+               for i := 0; i < seqv.Len(); i++ {
+                       val := seqv.Index(i).Interface()
+                       valStr, err := cast.ToStringE(val)
+                       if err != nil {
+                               continue
+                       }
+                       switch {
+                       case i == seqv.Len()-2 && dLast != nil:
+                               str += valStr + *dLast
+                       case i == seqv.Len()-1:
+                               str += valStr
+                       default:
+                               str += valStr + d
+                       }
+               }
+
+       default:
+               return "", errors.New("can't iterate over " + reflect.ValueOf(seq).Type().String())
+       }
+
+       return template.HTML(str), nil
+}
+
+func Sort(seq interface{}, args ...interface{}) ([]interface{}, error) {
+       seqv := reflect.ValueOf(seq)
+       seqv, isNil := indirect(seqv)
+       if isNil {
+               return nil, errors.New("can't iterate over a nil value")
+       }
+
+       // Create a list of pairs that will be used to do the sort
+       p := pairList{SortAsc: true}
+       p.Pairs = make([]pair, seqv.Len())
+
+       for i, l := range args {
+               dStr, err := cast.ToStringE(l)
+               switch {
+               case i == 0 && err != nil:
+                       p.SortByField = ""
+               case i == 0 && err == nil:
+                       p.SortByField = dStr
+               case i == 1 && err == nil && dStr == "desc":
+                       p.SortAsc = false
+               case i == 1:
+                       p.SortAsc = true
+               }
+       }
+
+       var sorted []interface{}
+       switch seqv.Kind() {
+       case reflect.Array, reflect.Slice:
+               for i := 0; i < seqv.Len(); i++ {
+                       p.Pairs[i].Key = reflect.ValueOf(i)
+                       p.Pairs[i].Value = seqv.Index(i)
+               }
+               if p.SortByField == "" {
+                       p.SortByField = "value"
+               }
+
+       case reflect.Map:
+               keys := seqv.MapKeys()
+               for i := 0; i < seqv.Len(); i++ {
+                       p.Pairs[i].Key = keys[i]
+                       p.Pairs[i].Value = seqv.MapIndex(keys[i])
+               }
+
+       default:
+               return nil, errors.New("can't sort " + reflect.ValueOf(seq).Type().String())
+       }
+       sorted = p.sort()
+       return sorted, nil
+}
+
+// Credit for pair sorting method goes to Andrew Gerrand
+// https://groups.google.com/forum/#!topic/golang-nuts/FT7cjmcL7gw
+// A data structure to hold a key/value pair.
+type pair struct {
+       Key   reflect.Value
+       Value reflect.Value
+}
+
+// A slice of pairs that implements sort.Interface to sort by Value.
+type pairList struct {
+       Pairs       []pair
+       SortByField string
+       SortAsc     bool
+}
+
+func (p pairList) Swap(i, j int) { p.Pairs[i], p.Pairs[j] = p.Pairs[j], p.Pairs[i] }
+func (p pairList) Len() int      { return len(p.Pairs) }
+func (p pairList) Less(i, j int) bool {
+       var truth bool
+       switch {
+       case p.SortByField == "value":
+               iVal := p.Pairs[i].Value
+               jVal := p.Pairs[j].Value
+               truth = Lt(iVal.Interface(), jVal.Interface())
+
+       case p.SortByField != "":
+               if p.Pairs[i].Value.FieldByName(p.SortByField).IsValid() {
+                       iVal := p.Pairs[i].Value.FieldByName(p.SortByField)
+                       jVal := p.Pairs[j].Value.FieldByName(p.SortByField)
+                       truth = Lt(iVal.Interface(), jVal.Interface())
+               }
+       default:
+               iVal := p.Pairs[i].Key
+               jVal := p.Pairs[j].Key
+               truth = Lt(iVal.Interface(), jVal.Interface())
+       }
+       return truth
+}
+
+// sorts a pairList and returns a slice of sorted values
+func (p pairList) sort() []interface{} {
+       if p.SortAsc {
+               sort.Sort(p)
+       } else {
+               sort.Sort(sort.Reverse(p))
+       }
+       sorted := make([]interface{}, len(p.Pairs))
+       for i, v := range p.Pairs {
+               sorted[i] = v.Value.Interface()
+       }
+
+       return sorted
+}
+
+func IsSet(a interface{}, key interface{}) bool {
+       av := reflect.ValueOf(a)
+       kv := reflect.ValueOf(key)
+
+       switch av.Kind() {
+       case reflect.Array, reflect.Chan, reflect.Slice:
+               if int64(av.Len()) > kv.Int() {
+                       return true
+               }
+       case reflect.Map:
+               if kv.Type() == av.Type().Key() {
+                       return av.MapIndex(kv).IsValid()
+               }
+       }
+
+       return false
+}
+
+func ReturnWhenSet(a, k interface{}) interface{} {
+       av, isNil := indirect(reflect.ValueOf(a))
+       if isNil {
+               return ""
+       }
+
+       var avv reflect.Value
+       switch av.Kind() {
+       case reflect.Array, reflect.Slice:
+               index, ok := k.(int)
+               if ok && av.Len() > index {
+                       avv = av.Index(index)
+               }
+       case reflect.Map:
+               kv := reflect.ValueOf(k)
+               if kv.Type().AssignableTo(av.Type().Key()) {
+                       avv = av.MapIndex(kv)
+               }
+       }
+
+       if avv.IsValid() {
+               switch avv.Kind() {
+               case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+                       return avv.Int()
+               case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
+                       return avv.Uint()
+               case reflect.Float32, reflect.Float64:
+                       return avv.Float()
+               case reflect.String:
+                       return avv.String()
+               }
+       }
+
+       return ""
+}
+
+func Highlight(in interface{}, lang string) template.HTML {
+       var str string
+       av := reflect.ValueOf(in)
+       switch av.Kind() {
+       case reflect.String:
+               str = av.String()
+       }
+
+       return template.HTML(helpers.Highlight(html.UnescapeString(str), lang))
+}
+
+var markdownTrimPrefix = []byte("<p>")
+var markdownTrimSuffix = []byte("</p>\n")
+
+func Markdownify(text string) template.HTML {
+       m := helpers.RenderBytes(&helpers.RenderingContext{Content: []byte(text), PageFmt: "markdown"})
+       m = bytes.TrimPrefix(m, markdownTrimPrefix)
+       m = bytes.TrimSuffix(m, markdownTrimSuffix)
+       return template.HTML(m)
+}
+
+func refPage(page interface{}, ref, methodName string) template.HTML {
+       value := reflect.ValueOf(page)
+
+       method := value.MethodByName(methodName)
+
+       if method.IsValid() && method.Type().NumIn() == 1 && method.Type().NumOut() == 2 {
+               result := method.Call([]reflect.Value{reflect.ValueOf(ref)})
+
+               url, err := result[0], result[1]
+
+               if !err.IsNil() {
+                       jww.ERROR.Printf("%s", err.Interface())
+                       return template.HTML(fmt.Sprintf("%s", err.Interface()))
+               }
+
+               if url.String() == "" {
+                       jww.ERROR.Printf("ref %s could not be found\n", ref)
+                       return template.HTML(ref)
+               }
+
+               return template.HTML(url.String())
+       }
+
+       jww.ERROR.Printf("Can only create references from Page and Node objects.")
+       return template.HTML(ref)
+}
+
+func Ref(page interface{}, ref string) template.HTML {
+       return refPage(page, ref, "Ref")
+}
+
+func RelRef(page interface{}, ref string) template.HTML {
+       return refPage(page, ref, "RelRef")
+}
+
+func Chomp(text interface{}) (string, error) {
+       s, err := cast.ToStringE(text)
+       if err != nil {
+               return "", err
+       }
+
+       return strings.TrimRight(s, "\r\n"), nil
+}
+
+// Trim leading/trailing characters defined by b from a
+func Trim(a interface{}, b string) (string, error) {
+       aStr, err := cast.ToStringE(a)
+       if err != nil {
+               return "", err
+       }
+       return strings.Trim(aStr, b), nil
+}
+
+// Replace all occurences of b with c in a
+func Replace(a, b, c interface{}) (string, error) {
+       aStr, err := cast.ToStringE(a)
+       if err != nil {
+               return "", err
+       }
+       bStr, err := cast.ToStringE(b)
+       if err != nil {
+               return "", err
+       }
+       cStr, err := cast.ToStringE(c)
+       if err != nil {
+               return "", err
+       }
+       return strings.Replace(aStr, bStr, cStr, -1), nil
+}
+
+// DateFormat converts the textual representation of the datetime string into
+// the other form or returns it of the time.Time value. These are formatted
+// with the layout string
+func DateFormat(layout string, v interface{}) (string, error) {
+       t, err := cast.ToTimeE(v)
+       if err != nil {
+               return "", err
+       }
+       return t.Format(layout), nil
+}
+
+func SafeHTML(text string) template.HTML {
+       return template.HTML(text)
+}
+
+// "safeHTMLAttr" is currently disabled, pending further discussion
+// on its use case.  2015-01-19
+func SafeHTMLAttr(text string) template.HTMLAttr {
+       return template.HTMLAttr(text)
+}
+
+func SafeCSS(text string) template.CSS {
+       return template.CSS(text)
+}
+
+func SafeURL(text string) template.URL {
+       return template.URL(text)
+}
+
+func doArithmetic(a, b interface{}, op rune) (interface{}, error) {
+       av := reflect.ValueOf(a)
+       bv := reflect.ValueOf(b)
+       var ai, bi int64
+       var af, bf float64
+       var au, bu uint64
+       switch av.Kind() {
+       case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+               ai = av.Int()
+               switch bv.Kind() {
+               case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+                       bi = bv.Int()
+               case reflect.Float32, reflect.Float64:
+                       af = float64(ai) // may overflow
+                       ai = 0
+                       bf = bv.Float()
+               case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
+                       bu = bv.Uint()
+                       if ai >= 0 {
+                               au = uint64(ai)
+                               ai = 0
+                       } else {
+                               bi = int64(bu) // may overflow
+                               bu = 0
+                       }
+               default:
+                       return nil, errors.New("Can't apply the operator to the values")
+               }
+       case reflect.Float32, reflect.Float64:
+               af = av.Float()
+               switch bv.Kind() {
+               case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+                       bf = float64(bv.Int()) // may overflow
+               case reflect.Float32, reflect.Float64:
+                       bf = bv.Float()
+               case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
+                       bf = float64(bv.Uint()) // may overflow
+               default:
+                       return nil, errors.New("Can't apply the operator to the values")
+               }
+       case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
+               au = av.Uint()
+               switch bv.Kind() {
+               case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+                       bi = bv.Int()
+                       if bi >= 0 {
+                               bu = uint64(bi)
+                               bi = 0
+                       } else {
+                               ai = int64(au) // may overflow
+                               au = 0
+                       }
+               case reflect.Float32, reflect.Float64:
+                       af = float64(au) // may overflow
+                       au = 0
+                       bf = bv.Float()
+               case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
+                       bu = bv.Uint()
+               default:
+                       return nil, errors.New("Can't apply the operator to the values")
+               }
+       case reflect.String:
+               as := av.String()
+               if bv.Kind() == reflect.String && op == '+' {
+                       bs := bv.String()
+                       return as + bs, nil
+               } else {
+                       return nil, errors.New("Can't apply the operator to the values")
+               }
+       default:
+               return nil, errors.New("Can't apply the operator to the values")
+       }
+
+       switch op {
+       case '+':
+               if ai != 0 || bi != 0 {
+                       return ai + bi, nil
+               } else if af != 0 || bf != 0 {
+                       return af + bf, nil
+               } else if au != 0 || bu != 0 {
+                       return au + bu, nil
+               } else {
+                       return 0, nil
+               }
+       case '-':
+               if ai != 0 || bi != 0 {
+                       return ai - bi, nil
+               } else if af != 0 || bf != 0 {
+                       return af - bf, nil
+               } else if au != 0 || bu != 0 {
+                       return au - bu, nil
+               } else {
+                       return 0, nil
+               }
+       case '*':
+               if ai != 0 || bi != 0 {
+                       return ai * bi, nil
+               } else if af != 0 || bf != 0 {
+                       return af * bf, nil
+               } else if au != 0 || bu != 0 {
+                       return au * bu, nil
+               } else {
+                       return 0, nil
+               }
+       case '/':
+               if bi != 0 {
+                       return ai / bi, nil
+               } else if bf != 0 {
+                       return af / bf, nil
+               } else if bu != 0 {
+                       return au / bu, nil
+               } else {
+                       return nil, errors.New("Can't divide the value by 0")
+               }
+       default:
+               return nil, errors.New("There is no such an operation")
+       }
+}
+
+func Mod(a, b interface{}) (int64, error) {
+       av := reflect.ValueOf(a)
+       bv := reflect.ValueOf(b)
+       var ai, bi int64
+
+       switch av.Kind() {
+       case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+               ai = av.Int()
+       default:
+               return 0, errors.New("Modulo operator can't be used with non integer value")
+       }
+
+       switch bv.Kind() {
+       case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+               bi = bv.Int()
+       default:
+               return 0, errors.New("Modulo operator can't be used with non integer value")
+       }
+
+       if bi == 0 {
+               return 0, errors.New("The number can't be divided by zero at modulo operation")
+       }
+
+       return ai % bi, nil
+}
+
+func ModBool(a, b interface{}) (bool, error) {
+       res, err := Mod(a, b)
+       if err != nil {
+               return false, err
+       }
+       return res == int64(0), nil
+}
+
+func init() {
+       funcMap = template.FuncMap{
+               "urlize":      helpers.URLize,
+               "sanitizeURL": helpers.SanitizeURL,
+               "sanitizeurl": helpers.SanitizeURL,
+               "eq":          Eq,
+               "ne":          Ne,
+               "gt":          Gt,
+               "ge":          Ge,
+               "lt":          Lt,
+               "le":          Le,
+               "in":          In,
+               "slicestr":    Slicestr,
+               "substr":      Substr,
+               "split":       Split,
+               "intersect":   Intersect,
+               "isSet":       IsSet,
+               "isset":       IsSet,
+               "echoParam":   ReturnWhenSet,
+               "safeHTML":    SafeHTML,
+               "safeCSS":     SafeCSS,
+               "safeURL":     SafeURL,
+               "markdownify": Markdownify,
+               "first":       First,
+               "where":       Where,
+               "delimit":     Delimit,
+               "sort":        Sort,
+               "highlight":   Highlight,
+               "add":         func(a, b interface{}) (interface{}, error) { return doArithmetic(a, b, '+') },
+               "sub":         func(a, b interface{}) (interface{}, error) { return doArithmetic(a, b, '-') },
+               "div":         func(a, b interface{}) (interface{}, error) { return doArithmetic(a, b, '/') },
+               "mod":         Mod,
+               "mul":         func(a, b interface{}) (interface{}, error) { return doArithmetic(a, b, '*') },
+               "modBool":     ModBool,
+               "lower":       func(a string) string { return strings.ToLower(a) },
+               "upper":       func(a string) string { return strings.ToUpper(a) },
+               "title":       func(a string) string { return strings.Title(a) },
+               "partial":     Partial,
+               "ref":         Ref,
+               "relref":      RelRef,
+               "apply":       Apply,
+               "chomp":       Chomp,
+               "replace":     Replace,
+               "trim":        Trim,
+               "dateFormat":  DateFormat,
+               "getJSON":     GetJSON,
+               "getCSV":      GetCSV,
+               "seq":         helpers.Seq,
+               "getenv":      func(varName string) string { return os.Getenv(varName) },
+
+               // "getJson" is deprecated. Will be removed in 0.15.
+               "getJson": func(urlParts ...string) interface{} {
+                       helpers.Deprecated("Template", "getJson", "getJSON")
+                       return GetJSON(urlParts...)
+               },
+               // "getJson" is deprecated. Will be removed in 0.15.
+               "getCsv": func(sep string, urlParts ...string) [][]string {
+                       helpers.Deprecated("Template", "getCsv", "getCSV")
+                       return GetCSV(sep, urlParts...)
+               },
+               // "safeHtml" is deprecated. Will be removed in 0.15.
+               "safeHtml": func(text string) template.HTML {
+                       helpers.Deprecated("Template", "safeHtml", "safeHTML")
+                       return SafeHTML(text)
+               },
+               // "safeCss" is deprecated. Will be removed in 0.15.
+               "safeCss": func(text string) template.CSS {
+                       helpers.Deprecated("Template", "safeCss", "safeCSS")
+                       return SafeCSS(text)
+               },
+               // "safeUrl" is deprecated. Will be removed in 0.15.
+               "safeUrl": func(text string) template.URL {
+                       helpers.Deprecated("Template", "safeUrl", "safeURL")
+                       return SafeURL(text)
+               },
+       }
+
+}
diff --git a/tpl/template_funcs_test.go b/tpl/template_funcs_test.go
new file mode 100644 (file)
index 0000000..8e99f2f
--- /dev/null
@@ -0,0 +1,1222 @@
+package tpl
+
+import (
+       "bytes"
+       "errors"
+       "fmt"
+       "github.com/stretchr/testify/assert"
+       "html/template"
+       "path"
+       "reflect"
+       "runtime"
+       "testing"
+       "time"
+)
+
+type tstNoStringer struct {
+}
+
+type tstCompareType int
+
+const (
+       tstEq tstCompareType = iota
+       tstNe
+       tstGt
+       tstGe
+       tstLt
+       tstLe
+)
+
+func tstIsEq(tp tstCompareType) bool {
+       return tp == tstEq || tp == tstGe || tp == tstLe
+}
+
+func tstIsGt(tp tstCompareType) bool {
+       return tp == tstGt || tp == tstGe
+}
+
+func tstIsLt(tp tstCompareType) bool {
+       return tp == tstLt || tp == tstLe
+}
+
+func TestCompare(t *testing.T) {
+       for _, this := range []struct {
+               tstCompareType
+               funcUnderTest func(a, b interface{}) bool
+       }{
+               {tstGt, Gt},
+               {tstLt, Lt},
+               {tstGe, Ge},
+               {tstLe, Le},
+               {tstEq, Eq},
+               {tstNe, Ne},
+       } {
+               doTestCompare(t, this.tstCompareType, this.funcUnderTest)
+       }
+
+}
+
+func doTestCompare(t *testing.T, tp tstCompareType, funcUnderTest func(a, b interface{}) bool) {
+       for i, this := range []struct {
+               left            interface{}
+               right           interface{}
+               expectIndicator int
+       }{
+               {5, 8, -1},
+               {8, 5, 1},
+               {5, 5, 0},
+               {int(5), int64(5), 0},
+               {int32(5), int(5), 0},
+               {int16(4), int(5), -1},
+               {uint(15), uint64(15), 0},
+               {-2, 1, -1},
+               {2, -5, 1},
+               {0.0, 1.23, -1},
+               {1.1, 1.1, 0},
+               {float32(1.0), float64(1.0), 0},
+               {1.23, 0.0, 1},
+               {"5", "5", 0},
+               {"8", "5", 1},
+               {"5", "0001", 1},
+               {[]int{100, 99}, []int{1, 2, 3, 4}, -1},
+       } {
+               result := funcUnderTest(this.left, this.right)
+               success := false
+
+               if this.expectIndicator == 0 {
+                       if tstIsEq(tp) {
+                               success = result
+                       } else {
+                               success = !result
+                       }
+               }
+
+               if this.expectIndicator < 0 {
+                       success = result && (tstIsLt(tp) || tp == tstNe)
+                       success = success || (!result && !tstIsLt(tp))
+               }
+
+               if this.expectIndicator > 0 {
+                       success = result && (tstIsGt(tp) || tp == tstNe)
+                       success = success || (!result && (!tstIsGt(tp) || tp != tstNe))
+               }
+
+               if !success {
+                       t.Errorf("[%d][%s] %v compared to %v: %t", i, path.Base(runtime.FuncForPC(reflect.ValueOf(funcUnderTest).Pointer()).Name()), this.left, this.right, result)
+               }
+       }
+}
+
+func TestArethmic(t *testing.T) {
+       for i, this := range []struct {
+               a      interface{}
+               b      interface{}
+               op     rune
+               expect interface{}
+       }{
+               {1, 2, '+', int64(3)},
+               {1, 2, '-', int64(-1)},
+               {2, 2, '*', int64(4)},
+               {4, 2, '/', int64(2)},
+               {uint8(1), uint8(3), '+', uint64(4)},
+               {uint8(3), uint8(2), '-', uint64(1)},
+               {uint8(2), uint8(2), '*', uint64(4)},
+               {uint16(4), uint8(2), '/', uint64(2)},
+               {4, 2, '¤', false},
+               {4, 0, '/', false},
+       } {
+               // TODO(bep): Take precision into account.
+               result, err := doArithmetic(this.a, this.b, this.op)
+               if b, ok := this.expect.(bool); ok && !b {
+                       if err == nil {
+                               t.Errorf("[%d] doArethmic didn't return an expected error", i)
+                       }
+               } else {
+                       if err != nil {
+                               t.Errorf("[%d] failed: %s", i, err)
+                               continue
+                       }
+                       if !reflect.DeepEqual(result, this.expect) {
+                               t.Errorf("[%d] doArethmic got %v (%T) but expected %v (%T)", i, result, result, this.expect, this.expect)
+                       }
+               }
+       }
+}
+
+func TestMod(t *testing.T) {
+       for i, this := range []struct {
+               a      interface{}
+               b      interface{}
+               expect interface{}
+       }{
+               {3, 2, int64(1)},
+               {3, 1, int64(0)},
+               {3, 0, false},
+               {0, 3, int64(0)},
+               {3.1, 2, false},
+               {3, 2.1, false},
+               {3.1, 2.1, false},
+               {int8(3), int8(2), int64(1)},
+               {int16(3), int16(2), int64(1)},
+               {int32(3), int32(2), int64(1)},
+               {int64(3), int64(2), int64(1)},
+       } {
+               result, err := Mod(this.a, this.b)
+               if b, ok := this.expect.(bool); ok && !b {
+                       if err == nil {
+                               t.Errorf("[%d] modulo didn't return an expected error", i)
+                       }
+               } else {
+                       if err != nil {
+                               t.Errorf("[%d] failed: %s", i, err)
+                               continue
+                       }
+                       if !reflect.DeepEqual(result, this.expect) {
+                               t.Errorf("[%d] modulo got %v but expected %v", i, result, this.expect)
+                       }
+               }
+       }
+}
+
+func TestModBool(t *testing.T) {
+       for i, this := range []struct {
+               a      interface{}
+               b      interface{}
+               expect interface{}
+       }{
+               {3, 3, true},
+               {3, 2, false},
+               {3, 1, true},
+               {3, 0, nil},
+               {0, 3, true},
+               {3.1, 2, nil},
+               {3, 2.1, nil},
+               {3.1, 2.1, nil},
+               {int8(3), int8(3), true},
+               {int8(3), int8(2), false},
+               {int16(3), int16(3), true},
+               {int16(3), int16(2), false},
+               {int32(3), int32(3), true},
+               {int32(3), int32(2), false},
+               {int64(3), int64(3), true},
+               {int64(3), int64(2), false},
+       } {
+               result, err := ModBool(this.a, this.b)
+               if this.expect == nil {
+                       if err == nil {
+                               t.Errorf("[%d] modulo didn't return an expected error", i)
+                       }
+               } else {
+                       if err != nil {
+                               t.Errorf("[%d] failed: %s", i, err)
+                               continue
+                       }
+                       if !reflect.DeepEqual(result, this.expect) {
+                               t.Errorf("[%d] modulo got %v but expected %v", i, result, this.expect)
+                       }
+               }
+       }
+}
+
+func TestFirst(t *testing.T) {
+       for i, this := range []struct {
+               count    interface{}
+               sequence interface{}
+               expect   interface{}
+       }{
+               {int(2), []string{"a", "b", "c"}, []string{"a", "b"}},
+               {int32(3), []string{"a", "b"}, []string{"a", "b"}},
+               {int64(2), []int{100, 200, 300}, []int{100, 200}},
+               {100, []int{100, 200}, []int{100, 200}},
+               {"1", []int{100, 200, 300}, []int{100}},
+               {int64(-1), []int{100, 200, 300}, false},
+               {"noint", []int{100, 200, 300}, false},
+               {1, nil, false},
+               {nil, []int{100}, false},
+               {1, t, false},
+       } {
+               results, err := First(this.count, this.sequence)
+               if b, ok := this.expect.(bool); ok && !b {
+                       if err == nil {
+                               t.Errorf("[%d] First didn't return an expected error", i)
+                       }
+               } else {
+                       if err != nil {
+                               t.Errorf("[%d] failed: %s", i, err)
+                               continue
+                       }
+                       if !reflect.DeepEqual(results, this.expect) {
+                               t.Errorf("[%d] First %d items, got %v but expected %v", i, this.count, results, this.expect)
+                       }
+               }
+       }
+}
+
+func TestIn(t *testing.T) {
+       for i, this := range []struct {
+               v1     interface{}
+               v2     interface{}
+               expect bool
+       }{
+               {[]string{"a", "b", "c"}, "b", true},
+               {[]string{"a", "b", "c"}, "d", false},
+               {[]string{"a", "12", "c"}, 12, false},
+               {[]int{1, 2, 4}, 2, true},
+               {[]int{1, 2, 4}, 3, false},
+               {[]float64{1.23, 2.45, 4.67}, 1.23, true},
+               {[]float64{1.234567, 2.45, 4.67}, 1.234568, false},
+               {"this substring should be found", "substring", true},
+               {"this substring should not be found", "subseastring", false},
+       } {
+               result := In(this.v1, this.v2)
+
+               if result != this.expect {
+                       t.Errorf("[%d] Got %v but expected %v", i, result, this.expect)
+               }
+       }
+}
+
+func TestSlicestr(t *testing.T) {
+       for i, this := range []struct {
+               v1     interface{}
+               v2     []int
+               expect interface{}
+       }{
+               {"abc", []int{1, 2}, "b"},
+               {"abc", []int{1, 3}, "bc"},
+               {"abc", []int{0, 1}, "a"},
+               {"abcdef", []int{}, "abcdef"},
+               {"abcdef", []int{0, 6}, "abcdef"},
+               {"abcdef", []int{0, 2}, "ab"},
+               {"abcdef", []int{2}, "cdef"},
+               {123, []int{1, 3}, "23"},
+               {123, []int{1, 2, 3}, false},
+               {tstNoStringer{}, []int{0, 1}, false},
+       } {
+               result, err := Slicestr(this.v1, this.v2...)
+
+               if b, ok := this.expect.(bool); ok && !b {
+                       if err == nil {
+                               t.Errorf("[%d] Slice didn't return an expected error", i)
+                       }
+               } else {
+                       if err != nil {
+                               t.Errorf("[%d] failed: %s", i, err)
+                               continue
+                       }
+                       if !reflect.DeepEqual(result, this.expect) {
+                               t.Errorf("[%d] Got %s but expected %s", i, result, this.expect)
+                       }
+               }
+       }
+}
+
+func TestSubstr(t *testing.T) {
+       for i, this := range []struct {
+               v1     interface{}
+               v2     int
+               v3     int
+               expect interface{}
+       }{
+               {"abc", 1, 2, "bc"},
+               {"abc", 0, 1, "a"},
+               {"abcdef", -1, 2, "ef"},
+               {"abcdef", -3, 3, "bcd"},
+               {"abcdef", 0, -1, "abcde"},
+               {"abcdef", 2, -1, "cde"},
+               {"abcdef", 4, -4, false},
+               {"abcdef", 7, 1, false},
+               {"abcdef", 1, 100, "bcdef"},
+               {"abcdef", -100, 3, "abc"},
+               {"abcdef", -3, -1, "de"},
+               {123, 1, 3, "23"},
+               {1.2e3, 0, 4, "1200"},
+               {tstNoStringer{}, 0, 1, false},
+       } {
+               result, err := Substr(this.v1, this.v2, this.v3)
+
+               if b, ok := this.expect.(bool); ok && !b {
+                       if err == nil {
+                               t.Errorf("[%d] Substr didn't return an expected error", i)
+                       }
+               } else {
+                       if err != nil {
+                               t.Errorf("[%d] failed: %s", i, err)
+                               continue
+                       }
+                       if !reflect.DeepEqual(result, this.expect) {
+                               t.Errorf("[%d] Got %s but expected %s", i, result, this.expect)
+                       }
+               }
+       }
+}
+
+func TestSplit(t *testing.T) {
+       for i, this := range []struct {
+               v1     interface{}
+               v2     string
+               expect interface{}
+       }{
+               {"a, b", ", ", []string{"a", "b"}},
+               {"a & b & c", " & ", []string{"a", "b", "c"}},
+               {"http://exmaple.com", "http://", []string{"", "exmaple.com"}},
+               {123, "2", []string{"1", "3"}},
+               {tstNoStringer{}, ",", false},
+       } {
+               result, err := Split(this.v1, this.v2)
+
+               if b, ok := this.expect.(bool); ok && !b {
+                       if err == nil {
+                               t.Errorf("[%d] Split didn't return an expected error", i)
+                       }
+               } else {
+                       if err != nil {
+                               t.Errorf("[%d] failed: %s", i, err)
+                               continue
+                       }
+                       if !reflect.DeepEqual(result, this.expect) {
+                               t.Errorf("[%d] Got %s but expected %s", i, result, this.expect)
+                       }
+               }
+       }
+
+}
+
+func TestIntersect(t *testing.T) {
+       for i, this := range []struct {
+               sequence1 interface{}
+               sequence2 interface{}
+               expect    interface{}
+       }{
+               {[]string{"a", "b", "c"}, []string{"a", "b"}, []string{"a", "b"}},
+               {[]string{"a", "b"}, []string{"a", "b", "c"}, []string{"a", "b"}},
+               {[]string{"a", "b", "c"}, []string{"d", "e"}, []string{}},
+               {[]string{}, []string{}, []string{}},
+               {[]string{"a", "b"}, nil, make([]interface{}, 0)},
+               {nil, []string{"a", "b"}, make([]interface{}, 0)},
+               {nil, nil, make([]interface{}, 0)},
+               {[]string{"1", "2"}, []int{1, 2}, []string{}},
+               {[]int{1, 2}, []string{"1", "2"}, []int{}},
+               {[]int{1, 2, 4}, []int{2, 4}, []int{2, 4}},
+               {[]int{2, 4}, []int{1, 2, 4}, []int{2, 4}},
+               {[]int{1, 2, 4}, []int{3, 6}, []int{}},
+               {[]float64{2.2, 4.4}, []float64{1.1, 2.2, 4.4}, []float64{2.2, 4.4}},
+       } {
+               results, err := Intersect(this.sequence1, this.sequence2)
+               if err != nil {
+                       t.Errorf("[%d] failed: %s", i, err)
+                       continue
+               }
+               if !reflect.DeepEqual(results, this.expect) {
+                       t.Errorf("[%d] Got %v but expected %v", i, results, this.expect)
+               }
+       }
+
+       _, err1 := Intersect("not an array or slice", []string{"a"})
+
+       if err1 == nil {
+               t.Error("Excpected error for non array as first arg")
+       }
+
+       _, err2 := Intersect([]string{"a"}, "not an array or slice")
+
+       if err2 == nil {
+               t.Error("Excpected error for non array as second arg")
+       }
+}
+
+func TestIsSet(t *testing.T) {
+       aSlice := []interface{}{1, 2, 3, 5}
+       aMap := map[string]interface{}{"a": 1, "b": 2}
+
+       assert.True(t, IsSet(aSlice, 2))
+       assert.True(t, IsSet(aMap, "b"))
+       assert.False(t, IsSet(aSlice, 22))
+       assert.False(t, IsSet(aMap, "bc"))
+}
+
+func (x *TstX) TstRp() string {
+       return "r" + x.A
+}
+
+func (x TstX) TstRv() string {
+       return "r" + x.B
+}
+
+func (x TstX) unexportedMethod() string {
+       return x.unexported
+}
+
+func (x TstX) MethodWithArg(s string) string {
+       return s
+}
+
+func (x TstX) MethodReturnNothing() {}
+
+func (x TstX) MethodReturnErrorOnly() error {
+       return errors.New("something error occured")
+}
+
+func (x TstX) MethodReturnTwoValues() (string, string) {
+       return "foo", "bar"
+}
+
+func (x TstX) MethodReturnValueWithError() (string, error) {
+       return "", errors.New("something error occured")
+}
+
+func (x TstX) String() string {
+       return fmt.Sprintf("A: %s, B: %s", x.A, x.B)
+}
+
+type TstX struct {
+       A, B       string
+       unexported string
+}
+
+func TestEvaluateSubElem(t *testing.T) {
+       tstx := TstX{A: "foo", B: "bar"}
+       var inner struct {
+               S fmt.Stringer
+       }
+       inner.S = tstx
+       interfaceValue := reflect.ValueOf(&inner).Elem().Field(0)
+
+       for i, this := range []struct {
+               value  reflect.Value
+               key    string
+               expect interface{}
+       }{
+               {reflect.ValueOf(tstx), "A", "foo"},
+               {reflect.ValueOf(&tstx), "TstRp", "rfoo"},
+               {reflect.ValueOf(tstx), "TstRv", "rbar"},
+               //{reflect.ValueOf(map[int]string{1: "foo", 2: "bar"}), 1, "foo"},
+               {reflect.ValueOf(map[string]string{"key1": "foo", "key2": "bar"}), "key1", "foo"},
+               {interfaceValue, "String", "A: foo, B: bar"},
+               {reflect.Value{}, "foo", false},
+               //{reflect.ValueOf(map[int]string{1: "foo", 2: "bar"}), 1.2, false},
+               {reflect.ValueOf(tstx), "unexported", false},
+               {reflect.ValueOf(tstx), "unexportedMethod", false},
+               {reflect.ValueOf(tstx), "MethodWithArg", false},
+               {reflect.ValueOf(tstx), "MethodReturnNothing", false},
+               {reflect.ValueOf(tstx), "MethodReturnErrorOnly", false},
+               {reflect.ValueOf(tstx), "MethodReturnTwoValues", false},
+               {reflect.ValueOf(tstx), "MethodReturnValueWithError", false},
+               {reflect.ValueOf((*TstX)(nil)), "A", false},
+               {reflect.ValueOf(tstx), "C", false},
+               {reflect.ValueOf(map[int]string{1: "foo", 2: "bar"}), "1", false},
+               {reflect.ValueOf([]string{"foo", "bar"}), "1", false},
+       } {
+               result, err := evaluateSubElem(this.value, this.key)
+               if b, ok := this.expect.(bool); ok && !b {
+                       if err == nil {
+                               t.Errorf("[%d] evaluateSubElem didn't return an expected error", i)
+                       }
+               } else {
+                       if err != nil {
+                               t.Errorf("[%d] failed: %s", i, err)
+                               continue
+                       }
+                       if result.Kind() != reflect.String || result.String() != this.expect {
+                               t.Errorf("[%d] evaluateSubElem with %v got %v but expected %v", i, this.key, result, this.expect)
+                       }
+               }
+       }
+}
+
+func TestCheckCondition(t *testing.T) {
+       type expect struct {
+               result  bool
+               isError bool
+       }
+
+       for i, this := range []struct {
+               value reflect.Value
+               match reflect.Value
+               op    string
+               expect
+       }{
+               {reflect.ValueOf(123), reflect.ValueOf(123), "", expect{true, false}},
+               {reflect.ValueOf("foo"), reflect.ValueOf("foo"), "", expect{true, false}},
+               {reflect.ValueOf(123), reflect.ValueOf(456), "!=", expect{true, false}},
+               {reflect.ValueOf("foo"), reflect.ValueOf("bar"), "!=", expect{true, false}},
+               {reflect.ValueOf(456), reflect.ValueOf(123), ">=", expect{true, false}},
+               {reflect.ValueOf("foo"), reflect.ValueOf("bar"), ">=", expect{true, false}},
+               {reflect.ValueOf(456), reflect.ValueOf(123), ">", expect{true, false}},
+               {reflect.ValueOf("foo"), reflect.ValueOf("bar"), ">", expect{true, false}},
+               {reflect.ValueOf(123), reflect.ValueOf(456), "<=", expect{true, false}},
+               {reflect.ValueOf("bar"), reflect.ValueOf("foo"), "<=", expect{true, false}},
+               {reflect.ValueOf(123), reflect.ValueOf(456), "<", expect{true, false}},
+               {reflect.ValueOf("bar"), reflect.ValueOf("foo"), "<", expect{true, false}},
+               {reflect.ValueOf(123), reflect.ValueOf([]int{123, 45, 678}), "in", expect{true, false}},
+               {reflect.ValueOf("foo"), reflect.ValueOf([]string{"foo", "bar", "baz"}), "in", expect{true, false}},
+               {reflect.ValueOf(123), reflect.ValueOf([]int{45, 678}), "not in", expect{true, false}},
+               {reflect.ValueOf("foo"), reflect.ValueOf([]string{"bar", "baz"}), "not in", expect{true, false}},
+               {reflect.ValueOf("foo"), reflect.ValueOf("bar-foo-baz"), "in", expect{true, false}},
+               {reflect.ValueOf("foo"), reflect.ValueOf("bar--baz"), "not in", expect{true, false}},
+               {reflect.Value{}, reflect.ValueOf("foo"), "", expect{false, false}},
+               {reflect.ValueOf("foo"), reflect.Value{}, "", expect{false, false}},
+               {reflect.ValueOf((*TstX)(nil)), reflect.ValueOf("foo"), "", expect{false, false}},
+               {reflect.ValueOf("foo"), reflect.ValueOf((*TstX)(nil)), "", expect{false, false}},
+               {reflect.ValueOf("foo"), reflect.ValueOf(map[int]string{}), "", expect{false, false}},
+               {reflect.ValueOf("foo"), reflect.ValueOf([]int{1, 2}), "", expect{false, false}},
+               {reflect.ValueOf(123), reflect.ValueOf([]int{}), "in", expect{false, false}},
+               {reflect.ValueOf(123), reflect.ValueOf(123), "op", expect{false, true}},
+       } {
+               result, err := checkCondition(this.value, this.match, this.op)
+               if this.expect.isError {
+                       if err == nil {
+                               t.Errorf("[%d] checkCondition didn't return an expected error", i)
+                       }
+               } else {
+                       if err != nil {
+                               t.Errorf("[%d] failed: %s", i, err)
+                               continue
+                       }
+                       if result != this.expect.result {
+                               t.Errorf("[%d] check condition %v %s %v, got %v but expected %v", i, this.value, this.op, this.match, result, this.expect.result)
+                       }
+               }
+       }
+}
+
+func TestWhere(t *testing.T) {
+       // TODO(spf): Put these page tests back in
+       //page1 := &Page{contentType: "v", Source: Source{File: *source.NewFile("/x/y/z/source.md")}}
+       //page2 := &Page{contentType: "w", Source: Source{File: *source.NewFile("/y/z/a/source.md")}}
+
+       type Mid struct {
+               Tst TstX
+       }
+
+       for i, this := range []struct {
+               sequence interface{}
+               key      interface{}
+               op       string
+               match    interface{}
+               expect   interface{}
+       }{
+               {
+                       sequence: []map[int]string{
+                               {1: "a", 2: "m"}, {1: "c", 2: "d"}, {1: "e", 3: "m"},
+                       },
+                       key: 2, match: "m",
+                       expect: []map[int]string{
+                               {1: "a", 2: "m"},
+                       },
+               },
+               {
+                       sequence: []map[string]int{
+                               {"a": 1, "b": 2}, {"a": 3, "b": 4}, {"a": 5, "x": 4},
+                       },
+                       key: "b", match: 4,
+                       expect: []map[string]int{
+                               {"a": 3, "b": 4},
+                       },
+               },
+               {
+                       sequence: []TstX{
+                               {A: "a", B: "b"}, {A: "c", B: "d"}, {A: "e", B: "f"},
+                       },
+                       key: "B", match: "f",
+                       expect: []TstX{
+                               {A: "e", B: "f"},
+                       },
+               },
+               {
+                       sequence: []*map[int]string{
+                               {1: "a", 2: "m"}, {1: "c", 2: "d"}, {1: "e", 3: "m"},
+                       },
+                       key: 2, match: "m",
+                       expect: []*map[int]string{
+                               {1: "a", 2: "m"},
+                       },
+               },
+               {
+                       sequence: []*TstX{
+                               {A: "a", B: "b"}, {A: "c", B: "d"}, {A: "e", B: "f"},
+                       },
+                       key: "B", match: "f",
+                       expect: []*TstX{
+                               {A: "e", B: "f"},
+                       },
+               },
+               {
+                       sequence: []*TstX{
+                               {A: "a", B: "b"}, {A: "c", B: "d"}, {A: "e", B: "c"},
+                       },
+                       key: "TstRp", match: "rc",
+                       expect: []*TstX{
+                               {A: "c", B: "d"},
+                       },
+               },
+               {
+                       sequence: []TstX{
+                               {A: "a", B: "b"}, {A: "c", B: "d"}, {A: "e", B: "c"},
+                       },
+                       key: "TstRv", match: "rc",
+                       expect: []TstX{
+                               {A: "e", B: "c"},
+                       },
+               },
+               {
+                       sequence: []map[string]TstX{
+                               {"foo": TstX{A: "a", B: "b"}}, {"foo": TstX{A: "c", B: "d"}}, {"foo": TstX{A: "e", B: "f"}},
+                       },
+                       key: "foo.B", match: "d",
+                       expect: []map[string]TstX{
+                               {"foo": TstX{A: "c", B: "d"}},
+                       },
+               },
+               {
+                       sequence: []map[string]TstX{
+                               {"foo": TstX{A: "a", B: "b"}}, {"foo": TstX{A: "c", B: "d"}}, {"foo": TstX{A: "e", B: "f"}},
+                       },
+                       key: ".foo.B", match: "d",
+                       expect: []map[string]TstX{
+                               {"foo": TstX{A: "c", B: "d"}},
+                       },
+               },
+               {
+                       sequence: []map[string]TstX{
+                               {"foo": TstX{A: "a", B: "b"}}, {"foo": TstX{A: "c", B: "d"}}, {"foo": TstX{A: "e", B: "f"}},
+                       },
+                       key: "foo.TstRv", match: "rd",
+                       expect: []map[string]TstX{
+                               {"foo": TstX{A: "c", B: "d"}},
+                       },
+               },
+               {
+                       sequence: []map[string]*TstX{
+                               {"foo": &TstX{A: "a", B: "b"}}, {"foo": &TstX{A: "c", B: "d"}}, {"foo": &TstX{A: "e", B: "f"}},
+                       },
+                       key: "foo.TstRp", match: "rc",
+                       expect: []map[string]*TstX{
+                               {"foo": &TstX{A: "c", B: "d"}},
+                       },
+               },
+               {
+                       sequence: []map[string]Mid{
+                               {"foo": Mid{Tst: TstX{A: "a", B: "b"}}}, {"foo": Mid{Tst: TstX{A: "c", B: "d"}}}, {"foo": Mid{Tst: TstX{A: "e", B: "f"}}},
+                       },
+                       key: "foo.Tst.B", match: "d",
+                       expect: []map[string]Mid{
+                               {"foo": Mid{Tst: TstX{A: "c", B: "d"}}},
+                       },
+               },
+               {
+                       sequence: []map[string]Mid{
+                               {"foo": Mid{Tst: TstX{A: "a", B: "b"}}}, {"foo": Mid{Tst: TstX{A: "c", B: "d"}}}, {"foo": Mid{Tst: TstX{A: "e", B: "f"}}},
+                       },
+                       key: "foo.Tst.TstRv", match: "rd",
+                       expect: []map[string]Mid{
+                               {"foo": Mid{Tst: TstX{A: "c", B: "d"}}},
+                       },
+               },
+               {
+                       sequence: []map[string]*Mid{
+                               {"foo": &Mid{Tst: TstX{A: "a", B: "b"}}}, {"foo": &Mid{Tst: TstX{A: "c", B: "d"}}}, {"foo": &Mid{Tst: TstX{A: "e", B: "f"}}},
+                       },
+                       key: "foo.Tst.TstRp", match: "rc",
+                       expect: []map[string]*Mid{
+                               {"foo": &Mid{Tst: TstX{A: "c", B: "d"}}},
+                       },
+               },
+               {
+                       sequence: []map[string]int{
+                               {"a": 1, "b": 2}, {"a": 3, "b": 4}, {"a": 5, "b": 6},
+                       },
+                       key: "b", op: ">", match: 3,
+                       expect: []map[string]int{
+                               {"a": 3, "b": 4}, {"a": 5, "b": 6},
+                       },
+               },
+               {
+                       sequence: []TstX{
+                               {A: "a", B: "b"}, {A: "c", B: "d"}, {A: "e", B: "f"},
+                       },
+                       key: "B", op: "!=", match: "f",
+                       expect: []TstX{
+                               {A: "a", B: "b"}, {A: "c", B: "d"},
+                       },
+               },
+               {
+                       sequence: []map[string]int{
+                               {"a": 1, "b": 2}, {"a": 3, "b": 4}, {"a": 5, "b": 6},
+                       },
+                       key: "b", op: "in", match: []int{3, 4, 5},
+                       expect: []map[string]int{
+                               {"a": 3, "b": 4},
+                       },
+               },
+               {
+                       sequence: []TstX{
+                               {A: "a", B: "b"}, {A: "c", B: "d"}, {A: "e", B: "f"},
+                       },
+                       key: "B", op: "not in", match: []string{"c", "d", "e"},
+                       expect: []TstX{
+                               {A: "a", B: "b"}, {A: "e", B: "f"},
+                       },
+               },
+               {sequence: (*[]TstX)(nil), key: "A", match: "a", expect: false},
+               {sequence: TstX{A: "a", B: "b"}, key: "A", match: "a", expect: false},
+               {sequence: []map[string]*TstX{{"foo": nil}}, key: "foo.B", match: "d", expect: false},
+               {
+                       sequence: []TstX{
+                               {A: "a", B: "b"}, {A: "c", B: "d"}, {A: "e", B: "f"},
+                       },
+                       key: "B", op: "op", match: "f",
+                       expect: false,
+               },
+               //{[]*Page{page1, page2}, "Type", "v", []*Page{page1}},
+               //{[]*Page{page1, page2}, "Section", "y", []*Page{page2}},
+       } {
+               var results interface{}
+               var err error
+               if len(this.op) > 0 {
+                       results, err = Where(this.sequence, this.key, this.op, this.match)
+               } else {
+                       results, err = Where(this.sequence, this.key, this.match)
+               }
+               if b, ok := this.expect.(bool); ok && !b {
+                       if err == nil {
+                               t.Errorf("[%d] Where didn't return an expected error", i)
+                       }
+               } else {
+                       if err != nil {
+                               t.Errorf("[%d] failed: %s", i, err)
+                               continue
+                       }
+                       if !reflect.DeepEqual(results, this.expect) {
+                               t.Errorf("[%d] Where clause matching %v with %v, got %v but expected %v", i, this.key, this.match, results, this.expect)
+                       }
+               }
+       }
+
+       var err error
+       _, err = Where(map[string]int{"a": 1, "b": 2}, "a", []byte("="), 1)
+       if err == nil {
+               t.Errorf("Where called with none string op value didn't return an expected error")
+       }
+
+       _, err = Where(map[string]int{"a": 1, "b": 2}, "a", []byte("="), 1, 2)
+       if err == nil {
+               t.Errorf("Where called with more than two variable arguments didn't return an expected error")
+       }
+
+       _, err = Where(map[string]int{"a": 1, "b": 2}, "a")
+       if err == nil {
+               t.Errorf("Where called with no variable arguments didn't return an expected error")
+       }
+}
+
+func TestDelimit(t *testing.T) {
+       for i, this := range []struct {
+               sequence  interface{}
+               delimiter interface{}
+               last      interface{}
+               expect    template.HTML
+       }{
+               {[]string{"class1", "class2", "class3"}, " ", nil, "class1 class2 class3"},
+               {[]int{1, 2, 3, 4, 5}, ",", nil, "1,2,3,4,5"},
+               {[]int{1, 2, 3, 4, 5}, ", ", nil, "1, 2, 3, 4, 5"},
+               {[]string{"class1", "class2", "class3"}, " ", " and ", "class1 class2 and class3"},
+               {[]int{1, 2, 3, 4, 5}, ",", ",", "1,2,3,4,5"},
+               {[]int{1, 2, 3, 4, 5}, ", ", ", and ", "1, 2, 3, 4, and 5"},
+               // test maps with and without sorting required
+               {map[string]int{"1": 10, "2": 20, "3": 30, "4": 40, "5": 50}, "--", nil, "10--20--30--40--50"},
+               {map[string]int{"3": 10, "2": 20, "1": 30, "4": 40, "5": 50}, "--", nil, "30--20--10--40--50"},
+               {map[string]string{"1": "10", "2": "20", "3": "30", "4": "40", "5": "50"}, "--", nil, "10--20--30--40--50"},
+               {map[string]string{"3": "10", "2": "20", "1": "30", "4": "40", "5": "50"}, "--", nil, "30--20--10--40--50"},
+               {map[string]string{"one": "10", "two": "20", "three": "30", "four": "40", "five": "50"}, "--", nil, "50--40--10--30--20"},
+               {map[int]string{1: "10", 2: "20", 3: "30", 4: "40", 5: "50"}, "--", nil, "10--20--30--40--50"},
+               {map[int]string{3: "10", 2: "20", 1: "30", 4: "40", 5: "50"}, "--", nil, "30--20--10--40--50"},
+               {map[float64]string{3.3: "10", 2.3: "20", 1.3: "30", 4.3: "40", 5.3: "50"}, "--", nil, "30--20--10--40--50"},
+               // test maps with a last delimiter
+               {map[string]int{"1": 10, "2": 20, "3": 30, "4": 40, "5": 50}, "--", "--and--", "10--20--30--40--and--50"},
+               {map[string]int{"3": 10, "2": 20, "1": 30, "4": 40, "5": 50}, "--", "--and--", "30--20--10--40--and--50"},
+               {map[string]string{"1": "10", "2": "20", "3": "30", "4": "40", "5": "50"}, "--", "--and--", "10--20--30--40--and--50"},
+               {map[string]string{"3": "10", "2": "20", "1": "30", "4": "40", "5": "50"}, "--", "--and--", "30--20--10--40--and--50"},
+               {map[string]string{"one": "10", "two": "20", "three": "30", "four": "40", "five": "50"}, "--", "--and--", "50--40--10--30--and--20"},
+               {map[int]string{1: "10", 2: "20", 3: "30", 4: "40", 5: "50"}, "--", "--and--", "10--20--30--40--and--50"},
+               {map[int]string{3: "10", 2: "20", 1: "30", 4: "40", 5: "50"}, "--", "--and--", "30--20--10--40--and--50"},
+               {map[float64]string{3.5: "10", 2.5: "20", 1.5: "30", 4.5: "40", 5.5: "50"}, "--", "--and--", "30--20--10--40--and--50"},
+       } {
+               var result template.HTML
+               var err error
+               if this.last == nil {
+                       result, err = Delimit(this.sequence, this.delimiter)
+               } else {
+                       result, err = Delimit(this.sequence, this.delimiter, this.last)
+               }
+               if err != nil {
+                       t.Errorf("[%d] failed: %s", i, err)
+                       continue
+               }
+               if !reflect.DeepEqual(result, this.expect) {
+                       t.Errorf("[%d] Delimit called on sequence: %v | delimiter: `%v` | last: `%v`, got %v but expected %v", i, this.sequence, this.delimiter, this.last, result, this.expect)
+               }
+       }
+}
+
+func TestSort(t *testing.T) {
+       type ts struct {
+               MyInt    int
+               MyFloat  float64
+               MyString string
+       }
+       for i, this := range []struct {
+               sequence    interface{}
+               sortByField interface{}
+               sortAsc     string
+               expect      []interface{}
+       }{
+               {[]string{"class1", "class2", "class3"}, nil, "asc", []interface{}{"class1", "class2", "class3"}},
+               {[]string{"class3", "class1", "class2"}, nil, "asc", []interface{}{"class1", "class2", "class3"}},
+               {[]int{1, 2, 3, 4, 5}, nil, "asc", []interface{}{1, 2, 3, 4, 5}},
+               {[]int{5, 4, 3, 1, 2}, nil, "asc", []interface{}{1, 2, 3, 4, 5}},
+               // test map sorting by keys
+               {map[string]int{"1": 10, "2": 20, "3": 30, "4": 40, "5": 50}, nil, "asc", []interface{}{10, 20, 30, 40, 50}},
+               {map[string]int{"3": 10, "2": 20, "1": 30, "4": 40, "5": 50}, nil, "asc", []interface{}{30, 20, 10, 40, 50}},
+               {map[string]string{"1": "10", "2": "20", "3": "30", "4": "40", "5": "50"}, nil, "asc", []interface{}{"10", "20", "30", "40", "50"}},
+               {map[string]string{"3": "10", "2": "20", "1": "30", "4": "40", "5": "50"}, nil, "asc", []interface{}{"30", "20", "10", "40", "50"}},
+               {map[string]string{"one": "10", "two": "20", "three": "30", "four": "40", "five": "50"}, nil, "asc", []interface{}{"50", "40", "10", "30", "20"}},
+               {map[int]string{1: "10", 2: "20", 3: "30", 4: "40", 5: "50"}, nil, "asc", []interface{}{"10", "20", "30", "40", "50"}},
+               {map[int]string{3: "10", 2: "20", 1: "30", 4: "40", 5: "50"}, nil, "asc", []interface{}{"30", "20", "10", "40", "50"}},
+               {map[float64]string{3.3: "10", 2.3: "20", 1.3: "30", 4.3: "40", 5.3: "50"}, nil, "asc", []interface{}{"30", "20", "10", "40", "50"}},
+               // test map sorting by value
+               {map[string]int{"1": 10, "2": 20, "3": 30, "4": 40, "5": 50}, "value", "asc", []interface{}{10, 20, 30, 40, 50}},
+               {map[string]int{"3": 10, "2": 20, "1": 30, "4": 40, "5": 50}, "value", "asc", []interface{}{10, 20, 30, 40, 50}},
+               // test map sorting by field value
+               {
+                       map[string]ts{"1": {10, 10.5, "ten"}, "2": {20, 20.5, "twenty"}, "3": {30, 30.5, "thirty"}, "4": {40, 40.5, "forty"}, "5": {50, 50.5, "fifty"}},
+                       "MyInt",
+                       "asc",
+                       []interface{}{ts{10, 10.5, "ten"}, ts{20, 20.5, "twenty"}, ts{30, 30.5, "thirty"}, ts{40, 40.5, "forty"}, ts{50, 50.5, "fifty"}},
+               },
+               {
+                       map[string]ts{"1": {10, 10.5, "ten"}, "2": {20, 20.5, "twenty"}, "3": {30, 30.5, "thirty"}, "4": {40, 40.5, "forty"}, "5": {50, 50.5, "fifty"}},
+                       "MyFloat",
+                       "asc",
+                       []interface{}{ts{10, 10.5, "ten"}, ts{20, 20.5, "twenty"}, ts{30, 30.5, "thirty"}, ts{40, 40.5, "forty"}, ts{50, 50.5, "fifty"}},
+               },
+               {
+                       map[string]ts{"1": {10, 10.5, "ten"}, "2": {20, 20.5, "twenty"}, "3": {30, 30.5, "thirty"}, "4": {40, 40.5, "forty"}, "5": {50, 50.5, "fifty"}},
+                       "MyString",
+                       "asc",
+                       []interface{}{ts{50, 50.5, "fifty"}, ts{40, 40.5, "forty"}, ts{10, 10.5, "ten"}, ts{30, 30.5, "thirty"}, ts{20, 20.5, "twenty"}},
+               },
+               // Test sort desc
+               {[]string{"class1", "class2", "class3"}, "value", "desc", []interface{}{"class3", "class2", "class1"}},
+               {[]string{"class3", "class1", "class2"}, "value", "desc", []interface{}{"class3", "class2", "class1"}},
+       } {
+               var result []interface{}
+               var err error
+               if this.sortByField == nil {
+                       result, err = Sort(this.sequence)
+               } else {
+                       result, err = Sort(this.sequence, this.sortByField, this.sortAsc)
+               }
+               if err != nil {
+                       t.Errorf("[%d] failed: %s", i, err)
+                       continue
+               }
+               if !reflect.DeepEqual(result, this.expect) {
+                       t.Errorf("[%d] Sort called on sequence: %v | sortByField: `%v` | got %v but expected %v", i, this.sequence, this.sortByField, result, this.expect)
+               }
+       }
+}
+
+func TestReturnWhenSet(t *testing.T) {
+       for i, this := range []struct {
+               data   interface{}
+               key    interface{}
+               expect interface{}
+       }{
+               {[]int{1, 2, 3}, 1, int64(2)},
+               {[]uint{1, 2, 3}, 1, uint64(2)},
+               {[]float64{1.1, 2.2, 3.3}, 1, float64(2.2)},
+               {[]string{"foo", "bar", "baz"}, 1, "bar"},
+               {[]TstX{{A: "a", B: "b"}, {A: "c", B: "d"}, {A: "e", B: "f"}}, 1, ""},
+               {map[string]int{"foo": 1, "bar": 2, "baz": 3}, "bar", int64(2)},
+               {map[string]uint{"foo": 1, "bar": 2, "baz": 3}, "bar", uint64(2)},
+               {map[string]float64{"foo": 1.1, "bar": 2.2, "baz": 3.3}, "bar", float64(2.2)},
+               {map[string]string{"foo": "FOO", "bar": "BAR", "baz": "BAZ"}, "bar", "BAR"},
+               {map[string]TstX{"foo": {A: "a", B: "b"}, "bar": {A: "c", B: "d"}, "baz": {A: "e", B: "f"}}, "bar", ""},
+               {(*[]string)(nil), "bar", ""},
+       } {
+               result := ReturnWhenSet(this.data, this.key)
+               if !reflect.DeepEqual(result, this.expect) {
+                       t.Errorf("[%d] ReturnWhenSet got %v (type %v) but expected %v (type %v)", i, result, reflect.TypeOf(result), this.expect, reflect.TypeOf(this.expect))
+               }
+       }
+}
+
+func TestMarkdownify(t *testing.T) {
+
+       result := Markdownify("Hello **World!**")
+
+       expect := template.HTML("Hello <strong>World!</strong>")
+
+       if result != expect {
+               t.Errorf("Markdownify: got '%s', expected '%s'", result, expect)
+       }
+}
+
+func TestApply(t *testing.T) {
+       strings := []interface{}{"a\n", "b\n"}
+       noStringers := []interface{}{tstNoStringer{}, tstNoStringer{}}
+
+       var nilErr *error = nil
+
+       chomped, _ := Apply(strings, "chomp", ".")
+       assert.Equal(t, []interface{}{"a", "b"}, chomped)
+
+       chomped, _ = Apply(strings, "chomp", "c\n")
+       assert.Equal(t, []interface{}{"c", "c"}, chomped)
+
+       chomped, _ = Apply(nil, "chomp", ".")
+       assert.Equal(t, []interface{}{}, chomped)
+
+       _, err := Apply(strings, "apply", ".")
+       if err == nil {
+               t.Errorf("apply with apply should fail")
+       }
+
+       _, err = Apply(nilErr, "chomp", ".")
+       if err == nil {
+               t.Errorf("apply with nil in seq should fail")
+       }
+
+       _, err = Apply(strings, "dobedobedo", ".")
+       if err == nil {
+               t.Errorf("apply with unknown func should fail")
+       }
+
+       _, err = Apply(noStringers, "chomp", ".")
+       if err == nil {
+               t.Errorf("apply when func fails should fail")
+       }
+
+       _, err = Apply(tstNoStringer{}, "chomp", ".")
+       if err == nil {
+               t.Errorf("apply with non-sequence should fail")
+       }
+
+}
+
+func TestChomp(t *testing.T) {
+       base := "\n This is\na story "
+       for i, item := range []string{
+               "\n", "\n\n",
+               "\r", "\r\r",
+               "\r\n", "\r\n\r\n",
+       } {
+               chomped, _ := Chomp(base + item)
+
+               if chomped != base {
+                       t.Errorf("[%d] Chomp failed, got '%v'", i, chomped)
+               }
+
+               _, err := Chomp(tstNoStringer{})
+
+               if err == nil {
+                       t.Errorf("Chomp should fail")
+               }
+       }
+}
+
+func TestReplace(t *testing.T) {
+       v, _ := Replace("aab", "a", "b")
+       assert.Equal(t, "bbb", v)
+       v, _ = Replace("11a11", 1, 2)
+       assert.Equal(t, "22a22", v)
+       v, _ = Replace(12345, 1, 2)
+       assert.Equal(t, "22345", v)
+       _, e := Replace(tstNoStringer{}, "a", "b")
+       assert.NotNil(t, e, "tstNoStringer isn't trimmable")
+       _, e = Replace("a", tstNoStringer{}, "b")
+       assert.NotNil(t, e, "tstNoStringer cannot be converted to string")
+       _, e = Replace("a", "b", tstNoStringer{})
+       assert.NotNil(t, e, "tstNoStringer cannot be converted to string")
+}
+
+func TestTrim(t *testing.T) {
+       v, _ := Trim("1234 my way 13", "123")
+       assert.Equal(t, "4 my way ", v)
+       v, _ = Trim("   my way    ", " ")
+       assert.Equal(t, "my way", v)
+       v, _ = Trim(1234, "14")
+       assert.Equal(t, "23", v)
+       _, e := Trim(tstNoStringer{}, " ")
+       assert.NotNil(t, e, "tstNoStringer isn't trimmable")
+}
+
+func TestDateFormat(t *testing.T) {
+       for i, this := range []struct {
+               layout string
+               value  interface{}
+               expect interface{}
+       }{
+               {"Monday, Jan 2, 2006", "2015-01-21", "Wednesday, Jan 21, 2015"},
+               {"Monday, Jan 2, 2006", time.Date(2015, time.January, 21, 0, 0, 0, 0, time.UTC), "Wednesday, Jan 21, 2015"},
+               {"This isn't a date layout string", "2015-01-21", "This isn't a date layout string"},
+               {"Monday, Jan 2, 2006", 1421733600, false},
+               {"Monday, Jan 2, 2006", 1421733600.123, false},
+       } {
+               result, err := DateFormat(this.layout, this.value)
+               if b, ok := this.expect.(bool); ok && !b {
+                       if err == nil {
+                               t.Errorf("[%d] DateFormat didn't return an expected error", i)
+                       }
+               } else {
+                       if err != nil {
+                               t.Errorf("[%d] DateFormat failed: %s", i, err)
+                               continue
+                       }
+                       if result != this.expect {
+                               t.Errorf("[%d] DateFormat got %v but expected %v", i, result, this.expect)
+                       }
+               }
+       }
+}
+
+func TestSafeHTML(t *testing.T) {
+       for i, this := range []struct {
+               str                 string
+               tmplStr             string
+               expectWithoutEscape string
+               expectWithEscape    string
+       }{
+               {`<div></div>`, `{{ . }}`, `&lt;div&gt;&lt;/div&gt;`, `<div></div>`},
+       } {
+               tmpl, err := template.New("test").Parse(this.tmplStr)
+               if err != nil {
+                       t.Errorf("[%d] unable to create new html template %q: %s", i, this.tmplStr, err)
+                       continue
+               }
+
+               buf := new(bytes.Buffer)
+               err = tmpl.Execute(buf, this.str)
+               if err != nil {
+                       t.Errorf("[%d] execute template with a raw string value returns unexpected error: %s", i, err)
+               }
+               if buf.String() != this.expectWithoutEscape {
+                       t.Errorf("[%d] execute template with a raw string value, got %v but expected %v", i, buf.String(), this.expectWithoutEscape)
+               }
+
+               buf.Reset()
+               err = tmpl.Execute(buf, SafeHTML(this.str))
+               if err != nil {
+                       t.Errorf("[%d] execute template with an escaped string value by SafeHTML returns unexpected error: %s", i, err)
+               }
+               if buf.String() != this.expectWithEscape {
+                       t.Errorf("[%d] execute template with an escaped string value by SafeHTML, got %v but expected %v", i, buf.String(), this.expectWithEscape)
+               }
+       }
+}
+
+func TestSafeHTMLAttr(t *testing.T) {
+       for i, this := range []struct {
+               str                 string
+               tmplStr             string
+               expectWithoutEscape string
+               expectWithEscape    string
+       }{
+               {`href="irc://irc.freenode.net/#golang"`, `<a {{ . }}>irc</a>`, `<a ZgotmplZ>irc</a>`, `<a href="irc://irc.freenode.net/#golang">irc</a>`},
+       } {
+               tmpl, err := template.New("test").Parse(this.tmplStr)
+               if err != nil {
+                       t.Errorf("[%d] unable to create new html template %q: %s", i, this.tmplStr, err)
+                       continue
+               }
+
+               buf := new(bytes.Buffer)
+               err = tmpl.Execute(buf, this.str)
+               if err != nil {
+                       t.Errorf("[%d] execute template with a raw string value returns unexpected error: %s", i, err)
+               }
+               if buf.String() != this.expectWithoutEscape {
+                       t.Errorf("[%d] execute template with a raw string value, got %v but expected %v", i, buf.String(), this.expectWithoutEscape)
+               }
+
+               buf.Reset()
+               err = tmpl.Execute(buf, SafeHTMLAttr(this.str))
+               if err != nil {
+                       t.Errorf("[%d] execute template with an escaped string value by SafeHTMLAttr returns unexpected error: %s", i, err)
+               }
+               if buf.String() != this.expectWithEscape {
+                       t.Errorf("[%d] execute template with an escaped string value by SafeHTMLAttr, got %v but expected %v", i, buf.String(), this.expectWithEscape)
+               }
+       }
+}
+
+func TestSafeCSS(t *testing.T) {
+       for i, this := range []struct {
+               str                 string
+               tmplStr             string
+               expectWithoutEscape string
+               expectWithEscape    string
+       }{
+               {`width: 60px;`, `<div style="{{ . }}"></div>`, `<div style="ZgotmplZ"></div>`, `<div style="width: 60px;"></div>`},
+       } {
+               tmpl, err := template.New("test").Parse(this.tmplStr)
+               if err != nil {
+                       t.Errorf("[%d] unable to create new html template %q: %s", i, this.tmplStr, err)
+                       continue
+               }
+
+               buf := new(bytes.Buffer)
+               err = tmpl.Execute(buf, this.str)
+               if err != nil {
+                       t.Errorf("[%d] execute template with a raw string value returns unexpected error: %s", i, err)
+               }
+               if buf.String() != this.expectWithoutEscape {
+                       t.Errorf("[%d] execute template with a raw string value, got %v but expected %v", i, buf.String(), this.expectWithoutEscape)
+               }
+
+               buf.Reset()
+               err = tmpl.Execute(buf, SafeCSS(this.str))
+               if err != nil {
+                       t.Errorf("[%d] execute template with an escaped string value by SafeCSS returns unexpected error: %s", i, err)
+               }
+               if buf.String() != this.expectWithEscape {
+                       t.Errorf("[%d] execute template with an escaped string value by SafeCSS, got %v but expected %v", i, buf.String(), this.expectWithEscape)
+               }
+       }
+}
+
+func TestSafeURL(t *testing.T) {
+       for i, this := range []struct {
+               str                 string
+               tmplStr             string
+               expectWithoutEscape string
+               expectWithEscape    string
+       }{
+               {`irc://irc.freenode.net/#golang`, `<a href="{{ . }}">IRC</a>`, `<a href="#ZgotmplZ">IRC</a>`, `<a href="irc://irc.freenode.net/#golang">IRC</a>`},
+       } {
+               tmpl, err := template.New("test").Parse(this.tmplStr)
+               if err != nil {
+                       t.Errorf("[%d] unable to create new html template %q: %s", i, this.tmplStr, err)
+                       continue
+               }
+
+               buf := new(bytes.Buffer)
+               err = tmpl.Execute(buf, this.str)
+               if err != nil {
+                       t.Errorf("[%d] execute template with a raw string value returns unexpected error: %s", i, err)
+               }
+               if buf.String() != this.expectWithoutEscape {
+                       t.Errorf("[%d] execute template with a raw string value, got %v but expected %v", i, buf.String(), this.expectWithoutEscape)
+               }
+
+               buf.Reset()
+               err = tmpl.Execute(buf, SafeURL(this.str))
+               if err != nil {
+                       t.Errorf("[%d] execute template with an escaped string value by SafeURL returns unexpected error: %s", i, err)
+               }
+               if buf.String() != this.expectWithEscape {
+                       t.Errorf("[%d] execute template with an escaped string value by SafeURL, got %v but expected %v", i, buf.String(), this.expectWithEscape)
+               }
+       }
+}
index 8e99f2fb478628d6cdf393e4db6dc07d4e6d50f0..0c440966ba349cabee57d681b571195e206ce649 100644 (file)
 package tpl
 
-import (
-       "bytes"
-       "errors"
-       "fmt"
-       "github.com/stretchr/testify/assert"
-       "html/template"
-       "path"
-       "reflect"
-       "runtime"
-       "testing"
-       "time"
-)
-
-type tstNoStringer struct {
-}
-
-type tstCompareType int
-
-const (
-       tstEq tstCompareType = iota
-       tstNe
-       tstGt
-       tstGe
-       tstLt
-       tstLe
-)
-
-func tstIsEq(tp tstCompareType) bool {
-       return tp == tstEq || tp == tstGe || tp == tstLe
-}
-
-func tstIsGt(tp tstCompareType) bool {
-       return tp == tstGt || tp == tstGe
-}
-
-func tstIsLt(tp tstCompareType) bool {
-       return tp == tstLt || tp == tstLe
-}
-
-func TestCompare(t *testing.T) {
-       for _, this := range []struct {
-               tstCompareType
-               funcUnderTest func(a, b interface{}) bool
-       }{
-               {tstGt, Gt},
-               {tstLt, Lt},
-               {tstGe, Ge},
-               {tstLe, Le},
-               {tstEq, Eq},
-               {tstNe, Ne},
-       } {
-               doTestCompare(t, this.tstCompareType, this.funcUnderTest)
-       }
-
-}
-
-func doTestCompare(t *testing.T, tp tstCompareType, funcUnderTest func(a, b interface{}) bool) {
-       for i, this := range []struct {
-               left            interface{}
-               right           interface{}
-               expectIndicator int
-       }{
-               {5, 8, -1},
-               {8, 5, 1},
-               {5, 5, 0},
-               {int(5), int64(5), 0},
-               {int32(5), int(5), 0},
-               {int16(4), int(5), -1},
-               {uint(15), uint64(15), 0},
-               {-2, 1, -1},
-               {2, -5, 1},
-               {0.0, 1.23, -1},
-               {1.1, 1.1, 0},
-               {float32(1.0), float64(1.0), 0},
-               {1.23, 0.0, 1},
-               {"5", "5", 0},
-               {"8", "5", 1},
-               {"5", "0001", 1},
-               {[]int{100, 99}, []int{1, 2, 3, 4}, -1},
-       } {
-               result := funcUnderTest(this.left, this.right)
-               success := false
-
-               if this.expectIndicator == 0 {
-                       if tstIsEq(tp) {
-                               success = result
-                       } else {
-                               success = !result
-                       }
-               }
-
-               if this.expectIndicator < 0 {
-                       success = result && (tstIsLt(tp) || tp == tstNe)
-                       success = success || (!result && !tstIsLt(tp))
-               }
-
-               if this.expectIndicator > 0 {
-                       success = result && (tstIsGt(tp) || tp == tstNe)
-                       success = success || (!result && (!tstIsGt(tp) || tp != tstNe))
-               }
-
-               if !success {
-                       t.Errorf("[%d][%s] %v compared to %v: %t", i, path.Base(runtime.FuncForPC(reflect.ValueOf(funcUnderTest).Pointer()).Name()), this.left, this.right, result)
-               }
-       }
-}
-
-func TestArethmic(t *testing.T) {
-       for i, this := range []struct {
-               a      interface{}
-               b      interface{}
-               op     rune
-               expect interface{}
-       }{
-               {1, 2, '+', int64(3)},
-               {1, 2, '-', int64(-1)},
-               {2, 2, '*', int64(4)},
-               {4, 2, '/', int64(2)},
-               {uint8(1), uint8(3), '+', uint64(4)},
-               {uint8(3), uint8(2), '-', uint64(1)},
-               {uint8(2), uint8(2), '*', uint64(4)},
-               {uint16(4), uint8(2), '/', uint64(2)},
-               {4, 2, '¤', false},
-               {4, 0, '/', false},
-       } {
-               // TODO(bep): Take precision into account.
-               result, err := doArithmetic(this.a, this.b, this.op)
-               if b, ok := this.expect.(bool); ok && !b {
-                       if err == nil {
-                               t.Errorf("[%d] doArethmic didn't return an expected error", i)
-                       }
-               } else {
-                       if err != nil {
-                               t.Errorf("[%d] failed: %s", i, err)
-                               continue
-                       }
-                       if !reflect.DeepEqual(result, this.expect) {
-                               t.Errorf("[%d] doArethmic got %v (%T) but expected %v (%T)", i, result, result, this.expect, this.expect)
-                       }
-               }
-       }
-}
-
-func TestMod(t *testing.T) {
-       for i, this := range []struct {
-               a      interface{}
-               b      interface{}
-               expect interface{}
-       }{
-               {3, 2, int64(1)},
-               {3, 1, int64(0)},
-               {3, 0, false},
-               {0, 3, int64(0)},
-               {3.1, 2, false},
-               {3, 2.1, false},
-               {3.1, 2.1, false},
-               {int8(3), int8(2), int64(1)},
-               {int16(3), int16(2), int64(1)},
-               {int32(3), int32(2), int64(1)},
-               {int64(3), int64(2), int64(1)},
-       } {
-               result, err := Mod(this.a, this.b)
-               if b, ok := this.expect.(bool); ok && !b {
-                       if err == nil {
-                               t.Errorf("[%d] modulo didn't return an expected error", i)
-                       }
-               } else {
-                       if err != nil {
-                               t.Errorf("[%d] failed: %s", i, err)
-                               continue
-                       }
-                       if !reflect.DeepEqual(result, this.expect) {
-                               t.Errorf("[%d] modulo got %v but expected %v", i, result, this.expect)
-                       }
-               }
-       }
-}
-
-func TestModBool(t *testing.T) {
-       for i, this := range []struct {
-               a      interface{}
-               b      interface{}
-               expect interface{}
-       }{
-               {3, 3, true},
-               {3, 2, false},
-               {3, 1, true},
-               {3, 0, nil},
-               {0, 3, true},
-               {3.1, 2, nil},
-               {3, 2.1, nil},
-               {3.1, 2.1, nil},
-               {int8(3), int8(3), true},
-               {int8(3), int8(2), false},
-               {int16(3), int16(3), true},
-               {int16(3), int16(2), false},
-               {int32(3), int32(3), true},
-               {int32(3), int32(2), false},
-               {int64(3), int64(3), true},
-               {int64(3), int64(2), false},
-       } {
-               result, err := ModBool(this.a, this.b)
-               if this.expect == nil {
-                       if err == nil {
-                               t.Errorf("[%d] modulo didn't return an expected error", i)
-                       }
-               } else {
-                       if err != nil {
-                               t.Errorf("[%d] failed: %s", i, err)
-                               continue
-                       }
-                       if !reflect.DeepEqual(result, this.expect) {
-                               t.Errorf("[%d] modulo got %v but expected %v", i, result, this.expect)
-                       }
-               }
-       }
-}
-
-func TestFirst(t *testing.T) {
-       for i, this := range []struct {
-               count    interface{}
-               sequence interface{}
-               expect   interface{}
-       }{
-               {int(2), []string{"a", "b", "c"}, []string{"a", "b"}},
-               {int32(3), []string{"a", "b"}, []string{"a", "b"}},
-               {int64(2), []int{100, 200, 300}, []int{100, 200}},
-               {100, []int{100, 200}, []int{100, 200}},
-               {"1", []int{100, 200, 300}, []int{100}},
-               {int64(-1), []int{100, 200, 300}, false},
-               {"noint", []int{100, 200, 300}, false},
-               {1, nil, false},
-               {nil, []int{100}, false},
-               {1, t, false},
-       } {
-               results, err := First(this.count, this.sequence)
-               if b, ok := this.expect.(bool); ok && !b {
-                       if err == nil {
-                               t.Errorf("[%d] First didn't return an expected error", i)
-                       }
-               } else {
-                       if err != nil {
-                               t.Errorf("[%d] failed: %s", i, err)
-                               continue
-                       }
-                       if !reflect.DeepEqual(results, this.expect) {
-                               t.Errorf("[%d] First %d items, got %v but expected %v", i, this.count, results, this.expect)
-                       }
-               }
-       }
-}
-
-func TestIn(t *testing.T) {
-       for i, this := range []struct {
-               v1     interface{}
-               v2     interface{}
-               expect bool
-       }{
-               {[]string{"a", "b", "c"}, "b", true},
-               {[]string{"a", "b", "c"}, "d", false},
-               {[]string{"a", "12", "c"}, 12, false},
-               {[]int{1, 2, 4}, 2, true},
-               {[]int{1, 2, 4}, 3, false},
-               {[]float64{1.23, 2.45, 4.67}, 1.23, true},
-               {[]float64{1.234567, 2.45, 4.67}, 1.234568, false},
-               {"this substring should be found", "substring", true},
-               {"this substring should not be found", "subseastring", false},
-       } {
-               result := In(this.v1, this.v2)
-
-               if result != this.expect {
-                       t.Errorf("[%d] Got %v but expected %v", i, result, this.expect)
-               }
-       }
-}
-
-func TestSlicestr(t *testing.T) {
-       for i, this := range []struct {
-               v1     interface{}
-               v2     []int
-               expect interface{}
-       }{
-               {"abc", []int{1, 2}, "b"},
-               {"abc", []int{1, 3}, "bc"},
-               {"abc", []int{0, 1}, "a"},
-               {"abcdef", []int{}, "abcdef"},
-               {"abcdef", []int{0, 6}, "abcdef"},
-               {"abcdef", []int{0, 2}, "ab"},
-               {"abcdef", []int{2}, "cdef"},
-               {123, []int{1, 3}, "23"},
-               {123, []int{1, 2, 3}, false},
-               {tstNoStringer{}, []int{0, 1}, false},
-       } {
-               result, err := Slicestr(this.v1, this.v2...)
-
-               if b, ok := this.expect.(bool); ok && !b {
-                       if err == nil {
-                               t.Errorf("[%d] Slice didn't return an expected error", i)
-                       }
-               } else {
-                       if err != nil {
-                               t.Errorf("[%d] failed: %s", i, err)
-                               continue
-                       }
-                       if !reflect.DeepEqual(result, this.expect) {
-                               t.Errorf("[%d] Got %s but expected %s", i, result, this.expect)
-                       }
-               }
-       }
-}
-
-func TestSubstr(t *testing.T) {
-       for i, this := range []struct {
-               v1     interface{}
-               v2     int
-               v3     int
-               expect interface{}
-       }{
-               {"abc", 1, 2, "bc"},
-               {"abc", 0, 1, "a"},
-               {"abcdef", -1, 2, "ef"},
-               {"abcdef", -3, 3, "bcd"},
-               {"abcdef", 0, -1, "abcde"},
-               {"abcdef", 2, -1, "cde"},
-               {"abcdef", 4, -4, false},
-               {"abcdef", 7, 1, false},
-               {"abcdef", 1, 100, "bcdef"},
-               {"abcdef", -100, 3, "abc"},
-               {"abcdef", -3, -1, "de"},
-               {123, 1, 3, "23"},
-               {1.2e3, 0, 4, "1200"},
-               {tstNoStringer{}, 0, 1, false},
-       } {
-               result, err := Substr(this.v1, this.v2, this.v3)
-
-               if b, ok := this.expect.(bool); ok && !b {
-                       if err == nil {
-                               t.Errorf("[%d] Substr didn't return an expected error", i)
-                       }
-               } else {
-                       if err != nil {
-                               t.Errorf("[%d] failed: %s", i, err)
-                               continue
-                       }
-                       if !reflect.DeepEqual(result, this.expect) {
-                               t.Errorf("[%d] Got %s but expected %s", i, result, this.expect)
-                       }
-               }
-       }
-}
-
-func TestSplit(t *testing.T) {
-       for i, this := range []struct {
-               v1     interface{}
-               v2     string
-               expect interface{}
-       }{
-               {"a, b", ", ", []string{"a", "b"}},
-               {"a & b & c", " & ", []string{"a", "b", "c"}},
-               {"http://exmaple.com", "http://", []string{"", "exmaple.com"}},
-               {123, "2", []string{"1", "3"}},
-               {tstNoStringer{}, ",", false},
-       } {
-               result, err := Split(this.v1, this.v2)
-
-               if b, ok := this.expect.(bool); ok && !b {
-                       if err == nil {
-                               t.Errorf("[%d] Split didn't return an expected error", i)
-                       }
-               } else {
-                       if err != nil {
-                               t.Errorf("[%d] failed: %s", i, err)
-                               continue
-                       }
-                       if !reflect.DeepEqual(result, this.expect) {
-                               t.Errorf("[%d] Got %s but expected %s", i, result, this.expect)
-                       }
-               }
-       }
-
-}
-
-func TestIntersect(t *testing.T) {
-       for i, this := range []struct {
-               sequence1 interface{}
-               sequence2 interface{}
-               expect    interface{}
-       }{
-               {[]string{"a", "b", "c"}, []string{"a", "b"}, []string{"a", "b"}},
-               {[]string{"a", "b"}, []string{"a", "b", "c"}, []string{"a", "b"}},
-               {[]string{"a", "b", "c"}, []string{"d", "e"}, []string{}},
-               {[]string{}, []string{}, []string{}},
-               {[]string{"a", "b"}, nil, make([]interface{}, 0)},
-               {nil, []string{"a", "b"}, make([]interface{}, 0)},
-               {nil, nil, make([]interface{}, 0)},
-               {[]string{"1", "2"}, []int{1, 2}, []string{}},
-               {[]int{1, 2}, []string{"1", "2"}, []int{}},
-               {[]int{1, 2, 4}, []int{2, 4}, []int{2, 4}},
-               {[]int{2, 4}, []int{1, 2, 4}, []int{2, 4}},
-               {[]int{1, 2, 4}, []int{3, 6}, []int{}},
-               {[]float64{2.2, 4.4}, []float64{1.1, 2.2, 4.4}, []float64{2.2, 4.4}},
-       } {
-               results, err := Intersect(this.sequence1, this.sequence2)
-               if err != nil {
-                       t.Errorf("[%d] failed: %s", i, err)
-                       continue
-               }
-               if !reflect.DeepEqual(results, this.expect) {
-                       t.Errorf("[%d] Got %v but expected %v", i, results, this.expect)
-               }
-       }
-
-       _, err1 := Intersect("not an array or slice", []string{"a"})
-
-       if err1 == nil {
-               t.Error("Excpected error for non array as first arg")
-       }
-
-       _, err2 := Intersect([]string{"a"}, "not an array or slice")
-
-       if err2 == nil {
-               t.Error("Excpected error for non array as second arg")
-       }
-}
-
-func TestIsSet(t *testing.T) {
-       aSlice := []interface{}{1, 2, 3, 5}
-       aMap := map[string]interface{}{"a": 1, "b": 2}
-
-       assert.True(t, IsSet(aSlice, 2))
-       assert.True(t, IsSet(aMap, "b"))
-       assert.False(t, IsSet(aSlice, 22))
-       assert.False(t, IsSet(aMap, "bc"))
-}
-
-func (x *TstX) TstRp() string {
-       return "r" + x.A
-}
-
-func (x TstX) TstRv() string {
-       return "r" + x.B
-}
-
-func (x TstX) unexportedMethod() string {
-       return x.unexported
-}
-
-func (x TstX) MethodWithArg(s string) string {
-       return s
-}
-
-func (x TstX) MethodReturnNothing() {}
-
-func (x TstX) MethodReturnErrorOnly() error {
-       return errors.New("something error occured")
-}
-
-func (x TstX) MethodReturnTwoValues() (string, string) {
-       return "foo", "bar"
-}
-
-func (x TstX) MethodReturnValueWithError() (string, error) {
-       return "", errors.New("something error occured")
-}
-
-func (x TstX) String() string {
-       return fmt.Sprintf("A: %s, B: %s", x.A, x.B)
-}
-
-type TstX struct {
-       A, B       string
-       unexported string
-}
-
-func TestEvaluateSubElem(t *testing.T) {
-       tstx := TstX{A: "foo", B: "bar"}
-       var inner struct {
-               S fmt.Stringer
-       }
-       inner.S = tstx
-       interfaceValue := reflect.ValueOf(&inner).Elem().Field(0)
-
-       for i, this := range []struct {
-               value  reflect.Value
-               key    string
-               expect interface{}
-       }{
-               {reflect.ValueOf(tstx), "A", "foo"},
-               {reflect.ValueOf(&tstx), "TstRp", "rfoo"},
-               {reflect.ValueOf(tstx), "TstRv", "rbar"},
-               //{reflect.ValueOf(map[int]string{1: "foo", 2: "bar"}), 1, "foo"},
-               {reflect.ValueOf(map[string]string{"key1": "foo", "key2": "bar"}), "key1", "foo"},
-               {interfaceValue, "String", "A: foo, B: bar"},
-               {reflect.Value{}, "foo", false},
-               //{reflect.ValueOf(map[int]string{1: "foo", 2: "bar"}), 1.2, false},
-               {reflect.ValueOf(tstx), "unexported", false},
-               {reflect.ValueOf(tstx), "unexportedMethod", false},
-               {reflect.ValueOf(tstx), "MethodWithArg", false},
-               {reflect.ValueOf(tstx), "MethodReturnNothing", false},
-               {reflect.ValueOf(tstx), "MethodReturnErrorOnly", false},
-               {reflect.ValueOf(tstx), "MethodReturnTwoValues", false},
-               {reflect.ValueOf(tstx), "MethodReturnValueWithError", false},
-               {reflect.ValueOf((*TstX)(nil)), "A", false},
-               {reflect.ValueOf(tstx), "C", false},
-               {reflect.ValueOf(map[int]string{1: "foo", 2: "bar"}), "1", false},
-               {reflect.ValueOf([]string{"foo", "bar"}), "1", false},
-       } {
-               result, err := evaluateSubElem(this.value, this.key)
-               if b, ok := this.expect.(bool); ok && !b {
-                       if err == nil {
-                               t.Errorf("[%d] evaluateSubElem didn't return an expected error", i)
-                       }
-               } else {
-                       if err != nil {
-                               t.Errorf("[%d] failed: %s", i, err)
-                               continue
-                       }
-                       if result.Kind() != reflect.String || result.String() != this.expect {
-                               t.Errorf("[%d] evaluateSubElem with %v got %v but expected %v", i, this.key, result, this.expect)
-                       }
-               }
-       }
-}
-
-func TestCheckCondition(t *testing.T) {
-       type expect struct {
-               result  bool
-               isError bool
-       }
-
-       for i, this := range []struct {
-               value reflect.Value
-               match reflect.Value
-               op    string
-               expect
-       }{
-               {reflect.ValueOf(123), reflect.ValueOf(123), "", expect{true, false}},
-               {reflect.ValueOf("foo"), reflect.ValueOf("foo"), "", expect{true, false}},
-               {reflect.ValueOf(123), reflect.ValueOf(456), "!=", expect{true, false}},
-               {reflect.ValueOf("foo"), reflect.ValueOf("bar"), "!=", expect{true, false}},
-               {reflect.ValueOf(456), reflect.ValueOf(123), ">=", expect{true, false}},
-               {reflect.ValueOf("foo"), reflect.ValueOf("bar"), ">=", expect{true, false}},
-               {reflect.ValueOf(456), reflect.ValueOf(123), ">", expect{true, false}},
-               {reflect.ValueOf("foo"), reflect.ValueOf("bar"), ">", expect{true, false}},
-               {reflect.ValueOf(123), reflect.ValueOf(456), "<=", expect{true, false}},
-               {reflect.ValueOf("bar"), reflect.ValueOf("foo"), "<=", expect{true, false}},
-               {reflect.ValueOf(123), reflect.ValueOf(456), "<", expect{true, false}},
-               {reflect.ValueOf("bar"), reflect.ValueOf("foo"), "<", expect{true, false}},
-               {reflect.ValueOf(123), reflect.ValueOf([]int{123, 45, 678}), "in", expect{true, false}},
-               {reflect.ValueOf("foo"), reflect.ValueOf([]string{"foo", "bar", "baz"}), "in", expect{true, false}},
-               {reflect.ValueOf(123), reflect.ValueOf([]int{45, 678}), "not in", expect{true, false}},
-               {reflect.ValueOf("foo"), reflect.ValueOf([]string{"bar", "baz"}), "not in", expect{true, false}},
-               {reflect.ValueOf("foo"), reflect.ValueOf("bar-foo-baz"), "in", expect{true, false}},
-               {reflect.ValueOf("foo"), reflect.ValueOf("bar--baz"), "not in", expect{true, false}},
-               {reflect.Value{}, reflect.ValueOf("foo"), "", expect{false, false}},
-               {reflect.ValueOf("foo"), reflect.Value{}, "", expect{false, false}},
-               {reflect.ValueOf((*TstX)(nil)), reflect.ValueOf("foo"), "", expect{false, false}},
-               {reflect.ValueOf("foo"), reflect.ValueOf((*TstX)(nil)), "", expect{false, false}},
-               {reflect.ValueOf("foo"), reflect.ValueOf(map[int]string{}), "", expect{false, false}},
-               {reflect.ValueOf("foo"), reflect.ValueOf([]int{1, 2}), "", expect{false, false}},
-               {reflect.ValueOf(123), reflect.ValueOf([]int{}), "in", expect{false, false}},
-               {reflect.ValueOf(123), reflect.ValueOf(123), "op", expect{false, true}},
-       } {
-               result, err := checkCondition(this.value, this.match, this.op)
-               if this.expect.isError {
-                       if err == nil {
-                               t.Errorf("[%d] checkCondition didn't return an expected error", i)
-                       }
-               } else {
-                       if err != nil {
-                               t.Errorf("[%d] failed: %s", i, err)
-                               continue
-                       }
-                       if result != this.expect.result {
-                               t.Errorf("[%d] check condition %v %s %v, got %v but expected %v", i, this.value, this.op, this.match, result, this.expect.result)
-                       }
-               }
-       }
-}
-
-func TestWhere(t *testing.T) {
-       // TODO(spf): Put these page tests back in
-       //page1 := &Page{contentType: "v", Source: Source{File: *source.NewFile("/x/y/z/source.md")}}
-       //page2 := &Page{contentType: "w", Source: Source{File: *source.NewFile("/y/z/a/source.md")}}
-
-       type Mid struct {
-               Tst TstX
-       }
-
-       for i, this := range []struct {
-               sequence interface{}
-               key      interface{}
-               op       string
-               match    interface{}
-               expect   interface{}
-       }{
-               {
-                       sequence: []map[int]string{
-                               {1: "a", 2: "m"}, {1: "c", 2: "d"}, {1: "e", 3: "m"},
-                       },
-                       key: 2, match: "m",
-                       expect: []map[int]string{
-                               {1: "a", 2: "m"},
-                       },
-               },
-               {
-                       sequence: []map[string]int{
-                               {"a": 1, "b": 2}, {"a": 3, "b": 4}, {"a": 5, "x": 4},
-                       },
-                       key: "b", match: 4,
-                       expect: []map[string]int{
-                               {"a": 3, "b": 4},
-                       },
-               },
-               {
-                       sequence: []TstX{
-                               {A: "a", B: "b"}, {A: "c", B: "d"}, {A: "e", B: "f"},
-                       },
-                       key: "B", match: "f",
-                       expect: []TstX{
-                               {A: "e", B: "f"},
-                       },
-               },
-               {
-                       sequence: []*map[int]string{
-                               {1: "a", 2: "m"}, {1: "c", 2: "d"}, {1: "e", 3: "m"},
-                       },
-                       key: 2, match: "m",
-                       expect: []*map[int]string{
-                               {1: "a", 2: "m"},
-                       },
-               },
-               {
-                       sequence: []*TstX{
-                               {A: "a", B: "b"}, {A: "c", B: "d"}, {A: "e", B: "f"},
-                       },
-                       key: "B", match: "f",
-                       expect: []*TstX{
-                               {A: "e", B: "f"},
-                       },
-               },
-               {
-                       sequence: []*TstX{
-                               {A: "a", B: "b"}, {A: "c", B: "d"}, {A: "e", B: "c"},
-                       },
-                       key: "TstRp", match: "rc",
-                       expect: []*TstX{
-                               {A: "c", B: "d"},
-                       },
-               },
-               {
-                       sequence: []TstX{
-                               {A: "a", B: "b"}, {A: "c", B: "d"}, {A: "e", B: "c"},
-                       },
-                       key: "TstRv", match: "rc",
-                       expect: []TstX{
-                               {A: "e", B: "c"},
-                       },
-               },
-               {
-                       sequence: []map[string]TstX{
-                               {"foo": TstX{A: "a", B: "b"}}, {"foo": TstX{A: "c", B: "d"}}, {"foo": TstX{A: "e", B: "f"}},
-                       },
-                       key: "foo.B", match: "d",
-                       expect: []map[string]TstX{
-                               {"foo": TstX{A: "c", B: "d"}},
-                       },
-               },
-               {
-                       sequence: []map[string]TstX{
-                               {"foo": TstX{A: "a", B: "b"}}, {"foo": TstX{A: "c", B: "d"}}, {"foo": TstX{A: "e", B: "f"}},
-                       },
-                       key: ".foo.B", match: "d",
-                       expect: []map[string]TstX{
-                               {"foo": TstX{A: "c", B: "d"}},
-                       },
-               },
-               {
-                       sequence: []map[string]TstX{
-                               {"foo": TstX{A: "a", B: "b"}}, {"foo": TstX{A: "c", B: "d"}}, {"foo": TstX{A: "e", B: "f"}},
-                       },
-                       key: "foo.TstRv", match: "rd",
-                       expect: []map[string]TstX{
-                               {"foo": TstX{A: "c", B: "d"}},
-                       },
-               },
-               {
-                       sequence: []map[string]*TstX{
-                               {"foo": &TstX{A: "a", B: "b"}}, {"foo": &TstX{A: "c", B: "d"}}, {"foo": &TstX{A: "e", B: "f"}},
-                       },
-                       key: "foo.TstRp", match: "rc",
-                       expect: []map[string]*TstX{
-                               {"foo": &TstX{A: "c", B: "d"}},
-                       },
-               },
-               {
-                       sequence: []map[string]Mid{
-                               {"foo": Mid{Tst: TstX{A: "a", B: "b"}}}, {"foo": Mid{Tst: TstX{A: "c", B: "d"}}}, {"foo": Mid{Tst: TstX{A: "e", B: "f"}}},
-                       },
-                       key: "foo.Tst.B", match: "d",
-                       expect: []map[string]Mid{
-                               {"foo": Mid{Tst: TstX{A: "c", B: "d"}}},
-                       },
-               },
-               {
-                       sequence: []map[string]Mid{
-                               {"foo": Mid{Tst: TstX{A: "a", B: "b"}}}, {"foo": Mid{Tst: TstX{A: "c", B: "d"}}}, {"foo": Mid{Tst: TstX{A: "e", B: "f"}}},
-                       },
-                       key: "foo.Tst.TstRv", match: "rd",
-                       expect: []map[string]Mid{
-                               {"foo": Mid{Tst: TstX{A: "c", B: "d"}}},
-                       },
-               },
-               {
-                       sequence: []map[string]*Mid{
-                               {"foo": &Mid{Tst: TstX{A: "a", B: "b"}}}, {"foo": &Mid{Tst: TstX{A: "c", B: "d"}}}, {"foo": &Mid{Tst: TstX{A: "e", B: "f"}}},
-                       },
-                       key: "foo.Tst.TstRp", match: "rc",
-                       expect: []map[string]*Mid{
-                               {"foo": &Mid{Tst: TstX{A: "c", B: "d"}}},
-                       },
-               },
-               {
-                       sequence: []map[string]int{
-                               {"a": 1, "b": 2}, {"a": 3, "b": 4}, {"a": 5, "b": 6},
-                       },
-                       key: "b", op: ">", match: 3,
-                       expect: []map[string]int{
-                               {"a": 3, "b": 4}, {"a": 5, "b": 6},
-                       },
-               },
-               {
-                       sequence: []TstX{
-                               {A: "a", B: "b"}, {A: "c", B: "d"}, {A: "e", B: "f"},
-                       },
-                       key: "B", op: "!=", match: "f",
-                       expect: []TstX{
-                               {A: "a", B: "b"}, {A: "c", B: "d"},
-                       },
-               },
-               {
-                       sequence: []map[string]int{
-                               {"a": 1, "b": 2}, {"a": 3, "b": 4}, {"a": 5, "b": 6},
-                       },
-                       key: "b", op: "in", match: []int{3, 4, 5},
-                       expect: []map[string]int{
-                               {"a": 3, "b": 4},
-                       },
-               },
-               {
-                       sequence: []TstX{
-                               {A: "a", B: "b"}, {A: "c", B: "d"}, {A: "e", B: "f"},
-                       },
-                       key: "B", op: "not in", match: []string{"c", "d", "e"},
-                       expect: []TstX{
-                               {A: "a", B: "b"}, {A: "e", B: "f"},
-                       },
-               },
-               {sequence: (*[]TstX)(nil), key: "A", match: "a", expect: false},
-               {sequence: TstX{A: "a", B: "b"}, key: "A", match: "a", expect: false},
-               {sequence: []map[string]*TstX{{"foo": nil}}, key: "foo.B", match: "d", expect: false},
-               {
-                       sequence: []TstX{
-                               {A: "a", B: "b"}, {A: "c", B: "d"}, {A: "e", B: "f"},
-                       },
-                       key: "B", op: "op", match: "f",
-                       expect: false,
-               },
-               //{[]*Page{page1, page2}, "Type", "v", []*Page{page1}},
-               //{[]*Page{page1, page2}, "Section", "y", []*Page{page2}},
-       } {
-               var results interface{}
-               var err error
-               if len(this.op) > 0 {
-                       results, err = Where(this.sequence, this.key, this.op, this.match)
-               } else {
-                       results, err = Where(this.sequence, this.key, this.match)
-               }
-               if b, ok := this.expect.(bool); ok && !b {
-                       if err == nil {
-                               t.Errorf("[%d] Where didn't return an expected error", i)
-                       }
-               } else {
-                       if err != nil {
-                               t.Errorf("[%d] failed: %s", i, err)
-                               continue
-                       }
-                       if !reflect.DeepEqual(results, this.expect) {
-                               t.Errorf("[%d] Where clause matching %v with %v, got %v but expected %v", i, this.key, this.match, results, this.expect)
-                       }
-               }
-       }
-
-       var err error
-       _, err = Where(map[string]int{"a": 1, "b": 2}, "a", []byte("="), 1)
-       if err == nil {
-               t.Errorf("Where called with none string op value didn't return an expected error")
-       }
-
-       _, err = Where(map[string]int{"a": 1, "b": 2}, "a", []byte("="), 1, 2)
-       if err == nil {
-               t.Errorf("Where called with more than two variable arguments didn't return an expected error")
-       }
-
-       _, err = Where(map[string]int{"a": 1, "b": 2}, "a")
-       if err == nil {
-               t.Errorf("Where called with no variable arguments didn't return an expected error")
-       }
-}
-
-func TestDelimit(t *testing.T) {
-       for i, this := range []struct {
-               sequence  interface{}
-               delimiter interface{}
-               last      interface{}
-               expect    template.HTML
-       }{
-               {[]string{"class1", "class2", "class3"}, " ", nil, "class1 class2 class3"},
-               {[]int{1, 2, 3, 4, 5}, ",", nil, "1,2,3,4,5"},
-               {[]int{1, 2, 3, 4, 5}, ", ", nil, "1, 2, 3, 4, 5"},
-               {[]string{"class1", "class2", "class3"}, " ", " and ", "class1 class2 and class3"},
-               {[]int{1, 2, 3, 4, 5}, ",", ",", "1,2,3,4,5"},
-               {[]int{1, 2, 3, 4, 5}, ", ", ", and ", "1, 2, 3, 4, and 5"},
-               // test maps with and without sorting required
-               {map[string]int{"1": 10, "2": 20, "3": 30, "4": 40, "5": 50}, "--", nil, "10--20--30--40--50"},
-               {map[string]int{"3": 10, "2": 20, "1": 30, "4": 40, "5": 50}, "--", nil, "30--20--10--40--50"},
-               {map[string]string{"1": "10", "2": "20", "3": "30", "4": "40", "5": "50"}, "--", nil, "10--20--30--40--50"},
-               {map[string]string{"3": "10", "2": "20", "1": "30", "4": "40", "5": "50"}, "--", nil, "30--20--10--40--50"},
-               {map[string]string{"one": "10", "two": "20", "three": "30", "four": "40", "five": "50"}, "--", nil, "50--40--10--30--20"},
-               {map[int]string{1: "10", 2: "20", 3: "30", 4: "40", 5: "50"}, "--", nil, "10--20--30--40--50"},
-               {map[int]string{3: "10", 2: "20", 1: "30", 4: "40", 5: "50"}, "--", nil, "30--20--10--40--50"},
-               {map[float64]string{3.3: "10", 2.3: "20", 1.3: "30", 4.3: "40", 5.3: "50"}, "--", nil, "30--20--10--40--50"},
-               // test maps with a last delimiter
-               {map[string]int{"1": 10, "2": 20, "3": 30, "4": 40, "5": 50}, "--", "--and--", "10--20--30--40--and--50"},
-               {map[string]int{"3": 10, "2": 20, "1": 30, "4": 40, "5": 50}, "--", "--and--", "30--20--10--40--and--50"},
-               {map[string]string{"1": "10", "2": "20", "3": "30", "4": "40", "5": "50"}, "--", "--and--", "10--20--30--40--and--50"},
-               {map[string]string{"3": "10", "2": "20", "1": "30", "4": "40", "5": "50"}, "--", "--and--", "30--20--10--40--and--50"},
-               {map[string]string{"one": "10", "two": "20", "three": "30", "four": "40", "five": "50"}, "--", "--and--", "50--40--10--30--and--20"},
-               {map[int]string{1: "10", 2: "20", 3: "30", 4: "40", 5: "50"}, "--", "--and--", "10--20--30--40--and--50"},
-               {map[int]string{3: "10", 2: "20", 1: "30", 4: "40", 5: "50"}, "--", "--and--", "30--20--10--40--and--50"},
-               {map[float64]string{3.5: "10", 2.5: "20", 1.5: "30", 4.5: "40", 5.5: "50"}, "--", "--and--", "30--20--10--40--and--50"},
-       } {
-               var result template.HTML
-               var err error
-               if this.last == nil {
-                       result, err = Delimit(this.sequence, this.delimiter)
-               } else {
-                       result, err = Delimit(this.sequence, this.delimiter, this.last)
-               }
-               if err != nil {
-                       t.Errorf("[%d] failed: %s", i, err)
-                       continue
-               }
-               if !reflect.DeepEqual(result, this.expect) {
-                       t.Errorf("[%d] Delimit called on sequence: %v | delimiter: `%v` | last: `%v`, got %v but expected %v", i, this.sequence, this.delimiter, this.last, result, this.expect)
-               }
-       }
-}
-
-func TestSort(t *testing.T) {
-       type ts struct {
-               MyInt    int
-               MyFloat  float64
-               MyString string
-       }
-       for i, this := range []struct {
-               sequence    interface{}
-               sortByField interface{}
-               sortAsc     string
-               expect      []interface{}
-       }{
-               {[]string{"class1", "class2", "class3"}, nil, "asc", []interface{}{"class1", "class2", "class3"}},
-               {[]string{"class3", "class1", "class2"}, nil, "asc", []interface{}{"class1", "class2", "class3"}},
-               {[]int{1, 2, 3, 4, 5}, nil, "asc", []interface{}{1, 2, 3, 4, 5}},
-               {[]int{5, 4, 3, 1, 2}, nil, "asc", []interface{}{1, 2, 3, 4, 5}},
-               // test map sorting by keys
-               {map[string]int{"1": 10, "2": 20, "3": 30, "4": 40, "5": 50}, nil, "asc", []interface{}{10, 20, 30, 40, 50}},
-               {map[string]int{"3": 10, "2": 20, "1": 30, "4": 40, "5": 50}, nil, "asc", []interface{}{30, 20, 10, 40, 50}},
-               {map[string]string{"1": "10", "2": "20", "3": "30", "4": "40", "5": "50"}, nil, "asc", []interface{}{"10", "20", "30", "40", "50"}},
-               {map[string]string{"3": "10", "2": "20", "1": "30", "4": "40", "5": "50"}, nil, "asc", []interface{}{"30", "20", "10", "40", "50"}},
-               {map[string]string{"one": "10", "two": "20", "three": "30", "four": "40", "five": "50"}, nil, "asc", []interface{}{"50", "40", "10", "30", "20"}},
-               {map[int]string{1: "10", 2: "20", 3: "30", 4: "40", 5: "50"}, nil, "asc", []interface{}{"10", "20", "30", "40", "50"}},
-               {map[int]string{3: "10", 2: "20", 1: "30", 4: "40", 5: "50"}, nil, "asc", []interface{}{"30", "20", "10", "40", "50"}},
-               {map[float64]string{3.3: "10", 2.3: "20", 1.3: "30", 4.3: "40", 5.3: "50"}, nil, "asc", []interface{}{"30", "20", "10", "40", "50"}},
-               // test map sorting by value
-               {map[string]int{"1": 10, "2": 20, "3": 30, "4": 40, "5": 50}, "value", "asc", []interface{}{10, 20, 30, 40, 50}},
-               {map[string]int{"3": 10, "2": 20, "1": 30, "4": 40, "5": 50}, "value", "asc", []interface{}{10, 20, 30, 40, 50}},
-               // test map sorting by field value
-               {
-                       map[string]ts{"1": {10, 10.5, "ten"}, "2": {20, 20.5, "twenty"}, "3": {30, 30.5, "thirty"}, "4": {40, 40.5, "forty"}, "5": {50, 50.5, "fifty"}},
-                       "MyInt",
-                       "asc",
-                       []interface{}{ts{10, 10.5, "ten"}, ts{20, 20.5, "twenty"}, ts{30, 30.5, "thirty"}, ts{40, 40.5, "forty"}, ts{50, 50.5, "fifty"}},
-               },
-               {
-                       map[string]ts{"1": {10, 10.5, "ten"}, "2": {20, 20.5, "twenty"}, "3": {30, 30.5, "thirty"}, "4": {40, 40.5, "forty"}, "5": {50, 50.5, "fifty"}},
-                       "MyFloat",
-                       "asc",
-                       []interface{}{ts{10, 10.5, "ten"}, ts{20, 20.5, "twenty"}, ts{30, 30.5, "thirty"}, ts{40, 40.5, "forty"}, ts{50, 50.5, "fifty"}},
-               },
-               {
-                       map[string]ts{"1": {10, 10.5, "ten"}, "2": {20, 20.5, "twenty"}, "3": {30, 30.5, "thirty"}, "4": {40, 40.5, "forty"}, "5": {50, 50.5, "fifty"}},
-                       "MyString",
-                       "asc",
-                       []interface{}{ts{50, 50.5, "fifty"}, ts{40, 40.5, "forty"}, ts{10, 10.5, "ten"}, ts{30, 30.5, "thirty"}, ts{20, 20.5, "twenty"}},
-               },
-               // Test sort desc
-               {[]string{"class1", "class2", "class3"}, "value", "desc", []interface{}{"class3", "class2", "class1"}},
-               {[]string{"class3", "class1", "class2"}, "value", "desc", []interface{}{"class3", "class2", "class1"}},
-       } {
-               var result []interface{}
-               var err error
-               if this.sortByField == nil {
-                       result, err = Sort(this.sequence)
-               } else {
-                       result, err = Sort(this.sequence, this.sortByField, this.sortAsc)
-               }
-               if err != nil {
-                       t.Errorf("[%d] failed: %s", i, err)
-                       continue
-               }
-               if !reflect.DeepEqual(result, this.expect) {
-                       t.Errorf("[%d] Sort called on sequence: %v | sortByField: `%v` | got %v but expected %v", i, this.sequence, this.sortByField, result, this.expect)
-               }
-       }
-}
-
-func TestReturnWhenSet(t *testing.T) {
-       for i, this := range []struct {
-               data   interface{}
-               key    interface{}
-               expect interface{}
-       }{
-               {[]int{1, 2, 3}, 1, int64(2)},
-               {[]uint{1, 2, 3}, 1, uint64(2)},
-               {[]float64{1.1, 2.2, 3.3}, 1, float64(2.2)},
-               {[]string{"foo", "bar", "baz"}, 1, "bar"},
-               {[]TstX{{A: "a", B: "b"}, {A: "c", B: "d"}, {A: "e", B: "f"}}, 1, ""},
-               {map[string]int{"foo": 1, "bar": 2, "baz": 3}, "bar", int64(2)},
-               {map[string]uint{"foo": 1, "bar": 2, "baz": 3}, "bar", uint64(2)},
-               {map[string]float64{"foo": 1.1, "bar": 2.2, "baz": 3.3}, "bar", float64(2.2)},
-               {map[string]string{"foo": "FOO", "bar": "BAR", "baz": "BAZ"}, "bar", "BAR"},
-               {map[string]TstX{"foo": {A: "a", B: "b"}, "bar": {A: "c", B: "d"}, "baz": {A: "e", B: "f"}}, "bar", ""},
-               {(*[]string)(nil), "bar", ""},
-       } {
-               result := ReturnWhenSet(this.data, this.key)
-               if !reflect.DeepEqual(result, this.expect) {
-                       t.Errorf("[%d] ReturnWhenSet got %v (type %v) but expected %v (type %v)", i, result, reflect.TypeOf(result), this.expect, reflect.TypeOf(this.expect))
-               }
-       }
-}
-
-func TestMarkdownify(t *testing.T) {
-
-       result := Markdownify("Hello **World!**")
-
-       expect := template.HTML("Hello <strong>World!</strong>")
-
-       if result != expect {
-               t.Errorf("Markdownify: got '%s', expected '%s'", result, expect)
-       }
-}
-
-func TestApply(t *testing.T) {
-       strings := []interface{}{"a\n", "b\n"}
-       noStringers := []interface{}{tstNoStringer{}, tstNoStringer{}}
-
-       var nilErr *error = nil
-
-       chomped, _ := Apply(strings, "chomp", ".")
-       assert.Equal(t, []interface{}{"a", "b"}, chomped)
-
-       chomped, _ = Apply(strings, "chomp", "c\n")
-       assert.Equal(t, []interface{}{"c", "c"}, chomped)
-
-       chomped, _ = Apply(nil, "chomp", ".")
-       assert.Equal(t, []interface{}{}, chomped)
-
-       _, err := Apply(strings, "apply", ".")
-       if err == nil {
-               t.Errorf("apply with apply should fail")
-       }
-
-       _, err = Apply(nilErr, "chomp", ".")
-       if err == nil {
-               t.Errorf("apply with nil in seq should fail")
-       }
-
-       _, err = Apply(strings, "dobedobedo", ".")
-       if err == nil {
-               t.Errorf("apply with unknown func should fail")
-       }
-
-       _, err = Apply(noStringers, "chomp", ".")
-       if err == nil {
-               t.Errorf("apply when func fails should fail")
-       }
-
-       _, err = Apply(tstNoStringer{}, "chomp", ".")
-       if err == nil {
-               t.Errorf("apply with non-sequence should fail")
-       }
-
-}
-
-func TestChomp(t *testing.T) {
-       base := "\n This is\na story "
-       for i, item := range []string{
-               "\n", "\n\n",
-               "\r", "\r\r",
-               "\r\n", "\r\n\r\n",
-       } {
-               chomped, _ := Chomp(base + item)
-
-               if chomped != base {
-                       t.Errorf("[%d] Chomp failed, got '%v'", i, chomped)
-               }
-
-               _, err := Chomp(tstNoStringer{})
-
-               if err == nil {
-                       t.Errorf("Chomp should fail")
-               }
-       }
-}
-
-func TestReplace(t *testing.T) {
-       v, _ := Replace("aab", "a", "b")
-       assert.Equal(t, "bbb", v)
-       v, _ = Replace("11a11", 1, 2)
-       assert.Equal(t, "22a22", v)
-       v, _ = Replace(12345, 1, 2)
-       assert.Equal(t, "22345", v)
-       _, e := Replace(tstNoStringer{}, "a", "b")
-       assert.NotNil(t, e, "tstNoStringer isn't trimmable")
-       _, e = Replace("a", tstNoStringer{}, "b")
-       assert.NotNil(t, e, "tstNoStringer cannot be converted to string")
-       _, e = Replace("a", "b", tstNoStringer{})
-       assert.NotNil(t, e, "tstNoStringer cannot be converted to string")
-}
-
-func TestTrim(t *testing.T) {
-       v, _ := Trim("1234 my way 13", "123")
-       assert.Equal(t, "4 my way ", v)
-       v, _ = Trim("   my way    ", " ")
-       assert.Equal(t, "my way", v)
-       v, _ = Trim(1234, "14")
-       assert.Equal(t, "23", v)
-       _, e := Trim(tstNoStringer{}, " ")
-       assert.NotNil(t, e, "tstNoStringer isn't trimmable")
-}
-
-func TestDateFormat(t *testing.T) {
-       for i, this := range []struct {
-               layout string
-               value  interface{}
-               expect interface{}
-       }{
-               {"Monday, Jan 2, 2006", "2015-01-21", "Wednesday, Jan 21, 2015"},
-               {"Monday, Jan 2, 2006", time.Date(2015, time.January, 21, 0, 0, 0, 0, time.UTC), "Wednesday, Jan 21, 2015"},
-               {"This isn't a date layout string", "2015-01-21", "This isn't a date layout string"},
-               {"Monday, Jan 2, 2006", 1421733600, false},
-               {"Monday, Jan 2, 2006", 1421733600.123, false},
-       } {
-               result, err := DateFormat(this.layout, this.value)
-               if b, ok := this.expect.(bool); ok && !b {
-                       if err == nil {
-                               t.Errorf("[%d] DateFormat didn't return an expected error", i)
-                       }
-               } else {
-                       if err != nil {
-                               t.Errorf("[%d] DateFormat failed: %s", i, err)
-                               continue
-                       }
-                       if result != this.expect {
-                               t.Errorf("[%d] DateFormat got %v but expected %v", i, result, this.expect)
-                       }
-               }
-       }
-}
-
-func TestSafeHTML(t *testing.T) {
-       for i, this := range []struct {
-               str                 string
-               tmplStr             string
-               expectWithoutEscape string
-               expectWithEscape    string
-       }{
-               {`<div></div>`, `{{ . }}`, `&lt;div&gt;&lt;/div&gt;`, `<div></div>`},
-       } {
-               tmpl, err := template.New("test").Parse(this.tmplStr)
-               if err != nil {
-                       t.Errorf("[%d] unable to create new html template %q: %s", i, this.tmplStr, err)
-                       continue
-               }
-
-               buf := new(bytes.Buffer)
-               err = tmpl.Execute(buf, this.str)
-               if err != nil {
-                       t.Errorf("[%d] execute template with a raw string value returns unexpected error: %s", i, err)
-               }
-               if buf.String() != this.expectWithoutEscape {
-                       t.Errorf("[%d] execute template with a raw string value, got %v but expected %v", i, buf.String(), this.expectWithoutEscape)
-               }
-
-               buf.Reset()
-               err = tmpl.Execute(buf, SafeHTML(this.str))
-               if err != nil {
-                       t.Errorf("[%d] execute template with an escaped string value by SafeHTML returns unexpected error: %s", i, err)
-               }
-               if buf.String() != this.expectWithEscape {
-                       t.Errorf("[%d] execute template with an escaped string value by SafeHTML, got %v but expected %v", i, buf.String(), this.expectWithEscape)
-               }
-       }
-}
-
-func TestSafeHTMLAttr(t *testing.T) {
-       for i, this := range []struct {
-               str                 string
-               tmplStr             string
-               expectWithoutEscape string
-               expectWithEscape    string
-       }{
-               {`href="irc://irc.freenode.net/#golang"`, `<a {{ . }}>irc</a>`, `<a ZgotmplZ>irc</a>`, `<a href="irc://irc.freenode.net/#golang">irc</a>`},
-       } {
-               tmpl, err := template.New("test").Parse(this.tmplStr)
-               if err != nil {
-                       t.Errorf("[%d] unable to create new html template %q: %s", i, this.tmplStr, err)
-                       continue
-               }
-
-               buf := new(bytes.Buffer)
-               err = tmpl.Execute(buf, this.str)
-               if err != nil {
-                       t.Errorf("[%d] execute template with a raw string value returns unexpected error: %s", i, err)
-               }
-               if buf.String() != this.expectWithoutEscape {
-                       t.Errorf("[%d] execute template with a raw string value, got %v but expected %v", i, buf.String(), this.expectWithoutEscape)
-               }
-
-               buf.Reset()
-               err = tmpl.Execute(buf, SafeHTMLAttr(this.str))
-               if err != nil {
-                       t.Errorf("[%d] execute template with an escaped string value by SafeHTMLAttr returns unexpected error: %s", i, err)
-               }
-               if buf.String() != this.expectWithEscape {
-                       t.Errorf("[%d] execute template with an escaped string value by SafeHTMLAttr, got %v but expected %v", i, buf.String(), this.expectWithEscape)
-               }
-       }
-}
-
-func TestSafeCSS(t *testing.T) {
-       for i, this := range []struct {
-               str                 string
-               tmplStr             string
-               expectWithoutEscape string
-               expectWithEscape    string
-       }{
-               {`width: 60px;`, `<div style="{{ . }}"></div>`, `<div style="ZgotmplZ"></div>`, `<div style="width: 60px;"></div>`},
-       } {
-               tmpl, err := template.New("test").Parse(this.tmplStr)
-               if err != nil {
-                       t.Errorf("[%d] unable to create new html template %q: %s", i, this.tmplStr, err)
-                       continue
-               }
-
-               buf := new(bytes.Buffer)
-               err = tmpl.Execute(buf, this.str)
-               if err != nil {
-                       t.Errorf("[%d] execute template with a raw string value returns unexpected error: %s", i, err)
-               }
-               if buf.String() != this.expectWithoutEscape {
-                       t.Errorf("[%d] execute template with a raw string value, got %v but expected %v", i, buf.String(), this.expectWithoutEscape)
-               }
-
-               buf.Reset()
-               err = tmpl.Execute(buf, SafeCSS(this.str))
-               if err != nil {
-                       t.Errorf("[%d] execute template with an escaped string value by SafeCSS returns unexpected error: %s", i, err)
-               }
-               if buf.String() != this.expectWithEscape {
-                       t.Errorf("[%d] execute template with an escaped string value by SafeCSS, got %v but expected %v", i, buf.String(), this.expectWithEscape)
-               }
-       }
-}
-
-func TestSafeURL(t *testing.T) {
-       for i, this := range []struct {
-               str                 string
-               tmplStr             string
-               expectWithoutEscape string
-               expectWithEscape    string
-       }{
-               {`irc://irc.freenode.net/#golang`, `<a href="{{ . }}">IRC</a>`, `<a href="#ZgotmplZ">IRC</a>`, `<a href="irc://irc.freenode.net/#golang">IRC</a>`},
-       } {
-               tmpl, err := template.New("test").Parse(this.tmplStr)
-               if err != nil {
-                       t.Errorf("[%d] unable to create new html template %q: %s", i, this.tmplStr, err)
-                       continue
-               }
-
-               buf := new(bytes.Buffer)
-               err = tmpl.Execute(buf, this.str)
-               if err != nil {
-                       t.Errorf("[%d] execute template with a raw string value returns unexpected error: %s", i, err)
-               }
-               if buf.String() != this.expectWithoutEscape {
-                       t.Errorf("[%d] execute template with a raw string value, got %v but expected %v", i, buf.String(), this.expectWithoutEscape)
-               }
-
-               buf.Reset()
-               err = tmpl.Execute(buf, SafeURL(this.str))
-               if err != nil {
-                       t.Errorf("[%d] execute template with an escaped string value by SafeURL returns unexpected error: %s", i, err)
-               }
-               if buf.String() != this.expectWithEscape {
-                       t.Errorf("[%d] execute template with an escaped string value by SafeURL, got %v but expected %v", i, buf.String(), this.expectWithEscape)
-               }
-       }
-}
+// TODO(bep) test it