<commit_before>package logger

import (
	"os"

	. "github.com/tendermint/go-common"
	"github.com/tendermint/log15"
)

//var rootHandler log15.Handler
var mainHandler log15.Handler
var bypassHandler log15.Handler

func init() {
	Reset()
}

func SetLogLevel(logLevel string) {
	resetWithLogLevel(logLevel)
}

func resetWithLogLevel(logLevel string) {
	// main handler
	//handlers := []log15.Handler{}
	mainHandler = log15.LvlFilterHandler(
		getLevel(logLevel),
		log15.StreamHandler(os.Stdout, log15.TerminalFormat()),
	)
	//handlers = append(handlers, mainHandler)

	// bypass handler for not filtering on global logLevel.
	bypassHandler = log15.StreamHandler(os.Stdout, log15.TerminalFormat())
	//handlers = append(handlers, bypassHandler)

	// Set rootHandler.
	//rootHandler = log15.MultiHandler(handlers...)

	// By setting handlers on the root, we handle events from all loggers.
	log15.Root().SetHandler(mainHandler)
}

// You might want to call this after resetting tendermint/go-config.
func Reset() {

	var logLevel string = "debug"
	if config != nil {
		logLevel = config.GetString("log_level")
	}

	resetWithLogLevel(logLevel)
}

// See go-wire/log for an example of usage.
func MainHandler() log15.Handler {
	return mainHandler
}

func BypassHandler() log15.Handler {
	return bypassHandler
}

func New(ctx ...interface{}) log15.Logger {
	return NewMain(ctx...)
}

func NewMain(ctx ...interface{}) log15.Logger {
	return log15.Root().New(ctx...)
}

func NewBypass(ctx ...interface{}) log15.Logger {
	bypass := log15.New(ctx...)
	bypass.SetHandler(bypassHandler)
	return bypass
}

func getLevel(lvlString string) log15.Lvl {
	lvl, err := log15.LvlFromString(lvlString)
	if err != nil {
		Exit(Fmt("Invalid log level %v: %v", lvlString, err))
	}
	return lvl
}

//----------------------------------------
// Exported from log15

var LvlFilterHandler = log15.LvlFilterHandler
var LvlDebug = log15.LvlDebug
var LvlInfo = log15.LvlInfo
var LvlWarn = log15.LvlWarn
var LvlError = log15.LvlError
<commit_msg>Conform to new go-config default config behavior<commit_after>package logger

import (
	"os"

	. "github.com/tendermint/go-common"
	"github.com/tendermint/log15"
)

//var rootHandler log15.Handler
var mainHandler log15.Handler
var bypassHandler log15.Handler

func init() {
	Reset()
}

func SetLogLevel(logLevel string) {
	resetWithLogLevel(logLevel)
}

func resetWithLogLevel(logLevel string) {
	// main handler
	//handlers := []log15.Handler{}
	mainHandler = log15.LvlFilterHandler(
		getLevel(logLevel),
		log15.StreamHandler(os.Stdout, log15.TerminalFormat()),
	)
	//handlers = append(handlers, mainHandler)

	// bypass handler for not filtering on global logLevel.
	bypassHandler = log15.StreamHandler(os.Stdout, log15.TerminalFormat())
	//handlers = append(handlers, bypassHandler)

	// Set rootHandler.
	//rootHandler = log15.MultiHandler(handlers...)

	// By setting handlers on the root, we handle events from all loggers.
	log15.Root().SetHandler(mainHandler)
}

// You might want to call this after resetting tendermint/go-config.
func Reset() {

	var logLevel string = "debug"
	if config != nil && config.IsSet("log_level") {
		logLevel = config.GetString("log_level")
	}

	resetWithLogLevel(logLevel)
}

// See go-wire/log for an example of usage.
func MainHandler() log15.Handler {
	return mainHandler
}

func BypassHandler() log15.Handler {
	return bypassHandler
}

func New(ctx ...interface{}) log15.Logger {
	return NewMain(ctx...)
}

func NewMain(ctx ...interface{}) log15.Logger {
	return log15.Root().New(ctx...)
}

func NewBypass(ctx ...interface{}) log15.Logger {
	bypass := log15.New(ctx...)
	bypass.SetHandler(bypassHandler)
	return bypass
}

func getLevel(lvlString string) log15.Lvl {
	lvl, err := log15.LvlFromString(lvlString)
	if err != nil {
		Exit(Fmt("Invalid log level %v: %v", lvlString, err))
	}
	return lvl
}

//----------------------------------------
// Exported from log15

var LvlFilterHandler = log15.LvlFilterHandler
var LvlDebug = log15.LvlDebug
var LvlInfo = log15.LvlInfo
var LvlWarn = log15.LvlWarn
var LvlError = log15.LvlError
<|endoftext|>


<commit_before>package logger

import (
	"bufio"
	"bytes"
	"io"
	stdlog "log"
	"regexp"
	"sync"
)

type rxMap map[*regexp.Regexp]func(Logger, map[string]string)

type syncWriter struct {
	w  io.Writer
	ch chan int

	sync *sync.WaitGroup
}

func (sw *syncWriter) Write(p []byte) (n int, err error) {
	sw.sync.Add(bytes.Count(p, []byte("\n")))
	defer sw.sync.Wait()

	n, err = sw.w.Write(p)
	return
}

func byteCounter(sw *syncWriter) (func([]byte, bool) (int, []byte, error), func()) {
	return func(data []byte, atEOF bool) (advance int, token []byte, err error) {
		advance, token, err = bufio.ScanLines(data, atEOF)
		return
	}, func() { sw.sync.Done() }
}

func NewLog(rxm rxMap, opts ...optFunc) *stdlog.Logger {
	logger := New(opts...)

	pr, pw := io.Pipe()
	sw := &syncWriter{w: pw, sync: new(sync.WaitGroup)}
	split, waitForPrintToFinishBeforeTheNextScan := byteCounter(sw)

	go func() {
		scan := bufio.NewScanner(pr)
		scan.Split(split)

		for scan.Scan() {
			text := scan.Text()
			for rx, fn := range rxm {
				if rx == nil {
					continue
				}
				if m, ok := match(rx, text); ok {
					fn(logger, m)
					goto Wait
				}
			}
			logger.Println(text)
		Wait:
			waitForPrintToFinishBeforeTheNextScan()
		}
	}()

	return stdlog.New(sw, "", 0)
}

func match(rx *regexp.Regexp, txt string) (map[string]string, bool) {
	m := make(map[string]string)
	matches := rx.FindStringSubmatch(txt)
	ok := matches != nil
	if ok {
		for i, name := range rx.SubexpNames() {
			if i != 0 && name != "" {
				m[name] = matches[i]
			}
		}
	}
	return m, ok
}
<commit_msg>remove an unused channel type from the syncWriter struct<commit_after>package logger

import (
	"bufio"
	"bytes"
	"io"
	stdlog "log"
	"regexp"
	"sync"
)

type rxMap map[*regexp.Regexp]func(Logger, map[string]string)

type syncWriter struct {
	w  io.Writer
	sync *sync.WaitGroup
}

func (sw *syncWriter) Write(p []byte) (n int, err error) {
	sw.sync.Add(bytes.Count(p, []byte("\n")))
	defer sw.sync.Wait()

	n, err = sw.w.Write(p)
	return
}

func byteCounter(sw *syncWriter) (func([]byte, bool) (int, []byte, error), func()) {
	return func(data []byte, atEOF bool) (advance int, token []byte, err error) {
		advance, token, err = bufio.ScanLines(data, atEOF)
		return
	}, func() { sw.sync.Done() }
}

func NewLog(rxm rxMap, opts ...optFunc) *stdlog.Logger {
	logger := New(opts...)

	pr, pw := io.Pipe()
	sw := &syncWriter{w: pw, sync: new(sync.WaitGroup)}
	split, waitForPrintToFinishBeforeTheNextScan := byteCounter(sw)

	go func() {
		scan := bufio.NewScanner(pr)
		scan.Split(split)

		for scan.Scan() {
			text := scan.Text()
			for rx, fn := range rxm {
				if rx == nil {
					continue
				}
				if m, ok := match(rx, text); ok {
					fn(logger, m)
					goto Wait
				}
			}
			logger.Println(text)
		Wait:
			waitForPrintToFinishBeforeTheNextScan()
		}
	}()

	return stdlog.New(sw, "", 0)
}

func match(rx *regexp.Regexp, txt string) (map[string]string, bool) {
	m := make(map[string]string)
	matches := rx.FindStringSubmatch(txt)
	ok := matches != nil
	if ok {
		for i, name := range rx.SubexpNames() {
			if i != 0 && name != "" {
				m[name] = matches[i]
			}
		}
	}
	return m, ok
}
<|endoftext|>


<commit_before>package gou

import (
	"fmt"
	"log"
	"os"
	"runtime"
	"strings"
	"sync"
	"time"
)

const (
	NOLOGGING = -1
	FATAL     = 0
	ERROR     = 1
	WARN      = 2
	INFO      = 3
	DEBUG     = 4
)

/*
https://github.com/mewkiz/pkg/tree/master/term
RED = '\033[0;1;31m'
GREEN = '\033[0;1;32m'
YELLOW = '\033[0;1;33m'
BLUE = '\033[0;1;34m'
MAGENTA = '\033[0;1;35m'
CYAN = '\033[0;1;36m'
WHITE = '\033[0;1;37m'
DARK_MAGENTA = '\033[0;35m'
ANSI_RESET = '\033[0m'
LogColor         = map[int]string{FATAL: "\033[0m\033[37m",
	ERROR: "\033[0m\033[31m",
	WARN:  "\033[0m\033[33m",
	INFO:  "\033[0m\033[32m",
	DEBUG: "\033[0m\033[34m"}

\e]PFdedede
*/

var (
	LogLevel    int = ERROR
	EMPTY       struct{}
	ErrLogLevel int = ERROR
	logger      *log.Logger
	loggerErr   *log.Logger
	LogColor    = map[int]string{FATAL: "\033[0m\033[37m",
		ERROR: "\033[0m\033[31m",
		WARN:  "\033[0m\033[33m",
		INFO:  "\033[0m\033[35m",
		DEBUG: "\033[0m\033[34m"}
	LogPrefix = map[int]string{
		FATAL: "[FATAL] ",
		ERROR: "[ERROR] ",
		WARN:  "[WARN] ",
		INFO:  "[INFO] ",
		DEBUG: "[DEBUG] ",
	}
	postFix                      = "" //\033[0m
	LogLevelWords map[string]int = map[string]int{"fatal": 0, "error": 1, "warn": 2, "info": 3, "debug": 4, "none": -1}
	logThrottles                 = make(map[string]*Throttler)
	throttleMu    sync.Mutex
)

// Setup default logging to Stderr, equivalent to:
//
//	gou.SetLogger(log.New(os.Stderr, "", log.Ltime|log.Lshortfile), "debug")
func SetupLogging(lvl string) {
	SetLogger(log.New(os.Stderr, "", log.LstdFlags|log.Lshortfile|log.Lmicroseconds), strings.ToLower(lvl))
}

// Setup default logging to Stderr, equivalent to:
//
//	gou.SetLogger(log.New(os.Stderr, "", log.LstdFlags|log.Lshortfile|log.Lmicroseconds), level)
func SetupLoggingLong(lvl string) {
	SetLogger(log.New(os.Stderr, "", log.LstdFlags|log.Llongfile|log.Lmicroseconds), strings.ToLower(lvl))
}

// Setup colorized output if this is a terminal
func SetColorIfTerminal() {
	if IsTerminal() {
		SetColorOutput()
	}
}

// Setup colorized output
func SetColorOutput() {
	for lvl, color := range LogColor {
		LogPrefix[lvl] = color
	}
	postFix = "\033[0m"
}

// Setup default log output to go to a dev/null
//
//	log.SetOutput(new(DevNull))
func DiscardStandardLogger() {
	log.SetOutput(new(DevNull))
}

// you can set a logger, and log level,most common usage is:
//
//	gou.SetLogger(log.New(os.Stdout, "", log.LstdFlags), "debug")
//
//  loglevls:   debug, info, warn, error, fatal
// Note, that you can also set a seperate Error Log Level
func SetLogger(l *log.Logger, logLevel string) {
	logger = l
	LogLevelSet(logLevel)
}
func GetLogger() *log.Logger {
	return logger
}

// you can set a logger, and log level.  this is for errors, and assumes
// you are logging to Stderr (seperate from stdout above), allowing you to seperate
// debug&info logging from errors
//
//	gou.SetLogger(log.New(os.Stderr, "", log.LstdFlags), "debug")
//
//  loglevls:   debug, info, warn, error, fatal
func SetErrLogger(l *log.Logger, logLevel string) {
	loggerErr = l
	if lvl, ok := LogLevelWords[logLevel]; ok {
		ErrLogLevel = lvl
	}
}
func GetErrLogger() *log.Logger {
	return logger
}

// sets the log level from a string
func LogLevelSet(levelWord string) {
	if lvl, ok := LogLevelWords[levelWord]; ok {
		LogLevel = lvl
	}
}

// Log at debug level
func Debug(v ...interface{}) {
	if LogLevel >= 4 {
		DoLog(3, DEBUG, fmt.Sprint(v...))
	}
}

// Debug log formatted
func Debugf(format string, v ...interface{}) {
	if LogLevel >= 4 {
		DoLog(3, DEBUG, fmt.Sprintf(format, v...))
	}
}

// Log at info level
func Info(v ...interface{}) {
	if LogLevel >= 3 {
		DoLog(3, INFO, fmt.Sprint(v...))
	}
}

// info log formatted
func Infof(format string, v ...interface{}) {
	if LogLevel >= 3 {
		DoLog(3, INFO, fmt.Sprintf(format, v...))
	}
}

// Log at warn level
func Warn(v ...interface{}) {
	if LogLevel >= 2 {
		DoLog(3, WARN, fmt.Sprint(v...))
	}
}

// Debug log formatted
func Warnf(format string, v ...interface{}) {
	if LogLevel >= 2 {
		DoLog(3, WARN, fmt.Sprintf(format, v...))
	}
}

// Log at error level
func Error(v ...interface{}) {
	if LogLevel >= 1 {
		DoLog(3, ERROR, fmt.Sprint(v...))
	}
}

