<commit_before>package zapdriver

import (
	"strings"

	"go.uber.org/zap"
	"go.uber.org/zap/zapcore"
)

type DriverConfig struct {
	ReportAllErrors bool
}

// Core is a zapdriver specific core wrapped around the default zap core. It
// allows to merge all defined labels
type core struct {
	zapcore.Core

	// permLabels is a collection of labels that have been added to the logger
	// through the use of `With()`. These labels should never be cleared after
	// logging a single entry, unlike `tempLabel`.
	permLabels *labels

	// tempLabels keeps a record of all the labels that need to be applied to the
	// current log entry. Zap serializes log fields at different parts of the
	// stack, one such location is when calling `core.With` and the other one is
	// when calling `core.Write`. This makes it impossible to (for example) take
	// all `labels.xxx` fields, and wrap them in the `labels` namespace in one go.
	//
	// Instead, we have to filter out these labels at both locations, and then add
	// them back in the proper format right before we call `Write` on the original
	// Zap core.
	tempLabels *labels

	reportAllErrors bool
}

// WrapCore returns a `zap.Option` that wraps the default core with the
// zapdriver one.
func WrapCore() zap.Option {
	return zap.WrapCore(func(c zapcore.Core) zapcore.Core {
		return &core{
			Core:       c,
			permLabels: newLabels(),
			tempLabels: newLabels()}
	})
}

// WrapCoreWithConfig returns a `zap.Option` that wraps the default core with the
// configured zapdriver one.
func WrapCoreWithConfig(config DriverConfig) zap.Option {
	return zap.WrapCore(func(c zapcore.Core) zapcore.Core {
		return &core{
			Core:            c,
			permLabels:      newLabels(),
			tempLabels:      newLabels(),
			reportAllErrors: config.ReportAllErrors,
		}
	})
}

// With adds structured context to the Core.
func (c *core) With(fields []zap.Field) zapcore.Core {
	var lbls *labels
	lbls, fields = c.extractLabels(fields)

	lbls.mutex.RLock()
	c.permLabels.mutex.Lock()
	for k, v := range lbls.store {
		c.permLabels.store[k] = v
	}
	c.permLabels.mutex.Unlock()
	lbls.mutex.RUnlock()

	return &core{
		Core:            c.Core.With(fields),
		permLabels:      c.permLabels,
		tempLabels:      newLabels(),
		reportAllErrors: c.reportAllErrors,
	}
}

// Check determines whether the supplied Entry should be logged (using the
// embedded LevelEnabler and possibly some extra logic). If the entry
// should be logged, the Core adds itself to the CheckedEntry and returns
// the result.
//
// Callers must use Check before calling Write.
func (c *core) Check(ent zapcore.Entry, ce *zapcore.CheckedEntry) *zapcore.CheckedEntry {
	if c.Enabled(ent.Level) {
		return ce.AddCore(ent, c)
	}

	return ce
}

func (c *core) Write(ent zapcore.Entry, fields []zapcore.Field) error {
	var lbls *labels
	lbls, fields = c.extractLabels(fields)

	lbls.mutex.RLock()
	c.tempLabels.mutex.Lock()
	for k, v := range lbls.store {
		c.tempLabels.store[k] = v
	}
	c.tempLabels.mutex.Unlock()
	lbls.mutex.RUnlock()

	fields = append(fields, labelsField(c.allLabels()))
	fields = c.withSourceLocation(ent, fields)
	if c.reportAllErrors && ent.Level.Enabled(zapcore.ErrorLevel) {
		fields = c.withErrorReport(ent, fields)
	}

	c.tempLabels.reset()

	return c.Core.Write(ent, fields)
}

// Sync flushes buffered logs (if any).
func (c *core) Sync() error {
	return c.Core.Sync()
}

func (c *core) allLabels() *labels {
	lbls := newLabels()

	lbls.mutex.Lock()
	c.permLabels.mutex.RLock()
	for k, v := range c.permLabels.store {
		lbls.store[k] = v
	}
	c.permLabels.mutex.RUnlock()

	c.tempLabels.mutex.RLock()
	for k, v := range c.tempLabels.store {
		lbls.store[k] = v
	}
	c.tempLabels.mutex.RUnlock()
	lbls.mutex.Unlock()

	return lbls
}

func (c *core) extractLabels(fields []zapcore.Field) (*labels, []zapcore.Field) {
	lbls := newLabels()
	out := []zapcore.Field{}

	lbls.mutex.Lock()
	for i := range fields {
		if !isLabelField(fields[i]) {
			out = append(out, fields[i])
			continue
		}

		lbls.store[strings.Replace(fields[i].Key, "labels.", "", 1)] = fields[i].String
	}
	lbls.mutex.Unlock()

	return lbls, out
}

func (c *core) withLabels(fields []zapcore.Field) []zapcore.Field {
	lbls := newLabels()
	out := []zapcore.Field{}

	lbls.mutex.Lock()
	for i := range fields {
		if isLabelField(fields[i]) {
			lbls.store[strings.Replace(fields[i].Key, "labels.", "", 1)] = fields[i].String
			continue
		}

		out = append(out, fields[i])
	}
	lbls.mutex.Unlock()

	return append(out, labelsField(lbls))
}

func (c *core) withSourceLocation(ent zapcore.Entry, fields []zapcore.Field) []zapcore.Field {
	// If the source location was manually set, don't overwrite it
	for i := range fields {
		if fields[i].Key == sourceKey {
			return fields
		}
	}

	if !ent.Caller.Defined {
		return fields
	}

	return append(fields, SourceLocation(ent.Caller.PC, ent.Caller.File, ent.Caller.Line, true))
}

func (c *core) withErrorReport(ent zapcore.Entry, fields []zapcore.Field) []zapcore.Field {
	// If the error report was manually set, don't overwrite it
	for i := range fields {
		if fields[i].Key == contextKey {
			return fields
		}
	}

	if !ent.Caller.Defined {
		return fields
	}

	return append(fields, ErrorReport(ent.Caller.PC, ent.Caller.File, ent.Caller.Line, true))
}
<commit_msg>Save config object instead of individual keys<commit_after>package zapdriver

import (
	"strings"

	"go.uber.org/zap"
	"go.uber.org/zap/zapcore"
)

type DriverConfig struct {
	ReportAllErrors bool
}

// Core is a zapdriver specific core wrapped around the default zap core. It
// allows to merge all defined labels
type core struct {
	zapcore.Core

	// permLabels is a collection of labels that have been added to the logger
	// through the use of `With()`. These labels should never be cleared after
	// logging a single entry, unlike `tempLabel`.
	permLabels *labels

	// tempLabels keeps a record of all the labels that need to be applied to the
	// current log entry. Zap serializes log fields at different parts of the
	// stack, one such location is when calling `core.With` and the other one is
	// when calling `core.Write`. This makes it impossible to (for example) take
	// all `labels.xxx` fields, and wrap them in the `labels` namespace in one go.
	//
	// Instead, we have to filter out these labels at both locations, and then add
	// them back in the proper format right before we call `Write` on the original
	// Zap core.
	tempLabels *labels

	config DriverConfig
}

// WrapCore returns a `zap.Option` that wraps the default core with the
// zapdriver one.
func WrapCore() zap.Option {
	return zap.WrapCore(func(c zapcore.Core) zapcore.Core {
		return &core{
			Core:       c,
			permLabels: newLabels(),
			tempLabels: newLabels()}
	})
}

// WrapCoreWithConfig returns a `zap.Option` that wraps the default core with the
// configured zapdriver one.
func WrapCoreWithConfig(config DriverConfig) zap.Option {
	return zap.WrapCore(func(c zapcore.Core) zapcore.Core {
		return &core{
			Core:       c,
			permLabels: newLabels(),
			tempLabels: newLabels(),
			config:     config,
		}
	})
}

// With adds structured context to the Core.
func (c *core) With(fields []zap.Field) zapcore.Core {
	var lbls *labels
	lbls, fields = c.extractLabels(fields)

	lbls.mutex.RLock()
	c.permLabels.mutex.Lock()
	for k, v := range lbls.store {
		c.permLabels.store[k] = v
	}
	c.permLabels.mutex.Unlock()
	lbls.mutex.RUnlock()

	return &core{
		Core:       c.Core.With(fields),
		permLabels: c.permLabels,
		tempLabels: newLabels(),
		config:     c.config,
	}
}

// Check determines whether the supplied Entry should be logged (using the
// embedded LevelEnabler and possibly some extra logic). If the entry
// should be logged, the Core adds itself to the CheckedEntry and returns
// the result.
//
// Callers must use Check before calling Write.
func (c *core) Check(ent zapcore.Entry, ce *zapcore.CheckedEntry) *zapcore.CheckedEntry {
	if c.Enabled(ent.Level) {
		return ce.AddCore(ent, c)
	}

	return ce
}

func (c *core) Write(ent zapcore.Entry, fields []zapcore.Field) error {
	var lbls *labels
	lbls, fields = c.extractLabels(fields)

	lbls.mutex.RLock()
	c.tempLabels.mutex.Lock()
	for k, v := range lbls.store {
		c.tempLabels.store[k] = v
	}
	c.tempLabels.mutex.Unlock()
	lbls.mutex.RUnlock()

	fields = append(fields, labelsField(c.allLabels()))
	fields = c.withSourceLocation(ent, fields)
	if c.config.ReportAllErrors && ent.Level.Enabled(zapcore.ErrorLevel) {
		fields = c.withErrorReport(ent, fields)
	}

	c.tempLabels.reset()

	return c.Core.Write(ent, fields)
}

// Sync flushes buffered logs (if any).
func (c *core) Sync() error {
	return c.Core.Sync()
}

func (c *core) allLabels() *labels {
	lbls := newLabels()

	lbls.mutex.Lock()
	c.permLabels.mutex.RLock()
	for k, v := range c.permLabels.store {
		lbls.store[k] = v
	}
	c.permLabels.mutex.RUnlock()

	c.tempLabels.mutex.RLock()
	for k, v := range c.tempLabels.store {
		lbls.store[k] = v
	}
	c.tempLabels.mutex.RUnlock()
	lbls.mutex.Unlock()

	return lbls
}

func (c *core) extractLabels(fields []zapcore.Field) (*labels, []zapcore.Field) {
	lbls := newLabels()
	out := []zapcore.Field{}

	lbls.mutex.Lock()
	for i := range fields {
		if !isLabelField(fields[i]) {
			out = append(out, fields[i])
			continue
		}

		lbls.store[strings.Replace(fields[i].Key, "labels.", "", 1)] = fields[i].String
	}
	lbls.mutex.Unlock()

	return lbls, out
}

func (c *core) withLabels(fields []zapcore.Field) []zapcore.Field {
	lbls := newLabels()
	out := []zapcore.Field{}

	lbls.mutex.Lock()
	for i := range fields {
		if isLabelField(fields[i]) {
			lbls.store[strings.Replace(fields[i].Key, "labels.", "", 1)] = fields[i].String
			continue
		}

		out = append(out, fields[i])
	}
	lbls.mutex.Unlock()

	return append(out, labelsField(lbls))
}

func (c *core) withSourceLocation(ent zapcore.Entry, fields []zapcore.Field) []zapcore.Field {
	// If the source location was manually set, don't overwrite it
	for i := range fields {
		if fields[i].Key == sourceKey {
			return fields
		}
	}

	if !ent.Caller.Defined {
		return fields
	}

	return append(fields, SourceLocation(ent.Caller.PC, ent.Caller.File, ent.Caller.Line, true))
}

func (c *core) withErrorReport(ent zapcore.Entry, fields []zapcore.Field) []zapcore.Field {
	// If the error report was manually set, don't overwrite it
	for i := range fields {
		if fields[i].Key == contextKey {
			return fields
		}
	}

	if !ent.Caller.Defined {
		return fields
	}

	return append(fields, ErrorReport(ent.Caller.PC, ent.Caller.File, ent.Caller.Line, true))
}
<|endoftext|>


<commit_before>// Package sh provide an implementation
// for sh command executor.
package sh

import (
	"bufio"
	"io"
	"os"
	"os/exec"

	"github.com/xsb/dog/dog"
)

// Sh imlements sh shell executor.
type Sh struct {
	cmd string
}

func init() {
	sh := &Sh{}
	sh.cmd = "sh"
	dog.RegisterExecutor("sh", sh)
}

// Exec executes the created tmp script and writes the output to the writer.
func (sh *Sh) Exec(t *dog.Task, w io.Writer) error {
	if err := t.ToDisk(); err != nil {
		return err
	}

	defer func() {
		w.Write([]byte("=== Task " + t.Name + " finished ===\n"))
		// Remove temporary script
		err := os.Remove(t.Path)
		if err != nil {
			panic(err)
		}
	}()

	binary, err := exec.LookPath(sh.cmd)
	if err != nil {
		return err
	}

	cmd := exec.Command(binary, string(t.Run))
	stdoutReader, err := cmd.StdoutPipe()
	if err != nil {
		return err
	}

	stderrReader, err := cmd.StderrPipe()
	if err != nil {
		return err
	}

	stdoutScanner := bufio.NewScanner(stdoutReader)
	stderrScanner := bufio.NewScanner(stderrReader)
	go func() {
		for stdoutScanner.Scan() {
			msg := "\033[34m --= MSG: " + stdoutScanner.Text() + "\n\033[0m"
			w.Write([]byte(msg))
		}
	}()

	go func() {
		for stderrScanner.Scan() {
			msg := "\033[31m --= ERR: " + stderrScanner.Text() + "\n\033[0m"
			w.Write([]byte(msg))
		}
	}()

	err = cmd.Start()
	if err != nil {
		return err
	}
	w.Write([]byte("=== Task " + t.Name + " started ===\n"))

	err = cmd.Wait()
	if err != nil {
		return err
	}

	return nil
}
<commit_msg>Pass script path as a parameter instead of script string<commit_after>// Package sh provide an implementation
// for sh command executor.
package sh

