<commit_before>package mains

import (
	"bufio"
	"bytes"
	"context"
	"errors"
	"fmt"
	"io/ioutil"
	"os"
	"strconv"
	"strings"
	"unicode"

	"github.com/zetamatta/go-ansicfile"

	"github.com/zetamatta/nyagos/alias"
	"github.com/zetamatta/nyagos/lua"
	"github.com/zetamatta/nyagos/shell"
)

type LuaBinaryChank struct {
	Chank []byte
}

func (this *LuaBinaryChank) String() string {
	return "(lua-function)"
}

func (this *LuaBinaryChank) Call(ctx context.Context, cmd *shell.Cmd) (int, error) {
	L, L_ok := cmd.Tag().(lua.Lua)
	if !L_ok {
		return 255, errors.New("LuaBinaryChank.Call: Lua instance not found")
	}

	if f := cmd.Out().(*os.File); f != os.Stdout && f != os.Stderr {
		L.GetGlobal("io")        // +1
		L.GetField(-1, "output") // +1 (get function pointer)
		if err := L.PushFileWriter(f); err != nil {
			L.Pop(2)
			return 255, err
		}
		L.Call(1, 0)
		L.Pop(1) // remove io-table
	}
	if f := cmd.In().(*os.File); f != os.Stdin {
		L.GetGlobal("io")       // +1
		L.GetField(-1, "input") // +1 (get function pointer)
		if err := L.PushFileReader(f); err != nil {
			L.Pop(2)
			return 255, err
		}
		L.Call(1, 0)
		L.Pop(1) // remove io-table
	}

	if err := L.LoadBufferX(cmd.Arg(0), this.Chank, "b"); err != nil {
		return 255, err
	}
	L.NewTable()
	for i, arg1 := range cmd.Args() {
		L.PushString(arg1)
		L.RawSetI(-2, lua.Integer(i))
	}
	L.NewTable()
	for i, arg1 := range cmd.RawArgs() {
		L.PushString(arg1)
		L.RawSetI(-2, lua.Integer(i))
	}
	L.SetField(-2, "rawargs")
	err := callLua(&cmd.Shell, 1, 1)
	errorlevel := 0
	if err == nil {
		newargs := make([]string, 0)
		if L.IsTable(-1) {
			L.PushInteger(0)
			L.GetTable(-2)
			if val, err1 := L.ToString(-1); val != "" && err1 == nil {
				newargs = append(newargs, val)
			}
			L.Pop(1)
			for i := 1; ; i++ {
				L.PushInteger(lua.Integer(i))
				L.GetTable(-2)
				if L.IsNil(-1) {
					L.Pop(1)
					break
				}
				val, err1 := L.ToString(-1)
				L.Pop(1)
				if err1 != nil {
					break
				}
				newargs = append(newargs, val)
			}
			it := cmd.Command()
			it.SetArgs(newargs)
			errorlevel, err = it.Spawnvp(ctx)
		} else if val, err1 := L.ToInteger(-1); err1 == nil {
			errorlevel = val
		} else if val, err1 := L.ToString(-1); val != "" && err1 == nil {
			errorlevel, err = cmd.InterpretContext(ctx, val)
		}
	}
	L.Pop(1)
	return errorlevel, err
}

func cmdSetAlias(L lua.Lua) int {
	name, nameErr := L.ToString(-2)
	if nameErr != nil {
		return L.Push(nil, nameErr.Error())
	}
	key := strings.ToLower(name)
	switch L.GetType(-1) {
	case lua.LUA_TSTRING:
		value, err := L.ToString(-1)
		if err == nil {
			alias.Table[key] = alias.New(value)
		} else {
			return L.Push(nil, err)
		}
	case lua.LUA_TFUNCTION:
		chank := L.Dump()
		alias.Table[key] = &LuaBinaryChank{Chank: chank}
	case lua.LUA_TNIL:
		delete(alias.Table, key)
	}
	return L.Push(true)
}

func cmdGetAlias(L lua.Lua) int {
	name, nameErr := L.ToString(-1)
	if nameErr != nil {
		return L.Push(nil, nameErr)
	}
	value, ok := alias.Table[name]
	if !ok {
		L.PushNil()
		return 1
	}
	switch v := value.(type) {
	case *LuaBinaryChank:
		if err := L.LoadBufferX(name, v.Chank, "b"); err != nil {
			return L.Push(nil, err.Error())
		}
	default:
		L.PushString(v.String())
	}
	return 1
}

func cmdExec(L lua.Lua) int {
	errorlevel := 0
	var err error
	if L.IsTable(1) {
		L.Len(1)
		n, _ := L.ToInteger(-1)
		L.Pop(1)
		args := make([]string, 0, n+1)
		for i := 0; i <= n; i++ {
			L.RawGetI(-1, lua.Integer(i))
			arg1, err := L.ToString(-1)
			if err == nil && arg1 != "" {
				args = append(args, arg1)
			}
			L.Pop(1)
		}
		sh := getRegInt(L)
		if sh == nil {
			println("main/lua_cmd.go: cmdExec: not found interpreter object")
			sh = shell.New()
			sh.SetTag(L)
		}
		cmd := sh.Command()
		cmd.SetArgs(args)
		errorlevel, err = cmd.Spawnvp(context.Background())
	} else {
		statement, statementErr := L.ToString(1)
		if statementErr != nil {
			return L.Push(nil, statementErr)
		}
		it := getRegInt(L)
		if it == nil {
			it = shell.New()
			it.SetTag(L)
		}
		errorlevel, err = it.Interpret(statement)
	}
	return L.Push(int(errorlevel), err)
}

func cmdEval(L lua.Lua) int {
	statement, statementErr := L.ToString(1)
	if statementErr != nil {
		return L.Push(nil, statementErr)
	}
	r, w, err := os.Pipe()
	if err != nil {
		return L.Push(nil, err)
	}
	go func(statement string, w *os.File) {
		it := shell.New()
		it.SetTag(L)
		it.Stdout = w
		it.Interpret(statement)
		w.Close()
	}(statement, w)

	result, err := ioutil.ReadAll(r)
	r.Close()
	if err == nil {
		L.PushBytes(bytes.Trim(result, "\r\n\t "))
	} else {
		L.PushNil()
	}
	return 1
}

func luaStackToSlice(L lua.Lua) []string {
	argc := L.GetTop()
	argv := make([]string, 0, argc)
	for i := 1; i <= argc; i++ {
		if L.IsTable(i) {
			L.Len(i)
			size, size_err := L.ToInteger(-1)
			L.Pop(1)
			if size_err == nil {
				// zero element
				L.RawGetI(i, 0)
				if s, err := L.ToString(-1); err == nil && s != "" {
					argv = append(argv, s)
				}
				L.Pop(1)
				// 1,2,3...
				for j := 1; j <= size; j++ {
					L.RawGetI(i, lua.Integer(j))
					if s, err := L.ToString(-1); err == nil {
						argv = append(argv, s)
					} else {
						argv = append(argv, "")
					}
					L.Pop(1)
				}
			}
		} else {
			s, s_err := L.ToString(i)
			if s_err != nil {
				s = ""
			}
			argv = append(argv, s)
		}
	}
	return argv
}

func cmdOpenFile(L lua.Lua) int {
	path, path_err := L.ToString(1)
	if path_err != nil {
		return L.Push(nil, path_err.Error())
	}
	mode, mode_err := L.ToString(2)
	if mode_err != nil {
		return L.Push(nil, mode_err.Error())
	}
	if mode == "" {
		mode = "r"
	}
	fd, fd_err := ansicfile.Open(path, mode)
	if fd_err != nil {
		// print("-- open '", path, "' failed --\n")
		return L.Push(nil, fd_err)
	}
	// print("-- open '", path, "' success --\n")
	L.PushStream(fd)
	return 1
}

func cmdLoadFile(L lua.Lua) int {
	path, path_err := L.ToString(-1)
	if path_err != nil {
		return L.Push(nil, path_err.Error())
	}
	_, err := L.LoadFile(path, "bt")
	if err != nil {
		return L.Push(nil, path+": "+err.Error())
	} else {
		return 1
	}
}

type iolines_t struct {
	Fd         *os.File
	Reader     *bufio.Reader
	Marks      []string
	HasToClose bool
}

func (this *iolines_t) Close() {
	this.Reader = nil
	if this.HasToClose {
		this.Fd.Close()
	}
	this.Fd = nil
}

func (this *iolines_t) Ok() bool {
	return this != nil && this.Fd != nil && this.Reader != nil
}

func iolines_t_gc(L lua.Lua) int {
	defer L.DeleteUserDataAnchor(1)
	userdata := iolines_t{}
	sync := L.ToUserDataTo(1, &userdata)
	defer sync()
	// print("iolines_t_gc: gc\n")
	if !userdata.Ok() {
		// print("iolines_t_gc: nil\n")
		return 0
	}
	userdata.Close()
	return 0
}

func cmdLinesCallback(L lua.Lua) int {
	userdata := iolines_t{}
	sync := L.ToUserDataTo(1, &userdata)
	defer sync()

	if !userdata.Ok() {
		// print("cmdLinesCallback: nil\n")
		return L.Push(nil)
	}
	count := 0
	var err error

	for _, mark := range userdata.Marks {
		if err != nil {
			break
		}
		if unicode.IsDigit(rune(mark[0])) {
			var nbytes int
			nbytes, err = strconv.Atoi(mark)
			if err != nil {
				break
			}
			line := make([]byte, nbytes)
			var nreads int
			nreads, err = userdata.Reader.Read(line)
			if nreads > 0 {
				if nreads < nbytes {
					L.PushBytes(line[:nreads])
				} else {
					L.PushBytes(line)
				}
				count++
			}
			break
		}
		switch mark {
		default:
			var line []byte
			line, err = userdata.Reader.ReadBytes('\n')
			if err != nil {
				break
			}
			if mark != "L" {
				line = bytes.TrimRight(line, "\r\n")
			}
			L.PushBytes(line)
			count++
			break
		case "a":
			var data []byte
			data, err = ioutil.ReadAll(userdata.Reader)
			if err != nil || len(data) <= 0 {
				userdata.Close()
				return L.Push(nil)
			}
			L.PushBytes(data)
			count++
			break
		case "n":
			var val int
			if _, err := fmt.Fscan(userdata.Reader, &val); err != nil {
				userdata.Close()
				return L.Push(nil)
			} else {
				L.PushInteger(lua.Integer(val))
				count++
				break
			}
		}
	}
	if err != nil {
		// print("cmdLinesCallback: eof\n")
		userdata.Close()
		return L.Push(nil)
	}
	// print("cmdLinesCallback: text='", text, "'\n")
	return count
}

func cmdLines(L lua.Lua) int {
	top := L.GetTop()
	if top < 1 || L.IsNil(1) {
		L.Push(cmdLinesCallback)
		cmd := getRegInt(L)
		L.PushUserData(&iolines_t{
			Fd:         cmd.Stdin,
			Reader:     bufio.NewReader(cmd.Stdin),
			HasToClose: false,
			Marks:      []string{"l"},
		})
		L.NewTable()
		L.Push(iolines_t_gc)
		L.SetField(-2, "__gc")
		L.SetMetaTable(-2)
		return 2
	}
	path, path_err := L.ToString(1)
	if path_err != nil {
		return L.Push(nil, path_err.Error())
	}
	var marks []string
	if top < 2 {
		marks = []string{"l"}
	} else {
		marks = make([]string, 0, top-2)
		for i := 2; i <= top; i++ {
			mark1, err1 := L.ToString(i)
			if err1 != nil {
				return L.Push(nil, err1.Error())
			}
			marks = append(marks, mark1)
		}
	}
	fd, fd_err := os.Open(path)
	if fd_err != nil {
		return L.Push(nil, fd_err.Error())
	}
	L.Push(cmdLinesCallback)
	userdata := iolines_t{
		Fd:         fd,
		Reader:     bufio.NewReader(fd),
		Marks:      marks,
		HasToClose: true,
	}
	L.PushUserData(&userdata)
	L.NewTable()
	L.Push(iolines_t_gc)
	L.SetField(-2, "__gc")
	L.SetMetaTable(-2)
	// print("cmdLines: end\n")
	return 2
}
<commit_msg>(Remove unused function: mains.luaStackToSlice)<commit_after>package mains

import (
	"bufio"
	"bytes"
	"context"
	"errors"
	"fmt"
	"io/ioutil"
	"os"
	"strconv"
	"strings"
	"unicode"

	"github.com/zetamatta/go-ansicfile"

	"github.com/zetamatta/nyagos/alias"
	"github.com/zetamatta/nyagos/lua"
	"github.com/zetamatta/nyagos/shell"
)

type LuaBinaryChank struct {
	Chank []byte
}

func (this *LuaBinaryChank) String() string {
	return "(lua-function)"
}

func (this *LuaBinaryChank) Call(ctx context.Context, cmd *shell.Cmd) (int, error) {
	L, L_ok := cmd.Tag().(lua.Lua)
	if !L_ok {
		return 255, errors.New("LuaBinaryChank.Call: Lua instance not found")
	}

	if f := cmd.Out().(*os.File); f != os.Stdout && f != os.Stderr {
		L.GetGlobal("io")        // +1
		L.GetField(-1, "output") // +1 (get function pointer)
		if err := L.PushFileWriter(f); err != nil {
			L.Pop(2)
			return 255, err
		}
		L.Call(1, 0)
		L.Pop(1) // remove io-table
	}
	if f := cmd.In().(*os.File); f != os.Stdin {
		L.GetGlobal("io")       // +1
		L.GetField(-1, "input") // +1 (get function pointer)
		if err := L.PushFileReader(f); err != nil {
			L.Pop(2)
			return 255, err
		}
		L.Call(1, 0)
		L.Pop(1) // remove io-table
	}

	if err := L.LoadBufferX(cmd.Arg(0), this.Chank, "b"); err != nil {
		return 255, err
	}
	L.NewTable()
	for i, arg1 := range cmd.Args() {
		L.PushString(arg1)
		L.RawSetI(-2, lua.Integer(i))
	}
	L.NewTable()
	for i, arg1 := range cmd.RawArgs() {
		L.PushString(arg1)
		L.RawSetI(-2, lua.Integer(i))
	}
	L.SetField(-2, "rawargs")
	err := callLua(&cmd.Shell, 1, 1)
	errorlevel := 0
	if err == nil {
		newargs := make([]string, 0)
		if L.IsTable(-1) {
			L.PushInteger(0)
			L.GetTable(-2)
			if val, err1 := L.ToString(-1); val != "" && err1 == nil {
				newargs = append(newargs, val)
			}
			L.Pop(1)
			for i := 1; ; i++ {
				L.PushInteger(lua.Integer(i))
				L.GetTable(-2)
				if L.IsNil(-1) {
					L.Pop(1)
					break
				}
				val, err1 := L.ToString(-1)
				L.Pop(1)
				if err1 != nil {
					break
				}
				newargs = append(newargs, val)
			}
			it := cmd.Command()
			it.SetArgs(newargs)
			errorlevel, err = it.Spawnvp(ctx)
		} else if val, err1 := L.ToInteger(-1); err1 == nil {
			errorlevel = val
		} else if val, err1 := L.ToString(-1); val != "" && err1 == nil {
			errorlevel, err = cmd.InterpretContext(ctx, val)
		}
	}
	L.Pop(1)
	return errorlevel, err
}

