package html

import (
	
	
	
	
	
	
	
	

	
	
)

// Flags control optional behavior of HTML renderer.
type Flags int

// IDTag is the tag used for tag identification, it defaults to "id", some renderers
// may wish to override this and use e.g. "anchor".
var IDTag = "id"

// HTML renderer configuration options.
const (
	FlagsNone               Flags = 0
	SkipHTML                Flags = 1 << iota // Skip preformatted HTML blocks
	SkipImages                                // Skip embedded images
	SkipLinks                                 // Skip all links
	Safelink                                  // Only link to trusted protocols
	NofollowLinks                             // Only link with rel="nofollow"
	NoreferrerLinks                           // Only link with rel="noreferrer"
	NoopenerLinks                             // Only link with rel="noopener"
	HrefTargetBlank                           // Add a blank target
	CompletePage                              // Generate a complete HTML page
	UseXHTML                                  // Generate XHTML output instead of HTML
	FootnoteReturnLinks                       // Generate a link at the end of a footnote to return to the source
	FootnoteNoHRTag                           // Do not output an HR after starting a footnote list.
	Smartypants                               // Enable smart punctuation substitutions
	SmartypantsFractions                      // Enable smart fractions (with Smartypants)
	SmartypantsDashes                         // Enable smart dashes (with Smartypants)
	SmartypantsLatexDashes                    // Enable LaTeX-style dashes (with Smartypants)
	SmartypantsAngledQuotes                   // Enable angled double quotes (with Smartypants) for double quotes rendering
	SmartypantsQuotesNBSP                     // Enable « French guillemets » (with Smartypants)
	TOC                                       // Generate a table of contents
	LazyLoadImages                            // Include loading="lazy" with images

	CommonFlags Flags = Smartypants | SmartypantsFractions | SmartypantsDashes | SmartypantsLatexDashes
)

var (
	htmlTagRe = regexp.MustCompile("(?i)^" + htmlTag)
)

const (
	htmlTag = "(?:" + openTag + "|" + closeTag + "|" + htmlComment + "|" +
		processingInstruction + "|" + declaration + "|" + cdata + ")"
	closeTag              = "</" + tagName + "\\s*[>]"
	openTag               = "<" + tagName + attribute + "*" + "\\s*/?>"
	attribute             = "(?:" + "\\s+" + attributeName + attributeValueSpec + "?)"
	attributeValue        = "(?:" + unquotedValue + "|" + singleQuotedValue + "|" + doubleQuotedValue + ")"
	attributeValueSpec    = "(?:" + "\\s*=" + "\\s*" + attributeValue + ")"
	attributeName         = "[a-zA-Z_:][a-zA-Z0-9:._-]*"
	cdata                 = "<!\\[CDATA\\[[\\s\\S]*?\\]\\]>"
	declaration           = "<![A-Z]+" + "\\s+[^>]*>"
	doubleQuotedValue     = "\"[^\"]*\""
	htmlComment           = "<!---->|<!--(?:-?[^>-])(?:-?[^-])*-->"
	processingInstruction = "[<][?].*?[?][>]"
	singleQuotedValue     = "'[^']*'"
	tagName               = "[A-Za-z][A-Za-z0-9-]*"
	unquotedValue         = "[^\"'=<>`\\x00-\\x20]+"
)

// RenderNodeFunc allows reusing most of Renderer logic and replacing
// rendering of some nodes. If it returns false, Renderer.RenderNode
// will execute its logic. If it returns true, Renderer.RenderNode will
// skip rendering this node and will return WalkStatus
type RenderNodeFunc func(w io.Writer, node ast.Node, entering bool) (ast.WalkStatus, bool)

// RendererOptions is a collection of supplementary parameters tweaking
// the behavior of various parts of HTML renderer.
type RendererOptions struct {
	// Prepend this text to each relative URL.
	AbsolutePrefix string
	// Add this text to each footnote anchor, to ensure uniqueness.
	FootnoteAnchorPrefix string
	// Show this text inside the <a> tag for a footnote return link, if the
	// FootnoteReturnLinks flag is enabled. If blank, the string
	// <sup>[return]</sup> is used.
	FootnoteReturnLinkContents string
	// CitationFormatString defines how a citation is rendered. If blank, the string
	// <sup>[%s]</sup> is used. Where %s will be substituted with the citation target.
	CitationFormatString string
	// If set, add this text to the front of each Heading ID, to ensure uniqueness.
	HeadingIDPrefix string
	// If set, add this text to the back of each Heading ID, to ensure uniqueness.
	HeadingIDSuffix string
	// can over-write <p> for paragraph tag
	ParagraphTag string

	Title string // Document title (used if CompletePage is set)
	CSS   string // Optional CSS file URL (used if CompletePage is set)
	Icon  string // Optional icon file URL (used if CompletePage is set)
	Head  []byte // Optional head data injected in the <head> section (used if CompletePage is set)

	Flags Flags // Flags allow customizing this renderer's behavior

	// if set, called at the start of RenderNode(). Allows replacing
	// rendering of some nodes
	RenderNodeHook RenderNodeFunc

	// Comments is a list of comments the renderer should detect when
	// parsing code blocks and detecting callouts.
	Comments [][]byte

	// Generator is a meta tag that is inserted in the generated HTML so show what rendered it. It should not include the closing tag.
	// Defaults (note content quote is not closed) to `  <meta name="GENERATOR" content="github.com/gomarkdown/markdown markdown processor for Go`
	Generator string
}