import (
	"bufio"
	"io"
	"os"
	"os/exec"

	"github.com/xsb/dog/dog"
)

// Sh imlements sh shell executor.
type Sh struct {
	cmd string
}

func init() {
	sh := &Sh{}
	sh.cmd = "sh"
	dog.RegisterExecutor("sh", sh)
}

// Exec executes the created tmp script and writes the output to the writer.
func (sh *Sh) Exec(t *dog.Task, w io.Writer) error {
	if err := t.ToDisk(); err != nil {
		return err
	}

	defer func() {
		w.Write([]byte("=== Task " + t.Name + " finished ===\n"))
		// Remove temporary script
		err := os.Remove(t.Path)
		if err != nil {
			panic(err)
		}
	}()

	binary, err := exec.LookPath(sh.cmd)
	if err != nil {
		return err
	}

	cmd := exec.Command(binary, t.Path)
	stdoutReader, err := cmd.StdoutPipe()
	if err != nil {
		return err
	}

	stderrReader, err := cmd.StderrPipe()
	if err != nil {
		return err
	}

	stdoutScanner := bufio.NewScanner(stdoutReader)
	stderrScanner := bufio.NewScanner(stderrReader)
	go func() {
		for stdoutScanner.Scan() {
			msg := "\033[34m --= MSG: " + stdoutScanner.Text() + "\n\033[0m"
			w.Write([]byte(msg))
		}
	}()

	go func() {
		for stderrScanner.Scan() {
			msg := "\033[31m --= ERR: " + stderrScanner.Text() + "\n\033[0m"
			w.Write([]byte(msg))
		}
	}()

	err = cmd.Start()
	if err != nil {
		return err
	}
	w.Write([]byte("=== Task " + t.Name + " started ===\n"))

	err = cmd.Wait()
	if err != nil {
		return err
	}

	return nil
}
<|endoftext|>


<commit_before>// This package implements a custom Dispatcher based on the one of the twitch package.
package bot

import "github.com/sgt-kabukiman/kabukibot/twitch"

// Kabukibot's Dispatcher, the one plugins will use.
type Dispatcher interface {
	twitch.Dispatcher

	OnCommand(CommandHandlerFunc, *twitch.Channel) *twitch.Listener
	OnResponse(ResponseHandlerFunc, *twitch.Channel) *twitch.Listener

	HandleCommand(Command)
	HandleResponse(Response)
}

type dispatcher struct {
	twitch.Dispatcher
}

// Create a new Dispatcher.
func NewDispatcher() Dispatcher {
	d := twitch.NewDispatcher()

	return &dispatcher{d}
}

// Add listener for a command (a message starting with "!___").
func (d *dispatcher) OnCommand(f CommandHandlerFunc, c *twitch.Channel) *twitch.Listener {
	return d.AddListener("BOT.CMD", c, f)
}

// Add listener for a response.
func (d *dispatcher) OnResponse(f ResponseHandlerFunc, c *twitch.Channel) *twitch.Listener {
	return d.AddListener("BOT.RESPONSE", c, f)
}

// Trigger a command event and fire all registered listeners in order.
func (d *dispatcher) HandleCommand(cmd Command) {
	d.TriggerEvent("BOT.CMD", cmd.Channel(), func(listener interface{}) {
		listener.(CommandHandlerFunc)(cmd)
	})
}

// Trigger a response event and fire all registered listeners in order.
func (d *dispatcher) HandleResponse(r Response) {
	d.TriggerEvent("BOT.RESPONSE", r.Channel(), func(listener interface{}) {
		listener.(ResponseHandlerFunc)(r)
	})
}
<commit_msg>don't need a dispatcher anymore<commit_after><|endoftext|>


<commit_before>// Copyright 2012 Oliver Eilhard. All rights reserved.
// Use of this source code is governed by a MIT-license.
// See http://olivere.mit-license.org/license.txt for details.

package elastic

import (
	"fmt"
)

// The multi_match query builds further on top of the match query by allowing multiple fields to be specified.
// For more details, see:
// http://www.elasticsearch.org/guide/reference/query-dsl/multi-match-query.html
type MultiMatchQuery struct {
	Query
	text               interface{}
	fields             []string
	fieldBoosts        map[string]*float32
	_type              *MatchQueryType
	operator           string
	analyzer           string
	boost              *float32
	slop               *int
	fuzziness          string
	prefixLength       *int
	maxExpansions      *int
	minimumShouldMatch string
	rewrite            string
	fuzzyRewrite       string
	useDisMax          *bool
	tieBreaker         *int
	lenient            *bool
}

func NewMultiMatchQuery(text interface{}, fields ...string) MultiMatchQuery {
	q := MultiMatchQuery{
		text:        text,
		fields:      make([]string, 0),
		fieldBoosts: make(map[string]*float32),
	}
	q.fields = append(q.fields, fields...)
	return q
}

func (q MultiMatchQuery) Field(field string) MultiMatchQuery {
	q.fields = append(q.fields, field)
	return q
}

func (q MultiMatchQuery) FieldWithBoost(field string, boost float32) MultiMatchQuery {
	q.fields = append(q.fields, field)
	q.fieldBoosts[field] = &boost
	return q
}

func (q MultiMatchQuery) Type(_type MatchQueryType) MultiMatchQuery {
	q._type = &_type
	return q
}

func (q MultiMatchQuery) Operator(operator string) MultiMatchQuery {
	q.operator = operator
	return q
}

func (q MultiMatchQuery) Analyzer(analyzer string) MultiMatchQuery {
	q.analyzer = analyzer
	return q
}

func (q MultiMatchQuery) Boost(boost float32) MultiMatchQuery {
	q.boost = &boost
	return q
}

func (q MultiMatchQuery) Slop(slop int) MultiMatchQuery {
	q.slop = &slop
	return q
}

func (q MultiMatchQuery) Fuzziness(fuzziness string) MultiMatchQuery {
	q.fuzziness = fuzziness
	return q
}

func (q MultiMatchQuery) PrefixLength(prefixLength int) MultiMatchQuery {
	q.prefixLength = &prefixLength
	return q
}

func (q MultiMatchQuery) MaxExpansions(maxExpansions int) MultiMatchQuery {
	q.maxExpansions = &maxExpansions
	return q
}

func (q MultiMatchQuery) MinimumShouldMatch(minimumShouldMatch string) MultiMatchQuery {
	q.minimumShouldMatch = minimumShouldMatch
	return q
}

func (q MultiMatchQuery) Rewrite(rewrite string) MultiMatchQuery {
	q.rewrite = rewrite
	return q
}

func (q MultiMatchQuery) FuzzyRewrite(fuzzyRewrite string) MultiMatchQuery {
	q.fuzzyRewrite = fuzzyRewrite
	return q
}

func (q MultiMatchQuery) UseDisMax(useDisMax bool) MultiMatchQuery {
	q.useDisMax = &useDisMax
	return q
}

func (q MultiMatchQuery) TieBreaker(tieBreaker int) MultiMatchQuery {
	q.tieBreaker = &tieBreaker
	return q
}

func (q MultiMatchQuery) Lenient(lenient bool) MultiMatchQuery {
	q.lenient = &lenient
	return q
}

func (q MultiMatchQuery) Source() interface{} {
	//
	// {
	//   "multi_match" : {
	//     "query" : "this is a test",
	//     "fields" : [ "subject", "message" ]
	//   }
	// }

	source := make(map[string]interface{})

	multiMatch := make(map[string]interface{})
	source["multi_match"] = multiMatch

	multiMatch["query"] = q.text

	if len(q.fields) > 0 {
		fields := make([]string, 0)
		for _, field := range q.fields {
			if boost, found := q.fieldBoosts[field]; found {
				if boost != nil {
					fields = append(fields, fmt.Sprintf("%s^%f", field, *boost))
				} else {
					fields = append(fields, field)
				}
			} else {
				fields = append(fields, field)
			}
		}
		multiMatch["fields"] = fields
	}

	if q._type != nil {
		if *q._type == Boolean {
			multiMatch["type"] = "boolean"
		} else if *q._type == Phrase {
			multiMatch["type"] = "phrase"
		} else if *q._type == PhrasePrefix {
			multiMatch["type"] = "phrase_prefix"
		}
	}

	if q.operator != "" {
		multiMatch["operator"] = q.operator
	}

	if q.analyzer != "" {
		multiMatch["analyzer"] = q.analyzer
	}

	if q.boost != nil {
		multiMatch["boost"] = *q.boost
	}

	if q.slop != nil {
		multiMatch["slop"] = *q.slop
	}

	if q.fuzziness != "" {
		multiMatch["fuzziness"] = q.fuzziness
	}

	if q.prefixLength != nil {
		multiMatch["prefix_length"] = *q.prefixLength
	}

	if q.maxExpansions != nil {
		multiMatch["max_expansions"] = *q.maxExpansions
	}

	if q.minimumShouldMatch != "" {
		multiMatch["minimum_should_match"] = q.minimumShouldMatch
	}

	if q.rewrite != "" {
		multiMatch["rewrite"] = q.rewrite
	}

	if q.fuzzyRewrite != "" {
		multiMatch["fuzzy_rewrite"] = q.fuzzyRewrite
	}

	if q.useDisMax != nil {
		multiMatch["use_dis_max"] = *q.useDisMax
	}

	if q.tieBreaker != nil {
		multiMatch["tie_breaker"] = *q.tieBreaker
	}

	if q.lenient != nil {
		multiMatch["lenient"] = *q.lenient
	}

	return source
}
<commit_msg>TieBreaker in MultiMatchQuery is float32 (as in QueryStringQuery)<commit_after>// Copyright 2012 Oliver Eilhard. All rights reserved.
// Use of this source code is governed by a MIT-license.
// See http://olivere.mit-license.org/license.txt for details.

package elastic

import (
	"fmt"
)

// The multi_match query builds further on top of the match query by allowing multiple fields to be specified.
// For more details, see:
// http://www.elasticsearch.org/guide/reference/query-dsl/multi-match-query.html
type MultiMatchQuery struct {
	Query
	text               interface{}
	fields             []string
	fieldBoosts        map[string]*float32
	_type              *MatchQueryType
	operator           string
	analyzer           string
	boost              *float32
	slop               *int
	fuzziness          string
	prefixLength       *int
	maxExpansions      *int
	minimumShouldMatch string
	rewrite            string
	fuzzyRewrite       string
	useDisMax          *bool
	tieBreaker         *float32
	lenient            *bool
}

func NewMultiMatchQuery(text interface{}, fields ...string) MultiMatchQuery {
	q := MultiMatchQuery{
		text:        text,
		fields:      make([]string, 0),
		fieldBoosts: make(map[string]*float32),
	}
	q.fields = append(q.fields, fields...)
	return q
}

func (q MultiMatchQuery) Field(field string) MultiMatchQuery {
	q.fields = append(q.fields, field)
	return q
}

func (q MultiMatchQuery) FieldWithBoost(field string, boost float32) MultiMatchQuery {
	q.fields = append(q.fields, field)
	q.fieldBoosts[field] = &boost
	return q
}

func (q MultiMatchQuery) Type(_type MatchQueryType) MultiMatchQuery {
	q._type = &_type
	return q
}

func (q MultiMatchQuery) Operator(operator string) MultiMatchQuery {
	q.operator = operator
	return q
}

func (q MultiMatchQuery) Analyzer(analyzer string) MultiMatchQuery {
	q.analyzer = analyzer
	return q
}

func (q MultiMatchQuery) Boost(boost float32) MultiMatchQuery {
	q.boost = &boost
	return q
}

func (q MultiMatchQuery) Slop(slop int) MultiMatchQuery {
	q.slop = &slop
	return q
}

func (q MultiMatchQuery) Fuzziness(fuzziness string) MultiMatchQuery {
	q.fuzziness = fuzziness
	return q
}

func (q MultiMatchQuery) PrefixLength(prefixLength int) MultiMatchQuery {
	q.prefixLength = &prefixLength
	return q
}

func (q MultiMatchQuery) MaxExpansions(maxExpansions int) MultiMatchQuery {
	q.maxExpansions = &maxExpansions
	return q
}

func (q MultiMatchQuery) MinimumShouldMatch(minimumShouldMatch string) MultiMatchQuery {
	q.minimumShouldMatch = minimumShouldMatch
	return q
}

func (q MultiMatchQuery) Rewrite(rewrite string) MultiMatchQuery {
	q.rewrite = rewrite
	return q
}

func (q MultiMatchQuery) FuzzyRewrite(fuzzyRewrite string) MultiMatchQuery {
	q.fuzzyRewrite = fuzzyRewrite
	return q
}

func (q MultiMatchQuery) UseDisMax(useDisMax bool) MultiMatchQuery {
	q.useDisMax = &useDisMax
	return q
}

