func (a *Args) similar(r *Args, similar Similarity) bool {
	if a.Elided != r.Elided || len(a.Values) != len(r.Values) {
		return false
	}
	if similar == AnyValue {
		return true
	}
	for i, l := range a.Values {
		switch similar {
		case ExactFlags, ExactLines:
			if l != r.Values[i] {
				return false
			}
		default:
			if l.IsPtr() != r.Values[i].IsPtr() || (!l.IsPtr() && l != r.Values[i]) {
				return false
			}
		}
	}
	return true
}

func ( a * Args ) similar ( r * Args , similar Similarity ) bool { if a . Elided != r . Elided || len ( a . Values ) != len ( r . Values ) { return false } if similar == AnyValue { return true } for i , l := range a . Values { switch similar { case ExactFlags , ExactLines : if l != r . Values [ i ] { return false } default : if l . IsPtr ( ) != r . Values [ i ] . IsPtr ( ) || ( ! l . IsPtr ( ) && l != r . Values [ i ] ) { return false } } } return true }

// similar returns true if the two Args are equal or almost but not quite
// equal.

similar returns true if the two Args are equal or almost but not quite equal .


func (a *Args) merge(r *Args) Args {
	out := Args{
		Values: make([]Arg, len(a.Values)),
		Elided: a.Elided,
	}
	for i, l := range a.Values {
		if l != r.Values[i] {
			out.Values[i].Name = "*"
			out.Values[i].Value = l.Value
		} else {
			out.Values[i] = l
		}
	}
	return out
}

func ( a * Args ) merge ( r * Args ) Args { out := Args { Values : make ( [ ] Arg , len ( a . Values ) ) , Elided : a . Elided , } for i , l := range a . Values { if l != r . Values [ i ] { out . Values [ i ] . Name = " " out . Values [ i ] . Value = l . Value } else { out . Values [ i ] = l } } return out }

// merge merges two similar Args, zapping out differences.

merge merges two similar Args zapping out differences .


func (c *Call) equal(r *Call) bool {
	return c.SrcPath == r.SrcPath && c.Line == r.Line && c.Func == r.Func && c.Args.equal(&r.Args)
}

func ( c * Call ) equal ( r * Call ) bool { return c . SrcPath == r . SrcPath && c . Line == r . Line && c . Func == r . Func && c . Args . equal ( & r . Args ) }

// equal returns true only if both calls are exactly equal.

equal returns true only if both calls are exactly equal .


func (c *Call) similar(r *Call, similar Similarity) bool {
	return c.SrcPath == r.SrcPath && c.Line == r.Line && c.Func == r.Func && c.Args.similar(&r.Args, similar)
}

func ( c * Call ) similar ( r * Call , similar Similarity ) bool { return c . SrcPath == r . SrcPath && c . Line == r . Line && c . Func == r . Func && c . Args . similar ( & r . Args , similar ) }

// similar returns true if the two Call are equal or almost but not quite
// equal.

similar returns true if the two Call are equal or almost but not quite equal .


func (c *Call) merge(r *Call) Call {
	return Call{
		SrcPath:      c.SrcPath,
		Line:         c.Line,
		Func:         c.Func,
		Args:         c.Args.merge(&r.Args),
		LocalSrcPath: c.LocalSrcPath,
		IsStdlib:     c.IsStdlib,
	}
}

func ( c * Call ) merge ( r * Call ) Call { return Call { SrcPath : c . SrcPath , Line : c . Line , Func : c . Func , Args : c . Args . merge ( & r . Args ) , LocalSrcPath : c . LocalSrcPath , IsStdlib : c . IsStdlib , } }

// merge merges two similar Call, zapping out differences.

merge merges two similar Call zapping out differences .


func (c *Call) PkgSrc() string {
	return filepath.Join(filepath.Base(filepath.Dir(c.SrcPath)), c.SrcName())
}

func ( c * Call ) PkgSrc ( ) string { return filepath . Join ( filepath . Base ( filepath . Dir ( c . SrcPath ) ) , c . SrcName ( ) ) }

// PkgSrc is one directory plus the file name of the source file.

PkgSrc is one directory plus the file name of the source file .


func (c *Call) updateLocations(goroot, localgoroot string, gopaths map[string]string) {
	if c.SrcPath != "" {
		// Always check GOROOT first, then GOPATH.
		if strings.HasPrefix(c.SrcPath, goroot) {
			// Replace remote GOROOT with local GOROOT.
			c.LocalSrcPath = filepath.Join(localgoroot, c.SrcPath[len(goroot):])
		} else {
			// Replace remote GOPATH with local GOPATH.
			c.LocalSrcPath = c.SrcPath
			// TODO(maruel): Sort for deterministic behavior?
			for prefix, dest := range gopaths {
				if strings.HasPrefix(c.SrcPath, prefix) {
					c.LocalSrcPath = filepath.Join(dest, c.SrcPath[len(prefix):])
					break
				}
			}
		}
	}
	// Consider _test/_testmain.go as stdlib since it's injected by "go test".
	c.IsStdlib = (goroot != "" && strings.HasPrefix(c.SrcPath, goroot)) || c.PkgSrc() == testMainSrc
}

// updateLocations initializes LocalSrcPath and IsStdlib.

updateLocations initializes LocalSrcPath and IsStdlib .


func (s *Stack) equal(r *Stack) bool {
	if len(s.Calls) != len(r.Calls) || s.Elided != r.Elided {
		return false
	}
	for i := range s.Calls {
		if !s.Calls[i].equal(&r.Calls[i]) {
			return false
		}
	}
	return true
}

func ( s * Stack ) equal ( r * Stack ) bool { if len ( s . Calls ) != len ( r . Calls ) || s . Elided != r . Elided { return false } for i := range s . Calls { if ! s . Calls [ i ] . equal ( & r . Calls [ i ] ) { return false } } return true }

// equal returns true on if both call stacks are exactly equal.

equal returns true on if both call stacks are exactly equal .


func (s *Stack) similar(r *Stack, similar Similarity) bool {
	if len(s.Calls) != len(r.Calls) || s.Elided != r.Elided {
		return false
	}
	for i := range s.Calls {
		if !s.Calls[i].similar(&r.Calls[i], similar) {
			return false
		}
	}
	return true
}

func ( s * Stack ) similar ( r * Stack , similar Similarity ) bool { if len ( s . Calls ) != len ( r . Calls ) || s . Elided != r . Elided { return false } for i := range s . Calls { if ! s . Calls [ i ] . similar ( & r . Calls [ i ] , similar ) { return false } } return true }

// similar returns true if the two Stack are equal or almost but not quite
// equal.

similar returns true if the two Stack are equal or almost but not quite equal .


func (s *Stack) merge(r *Stack) *Stack {
	// Assumes similar stacks have the same length.
	out := &Stack{
		Calls:  make([]Call, len(s.Calls)),
		Elided: s.Elided,
	}
	for i := range s.Calls {
		out.Calls[i] = s.Calls[i].merge(&r.Calls[i])
	}
	return out
}

// merge merges two similar Stack, zapping out differences.

merge merges two similar Stack zapping out differences .


func (s *Stack) less(r *Stack) bool {
	lStdlib := 0
	lPrivate := 0
	for _, c := range s.Calls {
		if c.IsStdlib {
			lStdlib++
		} else {
			lPrivate++
		}
	}
	rStdlib := 0
	rPrivate := 0
	for _, s := range r.Calls {
		if s.IsStdlib {
			rStdlib++
		} else {
			rPrivate++
		}
	}
	if lPrivate > rPrivate {
		return true
	}
	if lPrivate < rPrivate {
		return false
	}
	if lStdlib > rStdlib {
		return false
	}
	if lStdlib < rStdlib {
		return true
	}

	// Stack lengths are the same.
	for x := range s.Calls {
		if s.Calls[x].Func.Raw < r.Calls[x].Func.Raw {
			return true
		}
		if s.Calls[x].Func.Raw > r.Calls[x].Func.Raw {
			return true
		}
		if s.Calls[x].PkgSrc() < r.Calls[x].PkgSrc() {
			return true
		}
		if s.Calls[x].PkgSrc() > r.Calls[x].PkgSrc() {
			return true
		}
		if s.Calls[x].Line < r.Calls[x].Line {
			return true
		}
		if s.Calls[x].Line > r.Calls[x].Line {
			return true
		}
	}
	return false
}

func
(
s
*
Stack
)
less
(
r
*
Stack
)
bool
{
lStdlib
:=
0
lPrivate
:=
0
for
_
,
c
:=
range
s
.
Calls
{
if
c
.
IsStdlib
{
lStdlib
++
}
else
{
lPrivate
++
}
}
rStdlib
:=
0
rPrivate
:=
0
for
_
,
s
:=
range
r
.
Calls
{
if
s
.
IsStdlib
{
rStdlib
++
}
else
{
rPrivate
++
}
}
if
lPrivate
>
rPrivate
{
return
true
}
if
lPrivate
<
rPrivate
{
return
false
}
if
lStdlib
>
rStdlib
{
return
false
}
if
lStdlib
<
rStdlib
{
return
true
}
// Stack lengths are the same.
for
x
:=
range
s
.
Calls
{
if
s
.
Calls
[
x
]
.
Func
.
Raw
<
r
.
Calls
[
x
]
.
Func
.
Raw
{
return
true
}
if
s
.
Calls
[
x
]
.
Func
.
Raw
>
r
.
Calls
[
x
]
.
Func
.
Raw
{
return
true
}
if
s
.
Calls
[
x
]
.
PkgSrc
(
)
<
r
.
Calls
[
x
]
.
PkgSrc
(
)
{
return
true
}
if
s
.
Calls
[
x
]
.
PkgSrc
(
)
>
r
.
Calls
[
x
]
.
PkgSrc
(
)
{
return
true
}
if
s
.
Calls
[
x
]
.
Line
<
r
.
Calls
[
x
]
.
Line
{
return
true
}
if
s
.
Calls
[
x
]
.
Line
>
r
.
Calls
[
x
]
.
Line
{
return
true
}
}
return
false
}

// less compares two Stack, where the ones that are less are more
// important, so they come up front.
//
// A Stack with more private functions is 'less' so it is at the top.
// Inversely, a Stack with only public functions is 'more' so it is at the
// bottom.

less compares two Stack where the ones that are less are more important so they come up front . A Stack with more private functions is less so it is at the top . Inversely a Stack with only public functions is more so it is at the bottom .


func (s *Signature) equal(r *Signature) bool {
	if s.State != r.State || !s.CreatedBy.equal(&r.CreatedBy) || s.Locked != r.Locked || s.SleepMin != r.SleepMin || s.SleepMax != r.SleepMax {
		return false
	}
	return s.Stack.equal(&r.Stack)
}

func ( s * Signature ) equal ( r * Signature ) bool { if s . State != r . State || ! s . CreatedBy . equal ( & r . CreatedBy ) || s . Locked != r . Locked || s . SleepMin != r . SleepMin || s . SleepMax != r . SleepMax { return false } return s . Stack . equal ( & r . Stack ) }

// equal returns true only if both signatures are exactly equal.

equal returns true only if both signatures are exactly equal .


func (s *Signature) similar(r *Signature, similar Similarity) bool {
	if s.State != r.State || !s.CreatedBy.similar(&r.CreatedBy, similar) {
		return false
	}
	if similar == ExactFlags && s.Locked != r.Locked {
		return false
	}
	return s.Stack.similar(&r.Stack, similar)
}

func ( s * Signature ) similar ( r * Signature , similar Similarity ) bool { if s . State != r . State || ! s . CreatedBy . similar ( & r . CreatedBy , similar ) { return false } if similar == ExactFlags && s . Locked != r . Locked { return false } return s . Stack . similar ( & r . Stack , similar ) }

// similar returns true if the two Signature are equal or almost but not quite
// equal.

similar returns true if the two Signature are equal or almost but not quite equal .


func (s *Signature) merge(r *Signature) *Signature {
	min := s.SleepMin
	if r.SleepMin < min {
		min = r.SleepMin
	}
	max := s.SleepMax
	if r.SleepMax > max {
		max = r.SleepMax
	}
	return &Signature{
		State:     s.State,     // Drop right side.
		CreatedBy: s.CreatedBy, // Drop right side.
		SleepMin:  min,
		SleepMax:  max,
		Stack:     *s.Stack.merge(&r.Stack),
		Locked:    s.Locked || r.Locked, // TODO(maruel): This is weirdo.
	}
}

func
(
s
*
Signature
)
merge
(
r
*
Signature
)
*
Signature
{
min
:=
s
.
SleepMin
if
r
.
SleepMin
<
min
{
min
=
r
.
SleepMin
}
max
:=
s
.
SleepMax
if
r
.
SleepMax
>
max
{
max
=
r
.
SleepMax
}
return
&
Signature
{
State
:
s
.
State
,
// Drop right side.
CreatedBy
:
s
.
CreatedBy
,
// Drop right side.
SleepMin
:
min
,
SleepMax
:
max
,
Stack
:
*
s
.
Stack
.
merge
(
&
r
.
Stack
)
,
Locked
:
s
.
Locked
||
r
.
Locked
,
// TODO(maruel): This is weirdo.
}
}

// merge merges two similar Signature, zapping out differences.

merge merges two similar Signature zapping out differences .


func (s *Signature) less(r *Signature) bool {
	if s.Stack.less(&r.Stack) {
		return true
	}
	if r.Stack.less(&s.Stack) {
		return false
	}
	if s.Locked && !r.Locked {
		return true
	}
	if r.Locked && !s.Locked {
		return false
	}
	if s.State < r.State {
		return true
	}
	if s.State > r.State {
		return false
	}
	return false
}