// Renderer implements Renderer interface for HTML output.
//
// Do not create this directly, instead use the NewRenderer function.
type Renderer struct {
	Opts RendererOptions

	closeTag string // how to end singleton tags: either " />" or ">"

	// Track heading IDs to prevent ID collision in a single generation.
	headingIDs map[string]int

	lastOutputLen int

	// if > 0, will strip html tags in Out and Outs
	DisableTags int

	// IsSafeURLOverride allows overriding the default URL matcher. URL is
	// safe if the overriding function returns true. Can be used to extend
	// the default list of safe URLs.
	IsSafeURLOverride func(url []byte) bool

	sr *SPRenderer

	documentMatter ast.DocumentMatters // keep track of front/main/back matter.
}

// Escaper defines how to escape HTML special characters
var Escaper = [256][]byte{
	'&': []byte("&amp;"),
	'<': []byte("&lt;"),
	'>': []byte("&gt;"),
	'"': []byte("&quot;"),
}

// EscapeHTML writes html-escaped d to w. It escapes &, <, > and " characters.
func ( io.Writer,  []byte) {
	var ,  int
	 := len()
	for  <  {
		 := Escaper[[]]
		if  != nil {
			.Write([:])
			.Write()
			 =  + 1
		}
		++
	}
	if  <  &&  <=  {
		.Write([:])
	}
}

func ( io.Writer,  []byte) {
	 := html.UnescapeString(string())
	EscapeHTML(, []byte())
}

// Escape writes the text to w, but skips the escape character.
func ( io.Writer,  []byte) {
	 := false
	for  := 0;  < len(); ++ {
		if [] == '\\' {
			 = !
		}
		if  && [] == '\\' {
			continue
		}
		.Write([]byte{[]})
	}
}

// NewRenderer creates and configures an Renderer object, which
// satisfies the Renderer interface.
func ( RendererOptions) *Renderer {
	// configure the rendering engine
	 := ">"
	if .Flags&UseXHTML != 0 {
		 = " />"
	}

	if .FootnoteReturnLinkContents == "" {
		.FootnoteReturnLinkContents = `<sup>[return]</sup>`
	}
	if .CitationFormatString == "" {
		.CitationFormatString = `<sup>[%s]</sup>`
	}
	if .Generator == "" {
		.Generator = `  <meta name="GENERATOR" content="github.com/gomarkdown/markdown markdown processor for Go`
	}

	return &Renderer{
		Opts: ,

		closeTag:   ,
		headingIDs: make(map[string]int),

		sr: NewSmartypantsRenderer(.Flags),
	}
}

func isRelativeLink( []byte) ( bool) {
	// empty links considerd relative
	if len() == 0 {
		return true
	}

	// a tag begin with '#'
	if [0] == '#' {
		return true
	}

	// link begin with '/' but not '//', the second maybe a protocol relative link
	if len() >= 2 && [0] == '/' && [1] != '/' {
		return true
	}

	// only the root '/'
	if len() == 1 && [0] == '/' {
		return true
	}

	// current directory : begin with "./"
	if bytes.HasPrefix(, []byte("./")) {
		return true
	}

	// parent directory : begin with "../"
	if bytes.HasPrefix(, []byte("../")) {
		return true
	}

	return false
}

func ( []byte,  string) []byte {
	if len() == 0 || len() == 0 {
		return 
	}
	if isRelativeLink() && [0] != '.' {
		 := 
		if [0] != '/' {
			 += "/"
		}
		 += string()
		return []byte()
	}
	return 
}

func appendLinkAttrs( []string,  Flags,  []byte) []string {
	if isRelativeLink() {
		return 
	}
	var  []string
	if &NofollowLinks != 0 {
		 = append(, "nofollow")
	}
	if &NoreferrerLinks != 0 {
		 = append(, "noreferrer")
	}
	if &NoopenerLinks != 0 {
		 = append(, "noopener")
	}
	if &HrefTargetBlank != 0 {
		 = append(, `target="_blank"`)
	}
	if len() == 0 {
		return 
	}
	 := fmt.Sprintf("rel=%q", strings.Join(, " "))
	return append(, )
}

func isMailto( []byte) bool {
	return bytes.HasPrefix(, []byte("mailto:"))
}

func needSkipLink( *Renderer,  []byte) bool {
	 := .Opts.Flags
	if &SkipLinks != 0 {
		return true
	}
	 := .IsSafeURLOverride
	if  == nil {
		 = parser.IsSafeURL
	}
	return &Safelink != 0 && !() && !isMailto()
}