func (q MultiMatchQuery) TieBreaker(tieBreaker float32) MultiMatchQuery {
	q.tieBreaker = &tieBreaker
	return q
}

func (q MultiMatchQuery) Lenient(lenient bool) MultiMatchQuery {
	q.lenient = &lenient
	return q
}

func (q MultiMatchQuery) Source() interface{} {
	//
	// {
	//   "multi_match" : {
	//     "query" : "this is a test",
	//     "fields" : [ "subject", "message" ]
	//   }
	// }

	source := make(map[string]interface{})

	multiMatch := make(map[string]interface{})
	source["multi_match"] = multiMatch

	multiMatch["query"] = q.text

	if len(q.fields) > 0 {
		fields := make([]string, 0)
		for _, field := range q.fields {
			if boost, found := q.fieldBoosts[field]; found {
				if boost != nil {
					fields = append(fields, fmt.Sprintf("%s^%f", field, *boost))
				} else {
					fields = append(fields, field)
				}
			} else {
				fields = append(fields, field)
			}
		}
		multiMatch["fields"] = fields
	}

	if q._type != nil {
		if *q._type == Boolean {
			multiMatch["type"] = "boolean"
		} else if *q._type == Phrase {
			multiMatch["type"] = "phrase"
		} else if *q._type == PhrasePrefix {
			multiMatch["type"] = "phrase_prefix"
		}
	}

	if q.operator != "" {
		multiMatch["operator"] = q.operator
	}

	if q.analyzer != "" {
		multiMatch["analyzer"] = q.analyzer
	}

	if q.boost != nil {
		multiMatch["boost"] = *q.boost
	}

	if q.slop != nil {
		multiMatch["slop"] = *q.slop
	}

	if q.fuzziness != "" {
		multiMatch["fuzziness"] = q.fuzziness
	}

	if q.prefixLength != nil {
		multiMatch["prefix_length"] = *q.prefixLength
	}

	if q.maxExpansions != nil {
		multiMatch["max_expansions"] = *q.maxExpansions
	}

	if q.minimumShouldMatch != "" {
		multiMatch["minimum_should_match"] = q.minimumShouldMatch
	}

	if q.rewrite != "" {
		multiMatch["rewrite"] = q.rewrite
	}

	if q.fuzzyRewrite != "" {
		multiMatch["fuzzy_rewrite"] = q.fuzzyRewrite
	}

	if q.useDisMax != nil {
		multiMatch["use_dis_max"] = *q.useDisMax
	}

	if q.tieBreaker != nil {
		multiMatch["tie_breaker"] = *q.tieBreaker
	}

	if q.lenient != nil {
		multiMatch["lenient"] = *q.lenient
	}

	return source
}
<|endoftext|>


<commit_before>/*
 *
 * k6 - a next-generation load testing tool
 * Copyright (C) 2016 Load Impact
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 */

package stats

import (
	"encoding/json"
	"errors"
	"strconv"
	"strings"
	"time"

	"github.com/dustin/go-humanize"
	"gopkg.in/guregu/null.v3"
)

const (
	counterString = `"counter"`
	gaugeString   = `"gauge"`
	trendString   = `"trend"`
	rateString    = `"rate"`

	defaultString = `"default"`
	timeString    = `"time"`
	dataString    = `"data"`
)

// Possible values for MetricType.
const (
	Counter = MetricType(iota) // A counter that sums its data points
	Gauge                      // A gauge that displays the latest value
	Trend                      // A trend, min/max/avg/med are interesting
	Rate                       // A rate, displays % of values that aren't 0
)

// Possible values for ValueType.
const (
	Default = ValueType(iota) // Values are presented as-is
	Time                      // Values are timestamps (nanoseconds)
	Data                      // Values are data amounts (bytes)
)

// The serialized metric type is invalid.
var ErrInvalidMetricType = errors.New("Invalid metric type")

// The serialized value type is invalid.
var ErrInvalidValueType = errors.New("Invalid value type")

// A MetricType specifies the type of a metric.
type MetricType int

// MarshalJSON serializes a MetricType as a human readable string.
func (t MetricType) MarshalJSON() ([]byte, error) {
	switch t {
	case Counter:
		return []byte(counterString), nil
	case Gauge:
		return []byte(gaugeString), nil
	case Trend:
		return []byte(trendString), nil
	case Rate:
		return []byte(rateString), nil
	default:
		return nil, ErrInvalidMetricType
	}
}

// UnmarshalJSON deserializes a MetricType from a string representation.
func (t *MetricType) UnmarshalJSON(data []byte) error {
	switch string(data) {
	case counterString:
		*t = Counter
	case gaugeString:
		*t = Gauge
	case trendString:
		*t = Trend
	case rateString:
		*t = Rate
	default:
		return ErrInvalidMetricType
	}

	return nil
}

func (t MetricType) String() string {
	switch t {
	case Counter:
		return counterString
	case Gauge:
		return gaugeString
	case Trend:
		return trendString
	case Rate:
		return rateString
	default:
		return "[INVALID]"
	}
}

// The type of values a metric contains.
type ValueType int

// MarshalJSON serializes a ValueType as a human readable string.
func (t ValueType) MarshalJSON() ([]byte, error) {
	switch t {
	case Default:
		return []byte(defaultString), nil
	case Time:
		return []byte(timeString), nil
	case Data:
		return []byte(dataString), nil
	default:
		return nil, ErrInvalidValueType
	}
}

// UnmarshalJSON deserializes a ValueType from a string representation.
func (t *ValueType) UnmarshalJSON(data []byte) error {
	switch string(data) {
	case defaultString:
		*t = Default
	case timeString:
		*t = Time
	case dataString:
		*t = Data
	default:
		return ErrInvalidValueType
	}

	return nil
}

func (t ValueType) String() string {
	switch t {
	case Default:
		return defaultString
	case Time:
		return timeString
	case Data:
		return dataString
	default:
		return "[INVALID]"
	}
}

// SampleTags is an immutable string[string] map for tags. Once a tag
// set is created, direct modification is prohibited. It has
// copy-on-write semantics and uses pointers for faster comparison
// between maps, since the same tag set is often used for multiple samples.
// All methods should not panic, even if they are called on a nil pointer.
type SampleTags struct {
	tags map[string]string
	json []byte
}

// Get returns an empty string and false if the the requested key is not
// present or its value and true if it is.
func (st *SampleTags) Get(key string) (string, bool) {
	if st == nil {
		return "", false
	}
	val, ok := st.tags[key]
	return val, ok
}

// IsEqual tries to compare two tag sets with maximum efficiency.
func (st *SampleTags) IsEqual(other *SampleTags) bool {
	if st == other {
		return true
	}
	if st == nil || other == nil || len(st.tags) != len(other.tags) {
		return false
	}
	for k, v := range st.tags {
		if otherv, ok := other.tags[k]; !ok || v != otherv {
			return false
		}
	}
	return true
}

func (st *SampleTags) Contains(other *SampleTags) bool {
	if st == other {
		return true
	}
	if st == nil || other == nil || len(st.tags) < len(other.tags) {
		return false
	}

	for k, v := range other.tags {
		if st.tags[k] != v {
			return false
		}
	}

	return true
}

// MarshalJSON serializes SampleTags to a JSON string and caches
// the result. It is not thread safe in the sense that the Go race
// detector will complain if it's used concurrently, but no data
// should be corrupted.
func (st *SampleTags) MarshalJSON() ([]byte, error) {
	if st == nil {
		return []byte("null"), nil
	}
	if st.json != nil {
		return st.json, nil
	}
	res, err := json.Marshal(st.tags)
	if err != nil {
		return res, err
	}
	st.json = res
	return res, nil
}

// UnmarshalJSON deserializes SampleTags from a JSON string.
func (st *SampleTags) UnmarshalJSON(data []byte) error {
	if st == nil {
		*st = SampleTags{}
	}
	return json.Unmarshal(data, &st.tags)
}

// CloneTags copies the underlying set of a sample tags and
// returns it. If the receiver is nil, it returns an empty non-nil map.
func (st *SampleTags) CloneTags() map[string]string {
	res := map[string]string{}
	if st != nil {
		for k, v := range st.tags {
			res[k] = v
		}
	}
	return res
}

// NewSampleTags *copies* the supplied tag set and returns a new SampleTags
// instance with the key-value pairs from it.
func NewSampleTags(data map[string]string) *SampleTags {
	tags := map[string]string{}
	for k, v := range data {
		tags[k] = v
	}
	return &SampleTags{tags: tags}
}

// IntoSampleTags "consumes" the passed map and creates a new SampleTags
// struct with the data. The map is set to nil as a hint that it shouldn't
// be changed after it has been transformed into an "immutable" tag set.
// Oh, how I miss Rust and move semantics... :)
func IntoSampleTags(data *map[string]string) *SampleTags {
	res := SampleTags{tags: *data}
	*data = nil
	return &res
}

// A Sample is a single measurement.
type Sample struct {
	Metric *Metric
	Time   time.Time
	Tags   *SampleTags
	Value  float64
}

// A Metric defines the shape of a set of data.
type Metric struct {
	Name       string       `json:"name"`
	Type       MetricType   `json:"type"`
	Contains   ValueType    `json:"contains"`
	Tainted    null.Bool    `json:"tainted"`
	Thresholds Thresholds   `json:"thresholds"`
	Submetrics []*Submetric `json:"submetrics"`
	Sub        Submetric    `json:"sub,omitempty"`
	Sink       Sink         `json:"-"`
}

func New(name string, typ MetricType, t ...ValueType) *Metric {
	vt := Default
	if len(t) > 0 {
		vt = t[0]
	}
	var sink Sink
	switch typ {
	case Counter:
		sink = &CounterSink{}
	case Gauge:
		sink = &GaugeSink{}
	case Trend:
		sink = &TrendSink{}
	case Rate:
		sink = &RateSink{}
	default:
		return nil
	}
	return &Metric{Name: name, Type: typ, Contains: vt, Sink: sink}
}

func (m *Metric) HumanizeValue(v float64) string {
	switch m.Type {
	case Rate:
		// Truncate instead of round when decreasing precision to 2 decimal places
		return strconv.FormatFloat(float64(int(v*100*100))/100, 'f', 2, 64) + "%"
	default:
		switch m.Contains {
		case Time:
			d := ToD(v)
			switch {
			case d > time.Minute:
				d -= d % (1 * time.Second)
			case d > time.Second:
				d -= d % (10 * time.Millisecond)
			case d > time.Millisecond:
				d -= d % (10 * time.Microsecond)
			case d > time.Microsecond:
				d -= d % (10 * time.Nanosecond)
			}
			return d.String()
		case Data:
			return humanize.Bytes(uint64(v))
		default:
			return humanize.Ftoa(v)
		}
	}
}

// A Submetric represents a filtered dataset based on a parent metric.
type Submetric struct {
	Name   string      `json:"name"`
	Parent string      `json:"parent"`
	Suffix string      `json:"suffix"`
	Tags   *SampleTags `json:"tags"`
	Metric *Metric     `json:"-"`
}

// Creates a submetric from a name.
func NewSubmetric(name string) (parentName string, sm *Submetric) {
	parts := strings.SplitN(strings.TrimSuffix(name, "}"), "{", 2)
	if len(parts) == 1 {
		return parts[0], &Submetric{Name: name}
	}

	kvs := strings.Split(parts[1], ",")
	tags := make(map[string]string, len(kvs))
	for _, kv := range kvs {
		if kv == "" {
			continue
		}
		parts := strings.SplitN(kv, ":", 2)

		key := strings.TrimSpace(strings.Trim(parts[0], `"'`))
		if len(parts) != 2 {
			tags[key] = ""
			continue
		}

		value := strings.TrimSpace(strings.Trim(parts[1], `"'`))
		tags[key] = value
	}
	return parts[0], &Submetric{Name: name, Parent: parts[0], Suffix: parts[1], Tags: IntoSampleTags(&tags)}
}

func (m *Metric) Summary(t time.Duration) *Summary {
	return &Summary{
		Metric:  m,
		Summary: m.Sink.Format(t),
	}
}

type Summary struct {
	Metric  *Metric            `json:"metric"`
	Summary map[string]float64 `json:"summary"`
}
<commit_msg>Returning true for SampleTags.Contains(nil)<commit_after>/*
 *
 * k6 - a next-generation load testing tool
 * Copyright (C) 2016 Load Impact
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 */

package stats

import (
	"encoding/json"
	"errors"
	"strconv"
	"strings"
	"time"

	"github.com/dustin/go-humanize"
	"gopkg.in/guregu/null.v3"
)

const (
	counterString = `"counter"`
	gaugeString   = `"gauge"`
	trendString   = `"trend"`
	rateString    = `"rate"`

	defaultString = `"default"`
	timeString    = `"time"`
	dataString    = `"data"`
)

// Possible values for MetricType.
const (
	Counter = MetricType(iota) // A counter that sums its data points
	Gauge                      // A gauge that displays the latest value
	Trend                      // A trend, min/max/avg/med are interesting
	Rate                       // A rate, displays % of values that aren't 0
)

// Possible values for ValueType.
const (
	Default = ValueType(iota) // Values are presented as-is
	Time                      // Values are timestamps (nanoseconds)
	Data                      // Values are data amounts (bytes)
)

