<commit_before>// Major parts of this implementation are copied verbatim from https://github.com/golang/glog, which is:
//
// Copyright 2013 Google Inc. All Rights Reserved.
//
package logger

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

	"github.com/jcgregorio/slog"
)

var (
	pid = os.Getpid()
)

type SyncWriter interface {
	Write(p []byte) (n int, err error)
	Sync() error
}

// severity identifies the sort of log: info, warning etc.
type severity int32

// These constants identify the log levels in order of increasing severity.
// A message written to a high-severity log file is also written to each
// lower-severity log file.
const (
	infoLog severity = iota
	warningLog
	errorLog
	fatalLog
	numSeverity = 4
)

const severityChar = "IWEF"

var severityName = []string{
	infoLog:    "INFO",
	warningLog: "WARNING",
	errorLog:   "ERROR",
	fatalLog:   "FATAL",
}

func New() Logger {
	return Logger{w: os.Stdout}
}

// Logger collects all the global state of the logging setup.
type Logger struct {
	w SyncWriter

	// freeList is a list of byte buffers, maintained under freeListMu.
	freeList *buffer
	// freeListMu maintains the free list. It is separate from the main mutex
	// so buffers can be grabbed and printed to without holding the main lock,
	// for better parallelization.
	freeListMu sync.Mutex
}

// buffer holds a byte Buffer for reuse. The zero value is ready for use.
type buffer struct {
	bytes.Buffer
	tmp  [64]byte // temporary byte array for creating headers.
	next *buffer
}

// getBuffer returns a new, ready-to-use buffer.
func (l *Logger) getBuffer() *buffer {
	l.freeListMu.Lock()
	b := l.freeList
	if b != nil {
		l.freeList = b.next
	}
	l.freeListMu.Unlock()
	if b == nil {
		b = new(buffer)
	} else {
		b.next = nil
		b.Reset()
	}
	return b
}

// putBuffer returns a buffer to the free list.
func (l *Logger) putBuffer(b *buffer) {
	if b.Len() >= 256 {
		// Let big buffers die a natural death.
		return
	}
	l.freeListMu.Lock()
	b.next = l.freeList
	l.freeList = b
	l.freeListMu.Unlock()
}

var timeNow = time.Now // Stubbed out for testing.

/*
header formats a log header as defined by the C++ implementation.
It returns a buffer containing the formatted header and the user's file and line number.
The depth specifies how many stack frames above lives the source line to be identified in the log message.

Log lines have this form:
	Lmmdd hh:mm:ss.uuuuuu threadid file:line] msg...
where the fields are defined as follows:
	L                A single character, representing the log level (eg 'I' for INFO)
	mm               The month (zero padded; ie May is '05')
	dd               The day (zero padded)
	hh:mm:ss.uuuuuu  Time in hours, minutes and fractional seconds
	threadid         The space-padded thread ID as returned by GetTID()
	file             The file name
	line             The line number
	msg              The user-supplied message
*/
func (l *Logger) header(s severity, depth int) (*buffer, string, int) {
	_, file, line, ok := runtime.Caller(3 + depth)
	if !ok {
		file = "???"
		line = 1
	} else {
		slash := strings.LastIndex(file, "/")
		if slash >= 0 {
			file = file[slash+1:]
		}
	}
	return l.formatHeader(s, file, line), file, line
}

// formatHeader formats a log header using the provided file name and line number.
func (l *Logger) formatHeader(s severity, file string, line int) *buffer {
	now := timeNow()
	if line < 0 {
		line = 0 // not a real line number, but acceptable to someDigits
	}
	if s > fatalLog {
		s = infoLog // for safety.
	}
	buf := l.getBuffer()

	// Avoid Fprintf, for speed. The format is so simple that we can do it quickly by hand.
	// It's worth about 3X. Fprintf is hard.
	_, month, day := now.Date()
	hour, minute, second := now.Clock()
	// Lmmdd hh:mm:ss.uuuuuu threadid file:line]
	buf.tmp[0] = severityChar[s]
	buf.twoDigits(1, int(month))
	buf.twoDigits(3, day)
	buf.tmp[5] = ' '
	buf.twoDigits(6, hour)
	buf.tmp[8] = ':'
	buf.twoDigits(9, minute)
	buf.tmp[11] = ':'
	buf.twoDigits(12, second)
	buf.tmp[14] = '.'
	buf.nDigits(6, 15, now.Nanosecond()/1000, '0')
	buf.tmp[21] = ' '
	buf.nDigits(7, 22, pid, ' ') // TODO: should be TID
	buf.tmp[29] = ' '
	buf.Write(buf.tmp[:30])
	buf.WriteString(file)
	buf.tmp[0] = ':'
	n := buf.someDigits(1, line)
	buf.tmp[n+1] = ']'
	buf.tmp[n+2] = ' '
	buf.Write(buf.tmp[:n+3])
	return buf
}

// Some custom tiny helper functions to print the log header efficiently.

const digits = "0123456789"

// twoDigits formats a zero-prefixed two-digit integer at buf.tmp[i].
func (buf *buffer) twoDigits(i, d int) {
	buf.tmp[i+1] = digits[d%10]
	d /= 10
	buf.tmp[i] = digits[d%10]
}

// nDigits formats an n-digit integer at buf.tmp[i],
// padding with pad on the left.
// It assumes d >= 0.
func (buf *buffer) nDigits(n, i, d int, pad byte) {
	j := n - 1
	for ; j >= 0 && d > 0; j-- {
		buf.tmp[i+j] = digits[d%10]
		d /= 10
	}
	for ; j >= 0; j-- {
		buf.tmp[i+j] = pad
	}
}

// someDigits formats a zero-prefixed variable-width integer at buf.tmp[i].
func (buf *buffer) someDigits(i, d int) int {
	// Print into the top, then copy down. We know there's space for at least
	// a 10-digit number.
	j := len(buf.tmp)
	for {
		j--
		buf.tmp[j] = digits[d%10]
		d /= 10
		if d == 0 {
			break
		}
	}
	return copy(buf.tmp[i:], buf.tmp[j:])
}

func (l *Logger) print(s severity, args ...interface{}) {
	l.printDepth(s, 1, args...)
}

func (l *Logger) printDepth(s severity, depth int, args ...interface{}) {
	buf, file, line := l.header(s, depth)
	fmt.Fprint(buf, args...)
	if buf.Bytes()[buf.Len()-1] != '\n' {
		buf.WriteByte('\n')
	}
	l.output(s, buf, file, line)
}

func (l *Logger) printf(s severity, format string, args ...interface{}) {
	buf, file, line := l.header(s, 0)
	fmt.Fprintf(buf, format, args...)
	if buf.Bytes()[buf.Len()-1] != '\n' {
		buf.WriteByte('\n')
	}
	l.output(s, buf, file, line)
}

// output writes the data to the log files and releases the buffer.
func (l *Logger) output(s severity, buf *buffer, file string, line int) {
	data := buf.Bytes()
	l.w.Write(data)
	if s == fatalLog {
		// Write the stack trace for all goroutines to the files.
		trace := stacks(true)
		l.w.Write(trace)
		l.w.Sync()
		os.Exit(255) // C++ uses -1, which is silly because it's anded with 255 anyway.
	}
}

// stacks is a wrapper for runtime.Stack that attempts to recover the data for all goroutines.
func stacks(all bool) []byte {
	// We don't know how big the traces are, so grow a few times if they don't fit. Start large, though.
	n := 10000
	if all {
		n = 100000
	}
	var trace []byte
	for i := 0; i < 5; i++ {
		trace = make([]byte, n)
		nbytes := runtime.Stack(trace, all)
		if nbytes < len(trace) {
			return trace[:nbytes]
		}
		n *= 2
	}
	return trace
}

func (l *Logger) Info(args ...interface{}) {
	l.print(infoLog, args...)
}

func (l *Logger) Infof(format string, args ...interface{}) {
	l.printf(infoLog, format, args...)
}

func (l *Logger) Warning(args ...interface{}) {
	l.print(warningLog, args...)
}

func (l *Logger) Warningf(format string, args ...interface{}) {
	l.printf(warningLog, format, args...)
}

func (l *Logger) Error(args ...interface{}) {
	l.print(errorLog, args...)
}

func (l *Logger) Errorf(format string, args ...interface{}) {
	l.printf(errorLog, format, args...)
}

func (l *Logger) Fatal(args ...interface{}) {
	l.print(fatalLog, args...)
}

func (l *Logger) Fatalf(format string, args ...interface{}) {
	l.printf(fatalLog, format, args...)
}

func (l *Logger) Raw(s string) {
	l.w.Write([]byte(s))
	if s[len(s)-1] != '\n' {
		l.w.Write([]byte{'\n'})
	}
}

// SetOutput changes where the logs are written to. By default
// the value is os.Stdout.
func (l *Logger) SetOutput(w SyncWriter) {
	l.w = w
}

var _ slog.Logger = (*Logger)(nil)
<commit_msg>Make New() return a slog.Logger compatible value.<commit_after>// Major parts of this implementation are copied verbatim from https://github.com/golang/glog, which is:
//
// Copyright 2013 Google Inc. All Rights Reserved.
//
package logger

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

	"github.com/jcgregorio/slog"
)

var (
	pid = os.Getpid()
)

type SyncWriter interface {
	Write(p []byte) (n int, err error)
	Sync() error
}

// severity identifies the sort of log: info, warning etc.
type severity int32

// These constants identify the log levels in order of increasing severity.
// A message written to a high-severity log file is also written to each
// lower-severity log file.
const (
	infoLog severity = iota
	warningLog
	errorLog
	fatalLog
	numSeverity = 4
)

const severityChar = "IWEF"

var severityName = []string{
	infoLog:    "INFO",
	warningLog: "WARNING",
	errorLog:   "ERROR",
	fatalLog:   "FATAL",
}

func New() *Logger {
	return &Logger{w: os.Stdout}
}

// Logger collects all the global state of the logging setup.
type Logger struct {
	w SyncWriter

	// freeList is a list of byte buffers, maintained under freeListMu.
	freeList *buffer
	// freeListMu maintains the free list. It is separate from the main mutex
	// so buffers can be grabbed and printed to without holding the main lock,
	// for better parallelization.
	freeListMu sync.Mutex
}

// buffer holds a byte Buffer for reuse. The zero value is ready for use.
type buffer struct {
	bytes.Buffer
	tmp  [64]byte // temporary byte array for creating headers.
	next *buffer
}

// getBuffer returns a new, ready-to-use buffer.
func (l *Logger) getBuffer() *buffer {
	l.freeListMu.Lock()
	b := l.freeList
	if b != nil {
		l.freeList = b.next
	}
	l.freeListMu.Unlock()
	if b == nil {
		b = new(buffer)
	} else {
		b.next = nil
		b.Reset()
	}
	return b
}

// putBuffer returns a buffer to the free list.
func (l *Logger) putBuffer(b *buffer) {
	if b.Len() >= 256 {
		// Let big buffers die a natural death.
		return
	}
	l.freeListMu.Lock()
	b.next = l.freeList
	l.freeList = b
	l.freeListMu.Unlock()
}

var timeNow = time.Now // Stubbed out for testing.

/*
header formats a log header as defined by the C++ implementation.
It returns a buffer containing the formatted header and the user's file and line number.
The depth specifies how many stack frames above lives the source line to be identified in the log message.

Log lines have this form:
	Lmmdd hh:mm:ss.uuuuuu threadid file:line] msg...
where the fields are defined as follows:
	L                A single character, representing the log level (eg 'I' for INFO)
	mm               The month (zero padded; ie May is '05')
	dd               The day (zero padded)
	hh:mm:ss.uuuuuu  Time in hours, minutes and fractional seconds
	threadid         The space-padded thread ID as returned by GetTID()
	file             The file name
	line             The line number
	msg              The user-supplied message
*/
func (l *Logger) header(s severity, depth int) (*buffer, string, int) {
	_, file, line, ok := runtime.Caller(3 + depth)
	if !ok {
		file = "???"
		line = 1
	} else {
		slash := strings.LastIndex(file, "/")
		if slash >= 0 {
			file = file[slash+1:]
		}
	}
	return l.formatHeader(s, file, line), file, line
}

