func (t *Template) renderAsSubtemplate(context *tales, out io.Writer, slots *variableContainer, config ...RenderConfig) error {
	rc := &renderContext{
		template:     t,
		out:          out,
		buffer:       make(buffer, 0, 1024),
		talesContext: context,
		debug:        defaultLogger,
		config:       config,
		slots:        slots,
	}
	for _, c := range config {
		c(t, rc)
	}
	rc.talesContext.globalVariables.SaveAll()
	defer rc.talesContext.globalVariables.RestoreAll()
	rc.talesContext.globalVariables.SetValue("macros", t)
	for rc.instructionPointer < len(t.instructions) {
		instruction := t.instructions[rc.instructionPointer]
		rc.debug("Executing renderAsSubtemplate instruction %v\n", instruction)
		err := instruction.render(rc)
		if err != nil {
			return err
		}
		rc.instructionPointer++
	}
	return nil
}
renderAsSubtemplate is used to render a template into an existing render.
package tal
import (
	"fmt"
	"golang.org/x/net/html"
	"io"
	"strings"
)
type RenderConfig func(t *Template, rc *renderContext)
func RenderDebugLogging(logger func(fmt string, args ...interface{})) RenderConfig {
	return func(t *Template, rc *renderContext) {
		rc.talesContext.debug = logger
		rc.debug = logger
	}
}
type attributesList []html.Attribute
func (a *attributesList) Remove(name string) bool {
	curList := *a
	for i, att := range curList {
		if att.Key == name {
			res := append(curList[:i], curList[i+1:]...)
			*a = res
			return true
		}
	}
	return false
}
func (a *attributesList) Set(name string, value string) bool {
	curList := *a
	for i, att := range curList {
		if att.Key == name {
			curList[i].Val = value
			return true
		}
	}
	res := append(curList, html.Attribute{Key: name, Val: value})
	*a = res
	return false
}
func (a *attributesList) Get(name string) interface{} {
	curList := *a
	for _, att := range curList {
		if att.Key == name {
			return att.Val
		}
	}
	return notFound
}
type templateInstruction interface {
	render(*renderContext) error
}
type defineSlot struct {
	name string
	endTagOffset int
}
func (d *defineSlot) render(rc *renderContext) error {
	slotFilling, ok := rc.slots.GetValue(d.name)
	if ok {
		slotFillingTemplate := slotFilling.(*Template)
		err := slotFillingTemplate.renderAsSubtemplate(rc.talesContext, rc.out, rc.slots, rc.config...)
		rc.instructionPointer += d.endTagOffset
		return err
	}
	return nil
}
func (d *defineSlot) String() string {
	return fmt.Sprintf("[Define Slot] %v (end offset %v)", d.name, d.endTagOffset)
}
type useMacro struct {
	expression string
	originalAttributes attributesList
	endTagOffset int
	filledSlots map[string]*Template
}
func (u *useMacro) render(rc *renderContext) error {
	contextValue := rc.talesContext.evaluate(u.expression, u.originalAttributes)
	if contextValue == Default {
		return nil
	}
	if contextValue == nil {
		rc.instructionPointer += u.endTagOffset
		return nil
	}
	mv, ok := contextValue.(*Template)
	if ok {
		rc.slots.SaveAll()
		for k, v := range u.filledSlots {
			rc.slots.SetValue(k, v)
		}
		err := mv.renderAsSubtemplate(rc.talesContext, rc.out, rc.slots, rc.config...)
		rc.slots.RestoreAll()
		rc.instructionPointer += u.endTagOffset
		return err
	}
	return nil
}
func (u *useMacro) String() string {
	return fmt.Sprintf("[Use Macro] %v", u.expression)
}
type renderEndTag struct {
	tagName []byte
	checkOmitTagFlag bool
}
func (d *renderEndTag) render(rc *renderContext) error {
	render := true
	if d.checkOmitTagFlag {
		rc.debug("Checking omit tag flag\n")
		render = !rc.getOmitTagFlag()
	}
	if render {
		rc.debug("End Tag will be rendered\n")
		rc.buffer.reset()
		rc.buffer.appendString("</")
		rc.buffer.append(d.tagName)
		rc.buffer.appendString(">")
		rc.out.Write(rc.buffer)
	} else {
		rc.debug("Rendering of end tag suppressed.\n")
	}
	return nil
}
func (d *renderEndTag) String() string {
	return fmt.Sprintf("[End Tag] %v (check omit flag: %v)", string(d.tagName), d.checkOmitTagFlag)
}
type defineVariable struct {
	name string
	global bool
	expression string
	originalAttributes attributesList
}
func (d *defineVariable) render(rc *renderContext) error {
	contextValue := rc.talesContext.evaluate(d.expression, d.originalAttributes)
	if d.global {
		rc.talesContext.globalVariables.SetValue(d.name, contextValue)
	} else {
		rc.talesContext.localVariables.AddValue(d.name, contextValue)
	}
	return nil
}
func (d *defineVariable) String() string {
	typeOfVar := "local"
	if d.global {
		typeOfVar = "global"
	}
	return fmt.Sprintf("[Define Variable] %v %v to '%v'", typeOfVar, d.name, d.expression)
}
type removeLocalVariable struct {
}
func (d *removeLocalVariable) render(rc *renderContext) error {
	rc.talesContext.localVariables.RemoveValue()
	return nil
}
func (d *removeLocalVariable) String() string {
	return "[Remove Local Variable]"
}
type renderRepeat struct {
	repeatName string
	condition string
	endTagOffset int
	repeatId int
	originalAttributes attributesList
}
func (d *renderRepeat) render(rc *renderContext) error {
	var contentValue interface{} = nil
	if d.condition != "" {
		contentValue = rc.talesContext.evaluate(d.condition, d.originalAttributes)
	}
	if contentValue == Default {
		return nil
	}
	if !isValueSequence(contentValue) {
		rc.instructionPointer += d.endTagOffset
		return nil
	}
	newRepeatVar := newRepeatVariable(d.repeatId, contentValue)
	rc.talesContext.repeatVariables.AddValue(d.repeatName, newRepeatVar)
	rc.talesContext.localVariables.AddValue(d.repeatName, newRepeatVar.indexedValue())
	return nil
}
func (d *renderRepeat) String() string {
	return fmt.Sprintf("[Repeat] %v condition '%v' (End Offset %v)", d.repeatName, d.condition, d.endTagOffset)
}
type renderEndRepeat struct {
	repeatName string
	repeatId int
	repeatStartOffset int
}
func (d *renderEndRepeat) render(rc *renderContext) error {
	candidate, ok := rc.talesContext.repeatVariables.GetValue(d.repeatName)
	if !ok {
		return nil
	}
	repeatVar := candidate.(*repeatVariable)
	if repeatVar.repeatId != d.repeatId {
		return nil
	}
	repeatVar.sequencePosition++
	if repeatVar.sequencePosition == repeatVar.sequenceLength {
		rc.talesContext.repeatVariables.RemoveValue()
		rc.talesContext.localVariables.RemoveValue()
		return nil
	}
	rc.talesContext.localVariables.SetValue(d.repeatName, repeatVar.indexedValue())
	rc.instructionPointer += d.repeatStartOffset
	return nil
}
func (d *renderEndRepeat) String() string {
	return fmt.Sprintf("[End Repeat] %v (id %v - loop start offset %v)", d.repeatName, d.repeatId, d.repeatStartOffset)
}
type renderData struct {
	data []byte
}
func (d *renderData) render(rc *renderContext) error {
	_, err := rc.out.Write(d.data)
	if err != nil {
		return err
	}
	return nil
}
func (d *renderData) String() string {
	dataStr := string(d.data)
	if len(dataStr) > 60 {
		dataStr = dataStr[:60] + "..."
	}
	return fmt.Sprintf("[Output] %v", strings.Replace(dataStr, string('\n'), `\n`, -1))
}
type renderCondition struct {
	condition string
	endTagOffset int
	originalAttributes attributesList
}
func (d *renderCondition) render(rc *renderContext) error {
	var contentValue interface{} = nil
	if d.condition != "" {
		contentValue = rc.talesContext.evaluate(d.condition, d.originalAttributes)
	}
	if trueOrFalse(contentValue) {
		return nil
	}
	rc.instructionPointer += d.endTagOffset
	return nil
}
func (d *renderCondition) String() string {
	return fmt.Sprintf("[Condition] '%v' (to offset %v)", d.condition, d.endTagOffset)
}
type renderStartTag struct {
	tagName []byte
	contentStructure bool
	contentExpression string
	originalAttributes attributesList
	attributeExpression []html.Attribute
	replaceCommand bool
	endTagOffset int
	omitTagExpression string
	voidElement bool
}
func (d *renderStartTag) String() string {
	desc := make(buffer, 0, 240)
	var params []interface{}
	desc.appendString("[Start Tag] %v")
	params = append(params, string(d.tagName))
	if d.contentExpression != "" {
		if d.contentStructure {
			desc.appendString(" structure")
		}
		if d.replaceCommand {
			desc.appendString(" replace with '%v'")
		} else {
			desc.appendString(" content of '%v'")
		}
		params = append(params, d.contentExpression)
	}
	if len(d.attributeExpression) > 0 {
		desc.appendString(" attributes set to %v")
		params = append(params, d.attributeExpression)
	}
	if d.omitTagExpression != "" {
		desc.appendString(" omit tag if '%v'")
		params = append(params, d.omitTagExpression)
	}
	desc.appendString(" (end tag offset %v void element %v)")
	params = append(params, d.endTagOffset)
	params = append(params, d.voidElement)
	return fmt.Sprintf(string(desc), params...)
}
func (d *renderStartTag) render(rc *renderContext) error {
	omitTagFlag := false
	if d.omitTagExpression != "" {
		omitTagValue := rc.talesContext.evaluate(d.omitTagExpression, d.originalAttributes)
		omitTagFlag = trueOrFalse(omitTagValue)
		rc.debug("Omit Tag Flag %v - Omit Tag Value %v - Void %v\n", omitTagFlag, omitTagValue, d.voidElement)
		if !d.voidElement {
			rc.addOmitTagFlag(omitTagFlag)
		}
	}
	var contentValue interface{}
	if d.contentExpression != "" {
		contentValue = rc.talesContext.evaluate(d.contentExpression, d.originalAttributes)
	}
	rc.debug("Start tag content is %v\n", contentValue)
	rc.buffer.reset()
	if contentValue == Default || (!d.replaceCommand && !omitTagFlag) {
		var attributes attributesList
		if len(d.attributeExpression) == 0 {
			attributes = d.originalAttributes
		} else {
			attributes = append(attributes, d.originalAttributes...)
			for _, talAtt := range d.attributeExpression {
				attValue := rc.talesContext.evaluate(talAtt.Val, d.originalAttributes)
				if attValue == nil {
					attributes.Remove(talAtt.Key)
				} else if attValue != Default {
					_, booleanAtt := htmlBooleanAttributes[talAtt.Key]
					if booleanAtt {
						if trueOrFalse(attValue) {
							attributes.Set(talAtt.Key, talAtt.Key)
						} else {
							attributes.Remove(talAtt.Key)
						}
					} else {
						attributes.Set(talAtt.Key, fmt.Sprint(attValue))
					}
				}
			}
		}
		rc.buffer.appendString("<")
		rc.buffer.append(d.tagName)
		for _, att := range attributes {
			rc.buffer.appendString(" ")
			rc.buffer.appendString(att.Key)
			rc.buffer.appendString("=\"")
			rc.buffer.appendString(html.EscapeString(att.Val))
			rc.buffer.appendString("\"")
		}
		rc.buffer.appendString(">")
		rc.out.Write(rc.buffer)
	}
	if contentValue == Default || d.contentExpression == "" {
		return nil
	}
	if contentValue != nil {
		if d.contentStructure {
			rc.out.Write([]byte(fmt.Sprint(contentValue)))
		} else {
			rc.out.Write([]byte(html.EscapeString(fmt.Sprint(contentValue))))
		}
	}
	if d.replaceCommand && !d.voidElement {
		rc.debug("Omit Tag is true, jumping to +%v\n", d.endTagOffset)
		rc.instructionPointer += d.endTagOffset
	} else {
		rc.instructionPointer += d.endTagOffset - 1
	}
	return nil
}
type renderContext struct {
	template *Template
	out io.Writer
	buffer buffer
	talesContext *tales
	instructionPointer int
	omitTagFlags []bool
	debug logFunc
	config []RenderConfig
	slots *variableContainer
}
func (rc *renderContext) getOmitTagFlag() bool {
	flagsLength := len(rc.omitTagFlags)
	if flagsLength == 0 {
		rc.debug("Unexpected render error - getOmitTagFlag called, but no flags available!\n")
		return false
	}
	result := rc.omitTagFlags[flagsLength-1]
	rc.omitTagFlags = rc.omitTagFlags[:flagsLength-1]
	return result
}
func (rc *renderContext) addOmitTagFlag(flag bool) {
	rc.omitTagFlags = append(rc.omitTagFlags, flag)
}
type Template struct {
	instructions []templateInstruction
	macros       map[string]*Template
}
func newTemplate() *Template {
	return &Template{macros: make(map[string]*Template)}
}
func (t *Template) String() string {
	buf := make(buffer, 0, 100)
	for index, instr := range t.instructions {
		buf.appendStringF("%v: %v\n", index, instr)
	}
	buf = append(buf, []byte("Start Test")...)
	buf.appendString("Append test")
	buf = append(buf, []byte("Test")...)
	return string(buf)
}
func (t *Template) addRenderInstruction(data []byte) {
	if len(t.instructions) > 0 {
		lastInstructionPos := len(t.instructions) - 1
		renderDataInstr, ok := t.instructions[lastInstructionPos].(*renderData)
		if ok {
			renderDataInstr.data = append(renderDataInstr.data, data...)
			return
		}
	}
	t.instructions = append(t.instructions, &renderData{data})
}
func (t *Template) addInstruction(instruction templateInstruction) {
	t.instructions = append(t.instructions, instruction)
}
func (t *Template) Render(context interface{}, out io.Writer, config ...RenderConfig) error {
	rc := &renderContext{
		template:     t,
		out:          out,
		buffer:       make(buffer, 0, 1024),
		talesContext: newTalesContext(context),
		debug:        defaultLogger,
		config:       config,
		slots:        newContainer(),
	}
	for _, c := range config {
		c(t, rc)
	}
	rc.talesContext.globalVariables.SetValue("macros", t)
	for rc.instructionPointer < len(t.instructions) {
		instruction := t.instructions[rc.instructionPointer]
		rc.debug("Executing instruction %v\n", instruction)
		err := instruction.render(rc)
		if err != nil {
			return err
		}
		rc.instructionPointer++
	}
	return nil
}
func (t *Template) TalesValue(name string) interface{} {
	result, ok := t.macros[name]
	if ok {
		return result
	}
	return nil
}