// Error log formatted
func Errorf(format string, v ...interface{}) {
	if LogLevel >= 1 {
		DoLog(3, ERROR, fmt.Sprintf(format, v...))
	}
}

// Log this error, and return error object
func LogErrorf(format string, v ...interface{}) error {
	err := fmt.Errorf(format, v...)
	if LogLevel >= 1 {
		DoLog(3, ERROR, err.Error())
	}
	return err
}

// Log to logger if setup
//    Log(ERROR, "message")
func Log(logLvl int, v ...interface{}) {
	if LogLevel >= logLvl {
		DoLog(3, logLvl, fmt.Sprint(v...))
	}
}

// Log to logger if setup, grab a stack trace and add that as well
//
//    u.LogTracef(u.ERROR, "message %s", varx)
//
func LogTracef(logLvl int, format string, v ...interface{}) {
	if LogLevel >= logLvl {
		// grab a stack trace
		stackBuf := make([]byte, 6000)
		stackBufLen := runtime.Stack(stackBuf, false)
		stackTraceStr := string(stackBuf[0:stackBufLen])
		parts := strings.Split(stackTraceStr, "\n")
		if len(parts) > 1 {
			v = append(v, strings.Join(parts[3:len(parts)], "\n"))
		}
		DoLog(3, logLvl, fmt.Sprintf(format+"\n%v", v...))
	}
}

// Throttle logging based on key, such that key would never occur more than
//   @limit times per hour
//
//    LogThrottleKey(u.ERROR, 1,"error_that_happens_a_lot" "message %s", varx)
//
func LogThrottleKey(logLvl, limit int, key, format string, v ...interface{}) {
	if LogLevel >= logLvl {
		throttleMu.Lock()
		th, ok := logThrottles[key]
		if !ok {
			th = NewThrottler(limit, 3600*time.Second)
			logThrottles[key] = th
		}
		if th.Throttle() {
			throttleMu.Unlock()
			return
		}
		throttleMu.Unlock()
		DoLog(3, logLvl, fmt.Sprintf(format, v...))
	}
}

// Throttle logging based on @format as a key, such that key would never occur more than
//   @limit times per hour
//
//    LogThrottle(u.ERROR, 1, "message %s", varx)
//
func LogThrottle(logLvl, limit int, format string, v ...interface{}) {
	if LogLevel >= logLvl {
		throttleMu.Lock()
		th, ok := logThrottles[format]
		if !ok {
			th = NewThrottler(limit, 3600*time.Second)
			logThrottles[format] = th
		}
		if th.Throttle() {
			throttleMu.Unlock()
			return
		}
		throttleMu.Unlock()
		DoLog(3, logLvl, fmt.Sprintf(format, v...))
	}
}

// Log to logger if setup
//    Logf(ERROR, "message %d", 20)
func Logf(logLvl int, format string, v ...interface{}) {
	if LogLevel >= logLvl {
		DoLog(3, logLvl, fmt.Sprintf(format, v...))
	}
}

// Log to logger if setup
//    LogP(ERROR, "prefix", "message", anyItems, youWant)
func LogP(logLvl int, prefix string, v ...interface{}) {
	if ErrLogLevel >= logLvl && loggerErr != nil {
		loggerErr.Output(3, prefix+LogPrefix[logLvl]+fmt.Sprint(v...)+postFix)
	} else if LogLevel >= logLvl && logger != nil {
		logger.Output(3, prefix+LogPrefix[logLvl]+fmt.Sprint(v...)+postFix)
	}
}

// Log to logger if setup with a prefix
//    LogPf(ERROR, "prefix", "formatString %s %v", anyItems, youWant)
func LogPf(logLvl int, prefix string, format string, v ...interface{}) {
	if ErrLogLevel >= logLvl && loggerErr != nil {
		loggerErr.Output(3, prefix+LogPrefix[logLvl]+fmt.Sprintf(format, v...)+postFix)
	} else if LogLevel >= logLvl && logger != nil {
		logger.Output(3, prefix+LogPrefix[logLvl]+fmt.Sprintf(format, v...)+postFix)
	}
}

// When you want to use the log short filename flag, and want to use
// the lower level logging functions (say from an *Assert* type function)
// you need to modify the stack depth:
//
//     func init() {}
// 	       SetLogger(log.New(os.Stderr, "", log.Ltime|log.Lshortfile|log.Lmicroseconds), lvl)
//     }
//
//     func assert(t *testing.T, myData) {
//         // we want log line to show line that called this assert, not this line
//         LogD(5, DEBUG, v...)
//     }
func LogD(depth int, logLvl int, v ...interface{}) {
	if LogLevel >= logLvl {
		DoLog(depth, logLvl, fmt.Sprint(v...))
	}
}

// Low level log with depth , level, message and logger
func DoLog(depth, logLvl int, msg string) {
	if ErrLogLevel >= logLvl && loggerErr != nil {
		loggerErr.Output(depth, LogPrefix[logLvl]+msg+postFix)
	} else if LogLevel >= logLvl && logger != nil {
		logger.Output(depth, LogPrefix[logLvl]+msg+postFix)
	}
}

type winsize struct {
	Row    uint16
	Col    uint16
	Xpixel uint16
	Ypixel uint16
}

const (
	_TIOCGWINSZ = 0x5413 // OSX 1074295912
)

//http://play.golang.org/p/5LIA41Iqfp
// Dummy discard, satisfies io.Writer without importing io or os.
type DevNull struct{}

func (DevNull) Write(p []byte) (int, error) {
	return len(p), nil
}
<commit_msg>Messsing with the potential of writing logs strait to elasticsearch<commit_after>package gou

import (
	"bytes"
	"fmt"
	"log"
	"os"
	"runtime"
	"strings"
	"sync"
	"time"

	"github.com/mattbaird/elastigo/lib"
)

const (
	NOLOGGING = -1
	FATAL     = 0
	ERROR     = 1
	WARN      = 2
	INFO      = 3
	DEBUG     = 4
)

/*
https://github.com/mewkiz/pkg/tree/master/term
RED = '\033[0;1;31m'
GREEN = '\033[0;1;32m'
YELLOW = '\033[0;1;33m'
BLUE = '\033[0;1;34m'
MAGENTA = '\033[0;1;35m'
CYAN = '\033[0;1;36m'
WHITE = '\033[0;1;37m'
DARK_MAGENTA = '\033[0;35m'
ANSI_RESET = '\033[0m'
LogColor         = map[int]string{FATAL: "\033[0m\033[37m",
	ERROR: "\033[0m\033[31m",
	WARN:  "\033[0m\033[33m",
	INFO:  "\033[0m\033[32m",
	DEBUG: "\033[0m\033[34m"}

\e]PFdedede
*/

var (
	LogLevel    int = ERROR
	EMPTY       struct{}
	ErrLogLevel int = ERROR
	logger      *log.Logger
	loggerErr   *log.Logger
	LogColor    = map[int]string{FATAL: "\033[0m\033[37m",
		ERROR: "\033[0m\033[31m",
		WARN:  "\033[0m\033[33m",
		INFO:  "\033[0m\033[35m",
		DEBUG: "\033[0m\033[34m"}
	LogPrefix = map[int]string{
		FATAL: "[FATAL] ",
		ERROR: "[ERROR] ",
		WARN:  "[WARN] ",
		INFO:  "[INFO] ",
		DEBUG: "[DEBUG] ",
	}
	escapeNewlines                = bool
	postFix                       = "" //\033[0m
	LogLevelWords  map[string]int = map[string]int{"fatal": 0, "error": 1, "warn": 2, "info": 3, "debug": 4, "none": -1}
	logThrottles                  = make(map[string]*Throttler)
	throttleMu     sync.Mutex

	indexer *elastigo.BulkIndexer
	econn   *elastigo.Conn
)

// Setup default logging to Stderr, equivalent to:
//
//	gou.SetLogger(log.New(os.Stderr, "", log.Ltime|log.Lshortfile), "debug")
func SetupLogging(lvl string) {
	SetLogger(log.New(os.Stderr, "", log.LstdFlags|log.Lshortfile|log.Lmicroseconds), strings.ToLower(lvl))
}

// Setup default logging to Stderr, equivalent to:
//
//	gou.SetLogger(log.New(os.Stderr, "", log.LstdFlags|log.Lshortfile|log.Lmicroseconds), level)
func SetupLoggingLong(lvl string) {
	SetLogger(log.New(os.Stderr, "", log.LstdFlags|log.Llongfile|log.Lmicroseconds), strings.ToLower(lvl))
}

func SetupLoggingDestinations(hosts []string) {
	elastigoConn = elastigo.NewConn()
	esHost := strings.Replace(hosts, ":9200", "", -1)
	elastigoConn.SetHosts([]string{esHost})
	indexer := elastigoConn.NewBulkIndexerErrors(5, 120)
	indexer.Sender = func(buf *bytes.Buffer) error {
		log.Infof("es writing: %d bytes", buf.Len())
		return indexer.Send(buf)
	}
	indexer.Start()
	econn = elastigoConn
}

// Setup colorized output if this is a terminal
func SetColorIfTerminal() {
	if IsTerminal() {
		SetColorOutput()
	}
}

// Setup colorized output
func SetColorOutput() {
	for lvl, color := range LogColor {
		LogPrefix[lvl] = color
	}
	postFix = "\033[0m"
}

// Setup default log output to go to a dev/null
//
//	log.SetOutput(new(DevNull))
func DiscardStandardLogger() {
	log.SetOutput(new(DevNull))
}

// you can set a logger, and log level,most common usage is:
//
//	gou.SetLogger(log.New(os.Stdout, "", log.LstdFlags), "debug")
//
//  loglevls:   debug, info, warn, error, fatal
// Note, that you can also set a seperate Error Log Level
func SetLogger(l *log.Logger, logLevel string) {
	logger = l
	LogLevelSet(logLevel)
}
func GetLogger() *log.Logger {
	return logger
}

// you can set a logger, and log level.  this is for errors, and assumes
// you are logging to Stderr (seperate from stdout above), allowing you to seperate
// debug&info logging from errors
//
//	gou.SetLogger(log.New(os.Stderr, "", log.LstdFlags), "debug")
//
//  loglevls:   debug, info, warn, error, fatal
func SetErrLogger(l *log.Logger, logLevel string) {
	loggerErr = l
	if lvl, ok := LogLevelWords[logLevel]; ok {
		ErrLogLevel = lvl
	}
}
func GetErrLogger() *log.Logger {
	return logger
}

// sets the log level from a string
func LogLevelSet(levelWord string) {
	if lvl, ok := LogLevelWords[levelWord]; ok {
		LogLevel = lvl
	}
}

// Log at debug level
func Debug(v ...interface{}) {
	if LogLevel >= 4 {
		DoLog(3, DEBUG, fmt.Sprint(v...))
	}
}

// Debug log formatted
func Debugf(format string, v ...interface{}) {
	if LogLevel >= 4 {
		DoLog(3, DEBUG, fmt.Sprintf(format, v...))
	}
}

// Log at info level
func Info(v ...interface{}) {
	if LogLevel >= 3 {
		DoLog(3, INFO, fmt.Sprint(v...))
	}
}

// info log formatted
func Infof(format string, v ...interface{}) {
	if LogLevel >= 3 {
		DoLog(3, INFO, fmt.Sprintf(format, v...))
	}
}

// Log at warn level
func Warn(v ...interface{}) {
	if LogLevel >= 2 {
		DoLog(3, WARN, fmt.Sprint(v...))
	}
}

// Debug log formatted
func Warnf(format string, v ...interface{}) {
	if LogLevel >= 2 {
		DoLog(3, WARN, fmt.Sprintf(format, v...))
	}
}

// Log at error level
func Error(v ...interface{}) {
	if LogLevel >= 1 {
		DoLog(3, ERROR, fmt.Sprint(v...))
	}
}

// Error log formatted
func Errorf(format string, v ...interface{}) {
	if LogLevel >= 1 {
		DoLog(3, ERROR, fmt.Sprintf(format, v...))
	}
}

// Log this error, and return error object
func LogErrorf(format string, v ...interface{}) error {
	err := fmt.Errorf(format, v...)
	if LogLevel >= 1 {
		DoLog(3, ERROR, err.Error())
	}
	return err
}

// Log to logger if setup
//    Log(ERROR, "message")
func Log(logLvl int, v ...interface{}) {
	if LogLevel >= logLvl {
		DoLog(3, logLvl, fmt.Sprint(v...))
	}
}

// Log to logger if setup, grab a stack trace and add that as well
//
//    u.LogTracef(u.ERROR, "message %s", varx)
//
func LogTracef(logLvl int, format string, v ...interface{}) {
	if LogLevel >= logLvl {
		// grab a stack trace
		stackBuf := make([]byte, 6000)
		stackBufLen := runtime.Stack(stackBuf, false)
		stackTraceStr := string(stackBuf[0:stackBufLen])
		parts := strings.Split(stackTraceStr, "\n")
		if len(parts) > 1 {
			v = append(v, strings.Join(parts[3:len(parts)], "\n"))
		}
		DoLog(3, logLvl, fmt.Sprintf(format+"\n%v", v...))
	}
}

// Throttle logging based on key, such that key would never occur more than
//   @limit times per hour
//
//    LogThrottleKey(u.ERROR, 1,"error_that_happens_a_lot" "message %s", varx)
//
func LogThrottleKey(logLvl, limit int, key, format string, v ...interface{}) {
	if LogLevel >= logLvl {
		throttleMu.Lock()
		th, ok := logThrottles[key]
		if !ok {
			th = NewThrottler(limit, 3600*time.Second)
			logThrottles[key] = th
		}
		if th.Throttle() {
			throttleMu.Unlock()
			return
		}
		throttleMu.Unlock()
		DoLog(3, logLvl, fmt.Sprintf(format, v...))
	}
}

// Throttle logging based on @format as a key, such that key would never occur more than
//   @limit times per hour
//
//    LogThrottle(u.ERROR, 1, "message %s", varx)
//
func LogThrottle(logLvl, limit int, format string, v ...interface{}) {
	if LogLevel >= logLvl {
		throttleMu.Lock()
		th, ok := logThrottles[format]
		if !ok {
			th = NewThrottler(limit, 3600*time.Second)
			logThrottles[format] = th
		}
		if th.Throttle() {
			throttleMu.Unlock()
			return
		}
		throttleMu.Unlock()
		DoLog(3, logLvl, fmt.Sprintf(format, v...))
	}
}