// formatHeader formats a log header using the provided file name and line number.
func (l *Logger) formatHeader(s severity, file string, line int) *buffer {
	now := timeNow()
	if line < 0 {
		line = 0 // not a real line number, but acceptable to someDigits
	}
	if s > fatalLog {
		s = infoLog // for safety.
	}
	buf := l.getBuffer()

	// Avoid Fprintf, for speed. The format is so simple that we can do it quickly by hand.
	// It's worth about 3X. Fprintf is hard.
	_, month, day := now.Date()
	hour, minute, second := now.Clock()
	// Lmmdd hh:mm:ss.uuuuuu threadid file:line]
	buf.tmp[0] = severityChar[s]
	buf.twoDigits(1, int(month))
	buf.twoDigits(3, day)
	buf.tmp[5] = ' '
	buf.twoDigits(6, hour)
	buf.tmp[8] = ':'
	buf.twoDigits(9, minute)
	buf.tmp[11] = ':'
	buf.twoDigits(12, second)
	buf.tmp[14] = '.'
	buf.nDigits(6, 15, now.Nanosecond()/1000, '0')
	buf.tmp[21] = ' '
	buf.nDigits(7, 22, pid, ' ') // TODO: should be TID
	buf.tmp[29] = ' '
	buf.Write(buf.tmp[:30])
	buf.WriteString(file)
	buf.tmp[0] = ':'
	n := buf.someDigits(1, line)
	buf.tmp[n+1] = ']'
	buf.tmp[n+2] = ' '
	buf.Write(buf.tmp[:n+3])
	return buf
}

// Some custom tiny helper functions to print the log header efficiently.

const digits = "0123456789"

// twoDigits formats a zero-prefixed two-digit integer at buf.tmp[i].
func (buf *buffer) twoDigits(i, d int) {
	buf.tmp[i+1] = digits[d%10]
	d /= 10
	buf.tmp[i] = digits[d%10]
}

// nDigits formats an n-digit integer at buf.tmp[i],
// padding with pad on the left.
// It assumes d >= 0.
func (buf *buffer) nDigits(n, i, d int, pad byte) {
	j := n - 1
	for ; j >= 0 && d > 0; j-- {
		buf.tmp[i+j] = digits[d%10]
		d /= 10
	}
	for ; j >= 0; j-- {
		buf.tmp[i+j] = pad
	}
}

// someDigits formats a zero-prefixed variable-width integer at buf.tmp[i].
func (buf *buffer) someDigits(i, d int) int {
	// Print into the top, then copy down. We know there's space for at least
	// a 10-digit number.
	j := len(buf.tmp)
	for {
		j--
		buf.tmp[j] = digits[d%10]
		d /= 10
		if d == 0 {
			break
		}
	}
	return copy(buf.tmp[i:], buf.tmp[j:])
}

func (l *Logger) print(s severity, args ...interface{}) {
	l.printDepth(s, 1, args...)
}

func (l *Logger) printDepth(s severity, depth int, args ...interface{}) {
	buf, file, line := l.header(s, depth)
	fmt.Fprint(buf, args...)
	if buf.Bytes()[buf.Len()-1] != '\n' {
		buf.WriteByte('\n')
	}
	l.output(s, buf, file, line)
}

func (l *Logger) printf(s severity, format string, args ...interface{}) {
	buf, file, line := l.header(s, 0)
	fmt.Fprintf(buf, format, args...)
	if buf.Bytes()[buf.Len()-1] != '\n' {
		buf.WriteByte('\n')
	}
	l.output(s, buf, file, line)
}

// output writes the data to the log files and releases the buffer.
func (l *Logger) output(s severity, buf *buffer, file string, line int) {
	data := buf.Bytes()
	l.w.Write(data)
	if s == fatalLog {
		// Write the stack trace for all goroutines to the files.
		trace := stacks(true)
		l.w.Write(trace)
		l.w.Sync()
		os.Exit(255) // C++ uses -1, which is silly because it's anded with 255 anyway.
	}
}

// stacks is a wrapper for runtime.Stack that attempts to recover the data for all goroutines.
func stacks(all bool) []byte {
	// We don't know how big the traces are, so grow a few times if they don't fit. Start large, though.
	n := 10000
	if all {
		n = 100000
	}
	var trace []byte
	for i := 0; i < 5; i++ {
		trace = make([]byte, n)
		nbytes := runtime.Stack(trace, all)
		if nbytes < len(trace) {
			return trace[:nbytes]
		}
		n *= 2
	}
	return trace
}

func (l *Logger) Info(args ...interface{}) {
	l.print(infoLog, args...)
}

func (l *Logger) Infof(format string, args ...interface{}) {
	l.printf(infoLog, format, args...)
}

func (l *Logger) Warning(args ...interface{}) {
	l.print(warningLog, args...)
}

func (l *Logger) Warningf(format string, args ...interface{}) {
	l.printf(warningLog, format, args...)
}

func (l *Logger) Error(args ...interface{}) {
	l.print(errorLog, args...)
}

func (l *Logger) Errorf(format string, args ...interface{}) {
	l.printf(errorLog, format, args...)
}

func (l *Logger) Fatal(args ...interface{}) {
	l.print(fatalLog, args...)
}

func (l *Logger) Fatalf(format string, args ...interface{}) {
	l.printf(fatalLog, format, args...)
}

func (l *Logger) Raw(s string) {
	l.w.Write([]byte(s))
	if s[len(s)-1] != '\n' {
		l.w.Write([]byte{'\n'})
	}
}

// SetOutput changes where the logs are written to. By default
// the value is os.Stdout.
func (l *Logger) SetOutput(w SyncWriter) {
	l.w = w
}

var _ slog.Logger = (*Logger)(nil)
<|endoftext|>


<commit_before>package logger

import (
	"fmt"

	"github.com/getsentry/raven-go"
	"github.com/mgutz/logxi/v1"
	"io"
	"os"
)

// UnaLogger wraps a logxi logger
// and delegate to some of it's logging methods
type UnaLogger interface {
	Debug(msg string, args ...interface{})
	Info(msg string, args ...interface{})
	Error(msg string, err error, args ...interface{})
	Underlying() log.Logger
	PassToSentry()
}

type unaLogger struct {
	Logger log.Logger
	passToSentry bool
	name string
}

type Config struct {
	Name string
	FileName string
}

// NewLogger creates a new logger with the given name
func NewLogger(conf Config) UnaLogger {
	// These configurations are made to make the
	// log payload compatible with the LogEntry format used in Google Cloud Logging
	// https://cloud.google.com/logging/docs/reference/v2/rest/v2/LogEntry
	log.KeyMap.Level = "severity"
	log.KeyMap.Message = "message"
	log.KeyMap.Time = "timestamp"
	log.LevelMap[log.LevelError] = "ERROR"
	log.LevelMap[log.LevelInfo] = "INFO"
	log.LevelMap[log.LevelDebug] = "DEBUG"

	logxiLogger := log.New(conf.Name)
	if conf.FileName != "" {
		if file, err := os.Create(conf.FileName); err == nil {
			logxiLogger = log.NewLogger(file, conf.Name)
		}
	}

	return &unaLogger{
		Logger: logxiLogger,
		name: conf.Name,
	}
}

// NewLogger creates a new logger with the given name
// and that passes errors to Sentry
func NewSentryLogger(conf Config) UnaLogger {
	l := NewLogger(conf)
	l.PassToSentry()
	return l
}

// SetWriter overrides the io.Writer of the underlying logxi logger
func (ul *unaLogger) SetWriter(writer io.Writer)  {
	ul.Logger = log.NewLogger(writer, ul.name)
}

// PassToSentry indicates whether the Error function
// should pass errors on to Sentry or not
func (ul *unaLogger) PassToSentry() {
	ul.passToSentry = true
}

// Underlying returns the underlying logxi logger
func (ul unaLogger) Underlying() log.Logger {
	return ul.Logger
}

// Info logs to Stdout with an "INFO" prefix
func (ul unaLogger) Info(msg string, args ...interface{}) {
	ul.Logger.Info(msg, args...)
}

// Debug logs to Stdout with an "DEBUG" prefix if Debug level is enabled
func (ul unaLogger) Debug(msg string, args ...interface{}) {
	if ul.Logger.IsDebug() {
		ul.Logger.Debug(msg, args...)
	}
}

// Error logs to Stdout with an "Error" prefix
// It also adds an "error" key to the provided err(error) argument
// If
func (ul unaLogger) Error(msg string, err error, args ...interface{}) {
	tags := make(map[string]string)
	for i := 0; i < len(args); i += 2 {
		tags[args[i].(string)] = fmt.Sprintf("%v", args[i+1])
	}
	e := ul.Logger.Error(msg, "error", err, "labels", tags)

	if ul.passToSentry {
		raven.SetDefaultLoggerName(ul.name)
		raven.CaptureError(e, tags)
	}
}
<commit_msg>Convenience func with just a string name<commit_after>package logger

import (
	"fmt"

	"io"
	"os"

	"github.com/getsentry/raven-go"
	"github.com/mgutz/logxi/v1"
)

// UnaLogger wraps a logxi logger
// and delegate to some of it's logging methods
type UnaLogger interface {
	Debug(msg string, args ...interface{})
	Info(msg string, args ...interface{})
	Error(msg string, err error, args ...interface{})
	Underlying() log.Logger
	PassToSentry()
}

type unaLogger struct {
	Logger       log.Logger
	passToSentry bool
	name         string
}

type Config struct {
	Name     string
	FileName string
}

// NewLogger creates a new logger with the given (string) name
func New(name string) UnaLogger {
	return NewLogger(Config{Name: name})
}

// NewLogger creates a new logger with the given (Config) name
func NewLogger(conf Config) UnaLogger {
	// These configurations are made to make the
	// log payload compatible with the LogEntry format used in Google Cloud Logging
	// https://cloud.google.com/logging/docs/reference/v2/rest/v2/LogEntry
	log.KeyMap.Level = "severity"
	log.KeyMap.Message = "message"
	log.KeyMap.Time = "timestamp"
	log.LevelMap[log.LevelError] = "ERROR"
	log.LevelMap[log.LevelInfo] = "INFO"
	log.LevelMap[log.LevelDebug] = "DEBUG"

	logxiLogger := log.New(conf.Name)
	if conf.FileName != "" {
		if file, err := os.Create(conf.FileName); err == nil {
			logxiLogger = log.NewLogger(file, conf.Name)
		}
	}

	return &unaLogger{
		Logger: logxiLogger,
		name:   conf.Name,
	}
}

// NewLogger creates a new logger with the given name
// and that passes errors to Sentry
func NewSentryLogger(conf Config) UnaLogger {
	l := NewLogger(conf)
	l.PassToSentry()
	return l
}

// SetWriter overrides the io.Writer of the underlying logxi logger
func (ul *unaLogger) SetWriter(writer io.Writer) {
	ul.Logger = log.NewLogger(writer, ul.name)
}

// PassToSentry indicates whether the Error function
// should pass errors on to Sentry or not
func (ul *unaLogger) PassToSentry() {
	ul.passToSentry = true
}

// Underlying returns the underlying logxi logger
func (ul unaLogger) Underlying() log.Logger {
	return ul.Logger
}

// Info logs to Stdout with an "INFO" prefix
func (ul unaLogger) Info(msg string, args ...interface{}) {
	ul.Logger.Info(msg, args...)
}

// Debug logs to Stdout with an "DEBUG" prefix if Debug level is enabled
func (ul unaLogger) Debug(msg string, args ...interface{}) {
	if ul.Logger.IsDebug() {
		ul.Logger.Debug(msg, args...)
	}
}

// Error logs to Stdout with an "Error" prefix
// It also adds an "error" key to the provided err(error) argument
// If
func (ul unaLogger) Error(msg string, err error, args ...interface{}) {
	tags := make(map[string]string)
	for i := 0; i < len(args); i += 2 {
		tags[args[i].(string)] = fmt.Sprintf("%v", args[i+1])
	}
	e := ul.Logger.Error(msg, "error", err, "labels", tags)

	if ul.passToSentry {
		raven.SetDefaultLoggerName(ul.name)
		raven.CaptureError(e, tags)
	}
}
<|endoftext|>


<commit_before>// Package name declaration
package logger

// Import packages
import (
	"bytes"
	"fmt"
	"io"
	"log"
	"os"
	"path"
	"runtime"
	"sync/atomic"
	"time"
)

var (
	// Map for te various codes of colors
	colors map[string]string

	// Contains color strings for stdout
	logNo uint64
)

// Color numbers for stdout
const (
	Black = (iota + 30)
	Red
	Green
	Yellow
	Blue
	Magenta
	Cyan
	White
)

// Worker class, Worker is a log object used to log messages and Color specifies
// if colored output is to be produced
type Worker struct {
	Minion *log.Logger
	Color  int
}

// Info class, Contains all the info on what has to logged, time is the current time, Module is the specific module
// For which we are logging, level is the state, importance and type of message logged,
// Message contains the string to be logged, format is the format of string to be passed to sprintf
type Info struct {
	Id       uint64
	Time     string
	Module   string
	Level    string
	Line     int
	Filename string
	Message  string
	format   string
}

// Logger class that is an interface to user to log messages, Module is the module for which we are testing
// worker is variable of Worker class that is used in bottom layers to log the message
type Logger struct {
	Module string
	worker *Worker
}

// Returns a proper string to be outputted for a particular info
func (r *Info) Output() string {
	msg := fmt.Sprintf(r.format, r.Id, r.Time, r.Filename, r.Line, r.Level, r.Message)
	return msg
}

