<commit_before>package gdw

import (
	"fmt"
	"math/rand"
	"sync"
	"sync/atomic"
	"time"

	"github.com/eapache/channels"
)

// Worker is used to define a goroutine pool whose results and/or execution are of interest, thus awaitable through WaitGroup.
type WorkerPool struct {
	jobQueue   *channels.InfiniteChannel
	limiter    *channels.ResizableChannel
	queueDepth int64
	wgMap      map[string]*sync.WaitGroup
}

// Random string utilities - START

var src = rand.NewSource(time.Now().UnixNano())

const (
	letterIdxBits = 6
	letterIdxMask = 1<<letterIdxBits - 1
	letterIdxMax  = 63 / letterIdxBits
	letterBytes   = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
)

func generateToken() string {
	b := make([]byte, 20)
	for i, cache, remain := 20-1, src.Int63(), letterIdxMax; i >= 0; {
		if remain == 0 {
			cache, remain = src.Int63(), letterIdxMax
		}
		if idx := int(cache & letterIdxMask); idx < len(letterBytes) {
			b[i] = letterBytes[idx]
			i--
		}
		cache >>= letterIdxBits
		remain--
	}
	return string(b)
}

// Random string utilities - END

func NewWorkerPool(size int) *WorkerPool {
	jobQueue := channels.NewInfiniteChannel()
	limiter := channels.NewResizableChannel()
	limiter.Resize(channels.BufferCap(size))
	worker := &WorkerPool{
		jobQueue:   jobQueue,
		limiter:    limiter,
		queueDepth: 0,
		wgMap:      make(map[string]*sync.WaitGroup),
	}
	worker.wgMap["gdw_main_pool"] = &sync.WaitGroup{}

	go func() {
		jobQueueOut := jobQueue.Out()
		limiterIn := limiter.In()
		limiterOut := limiter.Out()
		for jobs := range jobQueueOut {
			switch jt := jobs.(type) {

			case Job:
				limiterIn <- true
				atomic.AddInt64(&worker.queueDepth, -1)
				go func(j Job) {
					j.DoWork()
					<-limiterOut
					worker.wgMap["gdw_main_pool"].Done()
				}(jt)

			case []Job:
				for _, job := range jt {
					limiterIn <- true
					atomic.AddInt64(&worker.queueDepth, -1)
					go func(j Job) {
						j.DoWork()
						<-limiterOut
						worker.wgMap["gdw_main_pool"].Done()
					}(job)
				}

			case *batchedJob:
				limiterIn <- true
				atomic.AddInt64(&worker.queueDepth, -1)
				go func(bj *batchedJob) {
					bj.batched.DoWork()
					<-limiterOut
					worker.wgMap[bj.name].Done()
					worker.wgMap["gdw_main_pool"].Done()
				}(jt)

			case []*batchedJob:
				for _, job := range jt {
					limiterIn <- true
					atomic.AddInt64(&worker.queueDepth, -1)
					go func(bj *batchedJob) {
						bj.batched.DoWork()
						<-limiterOut
						worker.wgMap[bj.name].Done()
						worker.wgMap["gdw_main_pool"].Done()
					}(job)
				}

			}
		}
	}()

	return worker
}

func (w *WorkerPool) NewBatch(name string) (*Batch, error) {
	if name == "gdw_main_pool" {
		return nil, fmt.Errorf("Batch name cannot be %s.", name)
	}
	w.wgMap[name] = &sync.WaitGroup{}
	return &Batch{
		worker: w,
		name:   name,
	}, nil
}

func (w *WorkerPool) NewTempBatch() *Batch {
	token := generateToken()
	w.wgMap[token] = &sync.WaitGroup{}
	return &Batch{
		worker: w,
		name:   token,
	}
}

func (w *WorkerPool) LoadBatch(name string) (*Batch, error) {
	if _, ok := w.wgMap[name]; !ok {
		return nil, fmt.Errorf("No batch named %s exists.", name)
	}
	return &Batch{
		worker: w,
		name:   name,
	}, nil
}

func (w *WorkerPool) SetPoolSize(size int) {
	w.limiter.Resize(channels.BufferCap(size))
}

func (w *WorkerPool) GetPoolSize() int {
	return int(w.limiter.Cap())
}

func (w *WorkerPool) GetQueueDepth() int {
	return int(atomic.LoadInt64(&w.queueDepth))
}

func (w *WorkerPool) Add(job Job, amount int) {
	w.add(job, amount, "gdw_main_pool")
}

func (w *WorkerPool) add(job Job, amount int, batch string) {
	w.wgMap["gdw_main_pool"].Add(amount)
	atomic.AddInt64(&w.queueDepth, int64(amount))
	switch batch {

	case "gdw_main_pool":
		jobs := make([]Job, amount)
		for i := 0; i < amount; i++ {
			jobs[i] = job
		}
		w.jobQueue.In() <- jobs

	default:
		bjs := make([]*batchedJob, amount)
		for i := 0; i < amount; i++ {
			bj := &batchedJob{
				batched: job,
				name:    batch,
			}
			bjs[i] = bj
		}
		w.jobQueue.In() <- bjs

	}
}

func (w *WorkerPool) AddOne(job Job) {
	w.addOne(job, "gdw_main_pool")
}

func (w *WorkerPool) addOne(job Job, batch string) {
	w.wgMap["gdw_main_pool"].Add(1)
	atomic.AddInt64(&w.queueDepth, 1)
	switch batch {

	case "gdw_main_pool":
		w.jobQueue.In() <- job

	default:
		bj := &batchedJob{
			batched: job,
			name:    batch,
		}
		w.jobQueue.In() <- bj

	}
}

func (w *WorkerPool) Wait() {
	w.wgMap["gdw_main_pool"].Wait()
}

func (w *WorkerPool) WaitBatch(batch string) error {
	wg, ok := w.wgMap[batch]
	if !ok {
		return fmt.Errorf("No batch named %s exists.", batch)
	}
	wg.Wait()
	return nil
}

func (w *WorkerPool) CleanBatch(batch string) error {
	if _, ok := w.wgMap[batch]; !ok {
		return fmt.Errorf("No batch named %s exists.", batch)
	}
	delete(w.wgMap, batch)
	return nil
}

func (w *WorkerPool) Close() {
	w.jobQueue.Close()
	w.limiter.Close()
}
<commit_msg>string generator source<commit_after>package gdw

import (
	"fmt"
	"math/rand"
	"sync"
	"sync/atomic"
	"time"

	"github.com/eapache/channels"
)

// Worker is used to define a goroutine pool whose results and/or execution are of interest, thus awaitable through WaitGroup.
type WorkerPool struct {
	jobQueue   *channels.InfiniteChannel
	limiter    *channels.ResizableChannel
	queueDepth int64
	wgMap      map[string]*sync.WaitGroup
}

// Random string utilities - START
// source - http://stackoverflow.com/a/31832326/1112789

var src = rand.NewSource(time.Now().UnixNano())

const (
	letterIdxBits = 6
	letterIdxMask = 1<<letterIdxBits - 1
	letterIdxMax  = 63 / letterIdxBits
	letterBytes   = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
)

func generateToken() string {
	b := make([]byte, 20)
	for i, cache, remain := 20-1, src.Int63(), letterIdxMax; i >= 0; {
		if remain == 0 {
			cache, remain = src.Int63(), letterIdxMax
		}
		if idx := int(cache & letterIdxMask); idx < len(letterBytes) {
			b[i] = letterBytes[idx]
			i--
		}
		cache >>= letterIdxBits
		remain--
	}
	return string(b)
}

// Random string utilities - END

func NewWorkerPool(size int) *WorkerPool {
	jobQueue := channels.NewInfiniteChannel()
	limiter := channels.NewResizableChannel()
	limiter.Resize(channels.BufferCap(size))
	worker := &WorkerPool{
		jobQueue:   jobQueue,
		limiter:    limiter,
		queueDepth: 0,
		wgMap:      make(map[string]*sync.WaitGroup),
	}
	worker.wgMap["gdw_main_pool"] = &sync.WaitGroup{}

	go func() {
		jobQueueOut := jobQueue.Out()
		limiterIn := limiter.In()
		limiterOut := limiter.Out()
		for jobs := range jobQueueOut {
			switch jt := jobs.(type) {

			case Job:
				limiterIn <- true
				atomic.AddInt64(&worker.queueDepth, -1)
				go func(j Job) {
					j.DoWork()
					<-limiterOut
					worker.wgMap["gdw_main_pool"].Done()
				}(jt)

			case []Job:
				for _, job := range jt {
					limiterIn <- true
					atomic.AddInt64(&worker.queueDepth, -1)
					go func(j Job) {
						j.DoWork()
						<-limiterOut
						worker.wgMap["gdw_main_pool"].Done()
					}(job)
				}

			case *batchedJob:
				limiterIn <- true
				atomic.AddInt64(&worker.queueDepth, -1)
				go func(bj *batchedJob) {
					bj.batched.DoWork()
					<-limiterOut
					worker.wgMap[bj.name].Done()
					worker.wgMap["gdw_main_pool"].Done()
				}(jt)

			case []*batchedJob:
				for _, job := range jt {
					limiterIn <- true
					atomic.AddInt64(&worker.queueDepth, -1)
					go func(bj *batchedJob) {
						bj.batched.DoWork()
						<-limiterOut
						worker.wgMap[bj.name].Done()
						worker.wgMap["gdw_main_pool"].Done()
					}(job)
				}

			}
		}
	}()

	return worker
}

func (w *WorkerPool) NewBatch(name string) (*Batch, error) {
	if name == "gdw_main_pool" {
		return nil, fmt.Errorf("Batch name cannot be %s.", name)
	}
	w.wgMap[name] = &sync.WaitGroup{}
	return &Batch{
		worker: w,
		name:   name,
	}, nil
}

func (w *WorkerPool) NewTempBatch() *Batch {
	token := generateToken()
	w.wgMap[token] = &sync.WaitGroup{}
	return &Batch{
		worker: w,
		name:   token,
	}
}

func (w *WorkerPool) LoadBatch(name string) (*Batch, error) {
	if _, ok := w.wgMap[name]; !ok {
		return nil, fmt.Errorf("No batch named %s exists.", name)
	}
	return &Batch{
		worker: w,
		name:   name,
	}, nil
}

func (w *WorkerPool) SetPoolSize(size int) {
	w.limiter.Resize(channels.BufferCap(size))
}

func (w *WorkerPool) GetPoolSize() int {
	return int(w.limiter.Cap())
}

func (w *WorkerPool) GetQueueDepth() int {
	return int(atomic.LoadInt64(&w.queueDepth))
}

func (w *WorkerPool) Add(job Job, amount int) {
	w.add(job, amount, "gdw_main_pool")
}

func (w *WorkerPool) add(job Job, amount int, batch string) {
	w.wgMap["gdw_main_pool"].Add(amount)
	atomic.AddInt64(&w.queueDepth, int64(amount))
	switch batch {

	case "gdw_main_pool":
		jobs := make([]Job, amount)
		for i := 0; i < amount; i++ {
			jobs[i] = job
		}
		w.jobQueue.In() <- jobs

	default:
		bjs := make([]*batchedJob, amount)
		for i := 0; i < amount; i++ {
			bj := &batchedJob{
				batched: job,
				name:    batch,
			}
			bjs[i] = bj
		}
		w.jobQueue.In() <- bjs

	}
}

func (w *WorkerPool) AddOne(job Job) {
	w.addOne(job, "gdw_main_pool")
}

func (w *WorkerPool) addOne(job Job, batch string) {
	w.wgMap["gdw_main_pool"].Add(1)
	atomic.AddInt64(&w.queueDepth, 1)
	switch batch {

	case "gdw_main_pool":
		w.jobQueue.In() <- job

	default:
		bj := &batchedJob{
			batched: job,
			name:    batch,
		}
		w.jobQueue.In() <- bj

	}
}

func (w *WorkerPool) Wait() {
	w.wgMap["gdw_main_pool"].Wait()
}

func (w *WorkerPool) WaitBatch(batch string) error {
	wg, ok := w.wgMap[batch]
	if !ok {
		return fmt.Errorf("No batch named %s exists.", batch)
	}
	wg.Wait()
	return nil
}

func (w *WorkerPool) CleanBatch(batch string) error {
	if _, ok := w.wgMap[batch]; !ok {
		return fmt.Errorf("No batch named %s exists.", batch)
	}
	delete(w.wgMap, batch)
	return nil
}

func (w *WorkerPool) Close() {
	w.jobQueue.Close()
	w.limiter.Close()
}
<|endoftext|>


<commit_before>package types

import "github.com/pkg/errors"

