<commit_before>package automaton

import (
	"github.com/balzaczyy/golucene/core/util"
	"math/big"
)

// util/automaton/Automaton.java

/*
Represents an automaton and all its states and transitions. States
are integers and must be created using {@link #createState}.  Mark a
state as an accept state using {@link #setAccept}.  Add transitions
using {@link #addTransition}.  Each state must have all of its
transitions added at once; if this is too restrictive then use
{@link Automaton.Builder} instead.  State 0 is always the
initial state.  Once a state is finished, either
because you've starting adding transitions to another state or you
call {@link #finishState}, then that states transitions are sorted
(first by min, then max, then dest) and reduced (transitions with
adjacent labels going to the same dest are combined).
*/
type Automaton struct {
	curState      int
	states        []int // 2x
	transitions   []int // 3x
	isAccept      *big.Int
	deterministic bool
}

func newEmptyAutomaton() *Automaton {
	return &Automaton{
		deterministic: true,
		curState:      -1,
		isAccept:      big.NewInt(0),
	}
}

/* Create a new state. */
func (a *Automaton) createState() int {
	state := len(a.states) / 2
	a.states = append(a.states, -1, 0)
	return state
}

/* Set or clear this state as an accept state. */
func (a *Automaton) setAccept(state int, accept bool) {
	assert2(state < a.numStates(), "state=%v is out of bounds (numStates=%v)", state, a.numStates())
	if accept {
		a.isAccept.SetBit(a.isAccept, state, 1)
	} else {
		a.isAccept.SetBit(a.isAccept, state, 0)
	}
}

/* Add a new transition with min = max = label. */
func (a *Automaton) addTransition(source, dest, label int) {
	a.addTransitionRange(source, dest, label, label)
}

/* Add a new transition with the specified source, dest, min, max. */
func (a *Automaton) addTransitionRange(source, dest, min, max int) {
	assert(len(a.transitions)%3 == 0)
	assert2(source < a.numStates(), "source=%v is out of bounds (maxState is %v)", source, a.numStates()-1)
	assert2(dest < a.numStates(), "dest=%v is out of bounds (maxState is %v)", dest, a.numStates()-1)

	if a.curState != source {
		if a.curState != -1 {
			a.finishCurrentState()
		}

		// move to next source:
		a.curState = source
		assert2(a.states[2*a.curState] == -1, "from state (%v) already had transitions added", source)
		assert(a.states[2*a.curState+1] == 0)
		a.states[2*a.curState] = len(a.transitions)
	}

	a.transitions = append(a.transitions, dest, min, max)

	// increment transition count for this state
	a.states[2*a.curState+1]++
}

/*
Add a [virtual] epsilon transition between source and dest. Dest
state must already have all transitions added because this method
simply copies those same transitions over to source.
*/
func (a *Automaton) addEpsilon(source, dest int) {
	t := newTransition()
	count := a.initTransition(dest, t)
	for i := 0; i < count; i++ {
		a.nextTransition(t)
		a.addTransitionRange(source, t.dest, t.min, t.max)
	}
	if a.isAccept.Bit(dest) != 0 {
		a.setAccept(source, true)
	}
}

/*
Copies over all state/transition from other. The state numbers are
sequentially assigned (appended).
*/
func (a *Automaton) copy(other *Automaton) {
	// bulk copy and then fixup the state pointers
	stateOffset := a.numStates()
	a.states = append(a.states, other.states...)
	for i := 0; i < len(other.states); i += 2 {
		if a.states[stateOffset*2+i] != -1 {
			a.states[stateOffset*2+i] += len(a.transitions)
		}
	}
	otherNumStates := other.numStates()
	otherAcceptStates := other.isAccept
	for state := 0; state < otherNumStates; state++ {
		if otherAcceptStates.Bit(state) == 0 {
			continue
		}
		a.setAccept(stateOffset+state, true)
	}

	// bulk copy and then fixup dest for each transition
	transOffset := len(a.transitions)
	a.transitions = append(a.transitions, other.transitions...)
	for i := 0; i < len(other.transitions); i += 3 {
		a.transitions[transOffset+i] += stateOffset
	}

	if !other.deterministic {
		a.deterministic = false
	}
}

/* Freezes the last state, sorting and reducing the transitions. */
func (a *Automaton) finishCurrentState() {
	numTransitions := a.states[2*a.curState+1]
	assert(numTransitions > 0)

	offset := a.states[2*a.curState]
	start := offset / 3
	util.NewInPlaceMergeSorter(destMinMaxTransitions(a.transitions)).Sort(start, start+numTransitions)

	// reduce any "adjacent" transitions:
	upto, min, max, dest := 0, -1, -1, -1

	for i := 0; i < numTransitions; i++ {
		tDest := a.transitions[offset+3*i]
		tMin := a.transitions[offset+3*i+1]
		tMax := a.transitions[offset+3*i+2]

		if dest == tDest {
			panic("niy")
		} else {
			if dest != -1 {
				a.transitions[offset+3*upto] = dest
				a.transitions[offset+3*upto+1] = min
				a.transitions[offset+3*upto+2] = max
			}
			dest, min, max = tDest, tMin, tMax
		}
	}

	if dest != -1 {
		// last transition
		a.transitions[offset+3*upto] = dest
		a.transitions[offset+3*upto+1] = min
		a.transitions[offset+3*upto+2] = max
		upto++
	}

	a.transitions = a.transitions[:len(a.transitions)-(numTransitions-upto)*3]
	a.states[2*a.curState+1] = upto

	// sort transitions by min/max/dest:
	util.NewInPlaceMergeSorter(minMaxDestTransitions(a.transitions)).Sort(start, start+upto)

	if a.deterministic && upto > 1 {
		panic("niy")
	}
}

/*
Finishes the current state; call this once you are done adding
transitions for a state. This is automatically called if you start
adding transitions to a new source state, but for the last state you
add, you need to call this method yourself.
*/
func (a *Automaton) finishState() {
	if a.curState != -1 {
		a.finishCurrentState()
		a.curState = -1
	}
}

/* How many states this automaton has. */
func (a *Automaton) numStates() int {
	return len(a.states) / 2
}

/* How many transitions this state has. */
func (a *Automaton) numTransitions(state int) int {
	if count := a.states[2*state+1]; count != -1 {
		return count
	}
	return 0
}

type destMinMaxTransitions []int

func (s destMinMaxTransitions) Len() int {
	panic("niy")
}

func (s destMinMaxTransitions) Swap(i, j int) {
	panic("niy")
}

func (s destMinMaxTransitions) Less(i, j int) bool {
	panic("niy")
}

type minMaxDestTransitions []int

func (s minMaxDestTransitions) Len() int {
	panic("niy")
}

func (s minMaxDestTransitions) Swap(i, j int) {
	panic("niy")
}

func (s minMaxDestTransitions) Less(i, j int) bool {
	panic("niy")
}

/*
Initialize the provided Transition to iterate through all transitions
leaving the specified state. You must call nextTransition() to get
each transition. Returns the number of transitions leaving this tate.
*/
func (a *Automaton) initTransition(state int, t *Transition) int {
	assert2(state < a.numStates(), "state=%v nextState=%v", state, a.numStates())
	t.source = state
	t.transitionUpto = a.states[2*state]
	return a.numTransitions(state)
}

/* Iterate to the next transition after the provided one */
func (a *Automaton) nextTransition(t *Transition) {
	// make sure there is still a transition left
	assert((t.transitionUpto + 3 - a.states[2*t.source]) <= 3*a.states[2*t.source+1])
	t.dest = a.transitions[t.transitionUpto]
	t.min = a.transitions[t.transitionUpto+1]
	t.max = a.transitions[t.transitionUpto+2]
	t.transitionUpto += 3
}

// Go doesn't have unicode.MinRune which should be 0
const MIN_CODE_POINT = 0

type AutomatonBuilder struct {
}
<commit_msg>implement destMinMaxTransitions.less()<commit_after>package automaton

import (
	"github.com/balzaczyy/golucene/core/util"
	"math/big"
)

// util/automaton/Automaton.java

/*
Represents an automaton and all its states and transitions. States
are integers and must be created using {@link #createState}.  Mark a
state as an accept state using {@link #setAccept}.  Add transitions
using {@link #addTransition}.  Each state must have all of its
transitions added at once; if this is too restrictive then use
{@link Automaton.Builder} instead.  State 0 is always the
initial state.  Once a state is finished, either
because you've starting adding transitions to another state or you
call {@link #finishState}, then that states transitions are sorted
(first by min, then max, then dest) and reduced (transitions with
adjacent labels going to the same dest are combined).
*/
type Automaton struct {
	curState      int
	states        []int // 2x
	transitions   []int // 3x
	isAccept      *big.Int
	deterministic bool
}

func newEmptyAutomaton() *Automaton {
	return &Automaton{
		deterministic: true,
		curState:      -1,
		isAccept:      big.NewInt(0),
	}
}

/* Create a new state. */
func (a *Automaton) createState() int {
	state := len(a.states) / 2
	a.states = append(a.states, -1, 0)
	return state
}

/* Set or clear this state as an accept state. */
func (a *Automaton) setAccept(state int, accept bool) {
	assert2(state < a.numStates(), "state=%v is out of bounds (numStates=%v)", state, a.numStates())
	if accept {
		a.isAccept.SetBit(a.isAccept, state, 1)
	} else {
		a.isAccept.SetBit(a.isAccept, state, 0)
	}
}

/* Add a new transition with min = max = label. */
func (a *Automaton) addTransition(source, dest, label int) {
	a.addTransitionRange(source, dest, label, label)
}

/* Add a new transition with the specified source, dest, min, max. */
func (a *Automaton) addTransitionRange(source, dest, min, max int) {
	assert(len(a.transitions)%3 == 0)
	assert2(source < a.numStates(), "source=%v is out of bounds (maxState is %v)", source, a.numStates()-1)
	assert2(dest < a.numStates(), "dest=%v is out of bounds (maxState is %v)", dest, a.numStates()-1)

	if a.curState != source {
		if a.curState != -1 {
			a.finishCurrentState()
		}

		// move to next source:
		a.curState = source
		assert2(a.states[2*a.curState] == -1, "from state (%v) already had transitions added", source)
		assert(a.states[2*a.curState+1] == 0)
		a.states[2*a.curState] = len(a.transitions)
	}

	a.transitions = append(a.transitions, dest, min, max)

	// increment transition count for this state
	a.states[2*a.curState+1]++
}

/*
Add a [virtual] epsilon transition between source and dest. Dest
state must already have all transitions added because this method
simply copies those same transitions over to source.
*/
func (a *Automaton) addEpsilon(source, dest int) {
	t := newTransition()
	count := a.initTransition(dest, t)
	for i := 0; i < count; i++ {
		a.nextTransition(t)
		a.addTransitionRange(source, t.dest, t.min, t.max)
	}
	if a.isAccept.Bit(dest) != 0 {
		a.setAccept(source, true)
	}
}

/*
Copies over all state/transition from other. The state numbers are
sequentially assigned (appended).
*/
func (a *Automaton) copy(other *Automaton) {
	// bulk copy and then fixup the state pointers
	stateOffset := a.numStates()
	a.states = append(a.states, other.states...)
	for i := 0; i < len(other.states); i += 2 {
		if a.states[stateOffset*2+i] != -1 {
			a.states[stateOffset*2+i] += len(a.transitions)
		}
	}
	otherNumStates := other.numStates()
	otherAcceptStates := other.isAccept
	for state := 0; state < otherNumStates; state++ {
		if otherAcceptStates.Bit(state) == 0 {
			continue
		}
		a.setAccept(stateOffset+state, true)
	}

	// bulk copy and then fixup dest for each transition
	transOffset := len(a.transitions)
	a.transitions = append(a.transitions, other.transitions...)
	for i := 0; i < len(other.transitions); i += 3 {
		a.transitions[transOffset+i] += stateOffset
	}

	if !other.deterministic {
		a.deterministic = false
	}
}

/* Freezes the last state, sorting and reducing the transitions. */
func (a *Automaton) finishCurrentState() {
	numTransitions := a.states[2*a.curState+1]
	assert(numTransitions > 0)

	offset := a.states[2*a.curState]
	start := offset / 3
	util.NewInPlaceMergeSorter(destMinMaxTransitions(a.transitions)).Sort(start, start+numTransitions)

	// reduce any "adjacent" transitions:
	upto, min, max, dest := 0, -1, -1, -1

	for i := 0; i < numTransitions; i++ {
		tDest := a.transitions[offset+3*i]
		tMin := a.transitions[offset+3*i+1]
		tMax := a.transitions[offset+3*i+2]

		if dest == tDest {
			panic("niy")
		} else {
			if dest != -1 {
				a.transitions[offset+3*upto] = dest
				a.transitions[offset+3*upto+1] = min
				a.transitions[offset+3*upto+2] = max
			}
			dest, min, max = tDest, tMin, tMax
		}
	}

	if dest != -1 {
		// last transition
		a.transitions[offset+3*upto] = dest
		a.transitions[offset+3*upto+1] = min
		a.transitions[offset+3*upto+2] = max
		upto++
	}

	a.transitions = a.transitions[:len(a.transitions)-(numTransitions-upto)*3]
	a.states[2*a.curState+1] = upto

	// sort transitions by min/max/dest:
	util.NewInPlaceMergeSorter(minMaxDestTransitions(a.transitions)).Sort(start, start+upto)

	if a.deterministic && upto > 1 {
		panic("niy")
	}
}

