<commit_before>// Copyright (c) 2017 Daniel Oaks <daniel@danieloaks.net>
// released under the MIT license

package logger

import (
	"bufio"
	"fmt"
	"os"
	"time"

	"strings"

	"sync"

	colorable "github.com/mattn/go-colorable"
	"github.com/mgutz/ansi"
)

// Level represents the level to log messages at.
type Level int

const (
	// LogDebug represents debug messages.
	LogDebug Level = iota
	// LogInfo represents informational messages.
	LogInfo
	// LogWarning represents warnings.
	LogWarning
	// LogError represents errors.
	LogError
)

var (
	LogLevelNames = map[string]Level{
		"debug":    LogDebug,
		"info":     LogInfo,
		"warn":     LogWarning,
		"warning":  LogWarning,
		"warnings": LogWarning,
		"error":    LogError,
		"errors":   LogError,
	}
	LogLevelDisplayNames = map[Level]string{
		LogDebug:   "debug",
		LogInfo:    "info",
		LogWarning: "warning",
		LogError:   "error",
	}
)

// Manager is the main interface used to log debug/info/error messages.
type Manager struct {
	loggers         []singleLogger
	stdoutWriteLock sync.Mutex // use one lock for both stdout and stderr
	fileWriteLock   sync.Mutex
	DumpingRawInOut bool
}

// Config represents the configuration of a single logger.
type Config struct {
	// logging methods
	MethodStdout bool
	MethodStderr bool
	MethodFile   bool
	Filename     string
	// logging level
	Level Level
	// logging types
	Types         []string
	ExcludedTypes []string
}

// NewManager returns a new log manager.
func NewManager(config ...Config) (*Manager, error) {
	var logger Manager

	for _, logConfig := range config {
		typeMap := make(map[string]bool)
		for _, name := range logConfig.Types {
			typeMap[name] = true
		}
		excludedTypeMap := make(map[string]bool)
		for _, name := range logConfig.ExcludedTypes {
			excludedTypeMap[name] = true
		}

		sLogger := singleLogger{
			MethodSTDOUT: logConfig.MethodStdout,
			MethodSTDERR: logConfig.MethodStderr,
			MethodFile: fileMethod{
				Enabled:  logConfig.MethodFile,
				Filename: logConfig.Filename,
			},
			Level:           logConfig.Level,
			Types:           typeMap,
			ExcludedTypes:   excludedTypeMap,
			stdoutWriteLock: &logger.stdoutWriteLock,
			fileWriteLock:   &logger.fileWriteLock,
		}
		if typeMap["userinput"] || typeMap["useroutput"] || (typeMap["*"] && !(excludedTypeMap["userinput"] && excludedTypeMap["useroutput"])) {
			logger.DumpingRawInOut = true
		}
		if sLogger.MethodFile.Enabled {
			file, err := os.OpenFile(sLogger.MethodFile.Filename, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0666)
			if err != nil {
				return nil, fmt.Errorf("Could not open log file %s [%s]", sLogger.MethodFile.Filename, err.Error())
			}
			writer := bufio.NewWriter(file)
			sLogger.MethodFile.File = file
			sLogger.MethodFile.Writer = writer
		}
		logger.loggers = append(logger.loggers, sLogger)
	}

	return &logger, nil
}

// Log logs the given message with the given details.
func (logger *Manager) Log(level Level, logType string, messageParts ...string) {
	for _, singleLogger := range logger.loggers {
		singleLogger.Log(level, logType, messageParts...)
	}
}

// Debug logs the given message as a debug message.
func (logger *Manager) Debug(logType string, messageParts ...string) {
	for _, singleLogger := range logger.loggers {
		singleLogger.Log(LogDebug, logType, messageParts...)
	}
}

// Info logs the given message as an info message.
func (logger *Manager) Info(logType string, messageParts ...string) {
	for _, singleLogger := range logger.loggers {
		singleLogger.Log(LogInfo, logType, messageParts...)
	}
}

// Warning logs the given message as a warning message.
func (logger *Manager) Warning(logType string, messageParts ...string) {
	for _, singleLogger := range logger.loggers {
		singleLogger.Log(LogWarning, logType, messageParts...)
	}
}

// Error logs the given message as an error message.
func (logger *Manager) Error(logType string, messageParts ...string) {
	for _, singleLogger := range logger.loggers {
		singleLogger.Log(LogError, logType, messageParts...)
	}
}

// Fatal logs the given message as an error message, then exits.
func (logger *Manager) Fatal(logType string, messageParts ...string) {
	logger.Error(logType, messageParts...)
	logger.Error("FATAL", "Fatal error encountered, application exiting")
	os.Exit(1)
}

type fileMethod struct {
	Enabled  bool
	Filename string
	File     *os.File
	Writer   *bufio.Writer
}

// singleLogger represents a single logger instance.
type singleLogger struct {
	stdoutWriteLock *sync.Mutex
	fileWriteLock   *sync.Mutex
	MethodSTDOUT    bool
	MethodSTDERR    bool
	MethodFile      fileMethod
	Level           Level
	Types           map[string]bool
	ExcludedTypes   map[string]bool
}

// Log logs the given message with the given details.
func (logger *singleLogger) Log(level Level, logType string, messageParts ...string) {
	// no logging enabled
	if !(logger.MethodSTDOUT || logger.MethodSTDERR || logger.MethodFile.Enabled) {
		return
	}

	// ensure we're logging to the given level
	if level < logger.Level {
		return
	}

	// ensure we're capturing this logType
	logTypeCleaned := strings.ToLower(strings.TrimSpace(logType))
	capturing := (logger.Types["*"] || logger.Types[logTypeCleaned]) && !logger.ExcludedTypes["*"] && !logger.ExcludedTypes[logTypeCleaned]
	if !capturing {
		return
	}

	// assemble full line
	timeGrey := ansi.ColorFunc("243")
	grey := ansi.ColorFunc("8")
	alert := ansi.ColorFunc("232+b:red")
	warn := ansi.ColorFunc("black:214")
	info := ansi.ColorFunc("117")
	debug := ansi.ColorFunc("78")
	section := ansi.ColorFunc("229")

	levelDisplay := LogLevelDisplayNames[level]
	if level == LogError {
		levelDisplay = alert(levelDisplay)
	} else if level == LogWarning {
		levelDisplay = warn(levelDisplay)
	} else if level == LogInfo {
		levelDisplay = info(levelDisplay)
	} else if level == LogDebug {
		levelDisplay = debug(levelDisplay)
	}

	sep := grey(":")
	fullStringFormatted := fmt.Sprintf("%s %s %s %s %s %s ", timeGrey(time.Now().UTC().Format("2006-01-02T15:04:05Z")), sep, levelDisplay, sep, section(logType), sep)
	fullStringRaw := fmt.Sprintf("%s : %s : %s : ", time.Now().UTC().Format("2006-01-02T15:04:05Z"), LogLevelDisplayNames[level], logType)
	for i, p := range messageParts {
		fullStringFormatted += p
		fullStringRaw += p
		if i != len(messageParts)-1 {
			fullStringFormatted += " " + sep + " "
			fullStringRaw += " : "
		}
	}

	// output
	if logger.MethodSTDOUT {
		logger.stdoutWriteLock.Lock()
		fmt.Fprintln(colorable.NewColorableStdout(), fullStringFormatted)
		logger.stdoutWriteLock.Unlock()
	}
	if logger.MethodSTDERR {
		logger.stdoutWriteLock.Lock()
		fmt.Fprintln(colorable.NewColorableStderr(), fullStringFormatted)
		logger.stdoutWriteLock.Unlock()
	}
	if logger.MethodFile.Enabled {
		logger.fileWriteLock.Lock()
		logger.MethodFile.Writer.WriteString(fullStringRaw + "\n")
		logger.fileWriteLock.Unlock()
	}
}
<commit_msg>logger: Flush file writes to ensure they get written out<commit_after>// Copyright (c) 2017 Daniel Oaks <daniel@danieloaks.net>
// released under the MIT license

package logger

import (
	"bufio"
	"fmt"
	"os"
	"time"

	"strings"

	"sync"

	colorable "github.com/mattn/go-colorable"
	"github.com/mgutz/ansi"
)

// Level represents the level to log messages at.
type Level int

const (
	// LogDebug represents debug messages.
	LogDebug Level = iota
	// LogInfo represents informational messages.
	LogInfo
	// LogWarning represents warnings.
	LogWarning
	// LogError represents errors.
	LogError
)

var (
	LogLevelNames = map[string]Level{
		"debug":    LogDebug,
		"info":     LogInfo,
		"warn":     LogWarning,
		"warning":  LogWarning,
		"warnings": LogWarning,
		"error":    LogError,
		"errors":   LogError,
	}
	LogLevelDisplayNames = map[Level]string{
		LogDebug:   "debug",
		LogInfo:    "info",
		LogWarning: "warning",
		LogError:   "error",
	}
)

// Manager is the main interface used to log debug/info/error messages.
type Manager struct {
	loggers         []singleLogger
	stdoutWriteLock sync.Mutex // use one lock for both stdout and stderr
	fileWriteLock   sync.Mutex
	DumpingRawInOut bool
}

// Config represents the configuration of a single logger.
type Config struct {
	// logging methods
	MethodStdout bool
	MethodStderr bool
	MethodFile   bool
	Filename     string
	// logging level
	Level Level
	// logging types
	Types         []string
	ExcludedTypes []string
}

// NewManager returns a new log manager.
func NewManager(config ...Config) (*Manager, error) {
	var logger Manager

	for _, logConfig := range config {
		typeMap := make(map[string]bool)
		for _, name := range logConfig.Types {
			typeMap[name] = true
		}
		excludedTypeMap := make(map[string]bool)
		for _, name := range logConfig.ExcludedTypes {
			excludedTypeMap[name] = true
		}

		sLogger := singleLogger{
			MethodSTDOUT: logConfig.MethodStdout,
			MethodSTDERR: logConfig.MethodStderr,
			MethodFile: fileMethod{
				Enabled:  logConfig.MethodFile,
				Filename: logConfig.Filename,
			},
			Level:           logConfig.Level,
			Types:           typeMap,
			ExcludedTypes:   excludedTypeMap,
			stdoutWriteLock: &logger.stdoutWriteLock,
			fileWriteLock:   &logger.fileWriteLock,
		}
		if typeMap["userinput"] || typeMap["useroutput"] || (typeMap["*"] && !(excludedTypeMap["userinput"] && excludedTypeMap["useroutput"])) {
			logger.DumpingRawInOut = true
		}
		if sLogger.MethodFile.Enabled {
			file, err := os.OpenFile(sLogger.MethodFile.Filename, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0666)
			if err != nil {
				return nil, fmt.Errorf("Could not open log file %s [%s]", sLogger.MethodFile.Filename, err.Error())
			}
			writer := bufio.NewWriter(file)
			sLogger.MethodFile.File = file
			sLogger.MethodFile.Writer = writer
		}
		logger.loggers = append(logger.loggers, sLogger)
	}

	return &logger, nil
}

// Log logs the given message with the given details.
func (logger *Manager) Log(level Level, logType string, messageParts ...string) {
	for _, singleLogger := range logger.loggers {
		singleLogger.Log(level, logType, messageParts...)
	}
}

// Debug logs the given message as a debug message.
func (logger *Manager) Debug(logType string, messageParts ...string) {
	for _, singleLogger := range logger.loggers {
		singleLogger.Log(LogDebug, logType, messageParts...)
	}
}

// Info logs the given message as an info message.
func (logger *Manager) Info(logType string, messageParts ...string) {
	for _, singleLogger := range logger.loggers {
		singleLogger.Log(LogInfo, logType, messageParts...)
	}
}

// Warning logs the given message as a warning message.
func (logger *Manager) Warning(logType string, messageParts ...string) {
	for _, singleLogger := range logger.loggers {
		singleLogger.Log(LogWarning, logType, messageParts...)
	}
}

// Error logs the given message as an error message.
func (logger *Manager) Error(logType string, messageParts ...string) {
	for _, singleLogger := range logger.loggers {
		singleLogger.Log(LogError, logType, messageParts...)
	}
}

// Fatal logs the given message as an error message, then exits.
func (logger *Manager) Fatal(logType string, messageParts ...string) {
	logger.Error(logType, messageParts...)
	logger.Error("FATAL", "Fatal error encountered, application exiting")
	os.Exit(1)
}

type fileMethod struct {
	Enabled  bool
	Filename string
	File     *os.File
	Writer   *bufio.Writer
}

// singleLogger represents a single logger instance.
type singleLogger struct {
	stdoutWriteLock *sync.Mutex
	fileWriteLock   *sync.Mutex
	MethodSTDOUT    bool
	MethodSTDERR    bool
	MethodFile      fileMethod
	Level           Level
	Types           map[string]bool
	ExcludedTypes   map[string]bool
}