// A Place isn't something directly used by the Navitia.io api
// However, it allows the library user to use idiomatic go when working with the library
// If you want a countainer, see PlaceCountainer
// Place is satisfied by:
// - StopArea
// - POI
// - Address
// - StopPoint
// - AdministrativeRegion
type Place interface {
	// PlaceID returns the ID associated with the Place
	PlaceID() ID

	// PlaceName returns the name of the Place
	PlaceName() string

	// PlaceType returns the name of the type of the Place
	PlaceType() string
}

// PlaceCountainer is the ugly countainer sent by Navitia to make us all cry.
// However, as this can be useful. May be removed from the public API in gonavitia v0.
type PlaceCountainer struct {
	ID           ID     `json:"id"`
	Name         string `json:"name"`
	Quality      uint   `json:"quality,omitempty"`
	EmbeddedType string `json:"embedded_type"`

	// Four possibilitiess
	StopArea             *StopArea             `json:"stop_area,omitempty"`
	POI                  *POI                  `json:"POI,omitempty"`
	Address              *Address              `json:"address,omitempty"`
	StopPoint            *StopPoint            `json:"stop_point,omitempty"`
	AdministrativeRegion *AdministrativeRegion `json:"administrative_region,omitempty"`
}

// Place returns the Place countained in the PlaceCountainer
// If PlaceCountainer is empty, Place returns nil
// If there's no place indicated but PlaceCountainer isn't empty, Place returns an error as well as a nil Place.
func (pc PlaceCountainer) Place() (Place, error) {
	// If PlaceCountainer is empty, return nil
	empty := PlaceCountainer{}
	if pc == empty {
		return nil, nil
	}

	// Check for each type
	switch pc.EmbeddedType {
	case "stop_area":
		return pc.StopArea, nil
	case "poi":
		return pc.POI, nil
	case "address":
		return pc.Address, nil
	case "stop_point":
		return pc.StopPoint, nil
	case "administrative_region":
		return pc.AdministrativeRegion, nil
	default:
		return nil, errors.Errorf("No known embedded type indicated (we have \"%s\"), can't return a place !", pc.EmbeddedType)
	}
}

// A StopArea represents a stop area: a nameable zone, where there are some stop points.
type StopArea struct {
	ID   ID     `json:"id"`
	Name string `json:"name"`

	// Label of the stop area.
	// The name is directly taken from the data whereas the label is something computed by navitia for better traveler information.
	// If you don't know what to display, display the label
	Label string `json:"label"`

	// Coordinates of the stop area
	Coord Coordinates `json:"coord"`

	// Administrative regions of the stop area in which is placed the stop area
	AdministrativeRegions []AdministrativeRegion `json:"administrative_regions"`

	// Stop points countained in this stop area
	StopPoints []StopPoint `json:"stop_points"`
}

// PlaceID returns the ID associated with the StopArea
// Helps satisfy Place
func (sa StopArea) PlaceID() ID {
	return sa.ID
}

// PlaceName returns the name of the StopArea
// Helps satisfy Place
func (sa StopArea) PlaceName() string {
	return sa.Name
}

// PlaceType returns the type of place, in this case "stop_area"
// Helps satisfy Place
func (sa StopArea) PlaceType() string {
	return "stop_area"
}

// A POI is a Point Of Interest. A loosely-defined place.
type POI struct {
	ID   ID     `json:"id"`
	Name string `json:"name"`

	// The name is directly taken from the data whereas the label is something computed by navitia for better traveler information.
	// If you don't know what to display, display the label
	Label string `json:"label"`

	// The type of the POI
	Type POIType `json:"poi_type"`
}

// PlaceID returns the ID associated with the POI.
// Helps satisfy Place
func (poi POI) PlaceID() ID {
	return poi.ID
}

// PlaceName returns the name of the POI
// Helps satisfy Place
func (poi POI) PlaceName() string {
	return poi.Name
}

// PlaceType returns the type of place, in this case "poi"
// Helps satisfy Place
func (poi POI) PlaceType() string {
	return "poi"
}

// A POIType codes for the type of the point of interest
// TODO: A list of usual types ?
type POIType struct {
	ID   ID     `json:"id"`
	Name string `json:"name"`
}

// An Address codes for a real-world address: a point located in a street.
type Address struct {
	ID   ID     `json:"id"`
	Name string `json:"name"`

	// Label of the address
	// The name is directly taken from the data whereas the label is something computed by navitia for better traveler information.
	// If you don't know what to display, display the label
	Label string `json:"label"`

	// Coordinates of the address
	Coord Coordinates `json:"coord"`

	// House number of the address
	HouseNumber uint `json:"house_number"`

	// Administrative regions of the stop area in which is placed the stop area
	AdministrativeRegions []AdministrativeRegion `json:"administrative_regions"`
}

// PlaceID returns the ID associated with the Address
// Helps satisfy Place
func (add Address) PlaceID() ID {
	return add.ID
}

// PlaceName returns the name of the Address
// Helps satisfy Place
func (add Address) PlaceName() string {
	return add.Name
}

// PlaceType returns the type of place, in this case "address"
// Helps satisfy Place
func (add Address) PlaceType() string {
	return "address"
}

// A StopPoint codes for a stop point in a line: a location where vehicles can pickup or drop off passengers.
type StopPoint struct {
	ID ID `json:"id"`

	// Name of the stop point
	Name string `json:"name"`

	// Coordinates of the stop point
	Coord Coordinates `json:"coord"`

	// Administrative regions of the stop point
	AdministrativeRegions []AdministrativeRegion `json:"administrative_regions"`

	// List of equipments of the stop point
	Equipments []Equipment `json:"equipment"`

	// Stop Area countaining the stop point
	StopArea *StopArea `json:"stop_area"`
}

// PlaceID returns the ID associated with the Stop Point
// Helps satisfy Place
func (sp StopPoint) PlaceID() ID {
	return sp.ID
}

// PlaceName returns the name of the Stop Point
// Helps satisfy Place
func (sp StopPoint) PlaceName() string {
	return sp.Name
}

// PlaceType returns the type of place, in this case "stop_point"
// Helps satisfy Place
func (sp StopPoint) PlaceType() string {
	return "stop_point"
}

// An AdministrativeRegion represents an administrative region: a region under the control/responsibility of a specific organisation.
// It can be a city, a district, a neightborhood, etc.
type AdministrativeRegion struct {
	ID   ID     `json:"id"`
	Name string `json:"name"`

	// Label of the address
	// The name is directly taken from the data whereas the label is something computed by navitia for better traveler information.
	// If you don't know what to display, display the label
	Label string `json:"label"`

	// Coordinates of the administrative region
	Coord Coordinates `json:"coord"`

	// Level of the administrative region
	Level int `json:"level"`

	// Zip code of the administrative region
	ZipCode string
}

// PlaceID returns the ID associated with the AdministrativeRegion
// Helps satisfy Place
func (ar AdministrativeRegion) PlaceID() ID {
	return ar.ID
}

// PlaceName returns the name of the AdministrativeRegion
// Helps satisfy Place
func (ar AdministrativeRegion) PlaceName() string {
	return ar.Name
}

// PlaceType returns the type of place, in this case "administrative_region"
// Helps satisfy Place
func (ar AdministrativeRegion) PlaceType() string {
	return "administrative_region"
}
<commit_msg>Add String methods to each type implementing Place, and to Place itself<commit_after>package types

import (
	"fmt"
	"github.com/pkg/errors"
)

// A Place isn't something directly used by the Navitia.io api
// However, it allows the library user to use idiomatic go when working with the library
// If you want a countainer, see PlaceCountainer
// Place is satisfied by:
// - StopArea
// - POI
// - Address
// - StopPoint
// - AdministrativeRegion
type Place interface {
	// PlaceID returns the ID associated with the Place
	PlaceID() ID

	// PlaceName returns the name of the Place
	PlaceName() string

	// PlaceType returns the name of the type of the Place
	PlaceType() string

	// String() for string printing
	String() string
}

// PlaceCountainer is the ugly countainer sent by Navitia to make us all cry.
// However, as this can be useful. May be removed from the public API in gonavitia v0.
type PlaceCountainer struct {
	ID           ID     `json:"id"`
	Name         string `json:"name"`
	Quality      uint   `json:"quality,omitempty"`
	EmbeddedType string `json:"embedded_type"`

	// Four possibilitiess
	StopArea             *StopArea             `json:"stop_area,omitempty"`
	POI                  *POI                  `json:"POI,omitempty"`
	Address              *Address              `json:"address,omitempty"`
	StopPoint            *StopPoint            `json:"stop_point,omitempty"`
	AdministrativeRegion *AdministrativeRegion `json:"administrative_region,omitempty"`
}

// Place returns the Place countained in the PlaceCountainer
// If PlaceCountainer is empty, Place returns nil
// If there's no place indicated but PlaceCountainer isn't empty, Place returns an error as well as a nil Place.
func (pc PlaceCountainer) Place() (Place, error) {
	// If PlaceCountainer is empty, return nil
	empty := PlaceCountainer{}
	if pc == empty {
		return nil, nil
	}

	// Check for each type
	switch pc.EmbeddedType {
	case "stop_area":
		return pc.StopArea, nil
	case "poi":
		return pc.POI, nil
	case "address":
		return pc.Address, nil
	case "stop_point":
		return pc.StopPoint, nil
	case "administrative_region":
		return pc.AdministrativeRegion, nil
	default:
		return nil, errors.Errorf("No known embedded type indicated (we have \"%s\"), can't return a place !", pc.EmbeddedType)
	}
}

// A StopArea represents a stop area: a nameable zone, where there are some stop points.
type StopArea struct {
	ID   ID     `json:"id"`
	Name string `json:"name"`

	// Label of the stop area.
	// The name is directly taken from the data whereas the label is something computed by navitia for better traveler information.
	// If you don't know what to display, display the label
	Label string `json:"label"`

	// Coordinates of the stop area
	Coord Coordinates `json:"coord"`

	// Administrative regions of the stop area in which is placed the stop area
	AdministrativeRegions []AdministrativeRegion `json:"administrative_regions"`

	// Stop points countained in this stop area
	StopPoints []StopPoint `json:"stop_points"`
}

// PlaceID returns the ID associated with the StopArea
// Helps satisfy Place
func (sa StopArea) PlaceID() ID {
	return sa.ID
}

// PlaceName returns the name of the StopArea
// Helps satisfy Place
func (sa StopArea) PlaceName() string {
	return sa.Name
}

// PlaceType returns the type of place, in this case "stop_area"
// Helps satisfy Place
func (sa StopArea) PlaceType() string {
	return "stop_area"
}

// String pretty-prints the StopArea.
// Satisifes Stringer and helps satisfy Place
func (sa StopArea) String() string {
	var label string
	if sa.Label == "" {
		label = sa.Name
	} else {
		label = sa.Label
	}

	format := "%s (id: %s)"
	return fmt.Sprintf(format, label, sa.ID)
}

// A POI is a Point Of Interest. A loosely-defined place.
type POI struct {
	ID   ID     `json:"id"`
	Name string `json:"name"`

	// The name is directly taken from the data whereas the label is something computed by navitia for better traveler information.
	// If you don't know what to display, display the label
	Label string `json:"label"`

	// The type of the POI
	Type POIType `json:"poi_type"`
}

// PlaceID returns the ID associated with the POI.
// Helps satisfy Place
func (poi POI) PlaceID() ID {
	return poi.ID
}

// PlaceName returns the name of the POI.
// Helps satisfy Place
func (poi POI) PlaceName() string {
	return poi.Name
}

// PlaceType returns the type of place, in this case "poi".
// Helps satisfy Place
func (poi POI) PlaceType() string {
	return "poi"
}

// String pretty-prints the POI.
// Satisifes Stringer and helps satisfy Place
func (poi POI) String() string {
	var label string
	if poi.Label == "" {
		label = poi.Name
	} else {
		label = poi.Label
	}

	format := "%s (id: %s)"
	return fmt.Sprintf(format, label, poi.ID)
}

// A POIType codes for the type of the point of interest
// TODO: A list of usual types ?
type POIType struct {
	ID   ID     `json:"id"`
	Name string `json:"name"`
}

// An Address codes for a real-world address: a point located in a street.
type Address struct {
	ID   ID     `json:"id"`
	Name string `json:"name"`

	// Label of the address
	// The name is directly taken from the data whereas the label is something computed by navitia for better traveler information.
	// If you don't know what to display, display the label
	Label string `json:"label"`

	// Coordinates of the address
	Coord Coordinates `json:"coord"`

	// House number of the address
	HouseNumber uint `json:"house_number"`

	// Administrative regions of the stop area in which is placed the stop area
	AdministrativeRegions []AdministrativeRegion `json:"administrative_regions"`
}