func ( s * Signature ) less ( r * Signature ) bool { if s . Stack . less ( & r . Stack ) { return true } if r . Stack . less ( & s . Stack ) { return false } if s . Locked && ! r . Locked { return true } if r . Locked && ! s . Locked { return false } if s . State < r . State { return true } if s . State > r . State { return false } return false }

// less compares two Signature, where the ones that are less are more
// important, so they come up front. A Signature with more private functions is
// 'less' so it is at the top. Inversely, a Signature with only public
// functions is 'more' so it is at the bottom.

less compares two Signature where the ones that are less are more important so they come up front . A Signature with more private functions is less so it is at the top . Inversely a Signature with only public functions is more so it is at the bottom .


func (s *Signature) CreatedByString(fullPath bool) string {
	created := s.CreatedBy.Func.PkgDotName()
	if created == "" {
		return ""
	}
	created += " @ "
	if fullPath {
		created += s.CreatedBy.FullSrcLine()
	} else {
		created += s.CreatedBy.SrcLine()
	}
	return created
}

func ( s * Signature ) CreatedByString ( fullPath bool ) string { created := s . CreatedBy . Func . PkgDotName ( ) if created == " " { return " " } created += " " if fullPath { created += s . CreatedBy . FullSrcLine ( ) } else { created += s . CreatedBy . SrcLine ( ) } return created }

// CreatedByString return a short context about the origin of this goroutine
// signature.

CreatedByString return a short context about the origin of this goroutine signature .


func nameArguments(goroutines []*Goroutine) {
	// Set a name for any pointer occurring more than once.
	type object struct {
		args      []*Arg
		inPrimary bool
		id        int
	}
	objects := map[uint64]object{}
	// Enumerate all the arguments.
	for i := range goroutines {
		for j := range goroutines[i].Stack.Calls {
			for k := range goroutines[i].Stack.Calls[j].Args.Values {
				arg := goroutines[i].Stack.Calls[j].Args.Values[k]
				if arg.IsPtr() {
					objects[arg.Value] = object{
						args:      append(objects[arg.Value].args, &goroutines[i].Stack.Calls[j].Args.Values[k]),
						inPrimary: objects[arg.Value].inPrimary || i == 0,
					}
				}
			}
		}
		// CreatedBy.Args is never set.
	}
	order := make(uint64Slice, 0, len(objects)/2)
	for k, obj := range objects {
		if len(obj.args) > 1 && obj.inPrimary {
			order = append(order, k)
		}
	}
	sort.Sort(order)
	nextID := 1
	for _, k := range order {
		for _, arg := range objects[k].args {
			arg.Name = fmt.Sprintf("#%d", nextID)
		}
		nextID++
	}

	// Now do the rest. This is done so the output is deterministic.
	order = make(uint64Slice, 0, len(objects))
	for k := range objects {
		order = append(order, k)
	}
	sort.Sort(order)
	for _, k := range order {
		// Process the remaining pointers, they were not referenced by primary
		// thread so will have higher IDs.
		if objects[k].inPrimary {
			continue
		}
		for _, arg := range objects[k].args {
			arg.Name = fmt.Sprintf("#%d", nextID)
		}
		nextID++
	}
}

// Private stuff.
// nameArguments is a post-processing step where Args are 'named' with numbers.

Private stuff . nameArguments is a post - processing step where Args are named with numbers .


func CalcLengths(buckets []*stack.Bucket, fullPath bool) (int, int) {
	srcLen := 0
	pkgLen := 0
	for _, bucket := range buckets {
		for _, line := range bucket.Signature.Stack.Calls {
			l := 0
			if fullPath {
				l = len(line.FullSrcLine())
			} else {
				l = len(line.SrcLine())
			}
			if l > srcLen {
				srcLen = l
			}
			l = len(line.Func.PkgName())
			if l > pkgLen {
				pkgLen = l
			}
		}
	}
	return srcLen, pkgLen
}

func CalcLengths ( buckets [ ] * stack . Bucket , fullPath bool ) ( int , int ) { srcLen := 0 pkgLen := 0 for _ , bucket := range buckets { for _ , line := range bucket . Signature . Stack . Calls { l := 0 if fullPath { l = len ( line . FullSrcLine ( ) ) } else { l = len ( line . SrcLine ( ) ) } if l > srcLen { srcLen = l } l = len ( line . Func . PkgName ( ) ) if l > pkgLen { pkgLen = l } } } return srcLen , pkgLen }

// CalcLengths returns the maximum length of the source lines and package names.

CalcLengths returns the maximum length of the source lines and package names .


func (p *Palette) functionColor(line *stack.Call) string {
	if line.IsStdlib {
		if line.Func.IsExported() {
			return p.FuncStdLibExported
		}
		return p.FuncStdLib
	} else if line.IsPkgMain() {
		return p.FuncMain
	} else if line.Func.IsExported() {
		return p.FuncOtherExported
	}
	return p.FuncOther
}

func ( p * Palette ) functionColor ( line * stack . Call ) string { if line . IsStdlib { if line . Func . IsExported ( ) { return p . FuncStdLibExported } return p . FuncStdLib } else if line . IsPkgMain ( ) { return p . FuncMain } else if line . Func . IsExported ( ) { return p . FuncOtherExported } return p . FuncOther }

// functionColor returns the color to be used for the function name based on
// the type of package the function is in.

functionColor returns the color to be used for the function name based on the type of package the function is in .


func (p *Palette) routineColor(bucket *stack.Bucket, multipleBuckets bool) string {
	if bucket.First && multipleBuckets {
		return p.RoutineFirst
	}
	return p.Routine
}

func ( p * Palette ) routineColor ( bucket * stack . Bucket , multipleBuckets bool ) string { if bucket . First && multipleBuckets { return p . RoutineFirst } return p . Routine }

// routineColor returns the color for the header of the goroutines bucket.

routineColor returns the color for the header of the goroutines bucket .


func (p *Palette) BucketHeader(bucket *stack.Bucket, fullPath, multipleBuckets bool) string {
	extra := ""
	if s := bucket.SleepString(); s != "" {
		extra += " [" + s + "]"
	}
	if bucket.Locked {
		extra += " [locked]"
	}
	if c := bucket.CreatedByString(fullPath); c != "" {
		extra += p.CreatedBy + " [Created by " + c + "]"
	}
	return fmt.Sprintf(
		"%s%d: %s%s%s\n",
		p.routineColor(bucket, multipleBuckets), len(bucket.IDs),
		bucket.State, extra,
		p.EOLReset)
}

func ( p * Palette ) BucketHeader ( bucket * stack . Bucket , fullPath , multipleBuckets bool ) string { extra := " " if s := bucket . SleepString ( ) ; s != " " { extra += " " + s + " " } if bucket . Locked { extra += " " } if c := bucket . CreatedByString ( fullPath ) ; c != " " { extra += p . CreatedBy + " " + c + " " } return fmt . Sprintf ( " \n " , p . routineColor ( bucket , multipleBuckets ) , len ( bucket . IDs ) , bucket . State , extra , p . EOLReset ) }

// BucketHeader prints the header of a goroutine signature.

BucketHeader prints the header of a goroutine signature .


func (p *Palette) callLine(line *stack.Call, srcLen, pkgLen int, fullPath bool) string {
	src := ""
	if fullPath {
		src = line.FullSrcLine()
	} else {
		src = line.SrcLine()
	}
	return fmt.Sprintf(
		"    %s%-*s %s%-*s %s%s%s(%s)%s",
		p.Package, pkgLen, line.Func.PkgName(),
		p.SrcFile, srcLen, src,
		p.functionColor(line), line.Func.Name(),
		p.Arguments, &line.Args,
		p.EOLReset)
}

func ( p * Palette ) callLine ( line * stack . Call , srcLen , pkgLen int , fullPath bool ) string { src := " " if fullPath { src = line . FullSrcLine ( ) } else { src = line . SrcLine ( ) } return fmt . Sprintf ( " " , p . Package , pkgLen , line . Func . PkgName ( ) , p . SrcFile , srcLen , src , p . functionColor ( line ) , line . Func . Name ( ) , p . Arguments , & line . Args , p . EOLReset ) }


func (p *Palette) StackLines(signature *stack.Signature, srcLen, pkgLen int, fullPath bool) string {
	out := make([]string, len(signature.Stack.Calls))
	for i := range signature.Stack.Calls {
		out[i] = p.callLine(&signature.Stack.Calls[i], srcLen, pkgLen, fullPath)
	}
	if signature.Stack.Elided {
		out = append(out, "    (...)")
	}
	return strings.Join(out, "\n") + "\n"
}

func ( p * Palette ) StackLines ( signature * stack . Signature , srcLen , pkgLen int , fullPath bool ) string { out := make ( [ ] string , len ( signature . Stack . Calls ) ) for i := range signature . Stack . Calls { out [ i ] = p . callLine ( & signature . Stack . Calls [ i ] , srcLen , pkgLen , fullPath ) } if signature . Stack . Elided { out = append ( out , " " ) } return strings . Join ( out , " \n " ) + " \n " }

// StackLines prints one complete stack trace, without the header.

StackLines prints one complete stack trace without the header .


func (c *cache) augmentGoroutine(goroutine *Goroutine) {
	if c.files == nil {
		c.files = map[string][]byte{}
	}
	if c.parsed == nil {
		c.parsed = map[string]*parsedFile{}
	}
	// For each call site, look at the next call and populate it. Then we can
	// walk back and reformat things.
	for i := range goroutine.Stack.Calls {
		c.load(goroutine.Stack.Calls[i].LocalSrcPath)
	}

	// Once all loaded, we can look at the next call when available.
	for i := 0; i < len(goroutine.Stack.Calls)-1; i++ {
		// Get the AST from the previous call and process the call line with it.
		if f := c.getFuncAST(&goroutine.Stack.Calls[i]); f != nil {
			processCall(&goroutine.Stack.Calls[i], f)
		}
	}
}

// augmentGoroutine processes source files to improve call to be more
// descriptive.
//
// It modifies the routine.

augmentGoroutine processes source files to improve call to be more descriptive . It modifies the routine .


func (c *cache) load(fileName string) {
	if _, ok := c.parsed[fileName]; ok {
		return
	}
	c.parsed[fileName] = nil
	if !strings.HasSuffix(fileName, ".go") {
		// Ignore C and assembly.
		c.files[fileName] = nil
		return
	}
	log.Printf("load(%s)", fileName)
	if _, ok := c.files[fileName]; !ok {
		var err error
		if c.files[fileName], err = ioutil.ReadFile(fileName); err != nil {
			log.Printf("Failed to read %s: %s", fileName, err)
			c.files[fileName] = nil
			return
		}
	}
	fset := token.NewFileSet()
	src := c.files[fileName]
	parsed, err := parser.ParseFile(fset, fileName, src, 0)
	if err != nil {
		log.Printf("Failed to parse %s: %s", fileName, err)
		return
	}
	// Convert the line number into raw file offset.
	offsets := []int{0, 0}
	start := 0
	for l := 1; start < len(src); l++ {
		start += bytes.IndexByte(src[start:], '\n') + 1
		offsets = append(offsets, start)
	}
	c.parsed[fileName] = &parsedFile{offsets, parsed}
}

// Private stuff.
// load loads a source file and parses the AST tree. Failures are ignored.

Private stuff . load loads a source file and parses the AST tree . Failures are ignored .


func (p *parsedFile) getFuncAST(f string, l int) (d *ast.FuncDecl) {
	if len(p.lineToByteOffset) <= l {
		// The line number in the stack trace line does not exist in the file. That
		// can only mean that the sources on disk do not match the sources used to
		// build the binary.
		// TODO(maruel): This should be surfaced, so that source parsing is
		// completely ignored.
		return
	}

	// Walk the AST to find the lineToByteOffset that fits the line number.
	var lastFunc *ast.FuncDecl
	var found ast.Node
	// Inspect() goes depth first. This means for example that a function like:
	// func a() {
	//   b := func() {}
	//   c()
	// }
	//
	// Were we are looking at the c() call can return confused values. It is
	// important to look at the actual ast.Node hierarchy.
	ast.Inspect(p.parsed, func(n ast.Node) bool {
		if d != nil {
			return false
		}
		if n == nil {
			return true
		}
		if found != nil {
			// We are walking up.
		}
		if int(n.Pos()) >= p.lineToByteOffset[l] {
			// We are expecting a ast.CallExpr node. It can be harder to figure out
			// when there are multiple calls on a single line, as the stack trace
			// doesn't have file byte offset information, only line based.
			// gofmt will always format to one function call per line but there can
			// be edge cases, like:
			//   a = A{Foo(), Bar()}
			d = lastFunc
			//p.processNode(call, n)
			return false
		} else if f, ok := n.(*ast.FuncDecl); ok {
			lastFunc = f
		}
		return true
	})
	return
}

// getFuncAST gets the callee site function AST representation for the code
// inside the function f at line l.

getFuncAST gets the callee site function AST representation for the code inside the function f at line l .


func fieldToType(f *ast.Field) (string, bool) {
	switch arg := f.Type.(type) {
	case *ast.ArrayType:
		return "[]" + name(arg.Elt), false
	case *ast.Ellipsis:
		return name(arg.Elt), true
	case *ast.FuncType:
		// Do not print the function signature to not overload the trace.
		return "func", false
	case *ast.Ident:
		return arg.Name, false
	case *ast.InterfaceType:
		return "interface{}", false
	case *ast.SelectorExpr:
		return arg.Sel.Name, false
	case *ast.StarExpr:
		return "*" + name(arg.X), false
	case *ast.MapType:
		return fmt.Sprintf("map[%s]%s", name(arg.Key), name(arg.Value)), false
	case *ast.ChanType:
		return fmt.Sprintf("chan %s", name(arg.Value)), false
	default:
		// TODO(maruel): Implement anything missing.
		return "<unknown>", false
	}
}