// Log to logger if setup
//    Logf(ERROR, "message %d", 20)
func Logf(logLvl int, format string, v ...interface{}) {
	if LogLevel >= logLvl {
		DoLog(3, logLvl, fmt.Sprintf(format, v...))
	}
}

// Log to logger if setup
//    LogP(ERROR, "prefix", "message", anyItems, youWant)
func LogP(logLvl int, prefix string, v ...interface{}) {
	if ErrLogLevel >= logLvl && loggerErr != nil {
		loggerErr.Output(3, prefix+LogPrefix[logLvl]+fmt.Sprint(v...)+postFix)
	} else if LogLevel >= logLvl && logger != nil {
		logger.Output(3, prefix+LogPrefix[logLvl]+fmt.Sprint(v...)+postFix)
	}
}

// Log to logger if setup with a prefix
//    LogPf(ERROR, "prefix", "formatString %s %v", anyItems, youWant)
func LogPf(logLvl int, prefix string, format string, v ...interface{}) {
	if ErrLogLevel >= logLvl && loggerErr != nil {
		loggerErr.Output(3, prefix+LogPrefix[logLvl]+fmt.Sprintf(format, v...)+postFix)
	} else if LogLevel >= logLvl && logger != nil {
		logger.Output(3, prefix+LogPrefix[logLvl]+fmt.Sprintf(format, v...)+postFix)
	}
}

// When you want to use the log short filename flag, and want to use
// the lower level logging functions (say from an *Assert* type function)
// you need to modify the stack depth:
//
//     func init() {}
// 	       SetLogger(log.New(os.Stderr, "", log.Ltime|log.Lshortfile|log.Lmicroseconds), lvl)
//     }
//
//     func assert(t *testing.T, myData) {
//         // we want log line to show line that called this assert, not this line
//         LogD(5, DEBUG, v...)
//     }
func LogD(depth int, logLvl int, v ...interface{}) {
	if LogLevel >= logLvl {
		DoLog(depth, logLvl, fmt.Sprint(v...))
	}
}

// Low level log with depth , level, message and logger
func DoLog(depth, logLvl int, msg string) {
	if escapeNewlines {
		msg = EscapeNewlines(msg)
	}
	if ErrLogLevel >= logLvl && loggerErr != nil {
		loggerErr.Output(depth, LogPrefix[logLvl]+msg+postFix)
	} else if LogLevel >= logLvl && logger != nil {
		logger.Output(depth, LogPrefix[logLvl]+msg+postFix)
	} else if LogLevel >= logLvl && logger != nil || loggerErr != nil {
		if logger != nil {
			//(index string, _type string, id, ttl string, date *time.Time, data interface{}, refresh bool)

			now := time.Now()
			idx := "logstash-" + now.Format("2006.01.02")
			indexer.Index(idx, "golog", "hihid", "30d", now, LogPrefix[logLvl]+msg+postFix, nil)
		}
	}
}

type winsize struct {
	Row    uint16
	Col    uint16
	Xpixel uint16
	Ypixel uint16
}

const (
	_TIOCGWINSZ = 0x5413 // OSX 1074295912
)

//http://play.golang.org/p/5LIA41Iqfp
// Dummy discard, satisfies io.Writer without importing io or os.
type DevNull struct{}

func (DevNull) Write(p []byte) (int, error) {
	return len(p), nil
}

//Replace standard newline characters with escaped newlines so long msgs will
//remain one line.
func EscapeNewlines(str string) string {
	return strings.Replace(str, "\n", "\\n", -1)
}
<|endoftext|>


<commit_before>package log

import (
	"encoding/json"
	"io"
	"time"
)

// 默认 debug 级别，方便调试，生产环境可以调用 LevelSet 设置 log 级别
var v Level = Ldebug

// 默认实现，输出到 os.Std 中，可以重定向到文件中，也可以调用 SetPrinter 其他方式输出
var std Printer

// SetLevel 设置日志级别
func SetLevel(l Level) {
	v = l
	if v > Ldebug {
		Colorized(false)
	}
}
func SetLevelString(s string) {
	l, err := ValueOfLevel(s)
	if err != nil {
		std.Tprintf(Lerror, "", "level value string %s invalid", s)
		return
	}
	SetLevel(l)
}

// Colorized 输出日志是否着色，默认着色，如果设置的级别高于 debug，不着色
func Colorized(c bool) { std.Colorized(c) }

// GetLevel 返回设置的日志级别
func GetLevel() (l Level) { return v }

// SetPrinter 切换 Printer 实现
func SetPrinter(p Printer) { std = p }

// SetWriter 改变输出位置，通过这个接口，可以实现日志文件按时间或按大小滚动
func SetWriter(w io.Writer) { std.SetWriter(w) }

// SetFormat 改变日志格式
func SetFormat(format string) { std.SetFormat(format) }

// 判断各种级别的日志是否会被输出
func IsTraceEnabled() bool { return v <= Ltrace }
func IsDebugEnabled() bool { return v <= Ldebug }
func IsInfoEnabled() bool  { return v <= Linfo }
func IsWarnEnabled() bool  { return v <= Lwarn }
func IsErrorEnabled() bool { return v <= Lerror }
func IsPanicEnabled() bool { return v <= Lpanic }
func IsFatalEnabled() bool { return v <= Lfatal }
func IsPrintEnabled() bool { return v <= Lprint }
func IsStackEnabled() bool { return v <= Lstack }

// 打印日志
func Trace(m ...interface{}) { std.Tprintf(Ltrace, "", "", m...) }
func Debug(m ...interface{}) { std.Tprintf(Ldebug, "", "", m...) }
func Info(m ...interface{})  { std.Tprintf(Linfo, "", "", m...) }
func Warn(m ...interface{})  { std.Tprintf(Lwarn, "", "", m...) }
func Error(m ...interface{}) { std.Tprintf(Lerror, "", "", m...) }
func Panic(m ...interface{}) { std.Tprintf(Lpanic, "", "", m...) }
func Fatal(m ...interface{}) { std.Tprintf(Lfatal, "", "", m...) }
func Print(m ...interface{}) { std.Tprintf(Lprint, "", "", m...) }
func Stack(m ...interface{}) { std.Tprintf(Lstack, "", "", m...) }

var nilerr = (error)(nil)

// Errorn check last argument, if error but nil, no print log
func Errorn(m ...interface{}) {
	if m[len(m)-1] == nilerr {
		return
	}
	std.Tprintf(Lerror, "", "", m...)
}
func Fataln(m ...interface{}) {
	if m[len(m)-1] == nilerr {
		return
	}
	std.Tprintf(Lfatal, "", "", m...)
}

// 按一定格式打印日志
func Tracef(format string, m ...interface{}) { std.Tprintf(Ltrace, "", format, m...) }
func Debugf(format string, m ...interface{}) { std.Tprintf(Ldebug, "", format, m...) }
func Infof(format string, m ...interface{})  { std.Tprintf(Linfo, "", format, m...) }
func Warnf(format string, m ...interface{})  { std.Tprintf(Lwarn, "", format, m...) }
func Errorf(format string, m ...interface{}) { std.Tprintf(Lerror, "", format, m...) }
func Panicf(format string, m ...interface{}) { std.Tprintf(Lpanic, "", format, m...) }
func Fatalf(format string, m ...interface{}) { std.Tprintf(Lfatal, "", format, m...) }
func Printf(format string, m ...interface{}) { std.Tprintf(Lprint, "", format, m...) }
func Stackf(format string, m ...interface{}) { std.Tprintf(Lstack, "", format, m...) }

// Errorn check last argument, if error but nil, no print log
func Errornf(format string, m ...interface{}) {
	if m[len(m)-1] == nilerr {
		return
	}
	std.Tprintf(Lerror, "", format, m...)
}
func Fatalnf(format string, m ...interface{}) {
	if m[len(m)-1] == nilerr {
		return
	}
	std.Tprintf(Lfatal, "", format, m...)
}

// 打印日志时带上 tag
func Ttrace(tag string, m ...interface{}) { std.Tprintf(Ltrace, tag, "", m...) }
func Tdebug(tag string, m ...interface{}) { std.Tprintf(Ldebug, tag, "", m...) }
func Tinfo(tag string, m ...interface{})  { std.Tprintf(Linfo, tag, "", m...) }
func Twarn(tag string, m ...interface{})  { std.Tprintf(Lwarn, tag, "", m...) }
func Terror(tag string, m ...interface{}) { std.Tprintf(Lerror, tag, "", m...) }
func Tpanic(tag string, m ...interface{}) { std.Tprintf(Lpanic, tag, "", m...) }
func Tfatal(tag string, m ...interface{}) { std.Tprintf(Lfatal, tag, "", m...) }
func Tprint(tag string, m ...interface{}) { std.Tprintf(Lprint, tag, "", m...) }
func Tstack(tag string, m ...interface{}) { std.Tprintf(Lstack, tag, "", m...) }

// Errorn check last argument, if error but nil, no print log
func Terrorn(tag string, m ...interface{}) {
	if m[len(m)-1] == nilerr {
		return
	}
	std.Tprintf(Lerror, tag, "", m...)
}
func Tfataln(tag string, m ...interface{}) {
	if m[len(m)-1] == nilerr {
		return
	}
	std.Tprintf(Lfatal, tag, "", m...)
}

// 按一定格式打印日志，并在打印日志时带上 tag
func Ttracef(tag string, format string, m ...interface{}) {
	std.Tprintf(Ltrace, tag, format, m...)
}
func Tdebugf(tag string, format string, m ...interface{}) {
	std.Tprintf(Ldebug, tag, format, m...)
}
func Tinfof(tag string, format string, m ...interface{}) { std.Tprintf(Linfo, tag, format, m...) }
func Twarnf(tag string, format string, m ...interface{}) { std.Tprintf(Lwarn, tag, format, m...) }
func Terrorf(tag string, format string, m ...interface{}) {
	std.Tprintf(Lerror, tag, format, m...)
}
func Tpanicf(tag string, format string, m ...interface{}) {
	std.Tprintf(Lpanic, tag, format, m...)
}
func Tfatalf(tag string, format string, m ...interface{}) {
	std.Tprintf(Lfatal, tag, format, m...)
}
func Tprintf(tag string, format string, m ...interface{}) {
	std.Tprintf(Lprint, tag, format, m...)
}
func Tstackf(tag string, format string, m ...interface{}) {
	std.Tprintf(Lstack, tag, format, m...)
}

// Errorn check last argument, if error but nil, no print log
func Terrornf(tag string, format string, m ...interface{}) {
	if m[len(m)-1] == nilerr {
		return
	}
	std.Tprintf(Lerror, tag, format, m...)
}
func Tfatalnf(tag string, format string, m ...interface{}) {
	if m[len(m)-1] == nilerr {
		return
	}
	std.Tprintf(Lfatal, tag, format, m...)
}

func Json(m ...interface{}) {
	if v > Ldebug {
		return
	}
	js, err := json.Marshal(m)
	if err != nil {
		std.Tprintf(Ldebug, "", "%s", err)
	} else {
		std.Tprintf(Ldebug, "", "%s", js[1:len(js)-1])
	}
}

// 先转换成 JSON 格式，然后打印
func JSON(m ...interface{}) {
	if v > Ldebug {
		return
	}
	js, err := json.Marshal(m)
	if err != nil {
		std.Tprintf(Ldebug, "", "%s", err)
	} else {
		std.Tprintf(Ldebug, "", "%s", js[1:len(js)-1])
	}
}
func JsonIndent(m ...interface{}) {
	if v > Ldebug {
		return
	}
	js, err := json.MarshalIndent(m, "", "    ")
	if err != nil {
		std.Tprintf(Ldebug, "", "%s", err)
	} else {
		std.Tprintf(Ldebug, "", "%s", js)
	}
}

func JSONIndent(m ...interface{}) {
	if v > Ldebug {
		return
	}
	js, err := json.MarshalIndent(m, "", "    ")
	if err != nil {
		std.Tprintf(Ldebug, "", "%s", err)
	} else {
		std.Tprintf(Ldebug, "", "%s", js)
	}
}

func Cost(something string) func() {
	std.Tprintf(Linfo, "", "%s start...", something)
	start := time.Now()
	return func() {
		std.Tprintf(Linfo, "", "%s cost %s", something,
			time.Now().Sub(start).Truncate(time.Second))
	}
}
<commit_msg>add costf<commit_after>package log

import (
	"encoding/json"
	"io"
	"time"
)

// 默认 debug 级别，方便调试，生产环境可以调用 LevelSet 设置 log 级别
var v Level = Ldebug

// 默认实现，输出到 os.Std 中，可以重定向到文件中，也可以调用 SetPrinter 其他方式输出
var std Printer

// SetLevel 设置日志级别
func SetLevel(l Level) {
	v = l
	if v > Ldebug {
		Colorized(false)
	}
}
func SetLevelString(s string) {
	l, err := ValueOfLevel(s)
	if err != nil {
		std.Tprintf(Lerror, "", "level value string %s invalid", s)
		return
	}
	SetLevel(l)
}

// Colorized 输出日志是否着色，默认着色，如果设置的级别高于 debug，不着色
func Colorized(c bool) { std.Colorized(c) }

// GetLevel 返回设置的日志级别
func GetLevel() (l Level) { return v }

// SetPrinter 切换 Printer 实现
func SetPrinter(p Printer) { std = p }

// SetWriter 改变输出位置，通过这个接口，可以实现日志文件按时间或按大小滚动
func SetWriter(w io.Writer) { std.SetWriter(w) }

// SetFormat 改变日志格式
func SetFormat(format string) { std.SetFormat(format) }

// 判断各种级别的日志是否会被输出
func IsTraceEnabled() bool { return v <= Ltrace }
func IsDebugEnabled() bool { return v <= Ldebug }
func IsInfoEnabled() bool  { return v <= Linfo }
func IsWarnEnabled() bool  { return v <= Lwarn }
func IsErrorEnabled() bool { return v <= Lerror }
func IsPanicEnabled() bool { return v <= Lpanic }
func IsFatalEnabled() bool { return v <= Lfatal }
func IsPrintEnabled() bool { return v <= Lprint }
func IsStackEnabled() bool { return v <= Lstack }

