689 lines
		
	
	
		
			23 KiB
		
	
	
	
		
			Lua
		
	
	
	
	
	
		
		
			
		
	
	
			689 lines
		
	
	
		
			23 KiB
		
	
	
	
		
			Lua
		
	
	
	
	
	
| 
								 | 
							
								local setmetatable = setmetatable
							 | 
						||
| 
								 | 
							
								local loadstring = loadstring
							 | 
						||
| 
								 | 
							
								local tostring = tostring
							 | 
						||
| 
								 | 
							
								local setfenv = setfenv
							 | 
						||
| 
								 | 
							
								local require = require
							 | 
						||
| 
								 | 
							
								local concat = table.concat
							 | 
						||
| 
								 | 
							
								local assert = assert
							 | 
						||
| 
								 | 
							
								local write = io.write
							 | 
						||
| 
								 | 
							
								local pcall = pcall
							 | 
						||
| 
								 | 
							
								local phase
							 | 
						||
| 
								 | 
							
								local open = io.open
							 | 
						||
| 
								 | 
							
								local load = load
							 | 
						||
| 
								 | 
							
								local type = type
							 | 
						||
| 
								 | 
							
								local dump = string.dump
							 | 
						||
| 
								 | 
							
								local find = string.find
							 | 
						||
| 
								 | 
							
								local gsub = string.gsub
							 | 
						||
| 
								 | 
							
								local byte = string.byte
							 | 
						||
| 
								 | 
							
								local null
							 | 
						||
| 
								 | 
							
								local sub = string.sub
							 | 
						||
| 
								 | 
							
								local ngx = ngx
							 | 
						||
| 
								 | 
							
								local jit = jit
							 | 
						||
| 
								 | 
							
								local var
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								local _VERSION = _VERSION
							 | 
						||
| 
								 | 
							
								local _ENV = _ENV -- luacheck: globals _ENV
							 | 
						||