func appendLanguageAttr( []string,  []byte) []string {
	if len() == 0 {
		return 
	}
	 := bytes.IndexAny(, "\t ")
	if  < 0 {
		 = len()
	}
	 := `class="language-` + string([:]) + `"`
	return append(, )
}

func ( *Renderer) ( io.Writer,  string,  []string) {
	 := 
	if len() > 0 {
		 += " " + strings.Join(, " ")
	}
	io.WriteString(, +">")
	.lastOutputLen = 1
}

func ( string,  *ast.Link) string {
	 :=  + string(Slugify(.Destination))
	 := strconv.Itoa(.NoteID)
	 := `<a href="#fn:` +  + `">` +  + `</a>`
	return `<sup class="footnote-ref" id="fnref:` +  + `">` +  + `</sup>`
}

func ( string,  []byte) string {
	return `<li id="fn:` +  + string() + `">`
}

func (,  string,  []byte) string {
	return ` <a class="footnote-return" href="#fnref:` +  + string() + `">` +  + `</a>`
}

func ( *ast.ListItem) bool {
	if ast.GetPrevNode() == nil {
		return false
	}
	 := .Parent.(*ast.List)
	return !.Tight && .ListFlags&ast.ListTypeDefinition == 0
}

func ( *ast.Paragraph) bool {
	 := .Parent
	 := .GetParent()
	if  == nil || !IsList() {
		return false
	}
	 := IsListItemTerm()
	 := .(*ast.List)
	 := .Tight || 
	return 
}

// Out is a helper to write data to writer
func ( *Renderer) ( io.Writer,  []byte) {
	.lastOutputLen = len()
	if .DisableTags > 0 {
		 = htmlTagRe.ReplaceAll(, []byte{})
	}
	.Write()
}

// Outs is a helper to write data to writer
func ( *Renderer) ( io.Writer,  string) {
	.lastOutputLen = len()
	if .DisableTags > 0 {
		 = htmlTagRe.ReplaceAllString(, "")
	}
	io.WriteString(, )
}

// CR writes a new line
func ( *Renderer) ( io.Writer) {
	if .lastOutputLen > 0 {
		.Outs(, "\n")
	}
}

var (
	openHTags  = []string{"<h1", "<h2", "<h3", "<h4", "<h5"}
	closeHTags = []string{"</h1>", "</h2>", "</h3>", "</h4>", "</h5>"}
)

func ( int) string {
	if  < 1 ||  > 5 {
		return "<h6"
	}
	return openHTags[-1]
}

func ( int) string {
	if  < 1 ||  > 5 {
		return "</h6>"
	}
	return closeHTags[-1]
}

func ( *Renderer) ( io.Writer,  []string) {
	 := TagWithAttributes("<hr", )
	.OutOneOf(, .Opts.Flags&UseXHTML == 0, , "<hr />")
}

// Text writes ast.Text node
func ( *Renderer) ( io.Writer,  *ast.Text) {
	if .Opts.Flags&Smartypants != 0 {
		var  bytes.Buffer
		EscapeHTML(&, .Literal)
		.sr.Process(, .Bytes())
	} else {
		,  := .Parent.(*ast.Link)
		if  {
			EscLink(, .Literal)
		} else {
			EscapeHTML(, .Literal)
		}
	}
}

// HardBreak writes ast.Hardbreak node
func ( *Renderer) ( io.Writer,  *ast.Hardbreak) {
	.OutOneOf(, .Opts.Flags&UseXHTML == 0, "<br>", "<br />")
	.CR()
}

// NonBlockingSpace writes ast.NonBlockingSpace node
func ( *Renderer) ( io.Writer,  *ast.NonBlockingSpace) {
	.Outs(, "&nbsp;")
}

// OutOneOf writes first or second depending on outFirst
func ( *Renderer) ( io.Writer,  bool,  string,  string) {
	if  {
		.Outs(, )
	} else {
		.Outs(, )
	}
}

// OutOneOfCr writes CR + first or second + CR depending on outFirst
func ( *Renderer) ( io.Writer,  bool,  string,  string) {
	if  {
		.CR()
		.Outs(, )
	} else {
		.Outs(, )
		.CR()
	}
}

// HTMLSpan writes ast.HTMLSpan node
func ( *Renderer) ( io.Writer,  *ast.HTMLSpan) {
	if .Opts.Flags&SkipHTML == 0 {
		.Out(, .Literal)
	}
}

func ( *Renderer) ( io.Writer,  *ast.Link) {
	 := .AdditionalAttributes
	 := .Destination
	 = AddAbsPrefix(, .Opts.AbsolutePrefix)
	var  bytes.Buffer
	.WriteString("href=\"")
	EscLink(&, )
	.WriteByte('"')
	 = append(, .String())
	if .NoteID != 0 {
		.Outs(, FootnoteRef(.Opts.FootnoteAnchorPrefix, ))
		return
	}

	 = appendLinkAttrs(, .Opts.Flags, )
	if len(.Title) > 0 {
		var  bytes.Buffer
		.WriteString("title=\"")
		EscapeHTML(&, .Title)
		.WriteByte('"')
		 = append(, .String())
	}
	.OutTag(, "<a", )
}