// 打印日志
func Trace(m ...interface{}) { std.Tprintf(Ltrace, "", "", m...) }
func Debug(m ...interface{}) { std.Tprintf(Ldebug, "", "", m...) }
func Info(m ...interface{})  { std.Tprintf(Linfo, "", "", m...) }
func Warn(m ...interface{})  { std.Tprintf(Lwarn, "", "", m...) }
func Error(m ...interface{}) { std.Tprintf(Lerror, "", "", m...) }
func Panic(m ...interface{}) { std.Tprintf(Lpanic, "", "", m...) }
func Fatal(m ...interface{}) { std.Tprintf(Lfatal, "", "", m...) }
func Print(m ...interface{}) { std.Tprintf(Lprint, "", "", m...) }
func Stack(m ...interface{}) { std.Tprintf(Lstack, "", "", m...) }

var nilerr = (error)(nil)

// Errorn check last argument, if error but nil, no print log
func Errorn(m ...interface{}) {
	if m[len(m)-1] == nilerr {
		return
	}
	std.Tprintf(Lerror, "", "", m...)
}
func Fataln(m ...interface{}) {
	if m[len(m)-1] == nilerr {
		return
	}
	std.Tprintf(Lfatal, "", "", m...)
}

// 按一定格式打印日志
func Tracef(format string, m ...interface{}) { std.Tprintf(Ltrace, "", format, m...) }
func Debugf(format string, m ...interface{}) { std.Tprintf(Ldebug, "", format, m...) }
func Infof(format string, m ...interface{})  { std.Tprintf(Linfo, "", format, m...) }
func Warnf(format string, m ...interface{})  { std.Tprintf(Lwarn, "", format, m...) }
func Errorf(format string, m ...interface{}) { std.Tprintf(Lerror, "", format, m...) }
func Panicf(format string, m ...interface{}) { std.Tprintf(Lpanic, "", format, m...) }
func Fatalf(format string, m ...interface{}) { std.Tprintf(Lfatal, "", format, m...) }
func Printf(format string, m ...interface{}) { std.Tprintf(Lprint, "", format, m...) }
func Stackf(format string, m ...interface{}) { std.Tprintf(Lstack, "", format, m...) }

// Errorn check last argument, if error but nil, no print log
func Errornf(format string, m ...interface{}) {
	if m[len(m)-1] == nilerr {
		return
	}
	std.Tprintf(Lerror, "", format, m...)
}
func Fatalnf(format string, m ...interface{}) {
	if m[len(m)-1] == nilerr {
		return
	}
	std.Tprintf(Lfatal, "", format, m...)
}

// 打印日志时带上 tag
func Ttrace(tag string, m ...interface{}) { std.Tprintf(Ltrace, tag, "", m...) }
func Tdebug(tag string, m ...interface{}) { std.Tprintf(Ldebug, tag, "", m...) }
func Tinfo(tag string, m ...interface{})  { std.Tprintf(Linfo, tag, "", m...) }
func Twarn(tag string, m ...interface{})  { std.Tprintf(Lwarn, tag, "", m...) }
func Terror(tag string, m ...interface{}) { std.Tprintf(Lerror, tag, "", m...) }
func Tpanic(tag string, m ...interface{}) { std.Tprintf(Lpanic, tag, "", m...) }
func Tfatal(tag string, m ...interface{}) { std.Tprintf(Lfatal, tag, "", m...) }
func Tprint(tag string, m ...interface{}) { std.Tprintf(Lprint, tag, "", m...) }
func Tstack(tag string, m ...interface{}) { std.Tprintf(Lstack, tag, "", m...) }

// Errorn check last argument, if error but nil, no print log
func Terrorn(tag string, m ...interface{}) {
	if m[len(m)-1] == nilerr {
		return
	}
	std.Tprintf(Lerror, tag, "", m...)
}
func Tfataln(tag string, m ...interface{}) {
	if m[len(m)-1] == nilerr {
		return
	}
	std.Tprintf(Lfatal, tag, "", m...)
}

// 按一定格式打印日志，并在打印日志时带上 tag
func Ttracef(tag string, format string, m ...interface{}) {
	std.Tprintf(Ltrace, tag, format, m...)
}
func Tdebugf(tag string, format string, m ...interface{}) {
	std.Tprintf(Ldebug, tag, format, m...)
}
func Tinfof(tag string, format string, m ...interface{}) { std.Tprintf(Linfo, tag, format, m...) }
func Twarnf(tag string, format string, m ...interface{}) { std.Tprintf(Lwarn, tag, format, m...) }
func Terrorf(tag string, format string, m ...interface{}) {
	std.Tprintf(Lerror, tag, format, m...)
}
func Tpanicf(tag string, format string, m ...interface{}) {
	std.Tprintf(Lpanic, tag, format, m...)
}
func Tfatalf(tag string, format string, m ...interface{}) {
	std.Tprintf(Lfatal, tag, format, m...)
}
func Tprintf(tag string, format string, m ...interface{}) {
	std.Tprintf(Lprint, tag, format, m...)
}
func Tstackf(tag string, format string, m ...interface{}) {
	std.Tprintf(Lstack, tag, format, m...)
}

// Errorn check last argument, if error but nil, no print log
func Terrornf(tag string, format string, m ...interface{}) {
	if m[len(m)-1] == nilerr {
		return
	}
	std.Tprintf(Lerror, tag, format, m...)
}
func Tfatalnf(tag string, format string, m ...interface{}) {
	if m[len(m)-1] == nilerr {
		return
	}
	std.Tprintf(Lfatal, tag, format, m...)
}

func Json(m ...interface{}) {
	if v > Ldebug {
		return
	}
	js, err := json.Marshal(m)
	if err != nil {
		std.Tprintf(Ldebug, "", "%s", err)
	} else {
		std.Tprintf(Ldebug, "", "%s", js[1:len(js)-1])
	}
}

// 先转换成 JSON 格式，然后打印
func JSON(m ...interface{}) {
	if v > Ldebug {
		return
	}
	js, err := json.Marshal(m)
	if err != nil {
		std.Tprintf(Ldebug, "", "%s", err)
	} else {
		std.Tprintf(Ldebug, "", "%s", js[1:len(js)-1])
	}
}
func JsonIndent(m ...interface{}) {
	if v > Ldebug {
		return
	}
	js, err := json.MarshalIndent(m, "", "    ")
	if err != nil {
		std.Tprintf(Ldebug, "", "%s", err)
	} else {
		std.Tprintf(Ldebug, "", "%s", js)
	}
}

func JSONIndent(m ...interface{}) {
	if v > Ldebug {
		return
	}
	js, err := json.MarshalIndent(m, "", "    ")
	if err != nil {
		std.Tprintf(Ldebug, "", "%s", err)
	} else {
		std.Tprintf(Ldebug, "", "%s", js)
	}
}

func Cost(m string) func() {
	std.Tprintf(Linfo, "", "%s start...", m)
	start := time.Now()
	return func() {
		std.Tprintf(Linfo, "", "%s cost %s", m,
			time.Now().Sub(start).Truncate(time.Second))
	}
}

func Costf(format, m string) func() {
	std.Tprintf(Linfo, "", format+" start...", m)
	start := time.Now()
	return func() {
		std.Tprintf(Linfo, "", format+" cost %s", m,
			time.Now().Sub(start).Truncate(time.Second))
	}
}
<|endoftext|>


<commit_before>package tmsh

import (
	"fmt"
	"strconv"
	"strings"
)

type Node struct {
	Name          string
	Addr          string
	MonitorRule   string
	MonitorStatus string
	EnabledState  string
}

type Pool struct {
	ActiveMemberCount int
	Name              string
	MonitorRule       string
	AvailabilityState string
	EnabledState      string
	StatusReason      string
	PoolMembers       []PoolMember
}

type PoolMember struct {
	Name              string
	Addr              string
	Port              int
	MonitorRule       string
	MonitorStatus     string
	EnabledState      string
	AvailabilityState string
	StatusReason      string
}

type VirtualServer struct {
	Destination string
	IpProtocol  string
	Mask        string
	Partition   string
	Pool        string
}

func Unmarshal(data string, v interface{}) error {
	l := Lexer{s: NewScanner(data)}
	if yyParse(&l) != 0 {
		return fmt.Errorf("Parse error")
	}
	return nil
}

func (bigip *BigIP) GetNode(name string) (*Node, error) {
	ret, _ := bigip.ExecuteCommand("show ltm node " + name + " field-fmt")
	if strings.Contains(ret, "was not found.") {
		return nil, fmt.Errorf(ret)
	}
	node := ParseShowLtmNode(ret)
	return node, nil
}

func (bigip *BigIP) CreateNode(name, ipaddr string) error {
	ret, _ := bigip.ExecuteCommand("create ltm node " + name + " address " + ipaddr)
	if ret != "" {
		return fmt.Errorf(ret)
	}
	return nil
}

func (bigip *BigIP) DeleteNode(name string) error {
	ret, _ := bigip.ExecuteCommand("delete ltm node " + name)
	if ret != "" {
		return fmt.Errorf(ret)
	}
	return nil
}

func (bigip *BigIP) EnableNode(name string) error {
	ret, _ := bigip.ExecuteCommand("modify ltm node " + name + " session user-enabled")
	if ret != "" {
		return fmt.Errorf(ret)
	}
	return nil
}

func (bigip *BigIP) DisableNode(name string) error {
	ret, _ := bigip.ExecuteCommand("modify ltm node " + name + " session user-disabled")
	if ret != "" {
		return fmt.Errorf(ret)
	}
	return nil
}

func (bigip *BigIP) GetPool(name string) (*Pool, error) {
	ret, _ := bigip.ExecuteCommand("show ltm pool " + name + " members field-fmt")
	if strings.Contains(ret, "was not found.") {
		return nil, fmt.Errorf(ret)
	}
	pool := ParseShowLtmPool(ret)
	return pool, nil
}

func (bigip *BigIP) CreatePool(name string) error {
	ret, _ := bigip.ExecuteCommand("create ltm pool " + name)
	if ret != "" {
		return fmt.Errorf(ret)
	}
	return nil
}

func (bigip *BigIP) DeletePool(name string) error {
	ret, _ := bigip.ExecuteCommand("delete ltm pool " + name)
	if ret != "" {
		return fmt.Errorf(ret)
	}
	return nil
}

func (bigip *BigIP) AddMonitorToPool(poolName, monitorName string) error {
	ret, _ := bigip.ExecuteCommand("modify ltm pool " + poolName + " monitor '" + monitorName + "'")
	if ret != "" {
		return fmt.Errorf(ret)
	}
	return nil
}

func (bigip *BigIP) AddPoolMember(poolName, nodeName, monitorName string, port int) error {
	member := nodeName + ":" + strconv.Itoa(port)
	cmd := "modify ltm pool " + poolName + " members add { " + member + " } monitor '" + monitorName + "'"
	ret, _ := bigip.ExecuteCommand(cmd)
	if ret != "" {
		return fmt.Errorf(ret)
	}
	return nil
}

func (bigip *BigIP) DeletePoolMember(poolName, nodeName string, port int) error {
	member := nodeName + ":" + strconv.Itoa(port)
	cmd := "modify ltm pool " + poolName + " members delete { " + member + " }"
	ret, _ := bigip.ExecuteCommand(cmd)
	if ret != "" {
		return fmt.Errorf(ret)
	}
	return nil
}

func (bigip *BigIP) EnablePoolMember(poolName, nodeName string, port int) error {
	member := nodeName + ":" + strconv.Itoa(port)
	cmd := "modify ltm pool " + poolName + " members modify { " + member + " { session user-enabled } }"
	ret, _ := bigip.ExecuteCommand(cmd)
	if ret != "" {
		return fmt.Errorf(ret)
	}
	return nil
}

func (bigip *BigIP) DisablePoolMember(poolName, nodeName string, port int) error {
	member := nodeName + ":" + strconv.Itoa(port)
	cmd := "modify ltm pool " + poolName + " members modify { " + member + " { session user-disabled } }"
	ret, _ := bigip.ExecuteCommand(cmd)
	if ret != "" {
		return fmt.Errorf(ret)
	}
	return nil
}

func (bigip *BigIP) GetVirtualServer(name string) (*VirtualServer, error) {
	ret, _ := bigip.ExecuteCommand("list ltm virtual " + name)
	if strings.Contains(ret, "was not found.") {
		return nil, fmt.Errorf(ret)
	}
	vs := ParseListLtmVirtual(ret)
	return vs, nil

}

func (bigip *BigIP) CreateVirtualServer(vsName, poolName, targetVIP, defaultProfileName string, targetPort int) error {
	destination := targetVIP + ":" + strconv.Itoa(targetPort)
	cmd := "create ltm virtual " + vsName + " { destination " + destination + " ip-protocol tcp mask 255.255.255.255 pool " + poolName + " profiles add { " + defaultProfileName + " } }"
	ret, _ := bigip.ExecuteCommand(cmd)
	if ret != "" {
		return fmt.Errorf(ret)
	}
	return nil
}

func (bigip *BigIP) DeleteVirtualServer(vsName string) error {
	ret, _ := bigip.ExecuteCommand("delete ltm virtual " + vsName)
	if ret != "" {
		return fmt.Errorf(ret)
	}
	return nil
}

func (bigip *BigIP) AddVirtualServerProfile(vsName, profileName, context string) error {
	cmd := "modify ltm virtual " + vsName + " profiles add { " + profileName + " { context " + context + " } }"
	ret, _ := bigip.ExecuteCommand(cmd)
	if ret != "" {
		return fmt.Errorf(ret)
	}
	return nil
}

func (bigip *BigIP) DeleteVirtualServerProfile(vsName, profileName, context string) error {
	cmd := "modify ltm virtual " + vsName + " profiles delete { " + profileName + " }"
	ret, _ := bigip.ExecuteCommand(cmd)
	if ret != "" {
		return fmt.Errorf(ret)
	}
	return nil
}

func (bigip *BigIP) ApplyPolicyToVirtualServer(vsName, policyName string) error {
	cmd := "modify ltm virtual " + vsName + " fw-enforced-policy " + policyName
	ret, _ := bigip.ExecuteCommand(cmd)
	if ret != "" {
		return fmt.Errorf(ret)
	}
	return nil
}