// fieldToType returns the type name and whether if it's an ellipsis.

fieldToType returns the type name and whether if it s an ellipsis .


func extractArgumentsType(f *ast.FuncDecl) ([]string, bool) {
	var fields []*ast.Field
	if f.Recv != nil {
		if len(f.Recv.List) != 1 {
			panic("Expect only one receiver; please fix panicparse's code")
		}
		// If it is an object receiver (vs a pointer receiver), its address is not
		// printed in the stack trace so it needs to be ignored.
		if _, ok := f.Recv.List[0].Type.(*ast.StarExpr); ok {
			fields = append(fields, f.Recv.List[0])
		}
	}
	var types []string
	extra := false
	for _, arg := range append(fields, f.Type.Params.List...) {
		// Assert that extra is only set on the last item of fields?
		var t string
		t, extra = fieldToType(arg)
		mult := len(arg.Names)
		if mult == 0 {
			mult = 1
		}
		for i := 0; i < mult; i++ {
			types = append(types, t)
		}
	}
	return types, extra
}

// extractArgumentsType returns the name of the type of each input argument.

extractArgumentsType returns the name of the type of each input argument .


func (t *Template) Reset(template, startTag, endTag string) error {
	// Keep these vars in t, so GC won't collect them and won't break
	// vars derived via unsafe*
	t.template = template
	t.startTag = startTag
	t.endTag = endTag
	t.texts = t.texts[:0]
	t.tags = t.tags[:0]

	if len(startTag) == 0 {
		panic("startTag cannot be empty")
	}
	if len(endTag) == 0 {
		panic("endTag cannot be empty")
	}

	s := unsafeString2Bytes(template)
	a := unsafeString2Bytes(startTag)
	b := unsafeString2Bytes(endTag)

	tagsCount := bytes.Count(s, a)
	if tagsCount == 0 {
		return nil
	}

	if tagsCount+1 > cap(t.texts) {
		t.texts = make([][]byte, 0, tagsCount+1)
	}
	if tagsCount > cap(t.tags) {
		t.tags = make([]string, 0, tagsCount)
	}

	for {
		n := bytes.Index(s, a)
		if n < 0 {
			t.texts = append(t.texts, s)
			break
		}
		t.texts = append(t.texts, s[:n])

		s = s[n+len(a):]
		n = bytes.Index(s, b)
		if n < 0 {
			return fmt.Errorf("Cannot find end tag=%q in the template=%q starting from %q", endTag, template, s)
		}

		t.tags = append(t.tags, unsafeBytes2String(s[:n]))
		s = s[n+len(b):]
	}

	return nil
}

// Reset resets the template t to new one defined by
// template, startTag and endTag.
//
// Reset allows Template object re-use.
//
// Reset may be called only if no other goroutines call t methods at the moment.

Reset resets the template t to new one defined by template startTag and endTag . Reset allows Template object re - use . Reset may be called only if no other goroutines call t methods at the moment .


func (m *Mutex) Unlock() {
	m.mu.Unlock()
	if !Opts.Disable {
		postUnlock(m)
	}
}

func ( m * Mutex ) Unlock ( ) { m . mu . Unlock ( ) if ! Opts . Disable { postUnlock ( m ) } }

// Unlock unlocks the mutex.
// It is a run-time error if m is not locked on entry to Unlock.
//
// A locked Mutex is not associated with a particular goroutine.
// It is allowed for one goroutine to lock a Mutex and then
// arrange for another goroutine to unlock it.

Unlock unlocks the mutex . It is a run - time error if m is not locked on entry to Unlock . A locked Mutex is not associated with a particular goroutine . It is allowed for one goroutine to lock a Mutex and then arrange for another goroutine to unlock it .


func (m *RWMutex) RUnlock() {
	m.mu.RUnlock()
	if !Opts.Disable {
		postUnlock(m)
	}
}

func ( m * RWMutex ) RUnlock ( ) { m . mu . RUnlock ( ) if ! Opts . Disable { postUnlock ( m ) } }

// RUnlock undoes a single RLock call;
// it does not affect other simultaneous readers.
// It is a run-time error if rw is not locked for reading
// on entry to RUnlock.

RUnlock undoes a single RLock call ; it does not affect other simultaneous readers . It is a run - time error if rw is not locked for reading on entry to RUnlock .


func (l *lockOrder) other(ptr interface{}) {
	empty := true
	for k := range l.cur {
		if k == ptr {
			continue
		}
		empty = false
	}
	if empty {
		return
	}
	fmt.Fprintln(Opts.LogBuf, "Other goroutines holding locks:")
	for k, pp := range l.cur {
		if k == ptr {
			continue
		}
		fmt.Fprintf(Opts.LogBuf, "goroutine %v lock %p\n", pp.gid, k)
		printStack(Opts.LogBuf, pp.stack)
	}
	fmt.Fprintln(Opts.LogBuf)
}

func ( l * lockOrder ) other ( ptr interface { } ) { empty := true for k := range l . cur { if k == ptr { continue } empty = false } if empty { return } fmt . Fprintln ( Opts . LogBuf , " " ) for k , pp := range l . cur { if k == ptr { continue } fmt . Fprintf ( Opts . LogBuf , " \n " , pp . gid , k ) printStack ( Opts . LogBuf , pp . stack ) } fmt . Fprintln ( Opts . LogBuf ) }


func getSourceLines(file string) [][]byte {
	fileSources.Lock()
	defer fileSources.Unlock()
	if fileSources.lines == nil {
		fileSources.lines = map[string][][]byte{}
	}
	if lines, ok := fileSources.lines[file]; ok {
		return lines
	}
	text, _ := ioutil.ReadFile(file)
	fileSources.lines[file] = bytes.Split(text, []byte{'\n'})
	return fileSources.lines[file]
}

func getSourceLines ( file string ) [ ] [ ] byte { fileSources . Lock ( ) defer fileSources . Unlock ( ) if fileSources . lines == nil { fileSources . lines = map [ string ] [ ] [ ] byte { } } if lines , ok := fileSources . lines [ file ] ; ok { return lines } text , _ := ioutil . ReadFile ( file ) fileSources . lines [ file ] = bytes . Split ( text , [ ] byte { '\n' } ) return fileSources . lines [ file ] }

// Reads souce file lines from disk if not cached already.

Reads souce file lines from disk if not cached already .


func stacks() []byte {
	buf := make([]byte, 1024*16)
	for {
		n := runtime.Stack(buf, true)
		if n < len(buf) {
			return buf[:n]
		}
		buf = make([]byte, 2*len(buf))
	}
}

func stacks ( ) [ ] byte { buf := make ( [ ] byte , 1024 * 16 ) for { n := runtime . Stack ( buf , true ) if n < len ( buf ) { return buf [ : n ] } buf = make ( [ ] byte , 2 * len ( buf ) ) } }


func NewWithAlphabet(abc string) string {
	enc := base57{newAlphabet(abc)}
	return enc.Encode(uuid.New())
}

func NewWithAlphabet ( abc string ) string { enc := base57 { newAlphabet ( abc ) } return enc . Encode ( uuid . New ( ) ) }

// NewWithAlphabet returns a new UUIDv4, encoded with base57 using the
// alternative alphabet abc.

NewWithAlphabet returns a new UUIDv4 encoded with base57 using the alternative alphabet abc .


func (b *base57) numToString(number *big.Int, padToLen int) string {
	var (
		out   string
		digit *big.Int
	)

	for number.Uint64() > 0 {
		number, digit = new(big.Int).DivMod(number, big.NewInt(b.alphabet.Length()), new(big.Int))
		out += b.alphabet.chars[digit.Int64()]
	}

	if padToLen > 0 {
		remainder := math.Max(float64(padToLen-len(out)), 0)
		out = out + strings.Repeat(b.alphabet.chars[0], int(remainder))
	}

	return out
}

func ( b * base57 ) numToString ( number * big . Int , padToLen int ) string { var ( out string digit * big . Int ) for number . Uint64 ( ) > 0 { number , digit = new ( big . Int ) . DivMod ( number , big . NewInt ( b . alphabet . Length ( ) ) , new ( big . Int ) ) out += b . alphabet . chars [ digit . Int64 ( ) ] } if padToLen > 0 { remainder := math . Max ( float64 ( padToLen - len ( out ) ) , 0 ) out = out + strings . Repeat ( b . alphabet . chars [ 0 ] , int ( remainder ) ) } return out }

// numToString converts a number a string using the given alpabet.

numToString converts a number a string using the given alpabet .


func (b *base57) stringToNum(s string) (string, error) {
	n := big.NewInt(0)

	for i := len(s) - 1; i >= 0; i-- {
		n.Mul(n, big.NewInt(b.alphabet.Length()))

		index, err := b.alphabet.Index(string(s[i]))
		if err != nil {
			return "", err
		}

		n.Add(n, big.NewInt(index))
	}

	x := fmt.Sprintf("%x", n)

	if len(x) < 32 {
		// Pad the most significant bit (MSG) with 0 (zero) if the string is too short.
		x = strings.Repeat("0", 32-len(x)) + x
	} else if len(x) > 32 {
		return "", fmt.Errorf("UUID length overflow for %q", s)
	}

	return fmt.Sprintf("%s-%s-%s-%s-%s", x[0:8], x[8:12], x[12:16], x[16:20], x[20:32]), nil
}

// stringToNum converts a string a number using the given alpabet.

stringToNum converts a string a number using the given alpabet .


func newAlphabet(s string) alphabet {
	abc := dedupe(strings.Split(s, ""))

	if len(abc) != 57 {
		panic("encoding alphabet is not 57-bytes long")
	}

	sort.Strings(abc)
	a := alphabet{
		len: int64(len(abc)),
	}
	copy(a.chars[:], abc)
	return a
}

func newAlphabet ( s string ) alphabet { abc := dedupe ( strings . Split ( s , " " ) ) if len ( abc ) != 57 { panic ( " " ) } sort . Strings ( abc ) a := alphabet { len : int64 ( len ( abc ) ) , } copy ( a . chars [ : ] , abc ) return a }

// Remove duplicates and sort it to ensure reproducability.

Remove duplicates and sort it to ensure reproducability .


func (a *alphabet) Index(t string) (int64, error) {
	for i, char := range a.chars {
		if char == t {
			return int64(i), nil
		}
	}
	return 0, fmt.Errorf("Element '%v' is not part of the alphabet", t)
}

func ( a * alphabet ) Index ( t string ) ( int64 , error ) { for i , char := range a . chars { if char == t { return int64 ( i ) , nil } } return 0 , fmt . Errorf ( " " , t ) }

// Index returns the index of the first instance of t in the alphabet, or an error if t is not present.

Index returns the index of the first instance of t in the alphabet or an error if t is not present .


func dedupe(s []string) []string {
	var out []string
	m := make(map[string]bool)

	for _, char := range s {
		if _, ok := m[char]; !ok {
			m[char] = true
			out = append(out, char)
		}
	}

	return out
}

func dedupe ( s [ ] string ) [ ] string { var out [ ] string m := make ( map [ string ] bool ) for _ , char := range s { if _ , ok := m [ char ] ; ! ok { m [ char ] = true out = append ( out , char ) } } return out }

// dudupe removes duplicate characters from s.

dudupe removes duplicate characters from s .


func Is(e error, original error) bool {

	if e == original {
		return true
	}

	if e, ok := e.(*Error); ok {
		return Is(e.Err, original)
	}

	if original, ok := original.(*Error); ok {
		return Is(e, original.Err)
	}

	return false
}

func Is ( e error , original error ) bool { if e == original { return true } if e , ok := e . ( * Error ) ; ok { return Is ( e . Err , original ) } if original , ok := original . ( * Error ) ; ok { return Is ( e , original . Err ) } return false }

// Is detects whether the error is equal to a given error. Errors
// are considered equal by this function if they are the same object,
// or if they both contain the same error inside an errors.Error.

Is detects whether the error is equal to a given error . Errors are considered equal by this function if they are the same object or if they both contain the same error inside an errors . Error .


func (err *Error) Error() string {

	msg := err.Err.Error()
	if err.prefix != "" {
		msg = fmt.Sprintf("%s: %s", err.prefix, msg)
	}

	return msg
}

func ( err * Error ) Error ( ) string { msg := err . Err . Error ( ) if err . prefix != " " { msg = fmt . Sprintf ( " " , err . prefix , msg ) } return msg }

// Error returns the underlying error's message.

Error returns the underlying error s message .


func (err *Error) ErrorStack() string {
	return err.TypeName() + " " + err.Error() + "\n" + string(err.Stack())
}

func ( err * Error ) ErrorStack ( ) string { return err . TypeName ( ) + " " + err . Error ( ) + " \n " + string ( err . Stack ( ) ) }

// ErrorStack returns a string that contains both the
// error message and the callstack.

ErrorStack returns a string that contains both the error message and the callstack .


func (t TextStyle) TextStyle(val string) string {
	if t == emptyTextStyle {
		return val
	}
	return fmt.Sprintf("%s%s%s", t.start, val, t.stop)
}

func ( t TextStyle ) TextStyle ( val string ) string { if t == emptyTextStyle { return val } return fmt . Sprintf ( " " , t . start , val , t . stop ) }

// TextStyle styles the given string using the desired text style.

TextStyle styles the given string using the desired text style .


