func jsBootstrap() template.HTML {
	files := []string{
		"/assets/js/bootstrap/transition.js",
		"/assets/js/bootstrap/util.js",
		"/assets/js/bootstrap/alert.js",
		"/assets/js/bootstrap/button.js",
		"/assets/js/bootstrap/carousel.js",
		"/assets/js/bootstrap/collapse.js",
		"/assets/js/bootstrap/dropdown.js",
		"/assets/js/bootstrap/modal.js",
		"/assets/js/bootstrap/scrollspy.js",
		"/assets/js/bootstrap/tab.js",
		"/assets/js/bootstrap/tooltip.js",
		"/assets/js/bootstrap/popover.js",
	}
	buf := bytes.Buffer{}
	for _, file := range files {
		buf.WriteString(fmt.Sprintf("<script src=\"%s\"></script>\n", file))
	}
	return template.HTML(buf.String())
}
jsBootstrap returns all javascript include tags for all twitter bootstrap
js plugins for the default generated bootstrap install.
package abcrender
import (
	"bytes"
	"encoding/json"
	"fmt"
	"html/template"
	"io"
	"io/ioutil"
	"path/filepath"
	"strings"
	"github.com/friendsofgo/errors"
	"github.com/unrolled/render"
)
type Renderer interface {
	Data(w io.Writer, status int, v []byte) error
	JSON(w io.Writer, status int, v interface{}) error
	Text(w io.Writer, status int, v string) error
	HTML(w io.Writer, status int, name string, binding interface{}) error
	HTMLWithLayout(w io.Writer, status int, name string, binding interface{}, layout string) error
}
type Render struct {
	*render.Render
	assetsManifest map[string]string
}
func (r *Render) HTML(w io.Writer, status int, name string, binding interface{}) error {
	return r.Render.HTML(w, status, name, binding)
}
func (r *Render) HTMLWithLayout(w io.Writer, status int, name string, binding interface{}, layout string) error {
	return r.Render.HTML(w, status, name, binding, render.HTMLOptions{Layout: layout})
}
func New(opts render.Options, manifest map[string]string) Renderer {
	return &Render{
		Render:         render.New(opts),
		assetsManifest: manifest,
	}
}
func GetManifest(publicPath string) (map[string]string, error) {
	manifestPath := filepath.Join(publicPath, "assets", "manifest.json")
	contents, err := ioutil.ReadFile(manifestPath)
	if err != nil {
		return nil, err
	}
	if len(contents) == 0 {
		return nil, errors.New("manifest.json is empty")
	}
	manifest := map[string]string{}
	err = json.Unmarshal(contents, &manifest)
	if err != nil {
		return nil, errors.Wrap(err, "cannot unmarshal manifest.json")
	}
	if len(manifest) == 0 {
		return nil, errors.New("manifest.json has no file mappings")
	}
	return manifest, nil
}
func AppHelpers(manifest map[string]string) template.FuncMap {
	return template.FuncMap{
		"liveReload": liveReloadHelper,
		"jsPath":     func(relpath string) string { return manifestHelper("js", relpath, manifest) },
		"cssPath":    func(relpath string) string { return manifestHelper("css", relpath, manifest) },
		"imgPath":    func(relpath string) string { return manifestHelper("img", relpath, manifest) },
		"videoPath":  func(relpath string) string { return manifestHelper("video", relpath, manifest) },
		"audioPath":  func(relpath string) string { return manifestHelper("audio", relpath, manifest) },
		"fontPath":   func(relpath string) string { return manifestHelper("font", relpath, manifest) },
		"assetPath": func(relpath string) string {
			v, ok := manifest[relpath]
			if !ok {
				return "/assets/" + relpath
			}
			return "/assets/" + v
		},
		"cssTag": cssTag,
		"jsTag":  jsTag,
		"joinPath": func(pieces ...string) string { return strings.Join(pieces, "/") },
		"jsBootstrap": jsBootstrap,
	}
}
func manifestHelper(typ string, relpath string, manifest map[string]string) string {
	v, ok := manifest[filepath.Join(typ, relpath)]
	if !ok {
		return fmt.Sprintf("/assets/%s/%s", typ, relpath)
	}
	return "/assets/" + v
}
func liveReloadHelper(relpath string, host string) string {
	return fmt.Sprintf("/assets/js/%s?host=%s", relpath, host)
}
func cssTag(relpath string) template.HTML {
	return template.HTML(fmt.Sprintf("<link href=\"%s\" rel=\"stylesheet\">", relpath))
}
func jsTag(relpath string) template.HTML {
	return template.HTML(fmt.Sprintf("<script src=\"%s\"></script>", relpath))
}