// PlaceID returns the ID associated with the Address
// Helps satisfy Place
func (add Address) PlaceID() ID {
	return add.ID
}

// PlaceName returns the name of the Address
// Helps satisfy Place
func (add Address) PlaceName() string {
	return add.Name
}

// PlaceType returns the type of place, in this case "address"
// Helps satisfy Place
func (add Address) PlaceType() string {
	return "address"
}

// String pretty-prints the Address.
// Satisifes Stringer and helps satisfy Place
func (add Address) String() string {
	var label string
	if add.Label == "" {
		label = add.Name
	} else {
		label = add.Label
	}

	format := "%s (id: %s)"
	return fmt.Sprintf(format, label, add.ID)
}

// A StopPoint codes for a stop point in a line: a location where vehicles can pickup or drop off passengers.
type StopPoint struct {
	ID ID `json:"id"`

	// Name of the stop point
	Name string `json:"name"`

	// Coordinates of the stop point
	Coord Coordinates `json:"coord"`

	// Administrative regions of the stop point
	AdministrativeRegions []AdministrativeRegion `json:"administrative_regions"`

	// List of equipments of the stop point
	Equipments []Equipment `json:"equipment"`

	// Stop Area countaining the stop point
	StopArea *StopArea `json:"stop_area"`
}

// PlaceID returns the ID associated with the Stop Point
// Helps satisfy Place
func (sp StopPoint) PlaceID() ID {
	return sp.ID
}

// PlaceName returns the name of the Stop Point
// Helps satisfy Place
func (sp StopPoint) PlaceName() string {
	return sp.Name
}

// PlaceType returns the type of place, in this case "stop_point"
// Helps satisfy Place
func (sp StopPoint) PlaceType() string {
	return "stop_point"
}

// String pretty-prints the StopPoint.
// Satisifes Stringer and helps satisfy Place
func (sp StopPoint) String() string {
	format := "%s (id: %s)"
	return fmt.Sprintf(format, sp.Name, sp.ID)
}

// An AdministrativeRegion represents an administrative region: a region under the control/responsibility of a specific organisation.
// It can be a city, a district, a neightborhood, etc.
type AdministrativeRegion struct {
	ID   ID     `json:"id"`
	Name string `json:"name"`

	// Label of the address
	// The name is directly taken from the data whereas the label is something computed by navitia for better traveler information.
	// If you don't know what to display, display the label
	Label string `json:"label"`

	// Coordinates of the administrative region
	Coord Coordinates `json:"coord"`

	// Level of the administrative region
	Level int `json:"level"`

	// Zip code of the administrative region
	ZipCode string
}

// PlaceID returns the ID associated with the AdministrativeRegion
// Helps satisfy Place
func (ar AdministrativeRegion) PlaceID() ID {
	return ar.ID
}

// PlaceName returns the name of the AdministrativeRegion
// Helps satisfy Place
func (ar AdministrativeRegion) PlaceName() string {
	return ar.Name
}

// PlaceType returns the type of place, in this case "administrative_region"
// Helps satisfy Place
func (ar AdministrativeRegion) PlaceType() string {
	return "administrative_region"
}

// String pretty-prints the AdministrativeRegion.
// Satisifes Stringer and helps satisfy Place
func (ar AdministrativeRegion) String() string {
	var label string
	if ar.Label == "" {
		label = ar.Name
	} else {
		label = ar.Label
	}

	format := "%s (id: %s)"
	return fmt.Sprintf(format, label, ar.ID)
}
<|endoftext|>


<commit_before>// Package visits provides a barebones mechanic to greet players.
package cod

import (
	"database/sql"
	"fmt"
	integrated "github.com/adabei/goldenbot-integrated/cod"
	"github.com/adabei/goldenbot/events"
	"github.com/adabei/goldenbot/events/cod"
	"github.com/adabei/goldenbot/helpers"
	"github.com/adabei/goldenbot/rcon"
	"log"
)

var config map[string]interface{} = map[string]interface{}{"message": "Welcome to the server %v. You have visited %d times."}

const schema = `
create table visits (
  players_id text primary key,
  total integer default 1
);`

type Visits struct {
	cfg      map[string]interface{}
	requests chan rcon.RCONQuery
	events   chan interface{}
	db       *sql.DB
}

func NewVisits(cfg map[string]interface{}, requests chan rcon.RCONQuery, ea events.Aggregator, db *sql.DB) *Visits {
	v := new(Visits)
	v.cfg = make(map[string]interface{})
	helpers.Merge(config, v.cfg)
	helpers.Merge(cfg, v.cfg)
	v.requests = requests
	v.events = ea.Subscribe(v)
	v.db = db
	return v
}

func (v *Visits) Setup() error {
	_, err := v.db.Exec(schema)
	return err
}

func (v *Visits) Start() {
	for {
		in := <-v.events
		if ev, ok := in.(cod.Join); ok {
			if exists(v.db, ev.GUID) {
				// update
				log.Println("visits: updating total for player", ev.GUID)
				_, err := v.db.Exec("update visits set total = total + 1 where players_id = ?;", ev.GUID)

				if err != nil {
					log.Fatal("visits: fatal error in update:", err)
				}
			} else {
				// insert new
				log.Println("visits: inserting player", ev.GUID, "into database")
				_, err := v.db.Exec("insert into visits(players_id) values(?);", ev.GUID)

				if err != nil {
					log.Fatal("visits: fatal error in insert:", err)
				}
			}

			var total int
			err := v.db.QueryRow("select total from visits where players_id = ?", ev.GUID).Scan(&total)
			if err != nil {
				total = 1
			}

			msg, ok := v.cfg["message"].(string)
			if ok {
				// it is to be expected that the new GUID is not registered yet
				num, _ := integrated.Num(ev.GUID)
				v.requests <- rcon.RCONQuery{Command: "tell " + string(num) + " " +
					fmt.Sprintf(msg, ev.Name, total), Response: nil}
			} else {
				log.Println("Could not cast welcome message. No such messages will be sent.")
			}
		}
	}
}

func exists(db *sql.DB, id string) bool {
	var guid string
	err := db.QueryRow("select players_id from visits where players_id = ?", id).Scan(&guid)
	if err != nil {
		return false
	}

	return true
}
<commit_msg>refactors config mechanism and the way messages are built<commit_after>// Package visits provides a barebones mechanic to greet players.
// Only the joining player will see this greeting and the number
// of times he has joined.
package cod

import (
	"database/sql"
	"fmt"
	integrated "github.com/adabei/goldenbot-integrated/cod"
	"github.com/adabei/goldenbot/events"
	"github.com/adabei/goldenbot/events/cod"
	"github.com/adabei/goldenbot/rcon"
	"log"
)

type VisitsConfig struct {
	Prefix       string
	FirstMessage string
	Message      string
}

const schema = `
create table visits (
  players_id text primary key,
  total integer default 1
);`

type Visits struct {
	Config   VisitsConfig
	requests chan rcon.RCONQuery
	events   chan interface{}
	db       *sql.DB
}

func NewVisits(config VisitsConfig, requests chan rcon.RCONQuery, ea events.Aggregator, db *sql.DB) *Visits {
	v := new(Visits)
	v.Config = config
	v.requests = requests
	v.events = ea.Subscribe(v)
	v.db = db
	return v
}

func (v *Visits) Setup() error {
	_, err := v.db.Exec(schema)
	return err
}

func (v *Visits) Start() {
	for {
		in := <-v.events
		if ev, ok := in.(cod.Join); ok {
			if exists(v.db, ev.GUID) {
				// update
				log.Println("visits: updating total for player", ev.GUID)
				_, err := v.db.Exec("update visits set total = total + 1 where players_id = ?;", ev.GUID)

				if err != nil {
					log.Fatal("visits: fatal error in update:", err)
				}
			} else {
				// insert new
				log.Println("visits: inserting player", ev.GUID, "into database")
				_, err := v.db.Exec("insert into visits(players_id) values(?);", ev.GUID)

				if err != nil {
					log.Fatal("visits: fatal error in insert:", err)
				}
			}

			var total int
			err := v.db.QueryRow("select total from visits where players_id = ?", ev.GUID).Scan(&total)
			if err != nil {
				total = 1
			}

			var msg string
			if total != 1 {
				msg = fmt.Sprintf(v.Config.Message, ev.Name, total)
			} else {
				msg = fmt.Sprintf(v.Config.FirstMessage, ev.Name)
			}

			num, err := integrated.Num(ev.GUID)
			if err == nil {
				v.requests <- rcon.RCONQuery{Command: "tell " + string(num) + " " +
					v.Config.Prefix + msg, Response: nil}
			} else {
				log.Println("visits: could not resolve num for player", ev.GUID)
			}
		}
	}
}

func exists(db *sql.DB, id string) bool {
	var guid string
	err := db.QueryRow("select players_id from visits where players_id = ?", id).Scan(&guid)
	if err != nil {
		return false
	}

	return true
}
<|endoftext|>


<commit_before>package main

import (
	"errors"
	"fmt"
	r "reflect"
	"strings"

	"github.com/cosmos72/gomacro/imports"
)

// Support an interface similar - but not identical - to the IPython (canonical Jupyter kernel).
// See http://ipython.readthedocs.io/en/stable/api/generated/IPython.display.html#IPython.display.display
// for a good overview of the support types. Note: This is missing _repr_markdown_ and _repr_javascript_.

const (
	MIMETypeHTML       = "text/html"
	MIMETypeJavaScript = "application/javascript"
	MIMETypeJPEG       = "image/jpeg"
	MIMETypeJSON       = "application/json"
	MIMETypeLatex      = "text/latex"
	MIMETypeMarkdown   = "text/markdown"
	MIMETypePNG        = "image/png"
	MIMETypePDF        = "application/pdf"
	MIMETypeSVG        = "image/svg+xml"
)

// injected as placeholder in the interpreter, it's then replaced at runtime
// by a closure that knows how to talk with Jupyter
func stubDisplay(Data) error {
	return errors.New("cannot display: connection with Jupyter not available")
}

// TODO handle the metadata

func MakeData(mimeType string, data interface{}) Data {
	return Data{
		Data: BundledMIMEData{
			"text/plain": fmt.Sprint(data),
			mimeType:     data,
		},
	}
}

func MakeData3(mimeType string, plaintext string, data interface{}) Data {
	return Data{
		Data: BundledMIMEData{
			"text/plain": plaintext,
			mimeType:     data,
		},
	}
}

func Bytes(mimeType string, bytes []byte) Data {
	return MakeData3(mimeType, mimeType, bytes)
}

func HTML(html string) Data {
	return MakeData(MIMETypeHTML, html)
}

func JSON(json map[string]interface{}) Data {
	return MakeData(MIMETypeJSON, json)
}

func JavaScript(javascript string) Data {
	return MakeData(MIMETypeJavaScript, javascript)
}

func JPEG(jpeg []byte) Data {
	return MakeData3(MIMETypeJPEG, "jpeg image", jpeg) // []byte are encoded as base64 by the marshaller
}

func Latex(latex string) Data {
	return MakeData3(MIMETypeLatex, latex, "$"+strings.Trim(latex, "$")+"$")
}

func Markdown(markdown string) Data {
	return MakeData(MIMETypeMarkdown, markdown)
}

func Math(latex string) Data {
	return MakeData3(MIMETypeLatex, latex, "$$"+strings.Trim(latex, "$")+"$$")
}

func PDF(pdf []byte) Data {
	return MakeData3(MIMETypePDF, "pdf document", pdf) // []byte are encoded as base64 by the marshaller
}

func PNG(png []byte) Data {
	return MakeData3(MIMETypePNG, "png image", png) // []byte are encoded as base64 by the marshaller
}

func String(mimeType string, s string) Data {
	return MakeData(mimeType, s)
}

func SVG(svg string) Data {
	return MakeData(MIMETypeSVG, svg)
}

// MIME encapsulates the data and metadata into a Data.
// The 'data' map is expected to contain at least one {key,value} pair,
// with value being a string, []byte or some other JSON serializable representation,
// and key equal to the MIME type of such value.
// The exact structure of value is determined by what the frontend expects.
// Some easier-to-use functions for common formats supported by the Jupyter frontend
// are provided by the various functions above.
func MIME(data, metadata map[string]interface{}) Data {
	return Data{data, metadata, nil}
}