/*
Finishes the current state; call this once you are done adding
transitions for a state. This is automatically called if you start
adding transitions to a new source state, but for the last state you
add, you need to call this method yourself.
*/
func (a *Automaton) finishState() {
	if a.curState != -1 {
		a.finishCurrentState()
		a.curState = -1
	}
}

/* How many states this automaton has. */
func (a *Automaton) numStates() int {
	return len(a.states) / 2
}

/* How many transitions this state has. */
func (a *Automaton) numTransitions(state int) int {
	if count := a.states[2*state+1]; count != -1 {
		return count
	}
	return 0
}

type destMinMaxTransitions []int

func (s destMinMaxTransitions) Len() int {
	panic("niy")
}

func (s destMinMaxTransitions) Swap(i, j int) {
	panic("niy")
}

func (s destMinMaxTransitions) Less(i, j int) bool {
	iStart := 3 * i
	jStart := 3 * j

	// first dest:
	iDest := s[iStart]
	jDest := s[jStart]
	if iDest < jDest {
		return true
	} else if iDest > jDest {
		return false
	}

	// then min:
	iMin := s[iStart+1]
	jMin := s[jStart+1]
	if iMin < jMin {
		return true
	} else if iMin > jMin {
		return false
	}

	// then max:
	iMax := s[iStart+2]
	jMax := s[jStart+2]
	return iMax < jMax
}

type minMaxDestTransitions []int

func (s minMaxDestTransitions) Len() int {
	panic("niy")
}

func (s minMaxDestTransitions) Swap(i, j int) {
	panic("niy")
}

func (s minMaxDestTransitions) Less(i, j int) bool {
	panic("niy")
}

/*
Initialize the provided Transition to iterate through all transitions
leaving the specified state. You must call nextTransition() to get
each transition. Returns the number of transitions leaving this tate.
*/
func (a *Automaton) initTransition(state int, t *Transition) int {
	assert2(state < a.numStates(), "state=%v nextState=%v", state, a.numStates())
	t.source = state
	t.transitionUpto = a.states[2*state]
	return a.numTransitions(state)
}

/* Iterate to the next transition after the provided one */
func (a *Automaton) nextTransition(t *Transition) {
	// make sure there is still a transition left
	assert((t.transitionUpto + 3 - a.states[2*t.source]) <= 3*a.states[2*t.source+1])
	t.dest = a.transitions[t.transitionUpto]
	t.min = a.transitions[t.transitionUpto+1]
	t.max = a.transitions[t.transitionUpto+2]
	t.transitionUpto += 3
}

// Go doesn't have unicode.MinRune which should be 0
const MIN_CODE_POINT = 0

type AutomatonBuilder struct {
}
<|endoftext|>


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

package docker

import (
	"encoding/json"
	"github.com/dotcloud/docker"
)

// ListContainersOptions specify parameters to the ListContainers function.
//
// See http://goo.gl/8IMr2 for more details.
type ListContainersOptions struct {
	All    bool
	Limit  int
	Since  string
	Before string
}

// ListContainers returns a slice of containers matching the given criteria.
//
// See http://goo.gl/8IMr2 for more details.
func (c *Client) ListContainers(opts *ListContainersOptions) ([]docker.ApiContainer, error) {
	path := "/containers/ps?" + queryString(opts)
	body, _, err := c.do("GET", path, nil)
	if err != nil {
		return nil, err
	}
	var containers []docker.ApiContainer
	err = json.Unmarshal(body, &containers)
	if err != nil {
		return nil, err
	}
	return containers, nil
}

// InspectContainer returns information about a container by its ID.
//
// See http://goo.gl/g5tpG for more details.
func (c *Client) InspectContainer(id string) (*docker.Container, error) {
	path := "/containers/" + id + "/json"
	body, _, err := c.do("GET", path, nil)
	if err != nil {
		return nil, err
	}
	var container docker.Container
	err = json.Unmarshal(body, &container)
	if err != nil {
		return nil, err
	}
	return &container, nil
}

// CreateContainer creates a new container, returning the container instance,
// or an error in case of failure.
//
// See http://goo.gl/lcR51 for more details.
func (c *Client) CreateContainer(config *docker.Config) (*docker.Container, error) {
	body, _, err := c.do("POST", "/containers/create", config)
	if err != nil {
		return nil, err
	}
	var container docker.Container
	err = json.Unmarshal(body, &container)
	if err != nil {
		return nil, err
	}
	return &container, nil
}

func (c *Client) KillContainer(id string) error {
	path := "/containers/" + id + "/kill"
	_, _, err := c.do("POST", path, nil)
	if err != nil {
		return err
	}
	return nil
}
<commit_msg>container: add docs for the KillContainer method<commit_after>// Copyright 2013 Francisco Souza. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package docker

import (
	"encoding/json"
	"github.com/dotcloud/docker"
)

// ListContainersOptions specify parameters to the ListContainers function.
//
// See http://goo.gl/8IMr2 for more details.
type ListContainersOptions struct {
	All    bool
	Limit  int
	Since  string
	Before string
}

// ListContainers returns a slice of containers matching the given criteria.
//
// See http://goo.gl/8IMr2 for more details.
func (c *Client) ListContainers(opts *ListContainersOptions) ([]docker.ApiContainer, error) {
	path := "/containers/ps?" + queryString(opts)
	body, _, err := c.do("GET", path, nil)
	if err != nil {
		return nil, err
	}
	var containers []docker.ApiContainer
	err = json.Unmarshal(body, &containers)
	if err != nil {
		return nil, err
	}
	return containers, nil
}

// InspectContainer returns information about a container by its ID.
//
// See http://goo.gl/g5tpG for more details.
func (c *Client) InspectContainer(id string) (*docker.Container, error) {
	path := "/containers/" + id + "/json"
	body, _, err := c.do("GET", path, nil)
	if err != nil {
		return nil, err
	}
	var container docker.Container
	err = json.Unmarshal(body, &container)
	if err != nil {
		return nil, err
	}
	return &container, nil
}

// CreateContainer creates a new container, returning the container instance,
// or an error in case of failure.
//
// See http://goo.gl/lcR51 for more details.
func (c *Client) CreateContainer(config *docker.Config) (*docker.Container, error) {
	body, _, err := c.do("POST", "/containers/create", config)
	if err != nil {
		return nil, err
	}
	var container docker.Container
	err = json.Unmarshal(body, &container)
	if err != nil {
		return nil, err
	}
	return &container, nil
}

// KillContainer removes a container, returning an error in case of failure.
//
// See http://goo.gl/DfPJC for more details.
func (c *Client) KillContainer(id string) error {
	path := "/containers/" + id + "/kill"
	_, _, err := c.do("POST", path, nil)
	if err != nil {
		return err
	}
	return nil
}
<|endoftext|>


<commit_before>package libcd

import "fmt"

// Container defines the container configuration.
type Container struct {
	Name           string            `json:"name"`
	Alias          string            `json:"alias"`
	Image          string            `json:"image"`
	Pull           bool              `json:"pull,omitempty"`
	AuthConfig     Auth              `json:"auth_config,omitempty"`
	Privileged     bool              `json:"privileged,omitempty"`
	WorkingDir     string            `json:"working_dir,omitempty"`
	Environment    map[string]string `json:"environment,omitempty"`
	Entrypoint     []string          `json:"entrypoint,omitempty"`
	Command        []string          `json:"command,omitempty"`
	ExtraHosts     []string          `json:"extra_hosts,omitempty"`
	Volumes        []string          `json:"volumes,omitempty"`
	VolumesFrom    []string          `json:"volumes_from,omitempty"`
	Devices        []string          `json:"devices,omitempty"`
	Network        string            `json:"network_mode,omitempty"`
	DNS            []string          `json:"dns,omitempty"`
	DNSSearch      []string          `json:"dns_search,omitempty"`
	MemSwapLimit   int64             `json:"memswap_limit,omitempty"`
	MemLimit       int64             `json:"mem_limit,omitempty"`
	CPUQuota       int64             `json:"cpu_quota,omitempty"`
	CPUShares      int64             `json:"cpu_shares,omitempty"`
	CPUSet         string            `json:"cpuset,omitempty"`
	OomKillDisable bool              `json:"oom_kill_disable,omitempty"`
}

// Validate validates the container configuration details and returns an error
// if the validation fails.
func (c *Container) Validate() error {
	switch {

	case c.Name == "":
		return fmt.Errorf("Missing container name")
	case c.Image == "":
		return fmt.Errorf("Missing container image")
	default:
		return nil
	}

}

// Auth provides authentication parameters to authenticate to a remote
// container registry for image download.
type Auth struct {
	Username string `json:"username,omitempty"`
	Password string `json:"password,omitempty"`
	Email    string `json:"email,omitempty"`
	Token    string `json:"registry_token,omitempty"`
}

// Volume defines a container volume.
type Volume struct {
	Name  string `json:"name,omitempty"`
	Alias string `json:"alias,omitempty"`
	Src   string `json:"src,omitempty"`
	Dst   string `json:"dst,omitempty"`
}

// Network defines a container network.
type Network struct {
	Name  string `json:"name,omitempty"`
	Alias string `json:"alias,omitempty"`
	Src   string `json:"src,omitempty"`
	Dst   string `json:"dst,omitempty"`
}
<commit_msg>updated volume and network<commit_after>package libcd

import "fmt"

// Container defines the container configuration.
type Container struct {
	Name           string            `json:"name"`
	Alias          string            `json:"alias"`
	Image          string            `json:"image"`
	Pull           bool              `json:"pull,omitempty"`
	AuthConfig     Auth              `json:"auth_config,omitempty"`
	Privileged     bool              `json:"privileged,omitempty"`
	WorkingDir     string            `json:"working_dir,omitempty"`
	Environment    map[string]string `json:"environment,omitempty"`
	Entrypoint     []string          `json:"entrypoint,omitempty"`
	Command        []string          `json:"command,omitempty"`
	ExtraHosts     []string          `json:"extra_hosts,omitempty"`
	Volumes        []string          `json:"volumes,omitempty"`
	VolumesFrom    []string          `json:"volumes_from,omitempty"`
	Devices        []string          `json:"devices,omitempty"`
	Network        string            `json:"network_mode,omitempty"`
	DNS            []string          `json:"dns,omitempty"`
	DNSSearch      []string          `json:"dns_search,omitempty"`
	MemSwapLimit   int64             `json:"memswap_limit,omitempty"`
	MemLimit       int64             `json:"mem_limit,omitempty"`
	CPUQuota       int64             `json:"cpu_quota,omitempty"`
	CPUShares      int64             `json:"cpu_shares,omitempty"`
	CPUSet         string            `json:"cpuset,omitempty"`
	OomKillDisable bool              `json:"oom_kill_disable,omitempty"`
}

// Validate validates the container configuration details and returns an error
// if the validation fails.
func (c *Container) Validate() error {
	switch {

	case c.Name == "":
		return fmt.Errorf("Missing container name")
	case c.Image == "":
		return fmt.Errorf("Missing container image")
	default:
		return nil
	}

}

// Auth provides authentication parameters to authenticate to a remote
// container registry for image download.
type Auth struct {
	Username string `json:"username,omitempty"`
	Password string `json:"password,omitempty"`
	Email    string `json:"email,omitempty"`
	Token    string `json:"registry_token,omitempty"`
}

// Volume defines a container volume.
type Volume struct {
	Name       string            `json:"name,omitempty"`
	Alias      string            `json:"alias,omitempty"`
	Driver     string            `json:"driver,omitempty"`
	DriverOpts map[string]string `json:"driver_opts,omitempty"`
	External   bool              `json:"external,omitempty"`
}

// Network defines a container network.
type Network struct {
	Name       string            `json:"name,omitempty"`
	Alias      string            `json:"alias,omitempty"`
	Driver     string            `json:"driver,omitempty"`
	DriverOpts map[string]string `json:"driver_opts,omitempty"`
	External   bool              `json:"external,omitempty"`
}
<|endoftext|>


<commit_before>package weed_server

import (
	"context"
	"fmt"
	"net/http"
	"os"
	"sync"
	"time"

	"google.golang.org/grpc"

	"github.com/chrislusf/seaweedfs/weed/operation"
	"github.com/chrislusf/seaweedfs/weed/pb/filer_pb"
	"github.com/chrislusf/seaweedfs/weed/pb/master_pb"
	"github.com/chrislusf/seaweedfs/weed/stats"
	"github.com/chrislusf/seaweedfs/weed/util"

	"github.com/chrislusf/seaweedfs/weed/filer2"
	_ "github.com/chrislusf/seaweedfs/weed/filer2/cassandra"
	_ "github.com/chrislusf/seaweedfs/weed/filer2/etcd"
	_ "github.com/chrislusf/seaweedfs/weed/filer2/leveldb"
	_ "github.com/chrislusf/seaweedfs/weed/filer2/leveldb2"
	_ "github.com/chrislusf/seaweedfs/weed/filer2/mysql"
	_ "github.com/chrislusf/seaweedfs/weed/filer2/postgres"
	_ "github.com/chrislusf/seaweedfs/weed/filer2/redis"
	"github.com/chrislusf/seaweedfs/weed/glog"
	"github.com/chrislusf/seaweedfs/weed/notification"
	_ "github.com/chrislusf/seaweedfs/weed/notification/aws_sqs"
	_ "github.com/chrislusf/seaweedfs/weed/notification/gocdk_pub_sub"
	_ "github.com/chrislusf/seaweedfs/weed/notification/google_pub_sub"
	_ "github.com/chrislusf/seaweedfs/weed/notification/kafka"
	_ "github.com/chrislusf/seaweedfs/weed/notification/log"
	"github.com/chrislusf/seaweedfs/weed/security"
)

