func (th *Theme) Template(name string) *template.Template {
	return th.templates[name]
}
Template gets template by name
package theme
import (
	"bytes"
	"errors"
	"fmt"
	"html/template"
	"io"
	"io/ioutil"
	"os"
	"path"
	"path/filepath"
	"regexp"
	"strings"
	"sync"
	"github.com/Unknwon/com"
	"github.com/go-xiaohei/pugo/app/model"
	"github.com/go-xiaohei/pugo/app/vars"
	"github.com/mcuadros/go-version"
	"gopkg.in/inconshreveable/log15.v2"
)
var (
	reDefineTag   = regexp.MustCompile("{{ ?define \"([^\"]*)\" ?\"?([a-zA-Z0-9]*)?\"? ?}}")
	reTemplateTag = regexp.MustCompile("{{ ?template \"([^\"]*)\" ?([^ ]*)? ?}}")
	errThemeMetaMissing     = errors.New("need add theme meta file")
	errThemeOutdatedVersion = errors.New("theme need newer PuGo version")
)
type (
	Theme struct {
		Meta       *Meta
		metaFile   string
		metaError  error
		dir        string
		lock       sync.Mutex
		funcMap    template.FuncMap
		templates  map[string]*template.Template
		extensions []string
		cache               []*namedTemplate
		regularTemplateDefs []string
	}
	namedTemplate struct {
		Name string
		Src  string
	}
)
func New(dir string) *Theme {
	theme := &Theme{
		dir:        dir,
		funcMap:    make(template.FuncMap),
		extensions: []string{".html"},
	}
	theme.funcMap["HTML"] = func(v interface{}) template.HTML {
		if str, ok := v.(string); ok {
			return template.HTML(str)
		}
		if b, ok := v.([]byte); ok {
			return template.HTML(string(b))
		}
		return template.HTML(fmt.Sprintf("%v", v))
	}
	theme.funcMap["Include"] = func(values ...interface{}) template.HTML {
		var buf bytes.Buffer
		if len(values) < 2 {
			return template.HTML("<!-- include template without path or data -->")
		}
		var pathData []string
		for i, v := range values {
			if i < len(values)-1 {
				str, ok := v.(string)
				if !ok {
					return template.HTML("<!-- include template with non-string path -->")
				}
				pathData = append(pathData, str)
			}
		}
		tpl := path.Join(pathData...)
		if err := theme.Execute(&buf, tpl, values[len(values)-1]); err != nil {
			return template.HTML("<!-- template " + tpl + " error:" + err.Error() + "-->")
		}
		return template.HTML(string(buf.Bytes()))
	}
	theme.parseMeta()
	return theme
}
func (th *Theme) parseMeta() {
	for t, f := range model.ShouldThemeMetaFiles() {
		file := path.Join(th.dir, f)
		if !com.IsFile(file) {
			continue
		}
		data, err := ioutil.ReadFile(file)
		if err != nil {
			th.metaError = err
			return
		}
		th.Meta, th.metaError = NewMeta(data, t)
		if th.Meta != nil {
			th.metaFile = file
			log15.Debug("Theme|%s", file)
		}
		return
	}
}
func (th *Theme) Func(key string, fn interface{}) {
	th.funcMap[key] = fn
}
func (th *Theme) Funcs() template.FuncMap {
	return th.funcMap
}
func (th *Theme) Load() error {
	return th.loadTemplates()
}
func (th *Theme) loadTemplates() error {
	th.lock.Lock()
	defer th.lock.Unlock()
	templates := make(map[string]*template.Template)
	err := filepath.Walk(th.dir, func(p string, fi os.FileInfo, err error) error {
		r, err := filepath.Rel(th.dir, p)  
		if err != nil {
			return err
		}
		ext := getExt(r)
		for _, extension := range th.extensions {
			if ext == extension {
				if err := th.add(p); err != nil {
					return err
				}
				for _, t := range th.regularTemplateDefs {
					found := false
					defineIdx := 0
					for _, nt := range th.cache {
						nt.Src = reDefineTag.ReplaceAllStringFunc(nt.Src, func(raw string) string {
							parsed := reDefineTag.FindStringSubmatch(raw)
							name := parsed[1]
							if name != t {
								return raw
							}
							if !found {
								found = true
								return raw
							}
							defineIdx++
							return fmt.Sprintf("{{ define \"%s_invalidated_#%d\" }}", name, defineIdx)
						})
					}
				}
				var (
					baseTmpl *template.Template
					i        int
				)
				for _, nt := range th.cache {
					var currentTmpl *template.Template
					if i == 0 {
						baseTmpl = template.New(nt.Name)
						currentTmpl = baseTmpl
					} else {
						currentTmpl = baseTmpl.New(nt.Name)
					}
					if _, err := currentTmpl.Funcs(th.funcMap).Parse(nt.Src); err != nil {
						return err
					}
					i++
				}
				tname := generateTemplateName(th.dir, p)
				templates[tname] = baseTmpl
				th.cache = th.cache[0:0]
				break
			}
		}
		return nil
	})
	th.templates = templates
	return err
}
func (th *Theme) add(path string) error {
	tplSrc, err := getFileContent(path)
	if err != nil {
		return err
	}
	tplName := generateTemplateName(th.dir, path)
	alreadyIncluded := false
	for _, nt := range th.cache {
		if nt.Name == tplName {
			alreadyIncluded = true
			break
		}
	}
	if alreadyIncluded {
		return nil
	}
	nt := &namedTemplate{
		Name: tplName,
		Src:  tplSrc,
	}
	th.cache = append(th.cache, nt)
	for _, raw := range reTemplateTag.FindAllString(nt.Src, -1) {
		parsed := reTemplateTag.FindStringSubmatch(raw)
		templatePath := parsed[1]
		ext := getExt(templatePath)
		if !strings.Contains(templatePath, ext) {
			th.regularTemplateDefs = append(th.regularTemplateDefs, templatePath)
			continue
		}
		th.add(filepath.Join(th.dir, templatePath))
	}
	return nil
}
func (th *Theme) Execute(w io.Writer, name string, data interface{}) error {
	tpl := th.Template(name)
	if tpl == nil {
		return fmt.Errorf("template '%s' is missing", name)
	}
	return tpl.ExecuteTemplate(w, name, data)
}
func (th *Theme) StaticDir() string {
	return path.Join(th.dir, th.Static())
}
func (th *Theme) Dir() string {
	return th.dir
}
func (th *Theme) Static() string {
	return "static"
}