// Log logs the given message with the given details.
func (logger *singleLogger) Log(level Level, logType string, messageParts ...string) {
	// no logging enabled
	if !(logger.MethodSTDOUT || logger.MethodSTDERR || logger.MethodFile.Enabled) {
		return
	}

	// ensure we're logging to the given level
	if level < logger.Level {
		return
	}

	// ensure we're capturing this logType
	logTypeCleaned := strings.ToLower(strings.TrimSpace(logType))
	capturing := (logger.Types["*"] || logger.Types[logTypeCleaned]) && !logger.ExcludedTypes["*"] && !logger.ExcludedTypes[logTypeCleaned]
	if !capturing {
		return
	}

	// assemble full line
	timeGrey := ansi.ColorFunc("243")
	grey := ansi.ColorFunc("8")
	alert := ansi.ColorFunc("232+b:red")
	warn := ansi.ColorFunc("black:214")
	info := ansi.ColorFunc("117")
	debug := ansi.ColorFunc("78")
	section := ansi.ColorFunc("229")

	levelDisplay := LogLevelDisplayNames[level]
	if level == LogError {
		levelDisplay = alert(levelDisplay)
	} else if level == LogWarning {
		levelDisplay = warn(levelDisplay)
	} else if level == LogInfo {
		levelDisplay = info(levelDisplay)
	} else if level == LogDebug {
		levelDisplay = debug(levelDisplay)
	}

	sep := grey(":")
	fullStringFormatted := fmt.Sprintf("%s %s %s %s %s %s ", timeGrey(time.Now().UTC().Format("2006-01-02T15:04:05Z")), sep, levelDisplay, sep, section(logType), sep)
	fullStringRaw := fmt.Sprintf("%s : %s : %s : ", time.Now().UTC().Format("2006-01-02T15:04:05Z"), LogLevelDisplayNames[level], logType)
	for i, p := range messageParts {
		fullStringFormatted += p
		fullStringRaw += p
		if i != len(messageParts)-1 {
			fullStringFormatted += " " + sep + " "
			fullStringRaw += " : "
		}
	}

	// output
	if logger.MethodSTDOUT {
		logger.stdoutWriteLock.Lock()
		fmt.Fprintln(colorable.NewColorableStdout(), fullStringFormatted)
		logger.stdoutWriteLock.Unlock()
	}
	if logger.MethodSTDERR {
		logger.stdoutWriteLock.Lock()
		fmt.Fprintln(colorable.NewColorableStderr(), fullStringFormatted)
		logger.stdoutWriteLock.Unlock()
	}
	if logger.MethodFile.Enabled {
		logger.fileWriteLock.Lock()
		logger.MethodFile.Writer.WriteString(fullStringRaw + "\n")
		logger.MethodFile.Writer.Flush()
		logger.fileWriteLock.Unlock()
	}
}
<|endoftext|>


<commit_before>// This is a work in progress to show how to Sign/Unsign It's Dangerous
// style tokens.

package goalone

import (
	"crypto/sha1"
	"crypto/subtle"
	"encoding/base64"
	"testing"
)

const (
	// ItsDangerousEpoch is the default epoch used by It's Dangerous
	ItsDangerousEpoch = 1293840000
	// ItsDangerousDerivation is the default Derivation used by It's Dangerous
	ItsDangerousDerivation = `django-concat`
)

var (
	// ItsDangerousSignerSalt is the default salt used by the It's Dangerous
	// "Signer" signer
	ItsDangerousSignerSalt = []byte(`itsdangerous.Signer`)
	// ItsDangerousSerializerSalt is the default salt used by the It's Dangerous
	// "Serializer" and "URLSafeSerializer" signers
	ItsDangerousSerializerSalt = []byte(`itsdangerous`)
)

// This test provides an example and a compatability test to the itsdangerous
// "Signer" signer.  This signer uses "Salt" by default, which is combined
// with the secret key and sha1.Sum'd.  Following this example you should be
// able to sign or unsign this type of itsdangerous token.
func TestItsDangerousSigner(t *testing.T) {

	// payload is the information that we're going to sign
	payload := []byte("my string")

	// key is the secret "password" used to sign the payload
	key := []byte(`secret-key`)

	// want is what we expect returned from Sign, this is the example
	// shown in the itsdangerous documentation for this signer
	want := []byte(`my string.wh6tMHxLgJqB6oY1uT73iMlyrOA`)

	// Take the key and add the default Signer Salt, combined with "signer" then
	// create a sha1.Sum of the result and uses that as the key
	key = append(append(ItsDangerousSignerSalt, []byte(`signer`)...), key...)
	ks := sha1.Sum(key)

	// Now, Sign the payload with the key.
	got := New(ks[:], nil).Sign(payload)

	// Test to make sure it worked and returned the right response.
	if subtle.ConstantTimeCompare(got, want) != 1 {
		t.Logf("payload : \n%s\n", payload)
		t.Logf("want    : \n%s\n", want)
		t.Logf("got     : \n%s\n", got)
		t.Fatal("got and want do not match")
	}
}

// This test provides an example and a compatability test to the itsdangerous
// Serializer signer.  This signer uses "Salt" by default, which is combined
// with the secret key and sha1.Sum'd.  Following this example you should be
// able to sign or unsign this type of itsdangerous token.
func TestItsDangerousSerializer(t *testing.T) {

	// payload is the information that we're going to sign
	payload := []byte("[1, 2, 3, 4]")

	// key is the secret "password" used to sign the payload
	key := []byte(`secret-key`)

	// want is what we expect returned from Sign, this is the example
	// shown in the itsdangerous documentation for this signer
	want := []byte("[1, 2, 3, 4].r7R9RhGgDPvvWl3iNzLuIIfELmo")

	// Take the key and add the default Serializer Salt, combined with
	// "signer" then create a sha1.Sum of the result and uses that as the key
	key = append(append(ItsDangerousSerializerSalt, []byte(`signer`)...), key...)
	ks := sha1.Sum(key)

	// Now, Sign the payload with the key.
	got := New(ks[:], nil).Sign(payload)

	// Test to make sure it worked and returned the right response.
	if subtle.ConstantTimeCompare(got, want) != 1 {
		t.Logf("payload : \n%s\n", payload)
		t.Logf("want    : \n%s\n", want)
		t.Logf("got     : \n%s\n", got)
		t.Fatal("got and want do not match")
	}
}

// This test provides an example and a compatability test to the itsdangerous
// URLSafeSerializer signer.  This signer uses "Salt" by default, which is
// combined with the secret key and sha1.Sum'd.  Following this example you
// should be able to sign or unsign this type of itsdangerous token.
func TestItsDangerousURLSafeSerializer(t *testing.T) {

	// payload is the information that we're going to sign
	payload := []byte("[1,2,3,4]")
	//	payload := []byte("WzEsMiwzLDRd")

	// key is the secret "password" used to sign the payload
	key := []byte(`secret-key`)

	// want is what we expect returned from Sign, this is the example
	// shown in the itsdangerous documentation for this signer.
	want := []byte("WzEsMiwzLDRd.wSPHqC0gR7VUqivlSukJ0IeTDgo")

	// Take the key and add the default Serializer Salt, combined with
	// "signer" then create a sha1.Sum of the result and uses that as the key
	key = append(append(ItsDangerousSerializerSalt, []byte(`signer`)...), key...)
	ks := sha1.Sum(key)

	// First, Base64 URL encode the payload

	ep := base64.RawURLEncoding.EncodeToString(payload)

	// Now, Sign the payload with the key.
	got := New(ks[:], nil).Sign([]byte(ep))

	// Test to make sure it worked and returned the right response.
	if subtle.ConstantTimeCompare(got, want) != 1 {
		t.Logf("payload : \n%s\n", payload)
		t.Logf("want    : \n%s\n", want)
		t.Logf("got     : \n%s\n", got)
		t.Fatal("got and want do not match")
	}
}
<commit_msg>Spelling.<commit_after>// This is a work in progress to show how to Sign/Unsign It's Dangerous
// style tokens.

package goalone

import (
	"crypto/sha1"
	"crypto/subtle"
	"encoding/base64"
	"testing"
)

const (
	// ItsDangerousEpoch is the default epoch used by It's Dangerous
	ItsDangerousEpoch = 1293840000
	// ItsDangerousDerivation is the default Derivation used by It's Dangerous
	ItsDangerousDerivation = `django-concat`
)

var (
	// ItsDangerousSignerSalt is the default salt used by the It's Dangerous
	// "Signer" signer
	ItsDangerousSignerSalt = []byte(`itsdangerous.Signer`)
	// ItsDangerousSerializerSalt is the default salt used by the It's Dangerous
	// "Serializer" and "URLSafeSerializer" signers
	ItsDangerousSerializerSalt = []byte(`itsdangerous`)
)

// This test provides an example and a compatibility test to the itsdangerous
// "Signer" signer.  This signer uses "Salt" by default, which is combined
// with the secret key and sha1.Sum'd.  Following this example you should be
// able to sign or unsign this type of itsdangerous token.
func TestItsDangerousSigner(t *testing.T) {

	// payload is the information that we're going to sign
	payload := []byte("my string")

	// key is the secret "password" used to sign the payload
	key := []byte(`secret-key`)

	// want is what we expect returned from Sign, this is the example
	// shown in the itsdangerous documentation for this signer
	want := []byte(`my string.wh6tMHxLgJqB6oY1uT73iMlyrOA`)

	// Take the key and add the default Signer Salt, combined with "signer" then
	// create a sha1.Sum of the result and uses that as the key
	key = append(append(ItsDangerousSignerSalt, []byte(`signer`)...), key...)
	ks := sha1.Sum(key)

	// Now, Sign the payload with the key.
	got := New(ks[:], nil).Sign(payload)

	// Test to make sure it worked and returned the right response.
	if subtle.ConstantTimeCompare(got, want) != 1 {
		t.Logf("payload : \n%s\n", payload)
		t.Logf("want    : \n%s\n", want)
		t.Logf("got     : \n%s\n", got)
		t.Fatal("got and want do not match")
	}
}

// This test provides an example and a compatibility test to the itsdangerous
// Serializer signer.  This signer uses "Salt" by default, which is combined
// with the secret key and sha1.Sum'd.  Following this example you should be
// able to sign or unsign this type of itsdangerous token.
func TestItsDangerousSerializer(t *testing.T) {

	// payload is the information that we're going to sign
	payload := []byte("[1, 2, 3, 4]")

	// key is the secret "password" used to sign the payload
	key := []byte(`secret-key`)

	// want is what we expect returned from Sign, this is the example
	// shown in the itsdangerous documentation for this signer
	want := []byte("[1, 2, 3, 4].r7R9RhGgDPvvWl3iNzLuIIfELmo")

	// Take the key and add the default Serializer Salt, combined with
	// "signer" then create a sha1.Sum of the result and uses that as the key
	key = append(append(ItsDangerousSerializerSalt, []byte(`signer`)...), key...)
	ks := sha1.Sum(key)

	// Now, Sign the payload with the key.
	got := New(ks[:], nil).Sign(payload)

	// Test to make sure it worked and returned the right response.
	if subtle.ConstantTimeCompare(got, want) != 1 {
		t.Logf("payload : \n%s\n", payload)
		t.Logf("want    : \n%s\n", want)
		t.Logf("got     : \n%s\n", got)
		t.Fatal("got and want do not match")
	}
}

// This test provides an example and a compatibility test to the itsdangerous
// URLSafeSerializer signer.  This signer uses "Salt" by default, which is
// combined with the secret key and sha1.Sum'd.  Following this example you
// should be able to sign or unsign this type of itsdangerous token.
func TestItsDangerousURLSafeSerializer(t *testing.T) {

	// payload is the information that we're going to sign
	payload := []byte("[1,2,3,4]")
	//	payload := []byte("WzEsMiwzLDRd")

	// key is the secret "password" used to sign the payload
	key := []byte(`secret-key`)

	// want is what we expect returned from Sign, this is the example
	// shown in the itsdangerous documentation for this signer.
	want := []byte("WzEsMiwzLDRd.wSPHqC0gR7VUqivlSukJ0IeTDgo")

	// Take the key and add the default Serializer Salt, combined with
	// "signer" then create a sha1.Sum of the result and uses that as the key
	key = append(append(ItsDangerousSerializerSalt, []byte(`signer`)...), key...)
	ks := sha1.Sum(key)

	// First, Base64 URL encode the payload

	ep := base64.RawURLEncoding.EncodeToString(payload)

	// Now, Sign the payload with the key.
	got := New(ks[:], nil).Sign([]byte(ep))

	// Test to make sure it worked and returned the right response.
	if subtle.ConstantTimeCompare(got, want) != 1 {
		t.Logf("payload : \n%s\n", payload)
		t.Logf("want    : \n%s\n", want)
		t.Logf("got     : \n%s\n", got)
		t.Fatal("got and want do not match")
	}
}
<|endoftext|>