// prepare imports.Package for interpreted code
var display = imports.Package{
	Binds: map[string]r.Value{
		"Bytes":              r.ValueOf(Bytes),
		"HTML":               r.ValueOf(HTML),
		"Image":              r.ValueOf(Image),
		"JPEG":               r.ValueOf(JPEG),
		"JSON":               r.ValueOf(JSON),
		"JavaScript":         r.ValueOf(JavaScript),
		"Latex":              r.ValueOf(Latex),
		"MakeData":           r.ValueOf(MakeData),
		"MakeData3":          r.ValueOf(MakeData3),
		"Markdown":           r.ValueOf(Markdown),
		"Math":               r.ValueOf(Math),
		"MIME":               r.ValueOf(MIME),
		"MIMETypeHTML":       r.ValueOf(MIMETypeHTML),
		"MIMETypeJavaScript": r.ValueOf(MIMETypeJavaScript),
		"MIMETypeJPEG":       r.ValueOf(MIMETypeJPEG),
		"MIMETypeJSON":       r.ValueOf(MIMETypeJSON),
		"MIMETypeLatex":      r.ValueOf(MIMETypeLatex),
		"MIMETypeMarkdown":   r.ValueOf(MIMETypeMarkdown),
		"MIMETypePDF":        r.ValueOf(MIMETypePDF),
		"MIMETypePNG":        r.ValueOf(MIMETypePNG),
		"MIMETypeSVG":        r.ValueOf(MIMETypeSVG),
		"PDF":                r.ValueOf(PDF),
		"PNG":                r.ValueOf(PNG),
		"String":             r.ValueOf(String),
		"SVG":                r.ValueOf(SVG),
	},
	Types: map[string]r.Type{
		"BundledMIMEData": r.TypeOf((*BundledMIMEData)(nil)).Elem(),
		"Data":            r.TypeOf((*Data)(nil)).Elem(),
	},
}

// allow importing "display" and "github.com/gopherdata/gophernotes" packages
func init() {
	imports.Packages["display"] = display
	imports.Packages["github.com/gopherdata/gophernotes"] = display
}
<commit_msg>added MIME type autodetection to most functions in package 'display'. new functions in package 'display': Any(), File(), Reader(), WriterTo()<commit_after>package main

import (
	"bytes"
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"net/http"
	r "reflect"
	"strings"

	"github.com/cosmos72/gomacro/imports"
)

// Support an interface similar - but not identical - to the IPython (canonical Jupyter kernel).
// See http://ipython.readthedocs.io/en/stable/api/generated/IPython.display.html#IPython.display.display
// for a good overview of the support types. Note: This is missing _repr_markdown_ and _repr_javascript_.

const (
	MIMETypeHTML       = "text/html"
	MIMETypeJavaScript = "application/javascript"
	MIMETypeJPEG       = "image/jpeg"
	MIMETypeJSON       = "application/json"
	MIMETypeLatex      = "text/latex"
	MIMETypeMarkdown   = "text/markdown"
	MIMETypePNG        = "image/png"
	MIMETypePDF        = "application/pdf"
	MIMETypeSVG        = "image/svg+xml"
)

// injected as placeholder in the interpreter, it's then replaced at runtime
// by a closure that knows how to talk with Jupyter
func stubDisplay(Data) error {
	return errors.New("cannot display: connection with Jupyter not available")
}

// TODO handle the metadata

func read(data interface{}) ([]byte, string) {
	var b []byte
	var s string
	switch x := data.(type) {
	case string:
		s = x
	case []byte:
		b = x
	case io.Reader:
		bb, err := ioutil.ReadAll(x)
		if err != nil {
			panic(err)
		}
		b = bb
	case io.WriterTo:
		var buf bytes.Buffer
		x.WriteTo(&buf)
		b = buf.Bytes()
	default:
		panic(errors.New(fmt.Sprintf("unsupported type, cannot display: expecting string, []byte, io.Reader or io.WriterTo, found %T", data)))
	}
	if len(s) == 0 {
		s = fmt.Sprint(data)
	}
	return b, s
}

func Any(mimeType string, data interface{}) Data {
	b, s := read(data)
	if len(mimeType) == 0 {
		mimeType = http.DetectContentType(b)
	}
	d := Data{
		Data: BundledMIMEData{
			"text/plain": s,
		},
	}
	if mimeType != "text/plain" {
		d.Data[mimeType] = b
	}
	return d
}

func MakeData(mimeType string, data interface{}) Data {
	d := Data{
		Data: BundledMIMEData{
			mimeType: data,
		},
	}
	if mimeType != "text/plain" {
		d.Data["text/plain"] = fmt.Sprint(data)
	}
	return d
}

func MakeData3(mimeType string, plaintext string, data interface{}) Data {
	return Data{
		Data: BundledMIMEData{
			"text/plain": plaintext,
			mimeType:     data,
		},
	}
}

func Bytes(mimeType string, bytes []byte) Data {
	if len(mimeType) == 0 {
		mimeType = http.DetectContentType(bytes)
	}
	return MakeData3(mimeType, mimeType, bytes)
}

func File(mimeType string, path string) Data {
	bytes, err := ioutil.ReadFile(path)
	if err != nil {
		panic(err)
	}
	return Bytes(mimeType, bytes)
}

func HTML(html string) Data {
	return String(MIMETypeHTML, html)
}

func JSON(json map[string]interface{}) Data {
	return MakeData(MIMETypeJSON, json)
}

func JavaScript(javascript string) Data {
	return String(MIMETypeJavaScript, javascript)
}

func JPEG(jpeg []byte) Data {
	return Bytes(MIMETypeJPEG, jpeg)
}

func Latex(latex string) Data {
	return MakeData3(MIMETypeLatex, latex, "$"+strings.Trim(latex, "$")+"$")
}

func Markdown(markdown string) Data {
	return String(MIMETypeMarkdown, markdown)
}

func Math(latex string) Data {
	return MakeData3(MIMETypeLatex, latex, "$$"+strings.Trim(latex, "$")+"$$")
}

func PDF(pdf []byte) Data {
	return Bytes(MIMETypePDF, pdf)
}

func PNG(png []byte) Data {
	return Bytes(MIMETypePNG, png)
}

func Reader(mimeType string, r io.Reader) Data {
	b, err := ioutil.ReadAll(r)
	if err != nil {
		panic(err)
	}
	return Bytes(mimeType, b)
}

func String(mimeType string, s string) Data {
	if len(mimeType) == 0 {
		mimeType = http.DetectContentType([]byte(s))
	}
	return MakeData3(mimeType, s, s)
}

func SVG(svg string) Data {
	return String(MIMETypeSVG, svg)
}

func WriterTo(mimeType string, to io.WriterTo) Data {
	var buf bytes.Buffer
	_, err := to.WriteTo(&buf)
	if err != nil {
		panic(err)
	}
	return Bytes(mimeType, buf.Bytes())
}

// MIME encapsulates the data and metadata into a Data.
// The 'data' map is expected to contain at least one {key,value} pair,
// with value being a string, []byte or some other JSON serializable representation,
// and key equal to the MIME type of such value.
// The exact structure of value is determined by what the frontend expects.
// Some easier-to-use functions for common formats supported by the Jupyter frontend
// are provided by the various functions above.
func MIME(data, metadata map[string]interface{}) Data {
	return Data{data, metadata, nil}
}

// prepare imports.Package for interpreted code
var display = imports.Package{
	Binds: map[string]r.Value{
		"Any":                r.ValueOf(Any),
		"Bytes":              r.ValueOf(Bytes),
		"File":               r.ValueOf(File),
		"HTML":               r.ValueOf(HTML),
		"Image":              r.ValueOf(Image),
		"JPEG":               r.ValueOf(JPEG),
		"JSON":               r.ValueOf(JSON),
		"JavaScript":         r.ValueOf(JavaScript),
		"Latex":              r.ValueOf(Latex),
		"MakeData":           r.ValueOf(MakeData),
		"MakeData3":          r.ValueOf(MakeData3),
		"Markdown":           r.ValueOf(Markdown),
		"Math":               r.ValueOf(Math),
		"MIME":               r.ValueOf(MIME),
		"MIMETypeHTML":       r.ValueOf(MIMETypeHTML),
		"MIMETypeJavaScript": r.ValueOf(MIMETypeJavaScript),
		"MIMETypeJPEG":       r.ValueOf(MIMETypeJPEG),
		"MIMETypeJSON":       r.ValueOf(MIMETypeJSON),
		"MIMETypeLatex":      r.ValueOf(MIMETypeLatex),
		"MIMETypeMarkdown":   r.ValueOf(MIMETypeMarkdown),
		"MIMETypePDF":        r.ValueOf(MIMETypePDF),
		"MIMETypePNG":        r.ValueOf(MIMETypePNG),
		"MIMETypeSVG":        r.ValueOf(MIMETypeSVG),
		"PDF":                r.ValueOf(PDF),
		"PNG":                r.ValueOf(PNG),
		"Reader":             r.ValueOf(Reader),
		"String":             r.ValueOf(String),
		"SVG":                r.ValueOf(SVG),
		"WriterTo":           r.ValueOf(WriterTo),
	},
	Types: map[string]r.Type{
		"BundledMIMEData": r.TypeOf((*BundledMIMEData)(nil)).Elem(),
		"Data":            r.TypeOf((*Data)(nil)).Elem(),
	},
}

// allow importing "display" and "github.com/gopherdata/gophernotes" packages
func init() {
	imports.Packages["display"] = display
	imports.Packages["github.com/gopherdata/gophernotes"] = display
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"sort"
	"strings"
)

func DisplayForceSobjects(sobjects []ForceSobject) {
	names := make([]string, len(sobjects))
	for i, sobject := range sobjects {
		names[i] = sobject["name"].(string)
	}
	sort.Strings(names)
	for _, name := range names {
		fmt.Println(name)
	}
}

func DisplayForceRecords(records []ForceRecord) {
	var keys []string
	if len(records) > 0 {
		for key, _ := range records[0] {
			if key != "attributes" {
				keys = append(keys, key)
			}
		}
		lengths := make([]int, len(keys))
		separators := make([]string, len(keys))
		for i, key := range keys {
			lengths[i] = 0
			for _, record := range records {
				l := len(record[key].(string))
				if l > lengths[i] {
					lengths[i] = l
				}
			}
			separators[i] = strings.Repeat("-", lengths[i]+2)
		}
		formatter_parts := make([]string, len(keys))
		for i, length := range lengths {
			formatter_parts[i] = fmt.Sprintf(" %%-%ds ", length)
		}
		formatter := strings.Join(formatter_parts, "|")
		fmt.Printf(formatter+"\n", StringSliceToInterfaceSlice(keys)...)
		fmt.Printf(strings.Join(separators, "+") + "\n")
		for _, record := range records {
			values := make([]string, len(keys))
			for i, key := range keys {
				values[i] = record[key].(string)
			}
			fmt.Printf(formatter+"\n", StringSliceToInterfaceSlice(values)...)
		}
		fmt.Printf(strings.Join(separators, "+") + "\n")
	}
	fmt.Printf(" (%d records)\n", len(records))
}

func DisplayForceRecord(record ForceRecord) {
	DisplayInterfaceMap(record, 0)
}

func DisplayInterfaceMap(object map[string]interface{}, indent int) {
	keys := make([]string, len(object))
	i := 0
	for key, _ := range object {
		keys[i] = key
		i++
	}
	sort.Strings(keys)
	for _, key := range keys {
		for i := 0; i < indent; i++ {
			fmt.Printf("  ")
		}
		fmt.Printf("%s: ", key)
		switch v := object[key].(type) {
		case map[string]interface{}:
			fmt.Printf("\n")
			DisplayInterfaceMap(v, indent+1)
		default:
			fmt.Printf("%v\n", v)
		}
	}
}

func StringSliceToInterfaceSlice(s []string) (i []interface{}) {
	for _, str := range s {
		i = append(i, interface{}(str))
	}
	return
}

type ForceSobjectFields []interface{}

func DisplayForceSobject(sobject ForceSobject) {
	fields := ForceSobjectFields(sobject["fields"].([]interface{}))
	sort.Sort(fields)
	for _, f := range fields {
		field := f.(map[string]interface{})
		switch field["type"] {
		case "picklist":
			var values []string
			for _, value := range field["picklistValues"].([]interface{}) {
				values = append(values, value.(map[string]interface{})["value"].(string))
			}
			fmt.Printf("%s: %s (%s)\n", field["name"], field["type"], strings.Join(values, ", "))
		case "reference":
			var refs []string
			for _, ref := range field["referenceTo"].([]interface{}) {
				refs = append(refs, ref.(string))
			}
			fmt.Printf("%s: %s (%s)\n", field["name"], field["type"], strings.Join(refs, ", "))
		default:
			fmt.Printf("%s: %s\n", field["name"], field["type"])
		}
	}
}
<commit_msg>fix query output<commit_after>package main

import (
	"fmt"
	"sort"
	"strings"
)