func ( *Renderer) ( io.Writer,  *ast.Link) {
	if .NoteID == 0 {
		.Outs(, "</a>")
	}
}

// Link writes ast.Link node
func ( *Renderer) ( io.Writer,  *ast.Link,  bool) {
	// mark it but don't link it if it is not a safe link: no smartypants
	if needSkipLink(, .Destination) {
		.OutOneOf(, , "<tt>", "</tt>")
		return
	}

	if  {
		.linkEnter(, )
	} else {
		.linkExit(, )
	}
}

func ( *Renderer) ( io.Writer,  *ast.Image) {
	.DisableTags++
	if .DisableTags > 1 {
		return
	}
	 := .Destination
	 = AddAbsPrefix(, .Opts.AbsolutePrefix)
	 := BlockAttrs()
	if .Opts.Flags&LazyLoadImages != 0 {
		 = append(, `loading="lazy"`)
	}

	 := TagWithAttributes("<img", )
	 = [:len()-1] // hackish: strip off ">" from end
	.Outs(, +` src="`)
	EscLink(, )
	.Outs(, `" alt="`)
}

func ( *Renderer) ( io.Writer,  *ast.Image) {
	.DisableTags--
	if .DisableTags > 0 {
		return
	}
	if .Title != nil {
		.Outs(, `" title="`)
		EscapeHTML(, .Title)
	}
	.Outs(, `" />`)
}

// Image writes ast.Image node
func ( *Renderer) ( io.Writer,  *ast.Image,  bool) {
	if  {
		.imageEnter(, )
	} else {
		.imageExit(, )
	}
}

func ( *Renderer) ( io.Writer,  *ast.Paragraph) {
	// TODO: untangle this clusterfuck about when the newlines need
	// to be added and when not.
	 := ast.GetPrevNode()
	if  != nil {
		switch .(type) {
		case *ast.HTMLBlock, *ast.List, *ast.Paragraph, *ast.Heading, *ast.CaptionFigure, *ast.CodeBlock, *ast.BlockQuote, *ast.Aside, *ast.HorizontalRule:
			.CR()
		}
	}

	if  == nil {
		,  := .Parent.(*ast.BlockQuote)
		if  {
			.CR()
		}
		,  := .Parent.(*ast.Aside)
		if  {
			.CR()
		}
	}

	 := "<p"
	if .Opts.ParagraphTag != "" {
		 = "<" + .Opts.ParagraphTag
	}
	 := TagWithAttributes(, BlockAttrs())
	.Outs(, )
}

func ( *Renderer) ( io.Writer,  *ast.Paragraph) {
	 := "</p>"
	if .Opts.ParagraphTag != "" {
		 = "</" + .Opts.ParagraphTag + ">"
	}
	.Outs(, )
	if !(IsListItem(.Parent) && ast.GetNextNode() == nil) {
		.CR()
	}
}

// Paragraph writes ast.Paragraph node
func ( *Renderer) ( io.Writer,  *ast.Paragraph,  bool) {
	if SkipParagraphTags() {
		return
	}
	if  {
		.paragraphEnter(, )
	} else {
		.paragraphExit(, )
	}
}

// Code writes ast.Code node
func ( *Renderer) ( io.Writer,  *ast.Code) {
	.Outs(, "<code>")
	EscapeHTML(, .Literal)
	.Outs(, "</code>")
}

// HTMLBlock write ast.HTMLBlock node
func ( *Renderer) ( io.Writer,  *ast.HTMLBlock) {
	if .Opts.Flags&SkipHTML != 0 {
		return
	}
	.CR()
	.Out(, .Literal)
	.CR()
}

func ( *Renderer) ( string) string {
	for ,  := .headingIDs[]; ; ,  = .headingIDs[] {
		 := fmt.Sprintf("%s-%d", , +1)

		if ,  := .headingIDs[]; ! {
			.headingIDs[] =  + 1
			 = 
		} else {
			 =  + "-1"
		}
	}

	if ,  := .headingIDs[]; ! {
		.headingIDs[] = 0
	}

	return 
}

func ( *Renderer) ( *ast.Heading) string {
	if .HeadingID == "" {
		return ""
	}
	 := .EnsureUniqueHeadingID(.HeadingID)
	if .Opts.HeadingIDPrefix != "" {
		 = .Opts.HeadingIDPrefix + 
	}
	if .Opts.HeadingIDSuffix != "" {
		 =  + .Opts.HeadingIDSuffix
	}
	.HeadingID = 
	return 
}

