func (s *HTMLEngine) ExecuteWriter(w io.Writer, name string, layout string, bindingData interface{}) error {
	if s.reload {
		s.rmu.Lock()
		defer s.rmu.Unlock()
		if err := s.Load(); err != nil {
			return err
		}
	}
	layout = getLayout(layout, s.layout)
	if layout != "" {
		s.layoutFuncsFor(name, bindingData)
		name = layout
	} else {
		s.runtimeFuncsFor(name, bindingData)
	}
	return s.Templates.ExecuteTemplate(w, name, bindingData)
}
ExecuteWriter executes a template and writes its result to the w writer.
package view
import (
	"bytes"
	"fmt"
	"html/template"
	"io"
	"io/ioutil"
	"os"
	"path/filepath"
	"strings"
	"sync"
	"time"
)
type (
	HTMLEngine struct {
		directory string
		extension string
		assetFn   func(name string) ([]byte, error)  
		namesFn   func() []string                    
		reload    bool                               
		options     []string  
		left        string
		right       string
		layout      string
		rmu         sync.RWMutex  
		layoutFuncs map[string]interface{}
		funcs       map[string]interface{}
		middleware func(name string, contents string) (string, error)
		Templates  *template.Template
	}
)
var _ Engine = &HTMLEngine{}
var emptyFuncs = template.FuncMap{
	"yield": func() (string, error) {
		return "", fmt.Errorf("yield was called, yet no layout defined")
	},
	"partial": func() (string, error) {
		return "", fmt.Errorf("block was called, yet no layout defined")
	},
	"partial_r": func() (string, error) {
		return "", fmt.Errorf("block was called, yet no layout defined")
	},
	"current": func() (string, error) {
		return "", nil
	}, "render": func() (string, error) {
		return "", nil
	},
}
func HTML(directory, extension string) *HTMLEngine {
	s := &HTMLEngine{
		directory:   directory,
		extension:   extension,
		assetFn:     nil,
		namesFn:     nil,
		reload:      false,
		left:        "{{",
		right:       "}}",
		layout:      "",
		layoutFuncs: make(map[string]interface{}, 0),
		funcs:       make(map[string]interface{}, 0),
	}
	return s
}
func (s *HTMLEngine) Ext() string {
	return s.extension
}
func (s *HTMLEngine) Binary(assetFn func(name string) ([]byte, error), namesFn func() []string) *HTMLEngine {
	s.assetFn, s.namesFn = assetFn, namesFn
	return s
}
func (s *HTMLEngine) Reload(developmentMode bool) *HTMLEngine {
	s.reload = developmentMode
	return s
}
func (s *HTMLEngine) Option(opt ...string) *HTMLEngine {
	s.rmu.Lock()
	s.options = append(s.options, opt...)
	s.rmu.Unlock()
	return s
}
func (s *HTMLEngine) Delims(left, right string) *HTMLEngine {
	s.left, s.right = left, right
	return s
}
func (s *HTMLEngine) Layout(layoutFile string) *HTMLEngine {
	s.layout = layoutFile
	return s
}
func (s *HTMLEngine) AddLayoutFunc(funcName string, funcBody interface{}) *HTMLEngine {
	s.rmu.Lock()
	s.layoutFuncs[funcName] = funcBody
	s.rmu.Unlock()
	return s
}
func (s *HTMLEngine) AddFunc(funcName string, funcBody interface{}) {
	s.rmu.Lock()
	s.funcs[funcName] = funcBody
	s.rmu.Unlock()
}
func (s *HTMLEngine) Load() error {
	if s.assetFn != nil && s.namesFn != nil {
		return s.loadAssets()
	}
	dir, err := filepath.Abs(s.directory)
	if err != nil {
		return err
	}
	s.directory = dir
	return s.loadDirectory()
}
func (s *HTMLEngine) loadDirectory() error {
	dir, extension := s.directory, s.extension
	var templateErr error
	s.Templates = template.New(dir)
	s.Templates.Delims(s.left, s.right)
	filepath.Walk(dir, func(path string, info os.FileInfo, err error) error {
		if info == nil || info.IsDir() {
		} else {
			rel, err := filepath.Rel(dir, path)
			if err != nil {
				templateErr = err
				return err
			}
			ext := filepath.Ext(path)
			if ext == extension {
				buf, err := ioutil.ReadFile(path)
				if err != nil {
					templateErr = err
					return err
				}
				contents := string(buf)
				name := filepath.ToSlash(rel)
				tmpl := s.Templates.New(name)
				tmpl.Option(s.options...)
				if s.middleware != nil {
					contents, err = s.middleware(name, contents)
				}
				if err != nil {
					templateErr = err
					return err
				}
				_, err = tmpl.Funcs(emptyFuncs).Funcs(s.funcs).Parse(contents)
				if err != nil {
					templateErr = err
					return err
				}
			}
		}
		return nil
	})
	return templateErr
}
func (s *HTMLEngine) loadAssets() error {
	virtualDirectory, virtualExtension := s.directory, s.extension
	assetFn, namesFn := s.assetFn, s.namesFn
	var templateErr error
	s.Templates = template.New(virtualDirectory)
	s.Templates.Delims(s.left, s.right)
	names := namesFn()
	if len(virtualDirectory) > 0 {
		if virtualDirectory[0] == '.' {  
			virtualDirectory = virtualDirectory[1:]
		}
		if virtualDirectory[0] == '/' || virtualDirectory[0] == os.PathSeparator {  
			virtualDirectory = virtualDirectory[1:]
		}
	}
	for _, path := range names {
		if !strings.HasPrefix(path, virtualDirectory) {
			continue
		}
		ext := filepath.Ext(path)
		if ext == virtualExtension {
			rel, err := filepath.Rel(virtualDirectory, path)
			if err != nil {
				templateErr = err
				continue
			}
			buf, err := assetFn(path)
			if err != nil {
				templateErr = fmt.Errorf("%v for path '%s'", err, path)
				continue
			}
			contents := string(buf)
			name := filepath.ToSlash(rel)
			tmpl := s.Templates.New(name)
			tmpl.Option(s.options...)
			if s.middleware != nil {
				contents, err = s.middleware(name, contents)
				if err != nil {
					templateErr = fmt.Errorf("%v for name '%s'", err, name)
					continue
				}
			}
			tmpl.Funcs(emptyFuncs).Funcs(s.funcs).Parse(contents)
		}
	}
	return templateErr
}
func (s *HTMLEngine) executeTemplateBuf(name string, binding interface{}) (*bytes.Buffer, error) {
	buf := new(bytes.Buffer)
	err := s.Templates.ExecuteTemplate(buf, name, binding)
	return buf, err
}
func (s *HTMLEngine) layoutFuncsFor(name string, binding interface{}) {
	funcs := template.FuncMap{
		"yield": func() (template.HTML, error) {
			buf, err := s.executeTemplateBuf(name, binding)
			return template.HTML(buf.String()), err
		},
		"current": func() (string, error) {
			return name, nil
		},
		"partial": func(partialName string) (template.HTML, error) {
			fullPartialName := fmt.Sprintf("%s-%s", partialName, name)
			if s.Templates.Lookup(fullPartialName) != nil {
				buf, err := s.executeTemplateBuf(fullPartialName, binding)
				return template.HTML(buf.String()), err
			}
			return "", nil
		},
		"partial_r": func(partialName string) (template.HTML, error) {
			ext := filepath.Ext(name)
			root := name[:len(name)-len(ext)]
			fullPartialName := fmt.Sprintf("%s%s%s", root, partialName, ext)
			if s.Templates.Lookup(fullPartialName) != nil {
				buf, err := s.executeTemplateBuf(fullPartialName, binding)
				return template.HTML(buf.String()), err
			}
			return "", nil
		},
		"render": func(fullPartialName string) (template.HTML, error) {
			buf, err := s.executeTemplateBuf(fullPartialName, binding)
			return template.HTML(buf.String()), err
		},
	}
	for k, v := range s.layoutFuncs {
		funcs[k] = v
	}
	if tpl := s.Templates.Lookup(name); tpl != nil {
		tpl.Funcs(funcs)
	}
}
func (s *HTMLEngine) runtimeFuncsFor(name string, binding interface{}) {
	funcs := template.FuncMap{
		"render": func(fullPartialName string) (template.HTML, error) {
			buf, err := s.executeTemplateBuf(fullPartialName, binding)
			return template.HTML(buf.String()), err
		},
	}
	if tpl := s.Templates.Lookup(name); tpl != nil {
		tpl.Funcs(funcs)
	}
}
var zero = time.Time{}