func cmdSetAlias(L lua.Lua) int {
	name, nameErr := L.ToString(-2)
	if nameErr != nil {
		return L.Push(nil, nameErr.Error())
	}
	key := strings.ToLower(name)
	switch L.GetType(-1) {
	case lua.LUA_TSTRING:
		value, err := L.ToString(-1)
		if err == nil {
			alias.Table[key] = alias.New(value)
		} else {
			return L.Push(nil, err)
		}
	case lua.LUA_TFUNCTION:
		chank := L.Dump()
		alias.Table[key] = &LuaBinaryChank{Chank: chank}
	case lua.LUA_TNIL:
		delete(alias.Table, key)
	}
	return L.Push(true)
}

func cmdGetAlias(L lua.Lua) int {
	name, nameErr := L.ToString(-1)
	if nameErr != nil {
		return L.Push(nil, nameErr)
	}
	value, ok := alias.Table[name]
	if !ok {
		L.PushNil()
		return 1
	}
	switch v := value.(type) {
	case *LuaBinaryChank:
		if err := L.LoadBufferX(name, v.Chank, "b"); err != nil {
			return L.Push(nil, err.Error())
		}
	default:
		L.PushString(v.String())
	}
	return 1
}

func cmdExec(L lua.Lua) int {
	errorlevel := 0
	var err error
	if L.IsTable(1) {
		L.Len(1)
		n, _ := L.ToInteger(-1)
		L.Pop(1)
		args := make([]string, 0, n+1)
		for i := 0; i <= n; i++ {
			L.RawGetI(-1, lua.Integer(i))
			arg1, err := L.ToString(-1)
			if err == nil && arg1 != "" {
				args = append(args, arg1)
			}
			L.Pop(1)
		}
		sh := getRegInt(L)
		if sh == nil {
			println("main/lua_cmd.go: cmdExec: not found interpreter object")
			sh = shell.New()
			sh.SetTag(L)
		}
		cmd := sh.Command()
		cmd.SetArgs(args)
		errorlevel, err = cmd.Spawnvp(context.Background())
	} else {
		statement, statementErr := L.ToString(1)
		if statementErr != nil {
			return L.Push(nil, statementErr)
		}
		it := getRegInt(L)
		if it == nil {
			it = shell.New()
			it.SetTag(L)
		}
		errorlevel, err = it.Interpret(statement)
	}
	return L.Push(int(errorlevel), err)
}

func cmdEval(L lua.Lua) int {
	statement, statementErr := L.ToString(1)
	if statementErr != nil {
		return L.Push(nil, statementErr)
	}
	r, w, err := os.Pipe()
	if err != nil {
		return L.Push(nil, err)
	}
	go func(statement string, w *os.File) {
		it := shell.New()
		it.SetTag(L)
		it.Stdout = w
		it.Interpret(statement)
		w.Close()
	}(statement, w)

	result, err := ioutil.ReadAll(r)
	r.Close()
	if err == nil {
		L.PushBytes(bytes.Trim(result, "\r\n\t "))
	} else {
		L.PushNil()
	}
	return 1
}

func cmdOpenFile(L lua.Lua) int {
	path, path_err := L.ToString(1)
	if path_err != nil {
		return L.Push(nil, path_err.Error())
	}
	mode, mode_err := L.ToString(2)
	if mode_err != nil {
		return L.Push(nil, mode_err.Error())
	}
	if mode == "" {
		mode = "r"
	}
	fd, fd_err := ansicfile.Open(path, mode)
	if fd_err != nil {
		// print("-- open '", path, "' failed --\n")
		return L.Push(nil, fd_err)
	}
	// print("-- open '", path, "' success --\n")
	L.PushStream(fd)
	return 1
}

func cmdLoadFile(L lua.Lua) int {
	path, path_err := L.ToString(-1)
	if path_err != nil {
		return L.Push(nil, path_err.Error())
	}
	_, err := L.LoadFile(path, "bt")
	if err != nil {
		return L.Push(nil, path+": "+err.Error())
	} else {
		return 1
	}
}

type iolines_t struct {
	Fd         *os.File
	Reader     *bufio.Reader
	Marks      []string
	HasToClose bool
}

func (this *iolines_t) Close() {
	this.Reader = nil
	if this.HasToClose {
		this.Fd.Close()
	}
	this.Fd = nil
}

func (this *iolines_t) Ok() bool {
	return this != nil && this.Fd != nil && this.Reader != nil
}

func iolines_t_gc(L lua.Lua) int {
	defer L.DeleteUserDataAnchor(1)
	userdata := iolines_t{}
	sync := L.ToUserDataTo(1, &userdata)
	defer sync()
	// print("iolines_t_gc: gc\n")
	if !userdata.Ok() {
		// print("iolines_t_gc: nil\n")
		return 0
	}
	userdata.Close()
	return 0
}

func cmdLinesCallback(L lua.Lua) int {
	userdata := iolines_t{}
	sync := L.ToUserDataTo(1, &userdata)
	defer sync()

	if !userdata.Ok() {
		// print("cmdLinesCallback: nil\n")
		return L.Push(nil)
	}
	count := 0
	var err error

	for _, mark := range userdata.Marks {
		if err != nil {
			break
		}
		if unicode.IsDigit(rune(mark[0])) {
			var nbytes int
			nbytes, err = strconv.Atoi(mark)
			if err != nil {
				break
			}
			line := make([]byte, nbytes)
			var nreads int
			nreads, err = userdata.Reader.Read(line)
			if nreads > 0 {
				if nreads < nbytes {
					L.PushBytes(line[:nreads])
				} else {
					L.PushBytes(line)
				}
				count++
			}
			break
		}
		switch mark {
		default:
			var line []byte
			line, err = userdata.Reader.ReadBytes('\n')
			if err != nil {
				break
			}
			if mark != "L" {
				line = bytes.TrimRight(line, "\r\n")
			}
			L.PushBytes(line)
			count++
			break
		case "a":
			var data []byte
			data, err = ioutil.ReadAll(userdata.Reader)
			if err != nil || len(data) <= 0 {
				userdata.Close()
				return L.Push(nil)
			}
			L.PushBytes(data)
			count++
			break
		case "n":
			var val int
			if _, err := fmt.Fscan(userdata.Reader, &val); err != nil {
				userdata.Close()
				return L.Push(nil)
			} else {
				L.PushInteger(lua.Integer(val))
				count++
				break
			}
		}
	}
	if err != nil {
		// print("cmdLinesCallback: eof\n")
		userdata.Close()
		return L.Push(nil)
	}
	// print("cmdLinesCallback: text='", text, "'\n")
	return count
}

func cmdLines(L lua.Lua) int {
	top := L.GetTop()
	if top < 1 || L.IsNil(1) {
		L.Push(cmdLinesCallback)
		cmd := getRegInt(L)
		L.PushUserData(&iolines_t{
			Fd:         cmd.Stdin,
			Reader:     bufio.NewReader(cmd.Stdin),
			HasToClose: false,
			Marks:      []string{"l"},
		})
		L.NewTable()
		L.Push(iolines_t_gc)
		L.SetField(-2, "__gc")
		L.SetMetaTable(-2)
		return 2
	}
	path, path_err := L.ToString(1)
	if path_err != nil {
		return L.Push(nil, path_err.Error())
	}
	var marks []string
	if top < 2 {
		marks = []string{"l"}
	} else {
		marks = make([]string, 0, top-2)
		for i := 2; i <= top; i++ {
			mark1, err1 := L.ToString(i)
			if err1 != nil {
				return L.Push(nil, err1.Error())
			}
			marks = append(marks, mark1)
		}
	}
	fd, fd_err := os.Open(path)
	if fd_err != nil {
		return L.Push(nil, fd_err.Error())
	}
	L.Push(cmdLinesCallback)
	userdata := iolines_t{
		Fd:         fd,
		Reader:     bufio.NewReader(fd),
		Marks:      marks,
		HasToClose: true,
	}
	L.PushUserData(&userdata)
	L.NewTable()
	L.Push(iolines_t_gc)
	L.SetField(-2, "__gc")
	L.SetMetaTable(-2)
	// print("cmdLines: end\n")
	return 2
}
<|endoftext|>


<commit_before>package handler

import (
	"github.com/dinever/dingo/app/model"
	"github.com/dinever/dingo/app/utils"
	"github.com/dinever/golf"
	"github.com/twinj/uuid"
	"strconv"
	"time"
)

func AdminHandler(ctx *Golf.Context) {
	user := ctx.Data["user"].(*model.User)
	ctx.Loader("admin").Render("home.html", map[string]interface{}{
		"Title":    "Dashboard",
		"Statis":   model.NewStatis(),
		"User":     user,
		"Messages": model.GetUnreadMessages(),
		"Monitor":  utils.ReadMemStats(),
	})
}

func ProfileHandler(ctx *Golf.Context) {
	user := ctx.Data["user"].(*model.User)
	ctx.Loader("admin").Render("profile.html", map[string]interface{}{
		"Title": "Profile",
		"User":  user,
	})
}

func ProfileChangeHandler(ctx *Golf.Context) {
	user := ctx.Data["user"].(*model.User)
	if user.Email != ctx.Request.FormValue("email") && !model.UserChangeEmail(ctx.Request.FormValue("email")) {
		ctx.JSON(map[string]interface{}{"res": false, "msg": "A user with that email address already exists."})
		return
	}
	user.Name = ctx.Request.FormValue("name")
	user.Slug = ctx.Request.FormValue("slug")
	user.Email = ctx.Request.FormValue("email")
	user.Avatar = utils.Gravatar(ctx.Request.FormValue("email"), "180")
	user.Website = ctx.Request.FormValue("url")
	user.Bio = ctx.Request.FormValue("bio")
	err := user.UpdateUser(user.Id)
	if err != nil {
		ctx.JSON(map[string]interface{}{
			"res": false,
			"msg": err.Error(),
		})
	}
	ctx.JSON(map[string]interface{}{"res": true})
}

func PostCreateHandler(ctx *Golf.Context) {
	user := ctx.Data["user"].(*model.User)
	c := model.NewPost()
	ctx.Loader("admin").Render("edit_article.html", map[string]interface{}{
		"Title": "New Post",
		"Post":  c,
		"User":  user,
	})
}

func PostSaveHandler(ctx *Golf.Context) {
	user := ctx.Data["user"].(*model.User)
	p := model.NewPost()
	id, err := ctx.Param("id")
	if err != nil {
		p.Id = 0
	} else {
		idInt, _ := strconv.Atoi(id)
		p.Id = int64(idInt)
	}
	p.Title = ctx.Request.FormValue("title")
	p.Slug = ctx.Request.FormValue("slug")
	p.Markdown = ctx.Request.FormValue("content")
	p.Tags = model.GenerateTagsFromCommaString(ctx.Request.FormValue("tag"))
	p.IsComment = ctx.Request.FormValue("comment") == "on"
	p.Category = ctx.Request.FormValue("category")
	p.CreatedBy = user.Id
	p.UpdatedBy = user.Id
	p.IsPublished = ctx.Request.FormValue("status") == "on"
	p.IsPage = false
	p.Author = ctx.Data["user"].(*model.User)
	p.Hits = 1
	var e error
	e = p.Save()
	if e != nil {
		ctx.JSON(map[string]interface{}{
			"res": false,
			"msg": e.Error()})
		return
	}
	ctx.JSON(map[string]interface{}{
		"res":     true,
		"content": p})
}

func AdminPostHandler(ctx *Golf.Context) {
	user := ctx.Data["user"].(*model.User)
	i, _ := strconv.Atoi(ctx.Request.FormValue("page"))
	articles, pager, err := model.GetPostList(int64(i), 10, false, false, "created_at DESC")
	if err != nil {
		panic(err)
	}
	ctx.Loader("admin").Render("posts.html", map[string]interface{}{
		"Title": "Posts",
		"Posts": articles,
		"User":  user,
		"Pager": pager,
	})
}

func PostEditHandler(ctx *Golf.Context) {
	id, _ := ctx.Param("id")
	user := ctx.Data["user"].(*model.User)
	articleId, _ := strconv.Atoi(id)
	c, err := model.GetPostById(int64(articleId))
	if c == nil || err != nil {
		ctx.Redirect("/admin/posts/")
		return
	}
	ctx.Loader("admin").Render("edit_article.html", map[string]interface{}{
		"Title": "Edit Post",
		"Post":  c,
		"User":  user,
	})
}

func PostRemoveHandler(ctx *Golf.Context) {
	id, _ := ctx.Param("id")
	articleId, _ := strconv.Atoi(id)
	err := model.DeletePostById(int64(articleId))
	if err != nil {
		ctx.JSON(map[string]interface{}{
			"res": false,
		})
	} else {
		ctx.JSON(map[string]interface{}{
			"res": true,
		})
	}
}

func PageCreateHandler(ctx *Golf.Context) {
	user := ctx.Data["user"].(*model.User)
	c := model.NewPost()
	ctx.Loader("admin").Render("edit_article.html", map[string]interface{}{
		"Title": "New Page",
		"Post":  c,
		"User":  user,
	})
}

func AdminPageHandler(ctx *Golf.Context) {
	user := ctx.Data["user"].(*model.User)
	i, _ := strconv.Atoi(ctx.Request.FormValue("page"))
	pages, pager, err := model.GetPostList(int64(i), 10, true, false, `created_at`)
	if err != nil {
		panic(err)
	}
	ctx.Loader("admin").Render("pages.html", map[string]interface{}{
		"Title": "Pages",
		"Pages": pages,
		"User":  user,
		"Pager": pager,
	})
}

func PageSaveHandler(ctx *Golf.Context) {
	user := ctx.Data["user"].(*model.User)
	p := model.NewPost()
	p.Id = 0
	if !model.PostChangeSlug(ctx.Request.FormValue("slug")) {
		ctx.JSON(map[string]interface{}{
			"res": false,
			"msg": "The slug of this post has conflicts with another post."})
		return
	}
	p.Title = ctx.Request.FormValue("title")
	p.Slug = ctx.Request.FormValue("slug")
	p.Markdown = ctx.Request.FormValue("content")
	p.Tags = model.GenerateTagsFromCommaString(ctx.Request.FormValue("tag"))
	p.IsComment = ctx.Request.FormValue("comment") == "on"
	p.Category = ctx.Request.FormValue("category")
	p.CreatedBy = user.Id
	p.IsPublished = ctx.Request.FormValue("status") == "on"
	p.IsPage = true
	p.Author = ctx.Data["user"].(*model.User)
	p.Hits = 1
	var e error
	e = p.Save()
	if e != nil {
		ctx.JSON(map[string]interface{}{
			"res": false,
			"msg": e.Error()})
		return
	}
	ctx.JSON(map[string]interface{}{
		"res":     true,
		"content": p})
}