| 
								 | 
							
								local _G = _G
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								local HTML_ENTITIES = {
							 | 
						||
| 
								 | 
							
								    ["&"] = "&",
							 | 
						||
| 
								 | 
							
								    ["<"] = "<",
							 | 
						||
| 
								 | 
							
								    [">"] = ">",
							 | 
						||
| 
								 | 
							
								    ['"'] = """,
							 | 
						||
| 
								 | 
							
								    ["'"] = "'",
							 | 
						||
| 
								 | 
							
								    ["/"] = "/"
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								local CODE_ENTITIES = {
							 | 
						||
| 
								 | 
							
								    ["{"] = "{",
							 | 
						||
| 
								 | 
							
								    ["}"] = "}",
							 | 
						||
| 
								 | 
							
								    ["&"] = "&",
							 | 
						||
| 
								 | 
							
								    ["<"] = "<",
							 | 
						||
| 
								 | 
							
								    [">"] = ">",
							 | 
						||
| 
								 | 
							
								    ['"'] = """,
							 | 
						||
| 
								 | 
							
								    ["'"] = "'",
							 | 
						||
| 
								 | 
							
								    ["/"] = "/"
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								local VAR_PHASES
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								local ESC    = byte("\27")
							 | 
						||
| 
								 | 
							
								local NUL    = byte("\0")
							 | 
						||
| 
								 | 
							
								local HT     = byte("\t")
							 | 
						||
| 
								 | 
							
								local VT     = byte("\v")
							 | 
						||
| 
								 | 
							
								local LF     = byte("\n")
							 | 
						||
| 
								 | 
							
								local SOL    = byte("/")
							 | 
						||
| 
								 | 
							
								local BSOL   = byte("\\")
							 | 
						||
| 
								 | 
							
								local SP     = byte(" ")
							 | 
						||
| 
								 | 
							
								local AST    = byte("*")
							 | 
						||
| 
								 | 
							
								local NUM    = byte("#")
							 | 
						||
| 
								 | 
							
								local LPAR   = byte("(")
							 | 
						||
| 
								 | 
							
								local LSQB   = byte("[")
							 | 
						||
| 
								 | 
							
								local LCUB   = byte("{")
							 | 
						||
| 
								 | 
							
								local MINUS  = byte("-")
							 | 
						||
| 
								 | 
							
								local PERCNT = byte("%")
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								local EMPTY  = ""
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								local VIEW_ENV
							 | 
						||
| 
								 | 
							
								if _VERSION == "Lua 5.1" then
							 | 
						||
| 
								 | 
							
								    VIEW_ENV = { __index = function(t, k)
							 | 
						||
| 
								 | 
							
								        return t.context[k] or t.template[k] or _G[k]
							 | 
						||
| 
								 | 
							
								    end }
							 | 
						||
| 
								 | 
							
								else
							 | 
						||
| 
								 | 
							
								    VIEW_ENV = { __index = function(t, k)
							 | 
						||
| 
								 | 
							
								        return t.context[k] or t.template[k] or _ENV[k]
							 | 
						||
| 
								 | 
							
								    end }
							 | 
						||
| 
								 | 
							
								end
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								local newtab
							 | 
						||
| 
								 | 
							
								do
							 | 
						||
| 
								 | 
							
								    local ok
							 | 
						||
| 
								 | 
							
								    ok, newtab = pcall(require, "table.new")
							 | 
						||
| 
								 | 
							
								    if not ok then newtab = function() return {} end end
							 | 
						||
| 
								 | 
							
								end
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								local function enabled(val)
							 | 
						||
| 
								 | 
							
								    if val == nil then return true end
							 | 
						||
| 
								 | 
							
								    return val == true or (val == "1" or val == "true" or val == "on")
							 | 
						||
| 
								 | 
							
								end
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								local function trim(s)
							 | 
						||
| 
								 | 
							
								    return gsub(gsub(s, "^%s+", EMPTY), "%s+$", EMPTY)
							 | 
						||
| 
								 | 
							
								end
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								local function rpos(view, s)
							 | 
						||
| 
								 | 
							
								    while s > 0 do
							 | 
						||
| 
								 | 
							
								        local c = byte(view, s, s)
							 | 
						||
| 
								 | 
							
								        if c == SP or c == HT or c == VT or c == NUL then
							 | 
						||
| 
								 | 
							
								            s = s - 1
							 | 
						||
| 
								 | 
							
								        else
							 | 
						||
| 
								 | 
							
								            break
							 | 
						||
| 
								 | 
							
								        end
							 | 
						||
| 
								 | 
							
								    end
							 | 
						||
| 
								 | 
							
								    return s
							 | 
						||
| 
								 | 
							
								end
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								local function escaped(view, s)
							 | 
						||
| 
								 | 
							
								    if s > 1 and byte(view, s - 1, s - 1) == BSOL then
							 | 
						||
| 
								 | 
							
								        if s > 2 and byte(view, s - 2, s - 2) == BSOL then
							 | 
						||
| 
								 | 
							
								            return false, 1
							 | 
						||
| 
								 | 
							
								        else
							 | 
						||
| 
								 | 
							
								            return true, 1
							 | 
						||
| 
								 | 
							
								        end
							 | 
						||
| 
								 | 
							
								    end
							 | 
						||
| 
								 | 
							
								    return false, 0
							 | 
						||
| 
								 | 
							
								end
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								local function read_file(path)
							 | 
						||
| 
								 | 
							
								    local file, err = open(path, "rb")
							 | 
						||
| 
								 | 
							
								    if not file then return nil, err end
							 | 
						||
| 
								 | 
							
								    local content
							 | 
						||
| 
								 | 
							
								    content, err = file:read "*a"
							 | 
						||
| 
								 | 
							
								    file:close()
							 | 
						||
| 
								 | 
							
								    return content, err
							 | 
						||
| 
								 | 
							
								end
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								local print_view
							 | 
						||
| 
								 | 
							
								local load_view
							 | 
						||
| 
								 | 
							
								if ngx then
							 | 
						||
| 
								 | 
							
								    print_view = ngx.print or write
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    var = ngx.var
							 | 
						||
| 
								 | 
							
								    null = ngx.null
							 | 
						||
| 
								 | 
							
								    phase = ngx.get_phase
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    VAR_PHASES = {
							 | 
						||
| 
								 | 
							
								        set           = true,
							 | 
						||
| 
								 | 
							
								        rewrite       = true,
							 | 
						||
| 
								 | 
							
								        access        = true,
							 | 
						||
| 
								 | 
							
								        content       = true,
							 | 
						||
| 
								 | 
							
								        header_filter = true,
							 | 
						||
| 
								 | 
							
								        body_filter   = true,
							 | 
						||
| 
								 | 
							
								        log           = true,
							 | 
						||
| 
								 | 
							
								        preread       = true
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    local capture = ngx.location.capture
							 | 
						||
| 
								 | 
							
								    local prefix = ngx.config.prefix()
							 | 
						||
| 
								 | 
							
								    load_view = function(template)
							 | 
						||
| 
								 | 
							
								        return function(view, plain)
							 | 
						||
| 
								 | 
							
								            if plain == true then return view end
							 | 
						||
| 
								 | 
							
								            local vars = VAR_PHASES[phase()]
							 | 
						||
| 
								 | 
							
								            local path = view
							 | 
						||
| 
								 | 
							
								            local root = template.location
							 | 
						||
| 
								 | 
							
								            if (not root or root == EMPTY) and vars then
							 | 
						||
| 
								 | 
							
								                root = var.template_location
							 | 
						||
| 
								 | 
							
								            end
							 | 
						||
| 
								 | 
							
								            if root and root ~= EMPTY then
							 | 
						||
| 
								 | 
							
								                if byte(root, -1) == SOL then root = sub(root, 1, -2) end
							 | 
						||
| 
								 | 
							
								                if byte(path,  1) == SOL then path = sub(path, 2) end
							 | 
						||
| 
								 | 
							
								                path = root .. "/" .. path
							 | 
						||
| 
								 | 
							
								                local res = capture(path)
							 | 
						||
| 
								 | 
							
								                if res.status == 200 then return res.body end
							 | 
						||
| 
								 | 
							
								            end
							 | 
						||
| 
								 | 
							
								            path = view
							 | 
						||
| 
								 | 
							
								            root = template.root
							 | 
						||
| 
								 | 
							
								            if (not root or root == EMPTY) and vars then
							 | 
						||
| 
								 | 
							
								                root = var.template_root
							 | 
						||
| 
								 | 
							
								                if not root or root == EMPTY then root = var.document_root or prefix end
							 | 
						||
| 
								 | 
							
								            end
							 | 
						||
| 
								 | 
							
								            if root and root ~= EMPTY then
							 | 
						||
| 
								 | 
							
								                if byte(root, -1) == SOL then root = sub(root, 1, -2) end
							 | 
						||
| 
								 | 
							
								                if byte(path,  1) == SOL then path = sub(path, 2) end
							 | 
						||
| 
								 | 
							
								                path = root .. "/" .. path
							 | 
						||
| 
								 | 
							
								            end
							 | 
						||
| 
								 | 
							
								            return plain == false and assert(read_file(path)) or read_file(path) or view
							 | 
						||
| 
								 | 
							
								        end
							 | 
						||
| 
								 | 
							
								    end
							 | 
						||
| 
								 | 
							
								else
							 | 
						||
| 
								 | 
							
								    print_view = write
							 | 
						||
| 
								 | 
							
								    load_view = function(template)
							 | 
						||
| 
								 | 
							
								        return function(view, plain)
							 | 
						||
| 
								 | 
							
								            if plain == true then return view end
							 | 
						||
| 
								 | 
							
								            local path, root = view, template.root
							 | 
						||
| 
								 | 
							
								            if root and root ~= EMPTY then
							 | 
						||
| 
								 | 
							
								                if byte(root, -1) == SOL then root = sub(root, 1, -2) end
							 | 
						||
| 
								 | 
							
								                if byte(view,  1) == SOL then path = sub(view, 2) end
							 | 
						||
| 
								 | 
							
								                path = root .. "/" .. path
							 | 
						||
| 
								 | 
							
								            end
							 | 
						||
| 
								 | 
							
								            return plain == false and assert(read_file(path)) or read_file(path) or view
							 | 
						||
| 
								 | 
							
								        end
							 | 
						||
| 
								 | 
							
								    end
							 | 
						||
| 
								 | 
							
								end
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								local function load_file(func)
							 | 
						||
| 
								 | 
							
								    return function(view) return func(view, false) end
							 | 
						||
| 
								 | 
							
								end
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								local function load_string(func)
							 | 
						||
| 
								 | 
							
								    return function(view) return func(view, true) end
							 | 
						||
| 
								 | 
							
								end
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								local loader
							 | 
						||
| 
								 | 
							
								if jit or _VERSION ~= "Lua 5.1" then
							 | 
						||
| 
								 | 
							
								    loader = function(template)
							 | 
						||
| 
								 | 
							
								        return function(view)
							 | 
						||
| 
								 | 
							
								            return assert(load(view, nil, nil, setmetatable({ template = template }, VIEW_ENV)))
							 | 
						||
| 
								 | 
							
								        end
							 | 
						||
| 
								 | 
							
								    end
							 | 
						||
| 
								 | 
							
								else
							 | 
						||
| 
								 | 
							
								    loader = function(template)
							 | 
						||
| 
								 | 
							
								        return function(view)
							 | 
						||
| 
								 | 
							
								            local func = assert(loadstring(view))
							 | 
						||
| 
								 | 
							
								            setfenv(func, setmetatable({ template = template }, VIEW_ENV))
							 | 
						||
| 
								 | 
							
								            return func
							 | 
						||
| 
								 | 
							
								        end
							 | 
						||
| 
								 | 
							
								    end
							 | 
						||
| 
								 | 
							
								end
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								local function visit(visitors, content, tag, name)
							 | 
						||
| 
								 | 
							
								    if not visitors then
							 | 
						||
| 
								 | 
							
								        return content
							 | 
						||
| 
								 | 
							
								    end
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    for i = 1, visitors.n do
							 | 
						||
| 
								 | 
							
								        content = visitors[i](content, tag, name)
							 | 
						||
| 
								 | 
							
								    end
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    return content
							 | 
						||
| 
								 | 
							
								end
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								local function new(template, safe)
							 | 
						||
| 
								 | 
							
								    template = template or newtab(0, 26)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    template._VERSION    = "2.0"
							 | 
						||
| 
								 | 
							
								    template.cache       = {}
							 | 
						||
| 
								 | 
							
								    template.load        = load_view(template)
							 | 
						||
| 
								 | 
							
								    template.load_file   = load_file(template.load)
							 | 
						||
| 
								 | 
							
								    template.load_string = load_string(template.load)
							 | 
						||
| 
								 | 
							
								    template.print       = print_view
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    local load_chunk = loader(template)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    local caching
							 | 
						||
| 
								 | 
							
								    if VAR_PHASES and VAR_PHASES[phase()] then
							 | 
						||
| 
								 | 
							
								        caching = enabled(var.template_cache)
							 | 
						||
| 
								 | 
							
								    else
							 | 
						||
| 
								 | 
							
								        caching = true
							 | 
						||
| 
								 | 
							
								    end
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    local visitors
							 | 
						||
| 
								 | 
							
								    function template.visit(func)
							 | 
						||
| 
								 | 
							
								        if not visitors then
							 | 
						||
| 
								 | 
							
								            visitors = { func, n = 1 }
							 | 
						||
| 
								 | 
							
								            return
							 | 
						||
| 
								 | 
							
								        end
							 | 
						||
| 
								 | 
							
								        visitors.n = visitors.n + 1
							 | 
						||
| 
								 | 
							
								        visitors[visitors.n] = func
							 | 
						||
| 
								 | 
							
								    end
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    function template.caching(enable)
							 | 
						||
| 
								 | 
							
								        if enable ~= nil then caching = enable == true end
							 | 
						||
| 
								 | 
							
								        return caching
							 | 
						||
| 
								 | 
							
								    end
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    function template.output(s)
							 | 
						||
| 
								 | 
							
								        if s == nil or s == null then return EMPTY end
							 | 
						||
| 
								 | 
							
								        if type(s) == "function" then return template.output(s()) end
							 | 
						||
| 
								 | 
							
								        return tostring(s)
							 | 
						||
| 
								 | 
							
								    end
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    function template.escape(s, c)
							 | 
						||
| 
								 | 
							
								        if type(s) == "string" then
							 | 
						||
| 
								 | 
							
								            if c then return gsub(s, "[}{\">/<'&]", CODE_ENTITIES) end
							 | 
						||
| 
								 | 
							
								            return gsub(s, "[\">/<'&]", HTML_ENTITIES)
							 | 
						||
| 
								 | 
							
								        end
							 | 
						||
| 
								 | 
							
								        return template.output(s)
							 | 
						||
| 
								 | 
							
								    end
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    function template.new(view, layout)
							 | 
						||
| 
								 | 
							
								        local vt = type(view)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        if vt == "boolean" then return new(nil,  view) end
							 | 
						||
| 
								 | 
							
								        if vt == "table"   then return new(view, safe) end
							 | 
						||
| 
								 | 
							
								        if vt == "nil"     then return new(nil,  safe) end
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        local render
							 | 
						||
| 
								 | 
							
								        local process
							 | 
						||
| 
								 | 
							
								        if layout then
							 | 
						||
| 
								 | 
							
								            if type(layout) == "table" then
							 | 
						||
| 
								 | 
							
								                render = function(self, context)
							 | 
						||
| 
								 | 
							
								                    context = context or self
							 | 
						||
| 
								 | 
							
								                    context.blocks = context.blocks or {}
							 | 
						||
| 
								 | 
							
								                    context.view = function(ctx) return template.process(view, ctx or context) end
							 | 
						||
| 
								 | 
							
								                    layout.blocks = context.blocks or {}
							 | 
						||
| 
								 | 
							
								                    layout.view = context.view or EMPTY
							 | 
						||
| 
								 | 
							
								                    layout:render()
							 | 
						||
| 
								 | 
							
								                end
							 | 
						||
| 
								 | 
							
								                process = function(self, context)
							 | 
						||
| 
								 | 
							
								                    context = context or self
							 | 
						||
| 
								 | 
							
								                    context.blocks = context.blocks or {}
							 | 
						||
| 
								 | 
							
								                    context.view = function(ctx) return template.process(view, ctx or context) end
							 | 
						||
| 
								 | 
							
								                    layout.blocks = context.blocks or {}
							 | 
						||
| 
								 | 
							
								                    layout.view = context.view
							 | 
						||
| 
								 | 
							
								                    return tostring(layout)
							 | 
						||
| 
								 | 
							
								                end
							 | 
						||
| 
								 | 
							
								            else
							 | 
						||
| 
								 | 
							
								                render = function(self, context)
							 | 
						||
| 
								 | 
							
								                    context = context or self
							 | 
						||
| 
								 | 
							
								                    context.blocks = context.blocks or {}
							 | 
						||
| 
								 | 
							
								                    context.view = function(ctx) return template.process(view, ctx or context) end
							 | 
						||
| 
								 | 
							
								                    template.render(layout, context)
							 | 
						||
| 
								 | 
							
								                end
							 | 
						||
| 
								 | 
							
								                process = function(self, context)
							 | 
						||
| 
								 | 
							
								                    context = context or self
							 | 
						||
| 
								 | 
							
								                    context.blocks = context.blocks or {}
							 | 
						||
| 
								 | 
							
								                    context.view = function(ctx) return template.process(view, ctx or context) end
							 | 
						||
| 
								 | 
							
								                    return template.process(layout, context)
							 | 
						||
| 
								 | 
							
								                end
							 | 
						||
| 
								 | 
							
								            end
							 | 
						||
| 
								 | 
							
								        else
							 | 
						||
| 
								 | 
							
								            render = function(self, context)
							 | 
						||
| 
								 | 
							
								                return template.render(view, context or self)
							 | 
						||
| 
								 | 
							
								            end
							 | 
						||
| 
								 | 
							
								            process = function(self, context)
							 | 
						||
| 
								 | 
							
								                return template.process(view, context or self)
							 | 
						||
| 
								 | 
							
								            end
							 | 
						||
| 
								 | 
							
								        end
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        if safe then
							 | 
						||
| 
								 | 
							
								            return setmetatable({
							 | 
						||
| 
								 | 
							
								                render = function(...)
							 | 
						||
| 
								 | 
							
								                    local ok, err = pcall(render, ...)
							 | 
						||
| 
								 | 
							
								                    if not ok then
							 | 
						||
| 
								 | 
							
								                        return nil, err
							 | 
						||
| 
								 | 
							
								                    end
							 | 
						||
| 
								 | 
							
								                end,
							 | 
						||
| 
								 | 
							
								                process = function(...)
							 | 
						||
| 
								 | 
							
								                    local ok, output = pcall(process, ...)
							 | 
						||
| 
								 | 
							
								                    if not ok then
							 | 
						||
| 
								 | 
							
								                        return nil, output
							 | 
						||
| 
								 | 
							
								                    end
							 | 
						||
| 
								 | 
							
								                    return output
							 | 
						||
| 
								 | 
							
								                end,
							 | 
						||
| 
								 | 
							
								             }, {
							 | 
						||
| 
								 | 
							
								                __tostring = function(...)
							 | 
						||
| 
								 | 
							
								                    local ok, output = pcall(process, ...)
							 | 
						||
| 
								 | 
							
								                    if not ok then
							 | 
						||
| 
								 | 
							
								                        return ""
							 | 
						||
| 
								 | 
							
								                    end
							 | 
						||
| 
								 | 
							
								                    return output
							 | 
						||
| 
								 | 
							
								            end })
							 | 
						||
| 
								 | 
							
								        end
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        return setmetatable({
							 | 
						||
| 
								 | 
							
								            render = render,
							 | 
						||
| 
								 | 
							
								            process = process
							 | 
						||
| 
								 | 
							
								        }, {
							 | 
						||
| 
								 | 
							
								            __tostring = process
							 | 
						||
| 
								 | 
							
								        })
							 | 
						||
| 
								 | 
							
								    end
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    function template.precompile(view, path, strip, plain)
							 | 
						||
| 
								 | 
							
								        local chunk = dump(template.compile(view, nil, plain), strip ~= false)
							 | 
						||
| 
								 | 
							
								        if path then
							 | 
						||
| 
								 | 
							
								            local file = open(path, "wb")
							 | 
						||
| 
								 | 
							
								            file:write(chunk)
							 | 
						||
| 
								 | 
							
								            file:close()
							 | 
						||
| 
								 | 
							
								        end
							 | 
						||
| 
								 | 
							
								        return chunk
							 | 
						||
| 
								 | 
							
								    end
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    function template.precompile_string(view, path, strip)
							 | 
						||
| 
								 | 
							
								        return template.precompile(view, path, strip, true)
							 | 
						||
| 
								 | 
							
								    end
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    function template.precompile_file(view, path, strip)
							 | 
						||
| 
								 | 
							
								        return template.precompile(view, path, strip, false)
							 | 
						||
| 
								 | 
							
								    end
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    function template.compile(view, cache_key, plain)
							 | 
						||
| 
								 | 
							
								        assert(view, "view was not provided for template.compile(view, cache_key, plain)")
							 | 
						||
| 
								 | 
							
								        if cache_key == "no-cache" then
							 | 
						||
| 
								 | 
							
								            return load_chunk(template.parse(view, plain)), false
							 | 
						||
| 
								 | 
							
								        end
							 | 
						||
| 
								 | 
							
								        cache_key = cache_key or view
							 | 
						||
| 
								 | 
							
								        local cache = template.cache
							 | 
						||
| 
								 | 
							
								        if cache[cache_key] then return cache[cache_key], true end
							 | 
						||
| 
								 | 
							
								        local func = load_chunk(template.parse(view, plain))
							 | 
						||
| 
								 | 
							
								        if caching then cache[cache_key] = func end
							 | 
						||
| 
								 | 
							
								        return func, false
							 | 
						||
| 
								 | 
							
								    end
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    function template.compile_file(view, cache_key)
							 | 
						||
| 
								 | 
							
								        return template.compile(view, cache_key, false)
							 | 
						||
| 
								 | 
							
								    end
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    function template.compile_string(view, cache_key)
							 | 
						||
| 
								 | 
							
								        return template.compile(view, cache_key, true)
							 | 
						||
| 
								 | 
							
								    end
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    function template.parse(view, plain)
							 | 
						||
| 
								 | 
							
								        assert(view, "view was not provided for template.parse(view, plain)")
							 | 
						||
| 
								 | 
							
								        if plain ~= true then
							 | 
						||
| 
								 | 
							
								            view = template.load(view, plain)
							 | 
						||
| 
								 | 
							
								            if byte(view, 1, 1) == ESC then return view end
							 | 
						||
| 
								 | 
							
								        end
							 | 
						||
| 
								 | 
							
								        local j = 2
							 | 
						||
| 
								 | 
							
								        local c = {[[
							 | 
						||
| 
								 | 
							
								context=... or {}
							 | 
						||
| 
								 | 
							
								local ___,blocks,layout={},blocks or {}
							 | 
						||
| 
								 | 
							
								local function include(v, c) return template.process(v, c or context) end
							 | 
						||
| 
								 | 
							
								local function echo(...) for i=1,select("#", ...) do ___[#___+1] = tostring(select(i, ...)) end end
							 | 
						||
| 
								 | 
							
								]] }
							 | 
						||
| 
								 | 
							
								        local i, s = 1, find(view, "{", 1, true)
							 | 
						||
| 
								 | 
							
								        while s do
							 | 
						||
| 
								 | 
							
								            local t, p = byte(view, s + 1, s + 1), s + 2
							 | 
						||
| 
								 | 
							
								            if t == LCUB then
							 | 
						||
| 
								 | 
							
								                local e = find(view, "}}", p, true)
							 | 
						||
| 
								 | 
							
								                if e then
							 | 
						||
| 
								 | 
							
								                    local z, w = escaped(view, s)
							 | 
						||
| 
								 | 
							
								                    if i < s - w then
							 | 
						||
| 
								 | 
							
								                        c[j] = "___[#___+1]=[=[\n"
							 | 
						||
| 
								 | 
							
								                        c[j+1] = visit(visitors, sub(view, i, s - 1 - w))
							 | 
						||
| 
								 | 
							
								                        c[j+2] = "]=]\n"
							 | 
						||
| 
								 | 
							
								                        j=j+3
							 | 
						||
| 
								 | 
							
								                    end
							 | 
						||
| 
								 | 
							
								                    if z then
							 | 
						||
| 
								 | 
							
								                        i = s
							 | 
						||
| 
								 | 
							
								                    else
							 | 
						||
| 
								 | 
							
								                        c[j] = "___[#___+1]=template.escape("
							 | 
						||
| 
								 | 
							
								                        c[j+1] = visit(visitors, trim(sub(view, p, e - 1)), "{")
							 | 
						||
| 
								 | 
							
								                        c[j+2] = ")\n"
							 | 
						||
| 
								 | 
							
								                        j=j+3
							 | 
						||
| 
								 | 
							
								                        s, i = e + 1, e + 2
							 | 
						||
| 
								 | 
							
								                    end
							 | 
						||
| 
								 | 
							
								                end
							 | 
						||
| 
								 | 
							
								            elseif t == AST then
							 | 
						||
| 
								 | 
							
								                local e = find(view, "*}", p, true)
							 | 
						||
| 
								 | 
							
								                if e then
							 | 
						||
| 
								 | 
							
								                    local z, w = escaped(view, s)
							 | 
						||
| 
								 | 
							
								                    if i < s - w then
							 | 
						||
| 
								 | 
							
								                        c[j] = "___[#___+1]=[=[\n"
							 | 
						||
| 
								 | 
							
								                        c[j+1] = visit(visitors, sub(view, i, s - 1 - w))
							 | 
						||
| 
								 | 
							
								                        c[j+2] = "]=]\n"
							 | 
						||
| 
								 | 
							
								                        j=j+3
							 | 
						||
| 
								 | 
							
								                    end
							 | 
						||
| 
								 | 
							
								                    if z then
							 | 
						||
| 
								 | 
							
								                        i = s
							 | 
						||
| 
								 | 
							
								                    else
							 | 
						||
| 
								 | 
							
								                        c[j] = "___[#___+1]=template.output("
							 | 
						||
| 
								 | 
							
								                        c[j+1] = visit(visitors, trim(sub(view, p, e - 1)), "*")
							 | 
						||
| 
								 | 
							
								                        c[j+2] = ")\n"
							 | 
						||
| 
								 | 
							
								                        j=j+3
							 | 
						||
| 
								 | 
							
								                        s, i = e + 1, e + 2
							 | 
						||
| 
								 | 
							
								                    end
							 | 
						||
| 
								 | 
							
								                end
							 | 
						||
| 
								 | 
							
								            elseif t == PERCNT then
							 | 
						||
| 
								 | 
							
								                local e = find(view, "%}", p, true)
							 | 
						||
| 
								 | 
							
								                if e then
							 | 
						||
| 
								 | 
							
								                    local z, w = escaped(view, s)
							 | 
						||
| 
								 | 
							
								                    if z then
							 | 
						||
| 
								 | 
							
								                        if i < s - w then
							 | 
						||
| 
								 | 
							
								                            c[j] = "___[#___+1]=[=[\n"
							 | 
						||
| 
								 | 
							
								                            c[j+1] = visit(visitors, sub(view, i, s - 1 - w))
							 | 
						||
| 
								 | 
							
								                            c[j+2] = "]=]\n"
							 | 
						||
| 
								 | 
							
								                            j=j+3
							 | 
						||
| 
								 | 
							
								                        end
							 | 
						||
| 
								 | 
							
								                        i = s
							 | 
						||
| 
								 | 
							
								                    else
							 | 
						||
| 
								 | 
							
								                        local n = e + 2
							 | 
						||
| 
								 | 
							
								                        if byte(view, n, n) == LF then
							 | 
						||
| 
								 | 
							
								                            n = n + 1
							 | 
						||
| 
								 | 
							
								                        end
							 | 
						||
| 
								 | 
							
								                        local r = rpos(view, s - 1)
							 | 
						||
| 
								 | 
							
								                        if i <= r then
							 | 
						||
| 
								 | 
							
								                            c[j] = "___[#___+1]=[=[\n"
							 | 
						||
| 
								 | 
							
								                            c[j+1] = visit(visitors, sub(view, i, r))
							 | 
						||
| 
								 | 
							
								                            c[j+2] = "]=]\n"
							 | 
						||
| 
								 | 
							
								                            j=j+3
							 | 
						||
| 
								 | 
							
								                        end
							 | 
						||
| 
								 | 
							
								                        c[j] = visit(visitors, trim(sub(view, p, e - 1)), "%")
							 | 
						||
| 
								 | 
							
								                        c[j+1] = "\n"
							 | 
						||
| 
								 | 
							
								                        j=j+2
							 | 
						||
| 
								 | 
							
								                        s, i = n - 1, n
							 | 
						||
| 
								 | 
							
								                    end
							 | 
						||
| 
								 | 
							
								                end
							 | 
						||
| 
								 | 
							
								            elseif t == LPAR then
							 | 
						||
| 
								 | 
							
								                local e = find(view, ")}", p, true)
							 | 
						||
| 
								 | 
							
								                if e then
							 | 
						||
| 
								 | 
							
								                    local z, w = escaped(view, s)
							 | 
						||
| 
								 | 
							
								                    if i < s - w then
							 | 
						||
| 
								 | 
							
								                        c[j] = "___[#___+1]=[=[\n"
							 | 
						||
| 
								 | 
							
								                        c[j+1] = visit(visitors, sub(view, i, s - 1 - w))
							 | 
						||
| 
								 | 
							
								                        c[j+2] = "]=]\n"
							 | 
						||
| 
								 | 
							
								                        j=j+3
							 | 
						||
| 
								 | 
							
								                    end
							 | 
						||
| 
								 | 
							
								                    if z then
							 | 
						||
| 
								 | 
							
								                        i = s
							 | 
						||
| 
								 | 
							
								                    else
							 | 
						||
| 
								 | 
							
								                        local f = visit(visitors, sub(view, p, e - 1), "(")
							 | 
						||
| 
								 | 
							
								                        local x = find(f, ",", 2, true)
							 | 
						||
| 
								 | 
							
								                        if x then
							 | 
						||
| 
								 | 
							
								                            c[j] = "___[#___+1]=include([=["
							 | 
						||
| 
								 | 
							
								                            c[j+1] = trim(sub(f, 1, x - 1))
							 | 
						||
| 
								 | 
							
								                            c[j+2] = "]=],"
							 | 
						||
| 
								 | 
							
								                            c[j+3] = trim(sub(f, x + 1))
							 | 
						||
| 
								 | 
							
								                            c[j+4] = ")\n"
							 | 
						||
| 
								 | 
							
								                            j=j+5
							 | 
						||
| 
								 | 
							
								                        else
							 | 
						||
| 
								 | 
							
								                            c[j] = "___[#___+1]=include([=["
							 | 
						||
| 
								 | 
							
								                            c[j+1] = trim(f)
							 | 
						||
| 
								 | 
							
								                            c[j+2] = "]=])\n"
							 | 
						||
| 
								 | 
							
								                            j=j+3
							 | 
						||
| 
								 | 
							
								                        end
							 | 
						||
| 
								 | 
							
								                        s, i = e + 1, e + 2
							 | 
						||
| 
								 | 
							
								                    end
							 | 
						||
| 
								 | 
							
								                end
							 | 
						||
| 
								 | 
							
								            elseif t == LSQB then
							 | 
						||
| 
								 | 
							
								                local e = find(view, "]}", p, true)
							 | 
						||
| 
								 | 
							
								                if e then
							 | 
						||
| 
								 | 
							
								                    local z, w = escaped(view, s)
							 | 
						||
| 
								 | 
							
								                    if i < s - w then
							 | 
						||
| 
								 | 
							
								                        c[j] = "___[#___+1]=[=[\n"
							 | 
						||
| 
								 | 
							
								                        c[j+1] = visit(visitors, sub(view, i, s - 1 - w))
							 | 
						||
| 
								 | 
							
								                        c[j+2] = "]=]\n"
							 | 
						||
| 
								 | 
							
								                        j=j+3
							 | 
						||
| 
								 | 
							
								                    end
							 | 
						||
| 
								 | 
							
								                    if z then
							 | 
						||
| 
								 | 
							
								                        i = s
							 | 
						||
| 
								 | 
							
								                    else
							 | 
						||
| 
								 | 
							
								                        c[j] = "___[#___+1]=include("
							 | 
						||
| 
								 | 
							
								                        c[j+1] = visit(visitors, trim(sub(view, p, e - 1)), "[")
							 | 
						||
| 
								 | 
							
								                        c[j+2] = ")\n"
							 | 
						||
| 
								 | 
							
								                        j=j+3
							 | 
						||
| 
								 | 
							
								                        s, i = e + 1, e + 2
							 | 
						||
| 
								 | 
							
								                    end
							 | 
						||
| 
								 | 
							
								                end
							 | 
						||
| 
								 | 
							
								            elseif t == MINUS then
							 | 
						||
| 
								 | 
							
								                local e = find(view, "-}", p, true)
							 | 
						||
| 
								 | 
							
								                if e then
							 | 
						||
| 
								 | 
							
								                    local x, y = find(view, sub(view, s, e + 1), e + 2, true)
							 | 
						||
| 
								 | 
							
								                    if x then
							 | 
						||
| 
								 | 
							
								                        local z, w = escaped(view, s)
							 | 
						||
| 
								 | 
							
								                        if z then
							 | 
						||
| 
								 | 
							
								                            if i < s - w then
							 | 
						||
| 
								 | 
							
								                                c[j] = "___[#___+1]=[=[\n"
							 | 
						||
| 
								 | 
							
								                                c[j+1] = visit(visitors, sub(view, i, s - 1 - w))
							 | 
						||
| 
								 | 
							
								                                c[j+2] = "]=]\n"
							 | 
						||
| 
								 | 
							
								                                j=j+3
							 | 
						||
| 
								 | 
							
								                            end
							 | 
						||
| 
								 | 
							
								                            i = s
							 | 
						||
| 
								 | 
							
								                        else
							 | 
						||
| 
								 | 
							
								                            y = y + 1
							 | 
						||
| 
								 | 
							
								                            x = x - 1
							 | 
						||
| 
								 | 
							
								                            if byte(view, y, y) == LF then
							 | 
						||
| 
								 | 
							
								                                y = y + 1
							 | 
						||
| 
								 | 
							
								                            end
							 | 
						||
| 
								 | 
							
								                            local b = trim(sub(view, p, e - 1))
							 | 
						||
| 
								 | 
							
								                            if b == "verbatim" or b == "raw" then
							 | 
						||
| 
								 | 
							
								                                if i < s - w then
							 | 
						||
| 
								 | 
							
								                                    c[j] = "___[#___+1]=[=[\n"
							 | 
						||
| 
								 | 
							
								                                    c[j+1] = visit(visitors, sub(view, i, s - 1 - w))
							 | 
						||
| 
								 | 
							
								                                    c[j+2] = "]=]\n"
							 | 
						||
| 
								 | 
							
								                                    j=j+3
							 | 
						||
| 
								 | 
							
								                                end
							 | 
						||
| 
								 | 
							
								                                c[j] = "___[#___+1]=[=["
							 | 
						||
| 
								 | 
							
								                                c[j+1] = visit(visitors, sub(view, e + 2, x))
							 | 
						||
| 
								 | 
							
								                                c[j+2] = "]=]\n"
							 | 
						||
| 
								 | 
							
								                                j=j+3
							 | 
						||
| 
								 | 
							
								                            else
							 | 
						||
| 
								 | 
							
								                                if byte(view, x, x) == LF then
							 | 
						||
| 
								 | 
							
								                                    x = x - 1
							 | 
						||
| 
								 | 
							
								                                end
							 | 
						||
| 
								 | 
							
								                                local r = rpos(view, s - 1)
							 | 
						||
| 
								 | 
							
								                                if i <= r then
							 | 
						||
| 
								 | 
							
								                                    c[j] = "___[#___+1]=[=[\n"
							 | 
						||
| 
								 | 
							
								                                    c[j+1] = visit(visitors, sub(view, i, r))
							 | 
						||
| 
								 | 
							
								                                    c[j+2] = "]=]\n"
							 | 
						||
| 
								 | 
							
								                                    j=j+3
							 | 
						||
| 
								 | 
							
								                                end
							 | 
						||
| 
								 | 
							
								                                c[j] = 'blocks["'
							 | 
						||
| 
								 | 
							
								                                c[j+1] = b
							 | 
						||
| 
								 | 
							
								                                c[j+2] = '"]=include[=['
							 | 
						||
| 
								 | 
							
								                                c[j+3] = visit(visitors, sub(view, e + 2, x), "-", b)
							 | 
						||
| 
								 | 
							
								                                c[j+4] = "]=]\n"
							 | 
						||
| 
								 | 
							
								                                j=j+5
							 | 
						||
| 
								 | 
							
								                            end
							 | 
						||
| 
								 | 
							
								                            s, i = y - 1, y
							 | 
						||
| 
								 | 
							
								                        end
							 | 
						||
| 
								 | 
							
								                    end
							 | 
						||
| 
								 | 
							
								                end
							 | 
						||
| 
								 | 
							
								            elseif t == NUM then
							 | 
						||
| 
								 | 
							
								                local e = find(view, "#}", p, true)
							 | 
						||
| 
								 | 
							
								                if e then
							 | 
						||
| 
								 | 
							
								                    local z, w = escaped(view, s)
							 | 
						||
| 
								 | 
							
								                    if i < s - w then
							 | 
						||
| 
								 | 
							
								                        c[j] = "___[#___+1]=[=[\n"
							 | 
						||
| 
								 | 
							
								                        c[j+1] = visit(visitors, sub(view, i, s - 1 - w))
							 | 
						||
| 
								 | 
							
								                        c[j+2] = "]=]\n"
							 | 
						||
| 
								 | 
							
								                        j=j+3
							 | 
						||
| 
								 | 
							
								                    end
							 | 
						||
| 
								 | 
							
								                    if z then
							 | 
						||
| 
								 | 
							
								                        i = s
							 | 
						||
| 
								 | 
							
								                    else
							 | 
						||
| 
								 | 
							
								                        e = e + 2
							 | 
						||
| 
								 | 
							
								                        if byte(view, e, e) == LF then
							 | 
						||
| 
								 | 
							
								                            e = e + 1
							 | 
						||
| 
								 | 
							
								                        end
							 | 
						||
| 
								 | 
							
								                        s, i = e - 1, e
							 | 
						||
| 
								 | 
							
								                    end
							 | 
						||
| 
								 | 
							
								                end
							 | 
						||
| 
								 | 
							
								            end
							 | 
						||
| 
								 | 
							
								            s = find(view, "{", s + 1, true)
							 | 
						||
| 
								 | 
							
								        end
							 | 
						||
| 
								 | 
							
								        s = sub(view, i)
							 | 
						||
| 
								 | 
							
								        if s and s ~= EMPTY then
							 | 
						||
| 
								 | 
							
								            c[j] = "___[#___+1]=[=[\n"
							 | 
						||
| 
								 | 
							
								            c[j+1] = visit(visitors, s)
							 | 
						||
| 
								 | 
							
								            c[j+2] = "]=]\n"
							 | 
						||
| 
								 | 
							
								            j=j+3
							 | 
						||
| 
								 | 
							
								        end
							 | 
						||
| 
								 | 
							
								        c[j] = "return layout and include(layout,setmetatable({view=table.concat(___),blocks=blocks},{__index=context})) or table.concat(___)" -- luacheck: ignore
							 | 
						||
| 
								 | 
							
								        return concat(c)
							 | 
						||
| 
								 | 
							
								    end
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    function template.parse_file(view)
							 | 
						||
| 
								 | 
							
								        return template.parse(view, false)
							 | 
						||
| 
								 | 
							
								    end
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    function template.parse_string(view)
							 | 
						||
| 
								 | 
							
								        return template.parse(view, true)
							 | 
						||
| 
								 | 
							
								    end
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    function template.process(view, context, cache_key, plain)
							 | 
						||
| 
								 | 
							
								        assert(view, "view was not provided for template.process(view, context, cache_key, plain)")
							 | 
						||
| 
								 | 
							
								        return template.compile(view, cache_key, plain)(context)
							 | 
						||
| 
								 | 
							
								    end
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    function template.process_file(view, context, cache_key)
							 | 
						||
| 
								 | 
							
								        assert(view, "view was not provided for template.process_file(view, context, cache_key)")
							 | 
						||
| 
								 | 
							
								        return template.compile(view, cache_key, false)(context)
							 | 
						||
| 
								 | 
							
								    end
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    function template.process_string(view, context, cache_key)
							 | 
						||
| 
								 | 
							
								        assert(view, "view was not provided for template.process_string(view, context, cache_key)")
							 | 
						||
| 
								 | 
							
								        return template.compile(view, cache_key, true)(context)
							 | 
						||
| 
								 | 
							
								    end
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    function template.render(view, context, cache_key, plain)
							 | 
						||
| 
								 | 
							
								        assert(view, "view was not provided for template.render(view, context, cache_key, plain)")
							 | 
						||
| 
								 | 
							
								        template.print(template.process(view, context, cache_key, plain))
							 | 
						||
| 
								 | 
							
								    end
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    function template.render_file(view, context, cache_key)
							 | 
						||
| 
								 | 
							
								        assert(view, "view was not provided for template.render_file(view, context, cache_key)")
							 | 
						||
| 
								 | 
							
								        template.render(view, context, cache_key, false)
							 | 
						||
| 
								 | 
							
								    end
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    function template.render_string(view, context, cache_key)
							 | 
						||
| 
								 | 
							
								        assert(view, "view was not provided for template.render_string(view, context, cache_key)")
							 | 
						||
| 
								 | 
							
								        template.render(view, context, cache_key, true)
							 | 
						||
| 
								 | 
							
								    end
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    if safe then
							 | 
						||
| 
								 | 
							
								        return setmetatable({}, {
							 | 
						||
| 
								 | 
							
								            __index = function(_, k)
							 | 
						||
| 
								 | 
							
								                if type(template[k]) == "function" then
							 | 
						||
| 
								 | 
							
								                    return function(...)
							 | 
						||
| 
								 | 
							
								                        local ok, a, b = pcall(template[k], ...)
							 | 
						||
| 
								 | 
							
								                        if not ok then
							 | 
						||
| 
								 | 
							
								                            return nil, a
							 | 
						||
| 
								 | 
							
								                        end
							 | 
						||
| 
								 | 
							
								                        return a, b
							 | 
						||
| 
								 | 
							
								                    end
							 | 
						||
| 
								 | 
							
								                end
							 | 
						||
| 
								 | 
							
								                return template[k]
							 | 
						||
| 
								 | 
							
								            end,
							 | 
						||
| 
								 | 
							
								            __new_index = function(_, k, v)
							 | 
						||
| 
								 | 
							
								                template[k] = v
							 | 
						||
| 
								 | 
							
								            end,
							 | 
						||
| 
								 | 
							
								        })
							 | 
						||
| 
								 | 
							
								    end
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    return template
							 | 
						||
| 
								 | 
							
								end
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								return new()
							 |