type FilerOption struct {
	Masters            []string
	Collection         string
	DefaultReplication string
	DisableDirListing  bool
	MaxMB              int
	DirListingLimit    int
	DataCenter         string
	DefaultLevelDbDir  string
	DisableHttp        bool
	Port               uint32
	recursiveDelete    bool
	Cipher             bool
}

type FilerServer struct {
	option         *FilerOption
	secret         security.SigningKey
	filer          *filer2.Filer
	grpcDialOption grpc.DialOption

	// notifying clients
	clientChansLock sync.RWMutex
	clientChans     map[string]chan *filer_pb.FullEventNotification

}

func NewFilerServer(defaultMux, readonlyMux *http.ServeMux, option *FilerOption) (fs *FilerServer, err error) {

	fs = &FilerServer{
		option:         option,
		grpcDialOption: security.LoadClientTLS(util.GetViper(), "grpc.filer"),
	}

	if len(option.Masters) == 0 {
		glog.Fatal("master list is required!")
	}

	fs.filer = filer2.NewFiler(option.Masters, fs.grpcDialOption, option.Port+10000)
	fs.filer.Cipher = option.Cipher

	maybeStartMetrics(fs, option)

	go fs.filer.KeepConnectedToMaster()

	v := util.GetViper()
	if !util.LoadConfiguration("filer", false) {
		v.Set("leveldb2.enabled", true)
		v.Set("leveldb2.dir", option.DefaultLevelDbDir)
		_, err := os.Stat(option.DefaultLevelDbDir)
		if os.IsNotExist(err) {
			os.MkdirAll(option.DefaultLevelDbDir, 0755)
		}
	}
	util.LoadConfiguration("notification", false)

	fs.option.recursiveDelete = v.GetBool("filer.options.recursive_delete")
	v.Set("filer.option.buckets_folder", "/buckets")
	v.Set("filer.option.queues_folder", "/queues")
	fs.filer.DirBucketsPath = v.GetString("filer.option.buckets_folder")
	fs.filer.DirQueuesPath = v.GetString("filer.option.queues_folder")
	fs.filer.LoadConfiguration(v)

	notification.LoadConfiguration(v, "notification.")

	handleStaticResources(defaultMux)
	if !option.DisableHttp {
		defaultMux.HandleFunc("/", fs.filerHandler)
	}
	if defaultMux != readonlyMux {
		readonlyMux.HandleFunc("/", fs.readonlyFilerHandler)
	}

	fs.filer.LoadBuckets(fs.filer.DirBucketsPath)

	util.OnInterrupt(func() {
		fs.filer.Shutdown()
	})

	return fs, nil
}

func maybeStartMetrics(fs *FilerServer, option *FilerOption) {
	isConnected := false
	var metricsAddress string
	var metricsIntervalSec int
	var readErr error
	for !isConnected {
		metricsAddress, metricsIntervalSec, readErr = readFilerConfiguration(fs.grpcDialOption, option.Masters[0])
		if readErr == nil {
			isConnected = true
		} else {
			time.Sleep(7 * time.Second)
		}
	}
	if metricsAddress == "" && metricsIntervalSec <= 0 {
		return
	}
	go stats.LoopPushingMetric("filer", stats.SourceName(option.Port), stats.FilerGather,
		func() (addr string, intervalSeconds int) {
			return metricsAddress, metricsIntervalSec
		})
}

func readFilerConfiguration(grpcDialOption grpc.DialOption, masterAddress string) (metricsAddress string, metricsIntervalSec int, err error) {
	err = operation.WithMasterServerClient(masterAddress, grpcDialOption, func(masterClient master_pb.SeaweedClient) error {
		resp, err := masterClient.GetMasterConfiguration(context.Background(), &master_pb.GetMasterConfigurationRequest{})
		if err != nil {
			return fmt.Errorf("get master %s configuration: %v", masterAddress, err)
		}
		metricsAddress, metricsIntervalSec = resp.MetricsAddress, int(resp.MetricsIntervalSeconds)
		return nil
	})
	return
}
<commit_msg>fail fast if filer configured wrong masters<commit_after>package weed_server

import (
	"context"
	"fmt"
	"net/http"
	"os"
	"sync"
	"time"

	"google.golang.org/grpc"

	"github.com/chrislusf/seaweedfs/weed/operation"
	"github.com/chrislusf/seaweedfs/weed/pb"
	"github.com/chrislusf/seaweedfs/weed/pb/filer_pb"
	"github.com/chrislusf/seaweedfs/weed/pb/master_pb"
	"github.com/chrislusf/seaweedfs/weed/stats"
	"github.com/chrislusf/seaweedfs/weed/util"

	"github.com/chrislusf/seaweedfs/weed/filer2"
	_ "github.com/chrislusf/seaweedfs/weed/filer2/cassandra"
	_ "github.com/chrislusf/seaweedfs/weed/filer2/etcd"
	_ "github.com/chrislusf/seaweedfs/weed/filer2/leveldb"
	_ "github.com/chrislusf/seaweedfs/weed/filer2/leveldb2"
	_ "github.com/chrislusf/seaweedfs/weed/filer2/mysql"
	_ "github.com/chrislusf/seaweedfs/weed/filer2/postgres"
	_ "github.com/chrislusf/seaweedfs/weed/filer2/redis"
	"github.com/chrislusf/seaweedfs/weed/glog"
	"github.com/chrislusf/seaweedfs/weed/notification"
	_ "github.com/chrislusf/seaweedfs/weed/notification/aws_sqs"
	_ "github.com/chrislusf/seaweedfs/weed/notification/gocdk_pub_sub"
	_ "github.com/chrislusf/seaweedfs/weed/notification/google_pub_sub"
	_ "github.com/chrislusf/seaweedfs/weed/notification/kafka"
	_ "github.com/chrislusf/seaweedfs/weed/notification/log"
	"github.com/chrislusf/seaweedfs/weed/security"
)

type FilerOption struct {
	Masters            []string
	Collection         string
	DefaultReplication string
	DisableDirListing  bool
	MaxMB              int
	DirListingLimit    int
	DataCenter         string
	DefaultLevelDbDir  string
	DisableHttp        bool
	Port               uint32
	recursiveDelete    bool
	Cipher             bool
}

type FilerServer struct {
	option         *FilerOption
	secret         security.SigningKey
	filer          *filer2.Filer
	grpcDialOption grpc.DialOption

	// notifying clients
	clientChansLock sync.RWMutex
	clientChans     map[string]chan *filer_pb.FullEventNotification
}

func NewFilerServer(defaultMux, readonlyMux *http.ServeMux, option *FilerOption) (fs *FilerServer, err error) {

	fs = &FilerServer{
		option:         option,
		grpcDialOption: security.LoadClientTLS(util.GetViper(), "grpc.filer"),
	}

	if len(option.Masters) == 0 {
		glog.Fatal("master list is required!")
	}

	fs.filer = filer2.NewFiler(option.Masters, fs.grpcDialOption, option.Port+10000)
	fs.filer.Cipher = option.Cipher

	maybeStartMetrics(fs, option)

	go fs.filer.KeepConnectedToMaster()

	v := util.GetViper()
	if !util.LoadConfiguration("filer", false) {
		v.Set("leveldb2.enabled", true)
		v.Set("leveldb2.dir", option.DefaultLevelDbDir)
		_, err := os.Stat(option.DefaultLevelDbDir)
		if os.IsNotExist(err) {
			os.MkdirAll(option.DefaultLevelDbDir, 0755)
		}
	}
	util.LoadConfiguration("notification", false)

	fs.option.recursiveDelete = v.GetBool("filer.options.recursive_delete")
	v.Set("filer.option.buckets_folder", "/buckets")
	v.Set("filer.option.queues_folder", "/queues")
	fs.filer.DirBucketsPath = v.GetString("filer.option.buckets_folder")
	fs.filer.DirQueuesPath = v.GetString("filer.option.queues_folder")
	fs.filer.LoadConfiguration(v)

	notification.LoadConfiguration(v, "notification.")

	handleStaticResources(defaultMux)
	if !option.DisableHttp {
		defaultMux.HandleFunc("/", fs.filerHandler)
	}
	if defaultMux != readonlyMux {
		readonlyMux.HandleFunc("/", fs.readonlyFilerHandler)
	}

	fs.filer.LoadBuckets(fs.filer.DirBucketsPath)

	util.OnInterrupt(func() {
		fs.filer.Shutdown()
	})

	return fs, nil
}

func maybeStartMetrics(fs *FilerServer, option *FilerOption) {

	for _, master := range option.Masters {
		_, err := pb.ParseFilerGrpcAddress(master)
		if err != nil {
			glog.Fatalf("invalid master address %s: %v", master, err)
		}
	}

	isConnected := false
	var metricsAddress string
	var metricsIntervalSec int
	var readErr error
	for !isConnected {
		metricsAddress, metricsIntervalSec, readErr = readFilerConfiguration(fs.grpcDialOption, option.Masters[0])
		if readErr == nil {
			isConnected = true
		} else {
			time.Sleep(7 * time.Second)
		}
	}
	if metricsAddress == "" && metricsIntervalSec <= 0 {
		return
	}
	go stats.LoopPushingMetric("filer", stats.SourceName(option.Port), stats.FilerGather,
		func() (addr string, intervalSeconds int) {
			return metricsAddress, metricsIntervalSec
		})
}

func readFilerConfiguration(grpcDialOption grpc.DialOption, masterAddress string) (metricsAddress string, metricsIntervalSec int, err error) {
	err = operation.WithMasterServerClient(masterAddress, grpcDialOption, func(masterClient master_pb.SeaweedClient) error {
		resp, err := masterClient.GetMasterConfiguration(context.Background(), &master_pb.GetMasterConfigurationRequest{})
		if err != nil {
			return fmt.Errorf("get master %s configuration: %v", masterAddress, err)
		}
		metricsAddress, metricsIntervalSec = resp.MetricsAddress, int(resp.MetricsIntervalSeconds)
		return nil
	})
	return
}
<|endoftext|>


<commit_before>/*
Copyright (c) 2012, Jan Schlicht <jan.schlicht@gmail.com>

Permission to use, copy, modify, and/or distribute this software for any purpose
with or without fee is hereby granted, provided that the above copyright notice
and this permission notice appear in all copies.

THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
THIS SOFTWARE.
*/

package resize

import (
	"image"
	"image/color"
)

type colorArray [4]float32

// converter allows to retrieve
// a colorArray for points of an image
type converter interface {
	at(x, y int) colorArray
}

type genericConverter struct {
	src image.Image
}

func replicateBorder1d(x, min, max int) int {
	if x < min {
		x = min
	} else if x >= max {
		x = max - 1
	}

	return x
}

func replicateBorder(x, y int, rect image.Rectangle) (xx, yy int) {
	xx = replicateBorder1d(x, rect.Min.X, rect.Max.X)
	yy = replicateBorder1d(y, rect.Min.Y, rect.Max.Y)
	return
}

func (c *genericConverter) at(x, y int) colorArray {
	r, g, b, a := c.src.At(replicateBorder(x, y, c.src.Bounds())).RGBA()
	return colorArray{
		float32(r),
		float32(g),
		float32(b),
		float32(a),
	}
}

type rgbaConverter struct {
	src *image.RGBA
}

func (c *rgbaConverter) at(x, y int) colorArray {
	i := c.src.PixOffset(replicateBorder(x, y, c.src.Rect))
	return colorArray{
		float32(uint16(c.src.Pix[i+0])<<8 | uint16(c.src.Pix[i+0])),
		float32(uint16(c.src.Pix[i+1])<<8 | uint16(c.src.Pix[i+1])),
		float32(uint16(c.src.Pix[i+2])<<8 | uint16(c.src.Pix[i+2])),
		float32(uint16(c.src.Pix[i+3])<<8 | uint16(c.src.Pix[i+3])),
	}
}

type rgba64Converter struct {
	src *image.RGBA64
}

func (c *rgba64Converter) at(x, y int) colorArray {
	i := c.src.PixOffset(replicateBorder(x, y, c.src.Rect))
	return colorArray{
		float32(uint16(c.src.Pix[i+0])<<8 | uint16(c.src.Pix[i+1])),
		float32(uint16(c.src.Pix[i+2])<<8 | uint16(c.src.Pix[i+3])),
		float32(uint16(c.src.Pix[i+4])<<8 | uint16(c.src.Pix[i+5])),
		float32(uint16(c.src.Pix[i+6])<<8 | uint16(c.src.Pix[i+7])),
	}
}

type grayConverter struct {
	src *image.Gray
}

func (c *grayConverter) at(x, y int) colorArray {
	i := c.src.PixOffset(replicateBorder(x, y, c.src.Rect))
	g := float32(uint16(c.src.Pix[i])<<8 | uint16(c.src.Pix[i]))
	return colorArray{
		g,
		g,
		g,
		float32(0xffff),
	}
}

type gray16Converter struct {
	src *image.Gray16
}

func (c *gray16Converter) at(x, y int) colorArray {
	i := c.src.PixOffset(replicateBorder(x, y, c.src.Rect))
	g := float32(uint16(c.src.Pix[i+0])<<8 | uint16(c.src.Pix[i+1]))
	return colorArray{
		g,
		g,
		g,
		float32(0xffff),
	}
}