// Returns an instance of worker class, prefix is the string attached to every log,
// flag determine the log params, color parameters verifies whether we need colored outputs or not
func NewWorker(prefix string, flag int, color int, out io.Writer) *Worker {
	return &Worker{Minion: log.New(out, prefix, flag), Color: color}
}

// Function of Worker class to log a string based on level
func (w *Worker) Log(level string, calldepth int, info *Info) error {
	if w.Color != 0 {
		buf := &bytes.Buffer{}
		buf.Write([]byte(colors[level]))
		buf.Write([]byte(info.Output()))
		buf.Write([]byte("\033[0m"))
		return w.Minion.Output(calldepth+1, buf.String())
	} else {
		return w.Minion.Output(calldepth+1, info.Output())
	}
}

// Returns a proper string to output for colored logging
func colorString(color int) string {
	return fmt.Sprintf("\033[%dm", int(color))
}

// Initializes the map of colors
func initColors() {
	colors = map[string]string{
		"CRITICAL": colorString(Magenta),
		"ERROR":    colorString(Red),
		"WARNING":  colorString(Yellow),
		"NOTICE":   colorString(Green),
		"DEBUG":    colorString(Cyan),
		"INFO":     colorString(White),
	}
}

// Returns a new instance of logger class, module is the specific module for which we are logging
// , color defines whether the output is to be colored or not, out is instance of type io.Writer defaults
// to os.Stderr
func New(args ...interface{}) (*Logger, error) {
	initColors()

	var module string = "DEFAULT"
	var color int = 1
	var out io.Writer = os.Stderr

	for _, arg := range args {
		switch t := arg.(type) {
		case string:
			module = t
		case int:
			color = t
		case io.Writer:
			out = t
		default:
			panic("logger: Unknown argument")
		}
	}
	newWorker := NewWorker("", 0, color, out)
	return &Logger{Module: module, worker: newWorker}, nil
}

// The log commnand is the function available to user to log message, lvl specifies
// the degree of the messagethe user wants to log, message is the info user wants to log
func (l *Logger) Log(lvl string, message string) {
	l.log_internal(lvl, message, 2)
}

func (l *Logger) log_internal(lvl string, message string, pos int) {
	var formatString string = "#%d %s %s:%d ▶ %.3s %s"
	_, filename, line, _ := runtime.Caller(pos)
	filename = path.Base(filename)
	info := &Info{
		Id:       atomic.AddUint64(&logNo, 1),
		Time:     time.Now().Format("2006-01-02 15:04:05"),
		Module:   l.Module,
		Level:    lvl,
		Message:  message,
		Filename: filename,
		Line:     line,
		format:   formatString,
	}
	l.worker.Log(lvl, 2, info)
}

// Fatal is just like func l,Cr.tical logger except that it is followed by exit to program
func (l *Logger) Fatal(message string) {
	l.log_internal("CRITICAL", message, 2)
	os.Exit(1)
}

// Panic is just like func l.Critical except that it is followed by a call to panic
func (l *Logger) Panic(message string) {
	l.log_internal("CRITICAL", message, 2)
	panic(message)
}

// Critical logs a message at a Critical Level
func (l *Logger) Critical(message string) {
	l.log_internal("CRITICAL", message, 2)
}

// Error logs a message at Error level
func (l *Logger) Error(message string) {
	l.log_internal("ERROR", message, 2)
}

// Warning logs a message at Warning level
func (l *Logger) Warning(message string) {
	l.log_internal("WARNING", message, 2)
}

// Notice logs a message at Notice level
func (l *Logger) Notice(message string) {
	l.log_internal("NOTICE", message, 2)
}

// Info logs a message at Info level
func (l *Logger) Info(message string) {
	l.log_internal("INFO", message, 2)
}

// Debug logs a message at Debug level
func (l *Logger) Debug(message string) {
	l.log_internal("DEBUG", message, 2)
}
<commit_msg>Added functions for printing the stack to the log.<commit_after>// Package name declaration
package logger

// Import packages
import (
	"bytes"
	"fmt"
	"io"
	"log"
	"os"
	"path"
	"runtime"
	"sync/atomic"
	"time"
)

var (
	// Map for te various codes of colors
	colors map[string]string

	// Contains color strings for stdout
	logNo uint64
)

// Color numbers for stdout
const (
	Black = (iota + 30)
	Red
	Green
	Yellow
	Blue
	Magenta
	Cyan
	White
)

// Worker class, Worker is a log object used to log messages and Color specifies
// if colored output is to be produced
type Worker struct {
	Minion *log.Logger
	Color  int
}

// Info class, Contains all the info on what has to logged, time is the current time, Module is the specific module
// For which we are logging, level is the state, importance and type of message logged,
// Message contains the string to be logged, format is the format of string to be passed to sprintf
type Info struct {
	Id       uint64
	Time     string
	Module   string
	Level    string
	Line     int
	Filename string
	Message  string
	format   string
}

// Logger class that is an interface to user to log messages, Module is the module for which we are testing
// worker is variable of Worker class that is used in bottom layers to log the message
type Logger struct {
	Module string
	worker *Worker
}

// Returns a proper string to be outputted for a particular info
func (r *Info) Output() string {
	msg := fmt.Sprintf(r.format, r.Id, r.Time, r.Filename, r.Line, r.Level, r.Message)
	return msg
}

// Returns an instance of worker class, prefix is the string attached to every log,
// flag determine the log params, color parameters verifies whether we need colored outputs or not
func NewWorker(prefix string, flag int, color int, out io.Writer) *Worker {
	return &Worker{Minion: log.New(out, prefix, flag), Color: color}
}

// Function of Worker class to log a string based on level
func (w *Worker) Log(level string, calldepth int, info *Info) error {
	if w.Color != 0 {
		buf := &bytes.Buffer{}
		buf.Write([]byte(colors[level]))
		buf.Write([]byte(info.Output()))
		buf.Write([]byte("\033[0m"))
		return w.Minion.Output(calldepth+1, buf.String())
	} else {
		return w.Minion.Output(calldepth+1, info.Output())
	}
}

// Returns a proper string to output for colored logging
func colorString(color int) string {
	return fmt.Sprintf("\033[%dm", int(color))
}

// Initializes the map of colors
func initColors() {
	colors = map[string]string{
		"CRITICAL": colorString(Magenta),
		"ERROR":    colorString(Red),
		"WARNING":  colorString(Yellow),
		"NOTICE":   colorString(Green),
		"DEBUG":    colorString(Cyan),
		"INFO":     colorString(White),
	}
}

// Returns a new instance of logger class, module is the specific module for which we are logging
// , color defines whether the output is to be colored or not, out is instance of type io.Writer defaults
// to os.Stderr
func New(args ...interface{}) (*Logger, error) {
	initColors()

	var module string = "DEFAULT"
	var color int = 1
	var out io.Writer = os.Stderr

	for _, arg := range args {
		switch t := arg.(type) {
		case string:
			module = t
		case int:
			color = t
		case io.Writer:
			out = t
		default:
			panic("logger: Unknown argument")
		}
	}
	newWorker := NewWorker("", 0, color, out)
	return &Logger{Module: module, worker: newWorker}, nil
}

// The log commnand is the function available to user to log message, lvl specifies
// the degree of the messagethe user wants to log, message is the info user wants to log
func (l *Logger) Log(lvl string, message string) {
	l.log_internal(lvl, message, 2)
}

func (l *Logger) log_internal(lvl string, message string, pos int) {
	var formatString string = "#%d %s %s:%d ▶ %.3s %s"
	_, filename, line, _ := runtime.Caller(pos)
	filename = path.Base(filename)
	info := &Info{
		Id:       atomic.AddUint64(&logNo, 1),
		Time:     time.Now().Format("2006-01-02 15:04:05"),
		Module:   l.Module,
		Level:    lvl,
		Message:  message,
		Filename: filename,
		Line:     line,
		format:   formatString,
	}
	l.worker.Log(lvl, 2, info)
}

// Fatal is just like func l,Cr.tical logger except that it is followed by exit to program
func (l *Logger) Fatal(message string) {
	l.log_internal("CRITICAL", message, 2)
	os.Exit(1)
}

// Panic is just like func l.Critical except that it is followed by a call to panic
func (l *Logger) Panic(message string) {
	l.log_internal("CRITICAL", message, 2)
	panic(message)
}

// Critical logs a message at a Critical Level
func (l *Logger) Critical(message string) {
	l.log_internal("CRITICAL", message, 2)
}

// Error logs a message at Error level
func (l *Logger) Error(message string) {
	l.log_internal("ERROR", message, 2)
}

// Warning logs a message at Warning level
func (l *Logger) Warning(message string) {
	l.log_internal("WARNING", message, 2)
}

// Notice logs a message at Notice level
func (l *Logger) Notice(message string) {
	l.log_internal("NOTICE", message, 2)
}

// Info logs a message at Info level
func (l *Logger) Info(message string) {
	l.log_internal("INFO", message, 2)
}

// Debug logs a message at Debug level
func (l *Logger) Debug(message string) {
	l.log_internal("DEBUG", message, 2)
}

func (l *Logger) StackAsError(message string) {
	if message == "" {
		message = "Stack info"
	}
	message += "\n"
	l.log_internal("ERROR", message+Stack(), 2)
}

// Returns a string with the execution stack for this goroutine
func Stack() string {
	buf := make([]byte, 1000000)
	runtime.Stack(buf, false)
	return string(buf)
}<|endoftext|>


<commit_before>package arangolite

import (
	"bytes"
	"encoding/json"
	"log"
	"os"
	"time"
)

type logger struct {
	log.Logger
}

func newLogger(enabled bool) *logger {
	var out *os.File

	if enabled {
		out = os.Stdout
	}

	return &logger{*log.New(out, "\n[Arangolite] ", 0)}
}

func (l *logger) logBegin(msg, url string, jsonQuery []byte) {
	l.Printf("%s %s %s | URL: %s\n    %s", blue, msg, reset, url, indentJSON(jsonQuery))
}

func (l *logger) logResult(result *result, start time.Time, in, out chan interface{}) {
	batchNb := 0

	for {
		tmp := <-in
		out <- tmp

		switch tmp.(type) {
		case json.RawMessage:
			batchNb++
			continue
		}
		break
	}

	execTime := time.Now().Sub(start)
	content := string(indentJSON([]byte(result.Content)))
	if len(content) > 5000 {
		content = content[0:5000] + "\n\n    Result has been truncated to 5000 characters"
	}

	if result.Cached {
		l.Printf("%s RESULT %s | %s CACHED %s | Execution: %v | Batches: %d\n    %s",
			blue, reset, yellow, reset, execTime, batchNb, content)
	} else {
		l.Printf("%s RESULT %s | Execution: %v | Batches: %d\n    %s",
			blue, reset, execTime, batchNb, content)
	}
}

func (l *logger) logError(errMsg string, execTime time.Duration) {
	l.Printf("%s RESULT %s | Execution: %v\n    ERROR: %s",
		blue, reset, execTime, errMsg)
}

var (
	green   = string([]byte{27, 91, 57, 55, 59, 52, 50, 109})
	white   = string([]byte{27, 91, 57, 48, 59, 52, 55, 109})
	yellow  = string([]byte{27, 91, 57, 55, 59, 52, 51, 109})
	red     = string([]byte{27, 91, 57, 55, 59, 52, 49, 109})
	blue    = string([]byte{27, 91, 57, 55, 59, 52, 52, 109})
	magenta = string([]byte{27, 91, 57, 55, 59, 52, 53, 109})
	cyan    = string([]byte{27, 91, 57, 55, 59, 52, 54, 109})
	reset   = string([]byte{27, 91, 48, 109})
)

func indentJSON(in []byte) []byte {
	b := &bytes.Buffer{}
	_ = json.Indent(b, in, "    ", "  ")

	return b.Bytes()
}
<commit_msg>Logger refactored.<commit_after>package arangolite

import (
	"bytes"
	"encoding/json"
	"log"
	"os"
	"time"
)

type logger struct {
	log.Logger
	printQuery  bool
	printResult bool
}

func newLogger() *logger {
	l := &logger{}
	l.Logger = *log.New(os.Stdout, "", 0)
	l.printQuery = true
	l.printResult = true

	return l
}

func (l *logger) Enabled(enabled bool) *logger {
	var out *os.File

	if enabled {
		out = os.Stdout
	}

	l.Logger = *log.New(out, "", 0)

	return l
}

func (l *logger) PrintQuery(enabled bool) *logger {
	l.printQuery = enabled
	return l
}

func (l *logger) PrintResult(enabled bool) *logger {
	l.printResult = enabled
	return l
}

func (l *logger) LogBegin(msg, url string, jsonQuery []byte) {
	l.Printf("\n[Arangolite] %s %s %s | URL: %s", blue, msg, reset, url)

	if l.printQuery {
		l.Println("    " + string(indentJSON(jsonQuery)))
	}
}