func NewPointsIndex(resolution Meters) *PointsIndex {
	newSet := func() interface{} {
		return newSet()
	}

	return &PointsIndex{newGeoIndex(resolution, newSet), make(map[string]Point)}
}

func NewPointsIndex ( resolution Meters ) * PointsIndex { newSet := func ( ) interface { } { return newSet ( ) } return & PointsIndex { newGeoIndex ( resolution , newSet ) , make ( map [ string ] Point ) } }

// NewPointsIndex creates new PointsIndex that maintains the points in each cell.

NewPointsIndex creates new PointsIndex that maintains the points in each cell .


func NewExpiringPointsIndex(resolution Meters, expiration Minutes) *PointsIndex {
	currentPosition := make(map[string]Point)

	newExpiringSet := func() interface{} {
		set := newExpiringSet(expiration)

		set.OnExpire(func(id string, value interface{}) {
			point := value.(Point)
			delete(currentPosition, point.Id())
		})

		return set
	}

	return &PointsIndex{newGeoIndex(resolution, newExpiringSet), currentPosition}
}

func NewExpiringPointsIndex ( resolution Meters , expiration Minutes ) * PointsIndex { currentPosition := make ( map [ string ] Point ) newExpiringSet := func ( ) interface { } { set := newExpiringSet ( expiration ) set . OnExpire ( func ( id string , value interface { } ) { point := value . ( Point ) delete ( currentPosition , point . Id ( ) ) } ) return set } return & PointsIndex { newGeoIndex ( resolution , newExpiringSet ) , currentPosition } }

// NewExpiringPointsIndex creates new PointIndex that expires the points in each cell after expiration minutes.

NewExpiringPointsIndex creates new PointIndex that expires the points in each cell after expiration minutes .


func (points *PointsIndex) Get(id string) Point {
	if point, ok := points.currentPosition[id]; ok {
		// first it gets the set of the currentPosition and then gets the point from the set
		// this is done so it triggers expiration on expiringSet, and returns nil if a point has expired
		if result, resultOk := points.index.GetEntryAt(point).(set).Get(id); resultOk {
			return result.(Point)
		}
	}
	return nil
}

// Get gets a point from the index given an id.

Get gets a point from the index given an id .


func (points *PointsIndex) GetAll() map[string]Point {
	newpoints := make(map[string]Point, 0)
	for i, p := range points.currentPosition {
		newpoints[i] = p
	}
	return newpoints
}

func ( points * PointsIndex ) GetAll ( ) map [ string ] Point { newpoints := make ( map [ string ] Point , 0 ) for i , p := range points . currentPosition { newpoints [ i ] = p } return newpoints }

// GetAll get all Points from the index as a map from id to point


func (points *PointsIndex) Add(point Point) {
	points.Remove(point.Id())
	newSet := points.index.AddEntryAt(point).(set)
	newSet.Add(point.Id(), point)
	points.currentPosition[point.Id()] = point
}

func ( points * PointsIndex ) Add ( point Point ) { points . Remove ( point . Id ( ) ) newSet := points . index . AddEntryAt ( point ) . ( set ) newSet . Add ( point . Id ( ) , point ) points . currentPosition [ point . Id ( ) ] = point }

// Add adds a point to the index. If a point with the same Id already exists it gets replaced.

Add adds a point to the index . If a point with the same Id already exists it gets replaced .


func (points *PointsIndex) Remove(id string) {
	if prevPoint, ok := points.currentPosition[id]; ok {
		set := points.index.GetEntryAt(prevPoint).(set)
		set.Remove(prevPoint.Id())
		delete(points.currentPosition, prevPoint.Id())
	}
}

func ( points * PointsIndex ) Remove ( id string ) { if prevPoint , ok := points . currentPosition [ id ] ; ok { set := points . index . GetEntryAt ( prevPoint ) . ( set ) set . Remove ( prevPoint . Id ( ) ) delete ( points . currentPosition , prevPoint . Id ( ) ) } }

// Remove removes a point from the index.


func (points *PointsIndex) Range(topLeft Point, bottomRight Point) []Point {
	entries := points.index.Range(topLeft, bottomRight)
	accept := func(point Point) bool {
		return between(point.Lat(), bottomRight.Lat(), topLeft.Lat()) &&
			between(point.Lon(), topLeft.Lon(), bottomRight.Lon())
	}

	return getPoints(entries, accept)
}

func ( points * PointsIndex ) Range ( topLeft Point , bottomRight Point ) [ ] Point { entries := points . index . Range ( topLeft , bottomRight ) accept := func ( point Point ) bool { return between ( point . Lat ( ) , bottomRight . Lat ( ) , topLeft . Lat ( ) ) && between ( point . Lon ( ) , topLeft . Lon ( ) , bottomRight . Lon ( ) ) } return getPoints ( entries , accept ) }

// Range returns the points within the range defined by top left and bottom right.

Range returns the points within the range defined by top left and bottom right .


func (points *PointsIndex) KNearest(point Point, k int, maxDistance Meters, accept func(p Point) bool) []Point {
	nearbyPoints := make([]Point, 0)
	pointEntry := points.index.GetEntryAt(point).(set)
	nearbyPoints = append(nearbyPoints, getPoints([]interface{}{pointEntry}, accept)...)

	totalCount := 0
	idx := cellOf(point, points.index.resolution)
	// Explicitely assign a greater max distance so that we definitely return enough points
	// and make sure it searches at least one square away.
	coarseMaxDistance := math.Max(float64(maxDistance)*2.0, float64(points.index.resolution)*2.0+0.01)

	for d := 1; float64(d)*float64(points.index.resolution) <= coarseMaxDistance; d++ {
		oldCount := len(nearbyPoints)

		nearbyPoints = getPointsAppend(nearbyPoints, points.index.get(idx.x-d, idx.x+d, idx.y+d, idx.y+d), accept)
		nearbyPoints = getPointsAppend(nearbyPoints, points.index.get(idx.x-d, idx.x+d, idx.y-d, idx.y-d), accept)
		nearbyPoints = getPointsAppend(nearbyPoints, points.index.get(idx.x-d, idx.x-d, idx.y-d+1, idx.y+d-1), accept)
		nearbyPoints = getPointsAppend(nearbyPoints, points.index.get(idx.x+d, idx.x+d, idx.y-d+1, idx.y+d-1), accept)

		totalCount += len(nearbyPoints) - oldCount

		if totalCount > k {
			break
		}
	}

	sortedPoints := &sortedPoints{nearbyPoints, point}
	sort.Sort(sortedPoints)

	k = min(k, len(sortedPoints.points))

	// filter points which longer than maxDistance away from point.
	for i, nearbyPoint := range sortedPoints.points {
		if Distance(point, nearbyPoint) > maxDistance || i == k {
			k = i
			break
		}
	}

	return sortedPoints.points[0:k]
}

// KNearest returns the k nearest points near point within maxDistance that match the accept criteria.

KNearest returns the k nearest points near point within maxDistance that match the accept criteria .


func (points *PointsIndex) PointsWithin(point Point, distance Meters, accept func(p Point) bool) []Point {

	d := int(distance / points.index.resolution)

	if d == 0 {
		d = 1
	}

	idx := cellOf(point, points.index.resolution)

	nearbyPoints := make([]Point, 0)
	nearbyPoints = getPointsAppend(nearbyPoints, points.index.get(idx.x-d, idx.x+d, idx.y-d, idx.y+d), accept)

	// filter points which longer than maxDistance away from point.
	withinPoints := make([]Point, 0)
	for _, nearbyPoint := range nearbyPoints {
		if Distance(point, nearbyPoint) < distance {
			withinPoints = append(withinPoints, nearbyPoint)
		}
	}

	return withinPoints
}

// PointsWithin returns all points with distance of point that match the accept criteria.

PointsWithin returns all points with distance of point that match the accept criteria .


func newMultiValueCounter(point Point) accumulatingCounter {
	values := make(map[string]int)
	values[point.Id()] = 1
	return &multiValueAccumulatingCounter{
		newSingleValueAccumulatingCounter(point).(*singleValueAccumulatingCounter),
		values,
	}
}

func newMultiValueCounter ( point Point ) accumulatingCounter { values := make ( map [ string ] int ) values [ point . Id ( ) ] = 1 return & multiValueAccumulatingCounter { newSingleValueAccumulatingCounter ( point ) . ( * singleValueAccumulatingCounter ) , values , } }


func newAverageAccumulatingCounter(point Point) accumulatingCounter {
	return &averageAccumulatingCounter{
		newSingleValueAccumulatingCounter(point).(*singleValueAccumulatingCounter),
		point.(*CountPoint).Count.(float64),
	}
}

func newAverageAccumulatingCounter ( point Point ) accumulatingCounter { return & averageAccumulatingCounter { newSingleValueAccumulatingCounter ( point ) . ( * singleValueAccumulatingCounter ) , point . ( * CountPoint ) . Count . ( float64 ) , } }

// Average accumulating counter. Expect adding and removing CountPoints.

Average accumulating counter . Expect adding and removing CountPoints .


func newGeoIndex(resolution Meters, newEntry func() interface{}) *geoIndex {
	return &geoIndex{resolution, make(map[cell]interface{}), newEntry}
}

func newGeoIndex ( resolution Meters , newEntry func ( ) interface { } ) * geoIndex { return & geoIndex { resolution , make ( map [ cell ] interface { } ) , newEntry } }

// Creates new geo index with resolution a function that returns a new entry that is stored in each cell.

Creates new geo index with resolution a function that returns a new entry that is stored in each cell .


func (geoIndex *geoIndex) AddEntryAt(point Point) interface{} {
	square := cellOf(point, geoIndex.resolution)

	if _, ok := geoIndex.index[square]; !ok {
		geoIndex.index[square] = geoIndex.newEntry()
	}

	return geoIndex.index[square]
}

func ( geoIndex * geoIndex ) AddEntryAt ( point Point ) interface { } { square := cellOf ( point , geoIndex . resolution ) if _ , ok := geoIndex . index [ square ] ; ! ok { geoIndex . index [ square ] = geoIndex . newEntry ( ) } return geoIndex . index [ square ] }

// AddEntryAt adds an entry if missing, returns the entry at specific position.

AddEntryAt adds an entry if missing returns the entry at specific position .


func (geoIndex *geoIndex) GetEntryAt(point Point) interface{} {
	square := cellOf(point, geoIndex.resolution)

	entries, ok := geoIndex.index[square]
	if !ok {
		return geoIndex.newEntry()
	}

	return entries
}

func ( geoIndex * geoIndex ) GetEntryAt ( point Point ) interface { } { square := cellOf ( point , geoIndex . resolution ) entries , ok := geoIndex . index [ square ] if ! ok { return geoIndex . newEntry ( ) } return entries }

// GetEntryAt gets an entry from the geoindex, if missing returns an empty entry without changing the index.

GetEntryAt gets an entry from the geoindex if missing returns an empty entry without changing the index .


func (geoIndex *geoIndex) Range(topLeft Point, bottomRight Point) []interface{} {
	topLeftIndex := cellOf(topLeft, geoIndex.resolution)
	bottomRightIndex := cellOf(bottomRight, geoIndex.resolution)

	return geoIndex.get(bottomRightIndex.x, topLeftIndex.x, topLeftIndex.y, bottomRightIndex.y)
}

func ( geoIndex * geoIndex ) Range ( topLeft Point , bottomRight Point ) [ ] interface { } { topLeftIndex := cellOf ( topLeft , geoIndex . resolution ) bottomRightIndex := cellOf ( bottomRight , geoIndex . resolution ) return geoIndex . get ( bottomRightIndex . x , topLeftIndex . x , topLeftIndex . y , bottomRightIndex . y ) }

// Range returns the index entries within lat, lng range.

Range returns the index entries within lat lng range .


func NewClusteringIndex() *ClusteringIndex {
	index := &ClusteringIndex{}
	index.streetLevel = NewPointsIndex(Km(0.5))
	index.cityLevel = NewCountIndex(Km(10))
	index.worldLevel = NewCountIndex(Km(500))

	return index
}

func NewClusteringIndex ( ) * ClusteringIndex { index := & ClusteringIndex { } index . streetLevel = NewPointsIndex ( Km ( 0.5 ) ) index . cityLevel = NewCountIndex ( Km ( 10 ) ) index . worldLevel = NewCountIndex ( Km ( 500 ) ) return index }

// NewClusteringIndex creates index that clusters the points at three levels with cell size 0.5, 5 and 500km.
// Useful for creating maps.

NewClusteringIndex creates index that clusters the points at three levels with cell size 0 . 5 5 and 500km . Useful for creating maps .


func NewExpiringClusteringIndex(expiration Minutes) *ClusteringIndex {
	index := &ClusteringIndex{}
	index.streetLevel = NewExpiringPointsIndex(Km(0.5), expiration)
	index.cityLevel = NewExpiringCountIndex(Km(10), expiration)
	index.worldLevel = NewExpiringCountIndex(Km(500), expiration)

	return index
}

func NewExpiringClusteringIndex ( expiration Minutes ) * ClusteringIndex { index := & ClusteringIndex { } index . streetLevel = NewExpiringPointsIndex ( Km ( 0.5 ) , expiration ) index . cityLevel = NewExpiringCountIndex ( Km ( 10 ) , expiration ) index . worldLevel = NewExpiringCountIndex ( Km ( 500 ) , expiration ) return index }

// NewExpiringClusteringIndex creates index that clusters the points at three levels with cell size 0.5, 5 and 500km and
// expires them after expiration minutes.

NewExpiringClusteringIndex creates index that clusters the points at three levels with cell size 0 . 5 5 and 500km and expires them after expiration minutes .