type ycbcrConverter struct {
	src *image.YCbCr
}

func (c *ycbcrConverter) at(x, y int) colorArray {
	xx, yy := replicateBorder(x, y, c.src.Rect)
	yi := c.src.YOffset(xx, yy)
	ci := c.src.COffset(xx, yy)
	r, g, b := color.YCbCrToRGB(c.src.Y[yi], c.src.Cb[ci], c.src.Cr[ci])
	return colorArray{
		float32(uint16(r) * 0x101),
		float32(uint16(g) * 0x101),
		float32(uint16(b) * 0x101),
		float32(0xffff),
	}
}
<commit_msg>Change ordering<commit_after>/*
Copyright (c) 2012, Jan Schlicht <jan.schlicht@gmail.com>

Permission to use, copy, modify, and/or distribute this software for any purpose
with or without fee is hereby granted, provided that the above copyright notice
and this permission notice appear in all copies.

THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
THIS SOFTWARE.
*/

package resize

import (
	"image"
	"image/color"
)

type colorArray [4]float32

func replicateBorder1d(x, min, max int) int {
	if x < min {
		x = min
	} else if x >= max {
		x = max - 1
	}

	return x
}

func replicateBorder(x, y int, rect image.Rectangle) (xx, yy int) {
	xx = replicateBorder1d(x, rect.Min.X, rect.Max.X)
	yy = replicateBorder1d(y, rect.Min.Y, rect.Max.Y)
	return
}

// converter allows to retrieve
// a colorArray for points of an image.
type converter interface {
	at(x, y int) colorArray
}

type genericConverter struct {
	src image.Image
}

func (c *genericConverter) at(x, y int) colorArray {
	r, g, b, a := c.src.At(replicateBorder(x, y, c.src.Bounds())).RGBA()
	return colorArray{
		float32(r),
		float32(g),
		float32(b),
		float32(a),
	}
}

type rgbaConverter struct {
	src *image.RGBA
}

func (c *rgbaConverter) at(x, y int) colorArray {
	i := c.src.PixOffset(replicateBorder(x, y, c.src.Rect))
	return colorArray{
		float32(uint16(c.src.Pix[i+0])<<8 | uint16(c.src.Pix[i+0])),
		float32(uint16(c.src.Pix[i+1])<<8 | uint16(c.src.Pix[i+1])),
		float32(uint16(c.src.Pix[i+2])<<8 | uint16(c.src.Pix[i+2])),
		float32(uint16(c.src.Pix[i+3])<<8 | uint16(c.src.Pix[i+3])),
	}
}

type rgba64Converter struct {
	src *image.RGBA64
}

func (c *rgba64Converter) at(x, y int) colorArray {
	i := c.src.PixOffset(replicateBorder(x, y, c.src.Rect))
	return colorArray{
		float32(uint16(c.src.Pix[i+0])<<8 | uint16(c.src.Pix[i+1])),
		float32(uint16(c.src.Pix[i+2])<<8 | uint16(c.src.Pix[i+3])),
		float32(uint16(c.src.Pix[i+4])<<8 | uint16(c.src.Pix[i+5])),
		float32(uint16(c.src.Pix[i+6])<<8 | uint16(c.src.Pix[i+7])),
	}
}

type grayConverter struct {
	src *image.Gray
}

func (c *grayConverter) at(x, y int) colorArray {
	i := c.src.PixOffset(replicateBorder(x, y, c.src.Rect))
	g := float32(uint16(c.src.Pix[i])<<8 | uint16(c.src.Pix[i]))
	return colorArray{
		g,
		g,
		g,
		float32(0xffff),
	}
}

type gray16Converter struct {
	src *image.Gray16
}

func (c *gray16Converter) at(x, y int) colorArray {
	i := c.src.PixOffset(replicateBorder(x, y, c.src.Rect))
	g := float32(uint16(c.src.Pix[i+0])<<8 | uint16(c.src.Pix[i+1]))
	return colorArray{
		g,
		g,
		g,
		float32(0xffff),
	}
}

type ycbcrConverter struct {
	src *image.YCbCr
}

func (c *ycbcrConverter) at(x, y int) colorArray {
	xx, yy := replicateBorder(x, y, c.src.Rect)
	yi := c.src.YOffset(xx, yy)
	ci := c.src.COffset(xx, yy)
	r, g, b := color.YCbCrToRGB(c.src.Y[yi], c.src.Cb[ci], c.src.Cr[ci])
	return colorArray{
		float32(uint16(r) * 0x101),
		float32(uint16(g) * 0x101),
		float32(uint16(b) * 0x101),
		float32(0xffff),
	}
}
<|endoftext|>


<commit_before>package format

import (
	"fmt"
	"io"
	"text/tabwriter"

	"github.com/yuuki1/grabeni/aws/model"
)

const header = "ENI ID\tPrivate DNS Name\tPrivate IP\tInstance ID\tInsrance Name\tDevice index\tStatus\tName\tAZ"

func PrintENI(w io.Writer, eni *model.ENI) {
	enis := make([]*model.ENI, 1)
	enis[0] = eni
	PrintENIs(w, enis)
}

func PrintENIs(w io.Writer, enis []*model.ENI) {
	// Format in tab-separated columns with a tab stop of 8.
	tw := tabwriter.NewWriter(w, 0, 8, 0, '\t', 0)

	fmt.Fprintln(tw, header)

	for _, eni := range enis {
		instance := eni.AttachedInstance()
		var instanceID, instanceName string
		if instance != nil {
			instanceID, instanceName = instance.InstanceID(), instance.Name()
		}

		fmt.Fprintln(tw, fmt.Sprintf("%s\t%s\t%s\t%s\t%s\t%d\t%s\t%s\t%s",
			eni.InterfaceID(),
			eni.PrivateDnsName(),
			eni.PrivateIpAddress(),
			instanceID,
			instanceName,
			eni.AttachedDeviceIndex(),
			eni.Status(),
			eni.Name(),
			eni.AvailabilityZone(),
		))
	}

	tw.Flush()
}
<commit_msg>Adjust format<commit_after>package format

import (
	"fmt"
	"io"
	"text/tabwriter"

	"github.com/yuuki1/grabeni/aws/model"
)

const header = "ID\tNAME\tSTATUS\tPRIVATE DNS NAME\tPRIVATE IP\tAZ\tDEVICE INDEX\tINSTANCE ID\tINSTANCE NAME"

func PrintENI(w io.Writer, eni *model.ENI) {
	enis := make([]*model.ENI, 1)
	enis[0] = eni
	PrintENIs(w, enis)
}

func PrintENIs(w io.Writer, enis []*model.ENI) {
	// Format in tab-separated columns with a tab stop of 8.
	tw := tabwriter.NewWriter(w, 0, 8, 0, '\t', 0)

	fmt.Fprintln(tw, header)

	for _, eni := range enis {
		instance := eni.AttachedInstance()
		var instanceID, instanceName string
		if instance != nil {
			instanceID, instanceName = instance.InstanceID(), instance.Name()
		}

		fmt.Fprintln(tw, fmt.Sprintf("%s\t%s\t%s\t%s\t%s\t%s\t%d\t%s\t%s",
			eni.InterfaceID(),
			eni.Name(),
			eni.Status(),
			eni.PrivateDnsName(),
			eni.PrivateIpAddress(),
			eni.AvailabilityZone(),
			eni.AttachedDeviceIndex(),
			instanceID,
			instanceName,
		))
	}

	tw.Flush()
}
<|endoftext|>


<commit_before>package plugin

import (
	"fmt"
	"log"
	"os"
	"os/exec"
	"path/filepath"
	"runtime"

	plugin "github.com/hashicorp/go-plugin"
	"github.com/mitchellh/go-homedir"
	tfplugin "github.com/terraform-linters/tflint-plugin-sdk/plugin"
	"github.com/terraform-linters/tflint/tflint"
)

// Discovery searches plugins according the passed configuration
// The search priority of plugins is as follows:
//
//   1. Current directory (./.tflint.d/plugins)
//   2. Home directory (~/.tflint.d/plugins)
//
// Files under these directories that satisfy the "tflint-ruleset-*" naming rules
// enabled in the configuration are treated as plugins.
func Discovery(config *tflint.Config) (*Plugin, error) {
	if _, err := os.Stat(localPluginRoot); !os.IsNotExist(err) {
		return findPlugins(config, localPluginRoot)
	}

	pluginDir, err := homedir.Expand(PluginRoot)
	if err != nil {
		return nil, err
	}
	return findPlugins(config, pluginDir)
}

func findPlugins(config *tflint.Config, dir string) (*Plugin, error) {
	clients := []*plugin.Client{}
	rulesets := []*tfplugin.Client{}

	for _, cfg := range config.Plugins {
		pluginPath := filepath.Join(dir, pluginFileName(cfg.Name))
		if _, err := os.Stat(pluginPath); os.IsNotExist(err) {
			return nil, fmt.Errorf("Plugin `%s` not found in %s", cfg.Name, dir)
		}

		if cfg.Enabled {
			log.Printf("[INFO] Plugin `%s` found", cfg.Name)

			client := tfplugin.NewClient(&tfplugin.ClientOpts{
				Cmd: exec.Command(pluginPath),
			})
			rpcClient, err := client.Client()
			if err != nil {
				return nil, err
			}
			raw, err := rpcClient.Dispense("ruleset")
			if err != nil {
				return nil, err
			}
			ruleset := raw.(*tfplugin.Client)

			clients = append(clients, client)
			rulesets = append(rulesets, ruleset)
		} else {
			log.Printf("[INFO] Plugin `%s` found, but the plugin is disabled", cfg.Name)
		}
	}

	return &Plugin{RuleSets: rulesets, clients: clients}, nil
}

func pluginFileName(name string) string {
	if runtime.GOOS == "windows" {
		return fmt.Sprintf("tflint-ruleset-%s.exe", name)
	}
	return fmt.Sprintf("tflint-ruleset-%s", name)
}
<commit_msg>Allow no extensions on windows<commit_after>package plugin

import (
	"fmt"
	"log"
	"os"
	"os/exec"
	"path/filepath"
	"runtime"

	plugin "github.com/hashicorp/go-plugin"
	"github.com/mitchellh/go-homedir"
	tfplugin "github.com/terraform-linters/tflint-plugin-sdk/plugin"
	"github.com/terraform-linters/tflint/tflint"
)

// Discovery searches plugins according the passed configuration
// The search priority of plugins is as follows:
//
//   1. Current directory (./.tflint.d/plugins)
//   2. Home directory (~/.tflint.d/plugins)
//
// Files under these directories that satisfy the "tflint-ruleset-*" naming rules
// enabled in the configuration are treated as plugins.
func Discovery(config *tflint.Config) (*Plugin, error) {
	if _, err := os.Stat(localPluginRoot); !os.IsNotExist(err) {
		return findPlugins(config, localPluginRoot)
	}

	pluginDir, err := homedir.Expand(PluginRoot)
	if err != nil {
		return nil, err
	}
	return findPlugins(config, pluginDir)
}

func findPlugins(config *tflint.Config, dir string) (*Plugin, error) {
	clients := []*plugin.Client{}
	rulesets := []*tfplugin.Client{}

	for _, cfg := range config.Plugins {
		pluginPath, err := getPluginPath(dir, cfg.Name)
		if os.IsNotExist(err) {
			return nil, fmt.Errorf("Plugin `%s` not found in %s", cfg.Name, dir)
		}

		if cfg.Enabled {
			log.Printf("[INFO] Plugin `%s` found", cfg.Name)

			client := tfplugin.NewClient(&tfplugin.ClientOpts{
				Cmd: exec.Command(pluginPath),
			})
			rpcClient, err := client.Client()
			if err != nil {
				return nil, err
			}
			raw, err := rpcClient.Dispense("ruleset")
			if err != nil {
				return nil, err
			}
			ruleset := raw.(*tfplugin.Client)

			clients = append(clients, client)
			rulesets = append(rulesets, ruleset)
		} else {
			log.Printf("[INFO] Plugin `%s` found, but the plugin is disabled", cfg.Name)
		}
	}

	return &Plugin{RuleSets: rulesets, clients: clients}, nil
}

func getPluginPath(dir string, name string) (string, error) {
	pluginPath := filepath.Join(dir, fmt.Sprintf("tflint-ruleset-%s", name))

	_, err := os.Stat(pluginPath)
	if os.IsNotExist(err) && runtime.GOOS != "windows" {
		return "", os.ErrNotExist
	} else if !os.IsNotExist(err) {
		return pluginPath, nil
	}

	if _, err := os.Stat(pluginPath + ".exe"); !os.IsNotExist(err) {
		return pluginPath + ".exe", nil
	}

	return "", os.ErrNotExist
}
<|endoftext|>


<commit_before>package analysis

import (
	"fmt"
	"time"
)

// Reporter - Listens to SIGUSR1 signal and
// provides a report on the proxy traffic
type Reporter struct {
	analyser AnalyserI
}

// NewReporter - Creates a new Reporter struct
func NewReporter(a *Analyser) *Reporter {
	return &Reporter{
		analyser: a,
	}
}