func CommentViewHandler(ctx *Golf.Context) {
	i, _ := strconv.Atoi(ctx.Request.FormValue("page"))
	user := ctx.Data["user"].(*model.User)
	comments, pager, err := model.GetCommentList(int64(i), 10)
	if err != nil {
		panic(err)
	}
	ctx.Loader("admin").Render("comments.html", map[string]interface{}{
		"Title":    "Comments",
		"Comments": comments,
		"User":     user,
		"Pager":    pager,
	})
}

func CommentAddHandler(ctx *Golf.Context) {
	pid, _ := strconv.Atoi(ctx.Request.FormValue("pid"))
	parent, err := model.GetCommentById(int64(pid))
	if err != nil {
		panic(err)
	}
	user := ctx.Data["user"].(*model.User)
	comment := new(model.Comment)
	comment.Author = user.Name
	comment.Email = user.Email
	comment.Url = user.Website
	comment.Content = ctx.Request.FormValue("content")
	comment.Avatar = utils.Gravatar(comment.Email, "50")
	comment.Parent = parent.Id
	comment.PostId = parent.PostId
	comment.Ip = ctx.Request.RemoteAddr
	comment.UserAgent = ctx.Request.UserAgent()
	comment.UserId = user.Id
	comment.Approved = true
	t := time.Now()
	comment.CreatedAt = &t
	id, err := comment.Save()
	if err != nil {
		panic(err)
	}
	comment.Id = id
	ctx.JSON(map[string]interface{}{
		"res":     true,
		"comment": comment.ToJson(),
	})
	model.CreateMessage("comment", comment)
}

func CommentUpdateHandler(ctx *Golf.Context) {
	id, _ := strconv.Atoi(ctx.Request.FormValue("id"))
	c, err := model.GetCommentById(int64(id))
	if err != nil {
		ctx.JSON(map[string]interface{}{
			"res": false,
			"msg": err.Error(),
		})
	}
	c.Approved = true
	c.Save()
	ctx.JSON(map[string]interface{}{
		"res": true,
	})
}

func CommentRemoveHandler(ctx *Golf.Context) {
	id, _ := strconv.Atoi(ctx.Request.FormValue("id"))
	err := model.DeleteComment(int64(id))
	if err != nil {
		ctx.JSON(map[string]interface{}{
			"res": true,
			"msg": err.Error(),
		})
	}
	ctx.JSON(map[string]interface{}{
		"res": true,
	})
}

func SettingViewHandler(ctx *Golf.Context) {
	user := ctx.Data["user"].(*model.User)
	ctx.Loader("admin").Render("setting.html", map[string]interface{}{
		"Title":      "Settings",
		"User":       user,
		"Custom":     model.GetCustomSettings(),
		"Navigators": model.GetNavigators(),
	})
}

func SettingUpdateHandler(ctx *Golf.Context) {
	user := ctx.Data["user"].(*model.User)
	var err error
	for key, value := range ctx.Request.Form {
		setting := new(model.Setting)
		setting.UUID = uuid.Formatter(uuid.NewV4(), uuid.CleanHyphen)
		setting.Key = key
		setting.Value = value[0]
		setting.Type = ""
		setting.CreatedBy = user.Id
		now := time.Now()
		setting.CreatedAt = &now
		err = model.SaveSetting(setting)
		if err != nil {
			panic(err)
			ctx.JSON(map[string]interface{}{
				"res": false,
				"msg": err.Error(),
			})
		}
	}
	ctx.JSON(map[string]interface{}{
		"res": true,
	})
}

func SettingCustomHandler(ctx *Golf.Context) {
	keys := ctx.Request.Form["key"]
	values := ctx.Request.Form["value"]
	for i, k := range keys {
		if len(k) < 1 {
			continue
		}
		model.SetSetting(k, values[i], "custom")
	}
	ctx.JSON(map[string]interface{}{
		"res": true,
	})
}

func SettingNavHandler(ctx *Golf.Context) {
	//	order := ctx.Request.Form["order"]
	//	text := ctx.Request.Form["text"]
	title := ctx.Request.FormValue("title")
	url := ctx.Request.FormValue("link")
	model.SetSetting(title, url, "navigation")
	ctx.JSON(map[string]interface{}{
		"res": true,
	})
}

func AdminPasswordPage(ctx *Golf.Context) {
	user := ctx.Data["user"].(*model.User)
	ctx.Loader("admin").Render("password.html", map[string]interface{}{
		"Title": "Change Password",
		"User":  user,
	})
}

func AdminPasswordChange(ctx *Golf.Context) {
	user := ctx.Data["user"].(*model.User)
	oldPassword := ctx.Request.FormValue("old")
	if !user.CheckPassword(oldPassword) {
		ctx.JSON(map[string]interface{}{
			"res": false,
			"msg": "Old password incorrect.",
		})
		return
	}
	newPassword := ctx.Request.FormValue("new")
	user.ChangePassword(newPassword)
	ctx.JSON(map[string]interface{}{
		"res": true,
	})
}

func AdminMonitorPage(ctx *Golf.Context) {
	user := ctx.Data["user"].(*model.User)
	ctx.Loader("admin").Render("monitor.html", map[string]interface{}{
		"Title":   "Monitor",
		"User":    user,
		"Monitor": utils.ReadMemStats(),
	})
}
<commit_msg>[style] Improved style<commit_after>package handler

import (
	"github.com/dinever/dingo/app/model"
	"github.com/dinever/dingo/app/utils"
	"github.com/dinever/golf"
	"github.com/twinj/uuid"
	"strconv"
	"time"
)

func AdminHandler(ctx *Golf.Context) {
	user := ctx.Data["user"].(*model.User)
	ctx.Loader("admin").Render("home.html", map[string]interface{}{
		"Title":    "Dashboard",
		"Statis":   model.NewStatis(),
		"User":     user,
		"Messages": model.GetUnreadMessages(),
		"Monitor":  utils.ReadMemStats(),
	})
}

func ProfileHandler(ctx *Golf.Context) {
	user := ctx.Data["user"].(*model.User)
	ctx.Loader("admin").Render("profile.html", map[string]interface{}{
		"Title": "Profile",
		"User":  user,
	})
}

func ProfileChangeHandler(ctx *Golf.Context) {
	user := ctx.Data["user"].(*model.User)
	if user.Email != ctx.Request.FormValue("email") && !model.UserChangeEmail(ctx.Request.FormValue("email")) {
		ctx.JSON(map[string]interface{}{"res": false, "msg": "A user with that email address already exists."})
		return
	}
	user.Name = ctx.Request.FormValue("name")
	user.Slug = ctx.Request.FormValue("slug")
	user.Email = ctx.Request.FormValue("email")
	user.Avatar = utils.Gravatar(ctx.Request.FormValue("email"), "180")
	user.Website = ctx.Request.FormValue("url")
	user.Bio = ctx.Request.FormValue("bio")
	err := user.UpdateUser(user.Id)
	if err != nil {
		ctx.JSON(map[string]interface{}{
			"res": false,
			"msg": err.Error(),
		})
	}
	ctx.JSON(map[string]interface{}{"res": true})
}

func PostCreateHandler(ctx *Golf.Context) {
	user := ctx.Data["user"].(*model.User)
	c := model.NewPost()
	ctx.Loader("admin").Render("edit_article.html", map[string]interface{}{
		"Title": "New Post",
		"Post":  c,
		"User":  user,
	})
}

func PostSaveHandler(ctx *Golf.Context) {
	user := ctx.Data["user"].(*model.User)
	p := model.NewPost()
	id, err := ctx.Param("id")
	if err != nil {
		p.Id = 0
	} else {
		idInt, _ := strconv.Atoi(id)
		p.Id = int64(idInt)
	}
	p.Title = ctx.Request.FormValue("title")
	p.Slug = ctx.Request.FormValue("slug")
	p.Markdown = ctx.Request.FormValue("content")
	p.Tags = model.GenerateTagsFromCommaString(ctx.Request.FormValue("tag"))
	p.IsComment = ctx.Request.FormValue("comment") == "on"
	p.Category = ctx.Request.FormValue("category")
	p.CreatedBy = user.Id
	p.UpdatedBy = user.Id
	p.IsPublished = ctx.Request.FormValue("status") == "on"
	p.IsPage = false
	p.Author = ctx.Data["user"].(*model.User)
	p.Hits = 1
	var e error
	e = p.Save()
	if e != nil {
		ctx.JSON(map[string]interface{}{
			"res": false,
			"msg": e.Error()})
		return
	}
	ctx.JSON(map[string]interface{}{
		"res":     true,
		"content": p,
	})
}

func AdminPostHandler(ctx *Golf.Context) {
	user := ctx.Data["user"].(*model.User)
	i, _ := strconv.Atoi(ctx.Request.FormValue("page"))
	articles, pager, err := model.GetPostList(int64(i), 10, false, false, "created_at DESC")
	if err != nil {
		panic(err)
	}
	ctx.Loader("admin").Render("posts.html", map[string]interface{}{
		"Title": "Posts",
		"Posts": articles,
		"User":  user,
		"Pager": pager,
	})
}

func PostEditHandler(ctx *Golf.Context) {
	id, _ := ctx.Param("id")
	user := ctx.Data["user"].(*model.User)
	articleId, _ := strconv.Atoi(id)
	c, err := model.GetPostById(int64(articleId))
	if c == nil || err != nil {
		ctx.Redirect("/admin/posts/")
		return
	}
	ctx.Loader("admin").Render("edit_article.html", map[string]interface{}{
		"Title": "Edit Post",
		"Post":  c,
		"User":  user,
	})
}

func PostRemoveHandler(ctx *Golf.Context) {
	id, _ := ctx.Param("id")
	articleId, _ := strconv.Atoi(id)
	err := model.DeletePostById(int64(articleId))
	if err != nil {
		ctx.JSON(map[string]interface{}{
			"res": false,
		})
	} else {
		ctx.JSON(map[string]interface{}{
			"res": true,
		})
	}
}

func PageCreateHandler(ctx *Golf.Context) {
	user := ctx.Data["user"].(*model.User)
	c := model.NewPost()
	ctx.Loader("admin").Render("edit_article.html", map[string]interface{}{
		"Title": "New Page",
		"Post":  c,
		"User":  user,
	})
}

func AdminPageHandler(ctx *Golf.Context) {
	user := ctx.Data["user"].(*model.User)
	i, _ := strconv.Atoi(ctx.Request.FormValue("page"))
	pages, pager, err := model.GetPostList(int64(i), 10, true, false, `created_at`)
	if err != nil {
		panic(err)
	}
	ctx.Loader("admin").Render("pages.html", map[string]interface{}{
		"Title": "Pages",
		"Pages": pages,
		"User":  user,
		"Pager": pager,
	})
}

func PageSaveHandler(ctx *Golf.Context) {
	user := ctx.Data["user"].(*model.User)
	p := model.NewPost()
	p.Id = 0
	if !model.PostChangeSlug(ctx.Request.FormValue("slug")) {
		ctx.JSON(map[string]interface{}{
			"res": false,
			"msg": "The slug of this post has conflicts with another post."})
		return
	}
	p.Title = ctx.Request.FormValue("title")
	p.Slug = ctx.Request.FormValue("slug")
	p.Markdown = ctx.Request.FormValue("content")
	p.Tags = model.GenerateTagsFromCommaString(ctx.Request.FormValue("tag"))
	p.IsComment = ctx.Request.FormValue("comment") == "on"
	p.Category = ctx.Request.FormValue("category")
	p.CreatedBy = user.Id
	p.IsPublished = ctx.Request.FormValue("status") == "on"
	p.IsPage = true
	p.Author = ctx.Data["user"].(*model.User)
	p.Hits = 1
	var e error
	e = p.Save()
	if e != nil {
		ctx.JSON(map[string]interface{}{
			"res": false,
			"msg": e.Error(),
		})
		return
	}
	ctx.JSON(map[string]interface{}{
		"res":     true,
		"content": p,
	})
}

func CommentViewHandler(ctx *Golf.Context) {
	i, _ := strconv.Atoi(ctx.Request.FormValue("page"))
	user := ctx.Data["user"].(*model.User)
	comments, pager, err := model.GetCommentList(int64(i), 10)
	if err != nil {
		panic(err)
	}
	ctx.Loader("admin").Render("comments.html", map[string]interface{}{
		"Title":    "Comments",
		"Comments": comments,
		"User":     user,
		"Pager":    pager,
	})
}

func CommentAddHandler(ctx *Golf.Context) {
	pid, _ := strconv.Atoi(ctx.Request.FormValue("pid"))
	parent, err := model.GetCommentById(int64(pid))
	if err != nil {
		panic(err)
	}
	user := ctx.Data["user"].(*model.User)
	comment := new(model.Comment)
	comment.Author = user.Name
	comment.Email = user.Email
	comment.Url = user.Website
	comment.Content = ctx.Request.FormValue("content")
	comment.Avatar = utils.Gravatar(comment.Email, "50")
	comment.Parent = parent.Id
	comment.PostId = parent.PostId
	comment.Ip = ctx.Request.RemoteAddr
	comment.UserAgent = ctx.Request.UserAgent()
	comment.UserId = user.Id
	comment.Approved = true
	t := time.Now()
	comment.CreatedAt = &t
	id, err := comment.Save()
	if err != nil {
		panic(err)
	}
	comment.Id = id
	ctx.JSON(map[string]interface{}{
		"res":     true,
		"comment": comment.ToJson(),
	})
	model.CreateMessage("comment", comment)
}

func CommentUpdateHandler(ctx *Golf.Context) {
	id, _ := strconv.Atoi(ctx.Request.FormValue("id"))
	c, err := model.GetCommentById(int64(id))
	if err != nil {
		ctx.JSON(map[string]interface{}{
			"res": false,
			"msg": err.Error(),
		})
	}
	c.Approved = true
	c.Save()
	ctx.JSON(map[string]interface{}{
		"res": true,
	})
}

func CommentRemoveHandler(ctx *Golf.Context) {
	id, _ := strconv.Atoi(ctx.Request.FormValue("id"))
	err := model.DeleteComment(int64(id))
	if err != nil {
		ctx.JSON(map[string]interface{}{
			"res": true,
			"msg": err.Error(),
		})
	}
	ctx.JSON(map[string]interface{}{
		"res": true,
	})
}