func (index *ClusteringIndex) Range(topLeft Point, bottomRight Point) []Point {
	dist := distance(topLeft, bottomRight)

	if dist < streetLevel {
		return index.streetLevel.Range(topLeft, bottomRight)
	} else if dist < cityLevel {
		return index.cityLevel.Range(topLeft, bottomRight)
	} else {
		return index.worldLevel.Range(topLeft, bottomRight)
	}
}

func ( index * ClusteringIndex ) Range ( topLeft Point , bottomRight Point ) [ ] Point { dist := distance ( topLeft , bottomRight ) if dist < streetLevel { return index . streetLevel . Range ( topLeft , bottomRight ) } else if dist < cityLevel { return index . cityLevel . Range ( topLeft , bottomRight ) } else { return index . worldLevel . Range ( topLeft , bottomRight ) } }

// Range returns points or count points depending on the size of the topLeft and bottomRight range.

Range returns points or count points depending on the size of the topLeft and bottomRight range .


func (index *ClusteringIndex) KNearest(point Point, k int, maxDistance Meters, accept func(p Point) bool) []Point {
	return index.streetLevel.KNearest(point, k, maxDistance, accept)
}

func ( index * ClusteringIndex ) KNearest ( point Point , k int , maxDistance Meters , accept func ( p Point ) bool ) [ ] Point { return index . streetLevel . KNearest ( point , k , maxDistance , accept ) }

// KNearest returns the K-Nearest points near point within maxDistance, that match the accept function.

KNearest returns the K - Nearest points near point within maxDistance that match the accept function .


func (queue *queue) Push(element interface{}) {
	if queue.size == queue.cap {
		queue.resize(queue.cap * 2)
	}

	queue.elements[queue.end%int64(queue.cap)] = element
	queue.end++
	queue.size++
}

func ( queue * queue ) Push ( element interface { } ) { if queue . size == queue . cap { queue . resize ( queue . cap * 2 ) } queue . elements [ queue . end % int64 ( queue . cap ) ] = element queue . end ++ queue . size ++ }

// Push adds an element at the end of the queue.

Push adds an element at the end of the queue .


func (queue *queue) Pop() interface{} {
	if queue.size == 0 {
		return nil
	}

	if queue.size < queue.cap/4 && queue.size > 4 {
		queue.resize(queue.cap / 2)
	}

	result := queue.elements[queue.start%int64(queue.cap)]
	queue.start++
	queue.size--

	return result
}

func ( queue * queue ) Pop ( ) interface { } { if queue . size == 0 { return nil } if queue . size < queue . cap / 4 && queue . size > 4 { queue . resize ( queue . cap / 2 ) } result := queue . elements [ queue . start % int64 ( queue . cap ) ] queue . start ++ queue . size -- return result }

// Pop removes an element from the front of the queue.

Pop removes an element from the front of the queue .


func (queue *queue) Peek() interface{} {
	if queue.size == 0 {
		return nil
	}
	return queue.elements[queue.start%int64(queue.cap)]
}

func ( queue * queue ) Peek ( ) interface { } { if queue . size == 0 { return nil } return queue . elements [ queue . start % int64 ( queue . cap ) ] }

// Peek returns the element at the front of the queue.

Peek returns the element at the front of the queue .


func (queue *queue) PeekBack() interface{} {
	if queue.size == 0 {
		return nil
	}

	return queue.elements[(queue.end-1)%int64(queue.cap)]
}

func ( queue * queue ) PeekBack ( ) interface { } { if queue . size == 0 { return nil } return queue . elements [ ( queue . end - 1 ) % int64 ( queue . cap ) ] }

// PeekBack returns the element at the back of the queue.

PeekBack returns the element at the back of the queue .


func (queue *queue) ForEach(process func(interface{})) {
	for i := queue.start; i < queue.end; i++ {
		process(queue.elements[i%int64(queue.cap)])
	}
}

func ( queue * queue ) ForEach ( process func ( interface { } ) ) { for i := queue . start ; i < queue . end ; i ++ { process ( queue . elements [ i % int64 ( queue . cap ) ] ) } }

// ForEach calls process for each element in the queue.

ForEach calls process for each element in the queue .


func (set basicSet) Clone() set {
	clone := basicSet(make(map[string]interface{}))
	for k, v := range set {
		clone[k] = v
	}

	return clone
}

func ( set basicSet ) Clone ( ) set { clone := basicSet ( make ( map [ string ] interface { } ) ) for k , v := range set { clone [ k ] = v } return clone }

// Clone creates a copy of the set where the values in clone set point to the same underlying reference as the original set


func NewCountIndex(resolution Meters) *CountIndex {
	newCounter := func() interface{} {
		return &singleValueAccumulatingCounter{}
	}

	return &CountIndex{newGeoIndex(resolution, newCounter), make(map[string]Point)}
}

func NewCountIndex ( resolution Meters ) * CountIndex { newCounter := func ( ) interface { } { return & singleValueAccumulatingCounter { } } return & CountIndex { newGeoIndex ( resolution , newCounter ) , make ( map [ string ] Point ) } }

// NewCountIndex creates an index which counts the points in each cell.

NewCountIndex creates an index which counts the points in each cell .


func NewExpiringCountIndex(resolution Meters, expiration Minutes) *CountIndex {
	newExpiringCounter := func() interface{} {
		return newExpiringCounter(expiration)
	}

	return &CountIndex{newGeoIndex(resolution, newExpiringCounter), make(map[string]Point)}
}

func NewExpiringCountIndex ( resolution Meters , expiration Minutes ) * CountIndex { newExpiringCounter := func ( ) interface { } { return newExpiringCounter ( expiration ) } return & CountIndex { newGeoIndex ( resolution , newExpiringCounter ) , make ( map [ string ] Point ) } }

// NewExpiringCountIndex creates an index, which maintains an expiring counter for each cell.

NewExpiringCountIndex creates an index which maintains an expiring counter for each cell .


func (countIndex *CountIndex) Range(topLeft Point, bottomRight Point) []Point {
	counters := countIndex.index.Range(topLeft, bottomRight)

	points := make([]Point, 0)

	for _, c := range counters {
		if c.(counter).Point() != nil {
			points = append(points, c.(counter).Point())
		}
	}

	return points
}

func ( countIndex * CountIndex ) Range ( topLeft Point , bottomRight Point ) [ ] Point { counters := countIndex . index . Range ( topLeft , bottomRight ) points := make ( [ ] Point , 0 ) for _ , c := range counters { if c . ( counter ) . Point ( ) != nil { points = append ( points , c . ( counter ) . Point ( ) ) } } return points }

// Range returns the counters within some lat, lng range.

Range returns the counters within some lat lng range .


func (index *CountIndex) KNearest(point Point, k int, maxDistance Meters, accept func(p Point) bool) []Point {
	panic("Unsupported operation")
}

func ( index * CountIndex ) KNearest ( point Point , k int , maxDistance Meters , accept func ( p Point ) bool ) [ ] Point { panic ( " " ) }

// KNearest just to satisfy an interface. Doesn't make much sense for count index.

KNearest just to satisfy an interface . Doesn t make much sense for count index .


func DirectionTo(p1, p2 Point) Direction {
	bearing := BearingTo(p1, p2)

	index := bearing - 22.5

	if index < 0 {
		index += 360
	}
	indexInt := int(index / 45.0)

	return Direction(indexInt)
}

func DirectionTo ( p1 , p2 Point ) Direction { bearing := BearingTo ( p1 , p2 ) index := bearing - 22.5 if index < 0 { index += 360 } indexInt := int ( index / 45.0 ) return Direction ( indexInt ) }

// DirectionTo returns the direction from p1 to p2


func BearingTo(p1, p2 Point) float64 {
	dLon := toRadians(p2.Lon() - p1.Lon())

	lat1 := toRadians(p1.Lat())
	lat2 := toRadians(p2.Lat())

	y := math.Sin(dLon) * math.Cos(lat2)
	x := math.Cos(lat1)*math.Sin(lat2) -
		math.Sin(lat1)*math.Cos(lat2)*math.Cos(dLon)
	brng := toDegrees(math.Atan2(y, x))

	return brng
}

func BearingTo ( p1 , p2 Point ) float64 { dLon := toRadians ( p2 . Lon ( ) - p1 . Lon ( ) ) lat1 := toRadians ( p1 . Lat ( ) ) lat2 := toRadians ( p2 . Lat ( ) ) y := math . Sin ( dLon ) * math . Cos ( lat2 ) x := math . Cos ( lat1 ) * math . Sin ( lat2 ) - math . Sin ( lat1 ) * math . Cos ( lat2 ) * math . Cos ( dLon ) brng := toDegrees ( math . Atan2 ( y , x ) ) return brng }

// BearingTo returns the bearing from p1 to p2


func approximateSquareDistance(p1, p2 Point) Meters {
	avgLat := (p1.Lat() + p2.Lat()) / 2.0

	latLen := math.Abs(p1.Lat()-p2.Lat()) * float64(latDegreeLength)
	lonLen := math.Abs(p1.Lon()-p2.Lon()) * float64(lonLength.get(avgLat))

	return Meters(latLen*latLen + lonLen*lonLen)
}

func approximateSquareDistance ( p1 , p2 Point ) Meters { avgLat := ( p1 . Lat ( ) + p2 . Lat ( ) ) / 2.0 latLen := math . Abs ( p1 . Lat ( ) - p2 . Lat ( ) ) * float64 ( latDegreeLength ) lonLen := math . Abs ( p1 . Lon ( ) - p2 . Lon ( ) ) * float64 ( lonLength . get ( avgLat ) ) return Meters ( latLen * latLen + lonLen * lonLen ) }

// Calculates approximate distance between two points using euclidian distance. The assumption here
// is that the points are relatively close to each other.

Calculates approximate distance between two points using euclidian distance . The assumption here is that the points are relatively close to each other .


func newResult(base []element, inner []element, includes map[string][]element) *result {
	return &result{
		base:     base,
		inner:    inner,
		includes: includes,
	}
}

func newResult ( base [ ] element , inner [ ] element , includes map [ string ] [ ] element ) * result { return & result { base : base , inner : inner , includes : includes , } }

// newResult creates and returns a result.

newResult creates and returns a result .


func NewSource(base, inner *File, includes []*File) *source {
	return &source{
		base:     base,
		inner:    inner,
		includes: includes,
	}
}

func NewSource ( base , inner * File , includes [ ] * File ) * source { return & source { base : base , inner : inner , includes : includes , } }

// NewSource creates and returns source.


func newHelperMethodYield(ln *line, rslt *result, src *source, parent element, opts *Options) (*helperMethodYield, error) {
	if len(ln.tokens) < 3 {
		return nil, fmt.Errorf("no template name is specified [file: %s][line: %d]", ln.fileName(), ln.no)
	}

	e := &helperMethodYield{
		elementBase:  newElementBase(ln, rslt, src, parent, opts),
		templateName: ln.tokens[2],
	}

	return e, nil
}

func newHelperMethodYield ( ln * line , rslt * result , src * source , parent element , opts * Options ) ( * helperMethodYield , error ) { if len ( ln . tokens ) < 3 { return nil , fmt . Errorf ( " " , ln . fileName ( ) , ln . no ) } e := & helperMethodYield { elementBase : newElementBase ( ln , rslt , src , parent , opts ) , templateName : ln . tokens [ 2 ] , } return e , nil }

// newHelperMethodYield creates and returns a helper method yield.

newHelperMethodYield creates and returns a helper method yield .


func newHelperMethodDoctype(ln *line, rslt *result, src *source, parent element, opts *Options) (*helperMethodDoctype, error) {
	if len(ln.tokens) < 3 {
		return nil, fmt.Errorf("doctype is not specified [file: %s][line: %d]", ln.fileName(), ln.no)
	}

	doctype := ln.tokens[2]

	if _, ok := doctypes[doctype]; !ok {
		return nil, fmt.Errorf("doctype is invalid [file: %s][line: %d][doctype: %s]", ln.fileName(), ln.no, doctype)
	}

	e := &helperMethodDoctype{
		elementBase: newElementBase(ln, rslt, src, parent, opts),
		doctype:     doctype,
	}

	return e, nil
}

func newHelperMethodDoctype ( ln * line , rslt * result , src * source , parent element , opts * Options ) ( * helperMethodDoctype , error ) { if len ( ln . tokens ) < 3 { return nil , fmt . Errorf ( " " , ln . fileName ( ) , ln . no ) } doctype := ln . tokens [ 2 ] if _ , ok := doctypes [ doctype ] ; ! ok { return nil , fmt . Errorf ( " " , ln . fileName ( ) , ln . no , doctype ) } e := & helperMethodDoctype { elementBase : newElementBase ( ln , rslt , src , parent , opts ) , doctype : doctype , } return e , nil }

// newHelperMethodDoctype creates and returns a helper method doctype.

newHelperMethodDoctype creates and returns a helper method doctype .


func NewFile(path string, data []byte) *File {
	return &File{
		path: path,
		data: data,
	}
}

func NewFile ( path string , data [ ] byte ) * File { return & File { path : path , data : data , } }


func Load(basePath, innerPath string, opts *Options) (*template.Template, error) {
	// Initialize the options.
	opts = InitializeOptions(opts)

	name := basePath + colon + innerPath

	if !opts.DynamicReload {
		if tpl, ok := getCache(name); ok {
			return &tpl, nil
		}
	}

	// Read files.
	src, err := readFiles(basePath, innerPath, opts)
	if err != nil {
		return nil, err
	}

	// Parse the source.
	rslt, err := ParseSource(src, opts)
	if err != nil {
		return nil, err
	}

	// Compile the parsed result.
	tpl, err := CompileResult(name, rslt, opts)
	if err != nil {
		return nil, err
	}

	if !opts.DynamicReload {
		setCache(name, *tpl)
	}

	return tpl, nil
}