// The serialized metric type is invalid.
var ErrInvalidMetricType = errors.New("Invalid metric type")

// The serialized value type is invalid.
var ErrInvalidValueType = errors.New("Invalid value type")

// A MetricType specifies the type of a metric.
type MetricType int

// MarshalJSON serializes a MetricType as a human readable string.
func (t MetricType) MarshalJSON() ([]byte, error) {
	switch t {
	case Counter:
		return []byte(counterString), nil
	case Gauge:
		return []byte(gaugeString), nil
	case Trend:
		return []byte(trendString), nil
	case Rate:
		return []byte(rateString), nil
	default:
		return nil, ErrInvalidMetricType
	}
}

// UnmarshalJSON deserializes a MetricType from a string representation.
func (t *MetricType) UnmarshalJSON(data []byte) error {
	switch string(data) {
	case counterString:
		*t = Counter
	case gaugeString:
		*t = Gauge
	case trendString:
		*t = Trend
	case rateString:
		*t = Rate
	default:
		return ErrInvalidMetricType
	}

	return nil
}

func (t MetricType) String() string {
	switch t {
	case Counter:
		return counterString
	case Gauge:
		return gaugeString
	case Trend:
		return trendString
	case Rate:
		return rateString
	default:
		return "[INVALID]"
	}
}

// The type of values a metric contains.
type ValueType int

// MarshalJSON serializes a ValueType as a human readable string.
func (t ValueType) MarshalJSON() ([]byte, error) {
	switch t {
	case Default:
		return []byte(defaultString), nil
	case Time:
		return []byte(timeString), nil
	case Data:
		return []byte(dataString), nil
	default:
		return nil, ErrInvalidValueType
	}
}

// UnmarshalJSON deserializes a ValueType from a string representation.
func (t *ValueType) UnmarshalJSON(data []byte) error {
	switch string(data) {
	case defaultString:
		*t = Default
	case timeString:
		*t = Time
	case dataString:
		*t = Data
	default:
		return ErrInvalidValueType
	}

	return nil
}

func (t ValueType) String() string {
	switch t {
	case Default:
		return defaultString
	case Time:
		return timeString
	case Data:
		return dataString
	default:
		return "[INVALID]"
	}
}

// SampleTags is an immutable string[string] map for tags. Once a tag
// set is created, direct modification is prohibited. It has
// copy-on-write semantics and uses pointers for faster comparison
// between maps, since the same tag set is often used for multiple samples.
// All methods should not panic, even if they are called on a nil pointer.
type SampleTags struct {
	tags map[string]string
	json []byte
}

// Get returns an empty string and false if the the requested key is not
// present or its value and true if it is.
func (st *SampleTags) Get(key string) (string, bool) {
	if st == nil {
		return "", false
	}
	val, ok := st.tags[key]
	return val, ok
}

// IsEqual tries to compare two tag sets with maximum efficiency.
func (st *SampleTags) IsEqual(other *SampleTags) bool {
	if st == other {
		return true
	}
	if st == nil || other == nil || len(st.tags) != len(other.tags) {
		return false
	}
	for k, v := range st.tags {
		if otherv, ok := other.tags[k]; !ok || v != otherv {
			return false
		}
	}
	return true
}

func (st *SampleTags) Contains(other *SampleTags) bool {
	if st == other || other == nil {
		return true
	}
	if st == nil || len(st.tags) < len(other.tags) {
		return false
	}

	for k, v := range other.tags {
		if st.tags[k] != v {
			return false
		}
	}

	return true
}

// MarshalJSON serializes SampleTags to a JSON string and caches
// the result. It is not thread safe in the sense that the Go race
// detector will complain if it's used concurrently, but no data
// should be corrupted.
func (st *SampleTags) MarshalJSON() ([]byte, error) {
	if st == nil {
		return []byte("null"), nil
	}
	if st.json != nil {
		return st.json, nil
	}
	res, err := json.Marshal(st.tags)
	if err != nil {
		return res, err
	}
	st.json = res
	return res, nil
}

// UnmarshalJSON deserializes SampleTags from a JSON string.
func (st *SampleTags) UnmarshalJSON(data []byte) error {
	if st == nil {
		*st = SampleTags{}
	}
	return json.Unmarshal(data, &st.tags)
}

// CloneTags copies the underlying set of a sample tags and
// returns it. If the receiver is nil, it returns an empty non-nil map.
func (st *SampleTags) CloneTags() map[string]string {
	res := map[string]string{}
	if st != nil {
		for k, v := range st.tags {
			res[k] = v
		}
	}
	return res
}

// NewSampleTags *copies* the supplied tag set and returns a new SampleTags
// instance with the key-value pairs from it.
func NewSampleTags(data map[string]string) *SampleTags {
	tags := map[string]string{}
	for k, v := range data {
		tags[k] = v
	}
	return &SampleTags{tags: tags}
}

// IntoSampleTags "consumes" the passed map and creates a new SampleTags
// struct with the data. The map is set to nil as a hint that it shouldn't
// be changed after it has been transformed into an "immutable" tag set.
// Oh, how I miss Rust and move semantics... :)
func IntoSampleTags(data *map[string]string) *SampleTags {
	res := SampleTags{tags: *data}
	*data = nil
	return &res
}

// A Sample is a single measurement.
type Sample struct {
	Metric *Metric
	Time   time.Time
	Tags   *SampleTags
	Value  float64
}

// A Metric defines the shape of a set of data.
type Metric struct {
	Name       string       `json:"name"`
	Type       MetricType   `json:"type"`
	Contains   ValueType    `json:"contains"`
	Tainted    null.Bool    `json:"tainted"`
	Thresholds Thresholds   `json:"thresholds"`
	Submetrics []*Submetric `json:"submetrics"`
	Sub        Submetric    `json:"sub,omitempty"`
	Sink       Sink         `json:"-"`
}

func New(name string, typ MetricType, t ...ValueType) *Metric {
	vt := Default
	if len(t) > 0 {
		vt = t[0]
	}
	var sink Sink
	switch typ {
	case Counter:
		sink = &CounterSink{}
	case Gauge:
		sink = &GaugeSink{}
	case Trend:
		sink = &TrendSink{}
	case Rate:
		sink = &RateSink{}
	default:
		return nil
	}
	return &Metric{Name: name, Type: typ, Contains: vt, Sink: sink}
}

func (m *Metric) HumanizeValue(v float64) string {
	switch m.Type {
	case Rate:
		// Truncate instead of round when decreasing precision to 2 decimal places
		return strconv.FormatFloat(float64(int(v*100*100))/100, 'f', 2, 64) + "%"
	default:
		switch m.Contains {
		case Time:
			d := ToD(v)
			switch {
			case d > time.Minute:
				d -= d % (1 * time.Second)
			case d > time.Second:
				d -= d % (10 * time.Millisecond)
			case d > time.Millisecond:
				d -= d % (10 * time.Microsecond)
			case d > time.Microsecond:
				d -= d % (10 * time.Nanosecond)
			}
			return d.String()
		case Data:
			return humanize.Bytes(uint64(v))
		default:
			return humanize.Ftoa(v)
		}
	}
}

// A Submetric represents a filtered dataset based on a parent metric.
type Submetric struct {
	Name   string      `json:"name"`
	Parent string      `json:"parent"`
	Suffix string      `json:"suffix"`
	Tags   *SampleTags `json:"tags"`
	Metric *Metric     `json:"-"`
}

// Creates a submetric from a name.
func NewSubmetric(name string) (parentName string, sm *Submetric) {
	parts := strings.SplitN(strings.TrimSuffix(name, "}"), "{", 2)
	if len(parts) == 1 {
		return parts[0], &Submetric{Name: name}
	}

	kvs := strings.Split(parts[1], ",")
	tags := make(map[string]string, len(kvs))
	for _, kv := range kvs {
		if kv == "" {
			continue
		}
		parts := strings.SplitN(kv, ":", 2)

		key := strings.TrimSpace(strings.Trim(parts[0], `"'`))
		if len(parts) != 2 {
			tags[key] = ""
			continue
		}

		value := strings.TrimSpace(strings.Trim(parts[1], `"'`))
		tags[key] = value
	}
	return parts[0], &Submetric{Name: name, Parent: parts[0], Suffix: parts[1], Tags: IntoSampleTags(&tags)}
}

func (m *Metric) Summary(t time.Duration) *Summary {
	return &Summary{
		Metric:  m,
		Summary: m.Sink.Format(t),
	}
}

type Summary struct {
	Metric  *Metric            `json:"metric"`
	Summary map[string]float64 `json:"summary"`
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"errors"
	"flag"
	"fmt"
	"log"
	"math"
	"net"
	"os"
	"os/signal"
	"regexp"
	"runtime"
	"sort"
	"strconv"
	"strings"
	"syscall"
	"time"

	"github.com/stvp/go-toml-config"
)

const (
	VERSION                 = "0.5.2-alpha"
	MAX_UNPROCESSED_PACKETS = 1000
	MAX_UDP_PACKET_SIZE     = 512
)

var signalchan chan os.Signal

type Packet struct {
	Bucket   string
	Value    float64
	Modifier string
	Sampling float32
}

type Float64Slice []float64

func (s Float64Slice) Len() int           { return len(s) }
func (s Float64Slice) Swap(i, j int)      { s[i], s[j] = s[j], s[i] }
func (s Float64Slice) Less(i, j int) bool { return s[i] < s[j] }

type Percentiles []*Percentile
type Percentile struct {
	float float64
	str   string
}

func (a *Percentiles) Set(s string) error {
	f, err := strconv.ParseFloat(s, 64)
	if err != nil {
		return err
	}
	*a = append(*a, &Percentile{f, strings.Replace(s, ".", "_", -1)})
	return nil
}
func (p *Percentile) String() string {
	return p.str
}
func (a *Percentiles) String() string {
	return fmt.Sprintf("%v", *a)
}

var (
	listen_addr          = config.String("listen_addr", ":8125")
	graphite_addr        = config.String("graphite_addr", "127.0.0.1:2003")
	flushInterval        = config.Int("flush_interval", 10)
	prefix_rates         = config.String("prefix_rates", "stats.")
	prefix_timers        = config.String("prefix_timers", "stats.timers.")
	prefix_gauges        = config.String("prefix_gauges", "stats.gauges.")
	percentile_tresholds = config.String("percentile_tresholds", "")
	percentThreshold     = Percentiles{}

	debug       = flag.Bool("debug", false, "print statistics sent to graphite")
	showVersion = flag.Bool("version", false, "print version string")
	config_file = flag.String("config_file", "/etc/statsdaemon.ini", "config file location")
)

var (
	In       = make(chan *Packet, MAX_UNPROCESSED_PACKETS)
	counters = make(map[string]float64)
	gauges   = make(map[string]float64)
	timers   = make(map[string]Float64Slice)
)

func monitor() {
	period := time.Duration(*flushInterval) * time.Second
	ticker := time.NewTicker(period)
	for {
		select {
		case sig := <-signalchan:
			fmt.Printf("!! Caught signal %d... shutting down\n", sig)
			if err := submit(time.Now().Add(period)); err != nil {
				log.Printf("ERROR: %s", err)
			}
			return
		case <-ticker.C:
			if err := submit(time.Now().Add(period)); err != nil {
				log.Printf("ERROR: %s", err)
			}
		case s := <-In:
			if s.Modifier == "ms" {
				_, ok := timers[s.Bucket]
				if !ok {
					var t Float64Slice
					timers[s.Bucket] = t
				}
				timers[s.Bucket] = append(timers[s.Bucket], s.Value)
			} else if s.Modifier == "g" {
				gauges[s.Bucket] = s.Value
			} else {
				v, ok := counters[s.Bucket]
				if !ok || v < 0 {
					counters[s.Bucket] = 0
				}
				counters[s.Bucket] += s.Value * float64(1/s.Sampling)
			}
		}
	}
}

func submit(deadline time.Time) error {
	var buffer bytes.Buffer
	var num int64

	now := time.Now().Unix()

	client, err := net.Dial("tcp", *graphite_addr)
	if err != nil {
		if *debug {
			log.Printf("WARNING: resetting counters when in debug mode")
			processCounters(&buffer, now)
			processGauges(&buffer, now)
			processTimers(&buffer, now, percentThreshold)
		}
		errmsg := fmt.Sprintf("dialing %s failed - %s", *graphite_addr, err)
		return errors.New(errmsg)
	}
	defer client.Close()

	err = client.SetDeadline(deadline)
	if err != nil {
		errmsg := fmt.Sprintf("could not set deadline:", err)
		return errors.New(errmsg)
	}

	num += processCounters(&buffer, now)
	num += processGauges(&buffer, now)
	num += processTimers(&buffer, now, percentThreshold)
	if num == 0 {
		return nil
	}

	if *debug {
		for _, line := range bytes.Split(buffer.Bytes(), []byte("\n")) {
			if len(line) == 0 {
				continue
			}
			log.Printf("DEBUG: %s", line)
		}
	}

	_, err = client.Write(buffer.Bytes())
	if err != nil {
		errmsg := fmt.Sprintf("failed to write stats - %s", err)
		return errors.New(errmsg)
	}

	log.Printf("sent %d stats to %s", num, *graphite_addr)

	return nil
}