// Report - Creates and returns a statistics report
func (r *Reporter) Report() string {
	return fmt.Sprintf("msg_total: %d\n", r.analyser.TotalCount()) +
		fmt.Sprintf("msg_req: %d\n", r.analyser.Count("REQ")) +
		fmt.Sprintf("msg_ack: %d\n", r.analyser.Count("ACK")) +
		fmt.Sprintf("msg_nak: %d\n", r.analyser.Count("NAK")) +
		fmt.Sprintf("request_rate_1s: %f\n", r.analyser.RequestRate(1)) +
		fmt.Sprintf("request_rate_10s: %f\n", r.analyser.RequestRate(10)) +
		fmt.Sprintf("response_rate_1s: %f\n", r.analyser.ResponseRate(1)) +
		fmt.Sprintf("response_rate_10s: %f\n", r.analyser.ResponseRate(10))
}

// Run - Starts the reporter
func (r *Reporter) Run() error {
	for {
		time.Sleep(5 * time.Second)
		fmt.Println(r.Report())
	}
}
<commit_msg>Make Reporter respond to SIGUSR1 signals<commit_after>package analysis

import (
	"fmt"
	"os"
	"os/signal"
	"syscall"
)

// Reporter - Listens to SIGUSR1 signal and
// provides a report on the proxy traffic
type Reporter struct {
	analyser AnalyserI
}

// NewReporter - Creates a new Reporter struct
func NewReporter(a *Analyser) *Reporter {
	return &Reporter{
		analyser: a,
	}
}

// Report - Creates and returns a statistics report
func (r *Reporter) Report() string {
	return fmt.Sprintf("msg_total: %d\n", r.analyser.TotalCount()) +
		fmt.Sprintf("msg_req: %d\n", r.analyser.Count("REQ")) +
		fmt.Sprintf("msg_ack: %d\n", r.analyser.Count("ACK")) +
		fmt.Sprintf("msg_nak: %d\n", r.analyser.Count("NAK")) +
		fmt.Sprintf("request_rate_1s: %f\n", r.analyser.RequestRate(1)) +
		fmt.Sprintf("request_rate_10s: %f\n", r.analyser.RequestRate(10)) +
		fmt.Sprintf("response_rate_1s: %f\n", r.analyser.ResponseRate(1)) +
		fmt.Sprintf("response_rate_10s: %f\n", r.analyser.ResponseRate(10))
}

// Run - Starts the reporter
func (r *Reporter) Run() error {
	c := make(chan os.Signal, 1)
	signal.Notify(c, syscall.SIGUSR1)
	for {
		s := <-c
		switch s {
		case syscall.SIGUSR1:
			fmt.Println(r.Report())
		default:
			return fmt.Errorf("Got signal %s", s)
		}
	}
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"github.com/jyggen/pingu/pingu"
	"github.com/nlopes/slack"
	"github.com/spf13/viper"
	"net/http"
	"regexp"
	"strconv"
	"strings"
	"sync"
	"time"
)

type plugin struct {
	channel      string
	client       *client
	global       *leaderboard
	leaderboards leaderboardList
}

var leaderboardRegex *regexp.Regexp
var version string

func init() {
	leaderboardRegex = regexp.MustCompile("^!leaderboard(?: ([\\d]{4}))?$")
}

func New(c *viper.Viper) pingu.Plugin {
	return pingu.Plugin(&plugin{
		channel: c.GetString("aoc.channel"),
		client: &client{
			httpClient: &http.Client{
				Timeout: c.GetDuration("aoc.timeout") * time.Second,
			},
			ownerId: c.GetInt("aoc.owner"),
			session: c.GetString("aoc.session"),
		},
		global: &leaderboard{},
	})
}

func (pl *plugin) Author() pingu.Author {
	return pingu.Author{
		Email: "jonas@stendahl.me",
		Name:  "Jonas Stendahl",
	}
}

func (pl *plugin) Commands() pingu.Commands {
	return pingu.Commands{
		&pingu.Command{
			Description: "Prints either the global leaderboard, or the leaderboard for a specific year.",
			Func:        pl.postLeaderboard,
			Trigger:     leaderboardRegex,
		},
		&pingu.Command{
			Description: "Forces a refresh of all leaderboards.",
			Func: func(pi *pingu.Pingu, ev *slack.MessageEvent) {
				if ev.Channel != pl.channel {
					pi.Reply(ev, fmt.Sprintf("Noot! Noot! That command is only available in <#%s>!", pl.channel))
					return
				}

				pl.refreshLeaderboards(pi)
			},
			Trigger: regexp.MustCompile("^!refresh$"),
		},
	}
}

func (pl *plugin) Name() string {
	return "Advent of Code"
}

func (pl *plugin) Tasks() pingu.Tasks {
	return pingu.Tasks{
		&pingu.Task{
			Func:     pl.refreshLeaderboards,
			Interval: time.Minute * 5,
		},
	}
}

func (pl *plugin) Version() string {
	return version
}

func (pl *plugin) announceJoined(pi *pingu.Pingu, a leaderboard, b leaderboard) {
	availableStars := calculateAvailableStars(time.Now(), b.Year)

Loop:
	for _, our := range b.Members {
		for _, their := range a.Members {
			if our.Id == their.Id {
				continue Loop
			}
		}

		var starsLabel string

		if our.TotalStars != 1 {
			starsLabel = "stars"
		} else {
			starsLabel = "star"
		}

		pi.Say(fmt.Sprintf(
			"Noot! Noot! _%s_ has joined our ranks, starting at position *%d* with *%d %s* (%.2f%%) collected.",
			our.Name,
			our.Position,
			our.TotalStars,
			starsLabel,
			float64(our.TotalStars)/float64(availableStars)*100,
		), pl.channel)
	}
}

func (pl *plugin) announceLeft(pi *pingu.Pingu, a leaderboard, b leaderboard) {
Loop:
	for _, their := range a.Members {
		for _, our := range b.Members {
			if their.Id == our.Id {
				continue Loop
			}
		}

		pi.Say(fmt.Sprintf(
			"Noot! Noot! It seems like _%s_ has left our ranks. The leaderboards have been recalculated.",
			their.Name,
		), pl.channel)
	}
}

func (pl *plugin) announceChanges(pi *pingu.Pingu, a leaderboard, b leaderboard) {
	availableStars := calculateAvailableStars(time.Now(), b.Year)

OurLoop:
	for _, our := range b.Members {
		for _, their := range a.Members {
			if our.Id == their.Id {
				if our.TotalStars != their.TotalStars {
					diff := calculateDifference(our.Stars, their.Stars)
					diffLen := len(diff)

					if diffLen != 0 {
						starsMessage := pl.buildChangeMessage(diff)

						var starsLabel string

						if diffLen != 1 {
							starsLabel = "stars"
						} else {
							starsLabel = "star"
						}

						message := fmt.Sprintf("_%s_ earned *%d %s* by completing _%s_", our.Name, diffLen, starsLabel, starsMessage)

						if their.Position > our.Position {
							message += fmt.Sprintf(", moving up to *position %d*", our.Position)
						} else if their.Position < our.Position {
							message += fmt.Sprintf(", moving down to *position %d*", our.Position)
						} else {
							message += fmt.Sprintf(", staying at *position %d*", our.Position)
						}

						if our.TotalStars != 1 {
							starsLabel = "stars"
						} else {
							starsLabel = "star"
						}

						pi.Say(message+fmt.Sprintf(
							" with *%d %s* (%.2f%%)!",
							our.TotalStars,
							starsLabel,
							float64(our.TotalStars)/float64(availableStars)*100,
						), pl.channel)
					}
				}

				continue OurLoop
			}
		}
	}
}

func (pl *plugin) buildChangeMessage(l starList) string {
	numOfStars := len(l)

	if numOfStars == 0 {
		return ""
	}

	stars := make([]string, numOfStars)

	for i, s := range l {
		stars[i] = fmt.Sprintf("Day %d Part %d (%d)", s.Day, s.Part, s.Year)
	}

	starsString := strings.Join([]string{
		strings.Join(stars[:numOfStars-1], "_, _"),
		stars[numOfStars-1],
	}, "_ and _")

	if starsString[0:7] == "_ and _" {
		starsString = starsString[7:]
	}

	return starsString
}

func (pl *plugin) buildLeaderboard(l *leaderboard) string {
	availableStars := calculateAvailableStars(time.Now(), l.Year)
	message := ""

	for _, m := range l.Members {
		var starsLabel string

		if m.TotalStars != 1 {
			starsLabel = "stars"
		} else {
			starsLabel = "star"
		}

		message += fmt.Sprintf(
			"*%d.* _%s_ with *%d %s* (%.2f%%) collected.\n",
			m.Position,
			m.Name,
			m.TotalStars,
			starsLabel,
			float64(m.TotalStars)/float64(availableStars)*100,
		)
	}

	return message
}

func (pl *plugin) postLeaderboard(pi *pingu.Pingu, ev *slack.MessageEvent) {
	if ev.Channel != pl.channel {
		pi.Reply(ev, fmt.Sprintf("Noot! Noot! That command is only available in <#%s>!", pl.channel))
		return
	}

	var board *leaderboard

	match := leaderboardRegex.FindStringSubmatch(ev.Text)

	if match[1] != "" {
		year, _ := strconv.Atoi(match[1])

		for _, l := range pl.leaderboards {
			if l.Year == year {
				board = l
			}
		}

		if board == nil {
			pi.Reply(ev, fmt.Sprintf("Noot! Noot! %d does not have a leaderboard!", year))
		}
	} else {
		board = pl.global
	}

	pi.Say(pl.buildLeaderboard(board), ev.Channel)
}

func (pl *plugin) refreshGlobalLeaderboard() {
	members := make(map[int]*member)

	for _, l := range pl.leaderboards {
		for _, m := range l.Members {
			if _, ok := members[m.Id]; !ok {
				members[m.Id] = &member{
					Id:   m.Id,
					Name: m.Name,
				}
			}

			members[m.Id].GlobalScore += m.GlobalScore
			members[m.Id].LocalScore += m.LocalScore
			members[m.Id].Stars = append(members[m.Id].Stars, m.Stars...)
			members[m.Id].TotalStars += m.TotalStars

			if members[m.Id].LastStarAt.Before(m.LastStarAt) {
				members[m.Id].LastStarAt = m.LastStarAt
			}
		}
	}

	pl.global.Members = make(memberList, len(members))
	i := 0

	for _, m := range members {
		pl.global.Members[i] = m
		i++
	}

	pl.global.Sort()
}

func (pl *plugin) refreshLeaderboards(pi *pingu.Pingu) {
Loop:
	for _, year := range getValidYears(time.Now()) {
		for _, l := range pl.leaderboards {
			if l.Year == year {
				continue Loop
			}
		}

		pl.leaderboards = append(pl.leaderboards, &leaderboard{
			Year: year,
		})
	}

	var wg sync.WaitGroup

	wg.Add(len(pl.leaderboards))

	for _, l := range pl.leaderboards {
		go func(l *leaderboard) {
			before := *l
			err := l.Refresh(pl.client)
			after := *l

			if err != nil {
				pi.Logger().Error(err)
			} else if len(before.Members) != 0 {
				pl.announceChanges(pi, before, after)
			}

			wg.Done()
		}(l)
	}

	wg.Wait()
	before := *pl.global
	pl.refreshGlobalLeaderboard()
	after := *pl.global

	if len(before.Members) != 0 {
		pl.announceJoined(pi, before, after)
		pl.announceLeft(pi, before, after)
	}
}
<commit_msg>Update leaderboards every 15 minutes<commit_after>package main

import (
	"fmt"
	"github.com/jyggen/pingu/pingu"
	"github.com/nlopes/slack"
	"github.com/spf13/viper"
	"net/http"
	"regexp"
	"strconv"
	"strings"
	"sync"
	"time"
)

type plugin struct {
	channel      string
	client       *client
	global       *leaderboard
	leaderboards leaderboardList
}

var leaderboardRegex *regexp.Regexp
var version string

func init() {
	leaderboardRegex = regexp.MustCompile("^!leaderboard(?: ([\\d]{4}))?$")
}

func New(c *viper.Viper) pingu.Plugin {
	return pingu.Plugin(&plugin{
		channel: c.GetString("aoc.channel"),
		client: &client{
			httpClient: &http.Client{
				Timeout: c.GetDuration("aoc.timeout") * time.Second,
			},
			ownerId: c.GetInt("aoc.owner"),
			session: c.GetString("aoc.session"),
		},
		global: &leaderboard{},
	})
}

func (pl *plugin) Author() pingu.Author {
	return pingu.Author{
		Email: "jonas@stendahl.me",
		Name:  "Jonas Stendahl",
	}
}

func (pl *plugin) Commands() pingu.Commands {
	return pingu.Commands{
		&pingu.Command{
			Description: "Prints either the global leaderboard, or the leaderboard for a specific year.",
			Func:        pl.postLeaderboard,
			Trigger:     leaderboardRegex,
		},
		&pingu.Command{
			Description: "Forces a refresh of all leaderboards.",
			Func: func(pi *pingu.Pingu, ev *slack.MessageEvent) {
				if ev.Channel != pl.channel {
					pi.Reply(ev, fmt.Sprintf("Noot! Noot! That command is only available in <#%s>!", pl.channel))
					return
				}

				pl.refreshLeaderboards(pi)
			},
			Trigger: regexp.MustCompile("^!refresh$"),
		},
	}
}

func (pl *plugin) Name() string {
	return "Advent of Code"
}

func (pl *plugin) Tasks() pingu.Tasks {
	return pingu.Tasks{
		&pingu.Task{
			Func:     pl.refreshLeaderboards,
			Interval: time.Minute * 15,
		},
	}
}

func (pl *plugin) Version() string {
	return version
}