func ( *Renderer) ( io.Writer,  *ast.Heading) {
	var  []string
	var  string
	// TODO(miek): add helper functions for coalescing these classes.
	if .IsTitleblock {
		 = "title"
	}
	if .IsSpecial {
		if  != "" {
			 += " special"
		} else {
			 = "special"
		}
	}
	if  != "" {
		 = []string{`class="` +  + `"`}
	}

	if .HeadingID != "" {
		 := .MakeUniqueHeadingID()
		 := `id="` +  + `"`
		 = append(, )
	}
	 = append(, BlockAttrs()...)
	.CR()
	.OutTag(, HeadingOpenTagFromLevel(.Level), )
}

func ( *Renderer) ( io.Writer,  *ast.Heading) {
	.Outs(, HeadingCloseTagFromLevel(.Level))
	if !(IsListItem(.Parent) && ast.GetNextNode() == nil) {
		.CR()
	}
}

// Heading writes ast.Heading node
func ( *Renderer) ( io.Writer,  *ast.Heading,  bool) {
	if  {
		.HeadingEnter(, )
	} else {
		.HeadingExit(, )
	}
}

// HorizontalRule writes ast.HorizontalRule node
func ( *Renderer) ( io.Writer,  *ast.HorizontalRule) {
	.CR()
	.OutHRTag(, BlockAttrs())
	.CR()
}

func ( *Renderer) ( io.Writer,  *ast.List) {
	// TODO: attrs don't seem to be set
	var  []string

	if .IsFootnotesList {
		.Outs(, "\n<div class=\"footnotes\">\n\n")
		if .Opts.Flags&FootnoteNoHRTag == 0 {
			.OutHRTag(, nil)
			.CR()
		}
	}
	.CR()
	if IsListItem(.Parent) {
		 := .Parent.GetParent()
		if IsListTight() {
			.CR()
		}
	}

	 := "<ul"
	if .ListFlags&ast.ListTypeOrdered != 0 {
		if .Start > 0 {
			 = append(, fmt.Sprintf(`start="%d"`, .Start))
		}
		 = "<ol"
	}
	if .ListFlags&ast.ListTypeDefinition != 0 {
		 = "<dl"
	}
	 = append(, BlockAttrs()...)
	.OutTag(, , )
	.CR()
}

func ( *Renderer) ( io.Writer,  *ast.List) {
	 := "</ul>"
	if .ListFlags&ast.ListTypeOrdered != 0 {
		 = "</ol>"
	}
	if .ListFlags&ast.ListTypeDefinition != 0 {
		 = "</dl>"
	}
	.Outs(, )

	//cr(w)
	//if node.parent.Type != Item {
	//	cr(w)
	//}
	 := .Parent
	switch .(type) {
	case *ast.ListItem:
		if ast.GetNextNode() != nil {
			.CR()
		}
	case *ast.Document, *ast.BlockQuote, *ast.Aside:
		.CR()
	}

	if .IsFootnotesList {
		.Outs(, "\n</div>\n")
	}
}

// List writes ast.List node
func ( *Renderer) ( io.Writer,  *ast.List,  bool) {
	if  {
		.listEnter(, )
	} else {
		.listExit(, )
	}
}

func ( *Renderer) ( io.Writer,  *ast.ListItem) {
	if ListItemOpenCR() {
		.CR()
	}
	if .RefLink != nil {
		 := Slugify(.RefLink)
		.Outs(, FootnoteItem(.Opts.FootnoteAnchorPrefix, ))
		return
	}

	 := "<li>"
	if .ListFlags&ast.ListTypeDefinition != 0 {
		 = "<dd>"
	}
	if .ListFlags&ast.ListTypeTerm != 0 {
		 = "<dt>"
	}
	.Outs(, )
}

func ( *Renderer) ( io.Writer,  *ast.ListItem) {
	if .RefLink != nil && .Opts.Flags&FootnoteReturnLinks != 0 {
		 := Slugify(.RefLink)
		 := .Opts.FootnoteAnchorPrefix
		 := .Opts.FootnoteReturnLinkContents
		 := FootnoteReturnLink(, , )
		.Outs(, )
	}

	 := "</li>"
	if .ListFlags&ast.ListTypeDefinition != 0 {
		 = "</dd>"
	}
	if .ListFlags&ast.ListTypeTerm != 0 {
		 = "</dt>"
	}
	.Outs(, )
	.CR()
}

// ListItem writes ast.ListItem node
func ( *Renderer) ( io.Writer,  *ast.ListItem,  bool) {
	if  {
		.listItemEnter(, )
	} else {
		.listItemExit(, )
	}
}