func processCounters(buffer *bytes.Buffer, now int64) int64 {
	var num int64
	for s, c := range counters {
		counters[s] = -1
		v := c / float64(*flushInterval)
		fmt.Fprintf(buffer, "%s%s %f %d\n", *prefix_rates, s, v, now)
		num++
		delete(counters, s)
	}
	//counters = make(map[string]float64) this should be better than deleting every single entry
	return num
}

func processGauges(buffer *bytes.Buffer, now int64) int64 {
	var num int64
	for g, c := range gauges {
		if c == math.MaxUint64 {
			continue
		}
		fmt.Fprintf(buffer, "%s%s %f %d\n", *prefix_gauges, g, c, now)
		gauges[g] = math.MaxUint64
		num++
	}
	return num
}

func processTimers(buffer *bytes.Buffer, now int64, pctls Percentiles) int64 {
	// these are the metrics that get exposed:
	// count  estimate of original amount, by dividing received by samplerate
	// count_ps  same, per second
	// lower
	// mean  // arithmetic mean
	// mean_<pct> // arithmetic mean of values below <pct> percentile
	// median
	// std  standard deviation
	// sum
	// sum_90
	// upper
	// upper_90 / lower_90

	// internal vars:
	// seen -> len(t), i.e. real values seen.

	var num int64
	for u, t := range timers {
		if len(t) > 0 {
			seen := len(t)
			num++

			sort.Sort(t)
			min := t[0]
			max := t[len(t)-1]
			count := len(t)
			count_ps := float64(count) / float64(*flushInterval)

			sum := float64(0)
			for _, value := range t {
				sum += value
			}
			mean := float64(sum) / float64(len(t))
			sumOfDiffs := float64(0)
			for _, value := range t {
				sumOfDiffs += math.Pow((float64(value) - mean), 2)
			}
			stddev := math.Sqrt(sumOfDiffs / float64(seen))
			mid := seen / 2
			var median float64
			if seen%2 == 1 {
				median = t[mid]
			} else {
				median = (t[mid-1] + t[mid]) / 2
			}
			var cumulativeValues Float64Slice
			cumulativeValues = make(Float64Slice, seen, seen)
			cumulativeValues[0] = t[0]
			for i := 1; i < seen; i++ {
				cumulativeValues[i] = t[i] + cumulativeValues[i-1]
			}

			maxAtThreshold := max
			sum_pct := sum
			mean_pct := mean

			for _, pct := range pctls {

				if len(t) > 1 {
					var abs float64
					if pct.float >= 0 {
						abs = pct.float
					} else {
						abs = 100 + pct.float
					}
					// poor man's math.Round(x):
					// math.Floor(x + 0.5)
					indexOfPerc := int(math.Floor(((abs / 100.0) * float64(count)) + 0.5))
					if pct.float >= 0 {
						sum_pct = cumulativeValues[indexOfPerc-1]
						maxAtThreshold = t[indexOfPerc-1]
					} else {
						maxAtThreshold = t[indexOfPerc]
						sum_pct = cumulativeValues[seen-1] - cumulativeValues[seen-indexOfPerc-1]
					}
					mean_pct = float64(sum_pct) / float64(indexOfPerc)
				}

				var tmpl string
				var pctstr string
				if pct.float >= 0 {
					tmpl = "%s%s.upper_%s %f %d\n"
					pctstr = pct.str
				} else {
					tmpl = "%s%s.lower_%s %f %d\n"
					pctstr = pct.str[1:]
				}
				fmt.Fprintf(buffer, tmpl, *prefix_timers, u, pctstr, maxAtThreshold, now)
				fmt.Fprintf(buffer, "%s%s.mean_%s %f %d\n", *prefix_timers, u, pctstr, mean_pct, now)
				fmt.Fprintf(buffer, "%s%s.sum_%s %f %d\n", *prefix_timers, u, pctstr, sum_pct, now)
			}

			var z Float64Slice
			timers[u] = z

			fmt.Fprintf(buffer, "%s%s.mean %f %d\n", *prefix_timers, u, mean, now)
			fmt.Fprintf(buffer, "%s%s.median %f %d\n", *prefix_timers, u, median, now)
			fmt.Fprintf(buffer, "%s%s.std %f %d\n", *prefix_timers, u, stddev, now)
			fmt.Fprintf(buffer, "%s%s.sum %f %d\n", *prefix_timers, u, sum, now)
			fmt.Fprintf(buffer, "%s%s.upper %f %d\n", *prefix_timers, u, max, now)
			fmt.Fprintf(buffer, "%s%s.lower %f %d\n", *prefix_timers, u, min, now)
			fmt.Fprintf(buffer, "%s%s.count %d %d\n", *prefix_timers, u, count, now)
			fmt.Fprintf(buffer, "%s%s.count_ps %f %d\n", *prefix_timers, u, count_ps, now)
		}
	}
	return num
}

var packetRegexp = regexp.MustCompile("^([^:]+):(-?[0-9\\.]+)\\|(g|c|ms)(\\|@([0-9\\.]+))?\n?$")

func parseMessage(data []byte) []*Packet {
	var output []*Packet
	for _, line := range bytes.Split(data, []byte("\n")) {
		if len(line) == 0 {
			continue
		}
		item := packetRegexp.FindSubmatch(line)
		if len(item) == 0 {
			if *debug {
				log.Printf("invalid line ('%s' does not match pattern)\n", line)
			}
			continue
		}

		value, err := strconv.ParseFloat(string(item[2]), 64)
		if err != nil {
			log.Printf("ERROR: failed to parseFloat %s - %s", item[2], err)
			continue
		}

		sampleRate, err := strconv.ParseFloat(string(item[5]), 32)
		if err != nil {
			sampleRate = 1
		}

		packet := &Packet{
			Bucket:   string(item[1]),
			Value:    value,
			Modifier: string(item[3]),
			Sampling: float32(sampleRate),
		}
		output = append(output, packet)
	}
	return output
}

func udpListener() {
	address, _ := net.ResolveUDPAddr("udp", *listen_addr)
	log.Printf("listening on %s", address)
	listener, err := net.ListenUDP("udp", address)
	if err != nil {
		log.Fatalf("ERROR: ListenUDP - %s", err)
	}
	defer listener.Close()

	message := make([]byte, MAX_UDP_PACKET_SIZE)
	for {
		n, remaddr, err := listener.ReadFromUDP(message)
		if err != nil {
			log.Printf("ERROR: reading UDP packet from %+v - %s", remaddr, err)
			continue
		}

		for _, p := range parseMessage(message[:n]) {
			In <- p
		}
	}
}

func main() {
	flag.Parse()

	if *showVersion {
		fmt.Printf("statsdaemon v%s (built w/%s)\n", VERSION, runtime.Version())
		return
	}
	config.Parse(*config_file)
	pcts := strings.Split(*percentile_tresholds, ",")
	for _, pct := range pcts {
		percentThreshold.Set(pct)
	}

	signalchan = make(chan os.Signal, 1)
	signal.Notify(signalchan, syscall.SIGTERM)

	go udpListener()
	monitor()
}
<commit_msg>support cpu profiling<commit_after>package main

import (
	"bytes"
	"errors"
	"flag"
	"fmt"
	"log"
	"math"
	"net"
	"os"
	"os/signal"
	"regexp"
	"runtime"
	"runtime/pprof"
	"sort"
	"strconv"
	"strings"
	"syscall"
	"time"

	"github.com/stvp/go-toml-config"
)

const (
	VERSION                 = "0.5.2-alpha"
	MAX_UNPROCESSED_PACKETS = 1000
	MAX_UDP_PACKET_SIZE     = 512
)

var signalchan chan os.Signal

type Packet struct {
	Bucket   string
	Value    float64
	Modifier string
	Sampling float32
}

type Float64Slice []float64

func (s Float64Slice) Len() int           { return len(s) }
func (s Float64Slice) Swap(i, j int)      { s[i], s[j] = s[j], s[i] }
func (s Float64Slice) Less(i, j int) bool { return s[i] < s[j] }

type Percentiles []*Percentile
type Percentile struct {
	float float64
	str   string
}

func (a *Percentiles) Set(s string) error {
	f, err := strconv.ParseFloat(s, 64)
	if err != nil {
		return err
	}
	*a = append(*a, &Percentile{f, strings.Replace(s, ".", "_", -1)})
	return nil
}
func (p *Percentile) String() string {
	return p.str
}
func (a *Percentiles) String() string {
	return fmt.Sprintf("%v", *a)
}

var (
	listen_addr          = config.String("listen_addr", ":8125")
	graphite_addr        = config.String("graphite_addr", "127.0.0.1:2003")
	flushInterval        = config.Int("flush_interval", 10)
	prefix_rates         = config.String("prefix_rates", "stats.")
	prefix_timers        = config.String("prefix_timers", "stats.timers.")
	prefix_gauges        = config.String("prefix_gauges", "stats.gauges.")
	percentile_tresholds = config.String("percentile_tresholds", "")
	percentThreshold     = Percentiles{}

	debug       = flag.Bool("debug", false, "print statistics sent to graphite")
	showVersion = flag.Bool("version", false, "print version string")
	config_file = flag.String("config_file", "/etc/statsdaemon.ini", "config file location")
	cpuprofile  = flag.String("cpuprofile", "", "write cpu profile to file")
)

var (
	In       = make(chan *Packet, MAX_UNPROCESSED_PACKETS)
	counters = make(map[string]float64)
	gauges   = make(map[string]float64)
	timers   = make(map[string]Float64Slice)
)

func monitor() {
	period := time.Duration(*flushInterval) * time.Second
	ticker := time.NewTicker(period)
	for {
		select {
		case sig := <-signalchan:
			fmt.Printf("!! Caught signal %d... shutting down\n", sig)
			if err := submit(time.Now().Add(period)); err != nil {
				log.Printf("ERROR: %s", err)
			}
			return
		case <-ticker.C:
			if err := submit(time.Now().Add(period)); err != nil {
				log.Printf("ERROR: %s", err)
			}
		case s := <-In:
			if s.Modifier == "ms" {
				_, ok := timers[s.Bucket]
				if !ok {
					var t Float64Slice
					timers[s.Bucket] = t
				}
				timers[s.Bucket] = append(timers[s.Bucket], s.Value)
			} else if s.Modifier == "g" {
				gauges[s.Bucket] = s.Value
			} else {
				v, ok := counters[s.Bucket]
				if !ok || v < 0 {
					counters[s.Bucket] = 0
				}
				counters[s.Bucket] += s.Value * float64(1/s.Sampling)
			}
		}
	}
}

func submit(deadline time.Time) error {
	var buffer bytes.Buffer
	var num int64

	now := time.Now().Unix()

	client, err := net.Dial("tcp", *graphite_addr)
	if err != nil {
		if *debug {
			log.Printf("WARNING: resetting counters when in debug mode")
			processCounters(&buffer, now)
			processGauges(&buffer, now)
			processTimers(&buffer, now, percentThreshold)
		}
		errmsg := fmt.Sprintf("dialing %s failed - %s", *graphite_addr, err)
		return errors.New(errmsg)
	}
	defer client.Close()

	err = client.SetDeadline(deadline)
	if err != nil {
		errmsg := fmt.Sprintf("could not set deadline:", err)
		return errors.New(errmsg)
	}

	num += processCounters(&buffer, now)
	num += processGauges(&buffer, now)
	num += processTimers(&buffer, now, percentThreshold)
	if num == 0 {
		return nil
	}

	if *debug {
		for _, line := range bytes.Split(buffer.Bytes(), []byte("\n")) {
			if len(line) == 0 {
				continue
			}
			log.Printf("DEBUG: %s", line)
		}
	}

	_, err = client.Write(buffer.Bytes())
	if err != nil {
		errmsg := fmt.Sprintf("failed to write stats - %s", err)
		return errors.New(errmsg)
	}

	log.Printf("sent %d stats to %s", num, *graphite_addr)

	return nil
}

func processCounters(buffer *bytes.Buffer, now int64) int64 {
	var num int64
	for s, c := range counters {
		counters[s] = -1
		v := c / float64(*flushInterval)
		fmt.Fprintf(buffer, "%s%s %f %d\n", *prefix_rates, s, v, now)
		num++
		delete(counters, s)
	}
	//counters = make(map[string]float64) this should be better than deleting every single entry
	return num
}

func processGauges(buffer *bytes.Buffer, now int64) int64 {
	var num int64
	for g, c := range gauges {
		if c == math.MaxUint64 {
			continue
		}
		fmt.Fprintf(buffer, "%s%s %f %d\n", *prefix_gauges, g, c, now)
		gauges[g] = math.MaxUint64
		num++
	}
	return num
}

