func (s *AmberEngine) loadAssets() error {
	virtualDirectory, virtualExtension := s.directory, s.extension
	assetFn, namesFn := s.assetFn, s.namesFn
	funcs := template.FuncMap{}
	for k, v := range amber.FuncMap {  
		funcs[k] = v
	}
	for k, v := range s.funcs {
		funcs[k] = v
	}
	if len(virtualDirectory) > 0 {
		if virtualDirectory[0] == '.' {  
			virtualDirectory = virtualDirectory[1:]
		}
		if virtualDirectory[0] == '/' || virtualDirectory[0] == filepath.Separator {  
			virtualDirectory = virtualDirectory[1:]
		}
	}
	amber.FuncMap = funcs  
	names := namesFn()
	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 {
				return err
			}
			buf, err := assetFn(path)
			if err != nil {
				return err
			}
			name := filepath.ToSlash(rel)
			tmpl, err := amber.CompileData(buf, name, amber.DefaultOptions)
			if err != nil {
				return err
			}
			s.templateCache[name] = tmpl
		}
	}
	return nil
}
loadAssets builds the templates by binary, embedded.
package view
import (
	"fmt"
	"html/template"
	"io"
	"path/filepath"
	"strings"
	"sync"
	"github.com/eknkc/amber"
)
type AmberEngine struct {
	directory string
	extension string
	assetFn   func(name string) ([]byte, error)  
	namesFn   func() []string                    
	reload    bool
	rmu           sync.RWMutex  
	funcs         map[string]interface{}
	templateCache map[string]*template.Template
}
var _ Engine = &AmberEngine{}
func Amber(directory, extension string) *AmberEngine {
	s := &AmberEngine{
		directory:     directory,
		extension:     extension,
		templateCache: make(map[string]*template.Template, 0),
		funcs:         make(map[string]interface{}, 0),
	}
	return s
}
func (s *AmberEngine) Ext() string {
	return s.extension
}
func (s *AmberEngine) Binary(assetFn func(name string) ([]byte, error), namesFn func() []string) *AmberEngine {
	s.assetFn, s.namesFn = assetFn, namesFn
	return s
}
func (s *AmberEngine) Reload(developmentMode bool) *AmberEngine {
	s.reload = developmentMode
	return s
}
func (s *AmberEngine) AddFunc(funcName string, funcBody interface{}) {
	s.rmu.Lock()
	s.funcs[funcName] = funcBody
	s.rmu.Unlock()
}
func (s *AmberEngine) 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 *AmberEngine) loadDirectory() error {
	dir, extension := s.directory, s.extension
	opt := amber.DirOptions{}
	opt.Recursive = true
	funcs := template.FuncMap{}
	for k, v := range amber.FuncMap {  
		funcs[k] = v
	}
	for k, v := range s.funcs {
		funcs[k] = v
	}
	amber.FuncMap = funcs  
	opt.Ext = extension
	templates, err := amber.CompileDir(dir, opt, amber.DefaultOptions)  
	if err == nil {
		s.templateCache = make(map[string]*template.Template)
		for k, v := range templates {
			name := filepath.ToSlash(k + opt.Ext)
			s.templateCache[name] = v
			delete(templates, k)
		}
	}
	return err
}