func (bigip *BigIP) RouteAdvertisementEnabled(targetVIP string) error {
	cmd := "modify ltm virtual-address " + targetVIP + " route-advertisement enabled"
	ret, _ := bigip.ExecuteCommand(cmd)
	if ret != "" {
		return fmt.Errorf(ret)
	}
	return nil
}

func (bigip *BigIP) CreateSecurityFWPolicy(firewallPolicyName string) error {
	cmd := "create security firewall policy " + firewallPolicyName
	ret, _ := bigip.ExecuteCommand(cmd)
	if ret != "" {
		return fmt.Errorf(ret)
	}
	return nil
}

func (bigip *BigIP) AddSecurityFWPolicyRule(firewallPolicyName, ruleName, action string, targetPort int) error {
	if action != "accept" && action != "accept-decisively" &&
		action != "drop" && action != "reject" {
		return fmt.Errorf("Invalid action name: " + action)
	}

	cmd := "modify security firewall policy " + firewallPolicyName + " rules add { " + ruleName +
		" { action " + action + " ip-protocol tcp destination { ports add { " + strconv.Itoa(targetPort) + " } } place-after last } }"
	ret, _ := bigip.ExecuteCommand(cmd)
	if ret != "" {
		return fmt.Errorf(ret)
	}
	return nil
}
<commit_msg>Add struct tags<commit_after>package tmsh

import (
	"fmt"
	"strconv"
	"strings"
)

type Node struct {
	Name          string `ltm:"name"`
	Addr          string `ltm:"addr"`
	MonitorRule   string `ltm:"monitor-rule"`
	MonitorStatus string `ltm:"monitor-status"`
	EnabledState  string `ltm:"status.enabled-state"`
}

type Pool struct {
	ActiveMemberCount int          `ltm:"active-member-cnt"`
	Name              string       `ltm:"monitor-rule"`
	MonitorRule       string       `ltm:"name"`
	AvailabilityState string       `ltm:"status.availability-state available"`
	EnabledState      string       `ltm:"status.enabled-state enabled"`
	StatusReason      string       `ltm:"status.status-reason The pool is available"`
	PoolMembers       []PoolMember `ltm:"members"`
}

type PoolMember struct {
	Name              string `ltm:"name"`
	Addr              string `ltm:"addr"`
	Port              int    `ltm:"port"`
	MonitorRule       string `ltm:"monitor-rule"`
	MonitorStatus     string `ltm:"monitor-status"`
	EnabledState      string `ltm:"status.enabled-state disabled"`
	AvailabilityState string `ltm:"status.availability-state"`
	StatusReason      string `ltm:"status.status-reason"`
}

type VirtualServer struct {
	Destination string `ltm:"destination"`
	IpProtocol  string `ltm:"ip-protocol"`
	Mask        string `ltm:"mask"`
	Partition   string `ltm:"partition"`
	Pool        string `ltm:"pool"`
}

func Unmarshal(data string, v interface{}) error {
	l := Lexer{s: NewScanner(data)}
	if yyParse(&l) != 0 {
		return fmt.Errorf("Parse error")
	}
	return nil
}

func (bigip *BigIP) GetNode(name string) (*Node, error) {
	ret, _ := bigip.ExecuteCommand("show ltm node " + name + " field-fmt")
	if strings.Contains(ret, "was not found.") {
		return nil, fmt.Errorf(ret)
	}
	node := ParseShowLtmNode(ret)
	return node, nil
}

func (bigip *BigIP) CreateNode(name, ipaddr string) error {
	ret, _ := bigip.ExecuteCommand("create ltm node " + name + " address " + ipaddr)
	if ret != "" {
		return fmt.Errorf(ret)
	}
	return nil
}

func (bigip *BigIP) DeleteNode(name string) error {
	ret, _ := bigip.ExecuteCommand("delete ltm node " + name)
	if ret != "" {
		return fmt.Errorf(ret)
	}
	return nil
}

func (bigip *BigIP) EnableNode(name string) error {
	ret, _ := bigip.ExecuteCommand("modify ltm node " + name + " session user-enabled")
	if ret != "" {
		return fmt.Errorf(ret)
	}
	return nil
}

func (bigip *BigIP) DisableNode(name string) error {
	ret, _ := bigip.ExecuteCommand("modify ltm node " + name + " session user-disabled")
	if ret != "" {
		return fmt.Errorf(ret)
	}
	return nil
}

func (bigip *BigIP) GetPool(name string) (*Pool, error) {
	ret, _ := bigip.ExecuteCommand("show ltm pool " + name + " members field-fmt")
	if strings.Contains(ret, "was not found.") {
		return nil, fmt.Errorf(ret)
	}
	pool := ParseShowLtmPool(ret)
	return pool, nil
}

func (bigip *BigIP) CreatePool(name string) error {
	ret, _ := bigip.ExecuteCommand("create ltm pool " + name)
	if ret != "" {
		return fmt.Errorf(ret)
	}
	return nil
}

func (bigip *BigIP) DeletePool(name string) error {
	ret, _ := bigip.ExecuteCommand("delete ltm pool " + name)
	if ret != "" {
		return fmt.Errorf(ret)
	}
	return nil
}

func (bigip *BigIP) AddMonitorToPool(poolName, monitorName string) error {
	ret, _ := bigip.ExecuteCommand("modify ltm pool " + poolName + " monitor '" + monitorName + "'")
	if ret != "" {
		return fmt.Errorf(ret)
	}
	return nil
}

func (bigip *BigIP) AddPoolMember(poolName, nodeName, monitorName string, port int) error {
	member := nodeName + ":" + strconv.Itoa(port)
	cmd := "modify ltm pool " + poolName + " members add { " + member + " } monitor '" + monitorName + "'"
	ret, _ := bigip.ExecuteCommand(cmd)
	if ret != "" {
		return fmt.Errorf(ret)
	}
	return nil
}

func (bigip *BigIP) DeletePoolMember(poolName, nodeName string, port int) error {
	member := nodeName + ":" + strconv.Itoa(port)
	cmd := "modify ltm pool " + poolName + " members delete { " + member + " }"
	ret, _ := bigip.ExecuteCommand(cmd)
	if ret != "" {
		return fmt.Errorf(ret)
	}
	return nil
}

func (bigip *BigIP) EnablePoolMember(poolName, nodeName string, port int) error {
	member := nodeName + ":" + strconv.Itoa(port)
	cmd := "modify ltm pool " + poolName + " members modify { " + member + " { session user-enabled } }"
	ret, _ := bigip.ExecuteCommand(cmd)
	if ret != "" {
		return fmt.Errorf(ret)
	}
	return nil
}

func (bigip *BigIP) DisablePoolMember(poolName, nodeName string, port int) error {
	member := nodeName + ":" + strconv.Itoa(port)
	cmd := "modify ltm pool " + poolName + " members modify { " + member + " { session user-disabled } }"
	ret, _ := bigip.ExecuteCommand(cmd)
	if ret != "" {
		return fmt.Errorf(ret)
	}
	return nil
}

func (bigip *BigIP) GetVirtualServer(name string) (*VirtualServer, error) {
	ret, _ := bigip.ExecuteCommand("list ltm virtual " + name)
	if strings.Contains(ret, "was not found.") {
		return nil, fmt.Errorf(ret)
	}
	vs := ParseListLtmVirtual(ret)
	return vs, nil

}

func (bigip *BigIP) CreateVirtualServer(vsName, poolName, targetVIP, defaultProfileName string, targetPort int) error {
	destination := targetVIP + ":" + strconv.Itoa(targetPort)
	cmd := "create ltm virtual " + vsName + " { destination " + destination + " ip-protocol tcp mask 255.255.255.255 pool " + poolName + " profiles add { " + defaultProfileName + " } }"
	ret, _ := bigip.ExecuteCommand(cmd)
	if ret != "" {
		return fmt.Errorf(ret)
	}
	return nil
}

func (bigip *BigIP) DeleteVirtualServer(vsName string) error {
	ret, _ := bigip.ExecuteCommand("delete ltm virtual " + vsName)
	if ret != "" {
		return fmt.Errorf(ret)
	}
	return nil
}

func (bigip *BigIP) AddVirtualServerProfile(vsName, profileName, context string) error {
	cmd := "modify ltm virtual " + vsName + " profiles add { " + profileName + " { context " + context + " } }"
	ret, _ := bigip.ExecuteCommand(cmd)
	if ret != "" {
		return fmt.Errorf(ret)
	}
	return nil
}

func (bigip *BigIP) DeleteVirtualServerProfile(vsName, profileName, context string) error {
	cmd := "modify ltm virtual " + vsName + " profiles delete { " + profileName + " }"
	ret, _ := bigip.ExecuteCommand(cmd)
	if ret != "" {
		return fmt.Errorf(ret)
	}
	return nil
}

func (bigip *BigIP) ApplyPolicyToVirtualServer(vsName, policyName string) error {
	cmd := "modify ltm virtual " + vsName + " fw-enforced-policy " + policyName
	ret, _ := bigip.ExecuteCommand(cmd)
	if ret != "" {
		return fmt.Errorf(ret)
	}
	return nil
}

func (bigip *BigIP) RouteAdvertisementEnabled(targetVIP string) error {
	cmd := "modify ltm virtual-address " + targetVIP + " route-advertisement enabled"
	ret, _ := bigip.ExecuteCommand(cmd)
	if ret != "" {
		return fmt.Errorf(ret)
	}
	return nil
}

func (bigip *BigIP) CreateSecurityFWPolicy(firewallPolicyName string) error {
	cmd := "create security firewall policy " + firewallPolicyName
	ret, _ := bigip.ExecuteCommand(cmd)
	if ret != "" {
		return fmt.Errorf(ret)
	}
	return nil
}

func (bigip *BigIP) AddSecurityFWPolicyRule(firewallPolicyName, ruleName, action string, targetPort int) error {
	if action != "accept" && action != "accept-decisively" &&
		action != "drop" && action != "reject" {
		return fmt.Errorf("Invalid action name: " + action)
	}

	cmd := "modify security firewall policy " + firewallPolicyName + " rules add { " + ruleName +
		" { action " + action + " ip-protocol tcp destination { ports add { " + strconv.Itoa(targetPort) + " } } place-after last } }"
	ret, _ := bigip.ExecuteCommand(cmd)
	if ret != "" {
		return fmt.Errorf(ret)
	}
	return nil
}
<|endoftext|>


<commit_before>package flags

import (
	"fmt"
	"io"
	"os"
	"runtime"
	"strconv"
	"strings"
	"time"
)

func manQuote(s string) string {
	return strings.Replace(s, "\\", "\\\\", -1)
}

func formatForMan(wr io.Writer, s string) {
	for {
		idx := strings.IndexRune(s, '`')

		if idx < 0 {
			fmt.Fprintf(wr, "%s", manQuote(s))
			break
		}

		fmt.Fprintf(wr, "%s", manQuote(s[:idx]))

		s = s[idx+1:]
		idx = strings.IndexRune(s, '\'')

		if idx < 0 {
			fmt.Fprintf(wr, "%s", manQuote(s))
			break
		}

		fmt.Fprintf(wr, "\\fB%s\\fP", manQuote(s[:idx]))
		s = s[idx+1:]
	}
}

func writeManPageOptions(wr io.Writer, grp *Group) {
	grp.eachGroup(func(group *Group) {
		if !group.showInHelp() {
			return
		}

		// If the parent (grp) has any subgroups, display their descriptions as
		// subsection headers similar to the output of --help.
		if group.ShortDescription != "" && len(grp.groups) > 0 {
			fmt.Fprintf(wr, ".SS %s\n", group.ShortDescription)

			if group.LongDescription != "" {
				formatForMan(wr, group.LongDescription)
				fmt.Fprintln(wr, "")
			}
		}

		for _, opt := range group.options {
			if !opt.showInHelp() {
				continue
			}

			fmt.Fprintln(wr, ".TP")
			fmt.Fprintf(wr, "\\fB")

			if opt.ShortName != 0 {
				fmt.Fprintf(wr, "\\fB\\-%c\\fR", opt.ShortName)
			}

			if len(opt.LongName) != 0 {
				if opt.ShortName != 0 {
					fmt.Fprintf(wr, ", ")
				}

				fmt.Fprintf(wr, "\\fB\\-\\-%s\\fR", manQuote(opt.LongNameWithNamespace()))
			}

			if len(opt.ValueName) != 0 || opt.OptionalArgument {
				if opt.OptionalArgument {
					fmt.Fprintf(wr, " [\\fI%s=%s\\fR]", manQuote(opt.ValueName), manQuote(strings.Join(quoteV(opt.OptionalValue), ", ")))
				} else {
					fmt.Fprintf(wr, " \\fI%s\\fR", manQuote(opt.ValueName))
				}
			}

			if len(opt.Default) != 0 {
				fmt.Fprintf(wr, " <default: \\fI%s\\fR>", manQuote(strings.Join(quoteV(opt.Default), ", ")))
			} else if len(opt.EnvKeyWithNamespace()) != 0 {
				if runtime.GOOS == "windows" {
					fmt.Fprintf(wr, " <default: \\fI%%%s%%\\fR>", manQuote(opt.EnvKeyWithNamespace()))
				} else {
					fmt.Fprintf(wr, " <default: \\fI$%s\\fR>", manQuote(opt.EnvKeyWithNamespace()))
				}
			}

			if opt.Required {
				fmt.Fprintf(wr, " (\\fIrequired\\fR)")
			}

			fmt.Fprintln(wr, "\\fP")

			if len(opt.Description) != 0 {
				formatForMan(wr, opt.Description)
				fmt.Fprintln(wr, "")
			}
		}
	})
}

func writeManPageSubcommands(wr io.Writer, name string, usagePrefix string, root *Command) {
	commands := root.sortedVisibleCommands()

	for _, c := range commands {
		var nn string

		if c.Hidden {
			continue
		}

		if len(name) != 0 {
			nn = name + " " + c.Name
		} else {
			nn = c.Name
		}

		writeManPageCommand(wr, nn, usagePrefix, c)
	}
}