func SettingViewHandler(ctx *Golf.Context) {
	user := ctx.Data["user"].(*model.User)
	ctx.Loader("admin").Render("setting.html", map[string]interface{}{
		"Title":      "Settings",
		"User":       user,
		"Custom":     model.GetCustomSettings(),
		"Navigators": model.GetNavigators(),
	})
}

func SettingUpdateHandler(ctx *Golf.Context) {
	user := ctx.Data["user"].(*model.User)
	var err error
	for key, value := range ctx.Request.Form {
		setting := new(model.Setting)
		setting.UUID = uuid.Formatter(uuid.NewV4(), uuid.CleanHyphen)
		setting.Key = key
		setting.Value = value[0]
		setting.Type = ""
		setting.CreatedBy = user.Id
		now := time.Now()
		setting.CreatedAt = &now
		err = model.SaveSetting(setting)
		if err != nil {
			panic(err)
			ctx.JSON(map[string]interface{}{
				"res": false,
				"msg": err.Error(),
			})
		}
	}
	ctx.JSON(map[string]interface{}{
		"res": true,
	})
}

func SettingCustomHandler(ctx *Golf.Context) {
	keys := ctx.Request.Form["key"]
	values := ctx.Request.Form["value"]
	for i, k := range keys {
		if len(k) < 1 {
			continue
		}
		model.SetSetting(k, values[i], "custom")
	}
	ctx.JSON(map[string]interface{}{
		"res": true,
	})
}

func SettingNavHandler(ctx *Golf.Context) {
	//	order := ctx.Request.Form["order"]
	//	text := ctx.Request.Form["text"]
	title := ctx.Request.FormValue("title")
	url := ctx.Request.FormValue("link")
	model.SetSetting(title, url, "navigation")
	ctx.JSON(map[string]interface{}{
		"res": true,
	})
}

func AdminPasswordPage(ctx *Golf.Context) {
	user := ctx.Data["user"].(*model.User)
	ctx.Loader("admin").Render("password.html", map[string]interface{}{
		"Title": "Change Password",
		"User":  user,
	})
}

func AdminPasswordChange(ctx *Golf.Context) {
	user := ctx.Data["user"].(*model.User)
	oldPassword := ctx.Request.FormValue("old")
	if !user.CheckPassword(oldPassword) {
		ctx.JSON(map[string]interface{}{
			"res": false,
			"msg": "Old password incorrect.",
		})
		return
	}
	newPassword := ctx.Request.FormValue("new")
	user.ChangePassword(newPassword)
	ctx.JSON(map[string]interface{}{
		"res": true,
	})
}

func AdminMonitorPage(ctx *Golf.Context) {
	user := ctx.Data["user"].(*model.User)
	ctx.Loader("admin").Render("monitor.html", map[string]interface{}{
		"Title":   "Monitor",
		"User":    user,
		"Monitor": utils.ReadMemStats(),
	})
}
<|endoftext|>


<commit_before>package core

import (
	"fmt"
	"io/ioutil"
	"os"

	"github.com/Sirupsen/logrus"
	"github.com/vjeantet/bitfan/processors"
)

var logger = logrus.New()
var loggerProcessor = logrus.New()

func init() {
	logger.Level = logrus.WarnLevel
	loggerProcessor.Level = logrus.WarnLevel
	loggerProcessor.Formatter = &ProcessorFormatter{formatter: &logrus.TextFormatter{}}
}

type ProcessorFormatter struct {
	formatter  logrus.Formatter
	Xpipeline  string
	Xagent     string
	Xprocessor string
}

func (p *ProcessorFormatter) Format(entry *logrus.Entry) ([]byte, error) {
	if v, ok := entry.Data["Xprocessor"]; ok {
		entry.Message = fmt.Sprintf(`[%s] %s`,
			v,
			entry.Message,
		)
	}
	return p.formatter.Format(entry)
}

func Log() *logrus.Logger {
	return logger
}

func LogWithEvent(e processors.IPacket) *logrus.Entry {
	return Log().WithFields(logrus.Fields{
		"field.message": e.Fields().ValueOrEmptyForPathString("message"),
	})
}

func SetLogDebugMode(components []string) {

	for _, c := range components {
		switch c {
		case "core":
			Log().Level = logrus.DebugLevel
		case "processors":
			loggerProcessor.Level = logrus.DebugLevel
		}
	}
}

func SetLogVerboseMode(components []string) {
	for _, c := range components {
		switch c {
		case "core":
			Log().Level = logrus.InfoLevel
		case "processors":
			loggerProcessor.Level = logrus.InfoLevel
		}
	}
}

func SetLogOutputFile(fileLocation string) {
	Log().Out = ioutil.Discard
	Log().Formatter = &logrus.TextFormatter{DisableColors: true}
	f, err := os.OpenFile(fileLocation, os.O_WRONLY|os.O_CREATE, 0755)
	if err != nil {
		Log().Errorf("Error while opening log file %s", err)
	}
	Log().Out = f
}

func SetProcessorLogOutputFile(fileLocation string) {
	loggerProcessor.Formatter = &ProcessorFormatter{formatter: &logrus.TextFormatter{DisableColors: true}}
	f, err := os.OpenFile(fileLocation, os.O_WRONLY|os.O_CREATE, 0755)
	if err != nil {
		Log().Errorf("Error while opening log file %s", err)
	}
	loggerProcessor.Out = f
}

type processorLogger struct {
	e *logrus.Entry
}

func newProcessorLogger(procType, agentID, pipelineID string) *processorLogger {
	return &processorLogger{
		e: loggerProcessor.WithFields(map[string]interface{}{
			"Xprocessor": procType,
			"pipeline":   pipelineID,
			"agent":      agentID,
		}),
	}
}

func (p *processorLogger) Debug(args ...interface{}) {
	p.e.Debug(args...)
}
func (p *processorLogger) Debugf(format string, args ...interface{}) {
	p.e.Debugf(format, args...)
}
func (p *processorLogger) Debugln(args ...interface{}) {
	p.e.Debugln(args...)
}

func (p *processorLogger) Error(args ...interface{}) {
	p.e.Error(args...)
}
func (p *processorLogger) Errorf(format string, args ...interface{}) {
	p.e.Errorf(format, args...)
}
func (p *processorLogger) Errorln(args ...interface{}) {
	p.e.Errorln(args...)
}

func (p *processorLogger) Fatal(args ...interface{}) {
	p.e.Fatal(args...)
}
func (p *processorLogger) Fatalf(format string, args ...interface{}) {
	p.e.Fatalf(format, args...)
}
func (p *processorLogger) Fatalln(args ...interface{}) {
	p.e.Fatalln(args...)
}

func (p *processorLogger) Info(args ...interface{}) {
	p.e.Info(args...)
}
func (p *processorLogger) Infof(format string, args ...interface{}) {
	p.e.Infof(format, args...)
}
func (p *processorLogger) Infoln(args ...interface{}) {
	p.e.Infoln(args...)
}

func (p *processorLogger) Panic(args ...interface{}) {
	p.e.Panic(args...)
}
func (p *processorLogger) Panicf(format string, args ...interface{}) {
	p.e.Panicf(format, args...)
}
func (p *processorLogger) Panicln(args ...interface{}) {
	p.e.Panicln(args...)
}

func (p *processorLogger) Print(args ...interface{}) {
	p.e.Print(args...)
}
func (p *processorLogger) Printf(format string, args ...interface{}) {
	p.e.Printf(format, args...)
}
func (p *processorLogger) Println(args ...interface{}) {
	p.e.Println(args...)
}

func (p *processorLogger) Warn(args ...interface{}) {
	p.e.Warn(args...)
}

func (p *processorLogger) Warnf(format string, args ...interface{}) {
	p.e.Warnf(format, args...)
}
func (p *processorLogger) Warning(args ...interface{}) {
	p.e.Warning(args...)
}
func (p *processorLogger) Warningf(format string, args ...interface{}) {
	p.e.Warningf(format, args...)
}
func (p *processorLogger) Warningln(args ...interface{}) {
	p.e.Warningln(args...)
}
func (p *processorLogger) Warnln(args ...interface{}) {
	p.e.Warnln(args...)
}
<commit_msg>open log and append data<commit_after>package core

import (
	"fmt"
	"io/ioutil"
	"os"

	"github.com/Sirupsen/logrus"
	"github.com/vjeantet/bitfan/processors"
)

var logger = logrus.New()
var loggerProcessor = logrus.New()

func init() {
	logger.Level = logrus.WarnLevel
	loggerProcessor.Level = logrus.WarnLevel
	loggerProcessor.Formatter = &ProcessorFormatter{formatter: &logrus.TextFormatter{}}
}

type ProcessorFormatter struct {
	formatter  logrus.Formatter
	Xpipeline  string
	Xagent     string
	Xprocessor string
}

func (p *ProcessorFormatter) Format(entry *logrus.Entry) ([]byte, error) {
	if v, ok := entry.Data["Xprocessor"]; ok {
		entry.Message = fmt.Sprintf(`[%s] %s`,
			v,
			entry.Message,
		)
	}
	return p.formatter.Format(entry)
}

func Log() *logrus.Logger {
	return logger
}

func LogWithEvent(e processors.IPacket) *logrus.Entry {
	return Log().WithFields(logrus.Fields{
		"field.message": e.Fields().ValueOrEmptyForPathString("message"),
	})
}

func SetLogDebugMode(components []string) {

	for _, c := range components {
		switch c {
		case "core":
			Log().Level = logrus.DebugLevel
		case "processors":
			loggerProcessor.Level = logrus.DebugLevel
		}
	}
}

func SetLogVerboseMode(components []string) {
	for _, c := range components {
		switch c {
		case "core":
			Log().Level = logrus.InfoLevel
		case "processors":
			loggerProcessor.Level = logrus.InfoLevel
		}
	}
}

func SetLogOutputFile(fileLocation string) {
	Log().Out = ioutil.Discard
	Log().Formatter = &logrus.TextFormatter{DisableColors: true}
	f, err := os.OpenFile(fileLocation, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0755)
	if err != nil {
		Log().Errorf("Error while opening log file %s", err)
	}
	Log().Out = f
}

func SetProcessorLogOutputFile(fileLocation string) {
	loggerProcessor.Formatter = &ProcessorFormatter{formatter: &logrus.TextFormatter{DisableColors: true}}
	f, err := os.OpenFile(fileLocation, os.O_WRONLY|os.O_CREATE, 0755)
	if err != nil {
		Log().Errorf("Error while opening log file %s", err)
	}
	loggerProcessor.Out = f
}

type processorLogger struct {
	e *logrus.Entry
}

func newProcessorLogger(procType, agentID, pipelineID string) *processorLogger {
	return &processorLogger{
		e: loggerProcessor.WithFields(map[string]interface{}{
			"Xprocessor": procType,
			"pipeline":   pipelineID,
			"agent":      agentID,
		}),
	}
}

func (p *processorLogger) Debug(args ...interface{}) {
	p.e.Debug(args...)
}
func (p *processorLogger) Debugf(format string, args ...interface{}) {
	p.e.Debugf(format, args...)
}
func (p *processorLogger) Debugln(args ...interface{}) {
	p.e.Debugln(args...)
}

func (p *processorLogger) Error(args ...interface{}) {
	p.e.Error(args...)
}
func (p *processorLogger) Errorf(format string, args ...interface{}) {
	p.e.Errorf(format, args...)
}
func (p *processorLogger) Errorln(args ...interface{}) {
	p.e.Errorln(args...)
}

func (p *processorLogger) Fatal(args ...interface{}) {
	p.e.Fatal(args...)
}
func (p *processorLogger) Fatalf(format string, args ...interface{}) {
	p.e.Fatalf(format, args...)
}
func (p *processorLogger) Fatalln(args ...interface{}) {
	p.e.Fatalln(args...)
}

func (p *processorLogger) Info(args ...interface{}) {
	p.e.Info(args...)
}
func (p *processorLogger) Infof(format string, args ...interface{}) {
	p.e.Infof(format, args...)
}
func (p *processorLogger) Infoln(args ...interface{}) {
	p.e.Infoln(args...)
}

func (p *processorLogger) Panic(args ...interface{}) {
	p.e.Panic(args...)
}
func (p *processorLogger) Panicf(format string, args ...interface{}) {
	p.e.Panicf(format, args...)
}
func (p *processorLogger) Panicln(args ...interface{}) {
	p.e.Panicln(args...)
}

func (p *processorLogger) Print(args ...interface{}) {
	p.e.Print(args...)
}
func (p *processorLogger) Printf(format string, args ...interface{}) {
	p.e.Printf(format, args...)
}
func (p *processorLogger) Println(args ...interface{}) {
	p.e.Println(args...)
}

func (p *processorLogger) Warn(args ...interface{}) {
	p.e.Warn(args...)
}

func (p *processorLogger) Warnf(format string, args ...interface{}) {
	p.e.Warnf(format, args...)
}
func (p *processorLogger) Warning(args ...interface{}) {
	p.e.Warning(args...)
}
func (p *processorLogger) Warningf(format string, args ...interface{}) {
	p.e.Warningf(format, args...)
}
func (p *processorLogger) Warningln(args ...interface{}) {
	p.e.Warningln(args...)
}
func (p *processorLogger) Warnln(args ...interface{}) {
	p.e.Warnln(args...)
}
<|endoftext|>


<commit_before>// Licensed to the Apache Software Foundation (ASF) under one or more
// contributor license agreements.  See the NOTICE file distributed with
// this work for additional information regarding copyright ownership.
// The ASF licenses this file to You under the Apache 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://www.apache.org/licenses/LICENSE-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 direct

import (
	"bytes"
	"context"
	"fmt"
	"sort"

	"github.com/apache/beam/sdks/v2/go/pkg/beam/core/graph"
	"github.com/apache/beam/sdks/v2/go/pkg/beam/core/graph/window"
	"github.com/apache/beam/sdks/v2/go/pkg/beam/core/runtime/exec"
	"github.com/apache/beam/sdks/v2/go/pkg/beam/core/typex"
	"github.com/apache/beam/sdks/v2/go/pkg/beam/internal/errors"
)

type group struct {
	key    exec.FullValue
	values [][]exec.FullValue
}

// CoGBK buffers all input and continues on FinishBundle. Use with small single-bundle data only.
type CoGBK struct {
	UID  exec.UnitID
	Edge *graph.MultiEdge
	Out  exec.Node

	enc  exec.ElementEncoder // key encoder for coder-equality
	wEnc exec.WindowEncoder  // window encoder for windowing
	m    map[string]*group
	wins []typex.Window
}

func (n *CoGBK) ID() exec.UnitID {
	return n.UID
}

func (n *CoGBK) Up(ctx context.Context) error {
	n.enc = exec.MakeElementEncoder(n.Edge.Input[0].From.Coder.Components[0])
	n.wEnc = exec.MakeWindowEncoder(n.Edge.Input[0].From.WindowingStrategy().Fn.Coder())
	n.m = make(map[string]*group)
	return nil
}