func (l *logger) LogResult(result *result, start time.Time, in, out chan interface{}) {
	batchNb := 0

	for {
		tmp := <-in
		out <- tmp

		switch tmp.(type) {
		case json.RawMessage:
			batchNb++
			continue
		}
		break
	}

	execTime := time.Now().Sub(start)

	if result.Cached {
		l.Printf("\n[Arangolite] %s RESULT %s | %s CACHED %s | Execution: %v | Batches: %d",
			blue, reset, yellow, reset, execTime, batchNb)
	} else {
		l.Printf("\n[Arangolite] %s RESULT %s | Execution: %v | Batches: %d",
			blue, reset, execTime, batchNb)
	}

	if l.printResult {
		content := "    " + string(indentJSON([]byte(result.Content)))
		if batchNb > 1 {
			content += "\n\n    Result has been truncated to the first batch"
		}
		l.Println(content)
	}
}

func (l *logger) LogError(errMsg string, execTime time.Duration) {
	l.Printf("\n[Arangolite] %s RESULT %s | Execution: %v\n    ERROR: %s",
		blue, reset, execTime, errMsg)
}

var (
	green   = string([]byte{27, 91, 57, 55, 59, 52, 50, 109})
	white   = string([]byte{27, 91, 57, 48, 59, 52, 55, 109})
	yellow  = string([]byte{27, 91, 57, 55, 59, 52, 51, 109})
	red     = string([]byte{27, 91, 57, 55, 59, 52, 49, 109})
	blue    = string([]byte{27, 91, 57, 55, 59, 52, 52, 109})
	magenta = string([]byte{27, 91, 57, 55, 59, 52, 53, 109})
	cyan    = string([]byte{27, 91, 57, 55, 59, 52, 54, 109})
	reset   = string([]byte{27, 91, 48, 109})
)

func indentJSON(in []byte) []byte {
	b := &bytes.Buffer{}
	_ = json.Indent(b, in, "    ", "  ")

	return b.Bytes()
}
<|endoftext|>


<commit_before>package espsdk

import (
	"encoding/json"
	"time"

	log "github.com/Sirupsen/logrus"
)

// A Batch is a container for Contributions of the same type and
// any Releases that may be associated with them.
type Batch struct {
	AssignmentID                     string     `json:"assignment_id,omitempty"`
	BatchTags                        []string   `json:"batch_tags,omitempty"`
	BriefID                          string     `json:"brief_id,omitempty"`
	ContributionsAwaitingReviewCount int        `json:"contributions_awaiting_review_count,omitempty"`
	ContributionsCount               int        `json:"contributions_count,omitempty"`
	CreatedAt                        *time.Time `json:"created_at,omitempty"`
	CreatedBy                        string     `json:"created_by,omitempty"`
	CreatorIstockUsername            string     `json:"creator_istock_username,omitempty"`
	EventID                          string     `json:"event_id,omitempty"`
	ID                               int        `json:"id,omitempty"`
	IsGetty                          bool       `json:"is_getty,omitempty"`
	IsIstock                         bool       `json:"is_istock,omitempty"`
	IstockExclusive                  bool       `json:"istock_exclusive,omitempty"`
	LastContributionSubmittedAt      *time.Time `json:"last_contribution_submitted_at,omitempty"`
	LastSubmittedAt                  *time.Time `json:"last_submitted_at,omitempty"`
	Note                             string     `json:"note,omitempty"`
	ProfileID                        int        `json:"profile_id,omitempty"`
	ReviewedContributionsCount       int        `json:"reviewed_contributions_count,omitempty"`
	RevisableContributionsCount      int        `json:"revisable_contributions_count,omitempty"`
	SaveExtractedMetadata            bool       `json:"save_extracted_metadata,omitempty"`
	Status                           string     `json:"status,omitempty"`
	SubmissionName                   string     `json:"submission_name,omitempty"`
	SubmissionType                   string     `json:"submission_type,omitempty"`
	SubmittedContributionsCount      int        `json:"submitted_contributions_count,omitempty"`
	UpdatedAt                        *time.Time `json:"updated_at,omitempty"`
	UserID                           string     `json:"user_id,omitempty"`
}

// Marshal serializes a Batch into a byte slice.
func (b Batch) Marshal() ([]byte, error) { return indentedJSON(b) }

// Get requests the metadata for a specific Submission Batch.
func (b Batch) Get(client *Client) Batch { return b.Unmarshal(client.get(BatchPath(&b))) }

// Delete destroys a specific Submission Batch.
func (b Batch) Delete(client *Client) { client._delete(BatchPath(&b)) }

// NameIsValid provides validation for a proposed SubmissionName.
func (b Batch) NameIsValid() bool { return len(b.SubmissionName) > 0 }

// TypeIsValid reports whether a proposed type is valid for ESP.
func (b *Batch) TypeIsValid() bool { return batchTypeIsValid[b.SubmissionType] }

// ValidTypes are the BatchTypes supported by ESP.
func (b Batch) ValidTypes() []string {
	keys := make([]string, len(batchTypeIsValid))
	i := 0
	for k := range batchTypeIsValid {
		keys[i] = k
		i++
	}
	return keys
}

// Unmarshal attempts to deserialize the provided JSON payload
// into a Batch object.
func (b Batch) Unmarshal(payload []byte) Batch {
	var batch Batch
	if err := json.Unmarshal(payload, &batch); err != nil {
		log.Fatal(err)
	}
	return batch
}

// PrettyPrint returns a human-readable serialized JSON representation of
// the provided object.
func (b Batch) PrettyPrint() string { return prettyPrint(b) }

// A BatchUpdate contains a Batch. This matches the
// structure of the JSON payload the API expects during a PUT.
type BatchUpdate struct {
	Batch Batch `json:"submission_batch"`
}

// Marshal serializes a BatchUpdate into a byte slice.
func (s BatchUpdate) Marshal() ([]byte, error) { return indentedJSON(s) }

var batchTypeIsValid = map[string]bool{
	"getty_creative_video":  true,
	"getty_editorial_video": true,
	"getty_creative_still":  true,
	"getty_editorial_still": true,
	"istock_creative_video": true,
}

// A BatchList is a slice of zero or more Batches.
type BatchList []Batch

// Marshal serializes a BatchList into a byte slice.
func (bl BatchList) Marshal() ([]byte, error) { return indentedJSON(bl) }

func (bl BatchList) unmarshal(payload []byte) BatchList {
	var batchList BatchList
	if err := json.Unmarshal(payload, &batchList); err != nil {
		log.Fatal(err)
	}
	return batchList
}

func (bl BatchList) prettyPrint() string { return prettyPrint(bl) }

// A BatchListContainer matches the structure of the JSON payload returned
// by the GET (all) Batches API endpoint.
type BatchListContainer struct {
	Items BatchList `json:"items"`
	Meta  struct {
		TotalItems int `json:"total_items"`
	} `json:"meta"`
}

// Marshal serializes a BatchListContainer into a byte slice.
func (blc BatchListContainer) Marshal() ([]byte, error) { return indentedJSON(blc) }

// Unmarshal attempts to deserialize the provided JSON payload
// into the complete metadata returned by a request to the Index (GET all)
// API endpoint.
func (blc BatchListContainer) Unmarshal(payload []byte) BatchListContainer {
	var batchListContainer BatchListContainer
	if err := json.Unmarshal(payload, &batchListContainer); err != nil {
		log.Fatal(err)
	}
	return batchListContainer
}

// PrettyPrint returns a human-readable serialized JSON representation of
// the provided object.
func (blc BatchListContainer) PrettyPrint() string { return prettyPrint(blc) }
<commit_msg>move batch PUT to SDK<commit_after>package espsdk

import (
	"encoding/json"
	"time"

	log "github.com/Sirupsen/logrus"
)

// A Batch is a container for Contributions of the same type and
// any Releases that may be associated with them.
type Batch struct {
	AssignmentID                     string     `json:"assignment_id,omitempty"`
	BatchTags                        []string   `json:"batch_tags,omitempty"`
	BriefID                          string     `json:"brief_id,omitempty"`
	ContributionsAwaitingReviewCount int        `json:"contributions_awaiting_review_count,omitempty"`
	ContributionsCount               int        `json:"contributions_count,omitempty"`
	CreatedAt                        *time.Time `json:"created_at,omitempty"`
	CreatedBy                        string     `json:"created_by,omitempty"`
	CreatorIstockUsername            string     `json:"creator_istock_username,omitempty"`
	EventID                          string     `json:"event_id,omitempty"`
	ID                               int        `json:"id,omitempty"`
	IsGetty                          bool       `json:"is_getty,omitempty"`
	IsIstock                         bool       `json:"is_istock,omitempty"`
	IstockExclusive                  bool       `json:"istock_exclusive,omitempty"`
	LastContributionSubmittedAt      *time.Time `json:"last_contribution_submitted_at,omitempty"`
	LastSubmittedAt                  *time.Time `json:"last_submitted_at,omitempty"`
	Note                             string     `json:"note,omitempty"`
	ProfileID                        int        `json:"profile_id,omitempty"`
	ReviewedContributionsCount       int        `json:"reviewed_contributions_count,omitempty"`
	RevisableContributionsCount      int        `json:"revisable_contributions_count,omitempty"`
	SaveExtractedMetadata            bool       `json:"save_extracted_metadata,omitempty"`
	Status                           string     `json:"status,omitempty"`
	SubmissionName                   string     `json:"submission_name,omitempty"`
	SubmissionType                   string     `json:"submission_type,omitempty"`
	SubmittedContributionsCount      int        `json:"submitted_contributions_count,omitempty"`
	UpdatedAt                        *time.Time `json:"updated_at,omitempty"`
	UserID                           string     `json:"user_id,omitempty"`
}

// Marshal serializes a Batch into a byte slice.
func (b Batch) Marshal() ([]byte, error) { return indentedJSON(b) }

// Get requests the metadata for a specific Submission Batch.
func (b Batch) Get(client *Client) Batch { return b.Unmarshal(client.get(BatchPath(&b))) }

// Update changes metadata for an existing Batch.
func (b Batch) Update(client *Client, updatedData BatchUpdate) Batch {
	return b.Unmarshal(client.put(updatedData, BatchPath(&b)))
}

// Delete destroys a specific Submission Batch.
func (b Batch) Delete(client *Client) { client._delete(BatchPath(&b)) }

// NameIsValid provides validation for a proposed SubmissionName.
func (b Batch) NameIsValid() bool { return len(b.SubmissionName) > 0 }

// TypeIsValid reports whether a proposed type is valid for ESP.
func (b *Batch) TypeIsValid() bool { return batchTypeIsValid[b.SubmissionType] }

// ValidTypes are the BatchTypes supported by ESP.
func (b Batch) ValidTypes() []string {
	keys := make([]string, len(batchTypeIsValid))
	i := 0
	for k := range batchTypeIsValid {
		keys[i] = k
		i++
	}
	return keys
}

// Unmarshal attempts to deserialize the provided JSON payload
// into a Batch object.
func (b Batch) Unmarshal(payload []byte) Batch {
	var batch Batch
	if err := json.Unmarshal(payload, &batch); err != nil {
		log.Fatal(err)
	}
	return batch
}

// PrettyPrint returns a human-readable serialized JSON representation of
// the provided object.
func (b Batch) PrettyPrint() string { return prettyPrint(b) }

// A BatchUpdate contains a Batch. This matches the
// structure of the JSON payload the API expects during a PUT.
type BatchUpdate struct {
	Batch Batch `json:"submission_batch"`
}

// Marshal serializes a BatchUpdate into a byte slice.
func (s BatchUpdate) Marshal() ([]byte, error) { return indentedJSON(s) }

var batchTypeIsValid = map[string]bool{
	"getty_creative_video":  true,
	"getty_editorial_video": true,
	"getty_creative_still":  true,
	"getty_editorial_still": true,
	"istock_creative_video": true,
}

// A BatchList is a slice of zero or more Batches.
type BatchList []Batch

// Marshal serializes a BatchList into a byte slice.
func (bl BatchList) Marshal() ([]byte, error) { return indentedJSON(bl) }

func (bl BatchList) unmarshal(payload []byte) BatchList {
	var batchList BatchList
	if err := json.Unmarshal(payload, &batchList); err != nil {
		log.Fatal(err)
	}
	return batchList
}

func (bl BatchList) prettyPrint() string { return prettyPrint(bl) }

// A BatchListContainer matches the structure of the JSON payload returned
// by the GET (all) Batches API endpoint.
type BatchListContainer struct {
	Items BatchList `json:"items"`
	Meta  struct {
		TotalItems int `json:"total_items"`
	} `json:"meta"`
}

// Marshal serializes a BatchListContainer into a byte slice.
func (blc BatchListContainer) Marshal() ([]byte, error) { return indentedJSON(blc) }

// Unmarshal attempts to deserialize the provided JSON payload
// into the complete metadata returned by a request to the Index (GET all)
// API endpoint.
func (blc BatchListContainer) Unmarshal(payload []byte) BatchListContainer {
	var batchListContainer BatchListContainer
	if err := json.Unmarshal(payload, &batchListContainer); err != nil {
		log.Fatal(err)
	}
	return batchListContainer
}