func processTimers(buffer *bytes.Buffer, now int64, pctls Percentiles) int64 {
	// these are the metrics that get exposed:
	// count  estimate of original amount, by dividing received by samplerate
	// count_ps  same, per second
	// lower
	// mean  // arithmetic mean
	// mean_<pct> // arithmetic mean of values below <pct> percentile
	// median
	// std  standard deviation
	// sum
	// sum_90
	// upper
	// upper_90 / lower_90

	// internal vars:
	// seen -> len(t), i.e. real values seen.

	var num int64
	for u, t := range timers {
		if len(t) > 0 {
			seen := len(t)
			num++

			sort.Sort(t)
			min := t[0]
			max := t[len(t)-1]
			count := len(t)
			count_ps := float64(count) / float64(*flushInterval)

			sum := float64(0)
			for _, value := range t {
				sum += value
			}
			mean := float64(sum) / float64(len(t))
			sumOfDiffs := float64(0)
			for _, value := range t {
				sumOfDiffs += math.Pow((float64(value) - mean), 2)
			}
			stddev := math.Sqrt(sumOfDiffs / float64(seen))
			mid := seen / 2
			var median float64
			if seen%2 == 1 {
				median = t[mid]
			} else {
				median = (t[mid-1] + t[mid]) / 2
			}
			var cumulativeValues Float64Slice
			cumulativeValues = make(Float64Slice, seen, seen)
			cumulativeValues[0] = t[0]
			for i := 1; i < seen; i++ {
				cumulativeValues[i] = t[i] + cumulativeValues[i-1]
			}

			maxAtThreshold := max
			sum_pct := sum
			mean_pct := mean

			for _, pct := range pctls {

				if len(t) > 1 {
					var abs float64
					if pct.float >= 0 {
						abs = pct.float
					} else {
						abs = 100 + pct.float
					}
					// poor man's math.Round(x):
					// math.Floor(x + 0.5)
					indexOfPerc := int(math.Floor(((abs / 100.0) * float64(count)) + 0.5))
					if pct.float >= 0 {
						sum_pct = cumulativeValues[indexOfPerc-1]
						maxAtThreshold = t[indexOfPerc-1]
					} else {
						maxAtThreshold = t[indexOfPerc]
						sum_pct = cumulativeValues[seen-1] - cumulativeValues[seen-indexOfPerc-1]
					}
					mean_pct = float64(sum_pct) / float64(indexOfPerc)
				}

				var tmpl string
				var pctstr string
				if pct.float >= 0 {
					tmpl = "%s%s.upper_%s %f %d\n"
					pctstr = pct.str
				} else {
					tmpl = "%s%s.lower_%s %f %d\n"
					pctstr = pct.str[1:]
				}
				fmt.Fprintf(buffer, tmpl, *prefix_timers, u, pctstr, maxAtThreshold, now)
				fmt.Fprintf(buffer, "%s%s.mean_%s %f %d\n", *prefix_timers, u, pctstr, mean_pct, now)
				fmt.Fprintf(buffer, "%s%s.sum_%s %f %d\n", *prefix_timers, u, pctstr, sum_pct, now)
			}

			var z Float64Slice
			timers[u] = z

			fmt.Fprintf(buffer, "%s%s.mean %f %d\n", *prefix_timers, u, mean, now)
			fmt.Fprintf(buffer, "%s%s.median %f %d\n", *prefix_timers, u, median, now)
			fmt.Fprintf(buffer, "%s%s.std %f %d\n", *prefix_timers, u, stddev, now)
			fmt.Fprintf(buffer, "%s%s.sum %f %d\n", *prefix_timers, u, sum, now)
			fmt.Fprintf(buffer, "%s%s.upper %f %d\n", *prefix_timers, u, max, now)
			fmt.Fprintf(buffer, "%s%s.lower %f %d\n", *prefix_timers, u, min, now)
			fmt.Fprintf(buffer, "%s%s.count %d %d\n", *prefix_timers, u, count, now)
			fmt.Fprintf(buffer, "%s%s.count_ps %f %d\n", *prefix_timers, u, count_ps, now)
		}
	}
	return num
}

var packetRegexp = regexp.MustCompile("^([^:]+):(-?[0-9\\.]+)\\|(g|c|ms)(\\|@([0-9\\.]+))?\n?$")

func parseMessage(data []byte) []*Packet {
	var output []*Packet
	for _, line := range bytes.Split(data, []byte("\n")) {
		if len(line) == 0 {
			continue
		}
		item := packetRegexp.FindSubmatch(line)
		if len(item) == 0 {
			if *debug {
				log.Printf("invalid line ('%s' does not match pattern)\n", line)
			}
			continue
		}

		value, err := strconv.ParseFloat(string(item[2]), 64)
		if err != nil {
			log.Printf("ERROR: failed to parseFloat %s - %s", item[2], err)
			continue
		}

		sampleRate, err := strconv.ParseFloat(string(item[5]), 32)
		if err != nil {
			sampleRate = 1
		}

		packet := &Packet{
			Bucket:   string(item[1]),
			Value:    value,
			Modifier: string(item[3]),
			Sampling: float32(sampleRate),
		}
		output = append(output, packet)
	}
	return output
}

func udpListener() {
	address, _ := net.ResolveUDPAddr("udp", *listen_addr)
	log.Printf("listening on %s", address)
	listener, err := net.ListenUDP("udp", address)
	if err != nil {
		log.Fatalf("ERROR: ListenUDP - %s", err)
	}
	defer listener.Close()

	message := make([]byte, MAX_UDP_PACKET_SIZE)
	for {
		n, remaddr, err := listener.ReadFromUDP(message)
		if err != nil {
			log.Printf("ERROR: reading UDP packet from %+v - %s", remaddr, err)
			continue
		}

		for _, p := range parseMessage(message[:n]) {
			In <- p
		}
	}
}

func main() {
	flag.Parse()

	if *showVersion {
		fmt.Printf("statsdaemon v%s (built w/%s)\n", VERSION, runtime.Version())
		return
	}
	if *cpuprofile != "" {
		f, err := os.Create(*cpuprofile)
		if err != nil {
			log.Fatal(err)
		}
		pprof.StartCPUProfile(f)
		defer pprof.StopCPUProfile()
	}
	config.Parse(*config_file)
	pcts := strings.Split(*percentile_tresholds, ",")
	for _, pct := range pcts {
		percentThreshold.Set(pct)
	}

	signalchan = make(chan os.Signal, 1)
	signal.Notify(signalchan, syscall.SIGTERM)

	go udpListener()
	monitor()
}
<|endoftext|>


<commit_before>package triggers

import "git.lukas.moe/sn0w/Karen/helpers"

/**
 * Full credit to Der-Eddy and his original python implementation for Shinobu-Chan.
 * @link https://github.com/Der-Eddy/discord_bot
 */
type IPTables struct {}

func (i IPTables) Triggers() []string {
    return []string{
        "ipt",
        "iptables",
    }
}

func (i IPTables) Response() string {
    return helpers.GetText("triggers.iptables")
}
<commit_msg>Remove unused comment<commit_after>package triggers

import "git.lukas.moe/sn0w/Karen/helpers"

type IPTables struct {}

func (i IPTables) Triggers() []string {
    return []string{
        "ipt",
        "iptables",
    }
}

func (i IPTables) Response() string {
    return helpers.GetText("triggers.iptables")
}
<|endoftext|>


<commit_before>// Copyright 2012 Aaron Jacobs. All Rights Reserved.
// Author: aaronjjacobs@gmail.com (Aaron Jacobs)
//
// 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 backup

import (
	. "github.com/jacobsa/oglematchers"
	. "github.com/jacobsa/ogletest"
	"bytes"
	"errors"
	"github.com/jacobsa/comeback/blob"
	"github.com/jacobsa/comeback/blob/mock"
	"github.com/jacobsa/comeback/io/mock"
	"github.com/jacobsa/oglemock"
	"io"
	"testing"
	"testing/iotest"
)

const (
	expectedChunkSize = 1<<24
)

func TestRegister(t *testing.T) { RunTests(t) }

////////////////////////////////////////////////////////////////////////
// Helpers
////////////////////////////////////////////////////////////////////////

func makeChunk(char int) []byte {
	charStr := string(char)
	AssertEq(1, len(charStr), "Invalid character: %d", char)
	return bytes.Repeat([]byte(charStr), expectedChunkSize)
}

func returnStoreError(err string) oglemock.Action {
	f := func(b []byte) (blob.Score, error) { return nil, errors.New(err) }
	return oglemock.Invoke(f)
}

type FileSaverTest struct {
	blobStore mock_blob.MockStore
	mockReader mock_io.MockReader
	fileSaver FileSaver

	// Will be used instead of mockReader if non-nil.
	reader io.Reader

	scores []blob.Score
	err error
}

func init() { RegisterTestSuite(&FileSaverTest{}) }

func (t *FileSaverTest) SetUp(i *TestInfo) {
	t.blobStore = mock_blob.NewMockStore(i.MockController, "blobStore")
	t.mockReader = mock_io.NewMockReader(i.MockController, "reader")
	t.fileSaver, _ = NewFileSaver(t.blobStore)
}

func (t *FileSaverTest) callSaver() {
	var reader io.Reader = t.mockReader
	if t.reader != nil {
		reader = t.reader
	}

	t.scores, t.err = t.fileSaver.Save(reader)
}

////////////////////////////////////////////////////////////////////////
// Tests
////////////////////////////////////////////////////////////////////////

func (t *FileSaverTest) NoDataInReader() {
	// Reader
	t.reader = new(bytes.Buffer)

	// Call
	t.callSaver()

	AssertEq(nil, t.err)
	ExpectThat(t.scores, ElementsAre())
}

func (t *FileSaverTest) ReadErrorInFirstChunk() {
	// Chunks
	chunk0 := makeChunk('a')

	// Reader
	t.reader = io.MultiReader(
		iotest.TimeoutReader(bytes.NewReader(chunk0)),
	)

	// Call
	t.callSaver()

	ExpectThat(t.err, Error(HasSubstr("Reading")))
	ExpectThat(t.err, Error(HasSubstr("chunk")))
	ExpectThat(t.err, Error(HasSubstr(iotest.ErrTimeout.Error())))
}

func (t *FileSaverTest) ReadErrorInSecondChunk() {
	// Chunks
	chunk0 := makeChunk('a')
	chunk1 := makeChunk('b')

	// Reader
	t.reader = io.MultiReader(
		bytes.NewReader(chunk0),
		iotest.TimeoutReader(bytes.NewReader(chunk1)),
	)

	// Blob store
	ExpectCall(t.blobStore, "Store")(Any()).Times(1)

	// Call
	t.callSaver()

	ExpectThat(t.err, Error(HasSubstr("Reading")))
	ExpectThat(t.err, Error(HasSubstr("chunk")))
	ExpectThat(t.err, Error(HasSubstr(iotest.ErrTimeout.Error())))
}

func (t *FileSaverTest) CopesWithShortReadsWithinFullSizeChunks() {
	// Chunks
	chunk0 := makeChunk('a')

	// Reader
	t.reader = io.MultiReader(
		iotest.OneByteReader(bytes.NewReader(chunk0)),
	)

	// Blob store
	ExpectCall(t.blobStore, "Store")(DeepEquals(chunk0)).
		WillOnce(returnStoreError(""))

	// Call
	t.callSaver()
}

func (t *FileSaverTest) CopesWithEofAndNonZeroData() {
	// Chunks
	chunk0 := makeChunk('a')

	// Reader
	t.reader = io.MultiReader(
		iotest.DataErrReader(bytes.NewReader(chunk0)),
	)

	// Blob store
	ExpectCall(t.blobStore, "Store")(DeepEquals(chunk0)).
		WillOnce(returnStoreError(""))

	// Call
	t.callSaver()
}

func (t *FileSaverTest) OneSmallerSizedChunk() {
	// Chunks
	chunk0 := makeChunk('a')
	chunk0 = chunk0[0:len(chunk0)-10]

	// Reader
	t.reader = io.MultiReader(
		bytes.NewReader(chunk0),
	)

	// Blob store
	score0 := blob.ComputeScore([]byte(""))

	ExpectCall(t.blobStore, "Store")(DeepEquals(chunk0)).
		WillOnce(oglemock.Return(score0, nil))

	// Call
	t.callSaver()
}

func (t *FileSaverTest) OneFullSizedChunk() {
	// Chunks
	chunk0 := makeChunk('a')

	// Reader
	t.reader = io.MultiReader(
		bytes.NewReader(chunk0),
	)

	// Blob store
	score0 := blob.ComputeScore([]byte(""))

	ExpectCall(t.blobStore, "Store")(DeepEquals(chunk0)).
		WillOnce(oglemock.Return(score0, nil))

	// Call
	t.callSaver()
}

func (t *FileSaverTest) OneFullSizedChunkPlusOneByte() {
	// Chunks
	chunk0 := makeChunk('a')
	chunk1 := []byte{0xde}

	// Reader
	t.reader = io.MultiReader(
		bytes.NewReader(chunk0),
		bytes.NewReader(chunk1),
	)

	// Blob store
	score0 := blob.ComputeScore([]byte(""))
	score1 := blob.ComputeScore([]byte(""))

	ExpectCall(t.blobStore, "Store")(DeepEquals(chunk0)).
		WillOnce(oglemock.Return(score0, nil))

	ExpectCall(t.blobStore, "Store")(DeepEquals(chunk1)).
		WillOnce(oglemock.Return(score1, nil))

	// Call
	t.callSaver()
}

func (t *FileSaverTest) MultipleChunksWithNoRemainder() {
	ExpectEq("TODO", "")
}

func (t *FileSaverTest) MultipleChunksWithSmallRemainder() {
	ExpectEq("TODO", "")
}

func (t *FileSaverTest) MultipleChunksWithLargeRemainder() {
	ExpectEq("TODO", "")
}

func (t *FileSaverTest) ErrorStoringOneChunk() {
	ExpectEq("TODO", "")
}

func (t *FileSaverTest) ResultForEmptyReader() {
	ExpectEq("TODO", "")
}