func (pl *plugin) announceJoined(pi *pingu.Pingu, a leaderboard, b leaderboard) {
	availableStars := calculateAvailableStars(time.Now(), b.Year)

Loop:
	for _, our := range b.Members {
		for _, their := range a.Members {
			if our.Id == their.Id {
				continue Loop
			}
		}

		var starsLabel string

		if our.TotalStars != 1 {
			starsLabel = "stars"
		} else {
			starsLabel = "star"
		}

		pi.Say(fmt.Sprintf(
			"Noot! Noot! _%s_ has joined our ranks, starting at position *%d* with *%d %s* (%.2f%%) collected.",
			our.Name,
			our.Position,
			our.TotalStars,
			starsLabel,
			float64(our.TotalStars)/float64(availableStars)*100,
		), pl.channel)
	}
}

func (pl *plugin) announceLeft(pi *pingu.Pingu, a leaderboard, b leaderboard) {
Loop:
	for _, their := range a.Members {
		for _, our := range b.Members {
			if their.Id == our.Id {
				continue Loop
			}
		}

		pi.Say(fmt.Sprintf(
			"Noot! Noot! It seems like _%s_ has left our ranks. The leaderboards have been recalculated.",
			their.Name,
		), pl.channel)
	}
}

func (pl *plugin) announceChanges(pi *pingu.Pingu, a leaderboard, b leaderboard) {
	availableStars := calculateAvailableStars(time.Now(), b.Year)

OurLoop:
	for _, our := range b.Members {
		for _, their := range a.Members {
			if our.Id == their.Id {
				if our.TotalStars != their.TotalStars {
					diff := calculateDifference(our.Stars, their.Stars)
					diffLen := len(diff)

					if diffLen != 0 {
						starsMessage := pl.buildChangeMessage(diff)

						var starsLabel string

						if diffLen != 1 {
							starsLabel = "stars"
						} else {
							starsLabel = "star"
						}

						message := fmt.Sprintf("_%s_ earned *%d %s* by completing _%s_", our.Name, diffLen, starsLabel, starsMessage)

						if their.Position > our.Position {
							message += fmt.Sprintf(", moving up to *position %d*", our.Position)
						} else if their.Position < our.Position {
							message += fmt.Sprintf(", moving down to *position %d*", our.Position)
						} else {
							message += fmt.Sprintf(", staying at *position %d*", our.Position)
						}

						if our.TotalStars != 1 {
							starsLabel = "stars"
						} else {
							starsLabel = "star"
						}

						pi.Say(message+fmt.Sprintf(
							" with *%d %s* (%.2f%%)!",
							our.TotalStars,
							starsLabel,
							float64(our.TotalStars)/float64(availableStars)*100,
						), pl.channel)
					}
				}

				continue OurLoop
			}
		}
	}
}

func (pl *plugin) buildChangeMessage(l starList) string {
	numOfStars := len(l)

	if numOfStars == 0 {
		return ""
	}

	stars := make([]string, numOfStars)

	for i, s := range l {
		stars[i] = fmt.Sprintf("Day %d Part %d (%d)", s.Day, s.Part, s.Year)
	}

	starsString := strings.Join([]string{
		strings.Join(stars[:numOfStars-1], "_, _"),
		stars[numOfStars-1],
	}, "_ and _")

	if starsString[0:7] == "_ and _" {
		starsString = starsString[7:]
	}

	return starsString
}

func (pl *plugin) buildLeaderboard(l *leaderboard) string {
	availableStars := calculateAvailableStars(time.Now(), l.Year)
	message := ""

	for _, m := range l.Members {
		var starsLabel string

		if m.TotalStars != 1 {
			starsLabel = "stars"
		} else {
			starsLabel = "star"
		}

		message += fmt.Sprintf(
			"*%d.* _%s_ with *%d %s* (%.2f%%) collected.\n",
			m.Position,
			m.Name,
			m.TotalStars,
			starsLabel,
			float64(m.TotalStars)/float64(availableStars)*100,
		)
	}

	return message
}

func (pl *plugin) postLeaderboard(pi *pingu.Pingu, ev *slack.MessageEvent) {
	if ev.Channel != pl.channel {
		pi.Reply(ev, fmt.Sprintf("Noot! Noot! That command is only available in <#%s>!", pl.channel))
		return
	}

	var board *leaderboard

	match := leaderboardRegex.FindStringSubmatch(ev.Text)

	if match[1] != "" {
		year, _ := strconv.Atoi(match[1])

		for _, l := range pl.leaderboards {
			if l.Year == year {
				board = l
			}
		}

		if board == nil {
			pi.Reply(ev, fmt.Sprintf("Noot! Noot! %d does not have a leaderboard!", year))
		}
	} else {
		board = pl.global
	}

	pi.Say(pl.buildLeaderboard(board), ev.Channel)
}

func (pl *plugin) refreshGlobalLeaderboard() {
	members := make(map[int]*member)

	for _, l := range pl.leaderboards {
		for _, m := range l.Members {
			if _, ok := members[m.Id]; !ok {
				members[m.Id] = &member{
					Id:   m.Id,
					Name: m.Name,
				}
			}

			members[m.Id].GlobalScore += m.GlobalScore
			members[m.Id].LocalScore += m.LocalScore
			members[m.Id].Stars = append(members[m.Id].Stars, m.Stars...)
			members[m.Id].TotalStars += m.TotalStars

			if members[m.Id].LastStarAt.Before(m.LastStarAt) {
				members[m.Id].LastStarAt = m.LastStarAt
			}
		}
	}

	pl.global.Members = make(memberList, len(members))
	i := 0

	for _, m := range members {
		pl.global.Members[i] = m
		i++
	}

	pl.global.Sort()
}

func (pl *plugin) refreshLeaderboards(pi *pingu.Pingu) {
Loop:
	for _, year := range getValidYears(time.Now()) {
		for _, l := range pl.leaderboards {
			if l.Year == year {
				continue Loop
			}
		}

		pl.leaderboards = append(pl.leaderboards, &leaderboard{
			Year: year,
		})
	}

	var wg sync.WaitGroup

	wg.Add(len(pl.leaderboards))

	for _, l := range pl.leaderboards {
		go func(l *leaderboard) {
			before := *l
			err := l.Refresh(pl.client)
			after := *l

			if err != nil {
				pi.Logger().Error(err)
			} else if len(before.Members) != 0 {
				pl.announceChanges(pi, before, after)
			}

			wg.Done()
		}(l)
	}

	wg.Wait()
	before := *pl.global
	pl.refreshGlobalLeaderboard()
	after := *pl.global

	if len(before.Members) != 0 {
		pl.announceJoined(pi, before, after)
		pl.announceLeft(pi, before, after)
	}
}
<|endoftext|>


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

package core

import (
	"fmt"
	"github.com/rdrdr/hamcrest/base"
	"reflect"
)

// Returns a Matcher that matches any input value.
func Anything() *base.Matcher {
	return _Anything
}
var _Anything *base.Matcher // singleton
func init() {
	match := func (actual interface{}) *base.Result {
		return base.NewResultf(true, "always matches")
	}
	_Anything = base.NewMatcherf(match, "Anything")
}

// Returns a Matcher that matches the boolean value true.
func True() *base.Matcher {
	return base.True()
}

// Returns a Matcher that matches the boolean value false.
func False() *base.Matcher {
	return base.False()
}

// Returns a Matcher that matches on values that cause the given
// functionOrMatcher to panic.
//
// functionOrMatcher should either be a function that accepts one
// parameter or a Matcher.
func PanicWhenApplying(functionOrMatcher interface{}, name string) *base.Matcher {
	var doSomething func(interface{})
	if matcher, ok := functionOrMatcher.(*base.Matcher); ok {
		doSomething = func(actual interface{}) { matcher.Match(actual) }
	} else {
		value := reflect.NewValue(functionOrMatcher)
		if funcValue, ok := value.(*reflect.FuncValue); ok {
			funcType := funcValue.Type().(*reflect.FuncType)
			numIn := funcType.NumIn()
			if numIn == 0 {
				panic(fmt.Sprintf("func must accept a single arg, was %T", functionOrMatcher))
			}
			inType := funcType.In(0)
			switch {
			case numIn == 1: // always ok
			case numIn == 2 && funcType.DotDotDot(): // ok
			default:
				panic(fmt.Sprintf("func must accept a single arg, was %T", functionOrMatcher))
			}
			doSomething = func(actual interface{}) {
				actualValue := reflect.NewValue(actual)
				argValues := make([]reflect.Value, numIn, numIn)
				if numIn == 1 && funcType.DotDotDot() {
					inSlice := reflect.MakeSlice(inType.(*reflect.SliceType), 1, 1)
					inValue := inSlice.Elem(0)
					inValue.SetValue(actualValue)
					argValues[0] = inSlice
				} else {
					inValue := reflect.MakeZero(inType)
					inValue.SetValue(actualValue)
					argValues[0] = inValue
					if numIn == 2 && funcType.DotDotDot() {
						inType2 := funcType.In(1)
						argValues[1] = reflect.MakeSlice(inType2.(*reflect.SliceType), 0, 0)
					}
				}
				funcValue.Call(argValues)
			}
		}
	}
	match := func (actual interface{}) (result *base.Result) {
		defer func() {
			if recover() != nil {
				result = base.NewResultf(true, "Panicked")
			}
		}()
		doSomething(actual)
		result = base.NewResultf(false, "Did not panic")
		return
	}
	return base.NewMatcherf(match,
		"PanicWhenApplying[%v]", name)
}

// Returns a Matcher that decorates another matcher and only matches
// when the underlying matcher does not match (and vice versa).
func Not(matcher *base.Matcher) *base.Matcher {
	match := func (actual interface{}) *base.Result {
		result := matcher.Match(actual)
		return base.NewResult(!result.Matched(), result).
			WithCauses(result.Causes()...)
	}
	return base.NewMatcherf(match, "Not[%v]", matcher)
}

// Returns a Matcher that decorates another matcher.
func Is(matcher *base.Matcher) *base.Matcher {
	match := func (actual interface{}) *base.Result {
		result := matcher.Match(actual)
		return base.NewResult(result.Matched(), result).
			WithCauses(result.Causes()...)
	}
	return base.NewMatcherf(match, "Is[%v]", matcher)
}

// Returns a Matcher that matches if the actual value is nil
// or the nil value of its type.  (Note that this is *not*
// equivalent to DeeplyEqualTo(nil).)
func Nil() *base.Matcher {
	return base.Nil()
}

// Returns a Matcher that matches if the actual value is
// neither nil nor the nil value of its type.  (Note that
// this is *not* equivalent to Not(DeeplyEqualTo(nil)).)
func NonNil() *base.Matcher {
	return base.NonNil()
}

// Returns a Matcher that checks if the actual value is (deeply)
// equal to the given expected value, using reflect.DeepEqual.
//
// For an equality test equivalent to `==`, see the
// `hamcrest/comparison` package.
func DeepEqualTo(expected interface{}) *base.Matcher {
	return base.DeepEqualTo(expected)
}

// Returns a matcher that matches values that are greater-than the given
// expected value, using the greater-than (<) operator.
func GreaterThan(expected interface{}) *base.Matcher {
	return base.GreaterThan(expected)
}

// Returns a matcher that matches values that are greater-than-or-equal-to
// the given expected value, using the greater-than-or-equal-to (>=) operator.
func GreaterThanOrEqualTo(expected interface{}) *base.Matcher {
	return base.GreaterThanOrEqualTo(expected)
}

// Returns a matcher that matches values that are less-than the given
// expected value, using the less-than (<) operator.
func LessThan(expected interface{}) *base.Matcher {
	return base.LessThan(expected)
}

// Returns a matcher that matches values that are less-than-or-equal-to
// the given expected value, using the less-than-or-equal-to (<=) operator.
func LessThanOrEqualTo(expected interface{}) *base.Matcher {
	return base.LessThanOrEqualTo(expected)
}

// Returns a matcher that matches values that are equal to the
// given expected value, using the equality (==) operator.
func EqualTo(expected interface{}) *base.Matcher {
	return base.EqualTo(expected)
}

// Returns a matcher that matches values that are not equal to the
// given expected value, using the inequality (!=) operator.
func NotEqualTo(expected interface{}) *base.Matcher {
	return base.NotEqualTo(expected)
}

// Returns a short-circuiting Matcher that matches whenever all of
// the given matchers match a given input value.  If any component
// matcher fails to match an input value, later matchers are not
// attempted.
func AllOf(matchers...*base.Matcher) *base.Matcher {
	match := func (actual interface{}) *base.Result {
		var results []*base.Result
		for index, matcher := range matchers {
			result := matcher.Match(actual)
			results := append(results, result)
			if !result.Matched() {
				return base.NewResultf(false,
					"Failed matcher %v of %v: [%v]",
					index+1, len(matchers), matcher).
					WithCauses(results...)
			}
		}
		return base.NewResultf(true,
			"Matched all %v matchers", len(matchers)).
			WithCauses(results...)
	}
	descriptions := make([]interface{}, len(matchers), len(matchers))
	for index, matcher := range matchers {
		descriptions[index] = base.Description("[#%v: %v]", index+1, matcher)
	}
	return base.NewMatcherf(match, "AllOf%v", descriptions)
}