// PrettyPrint returns a human-readable serialized JSON representation of
// the provided object.
func (blc BatchListContainer) PrettyPrint() string { return prettyPrint(blc) }
<|endoftext|>


<commit_before>package solver

import (
	"bufio"
	"fmt"
	"io"
	"strconv"
	"strings"
)

// ParseSlice parse a slice of slice of lits and returns the equivalent problem.
// The argument is supposed to be a well-formed CNF.
func ParseSlice(cnf [][]int) *Problem {
	var pb Problem
	for _, line := range cnf {
		switch len(line) {
		case 0:
			pb.Status = Unsat
			return &pb
		case 1:
			if line[0] == 0 {
				panic("null unit clause")
			}
			lit := IntToLit(int32(line[0]))
			v := lit.Var()
			if int(v) >= pb.NbVars {
				pb.NbVars = int(v) + 1
			}
			pb.Units = append(pb.Units, lit)
		default:
			lits := make([]Lit, len(line))
			for j, val := range line {
				if val == 0 {
					panic("null literal in clause %q")
				}
				lits[j] = IntToLit(int32(val))
				if v := int(lits[j].Var()); v >= pb.NbVars {
					pb.NbVars = v + 1
				}
			}
			pb.Clauses = append(pb.Clauses, NewClause(lits))
		}
	}
	pb.Model = make([]decLevel, pb.NbVars)
	for _, unit := range pb.Units {
		v := unit.Var()
		if pb.Model[v] == 0 {
			if unit.IsPositive() {
				pb.Model[v] = 1
			} else {
				pb.Model[v] = -1
			}
		} else if pb.Model[v] > 0 != unit.IsPositive() {
			pb.Status = Unsat
			return &pb
		}
	}
	pb.simplify()
	return &pb
}

// ParseCardConstrs parses the given cardinality constraints.
// Will panic if a zero value appears in the literals.
func ParseCardConstrs(constrs []CardConstr) *Problem {
	var pb Problem
	for _, constr := range constrs {
		card := constr.AtLeast
		if card <= 0 { // Clause is trivially SAT, ignore
			continue
		}
		if len(constr.Lits) < card { // Clause cannot be satsfied
			pb.Status = Unsat
			return &pb
		}
		if len(constr.Lits) == card { // All lits must be true
			for i := range constr.Lits {
				if constr.Lits[i] == 0 {
					panic("literal 0 found in clause")
				}
				lit := IntToLit(int32(constr.Lits[i]))
				v := lit.Var()
				if int(v) >= pb.NbVars {
					pb.NbVars = int(v) + 1
				}
				pb.Units = append(pb.Units, lit)
			}
		} else {
			lits := make([]Lit, len(constr.Lits))
			for j, val := range constr.Lits {
				if val == 0 {
					panic("literal 0 found in clause")
				}
				lits[j] = IntToLit(int32(val))
				if v := int(lits[j].Var()); v >= pb.NbVars {
					pb.NbVars = v + 1
				}
			}
			pb.Clauses = append(pb.Clauses, NewCardClause(lits, card))
		}
	}
	pb.Model = make([]decLevel, pb.NbVars)
	for _, unit := range pb.Units {
		v := unit.Var()
		if pb.Model[v] == 0 {
			if unit.IsPositive() {
				pb.Model[v] = 1
			} else {
				pb.Model[v] = -1
			}
		} else if pb.Model[v] > 0 != unit.IsPositive() {
			pb.Status = Unsat
			return &pb
		}
	}
	pb.simplify()
	return &pb
}

// ParsePBConstrs parses and returns a PB problem from PBConstr values.
func ParsePBConstrs(constrs []PBConstr) *Problem {
	var pb Problem
	for _, constr := range constrs {
		for i := range constr.Lits {
			lit := IntToLit(int32(constr.Lits[i]))
			v := lit.Var()
			if int(v) >= pb.NbVars {
				pb.NbVars = int(v) + 1
			}
		}
		card := constr.AtLeast
		if card <= 0 { // Clause is trivially SAT, ignore
			continue
		}
		sumW := constr.WeightSum()
		if sumW < card { // Clause cannot be satsfied
			pb.Status = Unsat
			return &pb
		}
		if sumW == card { // All lits must be true
			for i := range constr.Lits {
				lit := IntToLit(int32(constr.Lits[i]))
				pb.Units = append(pb.Units, lit)
			}
		} else {
			lits := make([]Lit, len(constr.Lits))
			for j, val := range constr.Lits {
				lits[j] = IntToLit(int32(val))
			}
			pb.Clauses = append(pb.Clauses, NewPBClause(lits, constr.Weights, card))
		}
	}
	pb.Model = make([]decLevel, pb.NbVars)
	for _, unit := range pb.Units {
		v := unit.Var()
		if pb.Model[v] == 0 {
			if unit.IsPositive() {
				pb.Model[v] = 1
			} else {
				pb.Model[v] = -1
			}
		} else if pb.Model[v] > 0 != unit.IsPositive() {
			pb.Status = Unsat
			return &pb
		}
	}
	pb.simplifyPB()
	return &pb
}

// Parses a CNF line containing a clause and adds it to the problem.
func (pb *Problem) parseClause(line string) error {
	fields := strings.Fields(line)
	lits := make([]Lit, len(fields)-1)
	for i, field := range fields {
		if i == len(fields)-1 { // Ignore last field: it is the 0 clause terminator
			break
		}
		if field == "" {
			continue
		}
		cnfLit, err := strconv.Atoi(field)
		if err != nil {
			return fmt.Errorf("Invalid literal %q in CNF clause %q", field, line)
		}
		lits[i] = IntToLit(int32(cnfLit))
	}
	switch len(lits) {
	case 0:
		pb.Status = Unsat
		pb.Clauses = nil
	case 1:
		lit := lits[0]
		pb.Units = append(pb.Units, lit)
		v := lit.Var()
		if pb.Model[v] == 0 {
			if lit.IsPositive() {
				pb.Model[lit.Var()] = 1
			} else {
				pb.Model[lit.Var()] = -1
			}
		} else if pb.Model[v] > 0 != lit.IsPositive() {
			pb.Status = Unsat
		}
	default:
		pb.Clauses = append(pb.Clauses, NewClause(lits))
	}
	return nil
}

// ParseCNF parses a CNF file and returns the corresponding Problem.
func ParseCNF(f io.Reader) (*Problem, error) {
	scanner := bufio.NewScanner(f)
	var nbClauses int
	var pb Problem
	for scanner.Scan() {
		line := scanner.Text()
		if line == "" {
			continue
		}
		if line[0] == 'p' {
			fields := strings.Fields(line)
			if len(fields) < 4 {
				return nil, fmt.Errorf("invalid syntax %q in CNF file", line)
			}
			var err error
			pb.NbVars, err = strconv.Atoi(fields[2])
			if err != nil {
				return nil, fmt.Errorf("nbvars not an int : '%s'", fields[2])
			}
			pb.Model = make([]decLevel, pb.NbVars)
			nbClauses, err = strconv.Atoi(fields[3])
			if err != nil {
				return nil, fmt.Errorf("nbClauses not an int : '%s'", fields[3])
			}
			pb.Clauses = make([]*Clause, 0, nbClauses)
		} else if line[0] != 'c' { // Not a header, not a comment : a clause
			if err := pb.parseClause(line); err != nil {
				return nil, err
			}
		}
	}
	pb.simplify()
	return &pb, nil
}

// parsePBOptim parses the "min:" instruction.
func (pb *Problem) parsePBOptim(fields []string, line string) error {
	weights, lits, err := pb.parseTerms(fields[1:], line)
	if err != nil {
		return err
	}
	pb.minLits = make([]Lit, len(lits))
	for i, lit := range lits {
		pb.minLits[i] = IntToLit(int32(lit))
	}
	pb.minWeights = weights
	return nil
}

func (pb *Problem) parsePBLine(line string) error {
	if line[len(line)-1] != ';' {
		return fmt.Errorf("line %q does not end with semicolon", line)
	}
	fields := strings.Fields(line[:len(line)-1])
	if len(fields) == 0 {
		return fmt.Errorf("empty line in file")
	}
	if fields[0] == "min:" { // Optimization constraint
		return pb.parsePBOptim(fields, line)
	}
	return pb.parsePBConstrLine(fields, line)
}

func (pb *Problem) parsePBConstrLine(fields []string, line string) error {
	if len(fields) < 3 {
		return fmt.Errorf("invalid syntax %q", line)
	}
	operator := fields[len(fields)-2]
	if operator != ">=" && operator != "=" {
		return fmt.Errorf("invalid operator %q in %q: expected \">=\" or \"=\"", operator, line)
	}
	rhs, err := strconv.Atoi(fields[len(fields)-1])
	if err != nil {
		return fmt.Errorf("invalid value %q in %q: %v", fields[len(fields)-1], line, err)
	}
	weights, lits, err := pb.parseTerms(fields[:len(fields)-2], line)
	if err != nil {
		return err
	}
	var constrs []PBConstr
	if operator == ">=" {
		constrs = []PBConstr{GtEq(lits, weights, rhs)}
	} else {
		constrs = Eq(lits, weights, rhs)
	}
	for _, constr := range constrs {
		card := constr.AtLeast
		sumW := constr.WeightSum()
		if sumW < card { // Clause cannot be satsfied
			pb.Status = Unsat
			return nil
		}
		if sumW == card { // All lits must be true
			for i := range constr.Lits {
				lit := IntToLit(int32(constr.Lits[i]))
				pb.Units = append(pb.Units, lit)
			}
		} else {
			lits := make([]Lit, len(constr.Lits))
			for j, val := range constr.Lits {
				lits[j] = IntToLit(int32(val))
			}
			pb.Clauses = append(pb.Clauses, NewPBClause(lits, constr.Weights, card))
		}
	}
	return nil
}

func (pb *Problem) parseTerms(terms []string, line string) (weights []int, lits []int, err error) {
	weights = make([]int, 0, len(terms)/2)
	lits = make([]int, 0, len(terms)/2)
	i := 0
	for i < len(terms) {
		var l string
		w, err := strconv.Atoi(terms[i])
		if err != nil {
			l = terms[i]
			if !strings.HasPrefix(l, "x") && !strings.HasPrefix(l, "~x") {
				return nil, nil, fmt.Errorf("invalid weight %q in %q: %v", terms[i*2], line, err)
			}
			// This is a weightless lit, i.e a lit with weight 1.
			weights = append(weights, 1)
		} else {
			weights = append(weights, w)
			i++
			l = terms[i]
			if !strings.HasPrefix(l, "x") && !strings.HasPrefix(l, "~x") || len(l) < 2 {
				return nil, nil, fmt.Errorf("invalid variable name %q in %q", l, line)
			}
		}
		var lit int
		if l[0] == '~' {
			lit, err = strconv.Atoi(l[2:])
			lits = append(lits, -lit)
		} else {
			lit, err = strconv.Atoi(l[1:])
			lits = append(lits, lit)
		}
		if err != nil {
			return nil, nil, fmt.Errorf("invalid variable %q in %q: %v", l, line, err)
		}
		if lit > pb.NbVars {
			pb.NbVars = lit
		}
		i++
	}
	return weights, lits, nil
}

// ParseOPB parses a file corresponding to the OPB syntax.
// See http://www.cril.univ-artois.fr/PB16/format.pdf for more details.
func ParseOPB(f io.Reader) (*Problem, error) {
	scanner := bufio.NewScanner(f)
	var pb Problem
	for scanner.Scan() {
		line := scanner.Text()
		if line == "" || line[0] == '*' {
			continue
		}
		if err := pb.parsePBLine(line); err != nil {
			return nil, err
		}
	}
	if err := scanner.Err(); err != nil {
		return nil, fmt.Errorf("could not parse OPB: %v", err)
	}
	pb.Model = make([]decLevel, pb.NbVars)
	pb.simplifyPB()
	return &pb, nil
}
<commit_msg>improved DIMACS parser's efficiency<commit_after>package solver

import (
	"bufio"
	"fmt"
	"io"
	"strconv"
	"strings"
)

// ParseSlice parse a slice of slice of lits and returns the equivalent problem.
// The argument is supposed to be a well-formed CNF.
func ParseSlice(cnf [][]int) *Problem {
	var pb Problem
	for _, line := range cnf {
		switch len(line) {
		case 0:
			pb.Status = Unsat
			return &pb
		case 1:
			if line[0] == 0 {
				panic("null unit clause")
			}
			lit := IntToLit(int32(line[0]))
			v := lit.Var()
			if int(v) >= pb.NbVars {
				pb.NbVars = int(v) + 1
			}
			pb.Units = append(pb.Units, lit)
		default:
			lits := make([]Lit, len(line))
			for j, val := range line {
				if val == 0 {
					panic("null literal in clause %q")
				}
				lits[j] = IntToLit(int32(val))
				if v := int(lits[j].Var()); v >= pb.NbVars {
					pb.NbVars = v + 1
				}
			}
			pb.Clauses = append(pb.Clauses, NewClause(lits))
		}
	}
	pb.Model = make([]decLevel, pb.NbVars)
	for _, unit := range pb.Units {
		v := unit.Var()
		if pb.Model[v] == 0 {
			if unit.IsPositive() {
				pb.Model[v] = 1
			} else {
				pb.Model[v] = -1
			}
		} else if pb.Model[v] > 0 != unit.IsPositive() {
			pb.Status = Unsat
			return &pb
		}
	}
	pb.simplify()
	return &pb
}