func (t *FileSaverTest) AllStoresSuccessful() {
	ExpectEq("TODO", "")
}
<commit_msg>FileSaverTest.MultipleChunksWithNoRemainder<commit_after>// Copyright 2012 Aaron Jacobs. All Rights Reserved.
// Author: aaronjjacobs@gmail.com (Aaron Jacobs)
//
// 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 backup

import (
	. "github.com/jacobsa/oglematchers"
	. "github.com/jacobsa/ogletest"
	"bytes"
	"errors"
	"github.com/jacobsa/comeback/blob"
	"github.com/jacobsa/comeback/blob/mock"
	"github.com/jacobsa/comeback/io/mock"
	"github.com/jacobsa/oglemock"
	"io"
	"testing"
	"testing/iotest"
)

const (
	expectedChunkSize = 1<<24
)

func TestRegister(t *testing.T) { RunTests(t) }

////////////////////////////////////////////////////////////////////////
// Helpers
////////////////////////////////////////////////////////////////////////

func makeChunk(char int) []byte {
	charStr := string(char)
	AssertEq(1, len(charStr), "Invalid character: %d", char)
	return bytes.Repeat([]byte(charStr), expectedChunkSize)
}

func returnStoreError(err string) oglemock.Action {
	f := func(b []byte) (blob.Score, error) { return nil, errors.New(err) }
	return oglemock.Invoke(f)
}

type FileSaverTest struct {
	blobStore mock_blob.MockStore
	mockReader mock_io.MockReader
	fileSaver FileSaver

	// Will be used instead of mockReader if non-nil.
	reader io.Reader

	scores []blob.Score
	err error
}

func init() { RegisterTestSuite(&FileSaverTest{}) }

func (t *FileSaverTest) SetUp(i *TestInfo) {
	t.blobStore = mock_blob.NewMockStore(i.MockController, "blobStore")
	t.mockReader = mock_io.NewMockReader(i.MockController, "reader")
	t.fileSaver, _ = NewFileSaver(t.blobStore)
}

func (t *FileSaverTest) callSaver() {
	var reader io.Reader = t.mockReader
	if t.reader != nil {
		reader = t.reader
	}

	t.scores, t.err = t.fileSaver.Save(reader)
}

////////////////////////////////////////////////////////////////////////
// Tests
////////////////////////////////////////////////////////////////////////

func (t *FileSaverTest) NoDataInReader() {
	// Reader
	t.reader = new(bytes.Buffer)

	// Call
	t.callSaver()

	AssertEq(nil, t.err)
	ExpectThat(t.scores, ElementsAre())
}

func (t *FileSaverTest) ReadErrorInFirstChunk() {
	// Chunks
	chunk0 := makeChunk('a')

	// Reader
	t.reader = io.MultiReader(
		iotest.TimeoutReader(bytes.NewReader(chunk0)),
	)

	// Call
	t.callSaver()

	ExpectThat(t.err, Error(HasSubstr("Reading")))
	ExpectThat(t.err, Error(HasSubstr("chunk")))
	ExpectThat(t.err, Error(HasSubstr(iotest.ErrTimeout.Error())))
}

func (t *FileSaverTest) ReadErrorInSecondChunk() {
	// Chunks
	chunk0 := makeChunk('a')
	chunk1 := makeChunk('b')

	// Reader
	t.reader = io.MultiReader(
		bytes.NewReader(chunk0),
		iotest.TimeoutReader(bytes.NewReader(chunk1)),
	)

	// Blob store
	ExpectCall(t.blobStore, "Store")(Any()).Times(1)

	// Call
	t.callSaver()

	ExpectThat(t.err, Error(HasSubstr("Reading")))
	ExpectThat(t.err, Error(HasSubstr("chunk")))
	ExpectThat(t.err, Error(HasSubstr(iotest.ErrTimeout.Error())))
}

func (t *FileSaverTest) CopesWithShortReadsWithinFullSizeChunks() {
	// Chunks
	chunk0 := makeChunk('a')

	// Reader
	t.reader = io.MultiReader(
		iotest.OneByteReader(bytes.NewReader(chunk0)),
	)

	// Blob store
	ExpectCall(t.blobStore, "Store")(DeepEquals(chunk0)).
		WillOnce(returnStoreError(""))

	// Call
	t.callSaver()
}

func (t *FileSaverTest) CopesWithEofAndNonZeroData() {
	// Chunks
	chunk0 := makeChunk('a')

	// Reader
	t.reader = io.MultiReader(
		iotest.DataErrReader(bytes.NewReader(chunk0)),
	)

	// Blob store
	ExpectCall(t.blobStore, "Store")(DeepEquals(chunk0)).
		WillOnce(returnStoreError(""))

	// Call
	t.callSaver()
}

func (t *FileSaverTest) OneSmallerSizedChunk() {
	// Chunks
	chunk0 := makeChunk('a')
	chunk0 = chunk0[0:len(chunk0)-10]

	// Reader
	t.reader = io.MultiReader(
		bytes.NewReader(chunk0),
	)

	// Blob store
	score0 := blob.ComputeScore([]byte(""))

	ExpectCall(t.blobStore, "Store")(DeepEquals(chunk0)).
		WillOnce(oglemock.Return(score0, nil))

	// Call
	t.callSaver()
}

func (t *FileSaverTest) OneFullSizedChunk() {
	// Chunks
	chunk0 := makeChunk('a')

	// Reader
	t.reader = io.MultiReader(
		bytes.NewReader(chunk0),
	)

	// Blob store
	score0 := blob.ComputeScore([]byte(""))

	ExpectCall(t.blobStore, "Store")(DeepEquals(chunk0)).
		WillOnce(oglemock.Return(score0, nil))

	// Call
	t.callSaver()
}

func (t *FileSaverTest) OneFullSizedChunkPlusOneByte() {
	// Chunks
	chunk0 := makeChunk('a')
	chunk1 := []byte{0xde}

	// Reader
	t.reader = io.MultiReader(
		bytes.NewReader(chunk0),
		bytes.NewReader(chunk1),
	)

	// Blob store
	score0 := blob.ComputeScore([]byte(""))
	score1 := blob.ComputeScore([]byte(""))

	ExpectCall(t.blobStore, "Store")(DeepEquals(chunk0)).
		WillOnce(oglemock.Return(score0, nil))

	ExpectCall(t.blobStore, "Store")(DeepEquals(chunk1)).
		WillOnce(oglemock.Return(score1, nil))

	// Call
	t.callSaver()
}

func (t *FileSaverTest) MultipleChunksWithNoRemainder() {
	// Chunks
	chunk0 := makeChunk('a')
	chunk1 := makeChunk('b')
	chunk2 := makeChunk('c')

	// Reader
	t.reader = io.MultiReader(
		bytes.NewReader(chunk0),
		bytes.NewReader(chunk1),
		bytes.NewReader(chunk2),
	)

	// Blob store
	score0 := blob.ComputeScore([]byte(""))
	score1 := blob.ComputeScore([]byte(""))
	score2 := blob.ComputeScore([]byte(""))

	ExpectCall(t.blobStore, "Store")(DeepEquals(chunk0)).
		WillOnce(oglemock.Return(score0, nil))

	ExpectCall(t.blobStore, "Store")(DeepEquals(chunk1)).
		WillOnce(oglemock.Return(score1, nil))

	ExpectCall(t.blobStore, "Store")(DeepEquals(chunk2)).
		WillOnce(oglemock.Return(score2, nil))

	// Call
	t.callSaver()
}

func (t *FileSaverTest) MultipleChunksWithSmallRemainder() {
	ExpectEq("TODO", "")
}

func (t *FileSaverTest) MultipleChunksWithLargeRemainder() {
	ExpectEq("TODO", "")
}

func (t *FileSaverTest) ErrorStoringOneChunk() {
	ExpectEq("TODO", "")
}

func (t *FileSaverTest) ResultForEmptyReader() {
	ExpectEq("TODO", "")
}

func (t *FileSaverTest) AllStoresSuccessful() {
	ExpectEq("TODO", "")
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"os"
)

var cmdStart = &Command{
	Exec:        runStart,
	UsageLine:   "start [OPTIONS] SERVER [SERVER...]",
	Description: "Start a stopped server.",
	Help:        "Start a stopped server.",
}

func runStart(cmd *Command, args []string) {
	if len(args) != 1 {
		fmt.Fprintf(os.Stderr, "usage: scw %s\n", cmd.UsageLine)
		os.Exit(1)
	}
	needle := args[0]
	server := cmd.GetServer(needle)
	err := cmd.API.PostServerAction(server, "poweron")
	if err != nil {
		fmt.Fprintf(os.Stderr, "failed to start server %s: %s\n", server, err)
		os.Exit(1)
	}
}
<commit_msg>Added handling of multiple needles in 'scw start'. #16<commit_after>package main

import (
	"fmt"
	"os"
)

var cmdStart = &Command{
	Exec:        runStart,
	UsageLine:   "start [OPTIONS] SERVER [SERVER...]",
	Description: "Start a stopped server.",
	Help:        "Start a stopped server.",
}

func runStart(cmd *Command, args []string) {
	if len(args) == 0 {
		fmt.Fprintf(os.Stderr, "usage: scw %s\n", cmd.UsageLine)
		os.Exit(1)
	}
	has_error := false
	for _, needle := range args {
		server := cmd.GetServer(needle)
		err := cmd.API.PostServerAction(server, "poweron")
		if err != nil {
			fmt.Fprintf(os.Stderr, "failed to start server %s: %s\n", server, err)
			has_error = true
		} else {
			fmt.Fprintf(os.Stdout, "%s\n", server)
		}
	}
	if has_error {
		os.Exit(1)
	}
}
<|endoftext|>


<commit_before>// 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 main

import (
	"encoding/json"
	"errors"
	"flag"
	"fmt"
	"log"
	"net/http"
	"os"
	"os/exec"
	"os/signal"
	"regexp"
	"sort"
	"strconv"
	"strings"
	"sync"
	"time"

	"github.com/mattn/go-runewidth"
	"github.com/nsf/termbox-go"
)

const TIMEOUT = time.Duration(time.Second * 10)
const URL = "http://finance.yahoo.com/webservice/v1/symbols/%s/quote?format=json"
const UP = "↑"   // rune 8593
const DOWN = "↓" // rune 8595

var re = regexp.MustCompile(`^\d.+\.\d{2}`) // this is to have only 2 decimal places
var signalChan = make(chan os.Signal, 1)    // channel to catch ctrl-c

var (
	symbolFlag   = flag.String("s", "", "Symbols for ticker, comma seperate (no spaces)")
	intervalFlag = flag.Int("i", 0, "Interval for stock data to be updated in seconds")
)

type Stock struct {
	List List `json:"list"`
}

type List struct {
	Meta      Meta        `json:"meta"`
	Resources []Resources `json:"resources"`
}

type Meta struct {
	Type  string `json:"type"`
	Start uint   `json:"start"`
	Count uint   `json:"count"`
}

type Resources struct {
	Resource Resource `json:"resource"`
}

type Resource struct {
	Classname string `json:"classname"`
	Fields    Fields `json:"fields"`
}

type Fields struct {
	Name    string `json:"name"`
	Price   string `json:"price"`
	Symbol  string `json:"symbol"`
	TS      string `json:"ts"`
	Type    string `json:"type"`
	UTCTime string `json:"utctime"`
	Volume  string `json:"volume"`
}

type stockticker struct {
	quotes   map[string]map[string]float64
	interval time.Duration
	m        *sync.Mutex
}

// clearScreen runs a shell clear command
func clearScreen() {
	c := exec.Command("clear")
	c.Stdout = os.Stdout
	c.Run()
}

func NewStockTicker(i time.Duration) *stockticker {
	return &stockticker{
		quotes:   make(map[string]map[string]float64),
		interval: i,
		m:        &sync.Mutex{},
	}
}

func (t *stockticker) add(symbol string) {
	t.m.Lock()
	defer t.m.Unlock()
	if _, ok := t.quotes[symbol]; !ok {
		t.quotes[symbol] = map[string]float64{}
	}

}

func (t *stockticker) updateStock(symbol string, price float64) {
	t.m.Lock()
	defer t.m.Unlock()
	t.quotes[symbol] = map[string]float64{
		"previous": t.quotes[symbol]["current"],
		"current":  price,
	}
}

func query(symbol string) (*Stock, error) {
	data := &Stock{}
	client := http.Client{
		Timeout: TIMEOUT,
	}

	resp, err := client.Get(fmt.Sprintf(URL, symbol))
	if err != nil {
		return nil, errors.New("unable to retrive symbol data")
	}
	defer resp.Body.Close()

	if err := json.NewDecoder(resp.Body).Decode(&data); err != nil {
		log.Fatalln(err)
		os.Exit(1)
	}
	return data, nil
}

func convertPrice(p string) float64 {
	price, err := strconv.ParseFloat(p, 64)
	if err != nil {
		log.Fatalln(err)
		os.Exit(1)
	}
	return price
}

func (t *stockticker) runner() {
	var wg sync.WaitGroup
	for k, _ := range t.quotes {
		wg.Add(1)
		go func(k string) {
			defer wg.Done()
			stock, err := query(k)
			if err != nil {
				log.Fatalln(err)
				os.Exit(1)
			}
			t.updateStock(stock.List.Resources[0].Resource.Fields.Symbol,
				convertPrice(re.FindString(stock.List.Resources[0].Resource.Fields.Price)),
			)
		}(k)
	}
	wg.Wait()
}