<commit_before>// © 2012 the Minima Authors under the MIT license. See AUTHORS for the list of authors.
// Copyright 2012 The Plotinum Authors.

package ui

import (
	"image"
	"image/color"
	"image/draw"
	"io/ioutil"
	"os"

	"github.com/golang/freetype"
	"github.com/golang/freetype/truetype"
)

const (
	// PxInch is the number of pixels in an inch.
	// 72 seems to make font sizes consistent with
	// SDL_ttf…
	pxInch = 72.0

	// PtInch is the number of Postscript points in an inch.
	ptInch = 72.0
)

type glyphKey struct {
	rune       rune
	size       float64
	r, g, b, a uint32
}

// A font is a size and style in which text can be
// rendered to an image.
type font struct {
	// Size is the size of the font in points.
	size float64

	// color is the current color.
	color color.Color

	// Ttf is the truetype font handle.
	ttf *truetype.Font

	// Ctx is the freetype drawing context for this
	// font, size, and color.
	ctx *freetype.Context

	// Glyphs is a cache of pre-rendered glyphs.
	glyphs map[glyphKey]image.Image
}

// NewFont returns a new font loaded from a .ttf file.
// The default size is 12 points, and the default color
// is black.
func newFont(path string) (*font, error) {
	file, err := os.Open(path)
	if err != nil {
		return nil, err
	}
	defer file.Close()

	bytes, err := ioutil.ReadAll(file)
	if err != nil {
		return nil, err
	}

	ttf, err := freetype.ParseFont(bytes)
	if err != nil {
		return nil, err
	}

	const defaultSize = 12.
	defaultColor := color.RGBA{0, 0, 0, 255}
	ctx := freetype.NewContext()
	ctx.SetFont(ttf)
	ctx.SetDPI(pxInch)

	return &font{
		size:   defaultSize,
		color:  defaultColor,
		ttf:    ttf,
		ctx:    ctx,
		glyphs: make(map[glyphKey]image.Image),
	}, nil
}

// SetSize sets the font size.
func (f *font) setSize(sz float64) {
	f.size = sz
}

// SetColor sets the font color.
func (f *font) setColor(col color.Color) {
	f.color = col
}

// fontExtents describes some size attributes of all text
// rendered in this font.
type fontExtents struct {

	// Height is the height of the font in pixels.
	// The height is size used to create the font, and it
	// can be used as a reasonable line spacing.
	height int

	// Ascent is the distance in pixels from the baseline
	// (the y-value given as the font's drawing location
	// to the highest point of a rasterized glyph.
	ascent int

	// Decent is the distance in pixels from the baseline
	// to the lowest point of a rasterized glyph.  The
	// descent extents below the baseline so it is always
	// a negative value.
	descent int
}

// Extents returns the extents of a font.
func (f *font) extents() fontExtents {
	em := f.ttf.FUnitsPerEm()
	bounds := f.ttf.Bounds(em)
	scale := (f.size / ptInch * pxInch) / float64(em)
	a := int(float64(bounds.YMax)*scale + 0.5)
	d := int(float64(bounds.YMin)*scale - 0.5)
	return fontExtents{
		height:  a - d,
		ascent:  a,
		descent: d,
	}
}

// Width returns width of a string in pixels.
func (f *font) width(s string) int {
	em := f.ttf.FUnitsPerEm()
	var width int32
	prev, hasPrev := truetype.Index(0), false
	for _, r := range s {
		index := f.ttf.Index(r)
		if hasPrev {
			width += f.ttf.Kerning(em, prev, index)
		}
		width += f.ttf.HMetric(em, index).AdvanceWidth
		prev, hasPrev = index, true
	}
	scale := (f.size / ptInch * pxInch) / float64(em)
	return int(float64(width)*scale + 0.5)
}

// Render returns an image of the given string.
func (f *font) render(s string) (image.Image, error) {
	w, h := f.width(s), f.extents().height
	img := image.NewRGBA(image.Rect(0, 0, int(w), int(h)))

	em := f.ttf.FUnitsPerEm()
	scale := (f.size / ptInch * pxInch) / float64(em)

	var x int32
	prev, hasPrev := truetype.Index(0), false
	for _, r := range s {
		index := f.ttf.Index(r)
		if hasPrev {
			x += f.ttf.Kerning(em, prev, index)
		}

		g, err := f.glyph(r)
		if err != nil {
			return nil, err
		}
		b := g.Bounds().Add(image.Pt(int(float64(x)*scale), 0))
		draw.Draw(img, b, g, image.ZP, draw.Src)

		x += f.ttf.HMetric(em, index).AdvanceWidth
		prev, hasPrev = index, true
	}

	return img, nil
}

// Glyph returns an image.Image containing the glyph.
// If the glyph is in the cache then that is returned,
// otherwise the glyph is rendered, cached, and returned.
func (f *font) glyph(ru rune) (image.Image, error) {
	r, g, b, a := f.color.RGBA()
	key := glyphKey{
		rune: ru,
		size: f.size,
		r:    r,
		g:    g,
		b:    b,
		a:    a,
	}
	if img, ok := f.glyphs[key]; ok {
		return img, nil
	}
	s := string([]rune{ru})
	w := f.width(s)
	ext := f.extents()
	h := ext.height

	img := image.NewRGBA(image.Rect(0, 0, int(w), int(h)))
	f.ctx.SetFontSize(f.size)
	f.ctx.SetSrc(image.NewUniform(f.color))
	f.ctx.SetClip(img.Bounds())
	f.ctx.SetDst(img)

	pt := freetype.Pt(0, int(h+ext.descent))
	if _, err := f.ctx.DrawString(s, pt); err != nil {
		return nil, err
	}

	f.glyphs[key] = img

	return img, nil
}
<commit_msg>Naively smash some font API changes<commit_after>// © 2012 the Minima Authors under the MIT license. See AUTHORS for the list of authors.
// Copyright 2012 The Plotinum Authors.

package ui

import (
	"image"
	"image/color"
	"image/draw"
	"io/ioutil"
	"os"

	"github.com/golang/freetype"
	"github.com/golang/freetype/truetype"
	"golang.org/x/image/math/fixed"
)

const (
	// PxInch is the number of pixels in an inch.
	// 72 seems to make font sizes consistent with
	// SDL_ttf…
	pxInch = 72.0

	// PtInch is the number of Postscript points in an inch.
	ptInch = 72.0
)

type glyphKey struct {
	rune       rune
	size       float64
	r, g, b, a uint32
}

// A font is a size and style in which text can be
// rendered to an image.
type font struct {
	// Size is the size of the font in points.
	size float64

	// color is the current color.
	color color.Color

	// Ttf is the truetype font handle.
	ttf *truetype.Font

	// Ctx is the freetype drawing context for this
	// font, size, and color.
	ctx *freetype.Context

	// Glyphs is a cache of pre-rendered glyphs.
	glyphs map[glyphKey]image.Image
}

// NewFont returns a new font loaded from a .ttf file.
// The default size is 12 points, and the default color
// is black.
func newFont(path string) (*font, error) {
	file, err := os.Open(path)
	if err != nil {
		return nil, err
	}
	defer file.Close()

	bytes, err := ioutil.ReadAll(file)
	if err != nil {
		return nil, err
	}

	ttf, err := freetype.ParseFont(bytes)
	if err != nil {
		return nil, err
	}

	const defaultSize = 12.
	defaultColor := color.RGBA{0, 0, 0, 255}
	ctx := freetype.NewContext()
	ctx.SetFont(ttf)
	ctx.SetDPI(pxInch)

	return &font{
		size:   defaultSize,
		color:  defaultColor,
		ttf:    ttf,
		ctx:    ctx,
		glyphs: make(map[glyphKey]image.Image),
	}, nil
}

// SetSize sets the font size.
func (f *font) setSize(sz float64) {
	f.size = sz
}

// SetColor sets the font color.
func (f *font) setColor(col color.Color) {
	f.color = col
}

// fontExtents describes some size attributes of all text
// rendered in this font.
type fontExtents struct {

	// Height is the height of the font in pixels.
	// The height is size used to create the font, and it
	// can be used as a reasonable line spacing.
	height int

	// Ascent is the distance in pixels from the baseline
	// (the y-value given as the font's drawing location
	// to the highest point of a rasterized glyph.
	ascent int

	// Decent is the distance in pixels from the baseline
	// to the lowest point of a rasterized glyph.  The
	// descent extents below the baseline so it is always
	// a negative value.
	descent int
}

// Extents returns the extents of a font.
func (f *font) extents() fontExtents {
	em := f.ttf.FUnitsPerEm()
	bounds := f.ttf.Bounds(fixed.I(int(em)))
	scale := (f.size / ptInch * pxInch) / float64(em)
	a := int(float64(bounds.Max.Y)*scale + 0.5)
	d := int(float64(bounds.Min.Y)*scale - 0.5)
	return fontExtents{
		height:  a - d,
		ascent:  a,
		descent: d,
	}
}

// Width returns width of a string in pixels.
func (f *font) width(s string) int {
	em := f.ttf.FUnitsPerEm()
	var width fixed.Int26_6
	prev, hasPrev := truetype.Index(0), false
	for _, r := range s {
		index := f.ttf.Index(r)
		if hasPrev {
			width += f.ttf.Kern(fixed.I(int(em)), prev, index)
		}
		width += f.ttf.HMetric(fixed.I(int(em)), index).AdvanceWidth
		prev, hasPrev = index, true
	}
	scale := (f.size / ptInch * pxInch) / float64(em)
	return int(float64(width)*scale + 0.5)
}

// Render returns an image of the given string.
func (f *font) render(s string) (image.Image, error) {
	w, h := f.width(s), f.extents().height
	img := image.NewRGBA(image.Rect(0, 0, int(w), int(h)))

	em := f.ttf.FUnitsPerEm()
	scale := (f.size / ptInch * pxInch) / float64(em)

	var x fixed.Int26_6
	prev, hasPrev := truetype.Index(0), false
	for _, r := range s {
		index := f.ttf.Index(r)
		if hasPrev {
			x += f.ttf.Kern(fixed.I(int(em)), prev, index)
		}

		g, err := f.glyph(r)
		if err != nil {
			return nil, err
		}
		b := g.Bounds().Add(image.Pt(int(float64(x)*scale), 0))
		draw.Draw(img, b, g, image.ZP, draw.Src)

		x += f.ttf.HMetric(fixed.I(int(em)), index).AdvanceWidth
		prev, hasPrev = index, true
	}

	return img, nil
}

// Glyph returns an image.Image containing the glyph.
// If the glyph is in the cache then that is returned,
// otherwise the glyph is rendered, cached, and returned.
func (f *font) glyph(ru rune) (image.Image, error) {
	r, g, b, a := f.color.RGBA()
	key := glyphKey{
		rune: ru,
		size: f.size,
		r:    r,
		g:    g,
		b:    b,
		a:    a,
	}
	if img, ok := f.glyphs[key]; ok {
		return img, nil
	}
	s := string([]rune{ru})
	w := f.width(s)
	ext := f.extents()
	h := ext.height

	img := image.NewRGBA(image.Rect(0, 0, int(w), int(h)))
	f.ctx.SetFontSize(f.size)
	f.ctx.SetSrc(image.NewUniform(f.color))
	f.ctx.SetClip(img.Bounds())
	f.ctx.SetDst(img)

	pt := freetype.Pt(0, int(h+ext.descent))
	if _, err := f.ctx.DrawString(s, pt); err != nil {
		return nil, err
	}

	f.glyphs[key] = img

	return img, nil
}
<|endoftext|>


<commit_before>package eveConsumer

import (
	"context"
	"database/sql"
	"fmt"
	"log"
	"net/http"
	"strconv"
	"strings"

	"github.com/antihax/evedata/models"
	"github.com/antihax/goesi"
	"github.com/antihax/goesi/v1"
	"github.com/garyburd/redigo/redis"

	"golang.org/x/oauth2"
)

func init() {
	addConsumer("contactSync", contactSyncConsumer, "EVEDATA_contactSyncQueue")
	addTrigger("contactSync", contactSyncTrigger)
}

// Perform contact sync for wardecs
func contactSyncTrigger(c *EVEConsumer) (bool, error) {

	// Do quick maintenence to prevent errors.
	err := models.MaintContactSync()
	if err != nil {
		return false, err
	}

	// Gather characters for update. Group for optimized updating.
	rows, err := c.ctx.Db.Query(
		`SELECT source, group_concat(destination)
			FROM evedata.contactSyncs S
            INNER JOIN evedata.crestTokens T ON T.tokenCharacterID = destination
            WHERE lastStatus NOT LIKE "%400 Bad Request%"
		    GROUP BY source
            HAVING max(nextSync) < UTC_TIMESTAMP();`)

	if err != nil && err != sql.ErrNoRows {
		return false, err
	} else if err == sql.ErrNoRows { // Shut up warnings
		return false, nil
	}
	defer rows.Close()

	r := c.ctx.Cache.Get()
	defer r.Close()

	// Loop updatable characters
	for rows.Next() {
		var (
			source int64  // Source char
			dest   string // List of destination chars
		)

		err = rows.Scan(&source, &dest)
		if err != nil {
			log.Printf("Contact Sync: Failed scan: %v", err)
			continue
		}

		_, err = r.Do("SADD", "EVEDATA_contactSyncQueue", fmt.Sprintf("%d:%s", source, dest))
		if err != nil {
			log.Printf("Contact Sync: Failed scan: %v", err)
			continue
		}
	}
	return true, err
}