// Returns a short-circuiting Matcher that matches whenever all of
// the given matchers match a given input value.  If any component
// matcher fails to match an input value, later matchers are not
// attempted.
func AnyOf(matchers...*base.Matcher) *base.Matcher {
	match := func (actual interface{}) *base.Result {
		var results []*base.Result
		for index, matcher := range matchers {
			result := matcher.Match(actual)
			results := append(results, result)
			if result.Matched() {
				return base.NewResultf(true,
					"Matched on matcher %v of %v: [%v]",
					index+1, len(matchers), matcher).
					WithCauses(results...)
			}
		}
		return base.NewResultf(false,
			"Matched none of the %v matchers", len(matchers)).
			WithCauses(results...)
	}
	descriptions := make([]interface{}, len(matchers), len(matchers))
	for index, matcher := range matchers {
		descriptions[index] = base.Description("[#%v: %v]", index+1, matcher)
	}
	return base.NewMatcherf(match, "AnyOf%v", descriptions)
}

// Returns a function that composes the given function with a Matcher, such as:
//    ToLength := Composer(func(s string) int { return len(s) }, "ToLength")
// And then:
//    HasLengthThree := ToLength(Is(EqualTo(3)))
//    HasLengthThree.Match("no").Matched() // false
//    HasLengthThree.Match("yes").Matched() // true
//
// The given function must be able to accept a single argument and
// return a single argument.
func Applying(function interface{}, name string) func(*base.Matcher) *base.Matcher  {
	funcValue := reflect.NewValue(function).(*reflect.FuncValue)
	funcType := funcValue.Type().(*reflect.FuncType)
	numIn := funcType.NumIn()
	numOut := funcType.NumOut()
	if numIn == 0 {
		panic(fmt.Sprintf("function must accept at least one value, was %v by function %v", numIn, function))
	}
	if numOut == 0 {
		panic(fmt.Sprintf("function must return at least one value, was %v by function %v", numOut, function))
	}
	return func(matcher *base.Matcher) *base.Matcher {
		match := func (actual interface{}) *base.Result {
			Assign := func(dst reflect.Value, src reflect.Value) (ok bool) {
				defer func() { recover(); }()
				dst.SetValue(src)
				ok = true
				return
			}
			actualValue := reflect.NewValue(actual)
			argValues := make([]reflect.Value, numIn, numIn)
			if numIn > 0 {
				inType := funcType.In(0)
				if numIn == 1 && funcType.DotDotDot() {
					inSlice := reflect.MakeSlice(inType.(*reflect.SliceType), 1, 1)
					if !Assign(inSlice.Elem(0), actualValue) {
						return base.NewResultf(false,
							"Cannot use %T as input to %T", actual, function)
					}
					argValues[0] = inSlice
				} else {
					inValue := reflect.MakeZero(inType)
					if !Assign(inValue, actualValue) {
						return base.NewResultf(false,
							"Cannot use %T as input to %T", actual, function)
					}
					argValues[0] = inValue
				}
				for i := 1; i < numIn; i++ {
					inType = funcType.In(i)
					argValues[i] = reflect.MakeZero(inType)
				}
			}
			outValues := funcValue.Call(argValues)
			outValue := outValues[0]
			out := outValue.Interface()
			result := matcher.Match(out)
			return base.NewResultf(result.Matched(),
				"%v(%#v) = %v", name, actual, out).
				WithCauses(result)
		}
		return base.NewMatcherf(match, "%v[%v]", name, matcher)
	}
}
<commit_msg>Improve 'not' error message<commit_after>// Copyright 2011 Mick Killianey.  All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package core

import (
	"fmt"
	"github.com/rdrdr/hamcrest/base"
	"reflect"
)

// Returns a Matcher that matches any input value.
func Anything() *base.Matcher {
	return _Anything
}
var _Anything *base.Matcher // singleton
func init() {
	match := func (actual interface{}) *base.Result {
		return base.NewResultf(true, "always matches")
	}
	_Anything = base.NewMatcherf(match, "Anything")
}

// Returns a Matcher that matches the boolean value true.
func True() *base.Matcher {
	return base.True()
}

// Returns a Matcher that matches the boolean value false.
func False() *base.Matcher {
	return base.False()
}

// Returns a Matcher that matches on values that cause the given
// functionOrMatcher to panic.
//
// functionOrMatcher should either be a function that accepts one
// parameter or a Matcher.
func PanicWhenApplying(functionOrMatcher interface{}, name string) *base.Matcher {
	var doSomething func(interface{})
	if matcher, ok := functionOrMatcher.(*base.Matcher); ok {
		doSomething = func(actual interface{}) { matcher.Match(actual) }
	} else {
		value := reflect.NewValue(functionOrMatcher)
		if funcValue, ok := value.(*reflect.FuncValue); ok {
			funcType := funcValue.Type().(*reflect.FuncType)
			numIn := funcType.NumIn()
			if numIn == 0 {
				panic(fmt.Sprintf("func must accept a single arg, was %T", functionOrMatcher))
			}
			inType := funcType.In(0)
			switch {
			case numIn == 1: // always ok
			case numIn == 2 && funcType.DotDotDot(): // ok
			default:
				panic(fmt.Sprintf("func must accept a single arg, was %T", functionOrMatcher))
			}
			doSomething = func(actual interface{}) {
				actualValue := reflect.NewValue(actual)
				argValues := make([]reflect.Value, numIn, numIn)
				if numIn == 1 && funcType.DotDotDot() {
					inSlice := reflect.MakeSlice(inType.(*reflect.SliceType), 1, 1)
					inValue := inSlice.Elem(0)
					inValue.SetValue(actualValue)
					argValues[0] = inSlice
				} else {
					inValue := reflect.MakeZero(inType)
					inValue.SetValue(actualValue)
					argValues[0] = inValue
					if numIn == 2 && funcType.DotDotDot() {
						inType2 := funcType.In(1)
						argValues[1] = reflect.MakeSlice(inType2.(*reflect.SliceType), 0, 0)
					}
				}
				funcValue.Call(argValues)
			}
		}
	}
	match := func (actual interface{}) (result *base.Result) {
		defer func() {
			if recover() != nil {
				result = base.NewResultf(true, "Panicked")
			}
		}()
		doSomething(actual)
		result = base.NewResultf(false, "Did not panic")
		return
	}
	return base.NewMatcherf(match,
		"PanicWhenApplying[%v]", name)
}

// Returns a Matcher that decorates another matcher and only matches
// when the underlying matcher does not match (and vice versa).
func Not(matcher *base.Matcher) *base.Matcher {
	match := func (actual interface{}) *base.Result {
		result := matcher.Match(actual)
		if result.Matched() {
			return base.NewResultf(false,
				"'Not' failed because inner matcher passed: %v", matcher).
				WithCauses(result)
		}
		return base.NewResultf(true,
			"'Not' passed because inner matcher failed: %v", matcher).
			WithCauses(result)
	}
	return base.NewMatcherf(match, "Not[%v]", matcher)
}

// Returns a Matcher that decorates another matcher.
func Is(matcher *base.Matcher) *base.Matcher {
	match := func (actual interface{}) *base.Result {
		result := matcher.Match(actual)
		return base.NewResult(result.Matched(), result).
			WithCauses(result.Causes()...)
	}
	return base.NewMatcherf(match, "Is[%v]", matcher)
}

// Returns a Matcher that matches if the actual value is nil
// or the nil value of its type.  (Note that this is *not*
// equivalent to DeeplyEqualTo(nil).)
func Nil() *base.Matcher {
	return base.Nil()
}

// Returns a Matcher that matches if the actual value is
// neither nil nor the nil value of its type.  (Note that
// this is *not* equivalent to Not(DeeplyEqualTo(nil)).)
func NonNil() *base.Matcher {
	return base.NonNil()
}

// Returns a Matcher that checks if the actual value is (deeply)
// equal to the given expected value, using reflect.DeepEqual.
//
// For an equality test equivalent to `==`, see the
// `hamcrest/comparison` package.
func DeepEqualTo(expected interface{}) *base.Matcher {
	return base.DeepEqualTo(expected)
}

// Returns a matcher that matches values that are greater-than the given
// expected value, using the greater-than (<) operator.
func GreaterThan(expected interface{}) *base.Matcher {
	return base.GreaterThan(expected)
}

// Returns a matcher that matches values that are greater-than-or-equal-to
// the given expected value, using the greater-than-or-equal-to (>=) operator.
func GreaterThanOrEqualTo(expected interface{}) *base.Matcher {
	return base.GreaterThanOrEqualTo(expected)
}

// Returns a matcher that matches values that are less-than the given
// expected value, using the less-than (<) operator.
func LessThan(expected interface{}) *base.Matcher {
	return base.LessThan(expected)
}

// Returns a matcher that matches values that are less-than-or-equal-to
// the given expected value, using the less-than-or-equal-to (<=) operator.
func LessThanOrEqualTo(expected interface{}) *base.Matcher {
	return base.LessThanOrEqualTo(expected)
}

// Returns a matcher that matches values that are equal to the
// given expected value, using the equality (==) operator.
func EqualTo(expected interface{}) *base.Matcher {
	return base.EqualTo(expected)
}

// Returns a matcher that matches values that are not equal to the
// given expected value, using the inequality (!=) operator.
func NotEqualTo(expected interface{}) *base.Matcher {
	return base.NotEqualTo(expected)
}

// Returns a short-circuiting Matcher that matches whenever all of
// the given matchers match a given input value.  If any component
// matcher fails to match an input value, later matchers are not
// attempted.
func AllOf(matchers...*base.Matcher) *base.Matcher {
	match := func (actual interface{}) *base.Result {
		var results []*base.Result
		for index, matcher := range matchers {
			result := matcher.Match(actual)
			results := append(results, result)
			if !result.Matched() {
				return base.NewResultf(false,
					"Failed matcher %v of %v: [%v]",
					index+1, len(matchers), matcher).
					WithCauses(results...)
			}
		}
		return base.NewResultf(true,
			"Matched all %v matchers", len(matchers)).
			WithCauses(results...)
	}
	descriptions := make([]interface{}, len(matchers), len(matchers))
	for index, matcher := range matchers {
		descriptions[index] = base.Description("[#%v: %v]", index+1, matcher)
	}
	return base.NewMatcherf(match, "AllOf%v", descriptions)
}

// Returns a short-circuiting Matcher that matches whenever all of
// the given matchers match a given input value.  If any component
// matcher fails to match an input value, later matchers are not
// attempted.
func AnyOf(matchers...*base.Matcher) *base.Matcher {
	match := func (actual interface{}) *base.Result {
		var results []*base.Result
		for index, matcher := range matchers {
			result := matcher.Match(actual)
			results := append(results, result)
			if result.Matched() {
				return base.NewResultf(true,
					"Matched on matcher %v of %v: [%v]",
					index+1, len(matchers), matcher).
					WithCauses(results...)
			}
		}
		return base.NewResultf(false,
			"Matched none of the %v matchers", len(matchers)).
			WithCauses(results...)
	}
	descriptions := make([]interface{}, len(matchers), len(matchers))
	for index, matcher := range matchers {
		descriptions[index] = base.Description("[#%v: %v]", index+1, matcher)
	}
	return base.NewMatcherf(match, "AnyOf%v", descriptions)
}

// Returns a function that composes the given function with a Matcher, such as:
//    ToLength := Composer(func(s string) int { return len(s) }, "ToLength")
// And then:
//    HasLengthThree := ToLength(Is(EqualTo(3)))
//    HasLengthThree.Match("no").Matched() // false
//    HasLengthThree.Match("yes").Matched() // true
//
// The given function must be able to accept a single argument and
// return a single argument.
func Applying(function interface{}, name string) func(*base.Matcher) *base.Matcher  {
	funcValue := reflect.NewValue(function).(*reflect.FuncValue)
	funcType := funcValue.Type().(*reflect.FuncType)
	numIn := funcType.NumIn()
	numOut := funcType.NumOut()
	if numIn == 0 {
		panic(fmt.Sprintf("function must accept at least one value, was %v by function %v", numIn, function))
	}
	if numOut == 0 {
		panic(fmt.Sprintf("function must return at least one value, was %v by function %v", numOut, function))
	}
	return func(matcher *base.Matcher) *base.Matcher {
		match := func (actual interface{}) *base.Result {
			Assign := func(dst reflect.Value, src reflect.Value) (ok bool) {
				defer func() { recover(); }()
				dst.SetValue(src)
				ok = true
				return
			}
			actualValue := reflect.NewValue(actual)
			argValues := make([]reflect.Value, numIn, numIn)
			if numIn > 0 {
				inType := funcType.In(0)
				if numIn == 1 && funcType.DotDotDot() {
					inSlice := reflect.MakeSlice(inType.(*reflect.SliceType), 1, 1)
					if !Assign(inSlice.Elem(0), actualValue) {
						return base.NewResultf(false,
							"Cannot use %T as input to %T", actual, function)
					}
					argValues[0] = inSlice
				} else {
					inValue := reflect.MakeZero(inType)
					if !Assign(inValue, actualValue) {
						return base.NewResultf(false,
							"Cannot use %T as input to %T", actual, function)
					}
					argValues[0] = inValue
				}
				for i := 1; i < numIn; i++ {
					inType = funcType.In(i)
					argValues[i] = reflect.MakeZero(inType)
				}
			}
			outValues := funcValue.Call(argValues)
			outValue := outValues[0]
			out := outValue.Interface()
			result := matcher.Match(out)
			return base.NewResultf(result.Matched(),
				"%v(%#v) = %v", name, actual, out).
				WithCauses(result)
		}
		return base.NewMatcherf(match, "%v[%v]", name, matcher)
	}
}
<|endoftext|>


<commit_before>package bittrex

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

type response struct {
	Success bool             `json:"success,required"`
	Message string           `json:"message,omitempty"`
	Result  *json.RawMessage `json:"result,required"`
}