func
Load
(
basePath
,
innerPath
string
,
opts
*
Options
)
(
*
template
.
Template
,
error
)
{
// Initialize the options.
opts
=
InitializeOptions
(
opts
)
name
:=
basePath
+
colon
+
innerPath
if
!
opts
.
DynamicReload
{
if
tpl
,
ok
:=
getCache
(
name
)
;
ok
{
return
&
tpl
,
}
}
// Read files.
src
,
err
:=
readFiles
(
basePath
,
innerPath
,
opts
)
if
err
!=
{
return
,
err
}
// Parse the source.
rslt
,
err
:=
ParseSource
(
src
,
opts
)
if
err
!=
{
return
,
err
}
// Compile the parsed result.
tpl
,
err
:=
CompileResult
(
name
,
rslt
,
opts
)
if
err
!=
{
return
,
err
}
if
!
opts
.
DynamicReload
{
setCache
(
name
,
*
tpl
)
}
return
tpl
,
}

// Load loads and returns an HTML template. Each Ace templates are parsed only once
// and cached if the "DynamicReload" option are not set.

Load loads and returns an HTML template . Each Ace templates are parsed only once and cached if the DynamicReload option are not set .


func getCache(name string) (template.Template, bool) {
	cacheMutex.RLock()
	tpl, ok := cache[name]
	cacheMutex.RUnlock()
	return tpl, ok
}

func getCache ( name string ) ( template . Template , bool ) { cacheMutex . RLock ( ) tpl , ok := cache [ name ] cacheMutex . RUnlock ( ) return tpl , ok }

// getCache returns the cached template.


func setCache(name string, tpl template.Template) {
	cacheMutex.Lock()
	cache[name] = tpl
	cacheMutex.Unlock()
}

func setCache ( name string , tpl template . Template ) { cacheMutex . Lock ( ) cache [ name ] = tpl cacheMutex . Unlock ( ) }

// setCache sets the template to the cache.

setCache sets the template to the cache .


func FlushCache() {
	cacheMutex.Lock()
	cache = make(map[string]template.Template)
	cacheMutex.Unlock()
}

func FlushCache ( ) { cacheMutex . Lock ( ) cache = make ( map [ string ] template . Template ) cacheMutex . Unlock ( ) }

// FlushCache clears all cached templates.

FlushCache clears all cached templates .


func newPlainTextInner(ln *line, rslt *result, src *source, parent element, insertBr bool, opts *Options) *plainTextInner {
	return &plainTextInner{
		elementBase: newElementBase(ln, rslt, src, parent, opts),
		insertBr:    insertBr,
	}
}

func newPlainTextInner ( ln * line , rslt * result , src * source , parent element , insertBr bool , opts * Options ) * plainTextInner { return & plainTextInner { elementBase : newElementBase ( ln , rslt , src , parent , opts ) , insertBr : insertBr , } }

// newPlainTextInner creates and returns a plain text.

newPlainTextInner creates and returns a plain text .


func newEmptyElement(ln *line, rslt *result, src *source, parent element, opts *Options) *emptyElement {
	return &emptyElement{
		elementBase: newElementBase(ln, rslt, src, parent, opts),
	}
}

func newEmptyElement ( ln * line , rslt * result , src * source , parent element , opts * Options ) * emptyElement { return & emptyElement { elementBase : newElementBase ( ln , rslt , src , parent , opts ) , } }

// newEmpty creates and returns an empty element.

newEmpty creates and returns an empty element .


func newComment(ln *line, rslt *result, src *source, parent element, opts *Options) *comment {
	return &comment{
		elementBase: newElementBase(ln, rslt, src, parent, opts),
	}
}

func newComment ( ln * line , rslt * result , src * source , parent element , opts * Options ) * comment { return & comment { elementBase : newElementBase ( ln , rslt , src , parent , opts ) , } }

// newComment creates and returns a comment.

newComment creates and returns a comment .


func newHelperMethodJavascript(ln *line, rslt *result, src *source, parent element, opts *Options) *helperMethodJavascript {
	return &helperMethodJavascript{
		elementBase: newElementBase(ln, rslt, src, parent, opts),
	}
}

func newHelperMethodJavascript ( ln * line , rslt * result , src * source , parent element , opts * Options ) * helperMethodJavascript { return & helperMethodJavascript { elementBase : newElementBase ( ln , rslt , src , parent , opts ) , } }

// helperMethodJavascript creates and returns a helper method javascript.

helperMethodJavascript creates and returns a helper method javascript .


func ParseSource(src *source, opts *Options) (*result, error) {
	// Initialize the options.
	opts = InitializeOptions(opts)

	rslt := newResult(nil, nil, nil)

	base, err := parseBytes(src.base.data, rslt, src, opts, src.base)
	if err != nil {
		return nil, err
	}

	inner, err := parseBytes(src.inner.data, rslt, src, opts, src.inner)
	if err != nil {
		return nil, err
	}

	includes := make(map[string][]element)

	for _, f := range src.includes {
		includes[f.path], err = parseBytes(f.data, rslt, src, opts, f)
		if err != nil {
			return nil, err
		}
	}

	rslt.base = base
	rslt.inner = inner
	rslt.includes = includes

	return rslt, nil
}

func
ParseSource
(
src
*
source
,
opts
*
Options
)
(
*
result
,
error
)
{
// Initialize the options.
opts
=
InitializeOptions
(
opts
)
rslt
:=
newResult
(
,
,
)
base
,
err
:=
parseBytes
(
src
.
base
.
data
,
rslt
,
src
,
opts
,
src
.
base
)
if
err
!=
{
return
,
err
}
inner
,
err
:=
parseBytes
(
src
.
inner
.
data
,
rslt
,
src
,
opts
,
src
.
inner
)
if
err
!=
{
return
,
err
}
includes
:=
make
(
map
[
string
]
[
]
element
)
for
_
,
f
:=
range
src
.
includes
{
includes
[
f
.
path
]
,
err
=
parseBytes
(
f
.
data
,
rslt
,
src
,
opts
,
f
)
if
err
!=
{
return
,
err
}
}
rslt
.
base
=
base
rslt
.
inner
=
inner
rslt
.
includes
=
includes
return
rslt
,
}

// ParseSource parses the source and returns the result.

ParseSource parses the source and returns the result .


func parseBytes(data []byte, rslt *result, src *source, opts *Options, f *File) ([]element, error) {
	var elements []element

	lines := strings.Split(formatLF(string(data)), lf)

	i := 0
	l := len(lines)

	// Ignore the last empty line.
	if l > 0 && lines[l-1] == "" {
		l--
	}

	for i < l {
		// Fetch a line.
		ln := newLine(i+1, lines[i], opts, f)
		i++

		// Ignore the empty line.
		if ln.isEmpty() {
			continue
		}

		if ln.isTopIndent() {
			e, err := newElement(ln, rslt, src, nil, opts)
			if err != nil {
				return nil, err
			}

			// Append child elements to the element.
			if err := appendChildren(e, rslt, lines, &i, l, src, opts, f); err != nil {
				return nil, err
			}

			elements = append(elements, e)
		}
	}

	return elements, nil
}

// parseBytes parses the byte data and returns the elements.

parseBytes parses the byte data and returns the elements .


func appendChildren(parent element, rslt *result, lines []string, i *int, l int, src *source, opts *Options, f *File) error {
	for *i < l {
		// Fetch a line.
		ln := newLine(*i+1, lines[*i], opts, f)

		// Check if the line is a child of the parent.
		ok, err := ln.childOf(parent)

		if err != nil {
			return err
		}

		if !ok {
			return nil
		}

		child, err := newElement(ln, rslt, src, parent, opts)
		if err != nil {
			return err
		}

		parent.AppendChild(child)

		*i++

		if child.CanHaveChildren() {
			if err := appendChildren(child, rslt, lines, i, l, src, opts, f); err != nil {
				return err
			}
		}
	}

	return nil
}

// appendChildren parses the lines and appends the children to the element.

appendChildren parses the lines and appends the children to the element .


func newHTMLComment(ln *line, rslt *result, src *source, parent element, opts *Options) *htmlComment {
	return &htmlComment{
		elementBase: newElementBase(ln, rslt, src, parent, opts),
	}
}

func newHTMLComment ( ln * line , rslt * result , src * source , parent element , opts * Options ) * htmlComment { return & htmlComment { elementBase : newElementBase ( ln , rslt , src , parent , opts ) , } }

// newHTMLComment creates and returns an HTML comment.

newHTMLComment creates and returns an HTML comment .


func newHelperMethodInclude(ln *line, rslt *result, src *source, parent element, opts *Options) (*helperMethodInclude, error) {
	if len(ln.tokens) < 3 {
		return nil, fmt.Errorf("no template name is specified [file: %s][line: %d]", ln.fileName(), ln.no)
	}

	var pipeline string

	if len(ln.tokens) > 3 {
		pipeline = strings.Join(ln.tokens[3:], space)
	}

	e := &helperMethodInclude{
		elementBase:  newElementBase(ln, rslt, src, parent, opts),
		templateName: ln.tokens[2],
		pipeline:     pipeline,
	}

	return e, nil
}

func newHelperMethodInclude ( ln * line , rslt * result , src * source , parent element , opts * Options ) ( * helperMethodInclude , error ) { if len ( ln . tokens ) < 3 { return nil , fmt . Errorf ( " " , ln . fileName ( ) , ln . no ) } var pipeline string if len ( ln . tokens ) > 3 { pipeline = strings . Join ( ln . tokens [ 3 : ] , space ) } e := & helperMethodInclude { elementBase : newElementBase ( ln , rslt , src , parent , opts ) , templateName : ln . tokens [ 2 ] , pipeline : pipeline , } return e , nil }

// newHelperMethodInclude creates and returns a helper method include.

newHelperMethodInclude creates and returns a helper method include .


func newHelperMethodConditionalComment(ln *line, rslt *result, src *source, parent element, opts *Options) (*helperMethodConditionalComment, error) {
	switch len(ln.tokens) {
	case 2:
		return nil, fmt.Errorf("no comment type is specified [file: %s][line: %d]", ln.fileName(), ln.no)
	case 3:
		return nil, fmt.Errorf("no condition is specified [file: %s][line: %d]", ln.fileName(), ln.no)
	}

	commentType := ln.tokens[2]

	if commentType != commentTypeHidden && commentType != commentTypeRevealed {
		return nil, fmt.Errorf("the comment type is invalid [file: %s][line: %d]", ln.fileName(), ln.no)
	}

	e := &helperMethodConditionalComment{
		elementBase: newElementBase(ln, rslt, src, parent, opts),
		commentType: commentType,
		condition:   strings.Join(ln.tokens[3:], space),
	}

	return e, nil
}

func newHelperMethodConditionalComment ( ln * line , rslt * result , src * source , parent element , opts * Options ) ( * helperMethodConditionalComment , error ) { switch len ( ln . tokens ) { case 2 : return nil , fmt . Errorf ( " " , ln . fileName ( ) , ln . no ) case 3 : return nil , fmt . Errorf ( " " , ln . fileName ( ) , ln . no ) } commentType := ln . tokens [ 2 ] if commentType != commentTypeHidden && commentType != commentTypeRevealed { return nil , fmt . Errorf ( " " , ln . fileName ( ) , ln . no ) } e := & helperMethodConditionalComment { elementBase : newElementBase ( ln , rslt , src , parent , opts ) , commentType : commentType , condition : strings . Join ( ln . tokens [ 3 : ] , space ) , } return e , nil }

// newHelperMethodConditionalComment creates and returns an HTML comment.

newHelperMethodConditionalComment creates and returns an HTML comment .


func CompileResult(name string, rslt *result, opts *Options) (*template.Template, error) {
	// Initialize the options.
	opts = InitializeOptions(opts)

	// Create a template.
	t := template.New(name)

	return CompileResultWithTemplate(t, rslt, opts)
}

func
CompileResult
(
name
string
,
rslt
*
result
,
opts
*
Options
)
(
*
template
.
Template
,
error
)
{
// Initialize the options.
opts
=
InitializeOptions
(
opts
)
// Create a template.
t
:=
template
.
New
(
name
)
return
CompileResultWithTemplate
(
t
,
rslt
,
opts
)
}

// CompileResult compiles the parsed result to the template.Template.

CompileResult compiles the parsed result to the template . Template .


func CompileResultWithTemplate(t *template.Template, rslt *result, opts *Options) (*template.Template, error) {
	// Initialize the options.
	opts = InitializeOptions(opts)

	var err error

	// Create a buffer.
	baseBf := bytes.NewBuffer(nil)
	innerBf := bytes.NewBuffer(nil)
	includeBfs := make(map[string]*bytes.Buffer)

	// Write data to the buffer.
	for _, e := range rslt.base {
		if _, err := e.WriteTo(baseBf); err != nil {
			return nil, err
		}
	}

	for _, e := range rslt.inner {
		if _, err = e.WriteTo(innerBf); err != nil {
			return nil, err
		}
	}

	for path, elements := range rslt.includes {
		bf := bytes.NewBuffer(nil)

		// Write a define action.
		bf.WriteString(fmt.Sprintf(actionDefine, opts.DelimLeft, path, opts.DelimRight))

		for _, e := range elements {
			if _, err = e.WriteTo(bf); err != nil {
				return nil, err
			}
		}

		// Write an end action.
		bf.WriteString(fmt.Sprintf(actionEnd, opts.DelimLeft, opts.DelimRight))

		includeBfs[path] = bf
	}

	// Set Delimiters.
	t.Delims(opts.DelimLeft, opts.DelimRight)

	// Set FuncMaps.
	t.Funcs(template.FuncMap{
		preDefinedFuncNameHTML: func(s string) template.HTML {
			return template.HTML(s)
		},
	})

	t.Funcs(opts.FuncMap)

	// Parse a string to the template.
	t, err = t.Parse(baseBf.String())
	if err != nil {
		return nil, err
	}

	t, err = t.Parse(innerBf.String())
	if err != nil {
		return nil, err
	}

	for _, bf := range includeBfs {
		t, err = t.Parse(bf.String())
		if err != nil {
			return nil, err
		}
	}

	return t, nil
}

