func BuildCommentsWidget(cnf Mapper, topCtx mustache.Context) (Widget, error) { log.Println("Comments >>", cnf.Layout()) switch cnf.Layout() { case "disqus": disqus := cnf[cnf.Layout()].(map[string]interface{}) short_name := disqus["short_name"] if short_name == nil { return nil, errors.New("CommentsWidget Of disqus need short_name") } self := make(CommentsWidget) self["comments"] = fmt.Sprintf(Comments_disqus, short_name) return self, nil case "uyan": uyan := cnf[cnf.Layout()].(map[string]interface{}) uid := uyan["uid"] self := make(CommentsWidget) self["comments"] = fmt.Sprintf(tpl_uyan, uid) return self, nil case "duoshuo": duoshuo := cnf[cnf.Layout()].(map[string]interface{}) short_name := duoshuo["short_name"] if short_name == nil { return nil, errors.New("CommentsWidget Of duoshuo need short_name") } self := make(CommentsWidget) self["comments"] = fmt.Sprintf(Comments_duoshuo, short_name) return self, nil } // 其他的,想不到还有啥,哈哈,需要其他的就报个issue吧 return nil, errors.New("CommentsWidget Only for disqus yet") }
func BuildAnalyticsWidget(cnf Mapper, topCtx mustache.Context) (Widget, error) { switch cnf.Layout() { case "google": // 鼎鼎大名的免费,但有点拖慢加载速度,原因你懂的 google := cnf[cnf.Layout()].(map[string]interface{}) tracking_id := google["tracking_id"] if tracking_id == nil { return nil, errors.New("AnalyticsWidget Of Google need tracking_id") } self := make(AnalyticsWidget) self["analytics"] = fmt.Sprintf(Analytics_google, tracking_id) return self, nil case "cnzz": //免费,而且很快,但强制嵌入一个反向链接,靠! cnzz := cnf[cnf.Layout()].(map[string]interface{}) tracking_id := cnzz["tracking_id"] if tracking_id == nil { return nil, errors.New("AnalyticsWidget Of CNZZ need tracking_id") } self := make(AnalyticsWidget) self["analytics"] = fmt.Sprintf(tpl_cnzz, tracking_id, tracking_id) return self, nil } // 其他的尚不支持, 如果需要,请报个issue吧 return nil, errors.New("AnalyticsWidget Only for Goolge/CNZZ yet") }
func BuildCustomWidget(name string, dir string, cnf Mapper) (Widget, []string, error) { layoutName, ok := cnf["layout"] if !ok || layoutName == "" { log.Println("Skip Widget : " + dir) return nil, nil, nil } layoutFilePath := dir + "/layouts/" + layoutName.(string) + ".html" f, err := os.Open(layoutFilePath) if err != nil { return nil, nil, errors.New("Fail to load Widget Layout" + dir + "\n" + err.Error()) } defer f.Close() cont, err := ioutil.ReadAll(f) if err != nil { return nil, nil, errors.New("Fail to load Widget Layout" + dir + "\n" + err.Error()) } assets := []string{} for _, js := range cnf.GetStrings("javascripts") { path := "/assets/" + dir + "/javascripts/" + js assets = append(assets, fmt.Sprintf("<script type=\"text/javascript\" src=\"%s\"></script>", path)) } for _, css := range cnf.GetStrings("stylesheets") { path2 := "/assets/" + dir + "/stylesheets/" + css assets = append(assets, fmt.Sprintf("<link href=\"%s\" type=\"text/css\" rel=\"stylesheet\" media=\"all\">", path2)) } return &CustomWidget{name, &DocContent{string(cont), string(cont), nil}, cnf}, assets, nil }
func parseLanguageAbility(req *http.Request) ([]db.LanguageAbility, error) { var languages []db.LanguageAbility rawJson := req.FormValue("langAbilities") if len(rawJson) == 0 { return languages, errors.New("No argument") } decoder := json.NewDecoder(strings.NewReader(rawJson)) if _, e := decoder.Token(); e != nil { //The first array bracket return languages, errors.New("Wrong json format") } element := RawLang{} for decoder.More() { if e := decoder.Decode(&element); e != nil { continue } if len(element.Abilities) < 4 { continue } lang := db.LanguageAbility{ Name: element.LangName, Listening: uint(element.Abilities[0].Value), Speaking: uint(element.Abilities[1].Value), Reading: uint(element.Abilities[2].Value), Writing: uint(element.Abilities[3].Value), } languages = append(languages, lang) } decoder.Token() //The last array bracket return languages, nil }
func GetSessionUserPermission(req *http.Request) (UserPermission, error) { if v, err := GetUserSessionValue(req, USER_PERMISSION_SESSION_KEY); err != nil || v == nil { return UserPermission(0), errors.New("Invalid session key") } else { if perm, found := v.(UserPermission); found { return perm, nil } else { return UserPermission(0), errors.New("Invalid session permission format") } } }
func BuildCommentsWidget(cnf Mapper, topCtx mustache.Context) (Widget, error) { if cnf.Layout() != "disqus" { return nil, errors.New("CommentsWidget Only for disqus yet") } disqus := cnf[cnf.Layout()].(map[string]interface{}) short_name := disqus["short_name"] if short_name == nil { return nil, errors.New("CommentsWidget Of disqus need short_name") } self := make(CommentsWidget) self["comments"] = fmt.Sprintf(Comments_disqus, short_name) return self, nil }
func BuildAnalyticsWidget(cnf Mapper, topCtx mustache.Context) (Widget, error) { if cnf.Layout() != "google" { return nil, errors.New("AnalyticsWidget Only for Goolge yet") } google := cnf[cnf.Layout()].(map[string]interface{}) tracking_id := google["tracking_id"] if tracking_id == nil { return nil, errors.New("AnalyticsWidget Of Google need tracking_id") } self := make(AnalyticsWidget) self["analytics"] = fmt.Sprintf(Analytics_google, tracking_id) return self, nil }
func GetSessionGMId(req *http.Request) (bson.ObjectId, error) { if v, err := GetGMSessionValue(req, GM_ID_SESSION_KEY); err != nil || v == nil { return bson.ObjectId(""), errors.New("Invalid session id format") } else { if str, found := v.(string); found { if bson.IsObjectIdHex(str) { return bson.ObjectIdHex(str), nil } else { return bson.ObjectId(""), errors.New("Invalid session id format") } } else { return bson.ObjectId(""), errors.New("Invalid session id format") } } }
func parseTopic(req *http.Request) (uint, error) { for i, v := range TOPICS { if len(req.FormValue(v)) == 0 { continue } return uint(i), nil } return 1, errors.New("Not Found") }
func parseSchoolGrade(req *http.Request) (string, error) { gradeType := req.FormValue("gradeType") schoolGrade := req.FormValue("schoolGrade") var numGrade int if n, _ := fmt.Sscanf(schoolGrade, "%d", &numGrade); n < 1 || numGrade < 0 { return "", errors.New("Invalid Grade") } return fmt.Sprintf("%s@%d", gradeType, numGrade), nil }
func SetGMSessionValue(req *http.Request, resp http.ResponseWriter, key, value interface{}) error { //Ignore the error since sometimes the browser side coolie storage is broken //But we still can assign new cookies s, _ := SessionStorage.Get(req, GM_AUTH_SESSION) if s == nil { return errors.New("Session " + GM_AUTH_SESSION + " not available") } s.Values[key] = value return s.Save(req, resp) }
func initStorage() { if !Config.IsSet("storage.serviceAccountEmail") || !Config.IsSet("storage.privateKeyPath") { panic(errors.New("storage.serviceAccountEmail or storage.privateKeyPath not set")) } StorageServiceAccountEmail = Config.GetString("storage.serviceAccountEmail") //LogD.Println("Service account: " + StorageServiceAccountEmail) privateKeyPath := Config.GetString("storage.privateKeyPath") if file, err := os.Open(privateKeyPath); err != nil { panic(errors.New("storage.privateKeyPath not exist")) } else { defer file.Close() if StoragePrivateKey, err = ioutil.ReadAll(file); err != nil { panic(errors.New("storage.privateKeyPath read file error")) } else { //LogD.Printf("Private key length: %d\n", len(StoragePrivateKey)) } } }
// 遍历目录,加载挂件 func LoadWidgets(topCtx mustache.Context) ([]Widget, string, error) { widgets := make([]Widget, 0) assets := "" err := filepath.Walk("widgets", func(path string, info os.FileInfo, err error) error { if err != nil { return nil } if !info.IsDir() { return nil } cnf_path := path + "/config.yml" fst, err := os.Stat(cnf_path) if err != nil || fst.IsDir() { return nil //ignore } cnf, err := ReadYml(cnf_path) if err != nil { return errors.New(cnf_path + ":" + err.Error()) } if cnf["layout"] != nil { widget_enable, ok := cnf["layout"].(bool) if ok && !widget_enable { log.Println("Disable >", cnf_path) } } builderFunc := WidgetBuilders[info.Name()] if builderFunc == nil { // 看看是否符合自定义挂件的格式 _widget, _assets, _err := BuildCustomWidget(info.Name(), path, cnf) if _err != nil { log.Println("NO WidgetBuilder >>", cnf_path, _err) } if _widget != nil { widgets = append(widgets, _widget) if _assets != nil { for _, asset := range _assets { assets += asset + "\n" } } } return nil } widget, err := builderFunc(cnf, topCtx) if err != nil { return err } widgets = append(widgets, widget) log.Println("Load widget from ", cnf_path) return nil }) return widgets, assets, err }
func GetSessionUserId(req *http.Request) (bson.ObjectId, error) { if data := req.Header.Get(GM_PERMITTED_HEADER_KEY); len(data) != 0 && bson.IsObjectIdHex(data) { //Controlled user id user_id := bson.ObjectIdHex(data) return user_id, nil } if v, err := GetUserSessionValue(req, USER_ID_SESSION_KEY); err != nil || v == nil { return bson.ObjectId(""), errors.New("Invalid session id format") } else { if str, found := v.(string); found { if bson.IsObjectIdHex(str) { return bson.ObjectIdHex(str), nil } else { return bson.ObjectId(""), errors.New("Invalid session id format") } } else { return bson.ObjectId(""), errors.New("Invalid session id format") } } }
func parseRecommendationLetters(req *http.Request) ([]public.BasicUser, error) { var letters []public.BasicUser rawJson := req.FormValue("recommendationLetters") if len(rawJson) == 0 { return letters, errors.New("No argument") } decoder := json.NewDecoder(strings.NewReader(rawJson)) if _, e := decoder.Token(); e != nil { //The first array bracket return letters, errors.New("Wrong json format") } element := public.BasicUser{} for decoder.More() { if e := decoder.Decode(&element); e != nil { continue } letters = append(letters, element) } decoder.Token() //The last array bracket return letters, nil }
func parseStudiedClasses(req *http.Request) ([]db.StudiedClass, error) { var classes []db.StudiedClass rawJson := req.FormValue("classHistory") if len(rawJson) == 0 { return classes, errors.New("No argument") } decoder := json.NewDecoder(strings.NewReader(rawJson)) if _, e := decoder.Token(); e != nil { //The first array bracket return classes, errors.New("Wrong json format") } element := db.StudiedClass{} for decoder.More() { if e := decoder.Decode(&element); e != nil { continue } classes = append(classes, element) } decoder.Token() //The last array bracket return classes, nil }
func RenderInLayout(content string, layoutName string, layouts map[string]Mapper, ctx mustache.Context) (string, error) { //log.Println("Render Layout", layoutName, ">>", content, "<<END") ctx2 := make(map[string]string) ctx2["content"] = content layout := layouts[layoutName] if layout == nil { return "", errors.New("Not such Layout : " + layoutName) } //log.Println(layoutName, layout["_content"]) buf := &bytes.Buffer{} err := layout["_content"].(*DocContent).TPL.Render(mustache.MakeContexts(ctx2, ctx), buf) if err != nil { return content, err } if layout.Layout() != "" { return RenderInLayout(buf.String(), layout.Layout(), layouts, ctx) } return buf.String(), nil }
func initRecommLetter() { RecommLetterSubject = `NTHU A+ Recommendation Request` recommLetterContentTmpl := ` Hi, This is NTHU A+ management team. {{.ApplyUser.Name}}({{.ApplyUser.Email}}) wanted to request for your recommendation in his/her application. If you know about this, please visit {{.RecommUrl}} to leave your recommendation. Best Regards, NTHU A+ management team http://www.nthuaplus.org ` var err error RecommLetterTmpl, err = template.New("recommLetter").Parse(recommLetterContentTmpl) if err != nil { panic(errors.New("Error parsing recommendation letter template: " + err.Error())) } }
func (y *yamlReader) ReadMap(minIndent int) (map[string]interface{}, error) { _map := map[string]interface{}{} //log.Println("ReadMap", minIndent) OUT: for { line, err := y.NextLine() if err != nil { return _map, err } indent, str := getIndent(line) //log.Printf("Indent : %d, str = %s", indent, str) switch { case indent < minIndent: y.lastLine = line if len(_map) == 0 { return nil, nil } return _map, nil case indent == minIndent: key, value, err := y.asMapKeyValue(str) if err != nil { return nil, err } //log.Println("Key=", key, "value=", value) switch value { case nil: return nil, y.Error("Unexpect", nil) case MAP_KEY_ONLY: //log.Println("KeyOnly, read inner Map", key) //-------------------------------------- _line, err := y.NextLine() if err != nil { if err == io.EOF { if _line == "" { // Emtry map item? _map[key.(string)] = nil return _map, err } } else { return nil, y.Error("ERR?", err) } } y.lastLine = _line _indent, _str := getIndent(_line) if _indent < minIndent { return _map, nil } ////log.Println("##>>", _indent, _str) if _indent == minIndent { if _str[0] == '-' { //log.Println("Read Same-Indent ListItem for Map") _list, err := y.ReadList(minIndent) if _list != nil { _map[key.(string)] = _list } if err != nil { return _map, nil } continue OUT } else { // Emtry map item? _map[key.(string)] = nil continue OUT } } //-------------------------------------- //log.Println("Read Map Item", _indent, _str) obj, err := y.ReadObject(_indent) if obj != nil { _map[key.(string)] = obj } if err != nil { return _map, err } default: _map[key.(string)] = value } default: //log.Println("Bad", indent, str) return nil, y.Error("Bad Indent\n"+line, nil) } } panic("ERROR") return nil, errors.New("Impossible") }
func (y *yamlReader) Error(msg string, err error) error { if err != nil { return errors.New(fmt.Sprintf("line %d : %s : %v", y.lineNum, msg, err.Error())) } return errors.New(fmt.Sprintf("line %d >> %s", y.lineNum, msg)) }
func (y *yamlReader) ReadList(minIndent int) ([]interface{}, error) { list := []interface{}{} for { line, err := y.NextLine() if err != nil { return list, err } indent, str := getIndent(line) switch { case indent < minIndent: y.lastLine = line if len(list) == 0 { return nil, nil } return list, nil case indent == minIndent: if str[0] != '-' { y.lastLine = line return list, nil } if len(str) < 2 { return nil, y.Error("ListItem is Emtry", nil) } key, value, err := y.asMapKeyValue(str[1:]) if err != nil { return nil, err } switch value { case nil: list = append(list, key) case MAP_KEY_ONLY: return nil, y.Error("Not support List-Map yet", nil) default: _map := map[string]interface{}{key.(string): value} list = append(list, _map) _line, _err := y.NextLine() if _err != nil && _err != io.EOF { return nil, err } if _line == "" { return list, nil } y.lastLine = _line _indent, _str := getIndent(line) if _indent >= minIndent+2 { switch _str[0] { case '-': return nil, y.Error("Unexpect", nil) case '[': return nil, y.Error("Unexpect", nil) case '{': return nil, y.Error("Unexpect", nil) } // look like a map _map2, _err := y.ReadMap(_indent) if _map2 != nil { _map2[key.(string)] = value } if err != nil { return list, _err } } } continue default: return nil, y.Error("Bad Indent\n"+line, nil) } } panic("ERROR") return nil, errors.New("Impossible") }
func Compile() error { var payload Mapper var ctx mustache.Context var docCont *DocContent //var tpl *mustache.Template var str string var err error //var mdParser *markdown.Parser //var buf *bytes.Buffer var layouts map[string]Mapper payload, err = BuildPlayload() if err != nil { return err } payload_ctx := mustache.MakeContextDir(payload, ".tmp_partials/") themeName := FromCtx(payload_ctx, "site.config.theme").(string) os.Remove(".tmp_partials") copyDir("partials", ".tmp_partials") copyDir("themes/"+themeName+"/partials", ".tmp_partials") db_posts_dict, _ := payload_ctx.Get("db.posts.dictionary") //log.Println(">>>>>>>>>>>>", len(db_posts_dict.Val.Interface().(map[string]Mapper))) for id, post := range db_posts_dict.Val.Interface().(map[string]Mapper) { _tmp, err := PrapreMainContent(id, post["_content"].(*DocContent).Source, payload_ctx) if err != nil { return err } post["_content"].(*DocContent).Main = _tmp //log.Fatal(_tmp) } //mdParser = markdown.NewParser(&markdown.Extensions{Smart: true}) helpers := make(map[string]mustache.SectionRenderFunc) ctxHelpers := make(map[string]func(interface{}) interface{}) dynamicCtx := make(Mapper) topCtx := mustache.MakeContexts(payload_ctx, helpers, ctxHelpers, map[string]Mapper{"dynamic": dynamicCtx}) widgets, widget_assets, err := LoadWidgets(topCtx) if err != nil { return err } //log.Println(">>>", payload_ctx.Dir(), "?>", topCtx.Dir()) BaiscHelpers(payload, helpers, topCtx) CtxHelpers(payload, ctxHelpers, topCtx) layouts = payload["layouts"].(map[string]Mapper) if len(widgets) > 0 { widget_assets += PrapareAssets(themeName, "widgets", topCtx) } CopyResources(themeName) // Render Pages pages := payload["db"].(map[string]interface{})["pages"].(map[string]Mapper) for id, page := range pages { docCont = page["_content"].(*DocContent) top := make(map[string]interface{}) top["current_page_id"] = id top["page"] = page top["assets"] = PrapareAssets(themeName, page.Layout(), topCtx) + widget_assets widgetCtx := PrapareWidgets(widgets, page, topCtx) ctx = mustache.MakeContexts(page, top, topCtx, widgetCtx) //log.Println(">>", ctx.Dir(), topCtx.Dir()) _tmp, err := PrapreMainContent(id, docCont.Source, ctx) if err != nil { return err } page["_content"].(*DocContent).Main = _tmp str, err = RenderInLayout(docCont.Main, page.Layout(), layouts, ctx) if err != nil { return errors.New(id + ">" + err.Error()) } WriteTo(page.Url(), str) } // Render Posts for id, post := range db_posts_dict.Val.Interface().(map[string]Mapper) { top := make(map[string]interface{}) top["current_page_id"] = id top["page"] = post top["assets"] = PrapareAssets(themeName, post.Layout(), topCtx) + widget_assets docCont = post["_content"].(*DocContent) widgetCtx := PrapareWidgets(widgets, post, topCtx) ctx = mustache.MakeContexts(post, top, topCtx, widgetCtx) str, err = RenderInLayout(docCont.Main, post.Layout(), layouts, ctx) if err != nil { return errors.New(id + ">" + err.Error()) } WriteTo(post.Url(), str) } if Plugins != nil { for _, plugin := range Plugins { plugin.Exec(topCtx) } } log.Println("Done") return nil }
// 编译整个网站 func Compile() error { var ctx mustache.Context // 渲染上下文 var docCont *DocContent // 文档内容,仅作为变量声明 var str string // 仅声明,以减少不一样的编译错误 var err error // 仅声明 var layouts map[string]Mapper payload, err := BuildPlayload("./") // payload,核心上下文的主要部分,不可变 if err != nil { log.Println("Build PayLoad FAIL!!") return err } payload_ctx := mustache.MakeContextDir(payload, ".tmp_partials/") themeName := FromCtx(payload_ctx, "site.config.theme").(string) if FromCtx(payload_ctx, "site.config.markdown.toc_title") != nil { TOC_TITLE = FromCtx(payload_ctx, "site.config.markdown.toc_title").(string) } os.Remove(".tmp_partials") copyDir("partials", ".tmp_partials") copyDir("themes/"+themeName+"/partials", ".tmp_partials") db_posts_dict, _ := payload_ctx.Get("db.posts.dictionary") //log.Println(">>>>>>>>>>>>", len(db_posts_dict.Val.Interface().(map[string]Mapper))) for id, post := range db_posts_dict.Val.Interface().(map[string]Mapper) { _tmp, err := PrapreMainContent(id, post["_content"].(*DocContent).Source, payload_ctx) if err != nil { return err } post["_content"].(*DocContent).Main = _tmp //log.Fatal(_tmp) } //mdParser = markdown.NewParser(&markdown.Extensions{Smart: true}) helpers := make(map[string]mustache.SectionRenderFunc) ctxHelpers := make(map[string]func(interface{}) interface{}) dynamicMapper := make(Mapper) topCtx := mustache.MakeContexts(payload_ctx, helpers, ctxHelpers, dynamicMapper) widgets, widget_assets, err := LoadWidgets(topCtx) if err != nil { return err } //log.Println(">>>", payload_ctx.Dir(), "?>", topCtx.Dir()) BaiscHelpers(payload, helpers, topCtx) CtxHelpers(payload, ctxHelpers, topCtx) layouts = payload["layouts"].(map[string]Mapper) if len(widgets) > 0 { widget_assets += PrapareAssets(themeName, "widgets", topCtx) } CopyResources(themeName) // Render Pages pages := payload["db"].(map[string]interface{})["pages"].(map[string]Mapper) for id, page := range pages { docCont = page["_content"].(*DocContent) //top := make(map[string]interface{}) dynamicMapper["current_page_id"] = id dynamicMapper["page"] = page dynamicMapper["assets"] = PrapareAssets(themeName, page.Layout(), topCtx) + widget_assets widgetCtx := PrapareWidgets(widgets, page, topCtx) ctx = mustache.MakeContexts(page, dynamicMapper, topCtx, widgetCtx) //log.Println(">>", ctx.Dir(), topCtx.Dir()) _tmp, err := PrapreMainContent(id, docCont.Source, ctx) if err != nil { return err } page["_content"].(*DocContent).Main = _tmp str, err = RenderInLayout(docCont.Main, page.Layout(), layouts, ctx) if err != nil { return errors.New(id + ">" + err.Error()) } WriteTo(page.Url(), str) } // Render Posts for id, post := range db_posts_dict.Val.Interface().(map[string]Mapper) { //top := make(map[string]interface{}) dynamicMapper["current_page_id"] = id dynamicMapper["page"] = post dynamicMapper["assets"] = PrapareAssets(themeName, post.Layout(), topCtx) + widget_assets docCont = post["_content"].(*DocContent) widgetCtx := PrapareWidgets(widgets, post, topCtx) ctx = mustache.MakeContexts(post, dynamicMapper, topCtx, widgetCtx) str, err = RenderInLayout(docCont.Main, post.Layout(), layouts, ctx) if err != nil { return errors.New(id + ">" + err.Error()) } WriteTo(post.Url(), str) } //我们还得把分页给解决了哦 if paginatorCnf := FromCtx(topCtx, "site.config.paginator"); paginatorCnf != nil { var pgCnf Mapper pgCnf = paginatorCnf.(map[string]interface{}) if _, ok := layouts[pgCnf.String("layout")]; ok { log.Println("Enable paginator") renderPaginator(pgCnf, layouts, topCtx, widgets) } else { log.Println("Layout Not Found", pgCnf.String("layout")) } } if Plugins != nil { for _, plugin := range Plugins { plugin.Exec(topCtx) } } log.Println("Done") return nil }
func Parse(r io.Reader) (*Template, error) { tpl := &Template{} tpl.Tree = make([]Node, 0) //var err error rd := bufio.NewReaderSize(r, 8192) lineNumber := -1 flag := true sections := make([]*SectionNode, 0) for flag { lineNumber++ line, err := rd.ReadString('\n') if err != nil { if err != io.EOF { return nil, err } flag = false } tags, err := parseLine(line, lineNumber) if err != nil { return nil, err } for _, _tag := range tags { //log.Printf(">>> %v", _tag) _ = log.Ldate if _tag.Type != T_CONS { _tag.Value = strings.Trim(_tag.Value, "\t\n ") } switch _tag.Type { case T_Comment: continue case T_Section: //log.Printf(">Section [%v] %v", _tag.Value, _tag.Flag) sec := &SectionNode{_tag.Value, _tag.Flag, make([]Node, 0)} if len(sections) == 0 { tpl.Tree = append(tpl.Tree, sec) //log.Printf("Tree Len=%v", len(tpl.Tree)) } else { sections[len(sections)-1].Clildren = append(sections[len(sections)-1].Clildren, sec) } sections = append(sections, sec) case T_End: if len(sections) == 0 || sections[len(sections)-1].name != _tag.Value { //log.Printf(">> %v", sections) return nil, errors.New("End TAG Invaild >>" + _tag.Value) } //log.Printf(">Section End [%v]", _tag.Value) sections = sections[:len(sections)-1] default: var node Node switch _tag.Type { case T_CONS: //log.Println("Cons ? --> " + _tag.Value) node = &ConstantNode{_tag.Value} case T_Val: node = &ValNode{_tag.Value, _tag.Flag} case T_Partial: node = &PartialNode{_tag.Value} } if len(sections) == 0 { tpl.Tree = append(tpl.Tree, node) } else { sections[len(sections)-1].Clildren = append(sections[len(sections)-1].Clildren, node) } } } } return tpl, nil }