func DisplayForceSobjects(sobjects []ForceSobject) {
	names := make([]string, len(sobjects))
	for i, sobject := range sobjects {
		names[i] = sobject["name"].(string)
	}
	sort.Strings(names)
	for _, name := range names {
		fmt.Println(name)
	}
}

func DisplayForceRecords(records []ForceRecord) {
	var keys []string
	if len(records) > 0 {
		for key, _ := range records[0] {
			if key != "attributes" {
				keys = append(keys, key)
			}
		}
		lengths := make([]int, len(keys))
		separators := make([]string, len(keys))
		for i, key := range keys {
			lengths[i] = len(key)
			for _, record := range records {
				l := len(fmt.Sprintf("%v", record[key]))
				if l > lengths[i] {
					lengths[i] = l
				}
			}
			separators[i] = strings.Repeat("-", lengths[i]+2)
		}
		formatter_parts := make([]string, len(keys))
		for i, length := range lengths {
			formatter_parts[i] = fmt.Sprintf(" %%-%ds ", length)
		}
		formatter := strings.Join(formatter_parts, "|")
		fmt.Printf(formatter+"\n", StringSliceToInterfaceSlice(keys)...)
		fmt.Printf(strings.Join(separators, "+") + "\n")
		for _, record := range records {
			values := make([]string, len(keys))
			for i, key := range keys {
				values[i] = fmt.Sprintf("%v", record[key])
			}
			fmt.Printf(formatter+"\n", StringSliceToInterfaceSlice(values)...)
		}
		fmt.Printf(strings.Join(separators, "+") + "\n")
	}
	fmt.Printf(" (%d records)\n", len(records))
}

func DisplayForceRecord(record ForceRecord) {
	DisplayInterfaceMap(record, 0)
}

func DisplayInterfaceMap(object map[string]interface{}, indent int) {
	keys := make([]string, len(object))
	i := 0
	for key, _ := range object {
		keys[i] = key
		i++
	}
	sort.Strings(keys)
	for _, key := range keys {
		for i := 0; i < indent; i++ {
			fmt.Printf("  ")
		}
		fmt.Printf("%s: ", key)
		switch v := object[key].(type) {
		case map[string]interface{}:
			fmt.Printf("\n")
			DisplayInterfaceMap(v, indent+1)
		default:
			fmt.Printf("%v\n", v)
		}
	}
}

func StringSliceToInterfaceSlice(s []string) (i []interface{}) {
	for _, str := range s {
		i = append(i, interface{}(str))
	}
	return
}

type ForceSobjectFields []interface{}

func DisplayForceSobject(sobject ForceSobject) {
	fields := ForceSobjectFields(sobject["fields"].([]interface{}))
	sort.Sort(fields)
	for _, f := range fields {
		field := f.(map[string]interface{})
		switch field["type"] {
		case "picklist":
			var values []string
			for _, value := range field["picklistValues"].([]interface{}) {
				values = append(values, value.(map[string]interface{})["value"].(string))
			}
			fmt.Printf("%s: %s (%s)\n", field["name"], field["type"], strings.Join(values, ", "))
		case "reference":
			var refs []string
			for _, ref := range field["referenceTo"].([]interface{}) {
				refs = append(refs, ref.(string))
			}
			fmt.Printf("%s: %s (%s)\n", field["name"], field["type"], strings.Join(refs, ", "))
		default:
			fmt.Printf("%s: %s\n", field["name"], field["type"])
		}
	}
}
<|endoftext|>


<commit_before>package smf

import "github.com/gomidi/midi"

// Writer writes midi messages to a standard midi file (SMF)
type Writer interface {
	// Writer is also a midi.Writer that writes midi messages
	midi.Writer

	// SetDelta sets a time distance between the last written and the next midi message in ticks.
	// The meaning of a tick depends on the time format that is set in the header of the SMF file.
	SetDelta(ticks uint32)
}

// Reader reads midi messages from a standard midi file (SMF)
type Reader interface {
	// Reader is also a midi.Reader that reads midi messages
	midi.Reader

	// ReadHeader reads the header of SMF file
	// If it is not called, the first call to Read will implicitely read the header.
	// However to get the header information, ReadHeader must be called (which may also happen after the first message read)
	ReadHeader() (Header, error)

	// Delta returns the time distance between the last read midi message and the message before in ticks.
	// The meaning of a tick depends on the time format that is set in the header of the SMF file.
	Delta() (ticks uint32)

	// Track returns the number of the track of the last read midi message (starting with 0)
	Track() uint16
}

// Header represents the header of a SMF file
type Header interface {
	// Format returns the SMF format (0 = SingleTrack, 1 = MultiTrack, 2 = SequentialTracks)
	Format() Format

	// TimeFormat returns the time format (QuarterNoteTicks or TimeCode) and the value of that format
	TimeFormat() (format TimeFormat, value uint16)

	// NumTracks returns the number of tracks as defined inside the SMF header. It should be the same
	// as the real number of tracks in the file, although there is no guaranty.
	NumTracks() uint16
}

func UnpackTimeCode(raw uint16) (fps, subframes uint8) {
	// bit shifting first byte to second inverting sign
	fps = uint8(int8(byte(raw>>8)) * (-1))

	// taking the second byte
	subframes = byte(raw & uint16(255))
	return
}

const (
	// SingleTrack represents the singletrack SMF format (0)
	SingleTrack = format(0)

	// MultiTrack represents the multitrack SMF format (1)
	MultiTrack = format(1)

	// SequentialTracks represents the sequential track SMF format (2)
	SequentialTracks = format(2)

	// QuarterNoteTicks represents the "ticks per quarter note" (metric) time format
	QuarterNoteTicks = timeformat("QuarterNoteTicks")

	// TimeCode represents the SMTPE/Timecode time formats
	TimeCode = timeformat("TimeCode")
)

// Format is the common interface of all SMF file formats
type Format interface {
	String() string
	Number() uint16
	smfformat() // make the implementation exclusive to this package
}

// TimeFormat is the common interface of all SMF time formats
type TimeFormat interface {
	String() string
	timeformat() // make the implementation exclusive to this package
}

// format is an implementation of Format
type format uint16

func (f format) Number() uint16 {
	return uint16(f)
}

func (f format) smfformat() {}

func (f format) String() string {
	switch f {
	case SingleTrack:
		return "SMF0 (SingleTrack)"
	case MultiTrack:
		return "SMF1 (MultiTrack)"
	case SequentialTracks:
		return "SMF2 (SequentialTracks)"
	}
	panic("unreachable")
}

// timeformat is an implementation of TimeFormat
type timeformat string

func (t timeformat) String() string { return string(t) }
func (t timeformat) timeformat()    {}
<commit_msg>improve documentation for UnpackTimeCode<commit_after>package smf

import "github.com/gomidi/midi"

// Writer writes midi messages to a standard midi file (SMF)
type Writer interface {
	// Writer is also a midi.Writer that writes midi messages
	midi.Writer

	// SetDelta sets a time distance between the last written and the next midi message in ticks.
	// The meaning of a tick depends on the time format that is set in the header of the SMF file.
	SetDelta(ticks uint32)
}

// Reader reads midi messages from a standard midi file (SMF)
type Reader interface {
	// Reader is also a midi.Reader that reads midi messages
	midi.Reader

	// ReadHeader reads the header of SMF file
	// If it is not called, the first call to Read will implicitely read the header.
	// However to get the header information, ReadHeader must be called (which may also happen after the first message read)
	ReadHeader() (Header, error)

	// Delta returns the time distance between the last read midi message and the message before in ticks.
	// The meaning of a tick depends on the time format that is set in the header of the SMF file.
	Delta() (ticks uint32)

	// Track returns the number of the track of the last read midi message (starting with 0)
	Track() uint16
}

// Header represents the header of a SMF file
type Header interface {
	// Format returns the SMF format (0 = SingleTrack, 1 = MultiTrack, 2 = SequentialTracks)
	Format() Format

	// TimeFormat returns the time format (QuarterNoteTicks or TimeCode) and the value of that format
	// If TimeFormat is QuarterNoteTicks, the value is the ticks per quarter note.
	// If TimeFormat is TimeCode, the value is a raw value that must be unpacked with the help of
	// UnpackTimeCode.
	TimeFormat() (format TimeFormat, value uint16)

	// NumTracks returns the number of tracks as defined inside the SMF header. It should be the same
	// as the real number of tracks in the file, although there is no guaranty.
	NumTracks() uint16
}

// UnpackTimeCode unpacks the raw value returned from Header.TimeFormat if the format is TimeCode
// It returns SMPTE frames per second (29 corresponds to 30 drop frame) and the subframes.
func UnpackTimeCode(raw uint16) (fps, subframes uint8) {
	// bit shifting first byte to second inverting sign
	fps = uint8(int8(byte(raw>>8)) * (-1))

	// taking the second byte
	subframes = byte(raw & uint16(255))
	return
}

const (
	// SingleTrack represents the singletrack SMF format (0)
	SingleTrack = format(0)

	// MultiTrack represents the multitrack SMF format (1)
	MultiTrack = format(1)

	// SequentialTracks represents the sequential track SMF format (2)
	SequentialTracks = format(2)

	// QuarterNoteTicks represents the "ticks per quarter note" (metric) time format
	QuarterNoteTicks = timeformat("QuarterNoteTicks")

	// TimeCode represents the SMTPE/Timecode time formats
	TimeCode = timeformat("TimeCode")
)

// Format is the common interface of all SMF file formats
type Format interface {
	String() string
	Number() uint16
	smfformat() // make the implementation exclusive to this package
}

// TimeFormat is the common interface of all SMF time formats
type TimeFormat interface {
	String() string
	timeformat() // make the implementation exclusive to this package
}

// format is an implementation of Format
type format uint16

func (f format) Number() uint16 {
	return uint16(f)
}

func (f format) smfformat() {}

func (f format) String() string {
	switch f {
	case SingleTrack:
		return "SMF0 (SingleTrack)"
	case MultiTrack:
		return "SMF1 (MultiTrack)"
	case SequentialTracks:
		return "SMF2 (SequentialTracks)"
	}
	panic("unreachable")
}

// timeformat is an implementation of TimeFormat
type timeformat string

func (t timeformat) String() string { return string(t) }
func (t timeformat) timeformat()    {}
<|endoftext|>


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

package main

import (
	"bytes"
	"errors"
	"flag"
	"fmt"
	"os"
	"os/exec"
	"path"
	"path/filepath"
	"time"

	"go/build"
)

var (
	do_tests = flag.Bool("test", false, "Run tests (before running program)")
	do_build = flag.Bool("build", false, "Build program")
	ignore   = flag.Bool("nogit", true, "ignore .git directory")
)

func buildpathDir(buildpath string) (string, error) {
	pkg, err := build.Import(buildpath, "", 0)

	if err != nil {
		return "", err
	}

	if pkg.Goroot {
		return "", err
	}

	return pkg.Dir, nil
}

type scanCallback func(path string)

func scanChanges(path string, cb scanCallback) {
	last := time.Now()

	for {
		filepath.Walk(path, func(p string, info os.FileInfo, err error) error {
			if *ignore && info.IsDir() && p == filepath.Join(path, ".git") {
				return filepath.SkipDir
			}

			if info.ModTime().After(last) {
				cb(path)
				last = time.Now()
			}
			return nil
		})

		time.Sleep(500 * time.Millisecond)
	}
}

func log(format string, args ...interface{}) {
	fmt.Printf("[rerun] %s", fmt.Sprintf(format+"\n", args...))
}

func gobuild(buildpath string) (bool, error) {
	cmd := exec.Command("go", "build", "-v", buildpath)

	buf := bytes.NewBuffer([]byte{})
	cmd.Stdout = buf
	cmd.Stderr = buf

	if err := cmd.Run(); err != nil {
		log("build failed")
		fmt.Println(buf.String())
		return false, err
	}

	log("build succeeded")
	return true, nil
}

func goinstall(buildpath string) (bool, error) {
	cmd := exec.Command("go", "get", buildpath)

	buf := bytes.NewBuffer([]byte{})
	cmd.Stdout = buf
	cmd.Stderr = buf

	if err := cmd.Run(); err != nil {
		log("install failed")
		fmt.Println(buf.String())
		return false, err
	}

	log("install succeeded")
	return true, nil
}

func gotest(buildpath string) (bool, error) {
	cmd := exec.Command("go", "test", "-v", buildpath)

	buf := bytes.NewBuffer([]byte{})
	cmd.Stdout = buf
	cmd.Stderr = buf

	if err := cmd.Run(); err != nil {
		log("tests failed")
		fmt.Println(buf.String())
		return false, err
	}

	log("tests passed")
	return true, nil
}

