Add Disqus support out of the box. Move template/bundle into hugolib. - hugo - [fork] hugo port for 9front
 (HTM) git clone git@git.drkhsh.at/hugo.git
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) Submodules
 (DIR) README
 (DIR) LICENSE
       ---
 (DIR) commit 4a8de8ea46f45776518c7086222be0c94c893764
 (DIR) parent 41adafbc3e8c53475ba9a8bc8031dd4e0bf59664
 (HTM) Author: spf13 <steve.francia@gmail.com>
       Date:   Wed, 23 Apr 2014 02:52:01 -0400
       
       Add Disqus support out of the box. Move template/bundle into hugolib.
       
       Diffstat:
         M hugolib/page.go                     |       5 ++---
         A hugolib/path_seperators_windows_te… |      17 +++++++++++++++++
         M hugolib/shortcode.go                |       5 ++---
         M hugolib/site.go                     |      52 ++++++++++++++++----------------
         A hugolib/template.go                 |     275 +++++++++++++++++++++++++++++++
         A hugolib/template_embedded.go        |      84 +++++++++++++++++++++++++++++++
         A hugolib/template_test.go            |      55 +++++++++++++++++++++++++++++++
         D template/bundle/embedded.go         |      68 -------------------------------
         D template/bundle/path_seperators_wi… |      17 -----------------
         D template/bundle/template.go         |     271 -------------------------------
         D template/bundle/template_test.go    |      55 -------------------------------
       
       11 files changed, 461 insertions(+), 443 deletions(-)
       ---
 (DIR) diff --git a/hugolib/page.go b/hugolib/page.go
       @@ -28,7 +28,6 @@ import (
                "github.com/spf13/cast"
                "github.com/spf13/hugo/helpers"
                "github.com/spf13/hugo/parser"
       -        "github.com/spf13/hugo/template/bundle"
                jww "github.com/spf13/jwalterweatherman"
                "github.com/spf13/viper"
                "github.com/theplant/blackfriday"
       @@ -49,7 +48,7 @@ type Page struct {
                contentType     string
                Draft           bool
                Aliases         []string
       -        Tmpl            bundle.Template
       +        Tmpl            Template
                Markup          string
                renderable      bool
                layout          string
       @@ -519,7 +518,7 @@ func (page *Page) parse(reader io.Reader) error {
                return nil
        }
        
       -func (p *Page) ProcessShortcodes(t bundle.Template) {
       +func (p *Page) ProcessShortcodes(t Template) {
                p.rawContent = []byte(ShortcodesHandle(string(p.rawContent), p, t))
                p.Summary = template.HTML(ShortcodesHandle(string(p.Summary), p, t))
        }
 (DIR) diff --git a/hugolib/path_seperators_windows_test.go b/hugolib/path_seperators_windows_test.go
       @@ -0,0 +1,17 @@
       +package hugolib
       +
       +import (
       +        "testing"
       +)
       +
       +const (
       +        win_base = "c:\\a\\windows\\path\\layout"
       +        win_path = "c:\\a\\windows\\path\\layout\\sub1\\index.html"
       +)
       +
       +func TestTemplatePathSeperator(t *testing.T) {
       +        tmpl := new(GoHtmlTemplate)
       +        if name := tmpl.generateTemplateNameFrom(win_base, win_path); name != "sub1/index.html" {
       +                t.Fatalf("Template name incorrect.  Expected: %s, Got: %s", "sub1/index.html", name)
       +        }
       +}
 (DIR) diff --git a/hugolib/shortcode.go b/hugolib/shortcode.go
       @@ -20,7 +20,6 @@ import (
                "strings"
                "unicode"
        
       -        "github.com/spf13/hugo/template/bundle"
                jww "github.com/spf13/jwalterweatherman"
        )
        
       @@ -78,7 +77,7 @@ func (scp *ShortcodeWithPage) Get(key interface{}) interface{} {
        
        type Shortcodes map[string]ShortcodeFunc
        
       -func ShortcodesHandle(stringToParse string, p *Page, t bundle.Template) string {
       +func ShortcodesHandle(stringToParse string, p *Page, t Template) string {
                leadStart := strings.Index(stringToParse, `{{%`)
                if leadStart >= 0 {
                        leadEnd := strings.Index(stringToParse[leadStart:], `%}}`) + leadStart
       @@ -147,7 +146,7 @@ func FindEnd(str string, name string) (int, int) {
                return startPos, endPos
        }
        
       -func GetTemplate(name string, t bundle.Template) *template.Template {
       +func GetTemplate(name string, t Template) *template.Template {
                if x := t.Lookup("shortcodes/" + name + ".html"); x != nil {
                        return x
                }
 (DIR) diff --git a/hugolib/site.go b/hugolib/site.go
       @@ -27,7 +27,6 @@ import (
                "github.com/spf13/hugo/helpers"
                "github.com/spf13/hugo/source"
                "github.com/spf13/hugo/target"
       -        "github.com/spf13/hugo/template/bundle"
                "github.com/spf13/hugo/transform"
                jww "github.com/spf13/jwalterweatherman"
                "github.com/spf13/nitro"
       @@ -57,7 +56,7 @@ var DefaultTimer *nitro.B
        // 5. The entire collection of files is written to disk.
        type Site struct {
                Pages      Pages
       -        Tmpl       bundle.Template
       +        Tmpl       Template
                Taxonomies TaxonomyList
                Source     source.Input
                Sections   Taxonomy
       @@ -72,19 +71,20 @@ type Site struct {
        }
        
        type SiteInfo struct {
       -        BaseUrl      template.URL
       -        Taxonomies   TaxonomyList
       -        Indexes      *TaxonomyList // legacy, should be identical to Taxonomies
       -        Recent       *Pages
       -        Title        string
       -        Author       string
       -        AuthorEmail  string
       -        LanguageCode string
       -        Copyright    string
       -        LastChange   time.Time
       -        ConfigGet    func(key string) interface{}
       -        Permalinks   PermalinkOverrides
       -        Params       map[string]interface{}
       +        BaseUrl         template.URL
       +        Taxonomies      TaxonomyList
       +        Indexes         *TaxonomyList // legacy, should be identical to Taxonomies
       +        Recent          *Pages
       +        Title           string
       +        Author          map[string]string
       +        LanguageCode    string
       +        DisqusShortname string
       +        Copyright       string
       +        LastChange      time.Time
       +        ConfigGet       func(key string) interface{}
       +        Permalinks      PermalinkOverrides
       +        Params          map[string]interface{}
       +}
        }
        
        type runmode struct {
       @@ -130,7 +130,7 @@ func (s *Site) Analyze() {
        }
        
        func (s *Site) prepTemplates() {
       -        s.Tmpl = bundle.NewTemplate()
       +        s.Tmpl = NewTemplate()
                s.Tmpl.LoadTemplates(s.absLayoutDir())
                if s.hasTheme() {
                        s.Tmpl.LoadTemplatesWithPrefix(s.absThemeDir()+"/layouts", "theme")
       @@ -234,16 +234,16 @@ func (s *Site) initializeSiteInfo() {
                        permalinks = make(PermalinkOverrides)
                }
        
       -        s.Info = SiteInfo{
       -                BaseUrl:      template.URL(helpers.SanitizeUrl(viper.GetString("BaseUrl"))),
       -                Title:        viper.GetString("Title"),
       -                Author:       viper.GetString("author"),
       -                AuthorEmail:  viper.GetString("authoremail"),
       -                LanguageCode: viper.GetString("languagecode"),
       -                Copyright:    viper.GetString("copyright"),
       -                Recent:       &s.Pages,
       -                Params:       params,
       -                Permalinks:   permalinks,
       +        s.Info = &SiteInfo{
       +                BaseUrl:         template.URL(helpers.SanitizeUrl(viper.GetString("BaseUrl"))),
       +                Title:           viper.GetString("Title"),
       +                Author:          viper.GetStringMapString("author"),
       +                LanguageCode:    viper.GetString("languagecode"),
       +                Copyright:       viper.GetString("copyright"),
       +                DisqusShortname: viper.GetString("DisqusShortname"),
       +                Recent:          &s.Pages,
       +                Params:          params,
       +                Permalinks:      permalinks,
                }
        }
        
 (DIR) diff --git a/hugolib/template.go b/hugolib/template.go
       @@ -0,0 +1,275 @@
       +package hugolib
       +
       +import (
       +        "errors"
       +        "html"
       +        "html/template"
       +        "io"
       +        "io/ioutil"
       +        "os"
       +        "path/filepath"
       +        "reflect"
       +        "strconv"
       +        "strings"
       +
       +        "github.com/eknkc/amber"
       +        "github.com/spf13/hugo/helpers"
       +)
       +
       +func Gt(a interface{}, b interface{}) bool {
       +        var left, right int64
       +        av := reflect.ValueOf(a)
       +
       +        switch av.Kind() {
       +        case reflect.Array, reflect.Chan, reflect.Map, reflect.Slice:
       +                left = int64(av.Len())
       +        case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
       +                left = av.Int()
       +        case reflect.String:
       +                left, _ = strconv.ParseInt(av.String(), 10, 64)
       +        }
       +
       +        bv := reflect.ValueOf(b)
       +
       +        switch bv.Kind() {
       +        case reflect.Array, reflect.Chan, reflect.Map, reflect.Slice:
       +                right = int64(bv.Len())
       +        case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
       +                right = bv.Int()
       +        case reflect.String:
       +                right, _ = strconv.ParseInt(bv.String(), 10, 64)
       +        }
       +
       +        return left > right
       +}
       +
       +// First is exposed to templates, to iterate over the first N items in a
       +// rangeable list.
       +func First(limit int, seq interface{}) (interface{}, error) {
       +        if limit < 1 {
       +                return nil, errors.New("can't return negative/empty count of items from sequence")
       +        }
       +
       +        seqv := reflect.ValueOf(seq)
       +        // this is better than my first pass; ripped from text/template/exec.go indirect():
       +        for ; seqv.Kind() == reflect.Ptr || seqv.Kind() == reflect.Interface; seqv = seqv.Elem() {
       +                if seqv.IsNil() {
       +                        return nil, errors.New("can't iterate over a nil value")
       +                }
       +                if seqv.Kind() == reflect.Interface && seqv.NumMethod() > 0 {
       +                        break
       +                }
       +        }
       +
       +        switch seqv.Kind() {
       +        case reflect.Array, reflect.Slice, reflect.String:
       +                // okay
       +        default:
       +                return nil, errors.New("can't iterate over " + reflect.ValueOf(seq).Type().String())
       +        }
       +        if limit > seqv.Len() {
       +                limit = seqv.Len()
       +        }
       +        return seqv.Slice(0, limit).Interface(), nil
       +}
       +
       +func IsSet(a interface{}, key interface{}) bool {
       +        av := reflect.ValueOf(a)
       +        kv := reflect.ValueOf(key)
       +
       +        switch av.Kind() {
       +        case reflect.Array, reflect.Chan, reflect.Slice:
       +                if int64(av.Len()) > kv.Int() {
       +                        return true
       +                }
       +        case reflect.Map:
       +                if kv.Type() == av.Type().Key() {
       +                        return av.MapIndex(kv).IsValid()
       +                }
       +        }
       +
       +        return false
       +}
       +
       +func ReturnWhenSet(a interface{}, index int) interface{} {
       +        av := reflect.ValueOf(a)
       +
       +        switch av.Kind() {
       +        case reflect.Array, reflect.Slice:
       +                if av.Len() > index {
       +
       +                        avv := av.Index(index)
       +                        switch avv.Kind() {
       +                        case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
       +                                return avv.Int()
       +                        case reflect.String:
       +                                return avv.String()
       +                        }
       +                }
       +        }
       +
       +        return ""
       +}
       +
       +func Highlight(in interface{}, lang string) template.HTML {
       +        var str string
       +        av := reflect.ValueOf(in)
       +        switch av.Kind() {
       +        case reflect.String:
       +                str = av.String()
       +        }
       +
       +        if strings.HasPrefix(strings.TrimSpace(str), "<pre><code>") {
       +                str = str[strings.Index(str, "<pre><code>")+11:]
       +        }
       +        if strings.HasSuffix(strings.TrimSpace(str), "</code></pre>") {
       +                str = str[:strings.LastIndex(str, "</code></pre>")]
       +        }
       +        return template.HTML(helpers.Highlight(html.UnescapeString(str), lang))
       +}
       +
       +func SafeHtml(text string) template.HTML {
       +        return template.HTML(text)
       +}
       +
       +type Template interface {
       +        ExecuteTemplate(wr io.Writer, name string, data interface{}) error
       +        Lookup(name string) *template.Template
       +        Templates() []*template.Template
       +        New(name string) *template.Template
       +        LoadTemplates(absPath string)
       +        LoadTemplatesWithPrefix(absPath, prefix string)
       +        AddTemplate(name, tpl string) error
       +        AddInternalTemplate(prefix, name, tpl string) error
       +        AddInternalShortcode(name, tpl string) error
       +}
       +
       +type templateErr struct {
       +        name string
       +        err  error
       +}
       +
       +type GoHtmlTemplate struct {
       +        template.Template
       +        errors []*templateErr
       +}
       +
       +func NewTemplate() Template {
       +        var templates = &GoHtmlTemplate{
       +                Template: *template.New(""),
       +                errors:   make([]*templateErr, 0),
       +        }
       +
       +        funcMap := template.FuncMap{
       +                "urlize":      helpers.Urlize,
       +                "sanitizeurl": helpers.SanitizeUrl,
       +                "gt":          Gt,
       +                "isset":       IsSet,
       +                "echoParam":   ReturnWhenSet,
       +                "safeHtml":    SafeHtml,
       +                "first":       First,
       +                "highlight":   Highlight,
       +                "add":         func(a, b int) int { return a + b },
       +                "sub":         func(a, b int) int { return a - b },
       +                "div":         func(a, b int) int { return a / b },
       +                "mod":         func(a, b int) int { return a % b },
       +                "mul":         func(a, b int) int { return a * b },
       +                "modBool":     func(a, b int) bool { return a%b == 0 },
       +                "lower":       func(a string) string { return strings.ToLower(a) },
       +                "upper":       func(a string) string { return strings.ToUpper(a) },
       +                "title":       func(a string) string { return strings.Title(a) },
       +        }
       +
       +        templates.Funcs(funcMap)
       +
       +        templates.LoadEmbedded()
       +        return templates
       +}
       +
       +func (t *GoHtmlTemplate) LoadEmbedded() {
       +        t.EmbedShortcodes()
       +        t.EmbedTemplates()
       +}
       +
       +func (t *GoHtmlTemplate) AddInternalTemplate(prefix, name, tpl string) error {
       +        if prefix != "" {
       +                return t.AddTemplate("_internal/"+prefix+"/"+name, tpl)
       +        } else {
       +                return t.AddTemplate("_internal/"+name, tpl)
       +        }
       +}
       +
       +func (t *GoHtmlTemplate) AddInternalShortcode(name, content string) error {
       +        return t.AddInternalTemplate("shortcodes", name, content)
       +}
       +
       +func (t *GoHtmlTemplate) AddTemplate(name, tpl string) error {
       +        _, err := t.New(name).Parse(tpl)
       +        if err != nil {
       +                t.errors = append(t.errors, &templateErr{name: name, err: err})
       +        }
       +        return err
       +}
       +
       +func (t *GoHtmlTemplate) AddTemplateFile(name, path string) error {
       +        b, err := ioutil.ReadFile(path)
       +        if err != nil {
       +                return err
       +        }
       +        return t.AddTemplate(name, string(b))
       +}
       +
       +func (t *GoHtmlTemplate) generateTemplateNameFrom(base, path string) string {
       +        return filepath.ToSlash(path[len(base)+1:])
       +}
       +
       +func ignoreDotFile(path string) bool {
       +        return filepath.Base(path)[0] == '.'
       +}
       +
       +func (t *GoHtmlTemplate) loadTemplates(absPath string, prefix string) {
       +        walker := func(path string, fi os.FileInfo, err error) error {
       +                if err != nil {
       +                        return nil
       +                }
       +
       +                if !fi.IsDir() {
       +                        if ignoreDotFile(path) {
       +                                return nil
       +                        }
       +
       +                        tplName := t.generateTemplateNameFrom(absPath, path)
       +
       +                        if prefix != "" {
       +                                tplName = strings.Trim(prefix, "/") + "/" + tplName
       +                        }
       +
       +                        // TODO move this into the AddTemplateFile function
       +                        if strings.HasSuffix(path, ".amber") {
       +                                compiler := amber.New()
       +                                // Parse the input file
       +                                if err := compiler.ParseFile(path); err != nil {
       +                                        return nil
       +                                }
       +
       +                                if _, err := compiler.CompileWithTemplate(t.New(tplName)); err != nil {
       +                                        return err
       +                                }
       +
       +                        } else {
       +                                t.AddTemplateFile(tplName, path)
       +                        }
       +                }
       +                return nil
       +        }
       +
       +        filepath.Walk(absPath, walker)
       +}
       +
       +func (t *GoHtmlTemplate) LoadTemplatesWithPrefix(absPath string, prefix string) {
       +        t.loadTemplates(absPath, prefix)
       +}
       +
       +func (t *GoHtmlTemplate) LoadTemplates(absPath string) {
       +        t.loadTemplates(absPath, "")
       +}
 (DIR) diff --git a/hugolib/template_embedded.go b/hugolib/template_embedded.go
       @@ -0,0 +1,84 @@
       +// Copyright © 2013 Steve Francia <spf@spf13.com>.
       +//
       +// Licensed under the Simple Public License, Version 2.0 (the "License");
       +// you may not use this file except in compliance with the License.
       +// You may obtain a copy of the License at
       +// http://opensource.org/licenses/Simple-2.0
       +//
       +// Unless required by applicable law or agreed to in writing, software
       +// distributed under the License is distributed on an "AS IS" BASIS,
       +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
       +// See the License for the specific language governing permissions and
       +// limitations under the License.
       +
       +package hugolib
       +
       +type Tmpl struct {
       +        Name string
       +        Data string
       +}
       +
       +func (t *GoHtmlTemplate) EmbedShortcodes() {
       +        t.AddInternalShortcode("highlight.html", `{{ .Get 0 | highlight .Inner  }}`)
       +        t.AddInternalShortcode("test.html", `This is a simple Test`)
       +        t.AddInternalShortcode("figure.html", `<!-- image -->
       +<figure {{ with .Get "class" }}class="{{.}}"{{ end }}>
       +    {{ with .Get "link"}}<a href="{{.}}">{{ end }}
       +        <img src="{{ .Get "src" }}" {{ if or (.Get "alt") (.Get "caption") }}alt="{{ with .Get "alt"}}{{.}}{{else}}{{ .Get "caption" }}{{ end }}"{{ end }} />
       +    {{ if .Get "link"}}</a>{{ end }}
       +    {{ if or (or (.Get "title") (.Get "caption")) (.Get "attr")}}
       +    <figcaption>{{ if isset .Params "title" }}
       +        <h4>{{ .Get "title" }}</h4>{{ end }}
       +        {{ if or (.Get "caption") (.Get "attr")}}<p>
       +        {{ .Get "caption" }}
       +        {{ with .Get "attrlink"}}<a href="{{.}}"> {{ end }}
       +            {{ .Get "attr" }}
       +        {{ if .Get "attrlink"}}</a> {{ end }}
       +        </p> {{ end }}
       +    </figcaption>
       +    {{ end }}
       +</figure>
       +<!-- image -->`)
       +}
       +
       +func (t *GoHtmlTemplate) EmbedTemplates() {
       +
       +        t.AddInternalTemplate("_default", "rss.xml", `<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
       +  <channel>
       +      <title>{{ .Title }} on {{ .Site.Title }} </title>
       +      <generator uri="https://hugo.spf13.com">Hugo</generator>
       +    <link>{{ .Permalink }}</link>
       +    {{ with .Site.LanguageCode }}<language>{{.}}</language>{{end}}
       +    {{ with .Site.Author.name }}<author>{{.}}</author>{{end}}
       +    {{ with .Site.Copyright }}<copyright>{{.}}</copyright>{{end}}
       +    <updated>{{ .Date.Format "Mon, 02 Jan 2006 15:04:05 MST" }}</updated>
       +    {{ range first 15 .Data.Pages }}
       +    <item>
       +      <title>{{ .Title }}</title>
       +      <link>{{ .Permalink }}</link>
       +      <pubDate>{{ .Date.Format "Mon, 02 Jan 2006 15:04:05 MST" }}</pubDate>
       +      {{with .Site.Author.name}}<author>{{.}}</author>{{end}}
       +      <guid>{{ .Permalink }}</guid>
       +      <description>{{ .Content | html }}</description>
       +    </item>
       +    {{ end }}
       +  </channel>
       +</rss>`)
       +
       +        t.AddInternalTemplate("", "disqus.html", `{{ if .Site.DisqusShortname }}<div id="disqus_thread"></div>
       +<script type="text/javascript">
       +    var disqus_shortname = '{{ .Site.DisqusShortname }}';
       +    var disqus_identifier = '{{with .GetParam "disqus_identifier" }}{{ . }}{{ else }}{{ .Permalink }}{{end}}';
       +    var disqus_title = '{{with .GetParam "disqus_title" }}{{ . }}{{ else }}{{ .Title }}{{end}}';
       +    var disqus_url = '{{with .GetParam "disqus_url" }}{{ . | html  }}{{ else }}{{ .Permalink }}{{end}}';
       +
       +    (function() {
       +        var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true;
       +        dsq.src = '//' + disqus_shortname + '.disqus.com/embed.js';
       +        (document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq);
       +    })();
       +</script>
       +<noscript>Please enable JavaScript to view the <a href="http://disqus.com/?ref_noscript">comments powered by Disqus.</a></noscript>
       +<a href="http://disqus.com" class="dsq-brlink">comments powered by <span class="logo-disqus">Disqus</span></a>{{end}}`)
       +
       +}
 (DIR) diff --git a/hugolib/template_test.go b/hugolib/template_test.go
       @@ -0,0 +1,55 @@
       +package hugolib
       +
       +import (
       +        "reflect"
       +        "testing"
       +)
       +
       +func TestGt(t *testing.T) {
       +        for i, this := range []struct {
       +                left          interface{}
       +                right         interface{}
       +                leftShouldWin bool
       +        }{
       +                {5, 8, false},
       +                {8, 5, true},
       +                {5, 5, false},
       +                {-2, 1, false},
       +                {2, -5, true},
       +                {"8", "5", true},
       +                {"5", "0001", true},
       +                {[]int{100, 99}, []int{1, 2, 3, 4}, false},
       +        } {
       +                leftIsBigger := Gt(this.left, this.right)
       +                if leftIsBigger != this.leftShouldWin {
       +                        var which string
       +                        if leftIsBigger {
       +                                which = "expected right to be bigger, but left was"
       +                        } else {
       +                                which = "expected left to be bigger, but right was"
       +                        }
       +                        t.Errorf("[%d] %v compared to %v: %s", i, this.left, this.right, which)
       +                }
       +        }
       +}
       +
       +func TestFirst(t *testing.T) {
       +        for i, this := range []struct {
       +                count    int
       +                sequence interface{}
       +                expect   interface{}
       +        }{
       +                {2, []string{"a", "b", "c"}, []string{"a", "b"}},
       +                {3, []string{"a", "b"}, []string{"a", "b"}},
       +                {2, []int{100, 200, 300}, []int{100, 200}},
       +        } {
       +                results, err := First(this.count, this.sequence)
       +                if err != nil {
       +                        t.Errorf("[%d] failed: %s", i, err)
       +                        continue
       +                }
       +                if !reflect.DeepEqual(results, this.expect) {
       +                        t.Errorf("[%d] First %d items, got %v but expected %v", i, this.count, results, this.expect)
       +                }
       +        }
       +}
 (DIR) diff --git a/template/bundle/embedded.go b/template/bundle/embedded.go
       @@ -1,68 +0,0 @@
       -// Copyright © 2013 Steve Francia <spf@spf13.com>.
       -//
       -// Licensed under the Simple Public License, Version 2.0 (the "License");
       -// you may not use this file except in compliance with the License.
       -// You may obtain a copy of the License at
       -// http://opensource.org/licenses/Simple-2.0
       -//
       -// Unless required by applicable law or agreed to in writing, software
       -// distributed under the License is distributed on an "AS IS" BASIS,
       -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
       -// See the License for the specific language governing permissions and
       -// limitations under the License.
       -
       -package bundle
       -
       -type Tmpl struct {
       -        Name string
       -        Data string
       -}
       -
       -func (t *GoHtmlTemplate) EmbedShortcodes() {
       -        t.AddInternalShortcode("highlight.html", `{{ .Get 0 | highlight .Inner  }}`)
       -        t.AddInternalShortcode("test.html", `This is a simple Test`)
       -        t.AddInternalShortcode("figure.html", `<!-- image -->
       -<figure {{ with .Get "class" }}class="{{.}}"{{ end }}>
       -    {{ with .Get "link"}}<a href="{{.}}">{{ end }}
       -        <img src="{{ .Get "src" }}" {{ if or (.Get "alt") (.Get "caption") }}alt="{{ with .Get "alt"}}{{.}}{{else}}{{ .Get "caption" }}{{ end }}"{{ end }} />
       -    {{ if .Get "link"}}</a>{{ end }}
       -    {{ if or (or (.Get "title") (.Get "caption")) (.Get "attr")}}
       -    <figcaption>{{ if isset .Params "title" }}
       -        <h4>{{ .Get "title" }}</h4>{{ end }}
       -        {{ if or (.Get "caption") (.Get "attr")}}<p>
       -        {{ .Get "caption" }}
       -        {{ with .Get "attrlink"}}<a href="{{.}}"> {{ end }}
       -            {{ .Get "attr" }}
       -        {{ if .Get "attrlink"}}</a> {{ end }}
       -        </p> {{ end }}
       -    </figcaption>
       -    {{ end }}
       -</figure>
       -<!-- image -->`)
       -}
       -
       -func (t *GoHtmlTemplate) EmbedTemplates() {
       -
       -        t.AddInternalTemplate("_default", "rss.xml", `<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
       -  <channel>
       -      <title>{{ .Title }} on {{ .Site.Title }} </title>
       -      <generator uri="https://hugo.spf13.com">Hugo</generator>
       -    <link>{{ .Permalink }}</link>
       -    {{ with .Site.LanguageCode }}<language>{{.}}</language>{{end}}
       -    {{ with .Site.Author }}<author>{{.}}</author>{{end}}
       -    {{ with .Site.Copyright }}<copyright>{{.}}</copyright>{{end}}
       -    <updated>{{ .Date.Format "Mon, 02 Jan 2006 15:04:05 MST" }}</updated>
       -    {{ range first 15 .Data.Pages }}
       -    <item>
       -      <title>{{ .Title }}</title>
       -      <link>{{ .Permalink }}</link>
       -      <pubDate>{{ .Date.Format "Mon, 02 Jan 2006 15:04:05 MST" }}</pubDate>
       -      {{with .Site.Author}}<author>{{.}}</author>{{end}}
       -      <guid>{{ .Permalink }}</guid>
       -      <description>{{ .Content | html }}</description>
       -    </item>
       -    {{ end }}
       -  </channel>
       -</rss>`)
       -
       -}
 (DIR) diff --git a/template/bundle/path_seperators_windows_test.go b/template/bundle/path_seperators_windows_test.go
       @@ -1,17 +0,0 @@
       -package bundle
       -
       -import (
       -        "testing"
       -)
       -
       -const (
       -        win_base = "c:\\a\\windows\\path\\layout"
       -        win_path = "c:\\a\\windows\\path\\layout\\sub1\\index.html"
       -)
       -
       -func TestTemplatePathSeperator(t *testing.T) {
       -        tmpl := new(GoHtmlTemplate)
       -        if name := tmpl.generateTemplateNameFrom(win_base, win_path); name != "sub1/index.html" {
       -                t.Fatalf("Template name incorrect.  Expected: %s, Got: %s", "sub1/index.html", name)
       -        }
       -}
 (DIR) diff --git a/template/bundle/template.go b/template/bundle/template.go
       @@ -1,271 +0,0 @@
       -package bundle
       -
       -import (
       -        "errors"
       -        "html"
       -        "html/template"
       -        "io"
       -        "io/ioutil"
       -        "os"
       -        "path/filepath"
       -        "reflect"
       -        "strconv"
       -        "strings"
       -
       -        "github.com/eknkc/amber"
       -        "github.com/spf13/hugo/helpers"
       -)
       -
       -func Gt(a interface{}, b interface{}) bool {
       -        var left, right int64
       -        av := reflect.ValueOf(a)
       -
       -        switch av.Kind() {
       -        case reflect.Array, reflect.Chan, reflect.Map, reflect.Slice:
       -                left = int64(av.Len())
       -        case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
       -                left = av.Int()
       -        case reflect.String:
       -                left, _ = strconv.ParseInt(av.String(), 10, 64)
       -        }
       -
       -        bv := reflect.ValueOf(b)
       -
       -        switch bv.Kind() {
       -        case reflect.Array, reflect.Chan, reflect.Map, reflect.Slice:
       -                right = int64(bv.Len())
       -        case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
       -                right = bv.Int()
       -        case reflect.String:
       -                right, _ = strconv.ParseInt(bv.String(), 10, 64)
       -        }
       -
       -        return left > right
       -}
       -
       -// First is exposed to templates, to iterate over the first N items in a
       -// rangeable list.
       -func First(limit int, seq interface{}) (interface{}, error) {
       -        if limit < 1 {
       -                return nil, errors.New("can't return negative/empty count of items from sequence")
       -        }
       -
       -        seqv := reflect.ValueOf(seq)
       -        // this is better than my first pass; ripped from text/template/exec.go indirect():
       -        for ; seqv.Kind() == reflect.Ptr || seqv.Kind() == reflect.Interface; seqv = seqv.Elem() {
       -                if seqv.IsNil() {
       -                        return nil, errors.New("can't iterate over a nil value")
       -                }
       -                if seqv.Kind() == reflect.Interface && seqv.NumMethod() > 0 {
       -                        break
       -                }
       -        }
       -
       -        switch seqv.Kind() {
       -        case reflect.Array, reflect.Slice, reflect.String:
       -                // okay
       -        default:
       -                return nil, errors.New("can't iterate over " + reflect.ValueOf(seq).Type().String())
       -        }
       -        if limit > seqv.Len() {
       -                limit = seqv.Len()
       -        }
       -        return seqv.Slice(0, limit).Interface(), nil
       -}
       -
       -func IsSet(a interface{}, key interface{}) bool {
       -        av := reflect.ValueOf(a)
       -        kv := reflect.ValueOf(key)
       -
       -        switch av.Kind() {
       -        case reflect.Array, reflect.Chan, reflect.Slice:
       -                if int64(av.Len()) > kv.Int() {
       -                        return true
       -                }
       -        case reflect.Map:
       -                if kv.Type() == av.Type().Key() {
       -                        return av.MapIndex(kv).IsValid()
       -                }
       -        }
       -
       -        return false
       -}
       -
       -func ReturnWhenSet(a interface{}, index int) interface{} {
       -        av := reflect.ValueOf(a)
       -
       -        switch av.Kind() {
       -        case reflect.Array, reflect.Slice:
       -                if av.Len() > index {
       -
       -                        avv := av.Index(index)
       -                        switch avv.Kind() {
       -                        case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
       -                                return avv.Int()
       -                        case reflect.String:
       -                                return avv.String()
       -                        }
       -                }
       -        }
       -
       -        return ""
       -}
       -
       -func Highlight(in interface{}, lang string) template.HTML {
       -        var str string
       -        av := reflect.ValueOf(in)
       -        switch av.Kind() {
       -        case reflect.String:
       -                str = av.String()
       -        }
       -
       -        if strings.HasPrefix(strings.TrimSpace(str), "<pre><code>") {
       -                str = str[strings.Index(str, "<pre><code>")+11:]
       -        }
       -        if strings.HasSuffix(strings.TrimSpace(str), "</code></pre>") {
       -                str = str[:strings.LastIndex(str, "</code></pre>")]
       -        }
       -        return template.HTML(helpers.Highlight(html.UnescapeString(str), lang))
       -}
       -
       -func SafeHtml(text string) template.HTML {
       -        return template.HTML(text)
       -}
       -
       -type Template interface {
       -        ExecuteTemplate(wr io.Writer, name string, data interface{}) error
       -        Lookup(name string) *template.Template
       -        Templates() []*template.Template
       -        New(name string) *template.Template
       -        LoadTemplates(absPath string)
       -        LoadTemplatesWithPrefix(absPath, prefix string)
       -        AddTemplate(name, tpl string) error
       -        AddInternalTemplate(prefix, name, tpl string) error
       -        AddInternalShortcode(name, tpl string) error
       -}
       -
       -type templateErr struct {
       -        name string
       -        err  error
       -}
       -
       -type GoHtmlTemplate struct {
       -        template.Template
       -        errors []*templateErr
       -}
       -
       -func NewTemplate() Template {
       -        var templates = &GoHtmlTemplate{
       -                Template: *template.New(""),
       -                errors:   make([]*templateErr, 0),
       -        }
       -
       -        funcMap := template.FuncMap{
       -                "urlize":      helpers.Urlize,
       -                "sanitizeurl": helpers.SanitizeUrl,
       -                "gt":          Gt,
       -                "isset":       IsSet,
       -                "echoParam":   ReturnWhenSet,
       -                "safeHtml":    SafeHtml,
       -                "first":       First,
       -                "highlight":   Highlight,
       -                "add":         func(a, b int) int { return a + b },
       -                "sub":         func(a, b int) int { return a - b },
       -                "div":         func(a, b int) int { return a / b },
       -                "mod":         func(a, b int) int { return a % b },
       -                "mul":         func(a, b int) int { return a * b },
       -                "modBool":     func(a, b int) bool { return a%b == 0 },
       -                "lower":       func(a string) string { return strings.ToLower(a) },
       -                "upper":       func(a string) string { return strings.ToUpper(a) },
       -                "title":       func(a string) string { return strings.Title(a) },
       -        }
       -
       -        templates.Funcs(funcMap)
       -
       -        templates.LoadEmbedded()
       -        return templates
       -}
       -
       -func (t *GoHtmlTemplate) LoadEmbedded() {
       -        t.EmbedShortcodes()
       -        t.EmbedTemplates()
       -}
       -
       -func (t *GoHtmlTemplate) AddInternalTemplate(prefix, name, tpl string) error {
       -        return t.AddTemplate("_internal/"+prefix+"/"+name, tpl)
       -}
       -
       -func (t *GoHtmlTemplate) AddInternalShortcode(name, content string) error {
       -        return t.AddInternalTemplate("shortcodes", name, content)
       -}
       -
       -func (t *GoHtmlTemplate) AddTemplate(name, tpl string) error {
       -        _, err := t.New(name).Parse(tpl)
       -        if err != nil {
       -                t.errors = append(t.errors, &templateErr{name: name, err: err})
       -        }
       -        return err
       -}
       -
       -func (t *GoHtmlTemplate) AddTemplateFile(name, path string) error {
       -        b, err := ioutil.ReadFile(path)
       -        if err != nil {
       -                return err
       -        }
       -        return t.AddTemplate(name, string(b))
       -}
       -
       -func (t *GoHtmlTemplate) generateTemplateNameFrom(base, path string) string {
       -        return filepath.ToSlash(path[len(base)+1:])
       -}
       -
       -func ignoreDotFile(path string) bool {
       -        return filepath.Base(path)[0] == '.'
       -}
       -
       -func (t *GoHtmlTemplate) loadTemplates(absPath string, prefix string) {
       -        walker := func(path string, fi os.FileInfo, err error) error {
       -                if err != nil {
       -                        return nil
       -                }
       -
       -                if !fi.IsDir() {
       -                        if ignoreDotFile(path) {
       -                                return nil
       -                        }
       -
       -                        tplName := t.generateTemplateNameFrom(absPath, path)
       -
       -                        if prefix != "" {
       -                                tplName = strings.Trim(prefix, "/") + "/" + tplName
       -                        }
       -
       -                        // TODO move this into the AddTemplateFile function
       -                        if strings.HasSuffix(path, ".amber") {
       -                                compiler := amber.New()
       -                                // Parse the input file
       -                                if err := compiler.ParseFile(path); err != nil {
       -                                        return nil
       -                                }
       -
       -                                if _, err := compiler.CompileWithTemplate(t.New(tplName)); err != nil {
       -                                        return err
       -                                }
       -
       -                        } else {
       -                                t.AddTemplateFile(tplName, path)
       -                        }
       -                }
       -                return nil
       -        }
       -
       -        filepath.Walk(absPath, walker)
       -}
       -
       -func (t *GoHtmlTemplate) LoadTemplatesWithPrefix(absPath string, prefix string) {
       -        t.loadTemplates(absPath, prefix)
       -}
       -
       -func (t *GoHtmlTemplate) LoadTemplates(absPath string) {
       -        t.loadTemplates(absPath, "")
       -}
 (DIR) diff --git a/template/bundle/template_test.go b/template/bundle/template_test.go
       @@ -1,55 +0,0 @@
       -package bundle
       -
       -import (
       -        "reflect"
       -        "testing"
       -)
       -
       -func TestGt(t *testing.T) {
       -        for i, this := range []struct {
       -                left          interface{}
       -                right         interface{}
       -                leftShouldWin bool
       -        }{
       -                {5, 8, false},
       -                {8, 5, true},
       -                {5, 5, false},
       -                {-2, 1, false},
       -                {2, -5, true},
       -                {"8", "5", true},
       -                {"5", "0001", true},
       -                {[]int{100, 99}, []int{1, 2, 3, 4}, false},
       -        } {
       -                leftIsBigger := Gt(this.left, this.right)
       -                if leftIsBigger != this.leftShouldWin {
       -                        var which string
       -                        if leftIsBigger {
       -                                which = "expected right to be bigger, but left was"
       -                        } else {
       -                                which = "expected left to be bigger, but right was"
       -                        }
       -                        t.Errorf("[%d] %v compared to %v: %s", i, this.left, this.right, which)
       -                }
       -        }
       -}
       -
       -func TestFirst(t *testing.T) {
       -        for i, this := range []struct {
       -                count    int
       -                sequence interface{}
       -                expect   interface{}
       -        }{
       -                {2, []string{"a", "b", "c"}, []string{"a", "b"}},
       -                {3, []string{"a", "b"}, []string{"a", "b"}},
       -                {2, []int{100, 200, 300}, []int{100, 200}},
       -        } {
       -                results, err := First(this.count, this.sequence)
       -                if err != nil {
       -                        t.Errorf("[%d] failed: %s", i, err)
       -                        continue
       -                }
       -                if !reflect.DeepEqual(results, this.expect) {
       -                        t.Errorf("[%d] First %d items, got %v but expected %v", i, this.count, results, this.expect)
       -                }
       -        }
       -}