func contactSyncConsumer(c *EVEConsumer, redisPtr *redis.Conn) (bool, error) {
	r := *redisPtr
	ret, err := r.Do("SPOP", "EVEDATA_contactSyncQueue")
	if err != nil {
		return false, err
	} else if ret == nil {
		return false, nil
	}
	v, err := redis.String(ret, err)
	if err != nil {
		return false, err
	}

	// Split off characters into an array
	dest := strings.Split(v, ":")
	destinations := strings.Split(dest[1], ",")
	source, err := strconv.ParseInt(dest[0], 10, 64)
	if err != nil {
		return false, err
	}

	// get the source character information
	char, _, err := c.ctx.ESI.V4.CharacterApi.GetCharactersCharacterId((int32)(source), nil)
	if err != nil {
		return false, err
	}

	corp, _, err := c.ctx.ESI.V3.CorporationApi.GetCorporationsCorporationId(char.CorporationId, nil)
	if err != nil {
		return false, err
	}

	// Find the Entity ID to search for wars.
	var searchID int32
	if corp.AllianceId > 0 {
		searchID = corp.AllianceId
	} else {
		searchID = char.CorporationId
	}

	// Map of tokens
	type characterToken struct {
		token *oauth2.TokenSource
		cid   int64
	}
	tokens := make(map[int64]characterToken)

	// Get the tokens for our destinations
	for _, cidS := range destinations {
		cid, _ := strconv.ParseInt(cidS, 10, 64)
		a, err := c.getToken(source, cid)
		if err != nil {
			return false, err
		}
		// Save the token.
		tokens[cid] = characterToken{token: &a, cid: cid}
	}

	// Active Wars
	activeWars, err := models.GetActiveWarsByID((int64)(searchID))
	if err != nil {
		return false, err
	}

	// Pending Wars
	pendingWars, err := models.GetPendingWarsByID((int64)(searchID))
	if err != nil {
		return false, err
	}

	// Faction Wars
	var factionWars []models.FactionWarEntities
	if corp.Faction != "" {
		factionWars, err = models.GetFactionWarEntitiesForID(models.FactionsByName[corp.Faction])
		if err != nil {
			return false, err
		}
	}

	// Loop through all the destinations
	for _, token := range tokens {
		// authentication token context for destination char
		auth := context.WithValue(context.TODO(), goesi.ContextOAuth2, *token.token)
		var (
			contacts []goesiv1.GetCharactersCharacterIdContacts200Ok
			r        *http.Response
			err      error
		)

		// Default to OK
		tokenSuccess(source, token.cid, 200, "OK")

		// Get current contacts
		for i := 1; ; i++ {
			var con []goesiv1.GetCharactersCharacterIdContacts200Ok
			con, r, err = c.ctx.ESI.V1.ContactsApi.GetCharactersCharacterIdContacts(auth, (int32)(token.cid), map[string]interface{}{"page": (int32)(i)})
			if err != nil || r.StatusCode != 200 {
				tokenError(source, token.cid, r, err)
				return false, err
			}
			if len(con) == 0 {
				break
			}
			contacts = append(contacts, con...)
		}

		// Update cache time.
		if r != nil {
			contactSync := &models.ContactSync{Source: source, Destination: token.cid}
			err := contactSync.Updated(goesi.CacheExpires(r))
			if err != nil {
				return false, err
			}
		}

		var erase []int32
		var active []int32
		var pending []int32
		var pendingMove []int32
		var activeMove []int32

		activeCheck := make(map[int32]bool)
		pendingCheck := make(map[int32]bool)

		// Build a map of active wars
		for _, war := range activeWars {
			activeCheck[(int32)(war.ID)] = true
		}

		// Add faction wars to the active list
		for _, war := range factionWars {
			activeCheck[(int32)(war.ID)] = true
		}

		// Build a map of pending wars
		for _, war := range pendingWars {
			pendingCheck[(int32)(war.ID)] = true
		}

		// Loop through all current contacts and figure out needed moves
		for _, contact := range contacts {
			// skip anything > -0.4
			if contact.Standing > -0.4 {
				continue
			}

			pend := pendingCheck[contact.ContactId]
			act := activeCheck[contact.ContactId]

			// Is this existing contact in the active list
			if !act {
				// Is this existing contact in the pending list
				if !pend { // Not in either list. delete it.
					erase = append(erase, (int32)(contact.ContactId))
				} else if pend && contact.Standing > -5.0 { // in pending list but wrong standing
					// Take it out of the active list and put into pending move.
					delete(pendingCheck, contact.ContactId)
					pendingMove = append(pendingMove, (int32)(contact.ContactId))
				} else if pend && contact.Standing == -5.0 { // Contact correct, do nothing.
					delete(pendingCheck, contact.ContactId)
				}
			} else if act && contact.Standing != -10.0 { // in active list, but wrong standing
				delete(activeCheck, contact.ContactId)
				activeMove = append(activeMove, (int32)(contact.ContactId))
			} else if act && contact.Standing == -10.0 { // Contact correct, do nothing.
				delete(activeCheck, contact.ContactId)
			}
		}

		// Build a list of active wars to add
		for con, _ := range activeCheck {
			active = append(active, con)
		}

		// Build a list of pending wars to add
		for con, _ := range pendingCheck {
			pending = append(pending, con)
		}

		// Erase contacts which have no wars.
		if len(erase) > 0 {
			for start := 0; start < len(erase); start = start + 20 {
				end := min(start+20, len(erase))
				r, err = c.ctx.ESI.V1.ContactsApi.DeleteCharactersCharacterIdContacts(auth, (int32)(token.cid), erase[start:end], nil)
				if err != nil {
					tokenError(source, token.cid, r, err)
					return false, err
				}
			}
		}
		// Add contacts for active wars
		if len(active) > 0 {
			for start := 0; start < len(active); start = start + 100 {
				end := min(start+100, len(active))
				_, r, err = c.ctx.ESI.V1.ContactsApi.PostCharactersCharacterIdContacts(auth, (int32)(token.cid), active[start:end], -10, nil)

				if err != nil {
					tokenError(source, token.cid, r, err)
					return false, err
				}
			}
		}
		// Add contacts for pending wars
		if len(pending) > 0 {
			for start := 0; start < len(pending); start = start + 100 {
				end := min(start+100, len(pending))
				_, r, err = c.ctx.ESI.V1.ContactsApi.PostCharactersCharacterIdContacts(auth, (int32)(token.cid), pending[start:end], -5, nil)
				if err != nil {
					tokenError(source, token.cid, r, err)
					return false, err
				}
			}
		}
		// Move contacts to active wars
		if len(activeMove) > 0 {
			for start := 0; start < len(activeMove); start = start + 20 {
				end := min(start+20, len(activeMove))
				r, err = c.ctx.ESI.V1.ContactsApi.PutCharactersCharacterIdContacts(auth, (int32)(token.cid), activeMove[start:end], -10, nil)
				if err != nil {
					tokenError(source, token.cid, r, err)
					return false, err
				}
			}
		}
		// Move contacts to pending wars
		if len(pendingMove) > 0 {
			for start := 0; start < len(pendingMove); start = start + 20 {
				end := min(start+20, len(pendingMove))
				r, err = c.ctx.ESI.V1.ContactsApi.PutCharactersCharacterIdContacts(auth, (int32)(token.cid), pendingMove[start:end], -5, nil)
				if err != nil {
					tokenError(source, token.cid, r, err)
					return false, err
				}
			}
		}
	}
	return true, err
}
<commit_msg>Fix unable to do syncs from alts to alts.<commit_after>package eveConsumer

import (
	"context"
	"database/sql"
	"fmt"
	"log"
	"net/http"
	"strconv"
	"strings"

	"github.com/antihax/evedata/models"
	"github.com/antihax/goesi"
	"github.com/antihax/goesi/v1"
	"github.com/garyburd/redigo/redis"

	"golang.org/x/oauth2"
)

func init() {
	addConsumer("contactSync", contactSyncConsumer, "EVEDATA_contactSyncQueue")
	addTrigger("contactSync", contactSyncTrigger)
}

// Perform contact sync for wardecs
func contactSyncTrigger(c *EVEConsumer) (bool, error) {

	// Do quick maintenence to prevent errors.
	err := models.MaintContactSync()
	if err != nil {
		return false, err
	}

	// Gather characters for update. Group for optimized updating.
	rows, err := c.ctx.Db.Query(
		`SELECT S.characterID, source, group_concat(destination)
			FROM evedata.contactSyncs S
            INNER JOIN evedata.crestTokens T ON T.tokenCharacterID = destination
            WHERE lastStatus NOT LIKE "%400 Bad Request%"
		    GROUP BY source
            HAVING max(nextSync) < UTC_TIMESTAMP();`)

	if err != nil && err != sql.ErrNoRows {
		return false, err
	} else if err == sql.ErrNoRows { // Shut up warnings
		return false, nil
	}
	defer rows.Close()

	r := c.ctx.Cache.Get()
	defer r.Close()

	// Loop updatable characters
	for rows.Next() {
		var (
			characterID int64
			source      int64  // Source char
			dest        string // List of destination chars
		)

		err = rows.Scan(&characterID, &source, &dest)
		if err != nil {
			log.Printf("Contact Sync: Failed scan: %v", err)
			continue
		}

		_, err = r.Do("SADD", "EVEDATA_contactSyncQueue", fmt.Sprintf("%d:%d:%s", characterID, source, dest))
		if err != nil {
			log.Printf("Contact Sync: Failed scan: %v", err)
			continue
		}
	}
	return true, err
}