func (n *CoGBK) StartBundle(ctx context.Context, id string, data exec.DataContext) error {
	return n.Out.StartBundle(ctx, id, data)
}

func (n *CoGBK) ProcessElement(ctx context.Context, elm *exec.FullValue, _ ...exec.ReStream) error {
	index := elm.Elm.(int)
	value := elm.Elm2.(*exec.FullValue)

	for _, w := range elm.Windows {
		ws := []typex.Window{w}
		n.wins = append(n.wins, ws...)

		key, err := n.encodeKey(value.Elm, ws)
		if err != nil {
			return errors.Errorf("failed encoding key for %v: %v", elm, err)
		}
		g := n.getGroup(n.m, key, value, ws)
		g.values[index] = append(g.values[index], exec.FullValue{Elm: value.Elm2, Timestamp: value.Timestamp})
	}
	return nil
}

func (n *CoGBK) encodeKey(elm interface{}, ws []typex.Window) (string, error) {
	var buf bytes.Buffer
	if err := n.enc.Encode(&exec.FullValue{Elm: elm}, &buf); err != nil {
		return "", errors.WithContextf(err, "encoding key %v for CoGBK", elm)
	}
	if err := n.wEnc.Encode(ws, &buf); err != nil {
		return "", errors.WithContextf(err, "encoding window %v for CoGBK", ws)
	}
	return buf.String(), nil
}

func (n *CoGBK) getGroup(m map[string]*group, key string, value *exec.FullValue, ws []typex.Window) *group {
	g, ok := m[key]
	if !ok {
		g = &group{
			key:    exec.FullValue{Elm: value.Elm, Timestamp: value.Timestamp, Windows: ws},
			values: make([][]exec.FullValue, len(n.Edge.Input)),
		}
		m[key] = g
	}
	return g
}

func (n *CoGBK) FinishBundle(ctx context.Context) error {
	winKind := n.Edge.Input[0].From.WindowingStrategy().Fn.Kind
	if winKind == window.Sessions {
		mergeMap, mergeErr := n.mergeWindows()
		if mergeErr != nil {
			return errors.Errorf("failed to merge windows, got: %v", mergeErr)
		}
		if reprocessErr := n.reprocessByWindow(mergeMap); reprocessErr != nil {
			return errors.Errorf("failed to reprocess with merged windows, got :%v", reprocessErr)
		}
	}
	for key, g := range n.m {
		values := make([]exec.ReStream, len(g.values))
		for i, list := range g.values {
			values[i] = &exec.FixedReStream{Buf: list}
		}
		if err := n.Out.ProcessElement(ctx, &g.key, values...); err != nil {
			return err
		}
		delete(n.m, key)
	}
	return n.Out.FinishBundle(ctx)
}

func (n *CoGBK) mergeWindows() (map[typex.Window]int, error) {
	sort.Slice(n.wins, func(i int, j int) bool {
		return n.wins[i].MaxTimestamp() < n.wins[j].MaxTimestamp()
	})
	// mergeMap is a map from the oringal windows to the index of the new window
	// in the mergedWins slice
	mergeMap := make(map[typex.Window]int)
	mergedWins := []typex.Window{}
	for i := 0; i < len(n.wins); {
		intWin, ok := n.wins[i].(window.IntervalWindow)
		if !ok {
			return nil, errors.Errorf("tried to merge non-interval window type %T", n.wins[i])
		}
		mergeStart := intWin.Start
		mergeEnd := intWin.End
		j := i + 1
		for j < len(n.wins) {
			candidateWin := n.wins[j].(window.IntervalWindow)
			if candidateWin.Start <= mergeEnd {
				mergeEnd = candidateWin.End
				j++
			} else {
				break
			}
		}
		for k := i; k < j; k++ {
			mergeMap[n.wins[k]] = len(mergedWins)
		}
		mergedWins = append(mergedWins, window.IntervalWindow{Start: mergeStart, End: mergeEnd})
		i = j
	}
	n.wins = mergedWins
	return mergeMap, nil
}

func (n *CoGBK) reprocessByWindow(mergeMap map[typex.Window]int) error {
	newGroups := make(map[string]*group)
	for _, g := range n.m {
		ws := []typex.Window{n.wins[mergeMap[g.key.Windows[0]]]}
		key, err := n.encodeKey(g.key.Elm, ws)
		if err != nil {
			return errors.Errorf("failed encoding key for %v: %v", g.key.Elm, err)
		}
		gr := n.getGroup(newGroups, key, &g.key, ws)
		for i, list := range g.values {
			gr.values[i] = append(gr.values[i], list...)
		}
	}
	n.m = newGroups
	return nil
}

func (n *CoGBK) Down(ctx context.Context) error {
	return nil
}

func (n *CoGBK) String() string {
	return fmt.Sprintf("CoGBK. Out:%v", n.Out.ID())
}

// Inject injects the predecessor index into each FullValue, effectively
// converting KV<X,Y> into KV<X,KV<int,Y>>. Used to prime CoGBK.
type Inject struct {
	UID exec.UnitID
	N   int
	Out exec.Node
}

func (n *Inject) ID() exec.UnitID {
	return n.UID
}

func (n *Inject) Up(ctx context.Context) error {
	return nil
}

func (n *Inject) StartBundle(ctx context.Context, id string, data exec.DataContext) error {
	return n.Out.StartBundle(ctx, id, data)
}

func (n *Inject) ProcessElement(ctx context.Context, elm *exec.FullValue, values ...exec.ReStream) error {
	return n.Out.ProcessElement(ctx, &exec.FullValue{Elm: n.N, Elm2: elm, Timestamp: elm.Timestamp, Windows: elm.Windows}, values...)
}

func (n *Inject) FinishBundle(ctx context.Context) error {
	return n.Out.FinishBundle(ctx)
}

func (n *Inject) Down(ctx context.Context) error {
	return nil
}

