func NewTemplateSet() *TemplateSet {
	return &TemplateSet{
		sets: make(map[string]*template.Template),
		dirs: make(map[string]string),
	}
}
NewTemplateSet initializes a new empty template set.
package macaron
import (
	"bytes"
	"encoding/json"
	"encoding/xml"
	"fmt"
	"html/template"
	"io"
	"io/ioutil"
	"net/http"
	"os"
	"path"
	"path/filepath"
	"strings"
	"sync"
	"time"
	"github.com/unknwon/com"
)
const (
	_CONTENT_TYPE    = "Content-Type"
	_CONTENT_BINARY  = "application/octet-stream"
	_CONTENT_JSON    = "application/json"
	_CONTENT_HTML    = "text/html"
	_CONTENT_PLAIN   = "text/plain"
	_CONTENT_XHTML   = "application/xhtml+xml"
	_CONTENT_XML     = "text/xml"
	_DEFAULT_CHARSET = "UTF-8"
)
var (
	bufpool = sync.Pool{
		New: func() interface{} { return new(bytes.Buffer) },
	}
	helperFuncs = template.FuncMap{
		"yield": func() (string, error) {
			return "", fmt.Errorf("yield called with no layout defined")
		},
		"current": func() (string, error) {
			return "", nil
		},
	}
)
type (
	TemplateFile interface {
		Name() string
		Data() []byte
		Ext() string
	}
	TemplateFileSystem interface {
		ListFiles() []TemplateFile
		Get(string) (io.Reader, error)
	}
	Delims struct {
		Left string
		Right string
	}
	RenderOptions struct {
		Directory string
		AppendDirectories []string
		Layout string
		Extensions []string
		Funcs []template.FuncMap
		Delims Delims
		Charset string
		IndentJSON bool
		IndentXML bool
		PrefixJSON []byte
		PrefixXML []byte
		HTMLContentType string
		TemplateFileSystem
	}
	HTMLOptions struct {
		Layout string
	}
	Render interface {
		http.ResponseWriter
		SetResponseWriter(http.ResponseWriter)
		JSON(int, interface{})
		JSONString(interface{}) (string, error)
		RawData(int, []byte)    
		PlainText(int, []byte)  
		HTML(int, string, interface{}, ...HTMLOptions)
		HTMLSet(int, string, string, interface{}, ...HTMLOptions)
		HTMLSetString(string, string, interface{}, ...HTMLOptions) (string, error)
		HTMLString(string, interface{}, ...HTMLOptions) (string, error)
		HTMLSetBytes(string, string, interface{}, ...HTMLOptions) ([]byte, error)
		HTMLBytes(string, interface{}, ...HTMLOptions) ([]byte, error)
		XML(int, interface{})
		Error(int, ...string)
		Status(int)
		SetTemplatePath(string, string)
		HasTemplateSet(string) bool
	}
)
type TplFile struct {
	name string
	data []byte
	ext  string
}
func NewTplFile(name string, data []byte, ext string) *TplFile {
	return &TplFile{name, data, ext}
}
func (f *TplFile) Name() string {
	return f.name
}
func (f *TplFile) Data() []byte {
	return f.data
}
func (f *TplFile) Ext() string {
	return f.ext
}
type TplFileSystem struct {
	files []TemplateFile
}
func NewTemplateFileSystem(opt RenderOptions, omitData bool) TplFileSystem {
	fs := TplFileSystem{}
	fs.files = make([]TemplateFile, 0, 10)
	dirs := make([]string, 0, len(opt.AppendDirectories)+1)
	for i := len(opt.AppendDirectories) - 1; i >= 0; i-- {
		dirs = append(dirs, opt.AppendDirectories[i])
	}
	dirs = append(dirs, opt.Directory)
	var err error
	for i := range dirs {
		if !com.IsExist(dirs[i]) {
			continue
		}
		dirs[i], err = filepath.EvalSymlinks(dirs[i])
		if err != nil {
			panic("EvalSymlinks(" + dirs[i] + "): " + err.Error())
		}
	}
	lastDir := dirs[len(dirs)-1]
	if err = filepath.Walk(lastDir, func(path string, info os.FileInfo, _ error) error {
		r, err := filepath.Rel(lastDir, path)
		if err != nil {
			return err
		}
		ext := GetExt(r)
		for _, extension := range opt.Extensions {
			if ext != extension {
				continue
			}
			var data []byte
			if !omitData {
				for i := range dirs {
					path = filepath.Join(dirs[i], r)
					if !com.IsFile(path) {
						continue
					}
					data, err = ioutil.ReadFile(path)
					if err != nil {
						return err
					}
					break
				}
			}
			name := filepath.ToSlash((r[0 : len(r)-len(ext)]))
			fs.files = append(fs.files, NewTplFile(name, data, ext))
		}
		return nil
	}); err != nil {
		panic("NewTemplateFileSystem: " + err.Error())
	}
	return fs
}
func (fs TplFileSystem) ListFiles() []TemplateFile {
	return fs.files
}
func (fs TplFileSystem) Get(name string) (io.Reader, error) {
	for i := range fs.files {
		if fs.files[i].Name()+fs.files[i].Ext() == name {
			return bytes.NewReader(fs.files[i].Data()), nil
		}
	}
	return nil, fmt.Errorf("file '%s' not found", name)
}
func PrepareCharset(charset string) string {
	if len(charset) != 0 {
		return "; charset=" + charset
	}
	return "; charset=" + _DEFAULT_CHARSET
}
func GetExt(s string) string {
	index := strings.Index(s, ".")
	if index == -1 {
		return ""
	}
	return s[index:]
}
func compile(opt RenderOptions) *template.Template {
	t := template.New(opt.Directory)
	t.Delims(opt.Delims.Left, opt.Delims.Right)
	template.Must(t.Parse("Macaron"))
	if opt.TemplateFileSystem == nil {
		opt.TemplateFileSystem = NewTemplateFileSystem(opt, false)
	}
	for _, f := range opt.TemplateFileSystem.ListFiles() {
		tmpl := t.New(f.Name())
		for _, funcs := range opt.Funcs {
			tmpl.Funcs(funcs)
		}
		template.Must(tmpl.Funcs(helperFuncs).Parse(string(f.Data())))
	}
	return t
}
const (
	DEFAULT_TPL_SET_NAME = "DEFAULT"
)
type TemplateSet struct {
	lock sync.RWMutex
	sets map[string]*template.Template
	dirs map[string]string
}