コード例 #1
0
ファイル: main.go プロジェクト: adlerhsieh/another_go_web_app
func Register(templates *template.Template) {
	// http.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) {
	// 	// Load template according to the requested path, excluding the leading "/"
	// 	requestedFile := req.URL.Path[1:]
	// 	template := templates.Lookup(requestedFile + ".html")
	//
	// 	var context interface{} = nil
	// 	context = viewmodels.Get("My Title", requestedFile)
	//
	// 	if template != nil {
	// 		template.Execute(w, context)
	// 	} else {
	// 		w.WriteHeader(404)
	// 		w.Write([]byte("404 - " + http.StatusText(404)))
	// 	}
	// })

	ic := new(indexController)
	ic.template = templates.Lookup("index.html")
	http.HandleFunc("/index", ic.get)

	cc := new(categoriesController)
	cc.template = templates.Lookup("categories.html")
	http.HandleFunc("/categories", cc.get)

	// redirect /img/ and /css/ dir to assets/img/ and assets/css/
	http.HandleFunc("/img/", serveAssets)
	http.HandleFunc("/css/", serveAssets)
}
コード例 #2
0
ファイル: generator.go プロジェクト: alvaroloes/sdkgen
func (g *Generator) generatePerModelFiles(templateFileNames []string, modelTpls *template.Template, modelsDir string, filter func(modelInfo *modelInfo) bool) error {
	for _, tplFileName := range templateFileNames {
		tplName := filepath.Base(tplFileName)
		// Apply the templates to each model in the API
		for _, modelInfo := range g.modelsInfo {
			if filter(modelInfo) {
				continue
			}
			// TODO: Do this concurrently
			repl := strings.NewReplacer(
				templateExt, "",
				fileNameModelNameInterpolation, modelInfo.Name,
				fileNameAPINameInterpolation, g.config.APIName,
				fileNameAPIPrefixInterpolation, g.config.APIPrefix,
			)
			fileName := repl.Replace(tplName)
			err := generateFile(path.Join(modelsDir, fileName), modelTpls.Lookup(tplName), templateData{
				Config:           g.config,
				API:              g.api,
				CurrentModelInfo: modelInfo,
				AllModelsInfo:    g.modelsInfo,
				AuthInfo:         g.authInfo,
				CurrentTime:      time.Now(),
			})
			if err != nil {
				return errors.Annotatef(err, "when generating model or service %q", modelInfo.Name)
			}
		}
	}
	return nil
}
コード例 #3
0
ファイル: template_repo.go プロジェクト: jerbob92/go-swagger
func (t *Repository) addDependencies(templ *template.Template) (*template.Template, error) {

	name := templ.Name()

	deps := t.flattenDependencies(templ, nil)

	for dep := range deps {

		if dep == "" {
			continue
		}

		tt := templ.Lookup(dep)

		// Check if we have it
		if tt == nil {
			tt = t.templates[dep]

			// Still dont have it return an error
			if tt == nil {
				return templ, fmt.Errorf("Could not find template %s", dep)
			}
			var err error

			// Add it to the parse tree
			templ, err = templ.AddParseTree(dep, tt.Tree)

			if err != nil {
				return templ, fmt.Errorf("Dependency Error: %v", err)
			}

		}
	}
	return templ.Lookup(name), nil
}
コード例 #4
0
ファイル: codegen.go プロジェクト: jeffhoye/modelq
func (m ModelMeta) getTemplate(tmpl *template.Template, name string, defaultTmpl *template.Template) *template.Template {
	if tmpl != nil {
		if definedTmpl := tmpl.Lookup(name); definedTmpl != nil {
			return definedTmpl
		}
	}
	return defaultTmpl
}
コード例 #5
0
ファイル: templates.go プロジェクト: colonelmo/blacksmith
func executeTemplate(rootTemplte *template.Template, templateName string, machine datasource.Machine, hostAddr string) (string, error) {
	template := rootTemplte.Lookup(templateName)

	if template == nil {
		return "", fmt.Errorf("template with name=%s wasn't found for root=%s",
			templateName, rootTemplte)
	}

	buf := new(bytes.Buffer)
	template.Funcs(map[string]interface{}{
		"V": func(key string) string {
			flag, err := machine.GetFlag(key)
			if err != nil { // TODO excepts Not-Found
				logging.Log(templatesDebugTag,
					"Error while getting flag key=%s for machine=%s: %s",
					key, machine.Name(), err)
				return ""
			}
			return flag
		},
		"b64": func(text string) string {
			return base64.StdEncoding.EncodeToString([]byte(text))
		},
		"b64template": func(templateName string) string {
			text, err := executeTemplate(rootTemplte, templateName, machine, hostAddr)
			if err != nil {
				logging.Log(templatesDebugTag,
					"Error while b64template for templateName=%s machine=%s: %s",
					templateName, machine.Name(), err)
				return ""
			}
			return base64.StdEncoding.EncodeToString([]byte(text))
		},
	})
	ip, _ := machine.IP()
	data := struct {
		Mac      string
		IP       string
		Hostname string
		Domain   string
		HostAddr string
	}{
		machine.Mac().String(),
		ip.String(),
		machine.Name(),
		machine.Domain(),
		hostAddr,
	}
	err := template.ExecuteTemplate(buf, templateName, &data)
	if err != nil {
		return "", err
	}
	str := buf.String()
	str = strings.Trim(str, "\n")
	return str, nil
}
コード例 #6
0
ファイル: main.go プロジェクト: vincent-petithory/lonelycat
func FormatNotification(t *template.Template, n lonelycat.Notification) (string, error) {
	tpl := t.Lookup(n.Type)
	if tpl == nil {
		return "", ErrNoTemplate
	}
	var buf bytes.Buffer
	err := tpl.Execute(&buf, n)
	if err != nil {
		return "", err
	}
	return strings.TrimSpace(buf.String()), nil
}
コード例 #7
0
ファイル: template.go プロジェクト: klauern/caddy
func SetTemplate(t *template.Template, name, filename string) error {

	// Read template
	buf, err := ioutil.ReadFile(filename)
	if err != nil {
		return err
	}

	// Update if exists
	if tt := t.Lookup(name); tt != nil {
		_, err = tt.Parse(string(buf))
		return err
	}

	// Allocate new name if not
	_, err = t.New(name).Parse(string(buf))
	return err
}
コード例 #8
0
ファイル: centralCtrl.go プロジェクト: alok87/sysAdmin
func Register(template *template.Template) {

	uc := new(usersController)
	uc.template = template.Lookup("users.html")
	http.HandleFunc("/users", uc.serveUsers)
	http.HandleFunc("/ws", serveWs)

	http.HandleFunc("/img/", serveResource)
	http.HandleFunc("/css/", serveResource)
}
コード例 #9
0
ファイル: main.go プロジェクト: mattpetters/go-mvc
func Register(templates *template.Template) {
	// http.HandleFunc("/",
	// 	func(w http.ResponseWriter, r *http.Request) {
	// 		requestedFile := r.URL.Path[1:]
	// 		template := templates.Lookup(requestedFile + ".html")
	// 		fmt.Printf(requestedFile + "\n")
	//
	// 		var context interface{}
	// 		switch requestedFile {
	// 			case "home":
	// 				context = viewmodels.GetHome()
	// 			case "404":
	// 				context = viewmodels.Get404()
	// 			default:
	// 				template = templates.Lookup("404" + ".html")
	// 				context = viewmodels.Get404()
	// 				w.WriteHeader(404)
	// 				fmt.Printf("Showing 404 page \n")
	// 		}
	// 		if template != nil {
	// 			template.Execute(w, context)
	// 		} else {
	//
	// 		}
	// 	})

	//Home route
	hc := new(homeController)
	hc.template = templates.Lookup("home.html")
	http.HandleFunc("/home", hc.get)

	//Lights route
	lc := new(lightsController)
	lc.template = templates.Lookup("lights.html")
	http.HandleFunc("/lights", lc.get)

	http.HandleFunc("/img/", serveResource)
	http.HandleFunc("/css/", serveResource)
}
コード例 #10
0
ファイル: template.go プロジェクト: kurrik/tmpl
// Returns a copy of the root template with the supplied template merged in.
func (ts *Templates) mergeTemplate(t *template.Template) (out *template.Template, err error) {
	defer func() {
		if r := recover(); r != nil {
			// Seems to be a bug with cloning empty templates.
			err = fmt.Errorf("Problem cloning template: %v", r)
		}
	}()
	if ts.empty {
		out = template.New("root")
	} else {
		if out, err = ts.root.Clone(); err != nil {
			return
		}
	}
	for _, tmpl := range t.Templates() {
		ptr := out.Lookup(tmpl.Name())
		if ptr == nil {
			out.Parse(fmt.Sprintf(`{{define "%v"}}{{end}}`, tmpl.Name()))
			ptr = out.Lookup(tmpl.Name())
		}
		var clone *template.Template
		if clone, err = tmpl.Clone(); err != nil {
			return
		}
		(*ptr) = *clone
		// Merge existing root templates back into new template.
		for _, out_tmpl := range out.Templates() {
			ptr2 := clone.Lookup(out_tmpl.Name())
			if ptr2 == nil {
				clone.Parse(fmt.Sprintf(`{{define "%v"}}{{end}}`, out_tmpl.Name()))
				ptr2 = clone.Lookup(out_tmpl.Name())
				(*ptr2) = *out_tmpl
			}
		}
	}
	return
}
コード例 #11
0
ファイル: generator.go プロジェクト: alvaroloes/sdkgen
func (g *Generator) generateGeneralFiles(templateFileNames []string, generalTpls *template.Template, apiDir string) error {
	for _, tplFileName := range templateFileNames {
		tplName := filepath.Base(tplFileName)
		// TODO: Do this concurrently
		// Get the name of the file, replacing some special strings in the template name
		repl := strings.NewReplacer(
			templateExt, "",
			fileNameAPINameInterpolation, g.config.APIName,
			fileNameAPIPrefixInterpolation, g.config.APIPrefix,
		)
		fileName := repl.Replace(tplName)
		err := generateFile(path.Join(apiDir, fileName), generalTpls.Lookup(tplName), templateData{
			Config:        g.config,
			API:           g.api,
			AllModelsInfo: g.modelsInfo,
			CurrentTime:   time.Now(),
			AuthInfo:      g.authInfo,
		})
		if err != nil {
			return errors.Annotatef(err, "when generating API file %q", fileName)
		}
	}
	return nil
}
コード例 #12
0
ファイル: main.go プロジェクト: timchunght/gocart
func Register(templates *template.Template) {

	router := mux.NewRouter()

	hc := new(homeController)
	hc.template = templates.Lookup("home.html")
	router.HandleFunc("/home", hc.get)

	cc := new(categoriesController)
	cc.template = templates.Lookup("categories.html")
	router.HandleFunc("/categories", cc.get)

	categoryController := new(categoryController)
	categoryController.template = templates.Lookup("products.html")
	router.HandleFunc("/categories/{id}", categoryController.get)

	http.Handle("/", router)

	http.HandleFunc("/img/", serveResource)
	http.HandleFunc("/css/", serveResource)

}
コード例 #13
0
ファイル: templates.go プロジェクト: cafebazaar/blacksmith
func executeTemplate(rootTemplte *template.Template, templateName string,
	ds datasource.DataSource, machineInterface datasource.MachineInterface,
	webServerAddr string) (string, error) {
	template := rootTemplte.Lookup(templateName)

	if template == nil {
		return "", fmt.Errorf("template with name=%s wasn't found for root=%v",
			templateName, rootTemplte)
	}

	mac := machineInterface.Mac().String()

	buf := new(bytes.Buffer)
	template.Funcs(map[string]interface{}{
		"V": func(key string) string {
			value, err := machineInterface.GetVariable(key)
			if err != nil {
				log.WithField("where", "templating.executeTemplate").WithError(err).Warn(
					"error while GetVariable")
			}
			return value
		},
		"b64": func(text string) string {
			return base64.StdEncoding.EncodeToString([]byte(text))
		},
		"b64template": func(templateName string) string {
			text, err := executeTemplate(rootTemplte, templateName, ds, machineInterface, webServerAddr)
			if err != nil {
				log.WithField("where", "templating.executeTemplate").WithError(err).Warnf(
					"error while executeTemplate(templateName=%s machine=%s)",
					templateName, mac)
				return ""
			}
			return base64.StdEncoding.EncodeToString([]byte(text))
		},
	})

	etcdMembers, _ := ds.EtcdMembers()

	machine, err := machineInterface.Machine(false, nil)
	if err != nil {
		return "", err
	}

	data := struct {
		Mac           string
		IP            string
		Hostname      string
		Domain        string
		WebServerAddr string
		EtcdEndpoints string
	}{
		mac,
		machine.IP.String(),
		machineInterface.Hostname(),
		ds.ClusterName(),
		webServerAddr,
		etcdMembers,
	}
	err = template.ExecuteTemplate(buf, templateName, &data)
	if err != nil {
		return "", err
	}
	str := buf.String()
	str = strings.Trim(str, "\n")
	return str, nil
}
コード例 #14
0
ファイル: form.go プロジェクト: vpetrov/survana-tools
func (form *Form) toQualtrics(out io.Writer, templates *template.Template) (err error) {
	out.Write([]byte("[[AdvancedFormat]]"))

	var (
		field, next_field *Field
		qualtrics_field   *qualtricsField
		qualtrics_type    string
		i                 int = 0
		num_fields            = len(form.Fields)
	)

	for i < num_fields {
		field = &form.Fields[i]

		//attempt to link a question with its answer, based on the assumption that most
		//answer fields follow a 'question' field. If a question is followed by a question,
		//render the first one as a simple instruction field
		if field.SType == "question" {
			if i < num_fields-1 {
				next_field = &form.Fields[i+1]
				if next_field.SType == "question" {
					qualtrics_type, err = getQualtricsType(field)
					if err != nil {
						return
					}
					qualtrics_field = &qualtricsField{
						Question:         field,
						QuestionTemplate: templates.Lookup("instruction"),
						QualtricsType:    qualtrics_type,
						Answer:           nil,
						AnswerTemplate:   nil,
					}
				} else {
					//if this field has no html text, but answer has s-label, skip this field
					//and, on next iteration, convert the field label into a question
					if len(field.Html) == 0 && len(next_field.SLabel) > 0 {
						i++
						continue
					}
					qualtrics_type, err = getQualtricsType(next_field)
					if err != nil {
						return
					}
					qualtrics_field = &qualtricsField{
						Question:         field,
						QuestionTemplate: templates.Lookup("question"),
						QualtricsType:    qualtrics_type,
						Answer:           next_field,
						AnswerTemplate:   templates.Lookup(form.getTemplateName(next_field)),
					}
					i++
				}
			} else {
				qualtrics_field = &qualtricsField{
					Question:         field,
					QuestionTemplate: templates.Lookup("instruction"),
					Answer:           nil,
					AnswerTemplate:   nil,
				}
			}
		} else {
			qualtrics_type, err = getQualtricsType(field)
			if err != nil {
				return
			}

			var question *Field = nil
			var question_tpl *template.Template = nil

			if len(field.SLabel) > 0 {
				question = &Field{
					SId:   field.SId,
					SType: "question",
					Html:  field.SLabel,
				}
				question_tpl = templates.Lookup("question")
			}

			qualtrics_field = &qualtricsField{
				Question:         question,
				QuestionTemplate: question_tpl,
				Answer:           field,
				QualtricsType:    qualtrics_type,
				AnswerTemplate:   templates.Lookup(form.getTemplateName(field)),
			}
		}

		//output question
		if qualtrics_field.Question != nil {
			if qualtrics_field.QuestionTemplate == nil {
				err = fmt.Errorf("Question template not found for field %d: %s", i+1, qualtrics_field.Question)
				return
			}
			err = qualtrics_field.QuestionTemplate.Execute(out, qualtrics_field)
			if err != nil {
				return
			}
		}

		//output answer
		if qualtrics_field.Answer != nil {
			if qualtrics_field.AnswerTemplate == nil {
				err = fmt.Errorf("Answer template not found for field %d: %s", i+1, qualtrics_field.Answer)
				return
			}
			err = qualtrics_field.AnswerTemplate.Execute(out, qualtrics_field)
			if err != nil {
				return
			}
		}

		i++
	}

	return
}
コード例 #15
0
ファイル: main.go プロジェクト: lavalampmj/goafter7
func Register(templates *template.Template) {

	router := mux.NewRouter()

	hc := new(homeController)
	hc.template = templates.Lookup("home.html")
	router.HandleFunc("/home", hc.get)

	cc := new(categoriesController)
	cc.template = templates.Lookup("categories.html")
	router.HandleFunc("/categories", cc.get)

	categoryController := new(categoryController)
	categoryController.template = templates.Lookup("products.html")
	router.HandleFunc("/categories/{id}", categoryController.get)

	productController := new(productController)
	productController.template = templates.Lookup("product.html")
	router.HandleFunc("/products/{id}", productController.get)

	profileController := new(profileController)
	profileController.template = templates.Lookup("profile.html")
	router.HandleFunc("/profile", profileController.handle)

	standLocatorCtrl := new(standLocatorController)
	standLocatorCtrl.template = templates.Lookup("stand_locator.html")
	router.HandleFunc("/stand_locator", standLocatorCtrl.get)
	router.HandleFunc("/api/stand_locator", standLocatorCtrl.apiSearch)
	http.Handle("/", router)

	http.HandleFunc("/img/", serveResource)
	http.HandleFunc("/css/", serveResource)
}
コード例 #16
0
ファイル: main.go プロジェクト: Ikanant/GolangWebApp
// Will serve as the point where the controller layer configures itself and prepares to handle requests
// Receive the template CACHE that we build in the main package
// We will grab the three http functions form the main package
func Register(templates *template.Template) {

	// Now that we have Gorilla Mux, we need to create a new Router that will take the responsability away from us
	router := mux.NewRouter()
	//Gorilla Mux exposes an Interface that is very similar to the net/http package. So we just need to replace the http with router:

	hc := new(homeController)
	hc.template = templates.Lookup("home.html")
	hc.loginTemplate = templates.Lookup("login.html")
	hc.signupTemplate = templates.Lookup("signup.html")
	router.HandleFunc("/home", hc.get)
	router.HandleFunc("/login", hc.login)
	router.HandleFunc("/signup", hc.signup)
	router.HandleFunc("/logout", hc.logout)

	cc := new(categoriesController)
	cc.template = templates.Lookup("categories.html")
	router.HandleFunc("/categories", cc.get)

	categoryController := new(categoryController)
	categoryController.template = templates.Lookup("products.html")
	router.HandleFunc("/categories/{id}", categoryController.get)

	pc := new(productController)
	pc.template = templates.Lookup("product.html")
	router.HandleFunc("/product/{id}", pc.get)

	profileC := new(profileController)
	profileC.template = templates.Lookup("profile.html")
	router.HandleFunc("/profile", profileC.get)

	ac := new(aboutController)
	ac.template = templates.Lookup("about.html")
	router.HandleFunc("/about", ac.get)

	//Finally, we do need to use the HTTP package to set the router to listen for requests
	http.Handle("/", router)

	http.HandleFunc("/images/", serveResource)
	http.HandleFunc("/css/", serveResource)
	http.HandleFunc("/fonts/", serveResource)
	http.HandleFunc("/js/", serveResource)
}
コード例 #17
0
ファイル: templatepipe.go プロジェクト: vadv/ostent
func DataNode(root *template.Template, node parse.Node, data *Dotted, vars map[string][]string, prefixwords []string) {
	if true {
		switch node.Type() {
		case parse.NodeWith:
			withNode := node.(*parse.WithNode)
			arg0 := withNode.Pipe.Cmds[0].Args[0].String()
			var withv string
			if len(arg0) > 0 && arg0[0] == '.' {
				if decl := withNode.Pipe.Decl; len(decl) > 0 {
					// just {{with $ := ...}} cases

					withv = decl[0].Ident[0]
					words := strings.Split(arg0[1:], ".")
					vars[withv] = words
					data.Append(words, prefixwords)
				}
			}
			if withNode.List != nil {
				for _, n := range withNode.List.Nodes {
					DataNode(root, n, data, vars, prefixwords)
				}
			}
			if withNode.ElseList != nil {
				for _, n := range withNode.ElseList.Nodes {
					DataNode(root, n, data, vars, prefixwords)
				}
			}
			if withv != "" {
				delete(vars, withv)
			}
		case parse.NodeTemplate:
			tnode := node.(*parse.TemplateNode)
			var tawords []string
			for _, arg := range tnode.Pipe.Cmds[0].Args {
				s := arg.String()
				if len(s) > 1 && s[0] == '.' {
					tawords = strings.Split(s[1:], ".")
					data.Append(tawords, prefixwords)
					break // just one argument (pipeline) to "{{template}}" allowed anyway
				}
			}
			if sub := root.Lookup(tnode.Name); sub != nil && sub.Tree != nil && sub.Tree.Root != nil {
				for _, n := range sub.Tree.Root.Nodes {
					pw := prefixwords
					if tawords != nil {
						pw = append(prefixwords, tawords...)
					}
					DataNode(root, n, data, vars, pw)
				}
			}
		case parse.NodeAction:
			actionNode := node.(*parse.ActionNode)
			decl := actionNode.Pipe.Decl

			for _, cmd := range actionNode.Pipe.Cmds {
				if cmd.NodeType != parse.NodeCommand {
					continue
				}
				for _, arg := range cmd.Args {
					var ident []string
					switch arg.Type() {
					case parse.NodeChain:
						chain := arg.(*parse.ChainNode)
						if chain.Node.Type() == parse.NodePipe {
							pipe := chain.Node.(*parse.PipeNode)
							for _, arg := range pipe.Cmds[0].Args {
								if arg.Type() == parse.NodeField {
									w := arg.String()
									if len(w) > 0 && w[0] == '.' {
										data.Append(strings.Split(w[1:], "."), prefixwords)
									}
								}
							}
						}
					case parse.NodeField:
						ident = arg.(*parse.FieldNode).Ident

						if len(decl) > 0 && len(decl[0].Ident) > 0 {
							vars[decl[0].Ident[0]] = ident
						}
						data.Append(ident, prefixwords)

					case parse.NodeVariable:
						ident = arg.(*parse.VariableNode).Ident

						if words, ok := vars[ident[0]]; ok {
							words := append(words, ident[1:]...)
							data.Append(words, prefixwords)
							if len(decl) > 0 && len(decl[0].Ident) > 0 {
								vars[decl[0].Ident[0]] = words
							}
						}
					}
				}
			}
		case parse.NodeRange:
			rangeNode := node.(*parse.RangeNode)
			decl := rangeNode.Pipe.Decl[len(rangeNode.Pipe.Decl)-1].String()
			keys := []string{}

			for _, ifnode := range rangeNode.List.Nodes {
				switch ifnode.Type() {
				case parse.NodeAction:
					keys = append(keys, getKeys(decl, ifnode)...)
				case parse.NodeIf:
					for _, z := range ifnode.(*parse.IfNode).List.Nodes {
						if z.Type() == parse.NodeAction {
							keys = append(keys, getKeys(decl, z)...)
						}
					}
				case parse.NodeTemplate:
					// DataNode(root, ifnode, data, vars, prefixwords)
					arg0 := ifnode.(*parse.TemplateNode).Pipe.Cmds[0].Args[0]
					if arg0.Type() == parse.NodePipe {
						cmd0 := arg0.(*parse.PipeNode).Cmds[0]
						if cmd0.Type() == parse.NodeCommand {
							for _, a := range cmd0.Args {
								if s, prefix := a.String(), decl+"."; strings.HasPrefix(s, prefix) {
									keys = append(keys, strings.Split(strings.TrimPrefix(s, prefix), ".")...)
								}
							}
						}
					} else if arg0.Type() == parse.NodeVariable {
						keys = append(keys, arg0.(*parse.VariableNode).Ident[1:]...)
					}
				}
			}

			// fml
			arg0 := rangeNode.Pipe.Cmds[0].Args[0].String()
			words, ok := vars[arg0]
			if !ok && len(arg0) > 0 && arg0[0] == '.' {
				words = strings.Split(arg0[1:], ".")
				data.Append(words, prefixwords)
				ok = true
			}
			if ok {
				if leaf := data.Find(words); leaf != nil {
					leaf.Ranged = true
					leaf.Keys = append(leaf.Keys, keys...)
					leaf.Decl = decl // redefined $
				}
			}
		}
	}
}
コード例 #18
0
ファイル: dochandler.go プロジェクト: DaviWei/utils-1
/*
DocHandler will return a handler that renders the documentation for all routes registerd with DocHandle.

The resulting func will do this by going through each route in DocumentedRoutes and render the endpoint
using the provided template, providing it template functions to render separate endpoints, types, sub types
and examples of types.
*/
func DocHandler(templ *template.Template) http.Handler {
	return httpcontext.HandlerFunc(func(c httpcontext.HTTPContextLogger) (err error) {
		c.Resp().Header().Set("Content-Type", "text/html; charset=UTF-8")
		// we define a func to render a type
		// it basically just executes the "TypeTemplate" with the provided
		// stack to avoid infinite recursion
		renderType := func(t JSONType, stack []string) (result string, err error) {
			// if the type is already mentioned in one of the parents we have already mentioned,
			// bail
			for _, parent := range stack {
				if parent != "" && parent == t.ReflectType.Name() {
					result = fmt.Sprintf("[loop protector enabled, render stack: %v]", stack)
					return
				}
			}
			stack = append(stack, t.ReflectType.Name())
			buf := &bytes.Buffer{}
			// then execute the TypeTemplate with this type and this stack
			if err = templ.ExecuteTemplate(buf, "TypeTemplate", map[string]interface{}{
				"Type":  t,
				"Stack": stack,
			}); err != nil {
				return
			}
			result = buf.String()
			return
		}

		// routes are documented alphabetically
		sort.Sort(routes)
		// define all the functions that we left empty earlier
		err = templ.Funcs(map[string]interface{}{
			"RenderEndpoint": func(r DocumentedRoute) (string, error) {
				return r.Render(templ.Lookup("EndpointTemplate"))
			},
			"RenderSubType": func(t JSONType, stack []string) (result string, err error) {
				return renderType(t, stack)
			},
			"RenderType": func(t JSONType) (result string, err error) {
				return renderType(t, nil)
			},
			"First": first,
			"Example": func(r JSONType) (result string, err error) {
				// this will render an example of the provided JSONType
				defer func() {
					if e := recover(); e != nil {
						result = fmt.Sprintf("%v\n%s", e, utils.Stack())
					}
				}()
				x := utils.Example(r.ReflectType)
				b, err := json.MarshalIndent(x, "", "  ")
				if err != nil {
					return
				}
				if len(r.Fields) > 0 {
					var i interface{}
					if err = json.Unmarshal(b, &i); err != nil {
						return
					}
					if m, ok := i.(map[string]interface{}); ok {
						newMap := map[string]interface{}{}
						for k, v := range m {
							if _, found := r.Fields[k]; found {
								newMap[k] = v
							}
						}
						if b, err = json.MarshalIndent(newMap, "", "  "); err != nil {
							return
						}
					}
				}
				result = string(b)
				return
			},
		}).Execute(c.Resp(), map[string]interface{}{
			"Endpoints": routes,
		})
		return
	})
}