// EscapeHTMLCallouts writes html-escaped d to w. It escapes &, <, > and " characters, *but*
// expands callouts <<N>> with the callout HTML, i.e. by calling r.callout() with a newly created
// ast.Callout node.
func ( *Renderer) ( io.Writer,  []byte) {
	 := len()
:
	for  := 0;  < ; ++ {
		for ,  := range .Opts.Comments {
			if !bytes.HasPrefix([:], ) {
				break
			}

			 := len()
			if + <  {
				if ,  := parser.IsCallout([+:]);  > 0 {
					// We have seen a callout
					 := &ast.Callout{ID: }
					.Callout(, )
					 +=  +  - 1
					continue 
				}
			}
		}

		 := Escaper[[]]
		if  != nil {
			.Write()
		} else {
			.Write([]byte{[]})
		}
	}
}

// CodeBlock writes ast.CodeBlock node
func ( *Renderer) ( io.Writer,  *ast.CodeBlock) {
	var  []string
	// TODO(miek): this can add multiple class= attribute, they should be coalesced into one.
	// This is probably true for some other elements as well
	 = appendLanguageAttr(, .Info)
	 = append(, BlockAttrs()...)
	.CR()

	.Outs(, "<pre>")
	 := TagWithAttributes("<code", )
	.Outs(, )
	if .Opts.Comments != nil {
		.EscapeHTMLCallouts(, .Literal)
	} else {
		EscapeHTML(, .Literal)
	}
	.Outs(, "</code>")
	.Outs(, "</pre>")
	if !IsListItem(.Parent) {
		.CR()
	}
}

// Caption writes ast.Caption node
func ( *Renderer) ( io.Writer,  *ast.Caption,  bool) {
	if  {
		.Outs(, "<figcaption>")
		return
	}
	.Outs(, "</figcaption>")
}

// CaptionFigure writes ast.CaptionFigure node
func ( *Renderer) ( io.Writer,  *ast.CaptionFigure,  bool) {
	// TODO(miek): copy more generic ways of mmark over to here.
	 := "<figure"
	if .HeadingID != "" {
		 += ` id="` + .HeadingID + `">`
	} else {
		 += ">"
	}
	.OutOneOf(, , , "\n</figure>\n")
}

// TableCell writes ast.TableCell node
func ( *Renderer) ( io.Writer,  *ast.TableCell,  bool) {
	if ! {
		.OutOneOf(, .IsHeader, "</th>", "</td>")
		.CR()
		return
	}

	// entering
	var  []string
	 := "<td"
	if .IsHeader {
		 = "<th"
	}
	 := .Align.String()
	if  != "" {
		 = append(, fmt.Sprintf(`align="%s"`, ))
	}
	if  := .ColSpan;  > 0 {
		 = append(, fmt.Sprintf(`colspan="%d"`, ))
	}
	if ast.GetPrevNode() == nil {
		.CR()
	}
	.OutTag(, , )
}

// TableBody writes ast.TableBody node
func ( *Renderer) ( io.Writer,  *ast.TableBody,  bool) {
	if  {
		.CR()
		.Outs(, "<tbody>")
		// XXX: this is to adhere to a rather silly test. Should fix test.
		if ast.GetFirstChild() == nil {
			.CR()
		}
	} else {
		.Outs(, "</tbody>")
		.CR()
	}
}

// DocumentMatter writes ast.DocumentMatter
func ( *Renderer) ( io.Writer,  *ast.DocumentMatter,  bool) {
	if ! {
		return
	}
	if .documentMatter != ast.DocumentMatterNone {
		.Outs(, "</section>\n")
	}
	switch .Matter {
	case ast.DocumentMatterFront:
		.Outs(, `<section data-matter="front">`)
	case ast.DocumentMatterMain:
		.Outs(, `<section data-matter="main">`)
	case ast.DocumentMatterBack:
		.Outs(, `<section data-matter="back">`)
	}
	.documentMatter = .Matter
}

// Citation writes ast.Citation node
func ( *Renderer) ( io.Writer,  *ast.Citation) {
	for ,  := range .Destination {
		 := []string{`class="none"`}
		switch .Type[] {
		case ast.CitationTypeNormative:
			[0] = `class="normative"`
		case ast.CitationTypeInformative:
			[0] = `class="informative"`
		case ast.CitationTypeSuppressed:
			[0] = `class="suppressed"`
		}
		.OutTag(, "<cite", )
		.Outs(, fmt.Sprintf(`<a href="#%s">`+.Opts.CitationFormatString+`</a>`, , ))
		.Outs(, "</cite>")
	}
}

// Callout writes ast.Callout node
func ( *Renderer) ( io.Writer,  *ast.Callout) {
	 := []string{`class="callout"`}
	.OutTag(, "<span", )
	.Out(, .ID)
	.Outs(, "</span>")
}

// Index writes ast.Index node
func ( *Renderer) ( io.Writer,  *ast.Index) {
	// there is no in-text representation.
	 := []string{`class="index"`, fmt.Sprintf(`id="%s"`, .ID)}
	.OutTag(, "<span", )
	.Outs(, "</span>")
}