// Parses a CNF line containing a clause and adds it to the problem.
func (pb *Problem) parseClause(line string) error {
	fields := strings.Fields(line)
	lits := make([]Lit, len(fields)-1)
	for i, field := range fields {
		if i == len(fields)-1 { // Ignore last field: it is the 0 clause terminator
			break
		}
		if field == "" {
			continue
		}
		cnfLit, err := strconv.Atoi(field)
		if err != nil {
			return fmt.Errorf("Invalid literal %q in CNF clause %q", field, line)
		}
		lits[i] = IntToLit(int32(cnfLit))
	}
	switch len(lits) {
	case 0:
		pb.Status = Unsat
		pb.Clauses = nil
	case 1:
		lit := lits[0]
		pb.Units = append(pb.Units, lit)
		v := lit.Var()
		if pb.Model[v] == 0 {
			if lit.IsPositive() {
				pb.Model[lit.Var()] = 1
			} else {
				pb.Model[lit.Var()] = -1
			}
		} else if pb.Model[v] > 0 != lit.IsPositive() {
			pb.Status = Unsat
		}
	default:
		pb.Clauses = append(pb.Clauses, NewClause(lits))
	}
	return nil
}

func oldParseCNF(f io.Reader) (*Problem, error) {
	scanner := bufio.NewScanner(f)
	var nbClauses int
	var pb Problem
	for scanner.Scan() {
		line := scanner.Text()
		if line == "" {
			continue
		}
		if line[0] == 'p' {
			fields := strings.Fields(line)
			if len(fields) < 4 {
				return nil, fmt.Errorf("invalid syntax %q in CNF file", line)
			}
			var err error
			pb.NbVars, err = strconv.Atoi(fields[2])
			if err != nil {
				return nil, fmt.Errorf("nbvars not an int : '%s'", fields[2])
			}
			pb.Model = make([]decLevel, pb.NbVars)
			nbClauses, err = strconv.Atoi(fields[3])
			if err != nil {
				return nil, fmt.Errorf("nbClauses not an int : '%s'", fields[3])
			}
			pb.Clauses = make([]*Clause, 0, nbClauses)
		} else if line[0] != 'c' { // Not a header, not a comment : a clause
			if err := pb.parseClause(line); err != nil {
				return nil, err
			}
		}
	}
	pb.simplify()
	return &pb, nil
}

// readInt reads an int from r.
// 'b' is the last read byte. It can be a space, a '-' or a digit.
// The int can be negated.
// All spaces before the int value are ignored.
// Can return EOF.
func readInt(b *byte, r *bufio.Reader) (res int, err error) {
	for err == nil && (*b == ' ' || *b == '\t' || *b == '\n') {
		*b, err = r.ReadByte()
	}
	if err == io.EOF {
		return res, io.EOF
	}
	if err != nil {
		return res, fmt.Errorf("could not read digit: %v", err)
	}
	neg := 1
	if *b == '-' {
		neg = -1
		*b, err = r.ReadByte()
		if err != nil {
			return 0, fmt.Errorf("cannot read int: %v", err)
		}
	}
	for err == nil {
		if *b < '0' || *b > '9' {
			return 0, fmt.Errorf("cannot read int: %q is not a digit", *b)
		}
		res = 10*res + int(*b-'0')
		*b, err = r.ReadByte()
		if *b == ' ' || *b == '\t' || *b == '\n' {
			break
		}
	}
	res *= neg
	return res, err
}

func parseHeader(r *bufio.Reader) (nbVars, nbClauses int, err error) {
	line, err := r.ReadString('\n')
	if err != nil {
		return 0, 0, fmt.Errorf("cannot read header: %v", err)
	}
	fields := strings.Fields(line)
	if len(fields) < 3 {
		return 0, 0, fmt.Errorf("invalid syntax %q in header", line)
	}
	nbVars, err = strconv.Atoi(fields[1])
	if err != nil {
		return 0, 0, fmt.Errorf("nbvars not an int : %q", fields[1])
	}
	nbClauses, err = strconv.Atoi(fields[2])
	if err != nil {
		return 0, 0, fmt.Errorf("nbClauses not an int : '%s'", fields[2])
	}
	return nbVars, nbClauses, nil
}

// ParseCNF parses a CNF file and returns the corresponding Problem.
func ParseCNF(f io.Reader) (*Problem, error) {
	r := bufio.NewReader(f)
	var (
		nbClauses int
		pb        Problem
	)
	b, err := r.ReadByte()
	for err == nil {
		if b == 'c' { // Ignore comment
			b, err = r.ReadByte()
			for err == nil && b != '\n' {
				b, err = r.ReadByte()
			}
		} else if b == 'p' { // Parse header
			pb.NbVars, nbClauses, err = parseHeader(r)
			if err != nil {
				return nil, fmt.Errorf("cannot parse CNF header: %v", err)
			}
			pb.Model = make([]decLevel, pb.NbVars)
			pb.Clauses = make([]*Clause, 0, nbClauses)
		} else {
			var lits []Lit
			for {
				val, err := readInt(&b, r)
				if err != nil {
					return nil, fmt.Errorf("cannot parse clause: %v", err)
				}
				if val == 0 {
					pb.Clauses = append(pb.Clauses, NewClause(lits))
					break
				} else {
					lits = append(lits, IntToLit(int32(val)))
				}
			}
		}
		b, err = r.ReadByte()
	}
	if err != io.EOF {
		return nil, err
	}
	pb.simplify()
	return &pb, nil
}
<|endoftext|>


<commit_before>package main

import (
	_ "time"
	"crypto/rand"
	"encoding/json"
	"fmt"
	"github.com/gorilla/sessions"
	"io"
	"net/http"
	"database/sql"
	_ "github.com/go-sql-driver/mysql"
	"runtime"
	"errors"
	"html/template"
	"os/exec"
)

var templates = template.Must(template.ParseFiles("index.html"))

const MESSAGE_QUEUE_SIZE = 10

const STATUS_FAILURE = "{\"status\":\"failure\"}"

var authKey = []byte("somesecretauth")
var store sessions.Store

var pool *Pool
var clients map[int64]*Client

var db *sql.DB

type Pool struct {
	in  chan *Client
	out chan *Room
}

type Client struct {
	id      int64
	otherid int64
	in      chan string
	out     chan string
	retChan chan *Room
}

type Room struct {
	id      []byte
	client1 *Client
	client2 *Client
	Question *Question
}

type Question struct {
	Id 	int64			`json:"id"`
	Title string		`json:"title"`
	Body string			`json:"body"`
	Difficulty int 		`json:"diff"`
}

func (p *Pool) Pair() {
	for {
		c1, c2 := <-p.in, <-p.in

		for c1.id == c2.id {
			c2 = <- p.in
		}

		fmt.Println("match found for ", c1.id, " and ", c2.id)

		b := make([]byte, 32)
		n, err := io.ReadFull(rand.Reader, b)
		if err != nil || n != 32 {
			return
		}

		row := db.QueryRow("SELECT * FROM questions ORDER BY RAND()")
		q := new(Question)
		err = row.Scan(&q.Id, &q.Title, &q.Body, &q.Difficulty)
		if err !=  nil {
			fmt.Println(err)
		}

		room := &Room{b, c1, c2, q}

		c1.otherid, c2.otherid = c2.id, c1.id
		c1.in, c2.in = c2.out, c1.out

		c1.retChan <- room
		c2.retChan <- room
	}
}

func newPool() *Pool {
	pool := &Pool{
		in:  make(chan *Client),
		out: make(chan *Room),
	}

	go pool.Pair()

	return pool
}

func UIDFromSession(w http.ResponseWriter, r *http.Request) (int64, error) {
	session, _ := store.Get(r, "session")
	userid := session.Values["userid"]

	if userid == nil {
		return 0, errors.New("no cookie set")
	}
	return userid.(int64), nil
}

func main() {
	runtime.GOMAXPROCS(runtime.NumCPU())

	db, _ = sql.Open("mysql", "root:pass@/suitup")
	defer db.Close()

	store = sessions.NewCookieStore(authKey)

	pool = newPool()
	clients = make(map[int64]*Client)

	http.HandleFunc("/", mainHandle)

	http.HandleFunc("/login", login)

	http.HandleFunc("/message/check", checkMessage)
	http.HandleFunc("/message/send", sendMessage)

	http.HandleFunc("/question/new", newQuestion)
	http.HandleFunc("/question/submit", testCode)

	http.HandleFunc("/chatroom/join", joinChatRoom)
	http.HandleFunc("/chatroom/leave", leaveChatRoom)

	http.Handle("/assets/", http.StripPrefix("/assets/", http.FileServer(http.Dir("/home/suitup/hackmit/assets/"))))
	http.ListenAndServe(":8080", nil)
}

func mainHandle(w http.ResponseWriter, r *http.Request) {
	templates.ExecuteTemplate(w, "index.html", nil)
}

func joinChatRoom(w http.ResponseWriter, r *http.Request) {
	uid, err := UIDFromSession(w, r)
	handleError(err)

	fmt.Println("join ", uid)

	retChan := make(chan *Room)
	client := &Client{
		id:      uid,
		in:      nil,
		out:     make(chan string, MESSAGE_QUEUE_SIZE),
		retChan: retChan,
	}

	clients[uid] = client
	pool.in <- client

	chatroom := <- retChan

	fmt.Println("joinChatRoom-chatroom.id: ", chatroom.id)

	qjs, err := json.Marshal(chatroom.Question)

	fmt.Println("qjs: ", string(qjs))

	fmt.Fprint(w, "{\"status\":\"success\",\"crid\":\"", asciify(chatroom.id), "\",\"question\":", string(qjs), "}")
}

func asciify(ba []byte) string {
	ret := make([]byte, len(ba))
	for i, b := range ba {
		ret[i] = (b % 26) + 97
	}
	return string(ret)
}

func testCode(w http.ResponseWriter, r *http.Request) {
	r.ParseForm()
	code := r.FormValue("submission")
	_ = r.FormValue("cvid")
	qid := 1
	app := "/home/suitup/hackmit/secure.sh"
	out1, err1 := exec.Command("echo", string(qid), code).Output()
	if err1 != nil {
    	fmt.Println(err1)
	}
	fmt.Printf("The date is %s\n", out1)
	cmd := exec.Command(app, qid, code)
    out, err := cmd.Output()
    if err != nil {
    	fmt.Println(err)
    }
    fmt.Println(string(out))
    fmt.Fprint(w, "{\"status\":\"success\", \"data\": \"", string(out), "\"}" )
    return
}

func leaveChatRoom(w http.ResponseWriter, r *http.Request) {
	uid, _ := UIDFromSession(w, r)
	client := clients[uid]

	if client != nil {
		fmt.Println("leaving")
		delete(clients, client.otherid)
		delete(clients, uid)
	}

	fmt.Println("leave ", uid)

	fmt.Fprint(w, "{\"status\":\"success\"}")
}

func sendMessage(w http.ResponseWriter, r *http.Request) {
	uid, err := UIDFromSession(w, r)
	handleError(err)

	fmt.Println("send ", uid)

	r.ParseForm()
	message := r.FormValue("s")

	client := clients[uid]

	if client != nil {
		client.out <- message
		fmt.Fprint(w, "{\"status\":\"success\"}")
	} else {
		fmt.Fprint(w, STATUS_FAILURE)
	}
}

func checkMessage(w http.ResponseWriter, r *http.Request) {
	uid, err := UIDFromSession(w, r)
	handleError(err)

	fmt.Println("check ", uid)

	client := clients[uid]

	if client != nil {
		select {
		case message, ok := <- client.in:
			if ok {
				fmt.Fprint(w, "{\"status\":\"success\",\"s\":\"", message, "\"}")
			} else {
				delete(clients, uid)
				fmt.Fprint(w, "{\"status\":\"failure\"}")
			}
		default:
			fmt.Fprint(w, "{\"status\":\"success\",\"s\":\"\"}")
		}

	} else {
		fmt.Fprint(w, "{\"status\":\"failure\",\"s\":\"\"}")
	}
}

type User struct {
    Id            	int64      	`json:"id"`
    FacebookId  	string		`json:fbid"`
    Username 		string		`json:username"`
    Email 			string		`json:email"`
    Level 			int64		`json:lvl"`
    Score 			int64		`json:score"`
}