func (t *stockticker) printData() {
	var keys []string
	for k := range t.quotes {
		keys = append(keys, k)
	}
	sort.Strings(keys)

	pos := 1
	for _, k := range keys {
		if t.quotes[k]["previous"] == 0.00 || t.quotes[k]["previous"] == t.quotes[k]["current"] {
			printTb(1, pos, fmt.Sprintf("%6s %7v %7s %4s\n", k, t.quotes[k]["current"], "-", "-"))
			pos++
			//fmt.Printf("%6s %7v %%%5s %4s\n", k, v["current"], "-", "-")
		} else if t.quotes[k]["current"] > t.quotes[k]["previous"] {
			printTb(1, pos, fmt.Sprintf("%6s %7v %7v %4s\n", k, t.quotes[k]["current"], t.quotes[k]["previous"], UP))
			//fmt.Printf("%6s %7v %%%5v %4s\n", k, v["current"], 100*(v["previous"]/v["current"]), green(UP))
			pos++
		} else {
			printTb(1, pos, fmt.Sprintf("%6s %7v %7v %4s\n", k, t.quotes[k]["current"], t.quotes[k]["previous"], DOWN))
			//fmt.Printf("%6s %7v %%%5v %4s\n", k, v["current"], 100*(v["previous"]/v["current"]), red(DOWN))
			pos++
		}
	}
}

func printTb(x, y int, msg string) {
	for _, c := range []rune(msg) {
		termbox.SetCell(x, y, c, termbox.ColorWhite, termbox.ColorDefault)
		x += runewidth.RuneWidth(c)
	}
	termbox.Flush()
}

func main() {
	flag.Parse()

	signal.Notify(signalChan, os.Interrupt)
	go func() {
		for range signalChan {
			os.Exit(1)
		}
	}()

	if *symbolFlag == "" {
		flag.Usage()
		os.Exit(1)
	}

	t := NewStockTicker(time.Duration(*intervalFlag) * time.Second)

	switch {
	case strings.Contains(*symbolFlag, ","):
		for _, a := range strings.Split(*symbolFlag, ",") {
			t.add(a)
		}
	default:
		t.add(*symbolFlag)
	}

	err := termbox.Init()
	if err != nil {
		log.Fatal(err)
	}
	termbox.Clear(termbox.ColorDefault, termbox.ColorDefault)

	event := make(chan termbox.Event)
	go func() {
		for {
			// Post events to channel
			event <- termbox.PollEvent()
		}
	}()

loop:
	for {
		t.runner()
		t.printData()

		// Poll key event or timeout (maybe)
		select {
		case <-event:
			break loop
		case <-time.After(t.interval):
			continue loop
		}
	}
	close(event)
	time.Sleep(1 * time.Second)
	termbox.Close()
	os.Exit(0)
}
<commit_msg>make sure to handle error handling from the cli errors correctly<commit_after>// 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 main

import (
	"encoding/json"
	"errors"
	"flag"
	"fmt"
	"log"
	"net/http"
	"os"
	"os/exec"
	"os/signal"
	"regexp"
	"sort"
	"strconv"
	"strings"
	"sync"
	"time"

	"github.com/mattn/go-runewidth"
	"github.com/nsf/termbox-go"
)

const TIMEOUT = time.Duration(time.Second * 10)
const URL = "http://finance.yahoo.com/webservice/v1/symbols/%s/quote?format=json"
const UP = "↑"   // rune 8593
const DOWN = "↓" // rune 8595

var re = regexp.MustCompile(`^\d.+\.\d{2}`) // this is to have only 2 decimal places
var signalChan = make(chan os.Signal, 1)    // channel to catch ctrl-c

var (
	symbolFlag   = flag.String("s", "", "Symbols for ticker, comma seperate (no spaces)")
	intervalFlag = flag.Int("i", 0, "Interval for stock data to be updated in seconds")
)

type Stock struct {
	List List `json:"list"`
}

type List struct {
	Meta      Meta        `json:"meta"`
	Resources []Resources `json:"resources"`
}

type Meta struct {
	Type  string `json:"type"`
	Start uint   `json:"start"`
	Count uint   `json:"count"`
}

type Resources struct {
	Resource Resource `json:"resource"`
}

type Resource struct {
	Classname string `json:"classname"`
	Fields    Fields `json:"fields"`
}

type Fields struct {
	Name    string `json:"name"`
	Price   string `json:"price"`
	Symbol  string `json:"symbol"`
	TS      string `json:"ts"`
	Type    string `json:"type"`
	UTCTime string `json:"utctime"`
	Volume  string `json:"volume"`
}

type stockticker struct {
	quotes   map[string]map[string]float64
	interval time.Duration
	m        *sync.Mutex
}

// clearScreen runs a shell clear command
func clearScreen() {
	c := exec.Command("clear")
	c.Stdout = os.Stdout
	c.Run()
}

func NewStockTicker(i time.Duration) *stockticker {
	return &stockticker{
		quotes:   make(map[string]map[string]float64),
		interval: i,
		m:        &sync.Mutex{},
	}
}

func (t *stockticker) add(symbol string) {
	t.m.Lock()
	defer t.m.Unlock()
	if _, ok := t.quotes[symbol]; !ok {
		t.quotes[symbol] = map[string]float64{}
	}

}

func (t *stockticker) updateStock(symbol string, price float64) {
	t.m.Lock()
	defer t.m.Unlock()
	t.quotes[symbol] = map[string]float64{
		"previous": t.quotes[symbol]["current"],
		"current":  price,
	}
}

func query(symbol string) (*Stock, error) {
	data := &Stock{}
	client := http.Client{
		Timeout: TIMEOUT,
	}

	resp, err := client.Get(fmt.Sprintf(URL, symbol))
	if err != nil {
		return nil, errors.New("unable to retrive symbol data")
	}
	defer resp.Body.Close()

	if err := json.NewDecoder(resp.Body).Decode(&data); err != nil {
		log.Fatalln(err)
		os.Exit(1)
	}
	return data, nil
}

func convertPrice(p string) float64 {
	price, err := strconv.ParseFloat(p, 64)
	if err != nil {
		log.Fatalln(err)
		os.Exit(1)
	}
	return price
}

func (t *stockticker) runner() {
	var wg sync.WaitGroup
	for k, _ := range t.quotes {
		wg.Add(1)
		go func(k string) {
			defer wg.Done()
			stock, err := query(k)
			if err != nil {
				log.Fatalln(err)
				os.Exit(1)
			}
			t.updateStock(stock.List.Resources[0].Resource.Fields.Symbol,
				convertPrice(re.FindString(stock.List.Resources[0].Resource.Fields.Price)),
			)
		}(k)
	}
	wg.Wait()
}

func (t *stockticker) printData() {
	var keys []string
	for k := range t.quotes {
		keys = append(keys, k)
	}
	sort.Strings(keys)

	pos := 1
	for _, k := range keys {
		if t.quotes[k]["previous"] == 0.00 || t.quotes[k]["previous"] == t.quotes[k]["current"] {
			printTb(1, pos, fmt.Sprintf("%6s %7v %7s %4s\n", k, t.quotes[k]["current"], "-", "-"))
			pos++
			//fmt.Printf("%6s %7v %%%5s %4s\n", k, v["current"], "-", "-")
		} else if t.quotes[k]["current"] > t.quotes[k]["previous"] {
			printTb(1, pos, fmt.Sprintf("%6s %7v %7v %4s\n", k, t.quotes[k]["current"], t.quotes[k]["previous"], UP))
			//fmt.Printf("%6s %7v %%%5v %4s\n", k, v["current"], 100*(v["previous"]/v["current"]), green(UP))
			pos++
		} else {
			printTb(1, pos, fmt.Sprintf("%6s %7v %7v %4s\n", k, t.quotes[k]["current"], t.quotes[k]["previous"], DOWN))
			//fmt.Printf("%6s %7v %%%5v %4s\n", k, v["current"], 100*(v["previous"]/v["current"]), red(DOWN))
			pos++
		}
	}
}

func printTb(x, y int, msg string) {
	for _, c := range []rune(msg) {
		termbox.SetCell(x, y, c, termbox.ColorWhite, termbox.ColorDefault)
		x += runewidth.RuneWidth(c)
	}
	termbox.Flush()
}

func main() {
	flag.Parse()

	signal.Notify(signalChan, os.Interrupt)
	go func() {
		for range signalChan {
			os.Exit(1)
		}
	}()

	if flag.NFlag() != 2 || *symbolFlag == "" {
		flag.Usage()
		os.Exit(1)
	}

	t := NewStockTicker(time.Duration(*intervalFlag) * time.Second)

	switch {
	case strings.Contains(*symbolFlag, ","):
		for _, a := range strings.Split(*symbolFlag, ",") {
			t.add(a)
		}
	default:
		t.add(*symbolFlag)
	}

	err := termbox.Init()
	if err != nil {
		log.Fatal(err)
	}
	termbox.Clear(termbox.ColorDefault, termbox.ColorDefault)

	event := make(chan termbox.Event)
	go func() {
		for {
			// Post events to channel
			event <- termbox.PollEvent()
		}
	}()

loop:
	for {
		t.runner()
		t.printData()

		// Poll key event or timeout (maybe)
		select {
		case <-event:
			break loop
		case <-time.After(t.interval):
			continue loop
		}
	}
	close(event)
	time.Sleep(1 * time.Second)
	termbox.Close()
	os.Exit(0)
}
<|endoftext|>


<commit_before>package libnum

import (
  "github.com/ncw/gmp"
)

func BytesToNumber(src []byte) *gmp.Int {
  return new(gmp.Int).SetBytes(src)
}

func NumberToBytes(src *gmp.Int) []byte {
  return src.Bytes()
}

/*
 * returns true if n is a perfect square false otherwise
 */
func IsPerfectSquare(n *gmp.Int) bool {
  h := new(gmp.Int).And(n, gmp.NewInt(0xF))

  if h.Cmp(gmp.NewInt(9)) > 1 {
    return false
  }

  if (h.Cmp(gmp.NewInt(2)) != 0 && h.Cmp(gmp.NewInt(3)) != 0 &&
     h.Cmp(gmp.NewInt(5)) != 0 && h.Cmp(gmp.NewInt(6)) != 0 &&
     h.Cmp(gmp.NewInt(7)) != 0 && h.Cmp(gmp.NewInt(8)) != 0) {

    t := new(gmp.Int).Sqrt(n)

    if t.Mul(t,t).Cmp(n) == 0 {
      return true
    } else {
      false
    }
  }

  return false
}

func RationalToContfract(x, y *gmp.Int) []int {
  a := new(gmp.Int).Div(x,y)
  b := new(gmp.Int).Mul(a,y)
  c := new(gmp.Int)

  var pquotients []int

  if b.Cmp(x) == 0 {
    return []int{int(a.Int64())}
  }
  c.Mul(y,a).Sub(x,c)
  pquotients = RationalToContfract(y, c)
  pquotients = append([]int{int(a.Int64())}, pquotients...)
  return pquotients
}<commit_msg>implemented ContfractToRational() for the wiener attack<commit_after>package libnum

import (
  "github.com/ncw/gmp"
)

func BytesToNumber(src []byte) *gmp.Int {
  return new(gmp.Int).SetBytes(src)
}

func NumberToBytes(src *gmp.Int) []byte {
  return src.Bytes()
}

/*
 * returns true if n is a perfect square false otherwise
 */
func IsPerfectSquare(n *gmp.Int) bool {
  h := new(gmp.Int).And(n, gmp.NewInt(0xF))

  if h.Cmp(gmp.NewInt(9)) > 1 {
    return false
  }

  if (h.Cmp(gmp.NewInt(2)) != 0 && h.Cmp(gmp.NewInt(3)) != 0 &&
     h.Cmp(gmp.NewInt(5)) != 0 && h.Cmp(gmp.NewInt(6)) != 0 &&
     h.Cmp(gmp.NewInt(7)) != 0 && h.Cmp(gmp.NewInt(8)) != 0) {

    t := new(gmp.Int).Sqrt(n)

    if t.Mul(t,t).Cmp(n) == 0 {
      return true
    } else {
      false
    }
  }

  return false
}

func RationalToContfract(x, y *gmp.Int) []int {
  a := new(gmp.Int).Div(x,y)
  b := new(gmp.Int).Mul(a,y)
  c := new(gmp.Int)

  var pquotients []int

  if b.Cmp(x) == 0 {
    return []int{int(a.Int64())}
  }
  c.Mul(y,a).Sub(x,c)
  pquotients = RationalToContfract(y, c)
  pquotients = append([]int{int(a.Int64())}, pquotients...)
  return pquotients
}

func ContfractToRational(frac []int) (*gmp.Int, *gmp.Int) {
  var remainder []int

  switch l := len(frac); l {
    case 0:
      return gmp.NewInt(0), gmp.NewInt(1)
    case 1:
      return gmp.NewInt(int64(frac[0])), gmp.NewInt(1)
    default:
      remainder = frac[1:l]
      num, denom := ContfractToRational(remainder)
      fracZ := gmp.NewInt(int64(frac[0]))
      return fracZ.Mul(fracZ, num).Add(fracZ, denom), num
  }
}<|endoftext|>