func contactSyncConsumer(c *EVEConsumer, redisPtr *redis.Conn) (bool, error) {
	r := *redisPtr
	ret, err := r.Do("SPOP", "EVEDATA_contactSyncQueue")
	if err != nil {
		return false, err
	} else if ret == nil {
		return false, nil
	}
	v, err := redis.String(ret, err)
	if err != nil {
		return false, err
	}

	// Split off characters into an array
	dest := strings.Split(v, ":")
	destinations := strings.Split(dest[2], ",")
	characterID, err := strconv.ParseInt(dest[0], 10, 64)
	source, err := strconv.ParseInt(dest[1], 10, 64)
	if err != nil {
		return false, err
	}

	// get the source character information
	char, _, err := c.ctx.ESI.V4.CharacterApi.GetCharactersCharacterId((int32)(source), nil)
	if err != nil {
		return false, err
	}

	corp, _, err := c.ctx.ESI.V3.CorporationApi.GetCorporationsCorporationId(char.CorporationId, nil)
	if err != nil {
		return false, err
	}

	// Find the Entity ID to search for wars.
	var searchID int32
	if corp.AllianceId > 0 {
		searchID = corp.AllianceId
	} else {
		searchID = char.CorporationId
	}

	// Map of tokens
	type characterToken struct {
		token *oauth2.TokenSource
		cid   int64
	}
	tokens := make(map[int64]characterToken)

	// Get the tokens for our destinations
	for _, cidS := range destinations {
		cid, _ := strconv.ParseInt(cidS, 10, 64)
		a, err := c.getToken(characterID, cid)
		if err != nil {
			return false, err
		}
		// Save the token.
		tokens[cid] = characterToken{token: &a, cid: cid}
	}
	if source == 1962167517 {
		fmt.Printf("Found 1962167517 %+v\n", destinations)
	}
	// Active Wars
	activeWars, err := models.GetActiveWarsByID((int64)(searchID))
	if err != nil {
		return false, err
	}

	// Pending Wars
	pendingWars, err := models.GetPendingWarsByID((int64)(searchID))
	if err != nil {
		return false, err
	}

	// Faction Wars
	var factionWars []models.FactionWarEntities
	if corp.Faction != "" {
		factionWars, err = models.GetFactionWarEntitiesForID(models.FactionsByName[corp.Faction])
		if err != nil {
			return false, err
		}
	}

	// Loop through all the destinations
	for _, token := range tokens {
		// authentication token context for destination char
		auth := context.WithValue(context.TODO(), goesi.ContextOAuth2, *token.token)
		var (
			contacts []goesiv1.GetCharactersCharacterIdContacts200Ok
			r        *http.Response
			err      error
		)

		// Default to OK
		tokenSuccess(source, token.cid, 200, "OK")

		// Get current contacts
		for i := 1; ; i++ {
			var con []goesiv1.GetCharactersCharacterIdContacts200Ok
			con, r, err = c.ctx.ESI.V1.ContactsApi.GetCharactersCharacterIdContacts(auth, (int32)(token.cid), map[string]interface{}{"page": (int32)(i)})
			if err != nil || r.StatusCode != 200 {
				tokenError(source, token.cid, r, err)
				return false, err
			}
			if len(con) == 0 {
				break
			}
			contacts = append(contacts, con...)
		}

		// Update cache time.
		if r != nil {
			contactSync := &models.ContactSync{Source: source, Destination: token.cid}
			err := contactSync.Updated(goesi.CacheExpires(r))
			if err != nil {
				return false, err
			}
		}

		var erase []int32
		var active []int32
		var pending []int32
		var pendingMove []int32
		var activeMove []int32

		activeCheck := make(map[int32]bool)
		pendingCheck := make(map[int32]bool)

		// Build a map of active wars
		for _, war := range activeWars {
			activeCheck[(int32)(war.ID)] = true
		}

		// Add faction wars to the active list
		for _, war := range factionWars {
			activeCheck[(int32)(war.ID)] = true
		}

		// Build a map of pending wars
		for _, war := range pendingWars {
			pendingCheck[(int32)(war.ID)] = true
		}

		// Loop through all current contacts and figure out needed moves
		for _, contact := range contacts {
			// skip anything > -0.4
			if contact.Standing > -0.4 {
				continue
			}

			pend := pendingCheck[contact.ContactId]
			act := activeCheck[contact.ContactId]

			// Is this existing contact in the active list
			if !act {
				// Is this existing contact in the pending list
				if !pend { // Not in either list. delete it.
					erase = append(erase, (int32)(contact.ContactId))
				} else if pend && contact.Standing > -5.0 { // in pending list but wrong standing
					// Take it out of the active list and put into pending move.
					delete(pendingCheck, contact.ContactId)
					pendingMove = append(pendingMove, (int32)(contact.ContactId))
				} else if pend && contact.Standing == -5.0 { // Contact correct, do nothing.
					delete(pendingCheck, contact.ContactId)
				}
			} else if act && contact.Standing != -10.0 { // in active list, but wrong standing
				delete(activeCheck, contact.ContactId)
				activeMove = append(activeMove, (int32)(contact.ContactId))
			} else if act && contact.Standing == -10.0 { // Contact correct, do nothing.
				delete(activeCheck, contact.ContactId)
			}
		}

		// Build a list of active wars to add
		for con, _ := range activeCheck {
			active = append(active, con)
		}

		// Build a list of pending wars to add
		for con, _ := range pendingCheck {
			pending = append(pending, con)
		}

		// Erase contacts which have no wars.
		if len(erase) > 0 {
			for start := 0; start < len(erase); start = start + 20 {
				end := min(start+20, len(erase))
				r, err = c.ctx.ESI.V1.ContactsApi.DeleteCharactersCharacterIdContacts(auth, (int32)(token.cid), erase[start:end], nil)
				if err != nil {
					tokenError(source, token.cid, r, err)
					return false, err
				}
			}
		}
		// Add contacts for active wars
		if len(active) > 0 {
			for start := 0; start < len(active); start = start + 100 {
				end := min(start+100, len(active))
				_, r, err = c.ctx.ESI.V1.ContactsApi.PostCharactersCharacterIdContacts(auth, (int32)(token.cid), active[start:end], -10, nil)

				if err != nil {
					tokenError(source, token.cid, r, err)
					return false, err
				}
			}
		}
		// Add contacts for pending wars
		if len(pending) > 0 {
			for start := 0; start < len(pending); start = start + 100 {
				end := min(start+100, len(pending))
				_, r, err = c.ctx.ESI.V1.ContactsApi.PostCharactersCharacterIdContacts(auth, (int32)(token.cid), pending[start:end], -5, nil)
				if err != nil {
					tokenError(source, token.cid, r, err)
					return false, err
				}
			}
		}
		// Move contacts to active wars
		if len(activeMove) > 0 {
			for start := 0; start < len(activeMove); start = start + 20 {
				end := min(start+20, len(activeMove))
				r, err = c.ctx.ESI.V1.ContactsApi.PutCharactersCharacterIdContacts(auth, (int32)(token.cid), activeMove[start:end], -10, nil)
				if err != nil {
					tokenError(source, token.cid, r, err)
					return false, err
				}
			}
		}
		// Move contacts to pending wars
		if len(pendingMove) > 0 {
			for start := 0; start < len(pendingMove); start = start + 20 {
				end := min(start+20, len(pendingMove))
				r, err = c.ctx.ESI.V1.ContactsApi.PutCharactersCharacterIdContacts(auth, (int32)(token.cid), pendingMove[start:end], -5, nil)
				if err != nil {
					tokenError(source, token.cid, r, err)
					return false, err
				}
			}
		}
	}
	return true, err
}
<|endoftext|>


<commit_before>package types

import (
	"os"
	"time"

	"github.com/docker/docker/daemon/network"
	"github.com/docker/docker/pkg/version"
	"github.com/docker/docker/runconfig"
)

// ContainerCreateResponse contains the information returned to a client on the
// creation of a new container.
type ContainerCreateResponse struct {
	// ID is the ID of the created container.
	ID string `json:"Id"`

	// Warnings are any warnings encountered during the creation of the container.
	Warnings []string `json:"Warnings"`
}

// POST /containers/{name:.*}/exec
type ContainerExecCreateResponse struct {
	// ID is the exec ID.
	ID string `json:"Id"`
}

// POST /auth
type AuthResponse struct {
	// Status is the authentication status
	Status string `json:"Status"`
}

// POST "/containers/"+containerID+"/wait"
type ContainerWaitResponse struct {
	// StatusCode is the status code of the wait job
	StatusCode int `json:"StatusCode"`
}

// POST "/commit?container="+containerID
type ContainerCommitResponse struct {
	ID string `json:"Id"`
}

// GET "/containers/{name:.*}/changes"
type ContainerChange struct {
	Kind int
	Path string
}

// GET "/images/{name:.*}/history"
type ImageHistory struct {
	ID        string `json:"Id"`
	Created   int64
	CreatedBy string
	Tags      []string
	Size      int64
	Comment   string
}

// DELETE "/images/{name:.*}"
type ImageDelete struct {
	Untagged string `json:",omitempty"`
	Deleted  string `json:",omitempty"`
}

// GET "/images/json"
type Image struct {
	ID          string `json:"Id"`
	ParentId    string
	RepoTags    []string
	RepoDigests []string
	Created     int
	Size        int
	VirtualSize int
	Labels      map[string]string
}

type GraphDriverData struct {
	Name string
	Data map[string]string
}

// GET "/images/{name:.*}/json"
type ImageInspect struct {
	Id              string
	Parent          string
	Comment         string
	Created         time.Time
	Container       string
	ContainerConfig *runconfig.Config
	DockerVersion   string
	Author          string
	Config          *runconfig.Config
	Architecture    string
	Os              string
	Size            int64
	VirtualSize     int64
	GraphDriver     GraphDriverData
}

// GET  "/containers/json"
type Port struct {
	IP          string `json:",omitempty"`
	PrivatePort int
	PublicPort  int `json:",omitempty"`
	Type        string
}

type Container struct {
	ID         string `json:"Id"`
	Names      []string
	Image      string
	Command    string
	Created    int
	Ports      []Port
	SizeRw     int `json:",omitempty"`
	SizeRootFs int `json:",omitempty"`
	Labels     map[string]string
	Status     string
	HostConfig struct {
		NetworkMode string `json:",omitempty"`
	}
}

// POST "/containers/"+containerID+"/copy"
type CopyConfig struct {
	Resource string
}

// ContainerPathStat is used to encode the response from
// 	GET /containers/{name:.*}/stat-path
type ContainerPathStat struct {
	Name  string      `json:"name"`
	Path  string      `json:"path"`
	Size  int64       `json:"size"`
	Mode  os.FileMode `json:"mode"`
	Mtime time.Time   `json:"mtime"`
}

// GET "/containers/{name:.*}/top"
type ContainerProcessList struct {
	Processes [][]string
	Titles    []string
}

type Version struct {
	Version       string
	ApiVersion    version.Version
	GitCommit     string
	GoVersion     string
	Os            string
	Arch          string
	KernelVersion string `json:",omitempty"`
	Experimental  bool   `json:",omitempty"`
	BuildTime     string `json:",omitempty"`
}

// GET "/info"
type Info struct {
	ID                 string
	Containers         int
	Images             int
	Driver             string
	DriverStatus       [][2]string
	MemoryLimit        bool
	SwapLimit          bool
	CpuCfsPeriod       bool
	CpuCfsQuota        bool
	IPv4Forwarding     bool
	BridgeNfIptables   bool
	BridgeNfIp6tables  bool
	Debug              bool
	NFd                int
	OomKillDisable     bool
	NGoroutines        int
	SystemTime         string
	ExecutionDriver    string
	LoggingDriver      string
	NEventsListener    int
	KernelVersion      string
	OperatingSystem    string
	IndexServerAddress string
	RegistryConfig     interface{}
	InitSha1           string
	InitPath           string
	NCPU               int
	MemTotal           int64
	DockerRootDir      string
	HttpProxy          string
	HttpsProxy         string
	NoProxy            string
	Name               string
	Labels             []string
	ExperimentalBuild  bool
}

// This struct is a temp struct used by execStart
// Config fields is part of ExecConfig in runconfig package
type ExecStartCheck struct {
	// ExecStart will first check if it's detached
	Detach bool
	// Check if there's a tty
	Tty bool
}

type ContainerState struct {
	Running    bool
	Paused     bool
	Restarting bool
	OOMKilled  bool
	Dead       bool
	Pid        int
	ExitCode   int
	Error      string
	StartedAt  time.Time
	FinishedAt time.Time
}

// GET "/containers/{name:.*}/json"
type ContainerJSONBase struct {
	Id              string
	Created         time.Time
	Path            string
	Args            []string
	State           *ContainerState
	Image           string
	NetworkSettings *network.Settings
	ResolvConfPath  string
	HostnamePath    string
	HostsPath       string
	LogPath         string
	Name            string
	RestartCount    int
	Driver          string
	ExecDriver      string
	MountLabel      string
	ProcessLabel    string
	Volumes         map[string]string
	VolumesRW       map[string]bool
	AppArmorProfile string
	ExecIDs         []string
	HostConfig      *runconfig.HostConfig
	GraphDriver     GraphDriverData
}

type ContainerJSON struct {
	*ContainerJSONBase
	Config *runconfig.Config
}

// backcompatibility struct along with ContainerConfig
type ContainerJSONRaw struct {
	*ContainerJSONBase
	Config *ContainerConfig
}

type ContainerConfig struct {
	*runconfig.Config

	// backward compatibility, they now live in HostConfig
	Memory     int64
	MemorySwap int64
	CpuShares  int64
	Cpuset     string
}
<commit_msg>api/server: StatPath, ArchivePath, ExtractToDir<commit_after>package types

import (
	"os"
	"time"

	"github.com/docker/docker/daemon/network"
	"github.com/docker/docker/pkg/version"
	"github.com/docker/docker/runconfig"
)

// ContainerCreateResponse contains the information returned to a client on the
// creation of a new container.
type ContainerCreateResponse struct {
	// ID is the ID of the created container.
	ID string `json:"Id"`

	// Warnings are any warnings encountered during the creation of the container.
	Warnings []string `json:"Warnings"`
}

// POST /containers/{name:.*}/exec
type ContainerExecCreateResponse struct {
	// ID is the exec ID.
	ID string `json:"Id"`
}

// POST /auth
type AuthResponse struct {
	// Status is the authentication status
	Status string `json:"Status"`
}

// POST "/containers/"+containerID+"/wait"
type ContainerWaitResponse struct {
	// StatusCode is the status code of the wait job
	StatusCode int `json:"StatusCode"`
}

// POST "/commit?container="+containerID
type ContainerCommitResponse struct {
	ID string `json:"Id"`
}

// GET "/containers/{name:.*}/changes"
type ContainerChange struct {
	Kind int
	Path string
}

// GET "/images/{name:.*}/history"
type ImageHistory struct {
	ID        string `json:"Id"`
	Created   int64
	CreatedBy string
	Tags      []string
	Size      int64
	Comment   string
}

// DELETE "/images/{name:.*}"
type ImageDelete struct {
	Untagged string `json:",omitempty"`
	Deleted  string `json:",omitempty"`
}

// GET "/images/json"
type Image struct {
	ID          string `json:"Id"`
	ParentId    string
	RepoTags    []string
	RepoDigests []string
	Created     int
	Size        int
	VirtualSize int
	Labels      map[string]string
}

type GraphDriverData struct {
	Name string
	Data map[string]string
}