func newQuestion(w http.ResponseWriter, r *http.Request) {
	row := db.QueryRow("SELECT * FROM questions ORDER BY RAND()")
	q := new(Question)
	err := row.Scan(&q.Id, &q.Title, &q.Body, &q.Difficulty)

	if err != nil {
		fmt.Println(err)
		fmt.Fprint(w, STATUS_FAILURE)
	}

	b, err := json.Marshal(q)
	if err != nil {
		fmt.Println(err)
		fmt.Fprint(w, STATUS_FAILURE)
	}

	fmt.Fprint(w, string(b))
}

func login(w http.ResponseWriter, r *http.Request) {
	inputToken := r.FormValue("access_token")
	if len(inputToken) != 0 {
		uid := GetMe(inputToken)

		// row := db.QueryRow("SELECT id FROM users")
		row := db.QueryRow("SELECT id FROM users WHERE facebook_id=?", string(uid))
		user := new(User)
		err := row.Scan(&user.Id)

		if err != nil {
			_, err = db.Exec("INSERT INTO users (facebook_id, username, email, level, points) VALUES (?, ?, ?, 0, 0)", uid, "", "")
			if err != nil {
				fmt.Fprint(w, STATUS_FAILURE)
				return
			} else {
				row = db.QueryRow("SELECT id FROM users WHERE facebook_id=?", string(uid))
				err = row.Scan(&user.Id)
				if err != nil {
					fmt.Fprint(w, STATUS_FAILURE)
					return
				}
			}

		}

		session, _ := store.Get(r, "session")
		session.Values["userid"] = user.Id
		session.Save(r, w)

		fmt.Fprint(w, "{\"status\":\"success\"}")
	}
}

func readHttpBody(response *http.Response) string {
	bodyBuffer := make([]byte, 1000)
	var str string

	count, err := response.Body.Read(bodyBuffer)

	for ; count > 0; count, err = response.Body.Read(bodyBuffer) {

		if err != nil {

		}

		str += string(bodyBuffer[:count])
	}

	return str

}

func getUncachedResponse(uri string) (*http.Response, error) {
	request, err := http.NewRequest("GET", uri, nil)

	if err == nil {
		request.Header.Add("Cache-Control", "no-cache")

		client := new(http.Client)

		return client.Do(request)
	}

	if (err != nil) {
	}
	return nil, err

}

func GetMe(token string) string {
	response, err := getUncachedResponse("https://graph.facebook.com/me?access_token="+token)

	if err == nil {

		var jsonBlob interface{}

		responseBody := readHttpBody(response)

		if responseBody != "" {
			err = json.Unmarshal([]byte(responseBody), &jsonBlob)

			if err == nil {
				jsonObj := jsonBlob.(map[string]interface{})
				return jsonObj["id"].(string)
			}
		}
		return err.Error()
	}

	return err.Error()
}

func handleError(err error) {
	if err != nil {
		fmt.Println(err)
	}
}
<commit_msg>adding changes to bash call<commit_after>package main

import (
	_ "time"
	"crypto/rand"
	"encoding/json"
	"fmt"
	"github.com/gorilla/sessions"
	"io"
	"net/http"
	"database/sql"
	_ "github.com/go-sql-driver/mysql"
	"runtime"
	"errors"
	"html/template"
	"os/exec"
)

var templates = template.Must(template.ParseFiles("index.html"))

const MESSAGE_QUEUE_SIZE = 10

const STATUS_FAILURE = "{\"status\":\"failure\"}"

var authKey = []byte("somesecretauth")
var store sessions.Store

var pool *Pool
var clients map[int64]*Client

var db *sql.DB

type Pool struct {
	in  chan *Client
	out chan *Room
}

type Client struct {
	id      int64
	otherid int64
	in      chan string
	out     chan string
	retChan chan *Room
}

type Room struct {
	id      []byte
	client1 *Client
	client2 *Client
	Question *Question
}

type Question struct {
	Id 	int64			`json:"id"`
	Title string		`json:"title"`
	Body string			`json:"body"`
	Difficulty int 		`json:"diff"`
}

func (p *Pool) Pair() {
	for {
		c1, c2 := <-p.in, <-p.in

		for c1.id == c2.id {
			c2 = <- p.in
		}

		fmt.Println("match found for ", c1.id, " and ", c2.id)

		b := make([]byte, 32)
		n, err := io.ReadFull(rand.Reader, b)
		if err != nil || n != 32 {
			return
		}

		row := db.QueryRow("SELECT * FROM questions ORDER BY RAND()")
		q := new(Question)
		err = row.Scan(&q.Id, &q.Title, &q.Body, &q.Difficulty)
		if err !=  nil {
			fmt.Println(err)
		}

		room := &Room{b, c1, c2, q}

		c1.otherid, c2.otherid = c2.id, c1.id
		c1.in, c2.in = c2.out, c1.out

		c1.retChan <- room
		c2.retChan <- room
	}
}

func newPool() *Pool {
	pool := &Pool{
		in:  make(chan *Client),
		out: make(chan *Room),
	}

	go pool.Pair()

	return pool
}

func UIDFromSession(w http.ResponseWriter, r *http.Request) (int64, error) {
	session, _ := store.Get(r, "session")
	userid := session.Values["userid"]

	if userid == nil {
		return 0, errors.New("no cookie set")
	}
	return userid.(int64), nil
}

func main() {
	runtime.GOMAXPROCS(runtime.NumCPU())

	db, _ = sql.Open("mysql", "root:pass@/suitup")
	defer db.Close()

	store = sessions.NewCookieStore(authKey)

	pool = newPool()
	clients = make(map[int64]*Client)

	http.HandleFunc("/", mainHandle)

	http.HandleFunc("/login", login)

	http.HandleFunc("/message/check", checkMessage)
	http.HandleFunc("/message/send", sendMessage)

	http.HandleFunc("/question/new", newQuestion)
	http.HandleFunc("/question/submit", testCode)

	http.HandleFunc("/chatroom/join", joinChatRoom)
	http.HandleFunc("/chatroom/leave", leaveChatRoom)

	http.Handle("/assets/", http.StripPrefix("/assets/", http.FileServer(http.Dir("/home/suitup/hackmit/assets/"))))
	http.ListenAndServe(":8080", nil)
}

func mainHandle(w http.ResponseWriter, r *http.Request) {
	templates.ExecuteTemplate(w, "index.html", nil)
}

func joinChatRoom(w http.ResponseWriter, r *http.Request) {
	uid, err := UIDFromSession(w, r)
	handleError(err)

	fmt.Println("join ", uid)

	retChan := make(chan *Room)
	client := &Client{
		id:      uid,
		in:      nil,
		out:     make(chan string, MESSAGE_QUEUE_SIZE),
		retChan: retChan,
	}

	clients[uid] = client
	pool.in <- client

	chatroom := <- retChan

	fmt.Println("joinChatRoom-chatroom.id: ", chatroom.id)

	qjs, err := json.Marshal(chatroom.Question)

	fmt.Println("qjs: ", string(qjs))

	fmt.Fprint(w, "{\"status\":\"success\",\"crid\":\"", asciify(chatroom.id), "\",\"question\":", string(qjs), "}")
}

func asciify(ba []byte) string {
	ret := make([]byte, len(ba))
	for i, b := range ba {
		ret[i] = (b % 26) + 97
	}
	return string(ret)
}

func testCode(w http.ResponseWriter, r *http.Request) {
	r.ParseForm()
	code := r.FormValue("submission")
	_ = r.FormValue("cvid")
	qid := '1'
	app := "/home/suitup/hackmit/secure.sh"
	out1, err1 := exec.Command("echo", string(qid), code).Output()
	if err1 != nil {
    	fmt.Println(err1)
	}
	fmt.Printf("The date is %s\n", out1)
	cmd := exec.Command(app, qid, code)
    out, err := cmd.Output()
    if err != nil {
    	fmt.Println(err)
    }
    fmt.Println(string(out))
    fmt.Fprint(w, "{\"status\":\"success\", \"data\": \"", string(out), "\"}" )
    return
}

func leaveChatRoom(w http.ResponseWriter, r *http.Request) {
	uid, _ := UIDFromSession(w, r)
	client := clients[uid]

	if client != nil {
		fmt.Println("leaving")
		delete(clients, client.otherid)
		delete(clients, uid)
	}

	fmt.Println("leave ", uid)

	fmt.Fprint(w, "{\"status\":\"success\"}")
}

func sendMessage(w http.ResponseWriter, r *http.Request) {
	uid, err := UIDFromSession(w, r)
	handleError(err)

	fmt.Println("send ", uid)

	r.ParseForm()
	message := r.FormValue("s")

	client := clients[uid]

	if client != nil {
		client.out <- message
		fmt.Fprint(w, "{\"status\":\"success\"}")
	} else {
		fmt.Fprint(w, STATUS_FAILURE)
	}
}

func checkMessage(w http.ResponseWriter, r *http.Request) {
	uid, err := UIDFromSession(w, r)
	handleError(err)

	fmt.Println("check ", uid)

	client := clients[uid]

	if client != nil {
		select {
		case message, ok := <- client.in:
			if ok {
				fmt.Fprint(w, "{\"status\":\"success\",\"s\":\"", message, "\"}")
			} else {
				delete(clients, uid)
				fmt.Fprint(w, "{\"status\":\"failure\"}")
			}
		default:
			fmt.Fprint(w, "{\"status\":\"success\",\"s\":\"\"}")
		}

	} else {
		fmt.Fprint(w, "{\"status\":\"failure\",\"s\":\"\"}")
	}
}

type User struct {
    Id            	int64      	`json:"id"`
    FacebookId  	string		`json:fbid"`
    Username 		string		`json:username"`
    Email 			string		`json:email"`
    Level 			int64		`json:lvl"`
    Score 			int64		`json:score"`
}

func newQuestion(w http.ResponseWriter, r *http.Request) {
	row := db.QueryRow("SELECT * FROM questions ORDER BY RAND()")
	q := new(Question)
	err := row.Scan(&q.Id, &q.Title, &q.Body, &q.Difficulty)

	if err != nil {
		fmt.Println(err)
		fmt.Fprint(w, STATUS_FAILURE)
	}

	b, err := json.Marshal(q)
	if err != nil {
		fmt.Println(err)
		fmt.Fprint(w, STATUS_FAILURE)
	}

	fmt.Fprint(w, string(b))
}

func login(w http.ResponseWriter, r *http.Request) {
	inputToken := r.FormValue("access_token")
	if len(inputToken) != 0 {
		uid := GetMe(inputToken)

		// row := db.QueryRow("SELECT id FROM users")
		row := db.QueryRow("SELECT id FROM users WHERE facebook_id=?", string(uid))
		user := new(User)
		err := row.Scan(&user.Id)

		if err != nil {
			_, err = db.Exec("INSERT INTO users (facebook_id, username, email, level, points) VALUES (?, ?, ?, 0, 0)", uid, "", "")
			if err != nil {
				fmt.Fprint(w, STATUS_FAILURE)
				return
			} else {
				row = db.QueryRow("SELECT id FROM users WHERE facebook_id=?", string(uid))
				err = row.Scan(&user.Id)
				if err != nil {
					fmt.Fprint(w, STATUS_FAILURE)
					return
				}
			}

		}

		session, _ := store.Get(r, "session")
		session.Values["userid"] = user.Id
		session.Save(r, w)

		fmt.Fprint(w, "{\"status\":\"success\"}")
	}
}

func readHttpBody(response *http.Response) string {
	bodyBuffer := make([]byte, 1000)
	var str string

	count, err := response.Body.Read(bodyBuffer)

	for ; count > 0; count, err = response.Body.Read(bodyBuffer) {

		if err != nil {

		}

		str += string(bodyBuffer[:count])
	}

	return str

}

func getUncachedResponse(uri string) (*http.Response, error) {
	request, err := http.NewRequest("GET", uri, nil)

	if err == nil {
		request.Header.Add("Cache-Control", "no-cache")

		client := new(http.Client)

		return client.Do(request)
	}

	if (err != nil) {
	}
	return nil, err

}

func GetMe(token string) string {
	response, err := getUncachedResponse("https://graph.facebook.com/me?access_token="+token)

	if err == nil {

		var jsonBlob interface{}

		responseBody := readHttpBody(response)

		if responseBody != "" {
			err = json.Unmarshal([]byte(responseBody), &jsonBlob)

			if err == nil {
				jsonObj := jsonBlob.(map[string]interface{})
				return jsonObj["id"].(string)
			}
		}
		return err.Error()
	}

	return err.Error()
}

func handleError(err error) {
	if err != nil {
		fmt.Println(err)
	}
}
<|endoftext|>


<commit_before>package mysqlproto

import (
	"errors"
	"strconv"
)

// https://dev.mysql.com/doc/internals/en/generic-response-packets.html
const OK_PACKET = 0x00
const ERR_PACKET = 0xff
const EOF_PACKET = 0xfe

var ErrERRPacketPayload = errors.New("Invalid ERR_PACKET payload")
var ErrOKPacketPayload = errors.New("Invalid OK_PACKET payload")