func run(ch chan bool, bin string, args []string) {
	go func() {
		var proc *os.Process

		for relaunch := range ch {
			if proc != nil {
				if err := proc.Signal(os.Interrupt); err != nil {
					proc.Kill()
				}
				proc.Wait()
			}

			if !relaunch {
				continue
			}

			cmd := exec.Command(bin, args...)
			cmd.Stdout = os.Stdout
			cmd.Stderr = os.Stderr

			if err := cmd.Start(); err != nil {
				log("error: %s", err)
			}

			proc = cmd.Process
		}
	}()
	return
}

func refresh(buildpath string, ch chan bool) {
	if *do_tests {
		if ok, _ := gotest(buildpath); !ok {
			ch <- false
			return
		}
	}

	if *do_build {
		if ok, _ := gobuild(buildpath); !ok {
			ch <- false
			return
		}
	}

	if ok, _ := goinstall(buildpath); !ok {
		ch <- false
		return
	}

	ch <- true
	return
}

func rerun(buildpath string, args []string) (err error) {
	pkg, err := build.Import(buildpath, "", 0)
	if err != nil {
		return
	}

	if pkg.Name != "main" {
		err = errors.New(fmt.Sprintf("expected package %q, got %q", "main", pkg.Name))
		return
	}

	_, name := path.Split(buildpath)
	bin := filepath.Join(pkg.BinDir, name)

	ch := make(chan bool)
	go run(ch, bin, args)

	refresh(buildpath, ch)

	dir, err := buildpathDir(buildpath)
	if err != nil {
		return
	}

	scanChanges(dir, func(path string) {
		log("change detected")
		refresh(buildpath, ch)
	})

	return
}

func main() {
	flag.Parse()

	if len(flag.Args()) < 1 {
		fmt.Println("Usage: rerun [--ignore] [--test] [--no-run] [--build] [--race] <import path> [arg]*")
		os.Exit(1)
	}

	if *ignore {
		log("ignoring .git dir")
	}

	buildpath := flag.Args()[0]
	args := flag.Args()[1:]

	if err := rerun(buildpath, args); err != nil {
		log("error: %s", err)
	}
}
<commit_msg>fix usage<commit_after>// Copyright 2013 The rerun AUTHORS. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package main

import (
	"bytes"
	"errors"
	"flag"
	"fmt"
	"os"
	"os/exec"
	"path"
	"path/filepath"
	"time"

	"go/build"
)

var (
	do_tests = flag.Bool("test", false, "Run tests (before running program)")
	do_build = flag.Bool("build", false, "Build program")
	ignore   = flag.Bool("no-git", true, "ignore .git directory")
)

func buildpathDir(buildpath string) (string, error) {
	pkg, err := build.Import(buildpath, "", 0)

	if err != nil {
		return "", err
	}

	if pkg.Goroot {
		return "", err
	}

	return pkg.Dir, nil
}

type scanCallback func(path string)

func scanChanges(path string, cb scanCallback) {
	last := time.Now()

	for {
		filepath.Walk(path, func(p string, info os.FileInfo, err error) error {
			if *ignore && info.IsDir() && p == filepath.Join(path, ".git") {
				return filepath.SkipDir
			}

			if info.ModTime().After(last) {
				cb(path)
				last = time.Now()
			}
			return nil
		})

		time.Sleep(500 * time.Millisecond)
	}
}

func log(format string, args ...interface{}) {
	fmt.Printf("[rerun] %s", fmt.Sprintf(format+"\n", args...))
}

func gobuild(buildpath string) (bool, error) {
	cmd := exec.Command("go", "build", "-v", buildpath)

	buf := bytes.NewBuffer([]byte{})
	cmd.Stdout = buf
	cmd.Stderr = buf

	if err := cmd.Run(); err != nil {
		log("build failed")
		fmt.Println(buf.String())
		return false, err
	}

	log("build succeeded")
	return true, nil
}

func goinstall(buildpath string) (bool, error) {
	cmd := exec.Command("go", "get", buildpath)

	buf := bytes.NewBuffer([]byte{})
	cmd.Stdout = buf
	cmd.Stderr = buf

	if err := cmd.Run(); err != nil {
		log("install failed")
		fmt.Println(buf.String())
		return false, err
	}

	log("install succeeded")
	return true, nil
}

func gotest(buildpath string) (bool, error) {
	cmd := exec.Command("go", "test", "-v", buildpath)

	buf := bytes.NewBuffer([]byte{})
	cmd.Stdout = buf
	cmd.Stderr = buf

	if err := cmd.Run(); err != nil {
		log("tests failed")
		fmt.Println(buf.String())
		return false, err
	}

	log("tests passed")
	return true, nil
}

func run(ch chan bool, bin string, args []string) {
	go func() {
		var proc *os.Process

		for relaunch := range ch {
			if proc != nil {
				if err := proc.Signal(os.Interrupt); err != nil {
					proc.Kill()
				}
				proc.Wait()
			}

			if !relaunch {
				continue
			}

			cmd := exec.Command(bin, args...)
			cmd.Stdout = os.Stdout
			cmd.Stderr = os.Stderr

			if err := cmd.Start(); err != nil {
				log("error: %s", err)
			}

			proc = cmd.Process
		}
	}()
	return
}

func refresh(buildpath string, ch chan bool) {
	if *do_tests {
		if ok, _ := gotest(buildpath); !ok {
			ch <- false
			return
		}
	}

	if *do_build {
		if ok, _ := gobuild(buildpath); !ok {
			ch <- false
			return
		}
	}

	if ok, _ := goinstall(buildpath); !ok {
		ch <- false
		return
	}

	ch <- true
	return
}

func rerun(buildpath string, args []string) (err error) {
	pkg, err := build.Import(buildpath, "", 0)
	if err != nil {
		return
	}

	if pkg.Name != "main" {
		err = errors.New(fmt.Sprintf("expected package %q, got %q", "main", pkg.Name))
		return
	}

	_, name := path.Split(buildpath)
	bin := filepath.Join(pkg.BinDir, name)

	ch := make(chan bool)
	go run(ch, bin, args)

	refresh(buildpath, ch)

	dir, err := buildpathDir(buildpath)
	if err != nil {
		return
	}

	scanChanges(dir, func(path string) {
		log("change detected")
		refresh(buildpath, ch)
	})

	return
}

func main() {
	flag.Parse()

	if len(flag.Args()) < 1 {
		fmt.Println("Usage: rerun [--no-git] [--test] [--no-run] [--build] [--race] <import path> [arg]*")
		os.Exit(1)
	}

	if *ignore {
		log("ignoring .git dir")
	}

	buildpath := flag.Args()[0]
	args := flag.Args()[1:]

	if err := rerun(buildpath, args); err != nil {
		log("error: %s", err)
	}
}
<|endoftext|>


<commit_before>package events

import (
	"fmt"
	"math/rand"
	"sync"
	"sync/atomic"
	"time"

	"github.com/sirupsen/logrus"
)

// RetryingSink retries the write until success or an ErrSinkClosed is
// returned. Underlying sink must have p > 0 of succeeding or the sink will
// block. Retry is configured with a RetryStrategy.  Concurrent calls to a
// retrying sink are serialized through the sink, meaning that if one is
// in-flight, another will not proceed.
type RetryingSink struct {
	sink     Sink
	strategy RetryStrategy
	closed   chan struct{}
	once     sync.Once
}

// NewRetryingSink returns a sink that will retry writes to a sink, backing
// off on failure. Parameters threshold and backoff adjust the behavior of the
// circuit breaker.
func NewRetryingSink(sink Sink, strategy RetryStrategy) *RetryingSink {
	rs := &RetryingSink{
		sink:     sink,
		strategy: strategy,
		closed:   make(chan struct{}),
	}

	return rs
}

// Write attempts to flush the events to the downstream sink until it succeeds
// or the sink is closed.
func (rs *RetryingSink) Write(event Event) error {
	logger := logrus.WithField("event", event)

retry:
	select {
	case <-rs.closed:
		return ErrSinkClosed
	default:
	}

	if backoff := rs.strategy.Proceed(event); backoff > 0 {
		select {
		case <-time.After(backoff):
			// TODO(stevvooe): This branch holds up the next try. Before, we
			// would simply break to the "retry" label and then possibly wait
			// again. However, this requires all retry strategies to have a
			// large probability of probing the sync for success, rather than
			// just backing off and sending the request.
		case <-rs.closed:
			return ErrSinkClosed
		}
	}

	if err := rs.sink.Write(event); err != nil {
		if err == ErrSinkClosed {
			// terminal!
			return err
		}

		logger := logger.WithError(err) // shadow!!

		if rs.strategy.Failure(event, err) {
			logger.Errorf("retryingsink: dropped event")
			return nil
		}

		logger.Errorf("retryingsink: error writing event, retrying")
		goto retry
	}

	rs.strategy.Success(event)
	return nil
}

// Close closes the sink and the underlying sink.
func (rs *RetryingSink) Close() error {
	rs.once.Do(func() {
		close(rs.closed)
	})

	return nil
}

func (rs *RetryingSink) String() string {
	// Serialize a copy of the RetryingSink without the sync.Once, to avoid
	// a data race.
	rs2 := map[string]interface{}{
		"sink":     rs.sink,
		"strategy": rs.strategy,
		"closed":   rs.closed,
	}
	return fmt.Sprint(rs2)
}

// RetryStrategy defines a strategy for retrying event sink writes.
//
// All methods should be goroutine safe.
type RetryStrategy interface {
	// Proceed is called before every event send. If proceed returns a
	// positive, non-zero integer, the retryer will back off by the provided
	// duration.
	//
	// An event is provided, by may be ignored.
	Proceed(event Event) time.Duration

	// Failure reports a failure to the strategy. If this method returns true,
	// the event should be dropped.
	Failure(event Event, err error) bool

	// Success should be called when an event is sent successfully.
	Success(event Event)
}

// Breaker implements a circuit breaker retry strategy.
//
// The current implementation never drops events.
type Breaker struct {
	threshold int
	recent    int
	last      time.Time
	backoff   time.Duration // time after which we retry after failure.
	mu        sync.Mutex
}

var _ RetryStrategy = &Breaker{}

// NewBreaker returns a breaker that will backoff after the threshold has been
// tripped. A Breaker is thread safe and may be shared by many goroutines.
func NewBreaker(threshold int, backoff time.Duration) *Breaker {
	return &Breaker{
		threshold: threshold,
		backoff:   backoff,
	}
}

// Proceed checks the failures against the threshold.
func (b *Breaker) Proceed(event Event) time.Duration {
	b.mu.Lock()
	defer b.mu.Unlock()

	if b.recent < b.threshold {
		return 0
	}

	return b.last.Add(b.backoff).Sub(time.Now())
}

// Success resets the breaker.
func (b *Breaker) Success(event Event) {
	b.mu.Lock()
	defer b.mu.Unlock()

	b.recent = 0
	b.last = time.Time{}
}

// Failure records the failure and latest failure time.
func (b *Breaker) Failure(event Event, err error) bool {
	b.mu.Lock()
	defer b.mu.Unlock()

	b.recent++
	b.last = time.Now().UTC()
	return false // never drop events.
}

var (
	// DefaultExponentialBackoffConfig provides a default configuration for
	// exponential backoff.
	DefaultExponentialBackoffConfig = ExponentialBackoffConfig{
		Base:   time.Second,
		Factor: time.Second,
		Max:    20 * time.Second,
	}
)

// ExponentialBackoffConfig configures backoff parameters.
//
// Note that these parameters operate on the upper bound for choosing a random
// value. For example, at Base=1s, a random value in [0,1s) will be chosen for
// the backoff value.
type ExponentialBackoffConfig struct {
	// Base is the minimum bound for backing off after failure.
	Base time.Duration

	// Factor sets the amount of time by which the backoff grows with each
	// failure.
	Factor time.Duration

	// Max is the absolute maxiumum bound for a single backoff.
	Max time.Duration
}

// ExponentialBackoff implements random backoff with exponentially increasing
// bounds as the number consecutive failures increase.
type ExponentialBackoff struct {
	config   ExponentialBackoffConfig
	failures uint64 // consecutive failure counter.
}

// NewExponentialBackoff returns an exponential backoff strategy with the
// desired config. If config is nil, the default is returned.
func NewExponentialBackoff(config ExponentialBackoffConfig) *ExponentialBackoff {
	return &ExponentialBackoff{
		config: config,
	}
}

// Proceed returns the next randomly bound exponential backoff time.
func (b *ExponentialBackoff) Proceed(event Event) time.Duration {
	return b.backoff(atomic.LoadUint64(&b.failures))
}

// Success resets the failures counter.
func (b *ExponentialBackoff) Success(event Event) {
	atomic.StoreUint64(&b.failures, 0)
}