func writeManPageCommand(wr io.Writer, name string, usagePrefix string, command *Command) {
	fmt.Fprintf(wr, ".SS %s\n", name)
	fmt.Fprintln(wr, command.ShortDescription)

	if len(command.LongDescription) > 0 {
		fmt.Fprintln(wr, "")

		cmdstart := fmt.Sprintf("The %s command", manQuote(command.Name))

		if strings.HasPrefix(command.LongDescription, cmdstart) {
			fmt.Fprintf(wr, "The \\fI%s\\fP command", manQuote(command.Name))

			formatForMan(wr, command.LongDescription[len(cmdstart):])
			fmt.Fprintln(wr, "")
		} else {
			formatForMan(wr, command.LongDescription)
			fmt.Fprintln(wr, "")
		}
	}

	var pre = usagePrefix + " " + command.Name

	var usage string
	if us, ok := command.data.(Usage); ok {
		usage = us.Usage()
	} else if command.hasHelpOptions() {
		usage = fmt.Sprintf("[%s-OPTIONS]", command.Name)
	}

	var nextPrefix = pre
	if len(usage) > 0 {
		fmt.Fprintf(wr, "\n\\fBUsage\\fP: %s %s\n.TP\n", manQuote(pre), manQuote(usage))
		nextPrefix = pre + " " + usage
	}

	if len(command.Aliases) > 0 {
		fmt.Fprintf(wr, "\n\\fBAliases\\fP: %s\n\n", manQuote(strings.Join(command.Aliases, ", ")))
	}

	writeManPageOptions(wr, command.Group)
	writeManPageSubcommands(wr, name, nextPrefix, command)
}

// WriteManPage writes a basic man page in groff format to the specified
// writer.
func (p *Parser) WriteManPage(wr io.Writer) {
	t := time.Now()
	source_date_epoch := os.Getenv("SOURCE_DATE_EPOCH")
	if source_date_epoch != "" {
		sde, err := strconv.ParseInt(source_date_epoch, 10, 64)
		if err != nil {
			panic(fmt.Sprintf("Invalid SOURCE_DATE_EPOCH: %s", err))
		}
		t = time.Unix(sde, 0)
	}

	fmt.Fprintf(wr, ".TH %s 1 \"%s\"\n", manQuote(p.Name), t.Format("2 January 2006"))
	fmt.Fprintln(wr, ".SH NAME")
	fmt.Fprintf(wr, "%s \\- %s\n", manQuote(p.Name), manQuote(p.ShortDescription))
	fmt.Fprintln(wr, ".SH SYNOPSIS")

	usage := p.Usage

	if len(usage) == 0 {
		usage = "[OPTIONS]"
	}

	fmt.Fprintf(wr, "\\fB%s\\fP %s\n", manQuote(p.Name), manQuote(usage))
	fmt.Fprintln(wr, ".SH DESCRIPTION")

	formatForMan(wr, p.LongDescription)
	fmt.Fprintln(wr, "")

	fmt.Fprintln(wr, ".SH OPTIONS")

	writeManPageOptions(wr, p.Command.Group)

	if len(p.visibleCommands()) > 0 {
		fmt.Fprintln(wr, ".SH COMMANDS")

		writeManPageSubcommands(wr, "", p.Name+" "+usage, p.Command)
	}
}
<commit_msg>Do not quote new lines in description for man pages<commit_after>package flags

import (
	"fmt"
	"io"
	"os"
	"runtime"
	"strconv"
	"strings"
	"time"
)

func manQuoteLines(s string) string {
	lines := strings.Split(s, "\n")
	parts := []string{}

	for _, line := range lines {
		parts = append(parts, manQuote(line))
	}

	return strings.Join(parts, "\n")
}

func manQuote(s string) string {
	return strings.Replace(s, "\\", "\\\\", -1)
}

func formatForMan(wr io.Writer, s string, quoter func(s string) string) {
	for {
		idx := strings.IndexRune(s, '`')

		if idx < 0 {
			fmt.Fprintf(wr, "%s", quoter(s))
			break
		}

		fmt.Fprintf(wr, "%s", quoter(s[:idx]))

		s = s[idx+1:]
		idx = strings.IndexRune(s, '\'')

		if idx < 0 {
			fmt.Fprintf(wr, "%s", quoter(s))
			break
		}

		fmt.Fprintf(wr, "\\fB%s\\fP", quoter(s[:idx]))
		s = s[idx+1:]
	}
}

func writeManPageOptions(wr io.Writer, grp *Group) {
	grp.eachGroup(func(group *Group) {
		if !group.showInHelp() {
			return
		}

		// If the parent (grp) has any subgroups, display their descriptions as
		// subsection headers similar to the output of --help.
		if group.ShortDescription != "" && len(grp.groups) > 0 {
			fmt.Fprintf(wr, ".SS %s\n", group.ShortDescription)

			if group.LongDescription != "" {
				formatForMan(wr, group.LongDescription, manQuoteLines)
				fmt.Fprintln(wr, "")
			}
		}

		for _, opt := range group.options {
			if !opt.showInHelp() {
				continue
			}

			fmt.Fprintln(wr, ".TP")
			fmt.Fprintf(wr, "\\fB")

			if opt.ShortName != 0 {
				fmt.Fprintf(wr, "\\fB\\-%c\\fR", opt.ShortName)
			}

			if len(opt.LongName) != 0 {
				if opt.ShortName != 0 {
					fmt.Fprintf(wr, ", ")
				}

				fmt.Fprintf(wr, "\\fB\\-\\-%s\\fR", manQuote(opt.LongNameWithNamespace()))
			}

			if len(opt.ValueName) != 0 || opt.OptionalArgument {
				if opt.OptionalArgument {
					fmt.Fprintf(wr, " [\\fI%s=%s\\fR]", manQuote(opt.ValueName), manQuote(strings.Join(quoteV(opt.OptionalValue), ", ")))
				} else {
					fmt.Fprintf(wr, " \\fI%s\\fR", manQuote(opt.ValueName))
				}
			}

			if len(opt.Default) != 0 {
				fmt.Fprintf(wr, " <default: \\fI%s\\fR>", manQuote(strings.Join(quoteV(opt.Default), ", ")))
			} else if len(opt.EnvKeyWithNamespace()) != 0 {
				if runtime.GOOS == "windows" {
					fmt.Fprintf(wr, " <default: \\fI%%%s%%\\fR>", manQuote(opt.EnvKeyWithNamespace()))
				} else {
					fmt.Fprintf(wr, " <default: \\fI$%s\\fR>", manQuote(opt.EnvKeyWithNamespace()))
				}
			}

			if opt.Required {
				fmt.Fprintf(wr, " (\\fIrequired\\fR)")
			}

			fmt.Fprintln(wr, "\\fP")

			if len(opt.Description) != 0 {
				formatForMan(wr, opt.Description, manQuoteLines)
				fmt.Fprintln(wr, "")
			}
		}
	})
}

func writeManPageSubcommands(wr io.Writer, name string, usagePrefix string, root *Command) {
	commands := root.sortedVisibleCommands()

	for _, c := range commands {
		var nn string

		if c.Hidden {
			continue
		}

		if len(name) != 0 {
			nn = name + " " + c.Name
		} else {
			nn = c.Name
		}

		writeManPageCommand(wr, nn, usagePrefix, c)
	}
}

func writeManPageCommand(wr io.Writer, name string, usagePrefix string, command *Command) {
	fmt.Fprintf(wr, ".SS %s\n", name)
	fmt.Fprintln(wr, command.ShortDescription)

	if len(command.LongDescription) > 0 {
		fmt.Fprintln(wr, "")

		cmdstart := fmt.Sprintf("The %s command", manQuote(command.Name))

		if strings.HasPrefix(command.LongDescription, cmdstart) {
			fmt.Fprintf(wr, "The \\fI%s\\fP command", manQuote(command.Name))

			formatForMan(wr, command.LongDescription[len(cmdstart):], manQuoteLines)
			fmt.Fprintln(wr, "")
		} else {
			formatForMan(wr, command.LongDescription, manQuoteLines)
			fmt.Fprintln(wr, "")
		}
	}

	var pre = usagePrefix + " " + command.Name

	var usage string
	if us, ok := command.data.(Usage); ok {
		usage = us.Usage()
	} else if command.hasHelpOptions() {
		usage = fmt.Sprintf("[%s-OPTIONS]", command.Name)
	}

	var nextPrefix = pre
	if len(usage) > 0 {
		fmt.Fprintf(wr, "\n\\fBUsage\\fP: %s %s\n.TP\n", manQuote(pre), manQuote(usage))
		nextPrefix = pre + " " + usage
	}

	if len(command.Aliases) > 0 {
		fmt.Fprintf(wr, "\n\\fBAliases\\fP: %s\n\n", manQuote(strings.Join(command.Aliases, ", ")))
	}

	writeManPageOptions(wr, command.Group)
	writeManPageSubcommands(wr, name, nextPrefix, command)
}

// WriteManPage writes a basic man page in groff format to the specified
// writer.
func (p *Parser) WriteManPage(wr io.Writer) {
	t := time.Now()
	source_date_epoch := os.Getenv("SOURCE_DATE_EPOCH")
	if source_date_epoch != "" {
		sde, err := strconv.ParseInt(source_date_epoch, 10, 64)
		if err != nil {
			panic(fmt.Sprintf("Invalid SOURCE_DATE_EPOCH: %s", err))
		}
		t = time.Unix(sde, 0)
	}

	fmt.Fprintf(wr, ".TH %s 1 \"%s\"\n", manQuote(p.Name), t.Format("2 January 2006"))
	fmt.Fprintln(wr, ".SH NAME")
	fmt.Fprintf(wr, "%s \\- %s\n", manQuote(p.Name), manQuoteLines(p.ShortDescription))
	fmt.Fprintln(wr, ".SH SYNOPSIS")

	usage := p.Usage

	if len(usage) == 0 {
		usage = "[OPTIONS]"
	}

	fmt.Fprintf(wr, "\\fB%s\\fP %s\n", manQuote(p.Name), manQuote(usage))
	fmt.Fprintln(wr, ".SH DESCRIPTION")

	formatForMan(wr, p.LongDescription, manQuoteLines)
	fmt.Fprintln(wr, "")

	fmt.Fprintln(wr, ".SH OPTIONS")

	writeManPageOptions(wr, p.Command.Group)

	if len(p.visibleCommands()) > 0 {
		fmt.Fprintln(wr, ".SH COMMANDS")

		writeManPageSubcommands(wr, "", p.Name+" "+usage, p.Command)
	}
}
<|endoftext|>


<commit_before>package router

import (
	"github.com/gorilla/mux"

	"net/http"
)

var Router *mux.Router

func init() {
	Router = mux.NewRouter()

	cssHandler := http.FileServer(http.Dir("./public/css/"))
	jsHandler := http.FileServer(http.Dir("./public/js/"))
	imgHandler := http.FileServer(http.Dir("./public/img/"))
	http.Handle("/css/", http.StripPrefix("/public/css/", cssHandler))
	http.Handle("/js/", http.StripPrefix("/public/js/", jsHandler))
	http.Handle("/img/", http.StripPrefix("/public/img/", imgHandler))

	// Routes,
	Router.HandleFunc("/", HomeHandler).Name("home")
	Router.HandleFunc("/page/{page:[0-9]+}", HomeHandler).Name("home_page")
	Router.HandleFunc("/search", SearchHandler).Name("search")
	Router.HandleFunc("/search/{page}", SearchHandler).Name("search_page")
	Router.HandleFunc("/api/{page}", ApiHandler).Methods("GET")
	Router.HandleFunc("/api/view/{id}", ApiViewHandler).Methods("GET")
	Router.HandleFunc("/faq", FaqHandler).Name("faq")
	Router.HandleFunc("/feed", RssHandler).Name("feed")
	Router.HandleFunc("/view/{id}", ViewHandler).Name("view_torrent")
	Router.HandleFunc("/upload", UploadHandler).Name("upload")
	Router.HandleFunc("/user/register", UserRegisterFormHandler).Name("user_register")
}
<commit_msg>Fixed Typo<commit_after>package router

import (
	"github.com/gorilla/mux"

	"net/http"
)

var Router *mux.Router

func init() {
	Router = mux.NewRouter()

	cssHandler := http.FileServer(http.Dir("./public/css/"))
	jsHandler := http.FileServer(http.Dir("./public/js/"))
	imgHandler := http.FileServer(http.Dir("./public/img/"))
	http.Handle("/css/", http.StripPrefix("/css/", cssHandler))
	http.Handle("/js/", http.StripPrefix("/js/", jsHandler))
	http.Handle("/img/", http.StripPrefix("/img/", imgHandler))

	// Routes,
	Router.HandleFunc("/", HomeHandler).Name("home")
	Router.HandleFunc("/page/{page:[0-9]+}", HomeHandler).Name("home_page")
	Router.HandleFunc("/search", SearchHandler).Name("search")
	Router.HandleFunc("/search/{page}", SearchHandler).Name("search_page")
	Router.HandleFunc("/api/{page}", ApiHandler).Methods("GET")
	Router.HandleFunc("/api/view/{id}", ApiViewHandler).Methods("GET")
	Router.HandleFunc("/faq", FaqHandler).Name("faq")
	Router.HandleFunc("/feed", RssHandler).Name("feed")
	Router.HandleFunc("/view/{id}", ViewHandler).Name("view_torrent")
	Router.HandleFunc("/upload", UploadHandler).Name("upload")
	Router.HandleFunc("/user/register", UserRegisterFormHandler).Name("user_register")
}
<|endoftext|>


<commit_before>/*
	Copyright (C) 2016 vLife Systems Ltd <http://vlifesystems.com>
	This file is part of rhkit.

	rhkit is free software: you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation, either version 3 of the License, or
	(at your option) any later version.

	rhkit is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.

	You should have received a copy of the GNU General Public License
	along with rhkit; see the file COPYING.  If not, see
	<http://www.gnu.org/licenses/>.
*/

package rhkit

import (
	"fmt"
	"github.com/lawrencewoodman/dexpr"
	"github.com/lawrencewoodman/dlit"
	"github.com/vlifesystems/rhkit/rule"
	"sort"
	"strconv"
	"strings"
)

type ruleGeneratorFunc func(*Description, []string, string) []rule.Rule

