func (tmpl *Template) Render(context ...interface{}) (string, error) {
	var buf bytes.Buffer
	err := tmpl.FRender(&buf, context...)
	return buf.String(), err
}
Render uses the given data source - generally a map or struct - to render
the compiled template and return the output.
package mustache
import (
	"bytes"
	"fmt"
	"html/template"
	"io"
	"io/ioutil"
	"os"
	"path"
	"reflect"
	"strconv"
	"strings"
)
var (
	AllowMissingVariables = true
)
type TagType uint
const (
	Invalid TagType = iota
	Variable
	Section
	InvertedSection
	Partial
)
func (t TagType) String() string {
	if int(t) < len(tagNames) {
		return tagNames[t]
	}
	return "type" + strconv.Itoa(int(t))
}
var tagNames = []string{
	Invalid:         "Invalid",
	Variable:        "Variable",
	Section:         "Section",
	InvertedSection: "InvertedSection",
	Partial:         "Partial",
}
type Tag interface {
	Type() TagType
	Name() string
	Tags() []Tag
}
type textElement struct {
	text []byte
}
type varElement struct {
	name string
	raw  bool
}
type sectionElement struct {
	name      string
	inverted  bool
	startline int
	elems     []interface{}
}
type partialElement struct {
	name string
	prov PartialProvider
}
type Template struct {
	data    string
	otag    string
	ctag    string
	p       int
	curline int
	dir     string
	elems   []interface{}
	partial PartialProvider
}
type parseError struct {
	line    int
	message string
}
func (tmpl *Template) Tags() []Tag {
	return extractTags(tmpl.elems)
}
func extractTags(elems []interface{}) []Tag {
	tags := make([]Tag, 0, len(elems))
	for _, elem := range elems {
		switch elem := elem.(type) {
		case *varElement:
			tags = append(tags, elem)
		case *sectionElement:
			tags = append(tags, elem)
		case *partialElement:
			tags = append(tags, elem)
		}
	}
	return tags
}
func (e *varElement) Type() TagType {
	return Variable
}
func (e *varElement) Name() string {
	return e.name
}
func (e *varElement) Tags() []Tag {
	panic("mustache: Tags on Variable type")
}
func (e *sectionElement) Type() TagType {
	if e.inverted {
		return InvertedSection
	}
	return Section
}
func (e *sectionElement) Name() string {
	return e.name
}
func (e *sectionElement) Tags() []Tag {
	return extractTags(e.elems)
}
func (e *partialElement) Type() TagType {
	return Partial
}
func (e *partialElement) Name() string {
	return e.name
}
func (e *partialElement) Tags() []Tag {
	return nil
}
func (p parseError) Error() string {
	return fmt.Sprintf("line %d: %s", p.line, p.message)
}
func (tmpl *Template) readString(s string) (string, error) {
	newlines := 0
	for i := tmpl.p; ; i++ {
		if i+len(s) > len(tmpl.data) {
			return tmpl.data[tmpl.p:], io.EOF
		}
		if tmpl.data[i] == '\n' {
			newlines++
		}
		if tmpl.data[i] != s[0] {
			continue
		}
		match := true
		for j := 1; j < len(s); j++ {
			if s[j] != tmpl.data[i+j] {
				match = false
				break
			}
		}
		if match {
			e := i + len(s)
			text := tmpl.data[tmpl.p:e]
			tmpl.p = e
			tmpl.curline += newlines
			return text, nil
		}
	}
}
func (tmpl *Template) parsePartial(name string) (*partialElement, error) {
	var prov PartialProvider
	if tmpl.partial == nil {
		prov = &FileProvider{
			Paths: []string{tmpl.dir, " "},
		}
	} else {
		prov = tmpl.partial
	}
	return &partialElement{
		name: name,
		prov: prov,
	}, nil
}
func (tmpl *Template) parseSection(section *sectionElement) error {
	for {
		text, err := tmpl.readString(tmpl.otag)
		if err == io.EOF {
			return parseError{section.startline, "Section " + section.name + " has no closing tag"}
		}
		text = text[0 : len(text)-len(tmpl.otag)]
		section.elems = append(section.elems, &textElement{[]byte(text)})
		if tmpl.p < len(tmpl.data) && tmpl.data[tmpl.p] == '{' {
			text, err = tmpl.readString("}" + tmpl.ctag)
		} else {
			text, err = tmpl.readString(tmpl.ctag)
		}
		if err == io.EOF {
			return parseError{tmpl.curline, "unmatched open tag"}
		}
		tag := strings.TrimSpace(text[0 : len(text)-len(tmpl.ctag)])
		if len(tag) == 0 {
			return parseError{tmpl.curline, "empty tag"}
		}
		switch tag[0] {
		case '!':
			break
		case '#', '^':
			name := strings.TrimSpace(tag[1:])
			if len(tmpl.data) > tmpl.p && tmpl.data[tmpl.p] == '\n' {
				tmpl.p++
			} else if len(tmpl.data) > tmpl.p+1 && tmpl.data[tmpl.p] == '\r' && tmpl.data[tmpl.p+1] == '\n' {
				tmpl.p += 2
			}
			se := sectionElement{name, tag[0] == '^', tmpl.curline, []interface{}{}}
			err := tmpl.parseSection(&se)
			if err != nil {
				return err
			}
			section.elems = append(section.elems, &se)
		case '/':
			name := strings.TrimSpace(tag[1:])
			if name != section.name {
				return parseError{tmpl.curline, "interleaved closing tag: " + name}
			}
			return nil
		case '>':
			name := strings.TrimSpace(tag[1:])
			partial, err := tmpl.parsePartial(name)
			if err != nil {
				return err
			}
			section.elems = append(section.elems, partial)
		case '=':
			if tag[len(tag)-1] != '=' {
				return parseError{tmpl.curline, "Invalid meta tag"}
			}
			tag = strings.TrimSpace(tag[1 : len(tag)-1])
			newtags := strings.SplitN(tag, " ", 2)
			if len(newtags) == 2 {
				tmpl.otag = newtags[0]
				tmpl.ctag = newtags[1]
			}
		case '{':
			if tag[len(tag)-1] == '}' {
				section.elems = append(section.elems, &varElement{tag[1 : len(tag)-1], true})
			}
		default:
			section.elems = append(section.elems, &varElement{tag, false})
		}
	}
}
func (tmpl *Template) parse() error {
	for {
		text, err := tmpl.readString(tmpl.otag)
		if err == io.EOF {
			tmpl.elems = append(tmpl.elems, &textElement{[]byte(text)})
			return nil
		}
		text = text[0 : len(text)-len(tmpl.otag)]
		tmpl.elems = append(tmpl.elems, &textElement{[]byte(text)})
		if tmpl.p < len(tmpl.data) && tmpl.data[tmpl.p] == '{' {
			text, err = tmpl.readString("}" + tmpl.ctag)
		} else {
			text, err = tmpl.readString(tmpl.ctag)
		}
		if err == io.EOF {
			return parseError{tmpl.curline, "unmatched open tag"}
		}
		tag := strings.TrimSpace(text[0 : len(text)-len(tmpl.ctag)])
		if len(tag) == 0 {
			return parseError{tmpl.curline, "empty tag"}
		}
		switch tag[0] {
		case '!':
			break
		case '#', '^':
			name := strings.TrimSpace(tag[1:])
			if len(tmpl.data) > tmpl.p && tmpl.data[tmpl.p] == '\n' {
				tmpl.p++
			} else if len(tmpl.data) > tmpl.p+1 && tmpl.data[tmpl.p] == '\r' && tmpl.data[tmpl.p+1] == '\n' {
				tmpl.p += 2
			}
			se := sectionElement{name, tag[0] == '^', tmpl.curline, []interface{}{}}
			err := tmpl.parseSection(&se)
			if err != nil {
				return err
			}
			tmpl.elems = append(tmpl.elems, &se)
		case '/':
			return parseError{tmpl.curline, "unmatched close tag"}
		case '>':
			name := strings.TrimSpace(tag[1:])
			partial, err := tmpl.parsePartial(name)
			if err != nil {
				return err
			}
			tmpl.elems = append(tmpl.elems, partial)
		case '=':
			if tag[len(tag)-1] != '=' {
				return parseError{tmpl.curline, "Invalid meta tag"}
			}
			tag = strings.TrimSpace(tag[1 : len(tag)-1])
			newtags := strings.SplitN(tag, " ", 2)
			if len(newtags) == 2 {
				tmpl.otag = newtags[0]
				tmpl.ctag = newtags[1]
			}
		case '{':
			if tag[len(tag)-1] == '}' {
				tmpl.elems = append(tmpl.elems, &varElement{tag[1 : len(tag)-1], true})
			}
		default:
			tmpl.elems = append(tmpl.elems, &varElement{tag, false})
		}
	}
}
func lookup(contextChain []interface{}, name string, allowMissing bool) (reflect.Value, error) {
	if name != "." && strings.Contains(name, ".") {
		parts := strings.SplitN(name, ".", 2)
		v, err := lookup(contextChain, parts[0], allowMissing)
		if err != nil {
			return v, err
		}
		return lookup([]interface{}{v}, parts[1], allowMissing)
	}
	defer func() {
		if r := recover(); r != nil {
			fmt.Printf("Panic while looking up %q: %s\n", name, r)
		}
	}()
Outer:
	for _, ctx := range contextChain {
		v := ctx.(reflect.Value)
		for v.IsValid() {
			typ := v.Type()
			if n := v.Type().NumMethod(); n > 0 {
				for i := 0; i < n; i++ {
					m := typ.Method(i)
					mtyp := m.Type
					if m.Name == name && mtyp.NumIn() == 1 {
						return v.Method(i).Call(nil)[0], nil
					}
				}
			}
			if name == "." {
				return v, nil
			}
			switch av := v; av.Kind() {
			case reflect.Ptr:
				v = av.Elem()
			case reflect.Interface:
				v = av.Elem()
			case reflect.Struct:
				ret := av.FieldByName(name)
				if ret.IsValid() {
					return ret, nil
				}
				continue Outer
			case reflect.Map:
				ret := av.MapIndex(reflect.ValueOf(name))
				if ret.IsValid() {
					return ret, nil
				}
				continue Outer
			default:
				continue Outer
			}
		}
	}
	if allowMissing {
		return reflect.Value{}, nil
	}
	return reflect.Value{}, fmt.Errorf("Missing variable %q", name)
}
func isEmpty(v reflect.Value) bool {
	if !v.IsValid() || v.Interface() == nil {
		return true
	}
	valueInd := indirect(v)
	if !valueInd.IsValid() {
		return true
	}
	switch val := valueInd; val.Kind() {
	case reflect.Bool:
		return !val.Bool()
	case reflect.Slice:
		return val.Len() == 0
	case reflect.String:
		return len(strings.TrimSpace(val.String())) == 0
	}
	return false
}
func indirect(v reflect.Value) reflect.Value {
loop:
	for v.IsValid() {
		switch av := v; av.Kind() {
		case reflect.Ptr:
			v = av.Elem()
		case reflect.Interface:
			v = av.Elem()
		default:
			break loop
		}
	}
	return v
}
func renderSection(section *sectionElement, contextChain []interface{}, buf io.Writer) error {
	value, err := lookup(contextChain, section.name, true)
	if err != nil {
		return err
	}
	var context = contextChain[len(contextChain)-1].(reflect.Value)
	var contexts = []interface{}{}
	isEmpty := isEmpty(value)
	if isEmpty && !section.inverted || !isEmpty && section.inverted {
		return nil
	} else if !section.inverted {
		valueInd := indirect(value)
		switch val := valueInd; val.Kind() {
		case reflect.Slice:
			for i := 0; i < val.Len(); i++ {
				contexts = append(contexts, val.Index(i))
			}
		case reflect.Array:
			for i := 0; i < val.Len(); i++ {
				contexts = append(contexts, val.Index(i))
			}
		case reflect.Map, reflect.Struct:
			contexts = append(contexts, value)
		default:
			contexts = append(contexts, context)
		}
	} else if section.inverted {
		contexts = append(contexts, context)
	}
	chain2 := make([]interface{}, len(contextChain)+1)
	copy(chain2[1:], contextChain)
	for _, ctx := range contexts {
		chain2[0] = ctx
		for _, elem := range section.elems {
			renderElement(elem, chain2, buf)
		}
	}
	return nil
}
func renderElement(element interface{}, contextChain []interface{}, buf io.Writer) error {
	switch elem := element.(type) {
	case *textElement:
		buf.Write(elem.text)
	case *varElement:
		defer func() {
			if r := recover(); r != nil {
				fmt.Printf("Panic while looking up %q: %s\n", elem.name, r)
			}
		}()
		val, err := lookup(contextChain, elem.name, AllowMissingVariables)
		if err != nil {
			return err
		}
		if val.IsValid() {
			if elem.raw {
				fmt.Fprint(buf, val.Interface())
			} else {
				s := fmt.Sprint(val.Interface())
				template.HTMLEscape(buf, []byte(s))
			}
		}
	case *sectionElement:
		if err := renderSection(elem, contextChain, buf); err != nil {
			return err
		}
	case *partialElement:
		partial, err := elem.prov.Get(elem.name)
		if err != nil {
			return err
		}
		if err := partial.renderTemplate(contextChain, buf); err != nil {
			return err
		}
	}
	return nil
}
func (tmpl *Template) renderTemplate(contextChain []interface{}, buf io.Writer) error {
	for _, elem := range tmpl.elems {
		if err := renderElement(elem, contextChain, buf); err != nil {
			return err
		}
	}
	return nil
}
func (tmpl *Template) FRender(out io.Writer, context ...interface{}) error {
	var contextChain []interface{}
	for _, c := range context {
		val := reflect.ValueOf(c)
		contextChain = append(contextChain, val)
	}
	return tmpl.renderTemplate(contextChain, out)
}