type pingResponse struct {
	Response string `json:"response,required"`
}

type versionResponse struct {
	Version json.Number `json:"version,required,Number"`
}

// MarketSummary is the summary data of a market (usually 24h summary).
type MarketSummary struct {
	MarketName     string  `json:"MarketName,required"`     //The name of the market (e.g. BTC-ETH).
	High           float64 `json:"High,required"`           // The 24h high for the market.
	Low            float64 `json:"Low,required"`            // The 24h low for the market.
	Last           float64 `json:"Last,required"`           // The value of the last trade for the market (in base currency).
	Bid            float64 `json:"Bid,required"`            // The current highest bid value for the market.
	Ask            float64 `json:"Ask,required"`            // The current lowest ask value for the market.
	Volume         float64 `json:"Volume,required"`         // The 24h volume of the market, in market currency.
	BaseVolume     float64 `json:"BaseVolume,required"`     // The 24h volume for the market, in base currency.
	Timestamp      string  `json:"Timestamp,required"`      // The timestamp of the request.
	OpenBuyOrders  uint64  `json:"OpenBuyOrders,required"`  // The number of currently open buy orders.
	OpenSellOrders uint64  `json:"OpenSellOrders,required"` // The number of currently open sell orders.
	PrevDay        float64 `json:"PrevDay,required"`        // The closing price 24h before.
	Created        string  `json:"Created,required"`        // The timestamp of the creation of the market.
}

// MarketSummaries is a set of MarketSummary objects.
type MarketSummaries []MarketSummary

// MarketSummaryResult is a single unit of a MarketSummariesResult response and
// represents a single couple (Market Data, Market Summary) value.
type MarketSummaryResult struct {
	IsVerified bool          `json:"IsVerified"`
	Market     Market        `json:"Market,required"`
	Summary    MarketSummary `json:"Summary,required"`
}

// MarketSummariesResult is the response from a GetSummaries call.
type MarketSummariesResult []MarketSummaryResult

// Markets returns only the markets.
func (msr MarketSummariesResult) Markets() Markets {
	ret := make(Markets, len(msr))

	for i, result := range msr {
		ret[i] = result.Market
	}

	return ret
}

// Summaries returns only the market summaries.
func (msr MarketSummariesResult) Summaries() MarketSummaries {
	ret := make(MarketSummaries, len(msr))

	for i, result := range msr {
		ret[i] = result.Summary
	}

	return ret
}

// OpenOrder represents a currently open order.
type OpenOrder struct {
}

// OrderBook represents a set of public open Orders, which compose the OrderBook.
type OrderBook []OpenOrder

// Market represents a market metadata (name, base currency, trade currency)
// and so forth.
type Market struct {
	BaseCurrency       string  `json:"BaseCurrency,required"`
	BaseCurrencyLong   string  `json:"BaseCurrencyLong,required"`
	MarketCurrency     string  `json:"MarketCurrency,required"`
	MarketCurrencyLong string  `json:"MarketCurrencyLong,required"`
	MarketName         string  `json:"MarketName,required"`
	MinTradeSize       float64 `json:"MinTradeSize,required"`
	IsActive           bool    `json:"IsActive,required"`
	Created            string  `json:"Created,required"`
	Notice             string  `json:"Notice,required"`
	IsSponsored        bool    `json:"IsSponsored,required"`
	LogoURL            string  `json:"LogoUrl,required"`
}

// Markets is a set of markets.
type Markets []Market

type btcPriceResult struct {
	Bpi struct {
		USD struct {
			Code        string      `json:"code,required"`
			Description string      `json:"description,required"`
			Rate        string      `json:"rate,required"`
			RateFloat   json.Number `json:"rate_float,required"`
		} `json:"USD,required"`
		Disclaimer string `json:"disclaimer,required"`
	} `json:"bpi,required"`
	Time struct {
		Updated    string `json:"updated,required"`
		UpdatedISO string `json:"updatedISO,omitempty"`
		UpdatedUK  string `json:"updateduk,omitempty"`
	} `json:"time,required"`
}

// CandleStick represents a single candlestick in a chart.
type CandleStick struct {
	High       float64    `json:"H,required"`
	Open       float64    `json:"O,required"`
	Close      float64    `json:"C,required"`
	Low        float64    `json:"L,required"`
	Volume     float64    `json:"V,required"`
	BaseVolume float64    `json:"BV,required"`
	Timestamp  candleTime `json:"T,required"`
}

// CandleSticks is an array of CandleStick objects. It is a result from GetTicks
// and GetLatestTick calls too.
type CandleSticks []CandleStick
type csByTimestamp struct {
	CandleSticks
}

func (csbt csByTimestamp) Less(i, j int) bool {
	return time.Time(csbt.CandleSticks[i].Timestamp).Before(time.Time(csbt.CandleSticks[j].Timestamp))
}

func (csbt csByTimestamp) Len() int {
	return len(csbt.CandleSticks)
}

func (csbt csByTimestamp) Swap(i, j int) {
	csbt.CandleSticks[i], csbt.CandleSticks[j] = csbt.CandleSticks[j], csbt.CandleSticks[i]
}

// CandleIntervals represent all valid intervals supported
// by the GetTicks and GetLatestTick calls.
var CandleIntervals = map[string]bool{
	"oneMin":    true,
	"fiveMin":   true,
	"thirtyMin": true,
	"hour":      true,
	"day":       true,
}

type candleTime time.Time

func (t *candleTime) UnmarshalJSON(b []byte) error {
	if len(b) < 2 {
		return fmt.Errorf("could not parse time %s", string(b))
	}
	// trim enclosing ""
	result, err := time.Parse("2006-01-02T15:04:05", string(b[1:len(b)-1]))
	if err != nil {
		return fmt.Errorf("could not parse time: %v", err)
	}
	*t = candleTime(result)
	return nil
}

func (t candleTime) MarshalJSON() ([]byte, error) {
	stamp := fmt.Sprintf("\"%s\"", time.Time(t).Format("2006-01-02T15:04:05"))
	return []byte(stamp), nil
}

func (result btcPriceResult) Compress() BTCPrice {
	value, _ := result.Bpi.USD.RateFloat.Float64()
	ts, _ := time.Parse(time.RFC3339, result.Time.UpdatedISO)
	return BTCPrice{
		USDValue:  value,
		Timestamp: ts,
	}
}

// BTCPrice represents the BTC price at the specified timestamp.
type BTCPrice struct {
	USDValue  float64
	Timestamp time.Time
}
<commit_msg>Changing float64 to decimal.Decimal This change is required due to the fact that bittrex tends to floor values which are too small this problem is solved by using decimal type.<commit_after>package bittrex

import (
	"encoding/json"
	"fmt"
	"time"

	"github.com/shopspring/decimal"
)

type response struct {
	Success bool             `json:"success,required"`
	Message string           `json:"message,omitempty"`
	Result  *json.RawMessage `json:"result,required"`
}

type pingResponse struct {
	Response string `json:"response,required"`
}

type versionResponse struct {
	Version json.Number `json:"version,required,Number"`
}

// MarketSummary is the summary data of a market (usually 24h summary).
type MarketSummary struct {
	MarketName     string          `json:"MarketName,required"`     //The name of the market (e.g. BTC-ETH).
	High           decimal.Decimal `json:"High,required"`           // The 24h high for the market.
	Low            decimal.Decimal `json:"Low,required"`            // The 24h low for the market.
	Last           decimal.Decimal `json:"Last,required"`           // The value of the last trade for the market (in base currency).
	Bid            decimal.Decimal `json:"Bid,required"`            // The current highest bid value for the market.
	Ask            decimal.Decimal `json:"Ask,required"`            // The current lowest ask value for the market.
	Volume         decimal.Decimal `json:"Volume,required"`         // The 24h volume of the market, in market currency.
	BaseVolume     decimal.Decimal `json:"BaseVolume,required"`     // The 24h volume for the market, in base currency.
	Timestamp      string          `json:"Timestamp,required"`      // The timestamp of the request.
	OpenBuyOrders  uint64          `json:"OpenBuyOrders,required"`  // The number of currently open buy orders.
	OpenSellOrders uint64          `json:"OpenSellOrders,required"` // The number of currently open sell orders.
	PrevDay        decimal.Decimal `json:"PrevDay,required"`        // The closing price 24h before.
	Created        string          `json:"Created,required"`        // The timestamp of the creation of the market.
}

// MarketSummaries is a set of MarketSummary objects.
type MarketSummaries []MarketSummary

// MarketSummaryResult is a single unit of a MarketSummariesResult response and
// represents a single couple (Market Data, Market Summary) value.
type MarketSummaryResult struct {
	IsVerified bool          `json:"IsVerified"`
	Market     Market        `json:"Market,required"`
	Summary    MarketSummary `json:"Summary,required"`
}

// MarketSummariesResult is the response from a GetSummaries call.
type MarketSummariesResult []MarketSummaryResult

// Markets returns only the markets.
func (msr MarketSummariesResult) Markets() Markets {
	ret := make(Markets, len(msr))

	for i, result := range msr {
		ret[i] = result.Market
	}

	return ret
}

// Summaries returns only the market summaries.
func (msr MarketSummariesResult) Summaries() MarketSummaries {
	ret := make(MarketSummaries, len(msr))

	for i, result := range msr {
		ret[i] = result.Summary
	}

	return ret
}

// OpenOrder represents a currently open order.
type OpenOrder struct {
}

// OrderBook represents a set of public open Orders, which compose the OrderBook.
type OrderBook []OpenOrder

// Market represents a market metadata (name, base currency, trade currency)
// and so forth.
type Market struct {
	BaseCurrency       string          `json:"BaseCurrency,required"`
	BaseCurrencyLong   string          `json:"BaseCurrencyLong,required"`
	MarketCurrency     string          `json:"MarketCurrency,required"`
	MarketCurrencyLong string          `json:"MarketCurrencyLong,required"`
	MarketName         string          `json:"MarketName,required"`
	MinTradeSize       decimal.Decimal `json:"MinTradeSize,required"`
	IsActive           bool            `json:"IsActive,required"`
	Created            string          `json:"Created,required"`
	Notice             string          `json:"Notice,required"`
	IsSponsored        bool            `json:"IsSponsored,required"`
	LogoURL            string          `json:"LogoUrl,required"`
}

// Markets is a set of markets.
type Markets []Market

type btcPriceResult struct {
	Bpi struct {
		USD struct {
			Code        string      `json:"code,required"`
			Description string      `json:"description,required"`
			Rate        string      `json:"rate,required"`
			RateFloat   json.Number `json:"rate_float,required"`
		} `json:"USD,required"`
		Disclaimer string `json:"disclaimer,required"`
	} `json:"bpi,required"`
	Time struct {
		Updated    string `json:"updated,required"`
		UpdatedISO string `json:"updatedISO,omitempty"`
		UpdatedUK  string `json:"updateduk,omitempty"`
	} `json:"time,required"`
}

// CandleStick represents a single candlestick in a chart.
type CandleStick struct {
	High       decimal.Decimal `json:"H,required"`
	Open       decimal.Decimal `json:"O,required"`
	Close      decimal.Decimal `json:"C,required"`
	Low        decimal.Decimal `json:"L,required"`
	Volume     decimal.Decimal `json:"V,required"`
	BaseVolume decimal.Decimal `json:"BV,required"`
	Timestamp  candleTime      `json:"T,required"`
}

// CandleSticks is an array of CandleStick objects. It is a result from GetTicks
// and GetLatestTick calls too.
type CandleSticks []CandleStick
type csByTimestamp struct {
	CandleSticks
}

func (csbt csByTimestamp) Less(i, j int) bool {
	return time.Time(csbt.CandleSticks[i].Timestamp).Before(time.Time(csbt.CandleSticks[j].Timestamp))
}

func (csbt csByTimestamp) Len() int {
	return len(csbt.CandleSticks)
}

func (csbt csByTimestamp) Swap(i, j int) {
	csbt.CandleSticks[i], csbt.CandleSticks[j] = csbt.CandleSticks[j], csbt.CandleSticks[i]
}

// CandleIntervals represent all valid intervals supported
// by the GetTicks and GetLatestTick calls.
var CandleIntervals = map[string]bool{
	"oneMin":    true,
	"fiveMin":   true,
	"thirtyMin": true,
	"hour":      true,
	"day":       true,
}

type candleTime time.Time

func (t *candleTime) UnmarshalJSON(b []byte) error {
	if len(b) < 2 {
		return fmt.Errorf("could not parse time %s", string(b))
	}
	// trim enclosing ""
	result, err := time.Parse("2006-01-02T15:04:05", string(b[1:len(b)-1]))
	if err != nil {
		return fmt.Errorf("could not parse time: %v", err)
	}
	*t = candleTime(result)
	return nil
}

func (t candleTime) MarshalJSON() ([]byte, error) {
	stamp := fmt.Sprintf("\"%s\"", time.Time(t).Format("2006-01-02T15:04:05"))
	return []byte(stamp), nil
}

func (result btcPriceResult) Compress() BTCPrice {
	value, _ := result.Bpi.USD.RateFloat.Float64()
	ts, _ := time.Parse(time.RFC3339, result.Time.UpdatedISO)
	return BTCPrice{
		USDValue:  decimal.NewFromFloat(value),
		Timestamp: ts,
	}
}

// BTCPrice represents the BTC price at the specified timestamp.
type BTCPrice struct {
	USDValue  decimal.Decimal
	Timestamp time.Time
}
<|endoftext|>