func GenerateRules(
	inputDescription *Description,
	ruleFields []string,
) []rule.Rule {
	rules := make([]rule.Rule, 1)
	ruleGenerators := []ruleGeneratorFunc{
		generateIntRules, generateFloatRules, generateValueRules,
		generateCompareNumericRules, generateCompareStringRules,
		generateInRules,
	}
	rules[0] = rule.NewTrue()
	for field := range inputDescription.Fields {
		if stringInSlice(field, ruleFields) {
			for _, ruleGenerator := range ruleGenerators {
				newRules := ruleGenerator(inputDescription, ruleFields, field)
				rules = append(rules, newRules...)
			}
		}
	}

	if len(ruleFields) == 2 {
		cRules := CombineRules(rules)
		rules = append(rules, cRules...)
	}
	rule.Sort(rules)
	return rules
}

func CombineRules(rules []rule.Rule) []rule.Rule {
	rule.Sort(rules)
	combinedRules := make([]rule.Rule, 0)
	numRules := len(rules)
	for i := 0; i < numRules-1; i++ {
		for j := i + 1; j < numRules; j++ {
			if andRule, err := rule.NewAnd(rules[i], rules[j]); err == nil {
				combinedRules = append(combinedRules, andRule)
			}
			if orRule, err := rule.NewOr(rules[i], rules[j]); err == nil {
				combinedRules = append(combinedRules, orRule)
			}
		}
	}
	return rule.Uniq(combinedRules)
}

func stringInSlice(s string, strings []string) bool {
	for _, x := range strings {
		if x == s {
			return true
		}
	}
	return false
}

func generateValueRules(
	inputDescription *Description,
	ruleFields []string,
	field string,
) []rule.Rule {
	fd := inputDescription.Fields[field]
	rulesMap := make(map[string]rule.Rule)
	values := fd.Values
	if len(values) < 2 {
		return []rule.Rule{}
	}
	switch fd.Kind {
	case ftInt:
		for _, vd := range values {
			if vd.Num < 2 {
				continue
			}
			n, isInt := vd.Value.Int()
			if !isInt {
				panic(fmt.Sprintf("value isn't int: %s", vd.Value))
			}
			eqRule := rule.NewEQFVI(field, n)
			neRule := rule.NewNEFVI(field, n)
			rulesMap[eqRule.String()] = eqRule
			rulesMap[neRule.String()] = neRule
		}
	case ftFloat:
		maxDP := fd.MaxDP
		for _, vd := range values {
			if vd.Num < 2 {
				continue
			}
			n, isFloat := vd.Value.Float()
			if !isFloat {
				panic(fmt.Sprintf("value isn't float: %s", vd.Value))
			}
			tn := truncateFloat(n, maxDP)
			eqRule := rule.NewEQFVF(field, tn)
			neRule := rule.NewNEFVF(field, tn)
			rulesMap[eqRule.String()] = eqRule
			rulesMap[neRule.String()] = neRule
		}
	case ftString:
		for _, vd := range values {
			if vd.Num < 2 {
				continue
			}
			s := vd.Value.String()
			eqRule := rule.NewEQFVS(field, s)
			rulesMap[eqRule.String()] = eqRule
			if len(values) > 2 {
				neRule := rule.NewNEFVS(field, s)
				rulesMap[neRule.String()] = neRule
			}
		}
	}
	rules := rulesMapToArray(rulesMap)
	return rules
}

func generateIntRules(
	inputDescription *Description,
	ruleFields []string,
	field string,
) []rule.Rule {
	fd := inputDescription.Fields[field]
	if fd.Kind != ftInt {
		return []rule.Rule{}
	}
	rulesMap := make(map[string]rule.Rule)
	min, _ := fd.Min.Int()
	max, _ := fd.Max.Int()
	diff := max - min
	step := diff / 20
	if step == 0 {
		step = 1
	}

	for i := step; i <= diff; i += step {
		n := min + i
		r := rule.NewLEFVI(field, n)
		rulesMap[r.String()] = r
	}

	// i set to 0 to make more tweakable
	for i := int64(0); i < diff; i += step {
		n := min + i
		r := rule.NewGEFVI(field, n)
		rulesMap[r.String()] = r
	}

	// i set to 0 to make more tweakable
	for i := int64(0); i < diff; i += step {
		geN := min + i
		for j := step; j <= diff; j += step {
			leN := min + j
			rB, err := rule.NewBetweenFVI(field, geN, leN)
			if err == nil {
				rulesMap[rB.String()] = rB
			}
			rO, err := rule.NewOutsideFVI(field, leN, geN)
			if err == nil {
				rulesMap[rO.String()] = rO
			}
		}
	}

	return rulesMapToArray(rulesMap)
}

func truncateFloat(f float64, maxDP int) float64 {
	v := fmt.Sprintf("%.*f", maxDP, f)
	nf, _ := strconv.ParseFloat(v, 64)
	return nf
}

func generateFloatRules(
	inputDescription *Description,
	ruleFields []string,
	field string,
) []rule.Rule {
	fd := inputDescription.Fields[field]
	if fd.Kind != ftFloat {
		return []rule.Rule{}
	}
	rulesMap := make(map[string]rule.Rule)
	min, _ := fd.Min.Float()
	max, _ := fd.Max.Float()
	maxDP := fd.MaxDP
	diff := max - min
	step := diff / 20.0

	for i := step; i <= diff; i += step {
		n := truncateFloat(min+i, maxDP)
		r := rule.NewLEFVF(field, n)
		rulesMap[r.String()] = r
	}

	// i set to 0 to make more tweakable
	for i := float64(0); i < diff; i += step {
		n := truncateFloat(min+i, maxDP)
		r := rule.NewGEFVF(field, n)
		rulesMap[r.String()] = r
	}

	// i set to 0 to make more tweakable
	for i := float64(0); i < diff; i += step {
		geN := truncateFloat(min+i, maxDP)
		for j := step; j <= diff; j += step {
			leN := truncateFloat(min+j, maxDP)
			rB, err := rule.NewBetweenFVF(field, geN, leN)
			if err == nil {
				rulesMap[rB.String()] = rB
			}
			rO, err := rule.NewOutsideFVF(field, leN, geN)
			if err == nil {
				rulesMap[rO.String()] = rO
			}
		}
	}

	return rulesMapToArray(rulesMap)
}

func generateCompareNumericRules(
	inputDescription *Description,
	ruleFields []string,
	field string,
) []rule.Rule {
	fd := inputDescription.Fields[field]
	if fd.Kind != ftInt && fd.Kind != ftFloat {
		return []rule.Rule{}
	}
	fieldNum := calcFieldNum(inputDescription.Fields, field)
	rulesMap := make(map[string]rule.Rule)
	ruleNewFuncs := []func(string, string) rule.Rule{
		rule.NewLTFF,
		rule.NewLEFF,
		rule.NewEQFF,
		rule.NewNEFF,
		rule.NewGEFF,
		rule.NewGTFF,
	}

	for oField, oFd := range inputDescription.Fields {
		oFieldNum := calcFieldNum(inputDescription.Fields, oField)
		isComparable := hasComparableNumberRange(fd, oFd)
		if fieldNum < oFieldNum && isComparable &&
			stringInSlice(oField, ruleFields) {
			for _, ruleNewFunc := range ruleNewFuncs {
				r := ruleNewFunc(field, oField)
				rulesMap[r.String()] = r
			}
		}
	}
	rules := rulesMapToArray(rulesMap)
	return rules
}

func generateCompareStringRules(
	inputDescription *Description,
	ruleFields []string,
	field string,
) []rule.Rule {
	fd := inputDescription.Fields[field]
	if fd.Kind != ftString {
		return []rule.Rule{}
	}
	fieldNum := calcFieldNum(inputDescription.Fields, field)
	rulesMap := make(map[string]rule.Rule)
	ruleNewFuncs := []func(string, string) rule.Rule{
		rule.NewEQFF,
		rule.NewNEFF,
	}
	for oField, oFd := range inputDescription.Fields {
		if oFd.Kind == ftString {
			oFieldNum := calcFieldNum(inputDescription.Fields, oField)
			numSharedValues := calcNumSharedValues(fd, oFd)
			if fieldNum < oFieldNum && numSharedValues >= 2 &&
				stringInSlice(oField, ruleFields) {
				for _, ruleNewFunc := range ruleNewFuncs {
					r := ruleNewFunc(field, oField)
					rulesMap[r.String()] = r
				}
			}
		}
	}
	rules := rulesMapToArray(rulesMap)
	return rules
}

func calcNumSharedValues(
	fd1 *fieldDescription,
	fd2 *fieldDescription,
) int {
	numShared := 0
	for _, vd1 := range fd1.Values {
		if _, ok := fd2.Values[vd1.Value.String()]; ok {
			numShared++
		}
	}
	return numShared
}

func isNumberField(fd *fieldDescription) bool {
	return fd.Kind == ftInt || fd.Kind == ftFloat
}

var compareExpr *dexpr.Expr = dexpr.MustNew("min1 < max2 && max1 > min2")

func hasComparableNumberRange(
	fd1 *fieldDescription,
	fd2 *fieldDescription,
) bool {
	if !isNumberField(fd1) || !isNumberField(fd2) {
		return false
	}
	var isComparable bool
	vars := map[string]*dlit.Literal{
		"min1": fd1.Min,
		"max1": fd1.Max,
		"min2": fd2.Min,
		"max2": fd2.Max,
	}
	funcs := map[string]dexpr.CallFun{}
	isComparable, err := compareExpr.EvalBool(vars, funcs)
	return err == nil && isComparable
}

func rulesMapToArray(rulesMap map[string]rule.Rule) []rule.Rule {
	rules := make([]rule.Rule, len(rulesMap))
	i := 0
	for _, expr := range rulesMap {
		rules[i] = expr
		i++
	}
	return rules
}

// TODO: Allow more numValues if only two ruleFields
func generateInRules(
	inputDescription *Description,
	ruleFields []string,
	field string,
) []rule.Rule {
	fd := inputDescription.Fields[field]
	numValues := len(fd.Values)
	if fd.Kind != ftString &&
		fd.Kind != ftFloat &&
		fd.Kind != ftInt ||
		numValues <= 3 || numValues > 12 {
		return []rule.Rule{}
	}
	rulesMap := make(map[string]rule.Rule)
	for i := 3; ; i++ {
		numOnBits := calcNumOnBits(i)
		if numOnBits >= numValues {
			break
		}
		if numOnBits >= 2 && numOnBits <= 5 && numOnBits < (numValues-1) {
			compareValues := makeCompareValues(fd.Values, i)
			if len(compareValues) >= 2 {
				r := rule.NewInFV(field, compareValues)
				rulesMap[r.String()] = r
			}
		}
	}
	rules := rulesMapToArray(rulesMap)
	return rules
}

func makeCompareValues(
	values map[string]valueDescription,
	i int,
) []*dlit.Literal {
	bStr := fmt.Sprintf("%b", i)
	numValues := len(values)
	lits := valuesToLiterals(values)
	j := numValues - 1
	compareValues := []*dlit.Literal{}
	for _, b := range reverseString(bStr) {
		if b == '1' {
			lit := lits[numValues-1-j]
			if values[lit.String()].Num < 2 {
				return []*dlit.Literal{}
			}
			compareValues = append(compareValues, lit)
		}
		j -= 1
	}
	return compareValues
}

func valuesToLiterals(values map[string]valueDescription) []*dlit.Literal {
	lits := make([]*dlit.Literal, len(values))
	keys := make([]string, len(values))
	i := 0
	for k, _ := range values {
		keys[i] = k
		i++
	}
	// The keys are sorted to make it easier to test because maps aren't ordered
	sort.Strings(keys)
	j := 0
	for _, k := range keys {
		lits[j] = values[k].Value
		j++
	}
	return lits
}

func reverseString(s string) (r string) {
	for _, v := range s {
		r = string(v) + r
	}
	return
}

func calcNumOnBits(i int) int {
	bStr := fmt.Sprintf("%b", i)
	return strings.Count(bStr, "1")
}

func calcFieldNum(
	fieldDescriptions map[string]*fieldDescription,
	fieldN string,
) int {
	fields := make([]string, len(fieldDescriptions))
	i := 0
	for field := range fieldDescriptions {
		fields[i] = field
		i++
	}
	sort.Strings(fields)
	j := 0
	for _, field := range fields {
		if field == fieldN {
			return j
		}
		j++
	}
	panic("can't find field in fieldDescriptions")
}
<commit_msg>implify for x, _ := range statements<commit_after>/*
	Copyright (C) 2016 vLife Systems Ltd <http://vlifesystems.com>
	This file is part of rhkit.

	rhkit is free software: you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation, either version 3 of the License, or
	(at your option) any later version.

	rhkit is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.

	You should have received a copy of the GNU General Public License
	along with rhkit; see the file COPYING.  If not, see
	<http://www.gnu.org/licenses/>.
*/

package rhkit

import (
	"fmt"
	"github.com/lawrencewoodman/dexpr"
	"github.com/lawrencewoodman/dlit"
	"github.com/vlifesystems/rhkit/rule"
	"sort"
	"strconv"
	"strings"
)

type ruleGeneratorFunc func(*Description, []string, string) []rule.Rule

func GenerateRules(
	inputDescription *Description,
	ruleFields []string,
) []rule.Rule {
	rules := make([]rule.Rule, 1)
	ruleGenerators := []ruleGeneratorFunc{
		generateIntRules, generateFloatRules, generateValueRules,
		generateCompareNumericRules, generateCompareStringRules,
		generateInRules,
	}
	rules[0] = rule.NewTrue()
	for field := range inputDescription.Fields {
		if stringInSlice(field, ruleFields) {
			for _, ruleGenerator := range ruleGenerators {
				newRules := ruleGenerator(inputDescription, ruleFields, field)
				rules = append(rules, newRules...)
			}
		}
	}

	if len(ruleFields) == 2 {
		cRules := CombineRules(rules)
		rules = append(rules, cRules...)
	}
	rule.Sort(rules)
	return rules
}

func CombineRules(rules []rule.Rule) []rule.Rule {
	rule.Sort(rules)
	combinedRules := make([]rule.Rule, 0)
	numRules := len(rules)
	for i := 0; i < numRules-1; i++ {
		for j := i + 1; j < numRules; j++ {
			if andRule, err := rule.NewAnd(rules[i], rules[j]); err == nil {
				combinedRules = append(combinedRules, andRule)
			}
			if orRule, err := rule.NewOr(rules[i], rules[j]); err == nil {
				combinedRules = append(combinedRules, orRule)
			}
		}
	}
	return rule.Uniq(combinedRules)
}