func (n *Inject) String() string {
	return fmt.Sprintf("Inject[%v]. Out:%v", n.N, n.Out.ID())
}
<commit_msg>Fix wrong comment (#23272)<commit_after>// Licensed to the Apache Software Foundation (ASF) under one or more
// contributor license agreements.  See the NOTICE file distributed with
// this work for additional information regarding copyright ownership.
// The ASF licenses this file to You under the Apache 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://www.apache.org/licenses/LICENSE-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 direct

import (
	"bytes"
	"context"
	"fmt"
	"sort"

	"github.com/apache/beam/sdks/v2/go/pkg/beam/core/graph"
	"github.com/apache/beam/sdks/v2/go/pkg/beam/core/graph/window"
	"github.com/apache/beam/sdks/v2/go/pkg/beam/core/runtime/exec"
	"github.com/apache/beam/sdks/v2/go/pkg/beam/core/typex"
	"github.com/apache/beam/sdks/v2/go/pkg/beam/internal/errors"
)

type group struct {
	key    exec.FullValue
	values [][]exec.FullValue
}

// CoGBK buffers all input and continues on FinishBundle. Use with small single-bundle data only.
type CoGBK struct {
	UID  exec.UnitID
	Edge *graph.MultiEdge
	Out  exec.Node

	enc  exec.ElementEncoder // key encoder for coder-equality
	wEnc exec.WindowEncoder  // window encoder for windowing
	m    map[string]*group
	wins []typex.Window
}

func (n *CoGBK) ID() exec.UnitID {
	return n.UID
}

func (n *CoGBK) Up(ctx context.Context) error {
	n.enc = exec.MakeElementEncoder(n.Edge.Input[0].From.Coder.Components[0])
	n.wEnc = exec.MakeWindowEncoder(n.Edge.Input[0].From.WindowingStrategy().Fn.Coder())
	n.m = make(map[string]*group)
	return nil
}

func (n *CoGBK) StartBundle(ctx context.Context, id string, data exec.DataContext) error {
	return n.Out.StartBundle(ctx, id, data)
}

func (n *CoGBK) ProcessElement(ctx context.Context, elm *exec.FullValue, _ ...exec.ReStream) error {
	index := elm.Elm.(int)
	value := elm.Elm2.(*exec.FullValue)

	for _, w := range elm.Windows {
		ws := []typex.Window{w}
		n.wins = append(n.wins, ws...)

		key, err := n.encodeKey(value.Elm, ws)
		if err != nil {
			return errors.Errorf("failed encoding key for %v: %v", elm, err)
		}
		g := n.getGroup(n.m, key, value, ws)
		g.values[index] = append(g.values[index], exec.FullValue{Elm: value.Elm2, Timestamp: value.Timestamp})
	}
	return nil
}

func (n *CoGBK) encodeKey(elm interface{}, ws []typex.Window) (string, error) {
	var buf bytes.Buffer
	if err := n.enc.Encode(&exec.FullValue{Elm: elm}, &buf); err != nil {
		return "", errors.WithContextf(err, "encoding key %v for CoGBK", elm)
	}
	if err := n.wEnc.Encode(ws, &buf); err != nil {
		return "", errors.WithContextf(err, "encoding window %v for CoGBK", ws)
	}
	return buf.String(), nil
}

func (n *CoGBK) getGroup(m map[string]*group, key string, value *exec.FullValue, ws []typex.Window) *group {
	g, ok := m[key]
	if !ok {
		g = &group{
			key:    exec.FullValue{Elm: value.Elm, Timestamp: value.Timestamp, Windows: ws},
			values: make([][]exec.FullValue, len(n.Edge.Input)),
		}
		m[key] = g
	}
	return g
}

func (n *CoGBK) FinishBundle(ctx context.Context) error {
	winKind := n.Edge.Input[0].From.WindowingStrategy().Fn.Kind
	if winKind == window.Sessions {
		mergeMap, mergeErr := n.mergeWindows()
		if mergeErr != nil {
			return errors.Errorf("failed to merge windows, got: %v", mergeErr)
		}
		if reprocessErr := n.reprocessByWindow(mergeMap); reprocessErr != nil {
			return errors.Errorf("failed to reprocess with merged windows, got :%v", reprocessErr)
		}
	}
	for key, g := range n.m {
		values := make([]exec.ReStream, len(g.values))
		for i, list := range g.values {
			values[i] = &exec.FixedReStream{Buf: list}
		}
		if err := n.Out.ProcessElement(ctx, &g.key, values...); err != nil {
			return err
		}
		delete(n.m, key)
	}
	return n.Out.FinishBundle(ctx)
}

func (n *CoGBK) mergeWindows() (map[typex.Window]int, error) {
	sort.Slice(n.wins, func(i int, j int) bool {
		return n.wins[i].MaxTimestamp() < n.wins[j].MaxTimestamp()
	})
	// mergeMap is a map from the oringal windows to the index of the new window
	// in the mergedWins slice
	mergeMap := make(map[typex.Window]int)
	mergedWins := []typex.Window{}
	for i := 0; i < len(n.wins); {
		intWin, ok := n.wins[i].(window.IntervalWindow)
		if !ok {
			return nil, errors.Errorf("tried to merge non-interval window type %T", n.wins[i])
		}
		mergeStart := intWin.Start
		mergeEnd := intWin.End
		j := i + 1
		for j < len(n.wins) {
			candidateWin := n.wins[j].(window.IntervalWindow)
			if candidateWin.Start <= mergeEnd {
				mergeEnd = candidateWin.End
				j++
			} else {
				break
			}
		}
		for k := i; k < j; k++ {
			mergeMap[n.wins[k]] = len(mergedWins)
		}
		mergedWins = append(mergedWins, window.IntervalWindow{Start: mergeStart, End: mergeEnd})
		i = j
	}
	n.wins = mergedWins
	return mergeMap, nil
}

func (n *CoGBK) reprocessByWindow(mergeMap map[typex.Window]int) error {
	newGroups := make(map[string]*group)
	for _, g := range n.m {
		ws := []typex.Window{n.wins[mergeMap[g.key.Windows[0]]]}
		key, err := n.encodeKey(g.key.Elm, ws)
		if err != nil {
			return errors.Errorf("failed encoding key for %v: %v", g.key.Elm, err)
		}
		gr := n.getGroup(newGroups, key, &g.key, ws)
		for i, list := range g.values {
			gr.values[i] = append(gr.values[i], list...)
		}
	}
	n.m = newGroups
	return nil
}

func (n *CoGBK) Down(ctx context.Context) error {
	return nil
}

func (n *CoGBK) String() string {
	return fmt.Sprintf("CoGBK. Out:%v", n.Out.ID())
}

// Inject injects the predecessor index into each FullValue, effectively
// converting KV<X,Y> into KV<int,KV<X,Y>>. Used to prime CoGBK.
type Inject struct {
	UID exec.UnitID
	N   int
	Out exec.Node
}

func (n *Inject) ID() exec.UnitID {
	return n.UID
}

func (n *Inject) Up(ctx context.Context) error {
	return nil
}

func (n *Inject) StartBundle(ctx context.Context, id string, data exec.DataContext) error {
	return n.Out.StartBundle(ctx, id, data)
}

func (n *Inject) ProcessElement(ctx context.Context, elm *exec.FullValue, values ...exec.ReStream) error {
	return n.Out.ProcessElement(ctx, &exec.FullValue{Elm: n.N, Elm2: elm, Timestamp: elm.Timestamp, Windows: elm.Windows}, values...)
}

func (n *Inject) FinishBundle(ctx context.Context) error {
	return n.Out.FinishBundle(ctx)
}

func (n *Inject) Down(ctx context.Context) error {
	return nil
}

func (n *Inject) String() string {
	return fmt.Sprintf("Inject[%v]. Out:%v", n.N, n.Out.ID())
}
<|endoftext|>


<commit_before>package platform

// Largely based on
// https://github.com/moby/moby/blob/bc846d2e8fe5538220e0c31e9d0e8446f6fbc022/distribution/cpuinfo_unix.go
// Copyright 2012-2017 Docker, Inc.
//
// https://github.com/containerd/containerd/blob/726dcaea50883e51b2ec6db13caff0e7936b711d/platforms/cpuinfo.go
//    Copyright The containerd Authors.
//    Licensed under the Apache 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://www.apache.org/licenses/LICENSE-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.

import (
	"bufio"
	"fmt"
	"os"
	"runtime"
	"strings"

	"github.com/containers/image/v5/types"
	imgspecv1 "github.com/opencontainers/image-spec/specs-go/v1"
)

// For Linux, the kernel has already detected the ABI, ISA and Features.
// So we don't need to access the ARM registers to detect platform information
// by ourselves. We can just parse these information from /proc/cpuinfo
func getCPUInfo(pattern string) (info string, err error) {
	if runtime.GOOS != "linux" {
		return "", fmt.Errorf("getCPUInfo for OS %s not implemented", runtime.GOOS)
	}

	cpuinfo, err := os.Open("/proc/cpuinfo")
	if err != nil {
		return "", err
	}
	defer cpuinfo.Close()

	// Start to Parse the Cpuinfo line by line. For SMP SoC, we parse
	// the first core is enough.
	scanner := bufio.NewScanner(cpuinfo)
	for scanner.Scan() {
		newline := scanner.Text()
		list := strings.Split(newline, ":")

		if len(list) > 1 && strings.EqualFold(strings.TrimSpace(list[0]), pattern) {
			return strings.TrimSpace(list[1]), nil
		}
	}

	// Check whether the scanner encountered errors
	err = scanner.Err()
	if err != nil {
		return "", err
	}

	return "", fmt.Errorf("getCPUInfo for pattern: %s not found", pattern)
}

func getCPUVariantWindows(arch string) string {
	// Windows only supports v7 for ARM32 and v8 for ARM64 and so we can use
	// runtime.GOARCH to determine the variants
	var variant string
	switch arch {
	case "arm64":
		variant = "v8"
	case "arm":
		variant = "v7"
	default:
		variant = ""
	}

	return variant
}

func getCPUVariantArm() string {
	variant, err := getCPUInfo("Cpu architecture")
	if err != nil {
		return ""
	}
	// TODO handle RPi Zero mismatch (https://github.com/moby/moby/pull/36121#issuecomment-398328286)

	switch strings.ToLower(variant) {
	case "8", "aarch64":
		variant = "v8"
	case "7", "7m", "?(12)", "?(13)", "?(14)", "?(15)", "?(16)", "?(17)":
		variant = "v7"
	case "6", "6tej":
		variant = "v6"
	case "5", "5t", "5te", "5tej":
		variant = "v5"
	case "4", "4t":
		variant = "v4"
	case "3":
		variant = "v3"
	default:
		variant = ""
	}

	return variant
}

func getCPUVariant(os string, arch string) string {
	if os == "windows" {
		return getCPUVariantWindows(arch)
	}
	if arch == "arm" || arch == "arm64" {
		return getCPUVariantArm()
	}
	return ""
}

var compatibility = map[string][]string{
	"arm":   {"v7", "v6", "v5"},
	"arm64": {"v8"},
}

// WantedPlatforms returns all compatible platforms with the platform specifics possibly overriden by user,
// the most compatible platform is first.
// If some option (arch, os, variant) is not present, a value from current platform is detected.
func WantedPlatforms(ctx *types.SystemContext) ([]imgspecv1.Platform, error) {
	wantedArch := runtime.GOARCH
	wantedVariant := ""
	if ctx != nil && ctx.ArchitectureChoice != "" {
		wantedArch = ctx.ArchitectureChoice
	} else {
		// Only auto-detect the variant if we are using the default architecture.
		// If the user has specified the ArchitectureChoice, don't autodetect, even if
		// ctx.ArchitectureChoice == runtime.GOARCH, because we have no idea whether the runtime.GOARCH
		// value is relevant to the use case, and if we do autodetect a variant,
		// ctx.VariantChoice can't be used to override it back to "".
		wantedVariant = getCPUVariant(runtime.GOOS, runtime.GOARCH)
	}
	if ctx != nil && ctx.VariantChoice != "" {
		wantedVariant = ctx.VariantChoice
	}

	wantedOS := runtime.GOOS
	if ctx != nil && ctx.OSChoice != "" {
		wantedOS = ctx.OSChoice
	}

	var wantedPlatforms []imgspecv1.Platform
	if wantedVariant != "" && compatibility[wantedArch] != nil {
		variantOrder := compatibility[wantedArch]
		wantedPlatforms = make([]imgspecv1.Platform, 0, len(variantOrder))
		wantedIndex := -1
		for i, v := range variantOrder {
			if wantedVariant == v {
				wantedIndex = i
				break
			}
		}
		// user wants a variant which we know nothing about - not even compatibility
		if wantedIndex == -1 {
			wantedPlatforms = []imgspecv1.Platform{
				{
					OS:           wantedOS,
					Architecture: wantedArch,
					Variant:      wantedVariant,
				},
			}
		} else {
			for i := wantedIndex; i < len(variantOrder); i++ {
				v := variantOrder[i]
				wantedPlatforms = append(wantedPlatforms, imgspecv1.Platform{
					OS:           wantedOS,
					Architecture: wantedArch,
					Variant:      v,
				})
			}
		}
	} else {
		wantedPlatforms = []imgspecv1.Platform{
			{
				OS:           wantedOS,
				Architecture: wantedArch,
				Variant:      wantedVariant,
			},
		}
	}

	return wantedPlatforms, nil
}

func MatchesPlatform(image imgspecv1.Platform, wanted imgspecv1.Platform) bool {
	if image.Architecture != wanted.Architecture {
		return false
	}
	if image.OS != wanted.OS {
		return false
	}

	if wanted.Variant == "" || image.Variant == wanted.Variant {
		return true
	}

	return false
}
<commit_msg>Simplify the WantedPlatforms main loop<commit_after>package platform

// Largely based on
// https://github.com/moby/moby/blob/bc846d2e8fe5538220e0c31e9d0e8446f6fbc022/distribution/cpuinfo_unix.go
// Copyright 2012-2017 Docker, Inc.
//
// https://github.com/containerd/containerd/blob/726dcaea50883e51b2ec6db13caff0e7936b711d/platforms/cpuinfo.go
//    Copyright The containerd Authors.
//    Licensed under the Apache 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://www.apache.org/licenses/LICENSE-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.

import (
	"bufio"
	"fmt"
	"os"
	"runtime"
	"strings"

	"github.com/containers/image/v5/types"
	imgspecv1 "github.com/opencontainers/image-spec/specs-go/v1"
)

// For Linux, the kernel has already detected the ABI, ISA and Features.
// So we don't need to access the ARM registers to detect platform information
// by ourselves. We can just parse these information from /proc/cpuinfo
func getCPUInfo(pattern string) (info string, err error) {
	if runtime.GOOS != "linux" {
		return "", fmt.Errorf("getCPUInfo for OS %s not implemented", runtime.GOOS)
	}

	cpuinfo, err := os.Open("/proc/cpuinfo")
	if err != nil {
		return "", err
	}
	defer cpuinfo.Close()

	// Start to Parse the Cpuinfo line by line. For SMP SoC, we parse
	// the first core is enough.
	scanner := bufio.NewScanner(cpuinfo)
	for scanner.Scan() {
		newline := scanner.Text()
		list := strings.Split(newline, ":")

		if len(list) > 1 && strings.EqualFold(strings.TrimSpace(list[0]), pattern) {
			return strings.TrimSpace(list[1]), nil
		}
	}

	// Check whether the scanner encountered errors
	err = scanner.Err()
	if err != nil {
		return "", err
	}

	return "", fmt.Errorf("getCPUInfo for pattern: %s not found", pattern)
}

func getCPUVariantWindows(arch string) string {
	// Windows only supports v7 for ARM32 and v8 for ARM64 and so we can use
	// runtime.GOARCH to determine the variants
	var variant string
	switch arch {
	case "arm64":
		variant = "v8"
	case "arm":
		variant = "v7"
	default:
		variant = ""
	}

	return variant
}

func getCPUVariantArm() string {
	variant, err := getCPUInfo("Cpu architecture")
	if err != nil {
		return ""
	}
	// TODO handle RPi Zero mismatch (https://github.com/moby/moby/pull/36121#issuecomment-398328286)

	switch strings.ToLower(variant) {
	case "8", "aarch64":
		variant = "v8"
	case "7", "7m", "?(12)", "?(13)", "?(14)", "?(15)", "?(16)", "?(17)":
		variant = "v7"
	case "6", "6tej":
		variant = "v6"
	case "5", "5t", "5te", "5tej":
		variant = "v5"
	case "4", "4t":
		variant = "v4"
	case "3":
		variant = "v3"
	default:
		variant = ""
	}

	return variant
}

func getCPUVariant(os string, arch string) string {
	if os == "windows" {
		return getCPUVariantWindows(arch)
	}
	if arch == "arm" || arch == "arm64" {
		return getCPUVariantArm()
	}
	return ""
}

var compatibility = map[string][]string{
	"arm":   {"v7", "v6", "v5"},
	"arm64": {"v8"},
}

// WantedPlatforms returns all compatible platforms with the platform specifics possibly overriden by user,
// the most compatible platform is first.
// If some option (arch, os, variant) is not present, a value from current platform is detected.
func WantedPlatforms(ctx *types.SystemContext) ([]imgspecv1.Platform, error) {
	wantedArch := runtime.GOARCH
	wantedVariant := ""
	if ctx != nil && ctx.ArchitectureChoice != "" {
		wantedArch = ctx.ArchitectureChoice
	} else {
		// Only auto-detect the variant if we are using the default architecture.
		// If the user has specified the ArchitectureChoice, don't autodetect, even if
		// ctx.ArchitectureChoice == runtime.GOARCH, because we have no idea whether the runtime.GOARCH
		// value is relevant to the use case, and if we do autodetect a variant,
		// ctx.VariantChoice can't be used to override it back to "".
		wantedVariant = getCPUVariant(runtime.GOOS, runtime.GOARCH)
	}
	if ctx != nil && ctx.VariantChoice != "" {
		wantedVariant = ctx.VariantChoice
	}

	wantedOS := runtime.GOOS
	if ctx != nil && ctx.OSChoice != "" {
		wantedOS = ctx.OSChoice
	}

	var variants []string = nil
	if wantedVariant != "" && compatibility[wantedArch] != nil {
		variantOrder := compatibility[wantedArch]
		variants = make([]string, 0, len(variantOrder))
		wantedIndex := -1
		for i, v := range variantOrder {
			if wantedVariant == v {
				wantedIndex = i
				break
			}
		}
		// user wants a variant which we know nothing about - not even compatibility
		if wantedIndex == -1 {
			variants = []string{wantedVariant}
		} else {
			for i := wantedIndex; i < len(variantOrder); i++ {
				variants = append(variants, variantOrder[i])
			}
		}
	} else {
		variants = []string{wantedVariant}
	}

	res := make([]imgspecv1.Platform, 0, len(variants))
	for _, v := range variants {
		res = append(res, imgspecv1.Platform{
			OS:           wantedOS,
			Architecture: wantedArch,
			Variant:      v,
		})
	}
	return res, nil
}

func MatchesPlatform(image imgspecv1.Platform, wanted imgspecv1.Platform) bool {
	if image.Architecture != wanted.Architecture {
		return false
	}
	if image.OS != wanted.OS {
		return false
	}

	if wanted.Variant == "" || image.Variant == wanted.Variant {
		return true
	}

	return false
}
<|endoftext|>


<commit_before>package mangen

import (
	"bytes"
	"fmt"
	"strings"

	"github.com/russross/blackfriday"
)

type Man struct{}

func ManRenderer(flags int) blackfriday.Renderer {
	return &Man{}
}

func (m *Man) GetFlags() int {
	return 0
}

func (m *Man) TitleBlock(out *bytes.Buffer, text []byte) {
	out.WriteString(".TH ")

	splitText := bytes.Split(text, []byte("\n"))
	for i, line := range splitText {
		line = bytes.TrimPrefix(line, []byte("% "))
		if i == 0 {
			line = bytes.Replace(line, []byte("("), []byte("\" \""), 1)
			line = bytes.Replace(line, []byte(")"), []byte("\" \""), 1)
		}
		line = append([]byte("\""), line...)
		line = append(line, []byte("\" ")...)
		out.Write(line)
	}

	out.WriteString(" \"\"\n")
}

func (m *Man) BlockCode(out *bytes.Buffer, text []byte, lang string) {
	out.WriteString("\n.PP\n.RS\n\n.nf\n")
	escapeSpecialChars(out, text)
	out.WriteString("\n.fi\n.RE\n")
}

func (m *Man) BlockQuote(out *bytes.Buffer, text []byte) {
	out.WriteString("\n.PP\n.RS\n")
	out.Write(text)
	out.WriteString("\n.RE\n")
}

func (m *Man) BlockHtml(out *bytes.Buffer, text []byte) {
	fmt.Errorf("man: BlockHtml not supported")
	out.Write(text)
}

func (m *Man) Header(out *bytes.Buffer, text func() bool, level int, id string) {
	marker := out.Len()

	switch {
	case marker == 0:
		// This is the doc header
		out.WriteString(".TH ")
	case level == 1:
		out.WriteString("\n\n.SH ")
	case level == 2:
		out.WriteString("\n.SH ")
	default:
		out.WriteString("\n.SS ")
	}

	if !text() {
		out.Truncate(marker)
		return
	}
}

func (m *Man) HRule(out *bytes.Buffer) {
	out.WriteString("\n.ti 0\n\\l'\\n(.lu'\n")
}

func (m *Man) List(out *bytes.Buffer, text func() bool, flags int) {
	marker := out.Len()
	out.WriteString(".IP ")
	if flags&blackfriday.LIST_TYPE_ORDERED != 0 {
		out.WriteString("\\(bu 2")
	} else {
		out.WriteString("\\n+[step" + string(flags) + "]")
	}
	out.WriteString("\n")
	if !text() {
		out.Truncate(marker)
		return
	}

}

func (m *Man) ListItem(out *bytes.Buffer, text []byte, flags int) {
	out.WriteString("\n\\item ")
	out.Write(text)
}

func (m *Man) Paragraph(out *bytes.Buffer, text func() bool) {
	marker := out.Len()
	out.WriteString("\n.PP\n")
	if !text() {
		out.Truncate(marker)
		return
	}
	if marker != 0 {
		out.WriteString("\n")
	}
}

// TODO: This might now work
func (m *Man) Table(out *bytes.Buffer, header []byte, body []byte, columnData []int) {
	out.WriteString(".TS\nallbox;\n")

	out.Write(header)
	out.Write(body)
	out.WriteString("\n.TE\n")
}

func (m *Man) TableRow(out *bytes.Buffer, text []byte) {
	if out.Len() > 0 {
		out.WriteString("\n")
	}
	out.Write(text)
	out.WriteString("\n")
}

func (m *Man) TableHeaderCell(out *bytes.Buffer, text []byte, align int) {
	if out.Len() > 0 {
		out.WriteString(" ")
	}
	out.Write(text)
	out.WriteString(" ")
}

// TODO: This is probably broken
func (m *Man) TableCell(out *bytes.Buffer, text []byte, align int) {
	if out.Len() > 0 {
		out.WriteString("\t")
	}
	out.Write(text)
	out.WriteString("\t")
}

func (m *Man) Footnotes(out *bytes.Buffer, text func() bool) {

}

func (m *Man) FootnoteItem(out *bytes.Buffer, name, text []byte, flags int) {

}

func (m *Man) AutoLink(out *bytes.Buffer, link []byte, kind int) {
	out.WriteString("\n\\[la]")
	out.Write(link)
	out.WriteString("\\[ra]")
}

func (m *Man) CodeSpan(out *bytes.Buffer, text []byte) {
	out.WriteString("\\fB\\fC")
	escapeSpecialChars(out, text)
	out.WriteString("\\fR")
}

func (m *Man) DoubleEmphasis(out *bytes.Buffer, text []byte) {
	out.WriteString("\\fB")
	out.Write(text)
	out.WriteString("\\fP")
}

func (m *Man) Emphasis(out *bytes.Buffer, text []byte) {
	out.WriteString("\\fI")
	out.Write(text)
	out.WriteString("\\fP")
}

func (m *Man) Image(out *bytes.Buffer, link []byte, title []byte, alt []byte) {
	fmt.Errorf("man: Image not supported")
}

func (m *Man) LineBreak(out *bytes.Buffer) {
	out.WriteString("\n.br\n")
}

func (m *Man) Link(out *bytes.Buffer, link []byte, title []byte, content []byte) {
	m.AutoLink(out, link, 0)
}

func (m *Man) RawHtmlTag(out *bytes.Buffer, tag []byte) {
	fmt.Errorf("man: Raw HTML not supported")
}

func (m *Man) TripleEmphasis(out *bytes.Buffer, text []byte) {
	out.WriteString("\\s+2")
	out.Write(text)
	out.WriteString("\\s-2")
}

func (m *Man) StrikeThrough(out *bytes.Buffer, text []byte) {
	fmt.Errorf("man: strikethrough not supported")
}

func (m *Man) FootnoteRef(out *bytes.Buffer, ref []byte, id int) {

}

func (m *Man) Entity(out *bytes.Buffer, entity []byte) {
	// TODO: convert this into a unicode character or something
	out.Write(entity)
}

func processFooterText(text []byte) []byte {
	text = bytes.TrimPrefix(text, []byte("% "))
	newText := []byte{}
	textArr := strings.Split(string(text), ") ")

	for i, w := range textArr {
		if i == 0 {
			w = strings.Replace(w, "(", "\" \"", 1)
			w = fmt.Sprintf("\"%s\"", w)
		} else {
			w = fmt.Sprintf(" \"%s\"", w)
		}
		newText = append(newText, []byte(w)...)
	}
	newText = append(newText, []byte(" \"\"")...)

	return newText
}

func (m *Man) NormalText(out *bytes.Buffer, text []byte) {
	escapeSpecialChars(out, text)
}

func (m *Man) DocumentHeader(out *bytes.Buffer) {
}

func (m *Man) DocumentFooter(out *bytes.Buffer) {
}

func needsBackslash(c byte) bool {
	for _, r := range []byte("-_{}&\\~") {
		if c == r {
			return true
		}
	}
	return false
}

func escapeSpecialChars(out *bytes.Buffer, text []byte) {
	for i := 0; i < len(text); i++ {
		// directly copy normal characters
		org := i

		for i < len(text) && !needsBackslash(text[i]) {
			i++
		}
		if i > org {
			out.Write(text[org:i])
		}

		// escape a character
		if i >= len(text) {
			break
		}
		out.WriteByte('\\')
		out.WriteByte(text[i])
	}
}
<commit_msg>Render raw html as is<commit_after>package mangen

import (
	"bytes"
	"fmt"
	"strings"

	"github.com/russross/blackfriday"
)

type Man struct{}

func ManRenderer(flags int) blackfriday.Renderer {
	return &Man{}
}

func (m *Man) GetFlags() int {
	return 0
}

func (m *Man) TitleBlock(out *bytes.Buffer, text []byte) {
	out.WriteString(".TH ")

	splitText := bytes.Split(text, []byte("\n"))
	for i, line := range splitText {
		line = bytes.TrimPrefix(line, []byte("% "))
		if i == 0 {
			line = bytes.Replace(line, []byte("("), []byte("\" \""), 1)
			line = bytes.Replace(line, []byte(")"), []byte("\" \""), 1)
		}
		line = append([]byte("\""), line...)
		line = append(line, []byte("\" ")...)
		out.Write(line)
	}

	out.WriteString(" \"\"\n")
}

func (m *Man) BlockCode(out *bytes.Buffer, text []byte, lang string) {
	out.WriteString("\n.PP\n.RS\n\n.nf\n")
	escapeSpecialChars(out, text)
	out.WriteString("\n.fi\n.RE\n")
}

func (m *Man) BlockQuote(out *bytes.Buffer, text []byte) {
	out.WriteString("\n.PP\n.RS\n")
	out.Write(text)
	out.WriteString("\n.RE\n")
}

func (m *Man) BlockHtml(out *bytes.Buffer, text []byte) {
	fmt.Errorf("man: BlockHtml not supported")
	out.Write(text)
}

func (m *Man) Header(out *bytes.Buffer, text func() bool, level int, id string) {
	marker := out.Len()

	switch {
	case marker == 0:
		// This is the doc header
		out.WriteString(".TH ")
	case level == 1:
		out.WriteString("\n\n.SH ")
	case level == 2:
		out.WriteString("\n.SH ")
	default:
		out.WriteString("\n.SS ")
	}

	if !text() {
		out.Truncate(marker)
		return
	}
}

func (m *Man) HRule(out *bytes.Buffer) {
	out.WriteString("\n.ti 0\n\\l'\\n(.lu'\n")
}

func (m *Man) List(out *bytes.Buffer, text func() bool, flags int) {
	marker := out.Len()
	out.WriteString(".IP ")
	if flags&blackfriday.LIST_TYPE_ORDERED != 0 {
		out.WriteString("\\(bu 2")
	} else {
		out.WriteString("\\n+[step" + string(flags) + "]")
	}
	out.WriteString("\n")
	if !text() {
		out.Truncate(marker)
		return
	}

}

func (m *Man) ListItem(out *bytes.Buffer, text []byte, flags int) {
	out.WriteString("\n\\item ")
	out.Write(text)
}

func (m *Man) Paragraph(out *bytes.Buffer, text func() bool) {
	marker := out.Len()
	out.WriteString("\n.PP\n")
	if !text() {
		out.Truncate(marker)
		return
	}
	if marker != 0 {
		out.WriteString("\n")
	}
}

// TODO: This might now work
func (m *Man) Table(out *bytes.Buffer, header []byte, body []byte, columnData []int) {
	out.WriteString(".TS\nallbox;\n")

	out.Write(header)
	out.Write(body)
	out.WriteString("\n.TE\n")
}

func (m *Man) TableRow(out *bytes.Buffer, text []byte) {
	if out.Len() > 0 {
		out.WriteString("\n")
	}
	out.Write(text)
	out.WriteString("\n")
}

func (m *Man) TableHeaderCell(out *bytes.Buffer, text []byte, align int) {
	if out.Len() > 0 {
		out.WriteString(" ")
	}
	out.Write(text)
	out.WriteString(" ")
}

// TODO: This is probably broken
func (m *Man) TableCell(out *bytes.Buffer, text []byte, align int) {
	if out.Len() > 0 {
		out.WriteString("\t")
	}
	out.Write(text)
	out.WriteString("\t")
}

func (m *Man) Footnotes(out *bytes.Buffer, text func() bool) {

}

func (m *Man) FootnoteItem(out *bytes.Buffer, name, text []byte, flags int) {

}

func (m *Man) AutoLink(out *bytes.Buffer, link []byte, kind int) {
	out.WriteString("\n\\[la]")
	out.Write(link)
	out.WriteString("\\[ra]")
}

func (m *Man) CodeSpan(out *bytes.Buffer, text []byte) {
	out.WriteString("\\fB\\fC")
	escapeSpecialChars(out, text)
	out.WriteString("\\fR")
}

func (m *Man) DoubleEmphasis(out *bytes.Buffer, text []byte) {
	out.WriteString("\\fB")
	out.Write(text)
	out.WriteString("\\fP")
}

func (m *Man) Emphasis(out *bytes.Buffer, text []byte) {
	out.WriteString("\\fI")
	out.Write(text)
	out.WriteString("\\fP")
}

func (m *Man) Image(out *bytes.Buffer, link []byte, title []byte, alt []byte) {
	fmt.Errorf("man: Image not supported")
}

func (m *Man) LineBreak(out *bytes.Buffer) {
	out.WriteString("\n.br\n")
}

func (m *Man) Link(out *bytes.Buffer, link []byte, title []byte, content []byte) {
	m.AutoLink(out, link, 0)
}

func (m *Man) RawHtmlTag(out *bytes.Buffer, tag []byte) {
	out.Write(tag)
}

func (m *Man) TripleEmphasis(out *bytes.Buffer, text []byte) {
	out.WriteString("\\s+2")
	out.Write(text)
	out.WriteString("\\s-2")
}

func (m *Man) StrikeThrough(out *bytes.Buffer, text []byte) {
	fmt.Errorf("man: strikethrough not supported")
}

func (m *Man) FootnoteRef(out *bytes.Buffer, ref []byte, id int) {

}

func (m *Man) Entity(out *bytes.Buffer, entity []byte) {
	// TODO: convert this into a unicode character or something
	out.Write(entity)
}

func processFooterText(text []byte) []byte {
	text = bytes.TrimPrefix(text, []byte("% "))
	newText := []byte{}
	textArr := strings.Split(string(text), ") ")

	for i, w := range textArr {
		if i == 0 {
			w = strings.Replace(w, "(", "\" \"", 1)
			w = fmt.Sprintf("\"%s\"", w)
		} else {
			w = fmt.Sprintf(" \"%s\"", w)
		}
		newText = append(newText, []byte(w)...)
	}
	newText = append(newText, []byte(" \"\"")...)

	return newText
}

func (m *Man) NormalText(out *bytes.Buffer, text []byte) {
	escapeSpecialChars(out, text)
}

func (m *Man) DocumentHeader(out *bytes.Buffer) {
}

func (m *Man) DocumentFooter(out *bytes.Buffer) {
}

func needsBackslash(c byte) bool {
	for _, r := range []byte("-_{}&\\~") {
		if c == r {
			return true
		}
	}
	return false
}

func escapeSpecialChars(out *bytes.Buffer, text []byte) {
	for i := 0; i < len(text); i++ {
		// directly copy normal characters
		org := i

		for i < len(text) && !needsBackslash(text[i]) {
			i++
		}
		if i > org {
			out.Write(text[org:i])
		}

		// escape a character
		if i >= len(text) {
			break
		}
		out.WriteByte('\\')
		out.WriteByte(text[i])
	}
}
<|endoftext|>


<commit_before>package mails

import (
	"bytes"
	"crypto/md5"
	"fmt"
	"net/url"
	"os"
	"regexp"

	"github.com/toomore/mailbox/campaign"
	"github.com/toomore/mailbox/utils"
)

var areg = regexp.MustCompile(`href="(http[s]?://[a-zA-z0-9/\.:?=,-@%()]+)"`)

// ReplaceReader is to replace reader open mail link
func ReplaceReader(html *[]byte, cid string, seed string, uid string) {
	data := url.Values{}
	data.Set("c", cid)
	data.Set("u", uid)
	hm := campaign.MakeMacSeed(seed, data)
	*html = bytes.Replace(
		*html,
		[]byte("{{READER}}"),
		[]byte(fmt.Sprintf("https://%s/read/%x?%s", os.Getenv("mailbox_web_site"), hm, data.Encode())),
		1)
}

// ReplaceFname is to replace FNAME tag
func ReplaceFname(html *[]byte, fname string) {
	*html = bytes.Replace(*html, []byte("{{FNAME}}"), []byte(fname), -1)
}

// ReplaceATag is to replace HTML a tag
func ReplaceATag(html *[]byte, allATags []LinksData, cid string, seed string, uid string) {
	for _, v := range allATags {
		data := url.Values{}
		data.Set("c", cid)
		data.Set("u", uid)
		data.Set("l", v.LinkID)
		data.Set("t", "a")
		hm := campaign.MakeMacSeed(seed, data)

		*html = bytes.Replace(*html, []byte(fmt.Sprintf("href=\"%s\"", v.URL)),
			[]byte(fmt.Sprintf("href=\"https://%s/door/%x?%s\"", os.Getenv("mailbox_web_site"), hm, data.Encode())), -1)
	}
}

// LinksData is the link data
type LinksData struct {
	Md5h   string
	LinkID string
	URL    []byte
}

// FilterATags is to filter, find all a tag data
func FilterATags(body []byte, cid string) []LinksData {
	allATags := areg.FindAllSubmatch(body, -1)
	result := make([]LinksData, len(allATags))
	for i, v := range allATags {
		md5h := md5.New()
		md5h.Write(v[1])
		md5hstr := fmt.Sprintf("%x", md5h.Sum(nil))
		linkID := fmt.Sprintf("%s", utils.GenSeed())
		_, err := utils.GetConn().Query(`INSERT INTO links(id,cid,url,urlhash) VALUES(?,?,?,?)`, linkID, cid, v[1], md5hstr)
		if err != nil {
			rows, _ := utils.GetConn().Query(`SELECT id FROM links WHERE cid=? AND urlhash=?`, cid, md5hstr)
			for rows.Next() {
				rows.Scan(&linkID)
			}
		}
		result[i].Md5h = md5hstr
		result[i].LinkID = linkID
		result[i].URL = v[1]
	}
	return result
}
<commit_msg>FIxed replace<commit_after>package mails

import (
	"bytes"
	"crypto/md5"
	"fmt"
	"net/url"
	"os"
	"regexp"

	"github.com/toomore/mailbox/campaign"
	"github.com/toomore/mailbox/utils"
)

var areg = regexp.MustCompile(`href="(http[s]?://[a-zA-z0-9/\.:?=,-@%()_&]+)"`)

// ReplaceReader is to replace reader open mail link
func ReplaceReader(html *[]byte, cid string, seed string, uid string) {
	data := url.Values{}
	data.Set("c", cid)
	data.Set("u", uid)
	hm := campaign.MakeMacSeed(seed, data)
	*html = bytes.Replace(
		*html,
		[]byte("{{READER}}"),
		[]byte(fmt.Sprintf("https://%s/read/%x?%s", os.Getenv("mailbox_web_site"), hm, data.Encode())),
		1)
}

// ReplaceFname is to replace FNAME tag
func ReplaceFname(html *[]byte, fname string) {
	*html = bytes.Replace(*html, []byte("{{FNAME}}"), []byte(fname), -1)
}

// ReplaceATag is to replace HTML a tag
func ReplaceATag(html *[]byte, allATags []LinksData, cid string, seed string, uid string) {
	for _, v := range allATags {
		data := url.Values{}
		data.Set("c", cid)
		data.Set("u", uid)
		data.Set("l", v.LinkID)
		data.Set("t", "a")
		hm := campaign.MakeMacSeed(seed, data)

		*html = bytes.Replace(*html, []byte(fmt.Sprintf("href=\"%s\"", v.URL)),
			[]byte(fmt.Sprintf("href=\"https://%s/door/%x?%s\"", os.Getenv("mailbox_web_site"), hm, data.Encode())), -1)
	}
}

// LinksData is the link data
type LinksData struct {
	Md5h   string
	LinkID string
	URL    []byte
}

// FilterATags is to filter, find all a tag data
func FilterATags(body []byte, cid string) []LinksData {
	allATags := areg.FindAllSubmatch(body, -1)
	result := make([]LinksData, len(allATags))
	for i, v := range allATags {
		md5h := md5.New()
		md5h.Write(v[1])
		md5hstr := fmt.Sprintf("%x", md5h.Sum(nil))
		linkID := fmt.Sprintf("%s", utils.GenSeed())
		_, err := utils.GetConn().Query(`INSERT INTO links(id,cid,url,urlhash) VALUES(?,?,?,?)`, linkID, cid, v[1], md5hstr)
		if err != nil {
			rows, _ := utils.GetConn().Query(`SELECT id FROM links WHERE cid=? AND urlhash=?`, cid, md5hstr)
			for rows.Next() {
				rows.Scan(&linkID)
			}
		}
		result[i].Md5h = md5hstr
		result[i].LinkID = linkID
		result[i].URL = v[1]
	}
	return result
}
<|endoftext|>


<commit_before>// Copyright 2013 Hui Chen
// Copyright 2016 ego authors
//
// Licensed under the Apache 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://www.apache.org/licenses/LICENSE-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 core

import (
	"log"
	"sort"
	"sync"

	"github.com/go-ego/riot/types"
	"github.com/go-ego/riot/utils"
)

// Ranker ranker
type Ranker struct {
	lock struct {
		sync.RWMutex
		fields map[uint64]interface{}
		docs   map[uint64]bool
		// new
		content map[uint64]string
		attri   map[uint64]interface{}
	}

	idOnly      bool
	initialized bool
}

// Init init ranker
func (ranker *Ranker) Init(onlyID ...bool) {
	if ranker.initialized == true {
		log.Fatal("The Ranker can not be initialized twice.")
	}
	ranker.initialized = true

	if len(onlyID) > 0 {
		ranker.idOnly = onlyID[0]
	}

	ranker.lock.fields = make(map[uint64]interface{})
	ranker.lock.docs = make(map[uint64]bool)

	if !ranker.idOnly {
		// new
		ranker.lock.content = make(map[uint64]string)
		ranker.lock.attri = make(map[uint64]interface{})
	}
}

// AddDoc add doc
// 给某个文档添加评分字段
func (ranker *Ranker) AddDoc(
	// docId uint64, fields interface{}, content string, attri interface{}) {
	docId uint64, fields interface{}, content ...interface{}) {
	if ranker.initialized == false {
		log.Fatal("The Ranker has not been initialized.")
	}

	ranker.lock.Lock()
	ranker.lock.fields[docId] = fields
	ranker.lock.docs[docId] = true

	if !ranker.idOnly {
		// new
		if len(content) > 0 {
			ranker.lock.content[docId] = content[0].(string)
		}

		if len(content) > 1 {
			ranker.lock.attri[docId] = content[1]
			// ranker.lock.attri[docId] = attri
		}
	}

	ranker.lock.Unlock()
}

// RemoveDoc 删除某个文档的评分字段
func (ranker *Ranker) RemoveDoc(docId uint64) {
	if ranker.initialized == false {
		log.Fatal("The Ranker has not been initialized.")
	}

	ranker.lock.Lock()
	delete(ranker.lock.fields, docId)
	delete(ranker.lock.docs, docId)

	if !ranker.idOnly {
		// new
		delete(ranker.lock.content, docId)
		delete(ranker.lock.attri, docId)
	}

	ranker.lock.Unlock()
}

func maxOutput(options types.RankOpts, docsLen int) (int, int) {
	var start, end int
	if options.MaxOutputs != 0 {
		start = utils.MinInt(options.OutputOffset, docsLen)
		end = utils.MinInt(options.OutputOffset+options.MaxOutputs, docsLen)
		return start, end
	}

	start = utils.MinInt(options.OutputOffset, docsLen)
	end = docsLen
	return start, end
}

// RankDocID rank docs by types.ScoredIDs
func (ranker *Ranker) RankDocID(docs []types.IndexedDoc,
	options types.RankOpts, countDocsOnly bool) (types.ScoredIDs, int) {

	var outputDocs types.ScoredIDs
	numDocs := 0

	for _, d := range docs {
		ranker.lock.RLock()
		// 判断 doc 是否存在
		if _, ok := ranker.lock.docs[d.DocId]; ok {

			fs := ranker.lock.fields[d.DocId]

			ranker.lock.RUnlock()
			// 计算评分并剔除没有分值的文档
			scores := options.ScoringCriteria.Score(d, fs)
			if len(scores) > 0 {
				if !countDocsOnly {
					outputDocs = append(outputDocs, types.ScoredID{
						DocId:            d.DocId,
						Scores:           scores,
						TokenSnippetLocs: d.TokenSnippetLocs,
						TokenLocs:        d.TokenLocs})
				}
				numDocs++
			}
		} else {
			ranker.lock.RUnlock()
		}
	}

	// 排序
	if !countDocsOnly {
		if options.ReverseOrder {
			sort.Sort(sort.Reverse(outputDocs))
		} else {
			sort.Sort(outputDocs)
		}
		// 当用户要求只返回部分结果时返回部分结果
		docsLen := len(outputDocs)
		start, end := maxOutput(options, docsLen)

		return outputDocs[start:end], numDocs
	}

	return outputDocs, numDocs
}

// RankDocs rank docs by types.ScoredDocs
func (ranker *Ranker) RankDocs(docs []types.IndexedDoc,
	options types.RankOpts, countDocsOnly bool) (types.ScoredDocs, int) {

	var outputDocs types.ScoredDocs
	numDocs := 0

	for _, d := range docs {
		ranker.lock.RLock()
		// 判断 doc 是否存在
		if _, ok := ranker.lock.docs[d.DocId]; ok {

			fs := ranker.lock.fields[d.DocId]
			content := ranker.lock.content[d.DocId]
			attri := ranker.lock.attri[d.DocId]

			ranker.lock.RUnlock()
			// 计算评分并剔除没有分值的文档
			scores := options.ScoringCriteria.Score(d, fs)
			if len(scores) > 0 {
				if !countDocsOnly {
					scoredID := types.ScoredID{
						DocId:            d.DocId,
						Scores:           scores,
						TokenSnippetLocs: d.TokenSnippetLocs,
						TokenLocs:        d.TokenLocs,
					}

					outputDocs = append(outputDocs,
						types.ScoredDoc{
							ScoredID: scoredID,
							// new
							Fields:  fs,
							Content: content,
							Attri:   attri,
						})
				}
				numDocs++
			}
		} else {
			ranker.lock.RUnlock()
		}
	}

	// 排序
	if !countDocsOnly {
		if options.ReverseOrder {
			sort.Sort(sort.Reverse(outputDocs))
		} else {
			sort.Sort(outputDocs)
		}
		// 当用户要求只返回部分结果时返回部分结果
		docsLen := len(outputDocs)
		start, end := maxOutput(options, docsLen)

		return outputDocs[start:end], numDocs
	}

	return outputDocs, numDocs
}

// Rank rank docs
// 给文档评分并排序
func (ranker *Ranker) Rank(docs []types.IndexedDoc,
	options types.RankOpts, countDocsOnly bool) (interface{}, int) {

	if ranker.initialized == false {
		log.Fatal("The Ranker has not been initialized.")
	}

	// 对每个文档评分
	if ranker.idOnly {
		outputDocs, numDocs := ranker.RankDocID(docs, options, countDocsOnly)
		return outputDocs, numDocs
	}

	outputDocs, numDocs := ranker.RankDocs(docs, options, countDocsOnly)
	return outputDocs, numDocs
}
<commit_msg>optimize ranker code split func<commit_after>// Copyright 2013 Hui Chen
// Copyright 2016 ego authors
//
// Licensed under the Apache 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://www.apache.org/licenses/LICENSE-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 core

import (
	"log"
	"sort"
	"sync"

	"github.com/go-ego/riot/types"
	"github.com/go-ego/riot/utils"
)

// Ranker ranker
type Ranker struct {
	lock struct {
		sync.RWMutex
		fields map[uint64]interface{}
		docs   map[uint64]bool
		// new
		content map[uint64]string
		attri   map[uint64]interface{}
	}

	idOnly      bool
	initialized bool
}

// Init init ranker
func (ranker *Ranker) Init(onlyID ...bool) {
	if ranker.initialized == true {
		log.Fatal("The Ranker can not be initialized twice.")
	}
	ranker.initialized = true

	if len(onlyID) > 0 {
		ranker.idOnly = onlyID[0]
	}

	ranker.lock.fields = make(map[uint64]interface{})
	ranker.lock.docs = make(map[uint64]bool)

	if !ranker.idOnly {
		// new
		ranker.lock.content = make(map[uint64]string)
		ranker.lock.attri = make(map[uint64]interface{})
	}
}

// AddDoc add doc
// 给某个文档添加评分字段
func (ranker *Ranker) AddDoc(
	// docId uint64, fields interface{}, content string, attri interface{}) {
	docId uint64, fields interface{}, content ...interface{}) {
	if ranker.initialized == false {
		log.Fatal("The Ranker has not been initialized.")
	}

	ranker.lock.Lock()
	ranker.lock.fields[docId] = fields
	ranker.lock.docs[docId] = true

	if !ranker.idOnly {
		// new
		if len(content) > 0 {
			ranker.lock.content[docId] = content[0].(string)
		}

		if len(content) > 1 {
			ranker.lock.attri[docId] = content[1]
			// ranker.lock.attri[docId] = attri
		}
	}

	ranker.lock.Unlock()
}

// RemoveDoc 删除某个文档的评分字段
func (ranker *Ranker) RemoveDoc(docId uint64) {
	if ranker.initialized == false {
		log.Fatal("The Ranker has not been initialized.")
	}

	ranker.lock.Lock()
	delete(ranker.lock.fields, docId)
	delete(ranker.lock.docs, docId)

	if !ranker.idOnly {
		// new
		delete(ranker.lock.content, docId)
		delete(ranker.lock.attri, docId)
	}

	ranker.lock.Unlock()
}

func maxOutput(options types.RankOpts, docsLen int) (int, int) {
	var start, end int
	if options.MaxOutputs != 0 {
		start = utils.MinInt(options.OutputOffset, docsLen)
		end = utils.MinInt(options.OutputOffset+options.MaxOutputs, docsLen)
		return start, end
	}

	start = utils.MinInt(options.OutputOffset, docsLen)
	end = docsLen
	return start, end
}

func (ranker *Ranker) rankOutIDs(docs []types.IndexedDoc, options types.RankOpts,
	countDocsOnly bool) (outputDocs types.ScoredIDs, numDocs int) {
	for _, d := range docs {
		ranker.lock.RLock()
		// 判断 doc 是否存在
		if _, ok := ranker.lock.docs[d.DocId]; ok {

			fs := ranker.lock.fields[d.DocId]
			ranker.lock.RUnlock()

			// 计算评分并剔除没有分值的文档
			scores := options.ScoringCriteria.Score(d, fs)
			if len(scores) > 0 {
				if !countDocsOnly {
					outputDocs = append(outputDocs,
						types.ScoredID{
							DocId:            d.DocId,
							Scores:           scores,
							TokenSnippetLocs: d.TokenSnippetLocs,
							TokenLocs:        d.TokenLocs,
						})
				}
				numDocs++
			}
		} else {
			ranker.lock.RUnlock()
		}
	}

	return
}

// RankDocID rank docs by types.ScoredIDs
func (ranker *Ranker) RankDocID(docs []types.IndexedDoc,
	options types.RankOpts, countDocsOnly bool) (types.ScoredIDs, int) {

	outputDocs, numDocs := ranker.rankOutIDs(docs, options, countDocsOnly)

	// 排序
	if !countDocsOnly {
		if options.ReverseOrder {
			sort.Sort(sort.Reverse(outputDocs))
		} else {
			sort.Sort(outputDocs)
		}
		// 当用户要求只返回部分结果时返回部分结果
		docsLen := len(outputDocs)
		start, end := maxOutput(options, docsLen)

		return outputDocs[start:end], numDocs
	}

	return outputDocs, numDocs
}

func (ranker *Ranker) rankOutDocs(docs []types.IndexedDoc, options types.RankOpts,
	countDocsOnly bool) (outputDocs types.ScoredDocs, numDocs int) {
	for _, d := range docs {
		ranker.lock.RLock()
		// 判断 doc 是否存在
		if _, ok := ranker.lock.docs[d.DocId]; ok {

			fs := ranker.lock.fields[d.DocId]
			content := ranker.lock.content[d.DocId]
			attri := ranker.lock.attri[d.DocId]
			ranker.lock.RUnlock()

			// 计算评分并剔除没有分值的文档
			scores := options.ScoringCriteria.Score(d, fs)
			if len(scores) > 0 {
				if !countDocsOnly {
					scoredID := types.ScoredID{
						DocId:            d.DocId,
						Scores:           scores,
						TokenSnippetLocs: d.TokenSnippetLocs,
						TokenLocs:        d.TokenLocs,
					}

					outputDocs = append(outputDocs,
						types.ScoredDoc{
							ScoredID: scoredID,
							// new
							Fields:  fs,
							Content: content,
							Attri:   attri,
						})
				}
				numDocs++
			}
		} else {
			ranker.lock.RUnlock()
		}
	}

	return
}

// RankDocs rank docs by types.ScoredDocs
func (ranker *Ranker) RankDocs(docs []types.IndexedDoc,
	options types.RankOpts, countDocsOnly bool) (types.ScoredDocs, int) {

	outputDocs, numDocs := ranker.rankOutDocs(docs, options, countDocsOnly)

	// 排序
	if !countDocsOnly {
		if options.ReverseOrder {
			sort.Sort(sort.Reverse(outputDocs))
		} else {
			sort.Sort(outputDocs)
		}
		// 当用户要求只返回部分结果时返回部分结果
		docsLen := len(outputDocs)
		start, end := maxOutput(options, docsLen)

		return outputDocs[start:end], numDocs
	}

	return outputDocs, numDocs
}

// Rank rank docs
// 给文档评分并排序
func (ranker *Ranker) Rank(docs []types.IndexedDoc,
	options types.RankOpts, countDocsOnly bool) (interface{}, int) {

	if ranker.initialized == false {
		log.Fatal("The Ranker has not been initialized.")
	}

	// 对每个文档评分
	if ranker.idOnly {
		outputDocs, numDocs := ranker.RankDocID(docs, options, countDocsOnly)
		return outputDocs, numDocs
	}

	outputDocs, numDocs := ranker.RankDocs(docs, options, countDocsOnly)
	return outputDocs, numDocs
}
<|endoftext|>