// GET "/images/{name:.*}/json"
type ImageInspect struct {
	Id              string
	Parent          string
	Comment         string
	Created         time.Time
	Container       string
	ContainerConfig *runconfig.Config
	DockerVersion   string
	Author          string
	Config          *runconfig.Config
	Architecture    string
	Os              string
	Size            int64
	VirtualSize     int64
	GraphDriver     GraphDriverData
}

// GET  "/containers/json"
type Port struct {
	IP          string `json:",omitempty"`
	PrivatePort int
	PublicPort  int `json:",omitempty"`
	Type        string
}

type Container struct {
	ID         string `json:"Id"`
	Names      []string
	Image      string
	Command    string
	Created    int
	Ports      []Port
	SizeRw     int `json:",omitempty"`
	SizeRootFs int `json:",omitempty"`
	Labels     map[string]string
	Status     string
	HostConfig struct {
		NetworkMode string `json:",omitempty"`
	}
}

// POST "/containers/"+containerID+"/copy"
type CopyConfig struct {
	Resource string
}

// ContainerPathStat is used to encode the header from
// 	GET /containers/{name:.*}/archive
// "name" is the file or directory name.
// "path" is the absolute path to the resource in the container.
type ContainerPathStat struct {
	Name  string      `json:"name"`
	Path  string      `json:"path"`
	Size  int64       `json:"size"`
	Mode  os.FileMode `json:"mode"`
	Mtime time.Time   `json:"mtime"`
}

// GET "/containers/{name:.*}/top"
type ContainerProcessList struct {
	Processes [][]string
	Titles    []string
}

type Version struct {
	Version       string
	ApiVersion    version.Version
	GitCommit     string
	GoVersion     string
	Os            string
	Arch          string
	KernelVersion string `json:",omitempty"`
	Experimental  bool   `json:",omitempty"`
	BuildTime     string `json:",omitempty"`
}

// GET "/info"
type Info struct {
	ID                 string
	Containers         int
	Images             int
	Driver             string
	DriverStatus       [][2]string
	MemoryLimit        bool
	SwapLimit          bool
	CpuCfsPeriod       bool
	CpuCfsQuota        bool
	IPv4Forwarding     bool
	BridgeNfIptables   bool
	BridgeNfIp6tables  bool
	Debug              bool
	NFd                int
	OomKillDisable     bool
	NGoroutines        int
	SystemTime         string
	ExecutionDriver    string
	LoggingDriver      string
	NEventsListener    int
	KernelVersion      string
	OperatingSystem    string
	IndexServerAddress string
	RegistryConfig     interface{}
	InitSha1           string
	InitPath           string
	NCPU               int
	MemTotal           int64
	DockerRootDir      string
	HttpProxy          string
	HttpsProxy         string
	NoProxy            string
	Name               string
	Labels             []string
	ExperimentalBuild  bool
}

// This struct is a temp struct used by execStart
// Config fields is part of ExecConfig in runconfig package
type ExecStartCheck struct {
	// ExecStart will first check if it's detached
	Detach bool
	// Check if there's a tty
	Tty bool
}

type ContainerState struct {
	Running    bool
	Paused     bool
	Restarting bool
	OOMKilled  bool
	Dead       bool
	Pid        int
	ExitCode   int
	Error      string
	StartedAt  time.Time
	FinishedAt time.Time
}

// GET "/containers/{name:.*}/json"
type ContainerJSONBase struct {
	Id              string
	Created         time.Time
	Path            string
	Args            []string
	State           *ContainerState
	Image           string
	NetworkSettings *network.Settings
	ResolvConfPath  string
	HostnamePath    string
	HostsPath       string
	LogPath         string
	Name            string
	RestartCount    int
	Driver          string
	ExecDriver      string
	MountLabel      string
	ProcessLabel    string
	Volumes         map[string]string
	VolumesRW       map[string]bool
	AppArmorProfile string
	ExecIDs         []string
	HostConfig      *runconfig.HostConfig
	GraphDriver     GraphDriverData
}

type ContainerJSON struct {
	*ContainerJSONBase
	Config *runconfig.Config
}

// backcompatibility struct along with ContainerConfig
type ContainerJSONRaw struct {
	*ContainerJSONBase
	Config *ContainerConfig
}

type ContainerConfig struct {
	*runconfig.Config

	// backward compatibility, they now live in HostConfig
	Memory     int64
	MemorySwap int64
	CpuShares  int64
	Cpuset     string
}
<|endoftext|>


<commit_before>// Copyright 2019 by caixw, All rights reserved.
// Use of this source code is governed by a MIT
// license that can be found in the LICENSE file.

package orm

import (
	"errors"
	"fmt"

	"github.com/issue9/orm/v2/sqlbuilder"
)

// Upgrader 提供了对更新表结构的一些操作
type Upgrader struct {
	db    *DB
	model *Model
	err   error

	addCols  []*Column
	dropCols []string

	addConts  []string
	dropConts []string

	addIdxs  []string
	dropIdxs []string

	// TODO 修改列信息
}

// Upgrade 生成 Upgrader 对象
func (db *DB) Upgrade(v interface{}) (*Upgrader, error) {
	m, err := db.NewModel(v)
	if err != nil {
		return nil, err
	}

	return &Upgrader{
		db:        db,
		model:     m,
		addCols:   []*Column{},
		dropCols:  []string{},
		dropConts: []string{},
	}, nil
}

// DB 返回关联的 DB 实例
func (u *Upgrader) DB() *DB {
	return u.db
}

// Err 返回执行过程中的错误信息
func (u *Upgrader) Err() error {
	return u.err
}

// AddColumn 添加表中的列，列名必须存在于表模型中
func (u *Upgrader) AddColumn(name ...string) *Upgrader {
	if u.err != nil {
		return u
	}

	for _, n := range name {
		col := u.model.FindColumn(n)
		if col == nil {
			panic(fmt.Sprintf("列名 %s 不存在", n))
		}

		u.addCols = append(u.addCols, col)
	}

	return u
}

// DropColumns 删除表中的列，列名可以不存在于表模型，
// 只在数据库中的表包含该列名，就会被删除。
func (u *Upgrader) DropColumns(name ...string) *Upgrader {
	if u.err != nil {
		return u
	}

	if u.dropCols == nil {
		u.dropCols = name
		return u
	}

	u.dropCols = append(u.dropCols, name...)
	return u
}

// RenameColumn 修改列名
func (u *Upgrader) RenameColumn(old, new string) {
	// TODO
}

// ChangeColumn 改变列属性
func (u *Upgrader) ChangeColumn(old, new string, conv func(interface{}) interface{}) *Upgrader {
	// TODO
	return u
}

// AddConstraint 添加约束
//
// 约束必须存在于 model.constraints 中
func (u *Upgrader) AddConstraint(name ...string) *Upgrader {
	if u.err != nil {
		return u
	}

	if u.addConts == nil {
		u.addConts = name
		return u
	}

	u.addConts = append(u.addConts, name...)

	return u
}

// DropConstraint 删除约束
func (u *Upgrader) DropConstraint(conts ...string) *Upgrader {
	if u.err != nil {
		return u
	}

	if u.dropConts == nil {
		u.dropConts = conts
		return u
	}

	u.dropConts = append(u.dropConts, conts...)
	return u
}

// AddIndex 添加索引信息
func (u *Upgrader) AddIndex(name ...string) *Upgrader {
	if u.err != nil {
		return u
	}

	if u.addIdxs == nil {
		u.addIdxs = name
		return u
	}

	u.addIdxs = append(u.addIdxs, name...)
	return u
}

// DropIndex 删除索引
func (u *Upgrader) DropIndex(name ...string) *Upgrader {
	if u.Err() != nil {
		return u
	}

	if u.dropIdxs == nil {
		u.dropIdxs = name
		return u
	}

	u.dropIdxs = append(u.dropIdxs, name...)
	return u
}

// Do 执行操作
func (u *Upgrader) Do() error {
	if u.Err() != nil {
		return u.Err()
	}

	rollback := func() error {
		return nil
	}

	commit := func() error {
		return nil
	}

	var e Engine = u.DB()
	if u.DB().Dialect().TransactionalDDL() {
		tx, err := u.DB().Begin()
		if err != nil {
			return err
		}

		rollback = func() error {
			return tx.Rollback()
		}
		commit = func() error {
			return tx.Commit()
		}
		e = tx
	}

	if len(u.dropCols) > 0 {
		if err := u.dropColumns(e); err != nil {
			if err1 := rollback(); err1 != nil {
				return errors.New(err1.Error() + err.Error())
			}
			return err
		}
	}

	if len(u.dropConts) > 0 {
		if err := u.dropConstraints(e); err != nil {
			if err1 := rollback(); err1 != nil {
				return errors.New(err1.Error() + err.Error())
			}
			return err
		}
	}

	if len(u.dropIdxs) > 0 {
		if err := u.dropIndex(e); err != nil {
			if err1 := rollback(); err1 != nil {
				return errors.New(err1.Error() + err.Error())
			}
			return err
		}
	}

	if len(u.addCols) > 0 {
		if err := u.addColumns(e); err != nil {
			if err1 := rollback(); err1 != nil {
				return errors.New(err1.Error() + err.Error())
			}
			return err
		}
	}

	if len(u.addCols) > 0 {
		if err := u.addConstraints(e); err != nil {
			if err1 := rollback(); err1 != nil {
				return errors.New(err1.Error() + err.Error())
			}
			return err
		}
	}

	if len(u.addCols) > 0 {
		if err := u.addIndex(e); err != nil {
			if err1 := rollback(); err1 != nil {
				return errors.New(err1.Error() + err.Error())
			}
			return err
		}
	}

	return commit()
}

func (u *Upgrader) addColumns(e Engine) error {
	sql := sqlbuilder.AddColumn(e, e.Dialect())

	for _, col := range u.addCols {
		sql.Reset()

		_, err := sql.Table(u.model.Name).
			Column("{"+col.Name+"}", col.GoType, col.Nullable, col.HasDefault, col.Default, col.Length...).
			Exec()
		if err != nil {
			return err
		}
	}

	return nil
}

func (u *Upgrader) dropColumns(e Engine) error {
	sql := sqlbuilder.DropColumn(e)

	for _, n := range u.dropCols {
		sql.Reset()
		_, err := sql.Table(u.model.Name).
			Column(n).
			Exec()
		if err != nil {
			return err
		}
	}

	return nil
}

func (u *Upgrader) dropConstraints(e Engine) error {
	sql := sqlbuilder.DropConstraint(e)

	for _, n := range u.dropCols {
		sql.Reset()
		_, err := sql.Table(u.model.Name).
			Constraint(n).
			Exec()
		if err != nil {
			return err
		}
	}

	return nil
}

func (u *Upgrader) addConstraints(e Engine) error {
	stmt := sqlbuilder.AddConstraint(e)

	for _, c := range u.addConts {
		stmt.Reset()
		stmt.Table("{#" + u.model.Name + "}")

		for _, fk := range u.model.FK {
			if fk.Name != c {
				continue
			}

			stmt.FK(fk.Name, fk.Column.Name, fk.RefTableName, fk.RefColName, fk.UpdateRule, fk.DeleteRule)
			if _, err := stmt.Exec(); err != nil {
				return err
			}
			break
		}

		for name, u := range u.model.Uniques {
			if name != c {
				continue
			}

			cols := make([]string, 0, len(u))
			for _, col := range u {
				cols = append(cols, "{"+col.Name+"}")
			}
			stmt.Unique(name, cols...)

			if _, err := stmt.Exec(); err != nil {
				return err
			}

			break
		}

		if u.model.PK != nil && u.model.AIName == c {
			// NOTE: u.Model.AIName 为自动生成，而 AddConstraints 为手动指定约束名。
			// 有可能会造成主键名称不一样，而无法正确生成

			cols := make([]string, 0, len(u.model.PK))
			for _, col := range u.model.PK {
				cols = append(cols, "{"+col.Name+"}")
			}
			stmt.PK(u.model.AIName, cols...)

			if _, err := stmt.Exec(); err != nil {
				return err
			}
			break
		}

		for name, expr := range u.model.Checks {
			if name != c {
				continue
			}

			stmt.Check(name, expr)
			if _, err := stmt.Exec(); err != nil {
				return err
			}
			break
		}
	}

	return nil
}

func (u *Upgrader) addIndex(e Engine) error {
	stmt := sqlbuilder.CreateIndex(e)

	for _, index := range u.addIdxs {
		stmt.Reset()
		stmt.Table("{#" + u.model.Name + "}")

		for name, cols := range u.model.Indexes {
			if name != index {
				continue
			}

			cs := make([]string, 0, len(cols))
			for _, c := range cols {
				cs = append(cs, "{"+c.Name+"}")
			}

			stmt.Name(name)
			stmt.Columns(cs...)
		}
		if _, err := stmt.Exec(); err != nil {
			return err
		}
	}

	return nil
}