// RenderNode renders a markdown node to HTML
func ( *Renderer) ( io.Writer,  ast.Node,  bool) ast.WalkStatus {
	if .Opts.RenderNodeHook != nil {
		,  := .Opts.RenderNodeHook(, , )
		if  {
			return 
		}
	}
	switch node := .(type) {
	case *ast.Text:
		.Text(, )
	case *ast.Softbreak:
		.CR()
		// TODO: make it configurable via out(renderer.softbreak)
	case *ast.Hardbreak:
		.HardBreak(, )
	case *ast.NonBlockingSpace:
		.NonBlockingSpace(, )
	case *ast.Emph:
		.OutOneOf(, , "<em>", "</em>")
	case *ast.Strong:
		.OutOneOf(, , "<strong>", "</strong>")
	case *ast.Del:
		.OutOneOf(, , "<del>", "</del>")
	case *ast.BlockQuote:
		 := TagWithAttributes("<blockquote", BlockAttrs())
		.OutOneOfCr(, , , "</blockquote>")
	case *ast.Aside:
		 := TagWithAttributes("<aside", BlockAttrs())
		.OutOneOfCr(, , , "</aside>")
	case *ast.Link:
		.Link(, , )
	case *ast.CrossReference:
		 := &ast.Link{Destination: append([]byte("#"), .Destination...)}
		.Link(, , )
	case *ast.Citation:
		.Citation(, )
	case *ast.Image:
		if .Opts.Flags&SkipImages != 0 {
			return ast.SkipChildren
		}
		.Image(, , )
	case *ast.Code:
		.Code(, )
	case *ast.CodeBlock:
		.CodeBlock(, )
	case *ast.Caption:
		.Caption(, , )
	case *ast.CaptionFigure:
		.CaptionFigure(, , )
	case *ast.Document:
		// do nothing
	case *ast.Paragraph:
		.Paragraph(, , )
	case *ast.HTMLSpan:
		.HTMLSpan(, )
	case *ast.HTMLBlock:
		.HTMLBlock(, )
	case *ast.Heading:
		.Heading(, , )
	case *ast.HorizontalRule:
		.HorizontalRule(, )
	case *ast.List:
		.List(, , )
	case *ast.ListItem:
		.ListItem(, , )
	case *ast.Table:
		 := TagWithAttributes("<table", BlockAttrs())
		.OutOneOfCr(, , , "</table>")
	case *ast.TableCell:
		.TableCell(, , )
	case *ast.TableHeader:
		.OutOneOfCr(, , "<thead>", "</thead>")
	case *ast.TableBody:
		.TableBody(, , )
	case *ast.TableRow:
		.OutOneOfCr(, , "<tr>", "</tr>")
	case *ast.TableFooter:
		.OutOneOfCr(, , "<tfoot>", "</tfoot>")
	case *ast.Math:
		.OutOneOf(, true, `<span class="math inline">\(`, `\)</span>`)
		EscapeHTML(, .Literal)
		.OutOneOf(, false, `<span class="math inline">\(`, `\)</span>`)
	case *ast.MathBlock:
		.OutOneOf(, , `<p><span class="math display">\[`, `\]</span></p>`)
		if  {
			EscapeHTML(, .Literal)
		}
	case *ast.DocumentMatter:
		.DocumentMatter(, , )
	case *ast.Callout:
		.Callout(, )
	case *ast.Index:
		.Index(, )
	case *ast.Subscript:
		.OutOneOf(, true, "<sub>", "</sub>")
		if  {
			Escape(, .Literal)
		}
		.OutOneOf(, false, "<sub>", "</sub>")
	case *ast.Superscript:
		.OutOneOf(, true, "<sup>", "</sup>")
		if  {
			Escape(, .Literal)
		}
		.OutOneOf(, false, "<sup>", "</sup>")
	case *ast.Footnotes:
		// nothing by default; just output the list.
	default:
		panic(fmt.Sprintf("Unknown node %T", ))
	}
	return ast.GoToNext
}

// RenderHeader writes HTML document preamble and TOC if requested.
func ( *Renderer) ( io.Writer,  ast.Node) {
	.writeDocumentHeader()
	if .Opts.Flags&TOC != 0 {
		.writeTOC(, )
	}
}

// RenderFooter writes HTML document footer.
func ( *Renderer) ( io.Writer,  ast.Node) {
	if .documentMatter != ast.DocumentMatterNone {
		.Outs(, "</section>\n")
	}

	if .Opts.Flags&CompletePage == 0 {
		return
	}
	io.WriteString(, "\n</body>\n</html>\n")
}