func stringInSlice(s string, strings []string) bool {
	for _, x := range strings {
		if x == s {
			return true
		}
	}
	return false
}

func generateValueRules(
	inputDescription *Description,
	ruleFields []string,
	field string,
) []rule.Rule {
	fd := inputDescription.Fields[field]
	rulesMap := make(map[string]rule.Rule)
	values := fd.Values
	if len(values) < 2 {
		return []rule.Rule{}
	}
	switch fd.Kind {
	case ftInt:
		for _, vd := range values {
			if vd.Num < 2 {
				continue
			}
			n, isInt := vd.Value.Int()
			if !isInt {
				panic(fmt.Sprintf("value isn't int: %s", vd.Value))
			}
			eqRule := rule.NewEQFVI(field, n)
			neRule := rule.NewNEFVI(field, n)
			rulesMap[eqRule.String()] = eqRule
			rulesMap[neRule.String()] = neRule
		}
	case ftFloat:
		maxDP := fd.MaxDP
		for _, vd := range values {
			if vd.Num < 2 {
				continue
			}
			n, isFloat := vd.Value.Float()
			if !isFloat {
				panic(fmt.Sprintf("value isn't float: %s", vd.Value))
			}
			tn := truncateFloat(n, maxDP)
			eqRule := rule.NewEQFVF(field, tn)
			neRule := rule.NewNEFVF(field, tn)
			rulesMap[eqRule.String()] = eqRule
			rulesMap[neRule.String()] = neRule
		}
	case ftString:
		for _, vd := range values {
			if vd.Num < 2 {
				continue
			}
			s := vd.Value.String()
			eqRule := rule.NewEQFVS(field, s)
			rulesMap[eqRule.String()] = eqRule
			if len(values) > 2 {
				neRule := rule.NewNEFVS(field, s)
				rulesMap[neRule.String()] = neRule
			}
		}
	}
	rules := rulesMapToArray(rulesMap)
	return rules
}

func generateIntRules(
	inputDescription *Description,
	ruleFields []string,
	field string,
) []rule.Rule {
	fd := inputDescription.Fields[field]
	if fd.Kind != ftInt {
		return []rule.Rule{}
	}
	rulesMap := make(map[string]rule.Rule)
	min, _ := fd.Min.Int()
	max, _ := fd.Max.Int()
	diff := max - min
	step := diff / 20
	if step == 0 {
		step = 1
	}

	for i := step; i <= diff; i += step {
		n := min + i
		r := rule.NewLEFVI(field, n)
		rulesMap[r.String()] = r
	}

	// i set to 0 to make more tweakable
	for i := int64(0); i < diff; i += step {
		n := min + i
		r := rule.NewGEFVI(field, n)
		rulesMap[r.String()] = r
	}

	// i set to 0 to make more tweakable
	for i := int64(0); i < diff; i += step {
		geN := min + i
		for j := step; j <= diff; j += step {
			leN := min + j
			rB, err := rule.NewBetweenFVI(field, geN, leN)
			if err == nil {
				rulesMap[rB.String()] = rB
			}
			rO, err := rule.NewOutsideFVI(field, leN, geN)
			if err == nil {
				rulesMap[rO.String()] = rO
			}
		}
	}

	return rulesMapToArray(rulesMap)
}

func truncateFloat(f float64, maxDP int) float64 {
	v := fmt.Sprintf("%.*f", maxDP, f)
	nf, _ := strconv.ParseFloat(v, 64)
	return nf
}

func generateFloatRules(
	inputDescription *Description,
	ruleFields []string,
	field string,
) []rule.Rule {
	fd := inputDescription.Fields[field]
	if fd.Kind != ftFloat {
		return []rule.Rule{}
	}
	rulesMap := make(map[string]rule.Rule)
	min, _ := fd.Min.Float()
	max, _ := fd.Max.Float()
	maxDP := fd.MaxDP
	diff := max - min
	step := diff / 20.0

	for i := step; i <= diff; i += step {
		n := truncateFloat(min+i, maxDP)
		r := rule.NewLEFVF(field, n)
		rulesMap[r.String()] = r
	}

	// i set to 0 to make more tweakable
	for i := float64(0); i < diff; i += step {
		n := truncateFloat(min+i, maxDP)
		r := rule.NewGEFVF(field, n)
		rulesMap[r.String()] = r
	}

	// i set to 0 to make more tweakable
	for i := float64(0); i < diff; i += step {
		geN := truncateFloat(min+i, maxDP)
		for j := step; j <= diff; j += step {
			leN := truncateFloat(min+j, maxDP)
			rB, err := rule.NewBetweenFVF(field, geN, leN)
			if err == nil {
				rulesMap[rB.String()] = rB
			}
			rO, err := rule.NewOutsideFVF(field, leN, geN)
			if err == nil {
				rulesMap[rO.String()] = rO
			}
		}
	}

	return rulesMapToArray(rulesMap)
}

func generateCompareNumericRules(
	inputDescription *Description,
	ruleFields []string,
	field string,
) []rule.Rule {
	fd := inputDescription.Fields[field]
	if fd.Kind != ftInt && fd.Kind != ftFloat {
		return []rule.Rule{}
	}
	fieldNum := calcFieldNum(inputDescription.Fields, field)
	rulesMap := make(map[string]rule.Rule)
	ruleNewFuncs := []func(string, string) rule.Rule{
		rule.NewLTFF,
		rule.NewLEFF,
		rule.NewEQFF,
		rule.NewNEFF,
		rule.NewGEFF,
		rule.NewGTFF,
	}

	for oField, oFd := range inputDescription.Fields {
		oFieldNum := calcFieldNum(inputDescription.Fields, oField)
		isComparable := hasComparableNumberRange(fd, oFd)
		if fieldNum < oFieldNum && isComparable &&
			stringInSlice(oField, ruleFields) {
			for _, ruleNewFunc := range ruleNewFuncs {
				r := ruleNewFunc(field, oField)
				rulesMap[r.String()] = r
			}
		}
	}
	rules := rulesMapToArray(rulesMap)
	return rules
}

func generateCompareStringRules(
	inputDescription *Description,
	ruleFields []string,
	field string,
) []rule.Rule {
	fd := inputDescription.Fields[field]
	if fd.Kind != ftString {
		return []rule.Rule{}
	}
	fieldNum := calcFieldNum(inputDescription.Fields, field)
	rulesMap := make(map[string]rule.Rule)
	ruleNewFuncs := []func(string, string) rule.Rule{
		rule.NewEQFF,
		rule.NewNEFF,
	}
	for oField, oFd := range inputDescription.Fields {
		if oFd.Kind == ftString {
			oFieldNum := calcFieldNum(inputDescription.Fields, oField)
			numSharedValues := calcNumSharedValues(fd, oFd)
			if fieldNum < oFieldNum && numSharedValues >= 2 &&
				stringInSlice(oField, ruleFields) {
				for _, ruleNewFunc := range ruleNewFuncs {
					r := ruleNewFunc(field, oField)
					rulesMap[r.String()] = r
				}
			}
		}
	}
	rules := rulesMapToArray(rulesMap)
	return rules
}

func calcNumSharedValues(
	fd1 *fieldDescription,
	fd2 *fieldDescription,
) int {
	numShared := 0
	for _, vd1 := range fd1.Values {
		if _, ok := fd2.Values[vd1.Value.String()]; ok {
			numShared++
		}
	}
	return numShared
}

func isNumberField(fd *fieldDescription) bool {
	return fd.Kind == ftInt || fd.Kind == ftFloat
}

var compareExpr *dexpr.Expr = dexpr.MustNew("min1 < max2 && max1 > min2")

func hasComparableNumberRange(
	fd1 *fieldDescription,
	fd2 *fieldDescription,
) bool {
	if !isNumberField(fd1) || !isNumberField(fd2) {
		return false
	}
	var isComparable bool
	vars := map[string]*dlit.Literal{
		"min1": fd1.Min,
		"max1": fd1.Max,
		"min2": fd2.Min,
		"max2": fd2.Max,
	}
	funcs := map[string]dexpr.CallFun{}
	isComparable, err := compareExpr.EvalBool(vars, funcs)
	return err == nil && isComparable
}

func rulesMapToArray(rulesMap map[string]rule.Rule) []rule.Rule {
	rules := make([]rule.Rule, len(rulesMap))
	i := 0
	for _, expr := range rulesMap {
		rules[i] = expr
		i++
	}
	return rules
}

// TODO: Allow more numValues if only two ruleFields
func generateInRules(
	inputDescription *Description,
	ruleFields []string,
	field string,
) []rule.Rule {
	fd := inputDescription.Fields[field]
	numValues := len(fd.Values)
	if fd.Kind != ftString &&
		fd.Kind != ftFloat &&
		fd.Kind != ftInt ||
		numValues <= 3 || numValues > 12 {
		return []rule.Rule{}
	}
	rulesMap := make(map[string]rule.Rule)
	for i := 3; ; i++ {
		numOnBits := calcNumOnBits(i)
		if numOnBits >= numValues {
			break
		}
		if numOnBits >= 2 && numOnBits <= 5 && numOnBits < (numValues-1) {
			compareValues := makeCompareValues(fd.Values, i)
			if len(compareValues) >= 2 {
				r := rule.NewInFV(field, compareValues)
				rulesMap[r.String()] = r
			}
		}
	}
	rules := rulesMapToArray(rulesMap)
	return rules
}

func makeCompareValues(
	values map[string]valueDescription,
	i int,
) []*dlit.Literal {
	bStr := fmt.Sprintf("%b", i)
	numValues := len(values)
	lits := valuesToLiterals(values)
	j := numValues - 1
	compareValues := []*dlit.Literal{}
	for _, b := range reverseString(bStr) {
		if b == '1' {
			lit := lits[numValues-1-j]
			if values[lit.String()].Num < 2 {
				return []*dlit.Literal{}
			}
			compareValues = append(compareValues, lit)
		}
		j -= 1
	}
	return compareValues
}

func valuesToLiterals(values map[string]valueDescription) []*dlit.Literal {
	lits := make([]*dlit.Literal, len(values))
	keys := make([]string, len(values))
	i := 0
	for k := range values {
		keys[i] = k
		i++
	}
	// The keys are sorted to make it easier to test because maps aren't ordered
	sort.Strings(keys)
	j := 0
	for _, k := range keys {
		lits[j] = values[k].Value
		j++
	}
	return lits
}

func reverseString(s string) (r string) {
	for _, v := range s {
		r = string(v) + r
	}
	return
}

func calcNumOnBits(i int) int {
	bStr := fmt.Sprintf("%b", i)
	return strings.Count(bStr, "1")
}

func calcFieldNum(
	fieldDescriptions map[string]*fieldDescription,
	fieldN string,
) int {
	fields := make([]string, len(fieldDescriptions))
	i := 0
	for field := range fieldDescriptions {
		fields[i] = field
		i++
	}
	sort.Strings(fields)
	j := 0
	for _, field := range fields {
		if field == fieldN {
			return j
		}
		j++
	}
	panic("can't find field in fieldDescriptions")
}
<|endoftext|>


<commit_before>package gopsutil

import (
	"encoding/json"
)

type NetIOCountersStat struct {
	Name        string `json:"name"`         // interface name
	BytesSent   uint64 `json:"bytes_sent"`   // number of bytes sent
	BytesRecv   uint64 `json:"bytes_recv"`   // number of bytes received
	PacketsSent uint64 `json:"packets_sent"` // number of packets sent
	PacketsRecv uint64 `json:"packets_recv"` // number of packets received
	Errin       uint64 `json:"errin"`        // total number of errors while receiving
	Errout      uint64 `json:"errout"`       // total number of errors while sending
	Dropin      uint64 `json:"dropin"`       // total number of incoming packets which were dropped
	Dropout     uint64 `json:"dropout"`      // total number of outgoing packets which were dropped (always 0 on OSX and BSD)
}

type Addr struct {
	IP   string `json:"ip"`
	Port uint32 `json:"port"`
}

type NetConnectionStat struct {
	Fd     uint32 `json:"fd"`
	Family uint32 `json:"family"`
	Type   uint32 `json:"type"`
	Laddr  Addr   `json:"laddr"`
	Raddr  Addr   `json:"raddr"`
	Status string `json:"status"`
	Pid    int32  `json:"pid"`
}

func (n NetIOCountersStat) String() string {
	s, _ := json.Marshal(n)
	return string(s)
}

func (n NetConnectionStat) String() string {
	s, _ := json.Marshal(n)
	return string(s)
}

func (a Addr) String() string {
	s, _ := json.Marshal(a)
	return string(s)
}
<commit_msg>rename json tag to more understandable on NetConnectionsStat<commit_after>package gopsutil

import (
	"encoding/json"
)

type NetIOCountersStat struct {
	Name        string `json:"name"`         // interface name
	BytesSent   uint64 `json:"bytes_sent"`   // number of bytes sent
	BytesRecv   uint64 `json:"bytes_recv"`   // number of bytes received
	PacketsSent uint64 `json:"packets_sent"` // number of packets sent
	PacketsRecv uint64 `json:"packets_recv"` // number of packets received
	Errin       uint64 `json:"errin"`        // total number of errors while receiving
	Errout      uint64 `json:"errout"`       // total number of errors while sending
	Dropin      uint64 `json:"dropin"`       // total number of incoming packets which were dropped
	Dropout     uint64 `json:"dropout"`      // total number of outgoing packets which were dropped (always 0 on OSX and BSD)
}

type Addr struct {
	IP   string `json:"ip"`
	Port uint32 `json:"port"`
}

type NetConnectionStat struct {
	Fd     uint32 `json:"fd"`
	Family uint32 `json:"family"`
	Type   uint32 `json:"type"`
	Laddr  Addr   `json:"localaddr"`
	Raddr  Addr   `json:"remoteaddr"`
	Status string `json:"status"`
	Pid    int32  `json:"pid"`
}

func (n NetIOCountersStat) String() string {
	s, _ := json.Marshal(n)
	return string(s)
}

func (n NetConnectionStat) String() string {
	s, _ := json.Marshal(n)
	return string(s)
}

func (a Addr) String() string {
	s, _ := json.Marshal(a)
	return string(s)
}
<|endoftext|>