// Failure increments the failure counter.
func (b *ExponentialBackoff) Failure(event Event, err error) bool {
	atomic.AddUint64(&b.failures, 1)
	return false
}

// backoff calculates the amount of time to wait based on the number of
// consecutive failures.
func (b *ExponentialBackoff) backoff(failures uint64) time.Duration {
	if failures <= 0 {
		// proceed normally when there are no failures.
		return 0
	}

	factor := b.config.Factor
	if factor <= 0 {
		factor = DefaultExponentialBackoffConfig.Factor
	}

	backoff := b.config.Base + factor*time.Duration(1<<(failures-1))

	max := b.config.Max
	if max <= 0 {
		max = DefaultExponentialBackoffConfig.Max
	}

	if backoff > max || backoff < 0 {
		backoff = max
	}

	// Choose a uniformly distributed value from [0, backoff).
	return time.Duration(rand.Int63n(int64(backoff)))
}
<commit_msg>fix alignment for 32bit systems<commit_after>package events

import (
	"fmt"
	"math/rand"
	"sync"
	"sync/atomic"
	"time"

	"github.com/sirupsen/logrus"
)

// RetryingSink retries the write until success or an ErrSinkClosed is
// returned. Underlying sink must have p > 0 of succeeding or the sink will
// block. Retry is configured with a RetryStrategy.  Concurrent calls to a
// retrying sink are serialized through the sink, meaning that if one is
// in-flight, another will not proceed.
type RetryingSink struct {
	sink     Sink
	strategy RetryStrategy
	closed   chan struct{}
	once     sync.Once
}

// NewRetryingSink returns a sink that will retry writes to a sink, backing
// off on failure. Parameters threshold and backoff adjust the behavior of the
// circuit breaker.
func NewRetryingSink(sink Sink, strategy RetryStrategy) *RetryingSink {
	rs := &RetryingSink{
		sink:     sink,
		strategy: strategy,
		closed:   make(chan struct{}),
	}

	return rs
}

// Write attempts to flush the events to the downstream sink until it succeeds
// or the sink is closed.
func (rs *RetryingSink) Write(event Event) error {
	logger := logrus.WithField("event", event)

retry:
	select {
	case <-rs.closed:
		return ErrSinkClosed
	default:
	}

	if backoff := rs.strategy.Proceed(event); backoff > 0 {
		select {
		case <-time.After(backoff):
			// TODO(stevvooe): This branch holds up the next try. Before, we
			// would simply break to the "retry" label and then possibly wait
			// again. However, this requires all retry strategies to have a
			// large probability of probing the sync for success, rather than
			// just backing off and sending the request.
		case <-rs.closed:
			return ErrSinkClosed
		}
	}

	if err := rs.sink.Write(event); err != nil {
		if err == ErrSinkClosed {
			// terminal!
			return err
		}

		logger := logger.WithError(err) // shadow!!

		if rs.strategy.Failure(event, err) {
			logger.Errorf("retryingsink: dropped event")
			return nil
		}

		logger.Errorf("retryingsink: error writing event, retrying")
		goto retry
	}

	rs.strategy.Success(event)
	return nil
}

// Close closes the sink and the underlying sink.
func (rs *RetryingSink) Close() error {
	rs.once.Do(func() {
		close(rs.closed)
	})

	return nil
}

func (rs *RetryingSink) String() string {
	// Serialize a copy of the RetryingSink without the sync.Once, to avoid
	// a data race.
	rs2 := map[string]interface{}{
		"sink":     rs.sink,
		"strategy": rs.strategy,
		"closed":   rs.closed,
	}
	return fmt.Sprint(rs2)
}

// RetryStrategy defines a strategy for retrying event sink writes.
//
// All methods should be goroutine safe.
type RetryStrategy interface {
	// Proceed is called before every event send. If proceed returns a
	// positive, non-zero integer, the retryer will back off by the provided
	// duration.
	//
	// An event is provided, by may be ignored.
	Proceed(event Event) time.Duration

	// Failure reports a failure to the strategy. If this method returns true,
	// the event should be dropped.
	Failure(event Event, err error) bool

	// Success should be called when an event is sent successfully.
	Success(event Event)
}

// Breaker implements a circuit breaker retry strategy.
//
// The current implementation never drops events.
type Breaker struct {
	threshold int
	recent    int
	last      time.Time
	backoff   time.Duration // time after which we retry after failure.
	mu        sync.Mutex
}

var _ RetryStrategy = &Breaker{}

// NewBreaker returns a breaker that will backoff after the threshold has been
// tripped. A Breaker is thread safe and may be shared by many goroutines.
func NewBreaker(threshold int, backoff time.Duration) *Breaker {
	return &Breaker{
		threshold: threshold,
		backoff:   backoff,
	}
}

// Proceed checks the failures against the threshold.
func (b *Breaker) Proceed(event Event) time.Duration {
	b.mu.Lock()
	defer b.mu.Unlock()

	if b.recent < b.threshold {
		return 0
	}

	return b.last.Add(b.backoff).Sub(time.Now())
}

// Success resets the breaker.
func (b *Breaker) Success(event Event) {
	b.mu.Lock()
	defer b.mu.Unlock()

	b.recent = 0
	b.last = time.Time{}
}

// Failure records the failure and latest failure time.
func (b *Breaker) Failure(event Event, err error) bool {
	b.mu.Lock()
	defer b.mu.Unlock()

	b.recent++
	b.last = time.Now().UTC()
	return false // never drop events.
}

var (
	// DefaultExponentialBackoffConfig provides a default configuration for
	// exponential backoff.
	DefaultExponentialBackoffConfig = ExponentialBackoffConfig{
		Base:   time.Second,
		Factor: time.Second,
		Max:    20 * time.Second,
	}
)

// ExponentialBackoffConfig configures backoff parameters.
//
// Note that these parameters operate on the upper bound for choosing a random
// value. For example, at Base=1s, a random value in [0,1s) will be chosen for
// the backoff value.
type ExponentialBackoffConfig struct {
	// Base is the minimum bound for backing off after failure.
	Base time.Duration

	// Factor sets the amount of time by which the backoff grows with each
	// failure.
	Factor time.Duration

	// Max is the absolute maxiumum bound for a single backoff.
	Max time.Duration
}

// ExponentialBackoff implements random backoff with exponentially increasing
// bounds as the number consecutive failures increase.
type ExponentialBackoff struct {
	failures uint64 // consecutive failure counter (needs to be 64-bit aligned)
	config   ExponentialBackoffConfig
}

// NewExponentialBackoff returns an exponential backoff strategy with the
// desired config. If config is nil, the default is returned.
func NewExponentialBackoff(config ExponentialBackoffConfig) *ExponentialBackoff {
	return &ExponentialBackoff{
		config: config,
	}
}

// Proceed returns the next randomly bound exponential backoff time.
func (b *ExponentialBackoff) Proceed(event Event) time.Duration {
	return b.backoff(atomic.LoadUint64(&b.failures))
}

// Success resets the failures counter.
func (b *ExponentialBackoff) Success(event Event) {
	atomic.StoreUint64(&b.failures, 0)
}

// Failure increments the failure counter.
func (b *ExponentialBackoff) Failure(event Event, err error) bool {
	atomic.AddUint64(&b.failures, 1)
	return false
}

// backoff calculates the amount of time to wait based on the number of
// consecutive failures.
func (b *ExponentialBackoff) backoff(failures uint64) time.Duration {
	if failures <= 0 {
		// proceed normally when there are no failures.
		return 0
	}

	factor := b.config.Factor
	if factor <= 0 {
		factor = DefaultExponentialBackoffConfig.Factor
	}

	backoff := b.config.Base + factor*time.Duration(1<<(failures-1))

	max := b.config.Max
	if max <= 0 {
		max = DefaultExponentialBackoffConfig.Max
	}

	if backoff > max || backoff < 0 {
		backoff = max
	}

	// Choose a uniformly distributed value from [0, backoff).
	return time.Duration(rand.Int63n(int64(backoff)))
}
<|endoftext|>


<commit_before>package vagrant

import (
	"fmt"
	"github.com/mitchellh/packer/common"
	"github.com/mitchellh/packer/packer"
	"io/ioutil"
	"log"
	"os"
	"path/filepath"
	"strings"
)

type DigitalOceanBoxConfig struct {
	common.PackerConfig `mapstructure:",squash"`

	OutputPath          string `mapstructure:"output"`
	VagrantfileTemplate string `mapstructure:"vagrantfile_template"`

	tpl *packer.ConfigTemplate
}

type DigitalOceanVagrantfileTemplate struct {
	Image  string ""
	Region string ""
}

type DigitalOceanBoxPostProcessor struct {
	config DigitalOceanBoxConfig
}

func (p *DigitalOceanBoxPostProcessor) Configure(rDigitalOcean ...interface{}) error {
	md, err := common.DecodeConfig(&p.config, rDigitalOcean...)
	if err != nil {
		return err
	}

	p.config.tpl, err = packer.NewConfigTemplate()
	if err != nil {
		return err
	}
	p.config.tpl.UserVars = p.config.PackerUserVars

	// Accumulate any errors
	errs := common.CheckUnusedConfig(md)

	validates := map[string]*string{
		"output":               &p.config.OutputPath,
		"vagrantfile_template": &p.config.VagrantfileTemplate,
	}

	for n, ptr := range validates {
		if err := p.config.tpl.Validate(*ptr); err != nil {
			errs = packer.MultiErrorAppend(
				errs, fmt.Errorf("Error parsing %s: %s", n, err))
		}
	}

	if errs != nil && len(errs.Errors) > 0 {
		return errs
	}

	return nil
}

func (p *DigitalOceanBoxPostProcessor) PostProcess(ui packer.Ui, artifact packer.Artifact) (packer.Artifact, bool, error) {
	// Determine the image and region...
	tplData := &DigitalOceanVagrantfileTemplate{}

	parts := strings.Split(artifact.Id(), ":")
	if len(parts) != 2 {
		return nil, false, fmt.Errorf("Poorly formatted artifact ID: %s", artifact.Id())
	}

	tplData.Region = parts[0]
	tplData.Image = parts[1]

	// Compile the output path
	outputPath, err := p.config.tpl.Process(p.config.OutputPath, &OutputPathTemplate{
		ArtifactId: artifact.Id(),
		BuildName:  p.config.PackerBuildName,
		Provider:   "digitalocean",
	})
	if err != nil {
		return nil, false, err
	}

	// Create a temporary directory for us to build the contents of the box in
	dir, err := ioutil.TempDir("", "packer")
	if err != nil {
		return nil, false, err
	}
	defer os.RemoveAll(dir)

	// Create the Vagrantfile from the template
	vf, err := os.Create(filepath.Join(dir, "Vagrantfile"))
	if err != nil {
		return nil, false, err
	}
	defer vf.Close()

	vagrantfileContents := defaultDigitalOceanVagrantfile
	if p.config.VagrantfileTemplate != "" {
		log.Printf("Using vagrantfile template: %s", p.config.VagrantfileTemplate)
		f, err := os.Open(p.config.VagrantfileTemplate)
		if err != nil {
			err = fmt.Errorf("error opening vagrantfile template: %s", err)
			return nil, false, err
		}
		defer f.Close()

		contents, err := ioutil.ReadAll(f)
		if err != nil {
			err = fmt.Errorf("error reading vagrantfile template: %s", err)
			return nil, false, err
		}

		vagrantfileContents = string(contents)
	}

	vagrantfileContents, err = p.config.tpl.Process(vagrantfileContents, tplData)
	if err != nil {
		return nil, false, fmt.Errorf("Error writing Vagrantfile: %s", err)
	}
	vf.Write([]byte(vagrantfileContents))
	vf.Close()

	// Create the metadata
	metadata := map[string]string{"provider": "digital_ocean"}
	if err := WriteMetadata(dir, metadata); err != nil {
		return nil, false, err
	}

	// Compress the directory to the given output path
	if err := DirToBox(outputPath, dir, ui); err != nil {
		err = fmt.Errorf("error creating box: %s", err)
		return nil, false, err
	}

	return NewArtifact("DigitalOcean", outputPath), true, nil
}

var defaultDigitalOceanVagrantfile = `
Vagrant.configure("2") do |config|
  config.vm.provider :digital_ocean do |digital_ocean|
	digital_ocean.image = "{{ .Image }}"
	digital_ocean.region = "{{ .Region }}"
  end
end

`
<commit_msg>post-processor/vagrant: support compression level for DO<commit_after>package vagrant