func (u *Upgrader) dropIndex(e Engine) error {
	stmt := sqlbuilder.DropIndex(e, e.Dialect())

	for _, index := range u.dropIdxs {
		stmt.Reset()
		stmt.Table("{#" + u.model.Name + "}").
			Name(index)
		if _, err := stmt.Exec(); err != nil {
			return err
		}
	}

	return nil
}
<commit_msg>调整调用顺序<commit_after>// Copyright 2019 by caixw, All rights reserved.
// Use of this source code is governed by a MIT
// license that can be found in the LICENSE file.

package orm

import (
	"errors"
	"fmt"

	"github.com/issue9/orm/v2/sqlbuilder"
)

// Upgrader 提供了对更新表结构的一些操作
type Upgrader struct {
	db    *DB
	model *Model
	err   error

	addCols  []*Column
	dropCols []string

	addConts  []string
	dropConts []string

	addIdxs  []string
	dropIdxs []string

	// TODO 修改列信息
}

// Upgrade 生成 Upgrader 对象
func (db *DB) Upgrade(v interface{}) (*Upgrader, error) {
	m, err := db.NewModel(v)
	if err != nil {
		return nil, err
	}

	return &Upgrader{
		db:        db,
		model:     m,
		addCols:   []*Column{},
		dropCols:  []string{},
		dropConts: []string{},
	}, nil
}

// DB 返回关联的 DB 实例
func (u *Upgrader) DB() *DB {
	return u.db
}

// Err 返回执行过程中的错误信息
func (u *Upgrader) Err() error {
	return u.err
}

// AddColumn 添加表中的列，列名必须存在于表模型中
func (u *Upgrader) AddColumn(name ...string) *Upgrader {
	if u.err != nil {
		return u
	}

	for _, n := range name {
		col := u.model.FindColumn(n)
		if col == nil {
			panic(fmt.Sprintf("列名 %s 不存在", n))
		}

		u.addCols = append(u.addCols, col)
	}

	return u
}

// DropColumns 删除表中的列，列名可以不存在于表模型，
// 只在数据库中的表包含该列名，就会被删除。
func (u *Upgrader) DropColumns(name ...string) *Upgrader {
	if u.err != nil {
		return u
	}

	if u.dropCols == nil {
		u.dropCols = name
		return u
	}

	u.dropCols = append(u.dropCols, name...)
	return u
}

// RenameColumn 修改列名
func (u *Upgrader) RenameColumn(old, new string) {
	// TODO
}

// ChangeColumn 改变列属性
func (u *Upgrader) ChangeColumn(old, new string, conv func(interface{}) interface{}) *Upgrader {
	// TODO
	return u
}

// AddConstraint 添加约束
//
// 约束必须存在于 model.constraints 中
func (u *Upgrader) AddConstraint(name ...string) *Upgrader {
	if u.err != nil {
		return u
	}

	if u.addConts == nil {
		u.addConts = name
		return u
	}

	u.addConts = append(u.addConts, name...)

	return u
}

// DropConstraint 删除约束
func (u *Upgrader) DropConstraint(conts ...string) *Upgrader {
	if u.err != nil {
		return u
	}

	if u.dropConts == nil {
		u.dropConts = conts
		return u
	}

	u.dropConts = append(u.dropConts, conts...)
	return u
}

// AddIndex 添加索引信息
func (u *Upgrader) AddIndex(name ...string) *Upgrader {
	if u.err != nil {
		return u
	}

	if u.addIdxs == nil {
		u.addIdxs = name
		return u
	}

	u.addIdxs = append(u.addIdxs, name...)
	return u
}

// DropIndex 删除索引
func (u *Upgrader) DropIndex(name ...string) *Upgrader {
	if u.Err() != nil {
		return u
	}

	if u.dropIdxs == nil {
		u.dropIdxs = name
		return u
	}

	u.dropIdxs = append(u.dropIdxs, name...)
	return u
}

// Do 执行操作
func (u *Upgrader) Do() error {
	if u.Err() != nil {
		return u.Err()
	}

	rollback := func() error {
		return nil
	}

	commit := func() error {
		return nil
	}

	var e Engine = u.DB()
	if u.DB().Dialect().TransactionalDDL() {
		tx, err := u.DB().Begin()
		if err != nil {
			return err
		}

		rollback = func() error {
			return tx.Rollback()
		}
		commit = func() error {
			return tx.Commit()
		}
		e = tx
	}

	if len(u.dropConts) > 0 {
		if err := u.dropConstraints(e); err != nil {
			if err1 := rollback(); err1 != nil {
				return errors.New(err1.Error() + err.Error())
			}
			return err
		}
	}

	if len(u.dropIdxs) > 0 {
		if err := u.dropIndex(e); err != nil {
			if err1 := rollback(); err1 != nil {
				return errors.New(err1.Error() + err.Error())
			}
			return err
		}
	}

	// 外键约束可能正好依赖被删除的列。
	// 所以要在删除约束之后，再删除列信息。
	if len(u.dropCols) > 0 {
		if err := u.dropColumns(e); err != nil {
			if err1 := rollback(); err1 != nil {
				return errors.New(err1.Error() + err.Error())
			}
			return err
		}
	}

	// 先添加列，再添加约束和索引。后者可能依赖添加的列信息。
	if len(u.addCols) > 0 {
		if err := u.addColumns(e); err != nil {
			if err1 := rollback(); err1 != nil {
				return errors.New(err1.Error() + err.Error())
			}
			return err
		}
	}

	if len(u.addConts) > 0 {
		if err := u.addConstraints(e); err != nil {
			if err1 := rollback(); err1 != nil {
				return errors.New(err1.Error() + err.Error())
			}
			return err
		}
	}

	if len(u.addIdxs) > 0 {
		if err := u.addIndex(e); err != nil {
			if err1 := rollback(); err1 != nil {
				return errors.New(err1.Error() + err.Error())
			}
			return err
		}
	}

	return commit()
}

func (u *Upgrader) addColumns(e Engine) error {
	sql := sqlbuilder.AddColumn(e, e.Dialect())

	for _, col := range u.addCols {
		sql.Reset()

		_, err := sql.Table(u.model.Name).
			Column("{"+col.Name+"}", col.GoType, col.Nullable, col.HasDefault, col.Default, col.Length...).
			Exec()
		if err != nil {
			return err
		}
	}

	return nil
}

func (u *Upgrader) dropColumns(e Engine) error {
	sql := sqlbuilder.DropColumn(e)

	for _, n := range u.dropCols {
		sql.Reset()
		_, err := sql.Table(u.model.Name).
			Column(n).
			Exec()
		if err != nil {
			return err
		}
	}

	return nil
}

func (u *Upgrader) dropConstraints(e Engine) error {
	sql := sqlbuilder.DropConstraint(e)

	for _, n := range u.dropCols {
		sql.Reset()
		_, err := sql.Table(u.model.Name).
			Constraint(n).
			Exec()
		if err != nil {
			return err
		}
	}

	return nil
}

func (u *Upgrader) addConstraints(e Engine) error {
	stmt := sqlbuilder.AddConstraint(e)

	for _, c := range u.addConts {
		stmt.Reset()
		stmt.Table("{#" + u.model.Name + "}")

		for _, fk := range u.model.FK {
			if fk.Name != c {
				continue
			}

			stmt.FK(fk.Name, fk.Column.Name, fk.RefTableName, fk.RefColName, fk.UpdateRule, fk.DeleteRule)
			if _, err := stmt.Exec(); err != nil {
				return err
			}
			break
		}

		for name, u := range u.model.Uniques {
			if name != c {
				continue
			}

			cols := make([]string, 0, len(u))
			for _, col := range u {
				cols = append(cols, "{"+col.Name+"}")
			}
			stmt.Unique(name, cols...)

			if _, err := stmt.Exec(); err != nil {
				return err
			}

			break
		}

		if u.model.PK != nil && u.model.AIName == c {
			// NOTE: u.Model.AIName 为自动生成，而 AddConstraints 为手动指定约束名。
			// 有可能会造成主键名称不一样，而无法正确生成

			cols := make([]string, 0, len(u.model.PK))
			for _, col := range u.model.PK {
				cols = append(cols, "{"+col.Name+"}")
			}
			stmt.PK(u.model.AIName, cols...)

			if _, err := stmt.Exec(); err != nil {
				return err
			}
			break
		}

		for name, expr := range u.model.Checks {
			if name != c {
				continue
			}

			stmt.Check(name, expr)
			if _, err := stmt.Exec(); err != nil {
				return err
			}
			break
		}
	}

	return nil
}

func (u *Upgrader) addIndex(e Engine) error {
	stmt := sqlbuilder.CreateIndex(e)

	for _, index := range u.addIdxs {
		stmt.Reset()
		stmt.Table("{#" + u.model.Name + "}")

		for name, cols := range u.model.Indexes {
			if name != index {
				continue
			}

			cs := make([]string, 0, len(cols))
			for _, c := range cols {
				cs = append(cs, "{"+c.Name+"}")
			}

			stmt.Name(name)
			stmt.Columns(cs...)
		}
		if _, err := stmt.Exec(); err != nil {
			return err
		}
	}

	return nil
}

func (u *Upgrader) dropIndex(e Engine) error {
	stmt := sqlbuilder.DropIndex(e, e.Dialect())

	for _, index := range u.dropIdxs {
		stmt.Reset()
		stmt.Table("{#" + u.model.Name + "}").
			Name(index)
		if _, err := stmt.Exec(); err != nil {
			return err
		}
	}

	return nil
}
<|endoftext|>


<commit_before>package handlers

import (
	"net/http"
	"time"

	"github.com/pivotal-cf-experimental/lattice-app/routes"
	"github.com/pivotal-golang/lager"
	"github.com/tedsuo/rata"
)

func New(logger lager.Logger) rata.Handlers {
	t := time.Now()
	handlers := rata.Handlers{
		routes.Env:   &Env{},
		routes.Hello: &Hello{Time: t},
		routes.Exit:  &Exit{Time: t},
		routes.Index: &Index{},
	}

	for route, handler := range handlers {
		handlers[route] = &LoggingHandler{
			Route:   route,
			Handler: handler,
			Logger:  logger,
		}
	}

	return handlers
}

type LoggingHandler struct {
	Route   string
	Handler http.Handler
	Logger  lager.Logger
}

func (h *LoggingHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	session := h.Logger.Session(h.Route)
	session.Debug("request.begin")
	h.Handler.ServeHTTP(w, r)
	session.Debug("request.end")
}
<commit_msg>Revert "correct imports"<commit_after>package handlers

import (
	"net/http"
	"time"

	"github.com/aripka-pivotal/pivotal-cf-experimental/routes"
	"github.com/pivotal-golang/lager"
	"github.com/tedsuo/rata"
)

func New(logger lager.Logger) rata.Handlers {
	t := time.Now()
	handlers := rata.Handlers{
		routes.Env:   &Env{},
		routes.Hello: &Hello{Time: t},
		routes.Exit:  &Exit{Time: t},
		routes.Index: &Index{},
	}

	for route, handler := range handlers {
		handlers[route] = &LoggingHandler{
			Route:   route,
			Handler: handler,
			Logger:  logger,
		}
	}

	return handlers
}

type LoggingHandler struct {
	Route   string
	Handler http.Handler
	Logger  lager.Logger
}

func (h *LoggingHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	session := h.Logger.Session(h.Route)
	session.Debug("request.begin")
	h.Handler.ServeHTTP(w, r)
	session.Debug("request.end")
}
<|endoftext|>


<commit_before>package handlers

import (
	"github.com/danryan/hal"
	"github.com/davecgh/go-spew/spew"
)

const okStr = "OK"

// GetHandler pulls a key out of the store, when addressed like so:
// foobar?
// bawt> get: foobar=baz
var GetHandler = hal.Hear(`^(.+)?$`, func(res *hal.Response) error {
	key := res.Match[0][1]
	val, err := res.Robot.Store.Get(key)
	if err != nil {
		res.Send(err.Error())
		return err
	}
	return res.Send(string(val))
})

// SetHandler does a simple match/set into the Store
var SetHandler = hal.Hear(`^(.+) is (.+)$`, func(res *hal.Response) error {
	key := res.Match[0][1]
	val := res.Match[0][2]
	err := res.Robot.Store.Set(key, []byte(val))
	if err != nil {
		res.Send(err.Error())
		return err
	}
	return res.Send(okStr)
})

// DeleteHandler nukes keys in the Store
var DeleteHandler = hal.Hear(`^forget (.+)$`, func(res *hal.Response) error {
	key := res.Match[0][1]

	if err := res.Robot.Store.Delete(key); err != nil {
		res.Send(err.Error())
		return err
	}
	return res.Send(okStr)
})