func
CompileResultWithTemplate
(
t
*
template
.
Template
,
rslt
*
result
,
opts
*
Options
)
(
*
template
.
Template
,
error
)
{
// Initialize the options.
opts
=
InitializeOptions
(
opts
)
var
err
error
// Create a buffer.
baseBf
:=
bytes
.
NewBuffer
(
)
innerBf
:=
bytes
.
NewBuffer
(
)
includeBfs
:=
make
(
map
[
string
]
*
bytes
.
Buffer
)
// Write data to the buffer.
for
_
,
e
:=
range
rslt
.
base
{
if
_
,
err
:=
e
.
WriteTo
(
baseBf
)
;
err
!=
{
return
,
err
}
}
for
_
,
e
:=
range
rslt
.
inner
{
if
_
,
err
=
e
.
WriteTo
(
innerBf
)
;
err
!=
{
return
,
err
}
}
for
path
,
elements
:=
range
rslt
.
includes
{
bf
:=
bytes
.
NewBuffer
(
)
// Write a define action.
bf
.
WriteString
(
fmt
.
Sprintf
(
actionDefine
,
opts
.
DelimLeft
,
path
,
opts
.
DelimRight
)
)
for
_
,
e
:=
range
elements
{
if
_
,
err
=
e
.
WriteTo
(
bf
)
;
err
!=
{
return
,
err
}
}
// Write an end action.
bf
.
WriteString
(
fmt
.
Sprintf
(
actionEnd
,
opts
.
DelimLeft
,
opts
.
DelimRight
)
)
includeBfs
[
path
]
=
bf
}
// Set Delimiters.
t
.
Delims
(
opts
.
DelimLeft
,
opts
.
DelimRight
)
// Set FuncMaps.
t
.
Funcs
(
template
.
FuncMap
{
preDefinedFuncNameHTML
:
func
(
s
string
)
template
.
HTML
{
return
template
.
HTML
(
s
)
}
,
}
)
t
.
Funcs
(
opts
.
FuncMap
)
// Parse a string to the template.
t
,
err
=
t
.
Parse
(
baseBf
.
String
(
)
)
if
err
!=
{
return
,
err
}
t
,
err
=
t
.
Parse
(
innerBf
.
String
(
)
)
if
err
!=
{
return
,
err
}
for
_
,
bf
:=
range
includeBfs
{
t
,
err
=
t
.
Parse
(
bf
.
String
(
)
)
if
err
!=
{
return
,
err
}
}
return
t
,
}

// CompileResultWithTemplate compiles the parsed result and associates it with t.

CompileResultWithTemplate compiles the parsed result and associates it with t .


func (e *elementBase) AppendChild(child element) {
	e.children = append(e.children, child)
}

func ( e * elementBase ) AppendChild ( child element ) { e . children = append ( e . children , child ) }

// AppendChild appends the child element to the element.

AppendChild appends the child element to the element .


func (e *elementBase) writeChildren(bf *bytes.Buffer) (int64, error) {
	l := len(e.children)
	for index, child := range e.children {
		if index == l-1 {
			child.SetLastChild(true)
		}

		if e.opts.formatter != nil {
			if i, err := e.opts.formatter.OpeningElement(bf, child); err != nil {
				return int64(i), err
			}
		}
		if i, err := child.WriteTo(bf); err != nil {
			return int64(i), err
		}
	}
	return 0, nil
}

func ( e * elementBase ) writeChildren ( bf * bytes . Buffer ) ( int64 , error ) { l := len ( e . children ) for index , child := range e . children { if index == l - 1 { child . SetLastChild ( true ) } if e . opts . formatter != nil { if i , err := e . opts . formatter . OpeningElement ( bf , child ) ; err != nil { return int64 ( i ) , err } } if i , err := child . WriteTo ( bf ) ; err != nil { return int64 ( i ) , err } } return 0 , nil }

// writeChildren writes the children's HTML.

writeChildren writes the children s HTML .


func newElementBase(ln *line, rslt *result, src *source, parent element, opts *Options) elementBase {
	return elementBase{
		ln:     ln,
		rslt:   rslt,
		src:    src,
		parent: parent,
		opts:   opts,
	}
}

func newElementBase ( ln * line , rslt * result , src * source , parent element , opts * Options ) elementBase { return elementBase { ln : ln , rslt : rslt , src : src , parent : parent , opts : opts , } }

// newElementBase creates and returns an element base.

newElementBase creates and returns an element base .


func readFiles(basePath, innerPath string, opts *Options) (*source, error) {
	// Read the base file.
	base, err := readFile(basePath, opts)
	if err != nil {
		return nil, err
	}

	// Read the inner file.
	inner, err := readFile(innerPath, opts)
	if err != nil {
		return nil, err
	}

	var includes []*File

	// Find include files from the base file.
	if err := findIncludes(base.data, opts, &includes, base); err != nil {
		return nil, err
	}

	// Find include files from the inner file.
	if err := findIncludes(inner.data, opts, &includes, inner); err != nil {
		return nil, err
	}

	return NewSource(base, inner, includes), nil
}

// readFiles reads files and returns source for the parsing process.

readFiles reads files and returns source for the parsing process .


func readFile(path string, opts *Options) (*File, error) {
	var data []byte
	var err error

	if path != "" {
		name := filepath.Join(opts.BaseDir, path+dot+opts.Extension)

		if opts.Asset != nil {
			data, err = opts.Asset(name)
		} else {
			data, err = ioutil.ReadFile(name)
		}

		if err != nil {
			return nil, err
		}
	}

	return NewFile(path, data), nil
}

func readFile ( path string , opts * Options ) ( * File , error ) { var data [ ] byte var err error if path != " " { name := filepath . Join ( opts . BaseDir , path + dot + opts . Extension ) if opts . Asset != nil { data , err = opts . Asset ( name ) } else { data , err = ioutil . ReadFile ( name ) } if err != nil { return nil , err } } return NewFile ( path , data ) , nil }

// readFile reads a file and returns a file struct.

readFile reads a file and returns a file struct .


func findIncludes(data []byte, opts *Options, includes *[]*File, targetFile *File) error {
	includePaths, err := findIncludePaths(data, opts, targetFile)
	if err != nil {
		return err
	}

	for _, includePath := range includePaths {
		if !hasFile(*includes, includePath) {
			f, err := readFile(includePath, opts)
			if err != nil {
				return err
			}

			*includes = append(*includes, f)

			if err := findIncludes(f.data, opts, includes, f); err != nil {
				return err
			}
		}
	}

	return nil
}

func findIncludes ( data [ ] byte , opts * Options , includes * [ ] * File , targetFile * File ) error { includePaths , err := findIncludePaths ( data , opts , targetFile ) if err != nil { return err } for _ , includePath := range includePaths { if ! hasFile ( * includes , includePath ) { f , err := readFile ( includePath , opts ) if err != nil { return err } * includes = append ( * includes , f ) if err := findIncludes ( f . data , opts , includes , f ) ; err != nil { return err } } } return nil }

// findIncludes finds and adds include files.

findIncludes finds and adds include files .


func findIncludePaths(data []byte, opts *Options, f *File) ([]string, error) {
	var includePaths []string

	for i, str := range strings.Split(formatLF(string(data)), lf) {
		ln := newLine(i+1, str, opts, f)

		if ln.isHelperMethodOf(helperMethodNameInclude) {
			if len(ln.tokens) < 3 {
				return nil, fmt.Errorf("no template name is specified [file: %s][line: %d]", ln.fileName(), ln.no)
			}

			includePaths = append(includePaths, ln.tokens[2])
		}
	}

	return includePaths, nil
}

func findIncludePaths ( data [ ] byte , opts * Options , f * File ) ( [ ] string , error ) { var includePaths [ ] string for i , str := range strings . Split ( formatLF ( string ( data ) ) , lf ) { ln := newLine ( i + 1 , str , opts , f ) if ln . isHelperMethodOf ( helperMethodNameInclude ) { if len ( ln . tokens ) < 3 { return nil , fmt . Errorf ( " " , ln . fileName ( ) , ln . no ) } includePaths = append ( includePaths , ln . tokens [ 2 ] ) } } return includePaths , nil }

// findIncludePaths finds and returns include paths.

findIncludePaths finds and returns include paths .


func hasFile(files []*File, path string) bool {
	for _, f := range files {
		if f.path == path {
			return true
		}
	}

	return false
}

func hasFile ( files [ ] * File , path string ) bool { for _ , f := range files { if f . path == path { return true } } return false }

// hasFile return if files has a file which has the path specified by the parameter.

hasFile return if files has a file which has the path specified by the parameter .


func newHelperMethodCSS(ln *line, rslt *result, src *source, parent element, opts *Options) *helperMethodCSS {
	return &helperMethodCSS{
		elementBase: newElementBase(ln, rslt, src, parent, opts),
	}
}

func newHelperMethodCSS ( ln * line , rslt * result , src * source , parent element , opts * Options ) * helperMethodCSS { return & helperMethodCSS { elementBase : newElementBase ( ln , rslt , src , parent , opts ) , } }

// helperMethodCSS creates and returns a helper method css.

helperMethodCSS creates and returns a helper method css .


func newElement(ln *line, rslt *result, src *source, parent element, opts *Options) (element, error) {
	var e element
	var err error

	switch {
	case parent != nil && parent.ContainPlainText():
		e = newPlainTextInner(ln, rslt, src, parent, parent.InsertBr(), opts)
	case ln.isEmpty():
		e = newEmptyElement(ln, rslt, src, parent, opts)
	case ln.isComment():
		e = newComment(ln, rslt, src, parent, opts)
	case ln.isHTMLComment():
		e = newHTMLComment(ln, rslt, src, parent, opts)
	case ln.isHelperMethod():
		switch {
		case ln.isHelperMethodOf(helperMethodNameConditionalComment):
			e, err = newHelperMethodConditionalComment(ln, rslt, src, parent, opts)
		case ln.isHelperMethodOf(helperMethodNameContent):
			e, err = newHelperMethodContent(ln, rslt, src, parent, opts)
		case ln.isHelperMethodOf(helperMethodNameCSS):
			e = newHelperMethodCSS(ln, rslt, src, parent, opts)
		case ln.isHelperMethodOf(helperMethodNameDoctype):
			e, err = newHelperMethodDoctype(ln, rslt, src, parent, opts)
		case ln.isHelperMethodOf(helperMethodNameInclude):
			e, err = newHelperMethodInclude(ln, rslt, src, parent, opts)
		case ln.isHelperMethodOf(helperMethodNameJavascript):
			e = newHelperMethodJavascript(ln, rslt, src, parent, opts)
		case ln.isHelperMethodOf(helperMethodNameYield):
			e, err = newHelperMethodYield(ln, rslt, src, parent, opts)
		default:
			err = fmt.Errorf("the helper method name is invalid [file: %s][line: %d]", ln.fileName(), ln.no)
		}
	case ln.isPlainText():
		e = newPlainText(ln, rslt, src, parent, opts)
	case ln.isAction():
		e = newAction(ln, rslt, src, parent, opts)
	default:
		e, err = newHTMLTag(ln, rslt, src, parent, opts)
	}

	return e, err
}

func newElement ( ln * line , rslt * result , src * source , parent element , opts * Options ) ( element , error ) { var e element var err error switch { case parent != nil && parent . ContainPlainText ( ) : e = newPlainTextInner ( ln , rslt , src , parent , parent . InsertBr ( ) , opts ) case ln . isEmpty ( ) : e = newEmptyElement ( ln , rslt , src , parent , opts ) case ln . isComment ( ) : e = newComment ( ln , rslt , src , parent , opts ) case ln . isHTMLComment ( ) : e = newHTMLComment ( ln , rslt , src , parent , opts ) case ln . isHelperMethod ( ) : switch { case ln . isHelperMethodOf ( helperMethodNameConditionalComment ) : e , err = newHelperMethodConditionalComment ( ln , rslt , src , parent , opts ) case ln . isHelperMethodOf ( helperMethodNameContent ) : e , err = newHelperMethodContent ( ln , rslt , src , parent , opts ) case ln . isHelperMethodOf ( helperMethodNameCSS ) : e = newHelperMethodCSS ( ln , rslt , src , parent , opts ) case ln . isHelperMethodOf ( helperMethodNameDoctype ) : e , err = newHelperMethodDoctype ( ln , rslt , src , parent , opts ) case ln . isHelperMethodOf ( helperMethodNameInclude ) : e , err = newHelperMethodInclude ( ln , rslt , src , parent , opts ) case ln . isHelperMethodOf ( helperMethodNameJavascript ) : e = newHelperMethodJavascript ( ln , rslt , src , parent , opts ) case ln . isHelperMethodOf ( helperMethodNameYield ) : e , err = newHelperMethodYield ( ln , rslt , src , parent , opts ) default : err = fmt . Errorf ( " " , ln . fileName ( ) , ln . no ) } case ln . isPlainText ( ) : e = newPlainText ( ln , rslt , src , parent , opts ) case ln . isAction ( ) : e = newAction ( ln , rslt , src , parent , opts ) default : e , err = newHTMLTag ( ln , rslt , src , parent , opts ) } return e , err }