func ( *Renderer) ( io.Writer) {
	if .Opts.Flags&CompletePage == 0 {
		return
	}
	 := ""
	if .Opts.Flags&UseXHTML != 0 {
		io.WriteString(, "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" ")
		io.WriteString(, "\"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n")
		io.WriteString(, "<html xmlns=\"http://www.w3.org/1999/xhtml\">\n")
		 = " /"
	} else {
		io.WriteString(, "<!DOCTYPE html>\n")
		io.WriteString(, "<html>\n")
	}
	io.WriteString(, "<head>\n")
	io.WriteString(, "  <title>")
	if .Opts.Flags&Smartypants != 0 {
		.sr.Process(, []byte(.Opts.Title))
	} else {
		EscapeHTML(, []byte(.Opts.Title))
	}
	io.WriteString(, "</title>\n")
	io.WriteString(, .Opts.Generator)
	io.WriteString(, "\"")
	io.WriteString(, )
	io.WriteString(, ">\n")
	io.WriteString(, "  <meta charset=\"utf-8\"")
	io.WriteString(, )
	io.WriteString(, ">\n")
	if .Opts.CSS != "" {
		io.WriteString(, "  <link rel=\"stylesheet\" type=\"text/css\" href=\"")
		EscapeHTML(, []byte(.Opts.CSS))
		io.WriteString(, "\"")
		io.WriteString(, )
		io.WriteString(, ">\n")
	}
	if .Opts.Icon != "" {
		io.WriteString(, "  <link rel=\"icon\" type=\"image/x-icon\" href=\"")
		EscapeHTML(, []byte(.Opts.Icon))
		io.WriteString(, "\"")
		io.WriteString(, )
		io.WriteString(, ">\n")
	}
	if .Opts.Head != nil {
		.Write(.Opts.Head)
	}
	io.WriteString(, "</head>\n")
	io.WriteString(, "<body>\n\n")
}

func ( *Renderer) ( io.Writer,  ast.Node) {
	 := bytes.Buffer{}

	 := false
	 := 0
	 := 0

	ast.WalkFunc(, func( ast.Node,  bool) ast.WalkStatus {
		if ,  := .(*ast.Heading);  && !.IsTitleblock {
			 = 
			if ! {
				.WriteString("</a>")
				return ast.GoToNext
			}
			if .HeadingID == "" {
				.HeadingID = fmt.Sprintf("toc_%d", )
			}
			if .Level ==  {
				.WriteString("</li>\n\n<li>")
			} else if .Level <  {
				for .Level <  {
					--
					.WriteString("</li>\n</ul>")
				}
				.WriteString("</li>\n\n<li>")
			} else {
				for .Level >  {
					++
					.WriteString("\n<ul>\n<li>")
				}
			}

			fmt.Fprintf(&, `<a href="#%s">`, .HeadingID)
			++
			return ast.GoToNext
		}

		if  {
			return .RenderNode(&, , )
		}

		return ast.GoToNext
	})

	for ;  > 0; -- {
		.WriteString("</li>\n</ul>")
	}

	if .Len() > 0 {
		io.WriteString(, "<nav>\n")
		.Write(.Bytes())
		io.WriteString(, "\n\n</nav>\n")
	}
	.lastOutputLen = .Len()
}

func ( ast.Node) bool {
	,  := .(*ast.List)
	return 
}

func ( ast.Node) bool {
	if ,  := .(*ast.List);  {
		return .Tight
	}
	return false
}

func ( ast.Node) bool {
	,  := .(*ast.ListItem)
	return 
}

func ( ast.Node) bool {
	,  := .(*ast.ListItem)
	return  && .ListFlags&ast.ListTypeTerm != 0
}

// TODO: move to internal package
// Create a url-safe slug for fragments
func ( []byte) []byte {
	if len() == 0 {
		return 
	}
	 := make([]byte, 0, len())
	 := false

	for ,  := range  {
		if isAlnum() {
			 = false
			 = append(, )
		} else if  {
			continue
		} else {
			 = append(, '-')
			 = true
		}
	}
	var ,  int
	var  byte
	for ,  = range  {
		if  != '-' {
			break
		}
	}
	for  = len() - 1;  > 0; -- {
		if [] != '-' {
			break
		}
	}
	return [ : +1]
}

// BlockAttrs takes a node and checks if it has block level attributes set. If so it
// will return a slice each containing a "key=value(s)" string.
func ( ast.Node) []string {
	var  *ast.Attribute
	if  := .AsContainer();  != nil && .Attribute != nil {
		 = .Attribute
	}
	if  := .AsLeaf();  != nil && .Attribute != nil {
		 = .Attribute
	}
	if  == nil {
		return nil
	}

	var  []string
	if .ID != nil {
		 = append(, fmt.Sprintf(`%s="%s"`, IDTag, .ID))
	}

	 := ""
	for ,  := range .Classes {
		 += " " + string()
	}
	if  != "" {
		 = append(, fmt.Sprintf(`class="%s"`, [1:])) // skip space we added.
	}

	// sort the attributes so it remain stable between runs
	var  = []string{}
	for  := range .Attrs {
		 = append(, )
	}
	sort.Strings()
	for ,  := range  {
		 = append(, fmt.Sprintf(`%s="%s"`, , .Attrs[]))
	}

	return 
}

// TagWithAttributes creates a HTML tag with a given name and attributes
func ( string,  []string) string {
	 := 
	if len() > 0 {
		 += " " + strings.Join(, " ")
	}
	return  + ">"
}