// UsersHandler provides insite into the Robots user storage
var UsersHandler = hal.Hear(`^!show users$`, func(res *hal.Response) error {
	lines := []string{}
	for _, user := range res.Robot.Users.All() {
		lines = append(lines, spew.Sdump(user))
	}
	return res.Send(lines...)
})

// UserHandler is the singular form of UsersHandler
var UserHandler = hal.Hear(`^!show user (.+)$`, func(res *hal.Response) error {
	id := res.Match[0][1]
	user, _ := res.Robot.Users.Get(id)
	line := spew.Sdump(user)
	return res.Send(line)
})
<commit_msg>funny regex error<commit_after>package handlers

import (
	"github.com/danryan/hal"
	"github.com/davecgh/go-spew/spew"
)

const okStr = "OK"

// GetHandler pulls a key out of the store, when addressed like so:
// foobar?
// bawt> get: foobar=baz
var GetHandler = hal.Hear(`^\w+\?$`, func(res *hal.Response) error {
	key := res.Match[0][1]
	val, err := res.Robot.Store.Get(key)
	if err != nil {
		res.Send(err.Error())
		return err
	}
	return res.Send(string(val))
})

// SetHandler does a simple match/set into the Store
var SetHandler = hal.Hear(`^(\w+) is (.+)$`, func(res *hal.Response) error {
	key := res.Match[0][1]
	val := res.Match[0][2]
	err := res.Robot.Store.Set(key, []byte(val))
	if err != nil {
		res.Send(err.Error())
		return err
	}
	return res.Send(okStr)
})

// DeleteHandler nukes keys in the Store
var DeleteHandler = hal.Hear(`^forget (.+)$`, func(res *hal.Response) error {
	key := res.Match[0][1]

	if err := res.Robot.Store.Delete(key); err != nil {
		res.Send(err.Error())
		return err
	}
	return res.Send(okStr)
})

// UsersHandler provides insite into the Robots user storage
var UsersHandler = hal.Hear(`^!show users$`, func(res *hal.Response) error {
	lines := []string{}
	for _, user := range res.Robot.Users.All() {
		lines = append(lines, spew.Sdump(user))
	}
	return res.Send(lines...)
})

// UserHandler is the singular form of UsersHandler
var UserHandler = hal.Hear(`^!show user (.+)$`, func(res *hal.Response) error {
	id := res.Match[0][1]
	user, _ := res.Robot.Users.Get(id)
	line := spew.Sdump(user)
	return res.Send(line)
})
<|endoftext|>


<commit_before>/*
Copyright 2019 The Kubernetes Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package testutil

import (
	"io"

	"github.com/prometheus/client_golang/prometheus/testutil"

	"k8s.io/component-base/metrics"
)

// GatherAndCompare gathers all metrics from the provided Gatherer and compares
// it to an expected output read from the provided Reader in the Prometheus text
// exposition format. If any metricNames are provided, only metrics with those
// names are compared.
func GatherAndCompare(g metrics.Gatherer, expected io.Reader, metricNames ...string) error {
	return testutil.GatherAndCompare(g, expected, metricNames...)
}
<commit_msg>Introduce CollectAndCompare to testutils<commit_after>/*
Copyright 2019 The Kubernetes Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package testutil

import (
	"io"

	"github.com/prometheus/client_golang/prometheus/testutil"

	"k8s.io/component-base/metrics"
)

// CollectAndCompare registers the provided Collector with a newly created
// pedantic Registry. It then does the same as GatherAndCompare, gathering the
// metrics from the pedantic Registry.
func CollectAndCompare(c metrics.Collector, expected io.Reader, metricNames ...string) error {
	return testutil.CollectAndCompare(c, expected, metricNames...)
}

// GatherAndCompare gathers all metrics from the provided Gatherer and compares
// it to an expected output read from the provided Reader in the Prometheus text
// exposition format. If any metricNames are provided, only metrics with those
// names are compared.
func GatherAndCompare(g metrics.Gatherer, expected io.Reader, metricNames ...string) error {
	return testutil.GatherAndCompare(g, expected, metricNames...)
}
<|endoftext|>


<commit_before>// Copyright (c) 2015 Uber Technologies, Inc.

// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

package tchannel

// VersionInfo identifies the version of the TChannel library.
// Due to lack of proper package management, this version string will
// be maintained manually.
const VersionInfo = "1.8.0"
<commit_msg>Back to development<commit_after>// Copyright (c) 2015 Uber Technologies, Inc.

// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

package tchannel

// VersionInfo identifies the version of the TChannel library.
// Due to lack of proper package management, this version string will
// be maintained manually.
const VersionInfo = "1.8.0-dev"
<|endoftext|>


<commit_before>// Copyright (c) 2021 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

package tally

// Version is the current version of the library.
const Version = "4.1.1"
<commit_msg>increment version (#186)<commit_after>// Copyright (c) 2021 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

package tally

// Version is the current version of the library.
const Version = "4.1.3"
<|endoftext|>


<commit_before>package gf

const VERSION = "v1.16.3"
const AUTHORS = "john<john@goframe.org>"
<commit_msg>version updates<commit_after>package gf

const VERSION = "v1.16.4"
const AUTHORS = "john<john@goframe.org>"
<|endoftext|>


<commit_before>package main

const VERSION = "0.1.0.rc3"
<commit_msg>Bump version<commit_after>package main

const VERSION = "0.1.0.rc4"
<|endoftext|>


<commit_before>package main

import (
	"fmt"
)

const (
	Version = "dev"
)

var cmdVersion = &Command{
	Run:   runVersion,
	Usage: "version",
	Short: "Display current version",
	Long: `
Display current version

Examples:

  force version
`,
}

func init() {
}

func runVersion(cmd *Command, args []string) {
	fmt.Println(Version)
}
<commit_msg>added version<commit_after>package main

import (
	"fmt"
)

const (
	Version = "v0.22.6"
)

var cmdVersion = &Command{
	Run:   runVersion,
	Usage: "version",
	Short: "Display current version",
	Long: `
Display current version

Examples:

  force version
`,
}

func init() {
}

func runVersion(cmd *Command, args []string) {
	fmt.Println(Version)
}
<|endoftext|>


<commit_before>// (c) Copyright IBM Corp. 2021
// (c) Copyright Instana Inc. 2021

package instana

// Version is the version of Instana sensor
const Version = "1.27.1"
<commit_msg>Bump go-sensor version to 1.27.2<commit_after>// (c) Copyright IBM Corp. 2021
// (c) Copyright Instana Inc. 2021

package instana

// Version is the version of Instana sensor
const Version = "1.27.2"
<|endoftext|>


<commit_before>// Licensed to The Moov Authors under one or more contributor
// license agreements. See the NOTICE file distributed with
// this work for additional information regarding copyright
// ownership. The Moov Authors licenses this file to you under
// the Apache License, Version 2.0 (the "License"); you may
// not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied.  See the License for the
// specific language governing permissions and limitations
// under the License.

package ach

// Version Number
const Version = "v1.3.1"
<commit_msg>bump version for dev<commit_after>// Licensed to The Moov Authors under one or more contributor
// license agreements. See the NOTICE file distributed with
// this work for additional information regarding copyright
// ownership. The Moov Authors licenses this file to you under
// the Apache License, Version 2.0 (the "License"); you may
// not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied.  See the License for the
// specific language governing permissions and limitations
// under the License.

package ach

// Version Number
const Version = "v1.4.0-dev"
<|endoftext|>


<commit_before>// Copyright 2014 SteelSeries ApS.  All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// This package implements a basic LISP interpretor for embedding in a go program for scripting.
// This file implements Json<->Lisp conversions using frames.

package golisp

import (
	"encoding/json"
	"errors"
	"fmt"
	"math"
	"strings"
)

func JsonToLispWithFrames(json interface{}) (result *Data) {
	mapValue, ok := json.(map[string]interface{})
	if ok {
		var m = make(FrameMap, len(mapValue))
		for key, val := range mapValue {
			value := JsonToLispWithFrames(val)
			m[fmt.Sprintf("%s:", key)] = value
		}
		return FrameWithValue(&m)
	}

	arrayValue, ok := json.([]interface{})
	if ok {
		var ary *Data
		for _, val := range arrayValue {
			value := JsonToLispWithFrames(val)
			ary = Cons(value, ary)
		}
		return Reverse(ary)
	}

	numValue, ok := json.(float64)
	if ok {
		if math.Trunc(numValue) == numValue {
			return IntegerWithValue(int64(numValue))
		} else {
			return FloatWithValue(float32(numValue))
		}
	}

	strValue, ok := json.(string)
	if ok {
		return StringWithValue(strValue)
	}

	boolValue, ok := json.(bool)
	if ok {
		return BooleanWithValue(boolValue)
	}

	return
}

func JsonStringToLispWithFrames(jsonData string) (result *Data) {
	b := []byte(jsonData)
	var data interface{}
	err := json.Unmarshal(b, &data)
	if err != nil {
		panic(errors.New(fmt.Sprintf("Badly formed json: '%s'", jsonData)))
	}
	return JsonToLispWithFrames(data)
}

func LispWithFramesToJson(d *Data) (result interface{}) {
	if d == nil {
		return ""
	}

	if IntegerP(d) {
		return IntegerValue(d)
	}

	if FloatP(d) {
		return FloatValue(d)
	}

	if StringP(d) {
		return StringValue(d)
	}

	if BooleanP(d) {
		return BooleanValue(d)
	}

	if PairP(d) {
		ary := make([]interface{}, 0, Length(d))
		for c := d; NotNilP(c); c = Cdr(c) {
			ary = append(ary, LispWithFramesToJson(Car(c)))
		}
		return ary
	}

	if FrameP(d) {
		dict := make(map[string]interface{}, Length(d))
		for k, v := range *d.Frame {
			if !FunctionP(v) {
				dict[strings.TrimRight(k, ":")] = LispWithFramesToJson(v)
			}
		}
		return dict
	}

	return ""
}

func LispWithFramesToJsonString(d *Data) (result string) {
	temp := LispWithFramesToJson(d)
	j, err := json.Marshal(temp)
	if err == nil {
		return string(j)
	} else {
		return ""
	}
}
<commit_msg>Better error message<commit_after>// Copyright 2014 SteelSeries ApS.  All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// This package implements a basic LISP interpretor for embedding in a go program for scripting.
// This file implements Json<->Lisp conversions using frames.

package golisp

import (
	"encoding/json"
	"errors"
	"fmt"
	"math"
	"strings"
)

func JsonToLispWithFrames(json interface{}) (result *Data) {
	mapValue, ok := json.(map[string]interface{})
	if ok {
		var m = make(FrameMap, len(mapValue))
		for key, val := range mapValue {
			value := JsonToLispWithFrames(val)
			m[fmt.Sprintf("%s:", key)] = value
		}
		return FrameWithValue(&m)
	}

	arrayValue, ok := json.([]interface{})
	if ok {
		var ary *Data
		for _, val := range arrayValue {
			value := JsonToLispWithFrames(val)
			ary = Cons(value, ary)
		}
		return Reverse(ary)
	}

	numValue, ok := json.(float64)
	if ok {
		if math.Trunc(numValue) == numValue {
			return IntegerWithValue(int64(numValue))
		} else {
			return FloatWithValue(float32(numValue))
		}
	}

	strValue, ok := json.(string)
	if ok {
		return StringWithValue(strValue)
	}

	boolValue, ok := json.(bool)
	if ok {
		return BooleanWithValue(boolValue)
	}

	return
}

func JsonStringToLispWithFrames(jsonData string) (result *Data) {
	b := []byte(jsonData)
	var data interface{}
	err := json.Unmarshal(b, &data)
	if err != nil {
		panic(errors.New(fmt.Sprintf("Badly formed json: '%s'\n --> %v\n", jsonData, err)))
	}
	return JsonToLispWithFrames(data)
}

func LispWithFramesToJson(d *Data) (result interface{}) {
	if d == nil {
		return ""
	}

	if IntegerP(d) {
		return IntegerValue(d)
	}

	if FloatP(d) {
		return FloatValue(d)
	}

	if StringP(d) {
		return StringValue(d)
	}

	if BooleanP(d) {
		return BooleanValue(d)
	}

	if PairP(d) {
		ary := make([]interface{}, 0, Length(d))
		for c := d; NotNilP(c); c = Cdr(c) {
			ary = append(ary, LispWithFramesToJson(Car(c)))
		}
		return ary
	}

	if FrameP(d) {
		dict := make(map[string]interface{}, Length(d))
		for k, v := range *d.Frame {
			if !FunctionP(v) {
				dict[strings.TrimRight(k, ":")] = LispWithFramesToJson(v)
			}
		}
		return dict
	}

	return ""
}

func LispWithFramesToJsonString(d *Data) (result string) {
	temp := LispWithFramesToJson(d)
	j, err := json.Marshal(temp)
	if err == nil {
		return string(j)
	} else {
		return ""
	}
}
<|endoftext|>