// newElement creates and returns an element.

newElement creates and returns an element .


func newHelperMethodContent(ln *line, rslt *result, src *source, parent element, opts *Options) (*helperMethodContent, error) {
	if len(ln.tokens) < 3 || ln.tokens[2] == "" {
		return nil, fmt.Errorf("no name is specified [file: %s][line: %d]", ln.fileName(), ln.no)
	}

	e := &helperMethodContent{
		elementBase: newElementBase(ln, rslt, src, parent, opts),
		name:        ln.tokens[2],
	}

	return e, nil
}

func newHelperMethodContent ( ln * line , rslt * result , src * source , parent element , opts * Options ) ( * helperMethodContent , error ) { if len ( ln . tokens ) < 3 || ln . tokens [ 2 ] == " " { return nil , fmt . Errorf ( " " , ln . fileName ( ) , ln . no ) } e := & helperMethodContent { elementBase : newElementBase ( ln , rslt , src , parent , opts ) , name : ln . tokens [ 2 ] , } return e , nil }

// newHelperMethodContent creates and returns a helper method content.

newHelperMethodContent creates and returns a helper method content .


func (e *htmlTag) setAttributes() error {
	parsedTokens := e.parseTokens()

	var i int
	var token string
	var setTextValue bool

	// Set attributes to the element.
	for i, token = range parsedTokens {
		kv := strings.Split(token, equal)

		if len(kv) < 2 {
			setTextValue = true
			break
		}

		k := kv[0]
		v := strings.Join(kv[1:], equal)

		// Remove the prefix and suffix of the double quotes.
		if len(v) > 1 && strings.HasPrefix(v, doubleQuote) && strings.HasSuffix(v, doubleQuote) {
			v = v[1 : len(v)-1]
		}

		switch k {
		case attributeNameID:
			if e.id != "" {
				return fmt.Errorf("multiple IDs are specified [file: %s][line: %d]", e.ln.fileName(), e.ln.no)
			}
			e.id = v
		case e.opts.AttributeNameClass:
			e.classes = append(e.classes, strings.Split(v, space)...)
		default:
			e.attributes = append(e.attributes, htmlAttribute{k, v})
		}
	}

	// Set a text value to the element.
	if setTextValue {
		e.textValue = strings.Join(parsedTokens[i:], space)
	}

	return nil
}

// setAttributes parses the tokens and set attributes to the element.

setAttributes parses the tokens and set attributes to the element .


func (e *htmlTag) noCloseTag() bool {
	for _, name := range e.opts.NoCloseTagNames {
		if e.tagName == name {
			return true
		}
	}

	return false
}

func ( e * htmlTag ) noCloseTag ( ) bool { for _ , name := range e . opts . NoCloseTagNames { if e . tagName == name { return true } } return false }

// noCloseTag returns true is the HTML tag has no close tag.

noCloseTag returns true is the HTML tag has no close tag .


func (e *htmlTag) IsBlockElement() bool {
	if inline, found := inlineElements[e.tagName]; found {
		return !inline
	} else {
		return true
	}
}

func ( e * htmlTag ) IsBlockElement ( ) bool { if inline , found := inlineElements [ e . tagName ] ; found { return ! inline } else { return true } }


func newHTMLTag(ln *line, rslt *result, src *source, parent element, opts *Options) (*htmlTag, error) {
	if len(ln.tokens) < 1 {
		return nil, fmt.Errorf("an HTML tag is not specified [file: %s][line: %d]", ln.fileName(), ln.no)
	}

	s := ln.tokens[0]

	tagName := extractTagName(s)

	id, err := extractID(s, ln)
	if err != nil {
		return nil, err
	}

	classes := extractClasses(s)

	e := &htmlTag{
		elementBase:      newElementBase(ln, rslt, src, parent, opts),
		tagName:          tagName,
		id:               id,
		classes:          classes,
		containPlainText: strings.HasSuffix(s, dot),
		insertBr:         strings.HasSuffix(s, doubleDot),
		attributes:       make([]htmlAttribute, 0, 2),
	}

	if err := e.setAttributes(); err != nil {
		return nil, err
	}

	return e, nil
}

func newHTMLTag ( ln * line , rslt * result , src * source , parent element , opts * Options ) ( * htmlTag , error ) { if len ( ln . tokens ) < 1 { return nil , fmt . Errorf ( " " , ln . fileName ( ) , ln . no ) } s := ln . tokens [ 0 ] tagName := extractTagName ( s ) id , err := extractID ( s , ln ) if err != nil { return nil , err } classes := extractClasses ( s ) e := & htmlTag { elementBase : newElementBase ( ln , rslt , src , parent , opts ) , tagName : tagName , id : id , classes : classes , containPlainText : strings . HasSuffix ( s , dot ) , insertBr : strings . HasSuffix ( s , doubleDot ) , attributes : make ( [ ] htmlAttribute , 0 , 2 ) , } if err := e . setAttributes ( ) ; err != nil { return nil , err } return e , nil }

// newHTMLTag creates and returns an HTML tag.

newHTMLTag creates and returns an HTML tag .


func extractTagName(s string) string {
	tagName := strings.Split(strings.Split(s, sharp)[0], dot)[0]

	if tagName == "" {
		tagName = tagNameDiv
	}

	return tagName
}

func extractTagName ( s string ) string { tagName := strings . Split ( strings . Split ( s , sharp ) [ 0 ] , dot ) [ 0 ] if tagName == " " { tagName = tagNameDiv } return tagName }

// extractTag extracts and returns a tag.


func extractID(s string, ln *line) (string, error) {
	tokens := strings.Split(s, sharp)

	l := len(tokens)

	if l < 2 {
		return "", nil
	}

	if l > 2 {
		return "", fmt.Errorf("multiple IDs are specified [file: %s][line: %d]", ln.fileName(), ln.no)
	}

	return strings.Split(tokens[1], dot)[0], nil
}

func extractID ( s string , ln * line ) ( string , error ) { tokens := strings . Split ( s , sharp ) l := len ( tokens ) if l < 2 { return " " , nil } if l > 2 { return " " , fmt . Errorf ( " " , ln . fileName ( ) , ln . no ) } return strings . Split ( tokens [ 1 ] , dot ) [ 0 ] , nil }

// extractID extracts and returns an ID.


func extractClasses(s string) []string {
	var classes []string

	for i, token := range strings.Split(s, dot) {
		if i == 0 {
			continue
		}

		class := strings.Split(token, sharp)[0]

		if class == "" {
			continue
		}

		classes = append(classes, class)
	}

	return classes
}

func extractClasses ( s string ) [ ] string { var classes [ ] string for i , token := range strings . Split ( s , dot ) { if i == 0 { continue } class := strings . Split ( token , sharp ) [ 0 ] if class == " " { continue } classes = append ( classes , class ) } return classes }

// extractClasses extracts and returns classes.

extractClasses extracts and returns classes .


func (e *htmlTag) parseTokens() []string {
	var inQuote bool
	var inDelim bool
	var tokens []string
	var token string

	str := strings.Join(e.ln.tokens[1:], space)
	for _, chr := range str {
		switch c := string(chr); c {
		case space:
			if inQuote || inDelim {
				token += c
			} else {
				tokens = append(tokens, token)
				token = ""
			}
		case doubleQuote:
			if !inDelim {
				if inQuote {
					inQuote = false
				} else {
					inQuote = true
				}
			}
			token += c
		default:
			token += c
			if inDelim {
				if strings.HasSuffix(token, e.opts.DelimRight) {
					inDelim = false
				}
			} else {
				if strings.HasSuffix(token, e.opts.DelimLeft) {
					inDelim = true
				}
			}
		}
	}
	if len(token) > 0 {
		tokens = append(tokens, token)
	}
	return tokens
}

func ( e * htmlTag ) parseTokens ( ) [ ] string { var inQuote bool var inDelim bool var tokens [ ] string var token string str := strings . Join ( e . ln . tokens [ 1 : ] , space ) for _ , chr := range str { switch c := string ( chr ) ; c { case space : if inQuote || inDelim { token += c } else { tokens = append ( tokens , token ) token = " " } case doubleQuote : if ! inDelim { if inQuote { inQuote = false } else { inQuote = true } } token += c default : token += c if inDelim { if strings . HasSuffix ( token , e . opts . DelimRight ) { inDelim = false } } else { if strings . HasSuffix ( token , e . opts . DelimLeft ) { inDelim = true } } } } if len ( token ) > 0 { tokens = append ( tokens , token ) } return tokens }

// parseTokens parses the tokens and return them


func newPlainText(ln *line, rslt *result, src *source, parent element, opts *Options) *plainText {
	return &plainText{
		elementBase: newElementBase(ln, rslt, src, parent, opts),
		insertBr:    ln.tokens[0] == doublePipe,
	}
}

func newPlainText ( ln * line , rslt * result , src * source , parent element , opts * Options ) * plainText { return & plainText { elementBase : newElementBase ( ln , rslt , src , parent , opts ) , insertBr : ln . tokens [ 0 ] == doublePipe , } }

// newPlainText creates and returns a plain text.

newPlainText creates and returns a plain text .


func (l *line) isHelperMethod() bool {
	return len(l.tokens) > 1 && l.tokens[0] == equal
}

func ( l * line ) isHelperMethod ( ) bool { return len ( l . tokens ) > 1 && l . tokens [ 0 ] == equal }

// isHelperMethod returns true if the line is a helper method.

isHelperMethod returns true if the line is a helper method .


func (l *line) isHelperMethodOf(name string) bool {
	return l.isHelperMethod() && l.tokens[1] == name
}

func ( l * line ) isHelperMethodOf ( name string ) bool { return l . isHelperMethod ( ) && l . tokens [ 1 ] == name }

// isHelperMethodOf returns true if the line is a specified helper method.

isHelperMethodOf returns true if the line is a specified helper method .


func (l *line) isPlainText() bool {
	return len(l.tokens) > 0 && (l.tokens[0] == pipe || l.tokens[0] == doublePipe)
}

func ( l * line ) isPlainText ( ) bool { return len ( l . tokens ) > 0 && ( l . tokens [ 0 ] == pipe || l . tokens [ 0 ] == doublePipe ) }

// isPlainText returns true if the line is a plain text.

isPlainText returns true if the line is a plain text .


func (l *line) isComment() bool {
	return len(l.tokens) > 0 && l.tokens[0] == slash
}

func ( l * line ) isComment ( ) bool { return len ( l . tokens ) > 0 && l . tokens [ 0 ] == slash }

// isComment returns true if the line is a comment.

isComment returns true if the line is a comment .


func (l *line) isHTMLComment() bool {
	return len(l.tokens) > 0 && l.tokens[0] == slash+slash
}

func ( l * line ) isHTMLComment ( ) bool { return len ( l . tokens ) > 0 && l . tokens [ 0 ] == slash + slash }

// isHTMLComment returns true if the line is an HTML comment.

isHTMLComment returns true if the line is an HTML comment .


func (l *line) isAction() bool {
	str := strings.TrimSpace(l.str)
	return strings.HasPrefix(str, l.opts.DelimLeft) && strings.HasSuffix(str, l.opts.DelimRight)
}

func ( l * line ) isAction ( ) bool { str := strings . TrimSpace ( l . str ) return strings . HasPrefix ( str , l . opts . DelimLeft ) && strings . HasSuffix ( str , l . opts . DelimRight ) }

// isAction returns true if the line is an action.

isAction returns true if the line is an action .


func (l *line) fileName() string {
	return l.file.path + dot + l.opts.Extension
}

func ( l * line ) fileName ( ) string { return l . file . path + dot + l . opts . Extension }


func (l *line) childOf(parent element) (bool, error) {
	var ok bool
	var err error

	switch {
	case l.isEmpty():
		ok = true
	case parent.ContainPlainText():
		switch {
		case parent.Base().ln.indent < l.indent:
			ok = true
		}
	default:
		switch {
		case l.indent == parent.Base().ln.indent+1:
			ok = true
		case l.indent > parent.Base().ln.indent+1:
			err = fmt.Errorf("the indent is invalid [file: %s][line: %d]", l.fileName(), l.no)
		}
	}

	return ok, err
}

func ( l * line ) childOf ( parent element ) ( bool , error ) { var ok bool var err error switch { case l . isEmpty ( ) : ok = true case parent . ContainPlainText ( ) : switch { case parent . Base ( ) . ln . indent < l . indent : ok = true } default : switch { case l . indent == parent . Base ( ) . ln . indent + 1 : ok = true case l . indent > parent . Base ( ) . ln . indent + 1 : err = fmt . Errorf ( " " , l . fileName ( ) , l . no ) } } return ok , err }

// childOf returns true if the line is a child of the element.

childOf returns true if the line is a child of the element .


func newLine(no int, str string, opts *Options, f *File) *line {
	return &line{
		no:     no,
		str:    str,
		indent: indent(str),
		tokens: strings.Split(strings.TrimLeft(str, space), space),
		opts:   opts,
		file:   f,
	}
}

func newLine ( no int , str string , opts * Options , f * File ) * line { return & line { no : no , str : str , indent : indent ( str ) , tokens : strings . Split ( strings . TrimLeft ( str , space ) , space ) , opts : opts , file : f , } }


func indent(str string) int {
	var i int

	for _, b := range str {
		if b != unicodeSpace {
			break
		}
		i++
	}

	return i / 2
}

func indent ( str string ) int { var i int for _ , b := range str { if b != unicodeSpace { break } i ++ } return i / 2 }