type Packet struct {
	SequenceID byte
	Payload    []byte
}

type ERRPacket struct {
	Header         byte // always 0xff
	ErrorCode      uint16
	SQLStateMarker string
	SQLState       string
	ErrorMessage   string
}

type OKPacket struct {
	Header              byte // 0x00 or 0xfe
	AffectedRows        uint64
	LastInsertId        uint64
	StatusFlags         uint16
	Warnings            uint16
	Info                string
	SessionStateChanges string
}

// https://dev.mysql.com/doc/internals/en/packet-OK_Packet.html
func ParseOKPacket(data []byte, capabilityFlags uint32) (OKPacket, error) {
	if len(data) == 0 || (data[0] != OK_PACKET && data[0] != EOF_PACKET) {
		return OKPacket{}, ErrOKPacketPayload
	}

	offset := 0
	header := data[offset]
	offset += 1
	affectedRows, offsetInt, _ := lenDecInt(data[1:])
	offset += int(offsetInt)
	lastInsertId, offsetInt, _ := lenDecInt(data[offset:])
	offset += int(offsetInt)

	var statusFlags, warnings uint16
	if capabilityFlags&CLIENT_PROTOCOL_41 > 0 {
		statusFlags = uint16(data[offset]) | uint16(data[offset+1])<<8
		warnings = uint16(data[offset+2]) | uint16(data[offset+3])<<8
		offset += 4
	} else if capabilityFlags&CLIENT_TRANSACTIONS > 0 {
		statusFlags = uint16(data[offset]) | uint16(data[offset+1])<<8
		offset += 2
	}

	var info, sessionStateChanges string
	if capabilityFlags&CLIENT_SESSION_TRACK > 0 {
		size, intOffset, _ := lenDecInt(data[offset:])
		info = string(data[offset+int(intOffset) : offset+int(intOffset)+int(size)])
		offset += int(intOffset) + int(size)

		if statusFlags&SERVER_SESSION_STATE_CHANGED > 0 {
			size, intOffset, _ = lenDecInt(data[offset:])
			sessionStateChanges = string(data[offset+int(intOffset) : offset+int(intOffset)+int(size)])
			offset += int(intOffset) + int(size)
		}
	} else {
		info = string(data[offset:])
	}

	pkt := OKPacket{
		Header:              header,
		AffectedRows:        affectedRows,
		LastInsertId:        lastInsertId,
		StatusFlags:         statusFlags,
		Warnings:            warnings,
		Info:                info,
		SessionStateChanges: sessionStateChanges,
	}

	return pkt, nil
}

// https://dev.mysql.com/doc/internals/en/packet-ERR_Packet.html
func ParseERRPacket(data []byte, capabilityFlags uint32) (ERRPacket, error) {
	if len(data) == 0 || data[0] != ERR_PACKET {
		return ERRPacket{}, ErrERRPacketPayload
	}

	pkt := ERRPacket{
		Header:    data[0],
		ErrorCode: uint16(data[1]) | uint16(data[2])<<8,
	}

	offset := 3
	if capabilityFlags&CLIENT_PROTOCOL_41 > 0 {
		pkt.SQLStateMarker = string(data[3])
		pkt.SQLState = string(data[4:9])
		offset = 9
	}

	pkt.ErrorMessage = string(data[offset:])

	return pkt, nil
}

// https://dev.mysql.com/doc/refman/5.5/en/error-messages-server.html
func (p ERRPacket) Error() string {
	return "mysqlproto: Error: " + strconv.Itoa(int(p.ErrorCode)) +
		" SQLSTATE: " + p.SQLState +
		" Message: " + p.ErrorMessage
}

func parseError(data []byte, capabilityFlags uint32) error {
	pkt, err := ParseERRPacket(data, capabilityFlags)
	if err != nil {
		return err
	}
	return pkt
}
<commit_msg>Group constants and variables for better documentation<commit_after>package mysqlproto

import (
	"errors"
	"strconv"
)

// https://dev.mysql.com/doc/internals/en/generic-response-packets.html
const (
	OK_PACKET  = 0x00
	ERR_PACKET = 0xff
	EOF_PACKET = 0xfe
)

var (
	ErrERRPacketPayload = errors.New("Invalid ERR_PACKET payload")
	ErrOKPacketPayload  = errors.New("Invalid OK_PACKET payload")
)

type Packet struct {
	SequenceID byte
	Payload    []byte
}

type ERRPacket struct {
	Header         byte // always 0xff
	ErrorCode      uint16
	SQLStateMarker string
	SQLState       string
	ErrorMessage   string
}

type OKPacket struct {
	Header              byte // 0x00 or 0xfe
	AffectedRows        uint64
	LastInsertId        uint64
	StatusFlags         uint16
	Warnings            uint16
	Info                string
	SessionStateChanges string
}

// https://dev.mysql.com/doc/internals/en/packet-OK_Packet.html
func ParseOKPacket(data []byte, capabilityFlags uint32) (OKPacket, error) {
	if len(data) == 0 || (data[0] != OK_PACKET && data[0] != EOF_PACKET) {
		return OKPacket{}, ErrOKPacketPayload
	}

	offset := 0
	header := data[offset]
	offset += 1
	affectedRows, offsetInt, _ := lenDecInt(data[1:])
	offset += int(offsetInt)
	lastInsertId, offsetInt, _ := lenDecInt(data[offset:])
	offset += int(offsetInt)

	var statusFlags, warnings uint16
	if capabilityFlags&CLIENT_PROTOCOL_41 > 0 {
		statusFlags = uint16(data[offset]) | uint16(data[offset+1])<<8
		warnings = uint16(data[offset+2]) | uint16(data[offset+3])<<8
		offset += 4
	} else if capabilityFlags&CLIENT_TRANSACTIONS > 0 {
		statusFlags = uint16(data[offset]) | uint16(data[offset+1])<<8
		offset += 2
	}

	var info, sessionStateChanges string
	if capabilityFlags&CLIENT_SESSION_TRACK > 0 {
		size, intOffset, _ := lenDecInt(data[offset:])
		info = string(data[offset+int(intOffset) : offset+int(intOffset)+int(size)])
		offset += int(intOffset) + int(size)

		if statusFlags&SERVER_SESSION_STATE_CHANGED > 0 {
			size, intOffset, _ = lenDecInt(data[offset:])
			sessionStateChanges = string(data[offset+int(intOffset) : offset+int(intOffset)+int(size)])
			offset += int(intOffset) + int(size)
		}
	} else {
		info = string(data[offset:])
	}

	pkt := OKPacket{
		Header:              header,
		AffectedRows:        affectedRows,
		LastInsertId:        lastInsertId,
		StatusFlags:         statusFlags,
		Warnings:            warnings,
		Info:                info,
		SessionStateChanges: sessionStateChanges,
	}

	return pkt, nil
}

// https://dev.mysql.com/doc/internals/en/packet-ERR_Packet.html
func ParseERRPacket(data []byte, capabilityFlags uint32) (ERRPacket, error) {
	if len(data) == 0 || data[0] != ERR_PACKET {
		return ERRPacket{}, ErrERRPacketPayload
	}

	pkt := ERRPacket{
		Header:    data[0],
		ErrorCode: uint16(data[1]) | uint16(data[2])<<8,
	}

	offset := 3
	if capabilityFlags&CLIENT_PROTOCOL_41 > 0 {
		pkt.SQLStateMarker = string(data[3])
		pkt.SQLState = string(data[4:9])
		offset = 9
	}

	pkt.ErrorMessage = string(data[offset:])

	return pkt, nil
}

// https://dev.mysql.com/doc/refman/5.5/en/error-messages-server.html
func (p ERRPacket) Error() string {
	return "mysqlproto: Error: " + strconv.Itoa(int(p.ErrorCode)) +
		" SQLSTATE: " + p.SQLState +
		" Message: " + p.ErrorMessage
}

func parseError(data []byte, capabilityFlags uint32) error {
	pkt, err := ParseERRPacket(data, capabilityFlags)
	if err != nil {
		return err
	}
	return pkt
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"flag"
	"fmt"
	"io"
	"log"
	"net/http"

	"github.com/jmoiron/sqlx"
	_ "github.com/mattn/go-sqlite3"
)

func Plaintext(w http.ResponseWriter, req *http.Request) {
	io.WriteString(w, "Hello World!\n")
}

type JSONStruct struct {
	Array  []int          `json:"array"`
	Dict   map[string]int `json:"dict"`
	Int    int            `json:"int"`
	String string         `json:"string"`
	Double float64        `json:"double"`
	Null   interface{}    `json:"null"`
}

func JSON(w http.ResponseWriter, req *http.Request) {
	j := JSONStruct{Array: []int{1, 2, 3},
		Dict:   map[string]int{"one": 1, "two": 2, "three": 3},
		Int:    42,
		String: "test",
		Double: 3.14,
		Null:   nil}

	// I *think* the test requests pretty formatting for this test
	b, _ := json.MarshalIndent(j, "", " ")
	io.WriteString(w, string(b))

	// unformatted
	//json.NewEncoder(w).Encode(j)
}

type User struct {
	ID    int    `db:"id" json:"id,omitempty"`
	Name  string `db:"name" json:"name,omitempty"`
	Email string `db:"email" json:"email,omitempty"`
}

func SQLiteFetch(w http.ResponseWriter, req *http.Request) {
	db, err := sqlx.Open("sqlite3", "../database/test.sqlite")
	if err != nil {
		log.Fatal(err)
	}
	defer db.Close()

	user := User{}
	rows, err := db.Queryx("select * from users order by random() limit 1")
	if err != nil {
		log.Fatal(err)
	}
	defer rows.Close()

	for rows.Next() {
		err = rows.StructScan(&user)
		if err != nil {
			log.Fatal(err)
		}

		b, _ := json.MarshalIndent(user, "", " ")
		io.WriteString(w, string(b))

		//json.NewEncoder(w).Encode(user)
	}
}

var portNumber int

func main() {
	flag.IntVar(&portNumber, "port", 8300, "port number to listen on")
	flag.Parse()

	http.HandleFunc("/plaintext", Plaintext)
	http.HandleFunc("/json", JSON)
	http.HandleFunc("/sqlite-fetch", SQLiteFetch)

	log.Println("bench running on", fmt.Sprintf("%d", portNumber))

	err := http.ListenAndServe(fmt.Sprintf(":%d", portNumber), nil)
	if err != nil {
		log.Fatal(err)
	}
}
<commit_msg>tightening things up<commit_after>package main

import (
	"encoding/json"
	"flag"
	"fmt"
	"io"
	"log"
	"net/http"

	"github.com/jmoiron/sqlx"
	_ "github.com/mattn/go-sqlite3"
)

func Plaintext(w http.ResponseWriter, req *http.Request) {
	io.WriteString(w, "Hello World!\n")
}

type JSONStruct struct {
	Array  []int          `json:"array"`
	Dict   map[string]int `json:"dict"`
	Int    int            `json:"int"`
	String string         `json:"string"`
	Double float64        `json:"double"`
	Null   interface{}    `json:"null"`
}

func JSON(w http.ResponseWriter, req *http.Request) {
	j := JSONStruct{Array: []int{1, 2, 3},
		Dict:   map[string]int{"one": 1, "two": 2, "three": 3},
		Int:    42,
		String: "test",
		Double: 3.14,
		Null:   nil}

	b, _ := json.MarshalIndent(j, "", " ")
	io.WriteString(w, string(b))
}

type User struct {
	ID    int    `db:"id" json:"id,omitempty"`
	Name  string `db:"name" json:"name,omitempty"`
	Email string `db:"email" json:"email,omitempty"`
}

// typical usage would keep or cache the open DB connection
var db, _ = sqlx.Open("sqlite3", "../database/test.sqlite")

func SQLiteFetch(w http.ResponseWriter, req *http.Request) {
	//	db, err := sqlx.Open("sqlite3", "../database/test.sqlite")
	//	if err != nil {
	//		log.Fatal(err)
	//	}
	//	defer db.Close()

	user := User{}
	rows, err := db.Queryx("select * from users order by random() limit 1")
	if err != nil {
		log.Fatal(err)
	}
	defer rows.Close()

	for rows.Next() {
		err = rows.StructScan(&user)
		if err != nil {
			log.Fatal(err)
		}

		b, _ := json.MarshalIndent(user, "", " ")
		io.WriteString(w, string(b))
	}
}

var portNumber int

func main() {
	flag.IntVar(&portNumber, "port", 8300, "port number to listen on")
	flag.Parse()

	http.HandleFunc("/plaintext", Plaintext)
	http.HandleFunc("/json", JSON)
	http.HandleFunc("/sqlite-fetch", SQLiteFetch)

	log.Println("bench running on", fmt.Sprintf("%d", portNumber))

	err := http.ListenAndServe(fmt.Sprintf(":%d", portNumber), nil)
	if err != nil {
		log.Fatal(err)
	}
}
<|endoftext|>