return dflt, nil
 }
 
+// canBeNil reports whether an untyped nil can be assigned to the type. See reflect.Zero.
+//
+// Copied from Go stdlib src/text/template/exec.go.
+func canBeNil(typ reflect.Type) bool {
+       switch typ.Kind() {
+       case reflect.Chan, reflect.Func, reflect.Interface, reflect.Map, reflect.Ptr, reflect.Slice:
+               return true
+       }
+       return false
+}
+
+// prepareArg checks if value can be used as an argument of type argType, and
+// converts an invalid value to appropriate zero if possible.
+//
+// Copied from Go stdlib src/text/template/funcs.go.
+func prepareArg(value reflect.Value, argType reflect.Type) (reflect.Value, error) {
+       if !value.IsValid() {
+               if !canBeNil(argType) {
+                       return reflect.Value{}, fmt.Errorf("value is nil; should be of type %s", argType)
+               }
+               value = reflect.Zero(argType)
+       }
+       if !value.Type().AssignableTo(argType) {
+               return reflect.Value{}, fmt.Errorf("value has type %s; should be %s", value.Type(), argType)
+       }
+       return value, nil
+}
+
+// index returns the result of indexing its first argument by the following
+// arguments. Thus "index x 1 2 3" is, in Go syntax, x[1][2][3]. Each
+// indexed item must be a map, slice, or array.
+//
+// Copied from Go stdlib src/text/template/funcs.go.
+func index(item interface{}, indices ...interface{}) (interface{}, error) {
+       v := reflect.ValueOf(item)
+       if !v.IsValid() {
+               return nil, fmt.Errorf("index of untyped nil")
+       }
+       for _, i := range indices {
+               index := reflect.ValueOf(i)
+               var isNil bool
+               if v, isNil = indirect(v); isNil {
+                       return nil, fmt.Errorf("index of nil pointer")
+               }
+               switch v.Kind() {
+               case reflect.Array, reflect.Slice, reflect.String:
+                       var x int64
+                       switch index.Kind() {
+                       case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+                               x = index.Int()
+                       case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
+                               x = int64(index.Uint())
+                       case reflect.Invalid:
+                               return nil, fmt.Errorf("cannot index slice/array with nil")
+                       default:
+                               return nil, fmt.Errorf("cannot index slice/array with type %s", index.Type())
+                       }
+                       if x < 0 || x >= int64(v.Len()) {
+                               // We deviate from stdlib here.  Don't return an error if the
+                               // index is out of range.
+                               return nil, nil
+                       }
+                       v = v.Index(int(x))
+               case reflect.Map:
+                       index, err := prepareArg(index, v.Type().Key())
+                       if err != nil {
+                               return nil, err
+                       }
+                       if x := v.MapIndex(index); x.IsValid() {
+                               v = x
+                       } else {
+                               v = reflect.Zero(v.Type().Elem())
+                       }
+               case reflect.Invalid:
+                       // the loop holds invariant: v.IsValid()
+                       panic("unreachable")
+               default:
+                       return nil, fmt.Errorf("can't index item of type %s", v.Type())
+               }
+       }
+       return v.Interface(), nil
+}
+
 // safeHTMLAttr returns a given string as html/template HTMLAttr content.
 //
 // safeHTMLAttr is currently disabled, pending further discussion
                "highlight":    highlight,
                "humanize":     humanize,
                "in":           in,
+               "index":        index,
                "int":          func(v interface{}) int { return cast.ToInt(v) },
                "intersect":    intersect,
                "isSet":        isSet,
 
                {map[string]string{"foo": "pop"}, `{{ index . "bar" | default "nada" }}`, `nada`, true},
                {map[string]string{"foo": "cat"}, `{{ default "nope" .foo }}`, `cat`, true},
                {map[string]string{"foo": "dog"}, `{{ default "nope" .foo "extra" }}`, ``, false},
+               {map[string]interface{}{"images": []string{}}, `{{ default "default.jpg" (index .images 0) }}`, `default.jpg`, true},
        } {
                tmpl, err := New().New("test").Parse(this.tpl)
                if err != nil {