import (
	"compress/flate"
	"fmt"
	"github.com/mitchellh/packer/common"
	"github.com/mitchellh/packer/packer"
	"io/ioutil"
	"log"
	"os"
	"path/filepath"
	"strconv"
	"strings"
)

type DigitalOceanBoxConfig struct {
	common.PackerConfig `mapstructure:",squash"`

	OutputPath          string `mapstructure:"output"`
	VagrantfileTemplate string `mapstructure:"vagrantfile_template"`
	CompressionLevel    string `mapstructure:"compression_level"`

	tpl *packer.ConfigTemplate
}

type DigitalOceanVagrantfileTemplate struct {
	Image  string ""
	Region string ""
}

type DigitalOceanBoxPostProcessor struct {
	config DigitalOceanBoxConfig
}

func (p *DigitalOceanBoxPostProcessor) Configure(rDigitalOcean ...interface{}) error {
	md, err := common.DecodeConfig(&p.config, rDigitalOcean...)
	if err != nil {
		return err
	}

	p.config.tpl, err = packer.NewConfigTemplate()
	if err != nil {
		return err
	}
	p.config.tpl.UserVars = p.config.PackerUserVars

	// Accumulate any errors
	errs := common.CheckUnusedConfig(md)

	validates := map[string]*string{
		"output":               &p.config.OutputPath,
		"vagrantfile_template": &p.config.VagrantfileTemplate,
		"compression_level":    &p.config.CompressionLevel,
	}

	for n, ptr := range validates {
		if err := p.config.tpl.Validate(*ptr); err != nil {
			errs = packer.MultiErrorAppend(
				errs, fmt.Errorf("Error parsing %s: %s", n, err))
		}
	}

	if errs != nil && len(errs.Errors) > 0 {
		return errs
	}

	return nil
}

func (p *DigitalOceanBoxPostProcessor) PostProcess(ui packer.Ui, artifact packer.Artifact) (packer.Artifact, bool, error) {
	// Determine the image and region...
	tplData := &DigitalOceanVagrantfileTemplate{}

	parts := strings.Split(artifact.Id(), ":")
	if len(parts) != 2 {
		return nil, false, fmt.Errorf("Poorly formatted artifact ID: %s", artifact.Id())
	}

	tplData.Region = parts[0]
	tplData.Image = parts[1]

	// Compile the output path
	outputPath, err := p.config.tpl.Process(p.config.OutputPath, &OutputPathTemplate{
		ArtifactId: artifact.Id(),
		BuildName:  p.config.PackerBuildName,
		Provider:   "digitalocean",
	})
	if err != nil {
		return nil, false, err
	}

	// Create a temporary directory for us to build the contents of the box in
	dir, err := ioutil.TempDir("", "packer")
	if err != nil {
		return nil, false, err
	}
	defer os.RemoveAll(dir)

	// Create the Vagrantfile from the template
	vf, err := os.Create(filepath.Join(dir, "Vagrantfile"))
	if err != nil {
		return nil, false, err
	}
	defer vf.Close()

	vagrantfileContents := defaultDigitalOceanVagrantfile
	if p.config.VagrantfileTemplate != "" {
		log.Printf("Using vagrantfile template: %s", p.config.VagrantfileTemplate)
		f, err := os.Open(p.config.VagrantfileTemplate)
		if err != nil {
			err = fmt.Errorf("error opening vagrantfile template: %s", err)
			return nil, false, err
		}
		defer f.Close()

		contents, err := ioutil.ReadAll(f)
		if err != nil {
			err = fmt.Errorf("error reading vagrantfile template: %s", err)
			return nil, false, err
		}

		vagrantfileContents = string(contents)
	}

	vagrantfileContents, err = p.config.tpl.Process(vagrantfileContents, tplData)
	if err != nil {
		return nil, false, fmt.Errorf("Error writing Vagrantfile: %s", err)
	}
	vf.Write([]byte(vagrantfileContents))
	vf.Close()

	// Create the metadata
	metadata := map[string]string{"provider": "digital_ocean"}
	if err := WriteMetadata(dir, metadata); err != nil {
		return nil, false, err
	}

	// Compress the directory to the given output path
	var level int = flate.DefaultCompression
	if p.config.CompressionLevel != "" {
		level, err = strconv.Atoi(p.config.CompressionLevel)
		if err != nil {
			return nil, false, err
		}
	}

	if err := DirToBox(outputPath, dir, ui, level); err != nil {
		err = fmt.Errorf("error creating box: %s", err)
		return nil, false, err
	}

	return NewArtifact("DigitalOcean", outputPath), true, nil
}

var defaultDigitalOceanVagrantfile = `
Vagrant.configure("2") do |config|
  config.vm.provider :digital_ocean do |digital_ocean|
	digital_ocean.image = "{{ .Image }}"
	digital_ocean.region = "{{ .Region }}"
  end
end

`
<|endoftext|>


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

// This program is processed by the cover command, and then testAll is called.
// The test driver in main.go can then compare the coverage statistics with expectation.

// The word LINE is replaced by the line number in this file. When the file is executed,
// the coverage processing has changed the line numbers, so we can't use runtime.Caller.

package main

const anything = 1e9 // Just some unlikely value that means "we got here, don't care how often"

func testAll() {
	testSimple()
	testBlockRun()
	testIf()
	testFor()
	testRange()
	testSwitch()
	testTypeSwitch()
	testSelect1()
	testSelect2()
	testEmptySwitches()
}

func testSimple() {
	check(LINE, 1)
}

func testIf() {
	if true {
		check(LINE, 1)
	} else {
		check(LINE, 0)
	}
	if false {
		check(LINE, 0)
	} else {
		check(LINE, 1)
	}
	for i := 0; i < 3; i++ {
		if checkVal(LINE, 3, i) <= 2 {
			check(LINE, 3)
		}
		if checkVal(LINE, 3, i) <= 1 {
			check(LINE, 2)
		}
		if checkVal(LINE, 3, i) <= 0 {
			check(LINE, 1)
		}
	}
	for i := 0; i < 3; i++ {
		if checkVal(LINE, 3, i) <= 1 {
			check(LINE, 2)
		} else {
			check(LINE, 1)
		}
	}
	for i := 0; i < 3; i++ {
		if checkVal(LINE, 3, i) <= 0 {
			check(LINE, 1)
		} else if checkVal(LINE, 2, i) <= 1 {
			check(LINE, 1)
		} else if checkVal(LINE, 1, i) <= 2 {
			check(LINE, 1)
		} else if checkVal(LINE, 0, i) <= 3 {
			check(LINE, 0)
		}
	}
}

func testFor() {
	for i := 0; i < 10; i++ {
		check(LINE, 10)
	}
}

func testRange() {
	for _, f := range []func(){
		func() { check(LINE, 1) },
	} {
		f()
		check(LINE, 1)
	}
}

func testBlockRun() {
	check(LINE, 1)
	{
		check(LINE, 1)
	}
	{
		check(LINE, 1)
	}
	check(LINE, 1)
	{
		check(LINE, 1)
	}
	{
		check(LINE, 1)
	}
	check(LINE, 1)
}

func testSwitch() {
	for i := 0; i < 5; i++ {
		switch i {
		case 0:
			check(LINE, 1)
		case 1:
			check(LINE, 1)
		case 2:
			check(LINE, 1)
		default:
			check(LINE, 2)
		}
	}
}

func testTypeSwitch() {
	var x = []interface{}{1, 2.0, "hi"}
	for _, v := range x {
		switch v.(type) {
		case int:
			check(LINE, 1)
		case float64:
			check(LINE, 1)
		case string:
			check(LINE, 1)
		case complex128:
			check(LINE, 0)
		default:
			check(LINE, 0)
		}
	}
}

func testSelect1() {
	c := make(chan int)
	go func() {
		for i := 0; i < 1000; i++ {
			c <- i
		}
	}()
	for {
		select {
		case <-c:
			check(LINE, anything)
		case <-c:
			check(LINE, anything)
		default:
			check(LINE, 1)
			return
		}
	}
}

func testSelect2() {
	c1 := make(chan int, 1000)
	c2 := make(chan int, 1000)
	for i := 0; i < 1000; i++ {
		c1 <- i
		c2 <- i
	}
	for {
		select {
		case <-c1:
			check(LINE, 1000)
		case <-c2:
			check(LINE, 1000)
		default:
			check(LINE, 1)
			return
		}
	}
}

// Empty control statements created syntax errors. This function
// is here just to be sure that those are handled correctly now.
func testEmptySwitches() {
	check(LINE, 1)
	switch 3 {
	}
	check(LINE, 1)
	switch i := (interface{})(3).(int); i {
	}
	check(LINE, 1)
	go func() {
		check(LINE, 1)
		select {}
	}()
	check(LINE, 1)
}
<commit_msg>cmd/cover: fix race in test<commit_after>// Copyright 2013 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// This program is processed by the cover command, and then testAll is called.
// The test driver in main.go can then compare the coverage statistics with expectation.

// The word LINE is replaced by the line number in this file. When the file is executed,
// the coverage processing has changed the line numbers, so we can't use runtime.Caller.

package main

const anything = 1e9 // Just some unlikely value that means "we got here, don't care how often"

func testAll() {
	testSimple()
	testBlockRun()
	testIf()
	testFor()
	testRange()
	testSwitch()
	testTypeSwitch()
	testSelect1()
	testSelect2()
	testEmptySwitches()
}

func testSimple() {
	check(LINE, 1)
}

func testIf() {
	if true {
		check(LINE, 1)
	} else {
		check(LINE, 0)
	}
	if false {
		check(LINE, 0)
	} else {
		check(LINE, 1)
	}
	for i := 0; i < 3; i++ {
		if checkVal(LINE, 3, i) <= 2 {
			check(LINE, 3)
		}
		if checkVal(LINE, 3, i) <= 1 {
			check(LINE, 2)
		}
		if checkVal(LINE, 3, i) <= 0 {
			check(LINE, 1)
		}
	}
	for i := 0; i < 3; i++ {
		if checkVal(LINE, 3, i) <= 1 {
			check(LINE, 2)
		} else {
			check(LINE, 1)
		}
	}
	for i := 0; i < 3; i++ {
		if checkVal(LINE, 3, i) <= 0 {
			check(LINE, 1)
		} else if checkVal(LINE, 2, i) <= 1 {
			check(LINE, 1)
		} else if checkVal(LINE, 1, i) <= 2 {
			check(LINE, 1)
		} else if checkVal(LINE, 0, i) <= 3 {
			check(LINE, 0)
		}
	}
}

func testFor() {
	for i := 0; i < 10; i++ {
		check(LINE, 10)
	}
}

func testRange() {
	for _, f := range []func(){
		func() { check(LINE, 1) },
	} {
		f()
		check(LINE, 1)
	}
}

func testBlockRun() {
	check(LINE, 1)
	{
		check(LINE, 1)
	}
	{
		check(LINE, 1)
	}
	check(LINE, 1)
	{
		check(LINE, 1)
	}
	{
		check(LINE, 1)
	}
	check(LINE, 1)
}

func testSwitch() {
	for i := 0; i < 5; i++ {
		switch i {
		case 0:
			check(LINE, 1)
		case 1:
			check(LINE, 1)
		case 2:
			check(LINE, 1)
		default:
			check(LINE, 2)
		}
	}
}

func testTypeSwitch() {
	var x = []interface{}{1, 2.0, "hi"}
	for _, v := range x {
		switch v.(type) {
		case int:
			check(LINE, 1)
		case float64:
			check(LINE, 1)
		case string:
			check(LINE, 1)
		case complex128:
			check(LINE, 0)
		default:
			check(LINE, 0)
		}
	}
}

func testSelect1() {
	c := make(chan int)
	go func() {
		for i := 0; i < 1000; i++ {
			c <- i
		}
	}()
	for {
		select {
		case <-c:
			check(LINE, anything)
		case <-c:
			check(LINE, anything)
		default:
			check(LINE, 1)
			return
		}
	}
}

func testSelect2() {
	c1 := make(chan int, 1000)
	c2 := make(chan int, 1000)
	for i := 0; i < 1000; i++ {
		c1 <- i
		c2 <- i
	}
	for {
		select {
		case <-c1:
			check(LINE, 1000)
		case <-c2:
			check(LINE, 1000)
		default:
			check(LINE, 1)
			return
		}
	}
}

// Empty control statements created syntax errors. This function
// is here just to be sure that those are handled correctly now.
func testEmptySwitches() {
	check(LINE, 1)
	switch 3 {
	}
	check(LINE, 1)
	switch i := (interface{})(3).(int); i {
	}
	check(LINE, 1)
	c := make(chan int)
	go func() {
		check(LINE, 1)
		c <- 1
		select {}
	}()
	<-c
	check(LINE, 1)
}
<|endoftext|>