<commit_before>package lzma

import "io"

// opLenMargin provides the upper limit of the number of bytes required
// to encode a single operation.
const opLenMargin = 10

// compressFlags control the compression process.
type compressFlags uint32

// Values for compressFlags.
const (
	// all data should be compresed, even if compression is not
	// optimal.
	all compressFlags = 1 << iota
)

// opFinder enables the support of multiple different OpFinder
// algorithms.
type opFinder interface {
	findOps(e *EncoderDict, r reps, flags compressFlags) []operation
	name() string
}

// EncoderFlags provide the flags for an encoder.
type EncoderFlags uint32

// Flags for the encoder.
const (
	// Requests that an EOSMarker is written.
	EOSMarker EncoderFlags = 1 << iota
)

// Encoder compresses data buffered in the encoder dictionary and writes
// it into a byte writer.
type Encoder struct {
	Dict       *EncoderDict
	State      *State
	writerDict writerDict
	re         *rangeEncoder
	start      int64
	// generate eos marker
	marker   bool
	limit    bool
	opFinder opFinder
	margin   int
}

// NewEncoder creates a new encoder. If the byte writer must be
// limited use LimitedByteWriter provided by this package. The flags
// argument supports the EOSMarker flag, controlling whether a
// termnating end-of-stream marker must be written.
func NewEncoder(bw io.ByteWriter, state *State, dict *EncoderDict,
	flags EncoderFlags) (e *Encoder, err error) {

	re, err := newRangeEncoder(bw)
	if err != nil {
		return nil, err
	}
	e = &Encoder{
		opFinder: greedyFinder{},
		Dict:     dict,
		State:    state,
		re:       re,
		marker:   flags&EOSMarker != 0,
		start:    dict.pos(),
		margin:   opLenMargin,
	}
	if e.marker {
		e.margin += 5
	}
	return e, nil
}

// Write writes the bytes from p into the dictionary. If not enough
// space is available the data in the dictionary buffer will be
// compressed to make additional space available. If the limit of the
// underlying writer has been reached ErrLimit will be returned.
func (e *Encoder) Write(p []byte) (n int, err error) {
	for {
		k, err := e.Dict.write(p[n:])
		n += k
		if err == ErrNoSpace {
			if err = e.compress(0); err != nil {
				return n, err
			}
			continue
		}
		return n, err
	}
}

// Reopen reopens the encoder with a new byte writer.
func (e *Encoder) Reopen(bw io.ByteWriter) error {
	var err error
	if e.re, err = newRangeEncoder(bw); err != nil {
		return err
	}
	e.start = e.Dict.pos()
	e.limit = false
	return nil
}

// writeLiteral writes a literal into the LZMA stream
func (e *Encoder) writeLiteral(l lit) error {
	var err error
	state, state2, _ := e.State.states(e.writerDict.pos())
	if err = e.State.isMatch[state2].Encode(e.re, 0); err != nil {
		return err
	}
	litState := e.State.litState(e.writerDict.byteAt(1), e.writerDict.pos())
	match := e.writerDict.byteAt(int(e.State.rep[0]) + 1)
	err = e.State.litCodec.Encode(e.re, l.b, state, match, litState)
	if err != nil {
		return err
	}
	e.State.updateStateLiteral()
	return nil
}

// iverson implements the Iverson operator as proposed by Donald Knuth in his
// book Concrete Mathematics.
func iverson(ok bool) uint32 {
	if ok {
		return 1
	}
	return 0
}

// writeMatch writes a repetition operation into the operation stream
func (e *Encoder) writeMatch(m match) error {
	var err error
	if !(minDistance <= m.distance && m.distance <= maxDistance) {
		panic("match distance out of range")
	}
	dist := uint32(m.distance - minDistance)
	if !(minMatchLen <= m.n && m.n <= maxMatchLen) &&
		!(dist == e.State.rep[0] && m.n == 1) {
		panic("match length out of range")
	}
	state, state2, posState := e.State.states(e.writerDict.pos())
	if err = e.State.isMatch[state2].Encode(e.re, 1); err != nil {
		return err
	}
	g := 0
	for ; g < 4; g++ {
		if e.State.rep[g] == dist {
			break
		}
	}
	b := iverson(g < 4)
	if err = e.State.isRep[state].Encode(e.re, b); err != nil {
		return err
	}
	n := uint32(m.n - minMatchLen)
	if b == 0 {
		// simple match
		e.State.rep[3], e.State.rep[2], e.State.rep[1], e.State.rep[0] =
			e.State.rep[2], e.State.rep[1], e.State.rep[0], dist
		e.State.updateStateMatch()
		if err = e.State.lenCodec.Encode(e.re, n, posState); err != nil {
			return err
		}
		return e.State.distCodec.Encode(e.re, dist, n)
	}
	b = iverson(g != 0)
	if err = e.State.isRepG0[state].Encode(e.re, b); err != nil {
		return err
	}
	if b == 0 {
		// g == 0
		b = iverson(m.n != 1)
		if err = e.State.isRepG0Long[state2].Encode(e.re, b); err != nil {
			return err
		}
		if b == 0 {
			e.State.updateStateShortRep()
			return nil
		}
	} else {
		// g in {1,2,3}
		b = iverson(g != 1)
		if err = e.State.isRepG1[state].Encode(e.re, b); err != nil {
			return err
		}
		if b == 1 {
			// g in {2,3}
			b = iverson(g != 2)
			err = e.State.isRepG2[state].Encode(e.re, b)
			if err != nil {
				return err
			}
			if b == 1 {
				e.State.rep[3] = e.State.rep[2]
			}
			e.State.rep[2] = e.State.rep[1]
		}
		e.State.rep[1] = e.State.rep[0]
		e.State.rep[0] = dist
	}
	e.State.updateStateRep()
	return e.State.repLenCodec.Encode(e.re, n, posState)
}

// writeOp writes an operation value into the stream. It checks whether there
// is still enough space available using an upper limit for the size required.
func (e *Encoder) writeOp(op operation) error {
	if e.re.Available() < int64(e.margin) {
		return ErrLimit
	}
	var err error
	switch x := op.(type) {
	case match:
		err = e.writeMatch(x)
	case lit:
		err = e.writeLiteral(x)
	}
	if err != nil {
		return err
	}
	_, err = e.writerDict.advance(op.Len())
	return err
}

// compress compressed data from the dictionary buffer. If the flag all
// is set, all data in the dictionay buffer will be compressed. The
// function returns ErrLimit if the underlying writer has reached its
// limit.
func (e *Encoder) compress(flags compressFlags) error {
	if e.limit {
		return ErrLimit
	}
	e.writerDict = e.Dict.writerDict
	ops := e.opFinder.findOps(e.Dict, reps(e.State.rep), flags)
	for _, op := range ops {
		if err := e.writeOp(op); err != nil {
			if err == ErrLimit {
				e.limit = true
			}
			return err
		}
	}
	return nil
}

// eosMatch is a pseudo operation that indicates the end of the stream.
var eosMatch = match{distance: maxDistance, n: minMatchLen}

// Close terminates the LZMA stream. If requested the end-of-stream
// marker will be written. Reaching the writer limit is ignored.
func (e *Encoder) Close() error {
	err := e.compress(all)
	if err != nil && err != ErrLimit {
		return err
	}
	if e.marker {
		if err := e.writeMatch(eosMatch); err != nil {
			return err
		}
	}
	err = e.re.Close()
	return err
}

// Compressed returns the number bytes of the input data that been
// compressed.
func (e *Encoder) Compressed() int64 {
	return e.Dict.pos() - e.start
}
<commit_msg>lzma2: better documentation of the Close behaviour<commit_after>package lzma

import "io"

// opLenMargin provides the upper limit of the number of bytes required
// to encode a single operation.
const opLenMargin = 10

// compressFlags control the compression process.
type compressFlags uint32

// Values for compressFlags.
const (
	// all data should be compresed, even if compression is not
	// optimal.
	all compressFlags = 1 << iota
)

// opFinder enables the support of multiple different OpFinder
// algorithms.
type opFinder interface {
	findOps(e *EncoderDict, r reps, flags compressFlags) []operation
	name() string
}

// EncoderFlags provide the flags for an encoder.
type EncoderFlags uint32

// Flags for the encoder.
const (
	// Requests that an EOSMarker is written.
	EOSMarker EncoderFlags = 1 << iota
)

// Encoder compresses data buffered in the encoder dictionary and writes
// it into a byte writer.
type Encoder struct {
	Dict       *EncoderDict
	State      *State
	writerDict writerDict
	re         *rangeEncoder
	start      int64
	// generate eos marker
	marker   bool
	limit    bool
	opFinder opFinder
	margin   int
}

// NewEncoder creates a new encoder. If the byte writer must be
// limited use LimitedByteWriter provided by this package. The flags
// argument supports the EOSMarker flag, controlling whether a
// termnating end-of-stream marker must be written.
func NewEncoder(bw io.ByteWriter, state *State, dict *EncoderDict,
	flags EncoderFlags) (e *Encoder, err error) {

	re, err := newRangeEncoder(bw)
	if err != nil {
		return nil, err
	}
	e = &Encoder{
		opFinder: greedyFinder{},
		Dict:     dict,
		State:    state,
		re:       re,
		marker:   flags&EOSMarker != 0,
		start:    dict.pos(),
		margin:   opLenMargin,
	}
	if e.marker {
		e.margin += 5
	}
	return e, nil
}

// Write writes the bytes from p into the dictionary. If not enough
// space is available the data in the dictionary buffer will be
// compressed to make additional space available. If the limit of the
// underlying writer has been reached ErrLimit will be returned.
func (e *Encoder) Write(p []byte) (n int, err error) {
	for {
		k, err := e.Dict.write(p[n:])
		n += k
		if err == ErrNoSpace {
			if err = e.compress(0); err != nil {
				return n, err
			}
			continue
		}
		return n, err
	}
}

// Reopen reopens the encoder with a new byte writer.
func (e *Encoder) Reopen(bw io.ByteWriter) error {
	var err error
	if e.re, err = newRangeEncoder(bw); err != nil {
		return err
	}
	e.start = e.Dict.pos()
	e.limit = false
	return nil
}

// writeLiteral writes a literal into the LZMA stream
func (e *Encoder) writeLiteral(l lit) error {
	var err error
	state, state2, _ := e.State.states(e.writerDict.pos())
	if err = e.State.isMatch[state2].Encode(e.re, 0); err != nil {
		return err
	}
	litState := e.State.litState(e.writerDict.byteAt(1), e.writerDict.pos())
	match := e.writerDict.byteAt(int(e.State.rep[0]) + 1)
	err = e.State.litCodec.Encode(e.re, l.b, state, match, litState)
	if err != nil {
		return err
	}
	e.State.updateStateLiteral()
	return nil
}

// iverson implements the Iverson operator as proposed by Donald Knuth in his
// book Concrete Mathematics.
func iverson(ok bool) uint32 {
	if ok {
		return 1
	}
	return 0
}

// writeMatch writes a repetition operation into the operation stream
func (e *Encoder) writeMatch(m match) error {
	var err error
	if !(minDistance <= m.distance && m.distance <= maxDistance) {
		panic("match distance out of range")
	}
	dist := uint32(m.distance - minDistance)
	if !(minMatchLen <= m.n && m.n <= maxMatchLen) &&
		!(dist == e.State.rep[0] && m.n == 1) {
		panic("match length out of range")
	}
	state, state2, posState := e.State.states(e.writerDict.pos())
	if err = e.State.isMatch[state2].Encode(e.re, 1); err != nil {
		return err
	}
	g := 0
	for ; g < 4; g++ {
		if e.State.rep[g] == dist {
			break
		}
	}
	b := iverson(g < 4)
	if err = e.State.isRep[state].Encode(e.re, b); err != nil {
		return err
	}
	n := uint32(m.n - minMatchLen)
	if b == 0 {
		// simple match
		e.State.rep[3], e.State.rep[2], e.State.rep[1], e.State.rep[0] =
			e.State.rep[2], e.State.rep[1], e.State.rep[0], dist
		e.State.updateStateMatch()
		if err = e.State.lenCodec.Encode(e.re, n, posState); err != nil {
			return err
		}
		return e.State.distCodec.Encode(e.re, dist, n)
	}
	b = iverson(g != 0)
	if err = e.State.isRepG0[state].Encode(e.re, b); err != nil {
		return err
	}
	if b == 0 {
		// g == 0
		b = iverson(m.n != 1)
		if err = e.State.isRepG0Long[state2].Encode(e.re, b); err != nil {
			return err
		}
		if b == 0 {
			e.State.updateStateShortRep()
			return nil
		}
	} else {
		// g in {1,2,3}
		b = iverson(g != 1)
		if err = e.State.isRepG1[state].Encode(e.re, b); err != nil {
			return err
		}
		if b == 1 {
			// g in {2,3}
			b = iverson(g != 2)
			err = e.State.isRepG2[state].Encode(e.re, b)
			if err != nil {
				return err
			}
			if b == 1 {
				e.State.rep[3] = e.State.rep[2]
			}
			e.State.rep[2] = e.State.rep[1]
		}
		e.State.rep[1] = e.State.rep[0]
		e.State.rep[0] = dist
	}
	e.State.updateStateRep()
	return e.State.repLenCodec.Encode(e.re, n, posState)
}

// writeOp writes an operation value into the stream. It checks whether there
// is still enough space available using an upper limit for the size required.
func (e *Encoder) writeOp(op operation) error {
	if e.re.Available() < int64(e.margin) {
		return ErrLimit
	}
	var err error
	switch x := op.(type) {
	case match:
		err = e.writeMatch(x)
	case lit:
		err = e.writeLiteral(x)
	}
	if err != nil {
		return err
	}
	_, err = e.writerDict.advance(op.Len())
	return err
}

// compress compressed data from the dictionary buffer. If the flag all
// is set, all data in the dictionay buffer will be compressed. The
// function returns ErrLimit if the underlying writer has reached its
// limit.
func (e *Encoder) compress(flags compressFlags) error {
	if e.limit {
		return ErrLimit
	}
	e.writerDict = e.Dict.writerDict
	ops := e.opFinder.findOps(e.Dict, reps(e.State.rep), flags)
	for _, op := range ops {
		if err := e.writeOp(op); err != nil {
			if err == ErrLimit {
				e.limit = true
			}
			return err
		}
	}
	return nil
}

// eosMatch is a pseudo operation that indicates the end of the stream.
var eosMatch = match{distance: maxDistance, n: minMatchLen}

// Close terminates the LZMA stream. If requested the end-of-stream
// marker will be written. If the byte writer limit has been or will be
// reached during compression of the remaining data in the buffer the
// LZMA stream will be closed and data will remain in the buffer.
func (e *Encoder) Close() error {
	err := e.compress(all)
	if err != nil && err != ErrLimit {
		return err
	}
	if e.marker {
		if err := e.writeMatch(eosMatch); err != nil {
			return err
		}
	}
	err = e.re.Close()
	return err
}

// Compressed returns the number bytes of the input data that been
// compressed.
func (e *Encoder) Compressed() int64 {
	return e.Dict.pos() - e.start
}
<|endoftext|>


<commit_before>package boardgame

import (
	"github.com/jkomoros/boardgame/errors"
	"strconv"
)

//TODO: consider making Deck be an interface again (in some cases it
//might be nice to be able to cast the Deck directly to its underlying type to
//minimize later casts)

//A Deck represents an immutable collection of a certain type of components.
//Every component lives in one deck. 1 or more Stacks index into every Deck,
//and cover every item in the deck, with no items in more than one deck. The
//zero-value of Deck is useful. The Deck will not return items until it has
//been added to a ComponentChest, which helps enforce that Decks' values never
//change. Create a new Deck with NewDeck()
type Deck struct {
	chest *ComponentChest
	//Name is only set when it's added to the component chest.
	name string
	//Components should only ever be added at initalization time. After
	//initalization, Components should be read-only.
	components             []*Component
	shadowValues           SubState
	vendedShadowComponents map[int]*Component
	//TODO: protect shadowComponents cache with mutex to make threadsafe.
}

const genericComponentSentinel = -2

func NewDeck() *Deck {
	return &Deck{
		vendedShadowComponents: make(map[int]*Component),
	}
}

//NewSizedStack returns a new sized stack with the given size based on this
//deck. You normally do this in Empty*State delegate methods, if you aren't
//using the auto-inflating struct tags to configure your stacks.
func (d *Deck) NewSizedStack(size int) *SizedStack {
	return newSizedStack(d, size)
}

//NewGrowableStack returns a new growable stack with the given size based on
//this deck. If the growable stack has no size limit, pass 0 for maxLen. You
//normally do this in Empty*State delegate methods, if you aren't using the
//auto-inflating struct tags to configure your stacks.
func (d *Deck) NewGrowableStack(maxLen int) *GrowableStack {
	return newGrowableStack(d, maxLen)
}

//AddComponent adds a new component with the given values to the next spot in
//the deck. If the deck has already been added to a componentchest, this will
//do nothing.
func (d *Deck) AddComponent(v Reader) {
	if d.chest != nil {
		return
	}

	c := &Component{
		Deck:      d,
		DeckIndex: len(d.components),
		Values:    v,
	}

	d.components = append(d.components, c)
}

//AddComponentMulti is like AddComponent, but creates multiple versions of the
//same component. The exact same ComponentValues will be re-used, which is
//reasonable becasue components are read-only anyway.
func (d *Deck) AddComponentMulti(v Reader, count int) {
	for i := 0; i < count; i++ {
		d.AddComponent(v)
	}
}

//Components returns a list of Components in order in this deck, but only if
//this Deck has already been added to its ComponentChest.
func (d *Deck) Components() []*Component {
	if d.chest == nil {
		return nil
	}
	return d.components
}

//Chest points back to the chest we're part of.
func (d *Deck) Chest() *ComponentChest {
	return d.chest
}

func (d *Deck) Name() string {
	return d.name
}

//ComponentAt returns the component at a given index. It handles empty indexes
//and shadow indexes correctly.
func (d *Deck) ComponentAt(index int) *Component {
	if d.chest == nil {
		return nil
	}
	if index >= len(d.components) {
		return nil
	}
	if index >= 0 {
		return d.components[index]
	}

	//d.ShadowComponent handles all negative indexes correctly, which is what
	//we have.
	return d.ShadowComponent(index)

}

//SetShadowValues sets the SubState to return for every shadow
//component that is returned. May only be set before added to a chest. Should
//generally be the same shape of componentValues as used for other components
//in the deck.
func (d *Deck) SetShadowValues(v SubState) {
	if d.chest != nil {
		return
	}
	d.shadowValues = v
}

//ShadowComponent takes an index that is negative and returns a component that
//is empty but when compared to the result of previous calls to
//ShadowComponent with that index will have equality. This is important for
//sanitized states, where depending on the policy for that property, the stack
//might have its order revealed but not its contents, which requires throwaway
//but stable indexes.
func (d *Deck) ShadowComponent(index int) *Component {
	if index >= 0 {
		return nil
	}
	if index == emptyIndexSentinel {
		return nil
	}

	shadow, ok := d.vendedShadowComponents[index]

	if !ok {
		shadow = &Component{
			Deck:      d,
			DeckIndex: index,
			Values:    d.shadowValues,
		}
		d.vendedShadowComponents[index] = shadow
	}

	return shadow

}

//GenericComponent returns the component that is considereed fully generic for
//this deck. This is the component that every component will be if a Stack is
//sanitized with PolicyLen, for example. If you want to figure out if a Stack
//was sanitized according to that policy, you can compare the component to
//this.
func (d *Deck) GenericComponent() *Component {
	return d.ShadowComponent(genericComponentSentinel)
}

var illegalComponentValuesProps = map[PropertyType]bool{
	TypeEnumVar:       true,
	TypeGrowableStack: true,
	TypeSizedStack:    true,
	TypeTimer:         true,
}

//finish is called when the deck is added to a component chest. It signifies that no more items may be added.
func (d *Deck) finish(chest *ComponentChest, name string) error {

	for i, c := range d.components {
		if c.Values == nil {
			continue
		}
		validator, err := newReaderValidator(c.Values.Reader(), c.Values, illegalComponentValuesProps, chest, false)
		if err != nil {
			return errors.New("Component " + strconv.Itoa(i) + "failed to validate: " + err.Error())
		}
		if err := validator.Valid(c.Values.Reader()); err != nil {
			return errors.New("Component " + strconv.Itoa(i) + " failed to validate: " + err.Error())
		}
	}

	d.chest = chest
	//If a deck has a name, it cannot receive any more items.
	d.name = name
	return nil
}
<commit_msg>ShadowValues on Deck also now returns a Reader. Part of #502.<commit_after>package boardgame

import (
	"github.com/jkomoros/boardgame/errors"
	"strconv"
)

//TODO: consider making Deck be an interface again (in some cases it
//might be nice to be able to cast the Deck directly to its underlying type to
//minimize later casts)

//A Deck represents an immutable collection of a certain type of components.
//Every component lives in one deck. 1 or more Stacks index into every Deck,
//and cover every item in the deck, with no items in more than one deck. The
//zero-value of Deck is useful. The Deck will not return items until it has
//been added to a ComponentChest, which helps enforce that Decks' values never
//change. Create a new Deck with NewDeck()
type Deck struct {
	chest *ComponentChest
	//Name is only set when it's added to the component chest.
	name string
	//Components should only ever be added at initalization time. After
	//initalization, Components should be read-only.
	components             []*Component
	shadowValues           Reader
	vendedShadowComponents map[int]*Component
	//TODO: protect shadowComponents cache with mutex to make threadsafe.
}

const genericComponentSentinel = -2

func NewDeck() *Deck {
	return &Deck{
		vendedShadowComponents: make(map[int]*Component),
	}
}

//NewSizedStack returns a new sized stack with the given size based on this
//deck. You normally do this in Empty*State delegate methods, if you aren't
//using the auto-inflating struct tags to configure your stacks.
func (d *Deck) NewSizedStack(size int) *SizedStack {
	return newSizedStack(d, size)
}

//NewGrowableStack returns a new growable stack with the given size based on
//this deck. If the growable stack has no size limit, pass 0 for maxLen. You
//normally do this in Empty*State delegate methods, if you aren't using the
//auto-inflating struct tags to configure your stacks.
func (d *Deck) NewGrowableStack(maxLen int) *GrowableStack {
	return newGrowableStack(d, maxLen)
}

//AddComponent adds a new component with the given values to the next spot in
//the deck. If the deck has already been added to a componentchest, this will
//do nothing.
func (d *Deck) AddComponent(v Reader) {
	if d.chest != nil {
		return
	}

	c := &Component{
		Deck:      d,
		DeckIndex: len(d.components),
		Values:    v,
	}

	d.components = append(d.components, c)
}

//AddComponentMulti is like AddComponent, but creates multiple versions of the
//same component. The exact same ComponentValues will be re-used, which is
//reasonable becasue components are read-only anyway.
func (d *Deck) AddComponentMulti(v Reader, count int) {
	for i := 0; i < count; i++ {
		d.AddComponent(v)
	}
}

//Components returns a list of Components in order in this deck, but only if
//this Deck has already been added to its ComponentChest.
func (d *Deck) Components() []*Component {
	if d.chest == nil {
		return nil
	}
	return d.components
}

//Chest points back to the chest we're part of.
func (d *Deck) Chest() *ComponentChest {
	return d.chest
}

func (d *Deck) Name() string {
	return d.name
}

//ComponentAt returns the component at a given index. It handles empty indexes
//and shadow indexes correctly.
func (d *Deck) ComponentAt(index int) *Component {
	if d.chest == nil {
		return nil
	}
	if index >= len(d.components) {
		return nil
	}
	if index >= 0 {
		return d.components[index]
	}

	//d.ShadowComponent handles all negative indexes correctly, which is what
	//we have.
	return d.ShadowComponent(index)

}

//SetShadowValues sets the SubState to return for every shadow
//component that is returned. May only be set before added to a chest. Should
//generally be the same shape of componentValues as used for other components
//in the deck.
func (d *Deck) SetShadowValues(v Reader) {
	if d.chest != nil {
		return
	}
	d.shadowValues = v
}

//ShadowComponent takes an index that is negative and returns a component that
//is empty but when compared to the result of previous calls to
//ShadowComponent with that index will have equality. This is important for
//sanitized states, where depending on the policy for that property, the stack
//might have its order revealed but not its contents, which requires throwaway
//but stable indexes.
func (d *Deck) ShadowComponent(index int) *Component {
	if index >= 0 {
		return nil
	}
	if index == emptyIndexSentinel {
		return nil
	}

	shadow, ok := d.vendedShadowComponents[index]

	if !ok {
		shadow = &Component{
			Deck:      d,
			DeckIndex: index,
			Values:    d.shadowValues,
		}
		d.vendedShadowComponents[index] = shadow
	}

	return shadow

}

//GenericComponent returns the component that is considereed fully generic for
//this deck. This is the component that every component will be if a Stack is
//sanitized with PolicyLen, for example. If you want to figure out if a Stack
//was sanitized according to that policy, you can compare the component to
//this.
func (d *Deck) GenericComponent() *Component {
	return d.ShadowComponent(genericComponentSentinel)
}

var illegalComponentValuesProps = map[PropertyType]bool{
	TypeEnumVar:       true,
	TypeGrowableStack: true,
	TypeSizedStack:    true,
	TypeTimer:         true,
}

//finish is called when the deck is added to a component chest. It signifies that no more items may be added.
func (d *Deck) finish(chest *ComponentChest, name string) error {

	for i, c := range d.components {
		if c.Values == nil {
			continue
		}
		validator, err := newReaderValidator(c.Values.Reader(), c.Values, illegalComponentValuesProps, chest, false)
		if err != nil {
			return errors.New("Component " + strconv.Itoa(i) + "failed to validate: " + err.Error())
		}
		if err := validator.Valid(c.Values.Reader()); err != nil {
			return errors.New("Component " + strconv.Itoa(i) + " failed to validate: " + err.Error())
		}
	}

	d.chest = chest
	//If a deck has a name, it cannot receive any more items.
	d.name = name
	return nil
}
<|endoftext|>


<commit_before>package boardgame

import (
	"github.com/workfit/tester/assert"
	"strings"
	"testing"
)

func newTestGameChest() *ComponentChest {
	chest := NewComponentChest()

	deck := NewDeck()

	deck.AddComponent(&testingComponent{
		"foo",
		1,
	})

	deck.AddComponent(&testingComponent{
		"bar",
		2,
	})

	deck.AddComponent(&testingComponent{
		"baz",
		5,
	})

	deck.AddComponent(&testingComponent{
		"slam",
		10,
	})

	deck.SetShadowValues(&testShadowValues{
		Message: "Foo",
	})

	chest.AddDeck("test", deck)

	chest.Finish()

	return chest
}

func newTestGameManger() *GameManager {
	manager := NewGameManager(&testGameDelegate{}, newTestGameChest(), newTestStorageManager())

	manager.AddAgent(&testAgent{})

	manager.AddPlayerMove(&testMove{})
	manager.AddFixUpMove(&testMoveAdvanceCurentPlayer{DefaultMove{
		"Advance Current Player",
		"Advances to the next player when the current player has no more legal moves they can make this turn.",
	}})
	manager.AddFixUpMove(&testMoveInvalidPlayerIndex{})
	manager.AddPlayerMove(&testMoveIncrementCardInHand{})
	manager.AddPlayerMove(&testMoveDrawCard{})

	return manager
}

type nilStackGameDelegate struct {
	testGameDelegate
	//We wil always return a player state that has nil. But if this is false, we will also return one for game.
	nilForPlayer bool
}

func (n *nilStackGameDelegate) EmptyPlayerState(playe PlayerIndex) MutablePlayerState {
	return &testPlayerState{}
}

func (n *nilStackGameDelegate) EmptyGameState() MutableGameState {
	if n.nilForPlayer {
		//return a non-nil one.
		return n.testGameDelegate.EmptyGameState()
	}

	return &testGameState{}
}

func TestDefaultMove(t *testing.T) {
	//Tests that Moves based on DefaultMove copy correctly

	game := testGame()

	game.SetUp(0, nil)

	//FixUpMoveByName calls Copy under the covers.
	move := game.FixUpMoveByName("Advance Current Player")

	assert.For(t).ThatActual(move).IsNotNil()

	assert.For(t).ThatActualString(move.Name()).Equals("Advance Current Player")
}

func TestNilStackErrors(t *testing.T) {
	manager := NewGameManager(&nilStackGameDelegate{}, newTestGameChest(), newTestStorageManager())

	if err := manager.SetUp(); err != nil {
		t.Fatal("Couldn't set up nilStackGameDelegate-based manager")
	}

	game := NewGame(manager)

	if game == nil {
		t.Error("No game provided from new game")
	}

	if err := game.SetUp(0, nil); err == nil {
		t.Error("Didn't get error when setting up with an empty game state with nil stacks")
	}

	//Switch so gameState is valid, but playerState is still not, so we can
	//make sure we do the same test for playerStates.
	manager.delegate.(*nilStackGameDelegate).nilForPlayer = true

	if err := game.SetUp(0, nil); err == nil {
		t.Error("Didn't get an error when given an empty player state with nil stacks")
	}

}

func TestMisshappenComputedProperties(t *testing.T) {
	delegate := &stateComputeDelegate{
		config: &ComputedPropertiesConfig{
			Global: map[string]ComputedGlobalPropertyDefinition{
				"ThisPropertyIsNotSupported": ComputedGlobalPropertyDefinition{
					Dependencies: []StatePropertyRef{},
					PropType:     TypeGrowableStack,
					Compute: func(state State) (interface{}, error) {
						return nil, nil
					},
				},
			},
		},
		returnDefaultCollection: true,
	}

	manager := NewGameManager(delegate, newTestGameChest(), newTestStorageManager())

	if manager.SetUp() == nil {
		t.Error("We had a misshapen config object but didn't get an error at setup")
	}
}

func TestGameManagerModifiableGame(t *testing.T) {
	game := testGame()

	game.SetUp(0, nil)

	manager := game.Manager()

	//use ToLower to verify that ID comparison is not case sensitive.
	otherGame := manager.ModifiableGame(strings.ToLower(game.Id()))

	if game != otherGame {
		t.Error("ModifiableGame didn't give back the same game that already existed")
	}

	//OK, forget about the real game to test us making a new one.
	manager.modifiableGames = make(map[string]*Game)

	otherGame = manager.ModifiableGame(game.Id())

	if otherGame == nil {
		t.Error("Other game didn't return anything even though it was in storage!")
	}

	if game == otherGame {
		t.Error("ModifiableGame didn't grab a game from storage fresh")
	}

	otherGame = manager.ModifiableGame("NOGAMEATTHISID")

	if otherGame != nil {
		t.Error("ModifiableGame returned a game even for an invalid ID")
	}

}

func TestGameManagerSetUp(t *testing.T) {

	manager := newTestGameManger()

	if manager.PlayerMoves() != nil {
		t.Error("Got moves back before SetUp was called")
	}

	if manager.PlayerMoveByName("Test") != nil {
		t.Error("Move by name returned a move before SetUp was called")
	}

	if manager.Agents() != nil {
		t.Error("Agent before setup was not nil")
	}

	if manager.AgentByName("Test") != nil {
		t.Error("Agent test before setup was not nil")
	}

	manager.SetUp()

	moves := manager.PlayerMoves()

	if moves == nil {
		t.Error("Got nil player moves even after setting up")
	}

	for i := 0; i < len(moves); i++ {
		if moves[i] == manager.playerMoves[i] {
			t.Error("PlayerMoves didn't return a copy; got same item at", i)
		}
	}

	if manager.Agents() == nil {
		t.Error("Agents after setup was nil")
	}

	if manager.AgentByName("test") == nil {
		t.Error("Agent test after setup was nil")
	}

	if manager.PlayerMoveByName("Test") == nil {
		t.Error("MoveByName didn't return a valid move when provided the proper name after calling setup")
	}

	if manager.PlayerMoveByName("test") == nil {
		t.Error("MoveByName didn't return a valid move when provided with a lowercase name after calling SetUp.")
	}

}
<commit_msg>Strengthened the TestDefaultMove test a bit.<commit_after>package boardgame

import (
	"github.com/workfit/tester/assert"
	"strings"
	"testing"
)

func newTestGameChest() *ComponentChest {
	chest := NewComponentChest()

	deck := NewDeck()

	deck.AddComponent(&testingComponent{
		"foo",
		1,
	})

	deck.AddComponent(&testingComponent{
		"bar",
		2,
	})

	deck.AddComponent(&testingComponent{
		"baz",
		5,
	})

	deck.AddComponent(&testingComponent{
		"slam",
		10,
	})

	deck.SetShadowValues(&testShadowValues{
		Message: "Foo",
	})

	chest.AddDeck("test", deck)

	chest.Finish()

	return chest
}

func newTestGameManger() *GameManager {
	manager := NewGameManager(&testGameDelegate{}, newTestGameChest(), newTestStorageManager())

	manager.AddAgent(&testAgent{})

	manager.AddPlayerMove(&testMove{})
	manager.AddFixUpMove(&testMoveAdvanceCurentPlayer{DefaultMove{
		"Advance Current Player",
		"Advances to the next player when the current player has no more legal moves they can make this turn.",
	}})
	manager.AddFixUpMove(&testMoveInvalidPlayerIndex{})
	manager.AddPlayerMove(&testMoveIncrementCardInHand{})
	manager.AddPlayerMove(&testMoveDrawCard{})

	return manager
}

type nilStackGameDelegate struct {
	testGameDelegate
	//We wil always return a player state that has nil. But if this is false, we will also return one for game.
	nilForPlayer bool
}

func (n *nilStackGameDelegate) EmptyPlayerState(playe PlayerIndex) MutablePlayerState {
	return &testPlayerState{}
}

func (n *nilStackGameDelegate) EmptyGameState() MutableGameState {
	if n.nilForPlayer {
		//return a non-nil one.
		return n.testGameDelegate.EmptyGameState()
	}

	return &testGameState{}
}

func TestDefaultMove(t *testing.T) {
	//Tests that Moves based on DefaultMove copy correctly

	game := testGame()

	game.SetUp(0, nil)

	//FixUpMoveByName calls Copy under the covers.
	move := game.FixUpMoveByName("Advance Current Player")

	assert.For(t).ThatActual(move).IsNotNil()

	assert.For(t).ThatActualString(move.Name()).Equals("Advance Current Player")

	convertedMove, ok := move.(*testMoveAdvanceCurentPlayer)

	assert.For(t).ThatActual(ok).Equals(true)
	assert.For(t).ThatActual(convertedMove).IsNotNil()
}

func TestNilStackErrors(t *testing.T) {
	manager := NewGameManager(&nilStackGameDelegate{}, newTestGameChest(), newTestStorageManager())

	if err := manager.SetUp(); err != nil {
		t.Fatal("Couldn't set up nilStackGameDelegate-based manager")
	}

	game := NewGame(manager)

	if game == nil {
		t.Error("No game provided from new game")
	}

	if err := game.SetUp(0, nil); err == nil {
		t.Error("Didn't get error when setting up with an empty game state with nil stacks")
	}

	//Switch so gameState is valid, but playerState is still not, so we can
	//make sure we do the same test for playerStates.
	manager.delegate.(*nilStackGameDelegate).nilForPlayer = true

	if err := game.SetUp(0, nil); err == nil {
		t.Error("Didn't get an error when given an empty player state with nil stacks")
	}

}

func TestMisshappenComputedProperties(t *testing.T) {
	delegate := &stateComputeDelegate{
		config: &ComputedPropertiesConfig{
			Global: map[string]ComputedGlobalPropertyDefinition{
				"ThisPropertyIsNotSupported": ComputedGlobalPropertyDefinition{
					Dependencies: []StatePropertyRef{},
					PropType:     TypeGrowableStack,
					Compute: func(state State) (interface{}, error) {
						return nil, nil
					},
				},
			},
		},
		returnDefaultCollection: true,
	}

	manager := NewGameManager(delegate, newTestGameChest(), newTestStorageManager())

	if manager.SetUp() == nil {
		t.Error("We had a misshapen config object but didn't get an error at setup")
	}
}

func TestGameManagerModifiableGame(t *testing.T) {
	game := testGame()

	game.SetUp(0, nil)

	manager := game.Manager()

	//use ToLower to verify that ID comparison is not case sensitive.
	otherGame := manager.ModifiableGame(strings.ToLower(game.Id()))

	if game != otherGame {
		t.Error("ModifiableGame didn't give back the same game that already existed")
	}

	//OK, forget about the real game to test us making a new one.
	manager.modifiableGames = make(map[string]*Game)

	otherGame = manager.ModifiableGame(game.Id())

	if otherGame == nil {
		t.Error("Other game didn't return anything even though it was in storage!")
	}

	if game == otherGame {
		t.Error("ModifiableGame didn't grab a game from storage fresh")
	}

	otherGame = manager.ModifiableGame("NOGAMEATTHISID")

	if otherGame != nil {
		t.Error("ModifiableGame returned a game even for an invalid ID")
	}

}

func TestGameManagerSetUp(t *testing.T) {

	manager := newTestGameManger()

	if manager.PlayerMoves() != nil {
		t.Error("Got moves back before SetUp was called")
	}

	if manager.PlayerMoveByName("Test") != nil {
		t.Error("Move by name returned a move before SetUp was called")
	}

	if manager.Agents() != nil {
		t.Error("Agent before setup was not nil")
	}

	if manager.AgentByName("Test") != nil {
		t.Error("Agent test before setup was not nil")
	}

	manager.SetUp()

	moves := manager.PlayerMoves()

	if moves == nil {
		t.Error("Got nil player moves even after setting up")
	}

	for i := 0; i < len(moves); i++ {
		if moves[i] == manager.playerMoves[i] {
			t.Error("PlayerMoves didn't return a copy; got same item at", i)
		}
	}

	if manager.Agents() == nil {
		t.Error("Agents after setup was nil")
	}

	if manager.AgentByName("test") == nil {
		t.Error("Agent test after setup was nil")
	}

	if manager.PlayerMoveByName("Test") == nil {
		t.Error("MoveByName didn't return a valid move when provided the proper name after calling setup")
	}

	if manager.PlayerMoveByName("test") == nil {
		t.Error("MoveByName didn't return a valid move when provided with a lowercase name after calling SetUp.")
	}

}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"os"
	"runtime"
	"time"

	"github.com/miketheprogrammer/thrust-go/commands"
	. "github.com/miketheprogrammer/thrust-go/common"
	"github.com/miketheprogrammer/thrust-go/connection"
	"github.com/miketheprogrammer/thrust-go/dispatcher"
	"github.com/miketheprogrammer/thrust-go/menu"
	"github.com/miketheprogrammer/thrust-go/spawn"
	"github.com/miketheprogrammer/thrust-go/window"
)

func main() {
	addr := flag.String("socket", "", "unix socket where thrust is running")
	autoloaderDisabled := flag.Bool("disable-auto-loader", false, "disable auto running of thrust")

	// Parses Flags
	InitLogger()

	if len(*addr) == 0 {
		Log.Errorf("System cannot proceed without a socket to connect to. please use -socket={socket_addr}")
		os.Exit(2)
	}

	spawn.SpawnThrustCore(*addr, *autoloaderDisabled)

	err := connection.InitializeThreads("unix", *addr)
	if err != nil {
		fmt.Println(err)
		os.Exit(2)
	}
	out, in := connection.GetCommunicationChannels()

	thrustWindow := window.Window{}
	rootMenu := menu.Menu{}
	fileMenu := menu.Menu{}
	checkList := menu.Menu{}
	radioList := menu.Menu{}
	viewMenu := menu.Menu{}
	// Calls to other methods after create are Queued until Create returns
	thrustWindow.Create(in)
	thrustWindow.Show()

	rootMenu.Create(in)
	rootMenu.AddItem(2, "Root")

	fileMenu.Create(in)
	fileMenu.AddItem(3, "Open")
	fileMenu.AddItem(4, "Close")
	fileMenu.AddSeparator()

	checkList.Create(in)
	checkList.AddCheckItem(5, "Check 1")
	checkList.SetChecked(5, true)
	checkList.AddSeparator()
	checkList.AddCheckItem(6, "Check 2")
	checkList.SetChecked(6, true)
	checkList.SetEnabled(6, false)

	radioList.Create(in)
	radioList.AddRadioItem(7, "Radio 1-1", 1)
	radioList.AddRadioItem(8, "Radio 1-2", 1)
	radioList.AddSeparator()
	radioList.AddRadioItem(9, "Radio 2-1", 2)
	radioList.AddRadioItem(10, "Radio 2-2", 2)
	radioList.AddRadioItem(11, "Radio 2-3", 2)
	radioList.SetVisible(11, false)

	fileMenu.AddSubmenu(11, "CheckList", &checkList)
	fileMenu.AddSubmenu(12, "RadioList", &radioList)

	viewMenu.Create(in)
	layoutMenu := menu.Menu{}
	layoutMenu.Create(in)
	layoutStyleMenu := menu.Menu{}
	layoutStyleMenu.Create(in)
	layoutStyleMenu.AddRadioItem(13, "Horizontal", 3)
	layoutStyleMenu.AddRadioItem(14, "Vertical", 3)

	layoutMenu.AddSubmenu(15, "Styles", &layoutStyleMenu)
	viewMenu.AddSubmenu(16, "Layouts", &layoutMenu)
	rootMenu.AddSubmenu(17, "File", &fileMenu)
	rootMenu.AddSubmenu(18, "View", &viewMenu)

	if runtime.GOOS == "darwin" {
		rootMenu.SetApplicationMenu()
	} else {
		rootMenu.Attach(&thrustWindow)
	}

	thrustWindow.Maximize()

	dispatcher.RegisterHandler(func(c commands.CommandResponse) {
		thrustWindow.DispatchResponse(c)
	})

	dispatcher.RegisterHandler(func(c commands.CommandResponse) {
		rootMenu.DispatchResponse(c)
	})
	for {
		select {
		case response := <-out.CommandResponses:
			dispatcher.Dispatch(response)
			if len(fileMenu.WaitingResponses) > 0 {
				fileMenu.PrintRecursiveWaitingResponses()
			}
		default:
			break
		}
		time.Sleep(time.Microsecond * 10)

	}

}
<commit_msg>quick fix<commit_after>package main

import (
	"flag"
	"fmt"
	"os"
	"runtime"
	"time"

	"github.com/miketheprogrammer/thrust-go/commands"
	. "github.com/miketheprogrammer/thrust-go/common"
	"github.com/miketheprogrammer/thrust-go/connection"
	"github.com/miketheprogrammer/thrust-go/dispatcher"
	"github.com/miketheprogrammer/thrust-go/menu"
	"github.com/miketheprogrammer/thrust-go/spawn"
	"github.com/miketheprogrammer/thrust-go/window"
)

func main() {
	addr := flag.String("socket", "", "unix socket where thrust is running")
	autoloaderDisabled := flag.Bool("disable-auto-loader", false, "disable auto running of thrust")

	// Parses Flags
	InitLogger()

	if len(*addr) == 0 {
		Log.Errorf("System cannot proceed without a socket to connect to. please use -socket={socket_addr}")
		os.Exit(2)
	}

	spawn.SpawnThrustCore(*addr, *autoloaderDisabled)

	err := connection.InitializeThreads("unix", *addr)
	if err != nil {
		fmt.Println(err)
		os.Exit(2)
	}
	out, in := connection.GetCommunicationChannels()

	thrustWindow := window.Window{}
	rootMenu := menu.Menu{}
	fileMenu := menu.Menu{}
	checkList := menu.Menu{}
	radioList := menu.Menu{}
	viewMenu := menu.Menu{}
	// Calls to other methods after create are Queued until Create returns
	thrustWindow.Create(in)
	thrustWindow.Show()

	rootMenu.Create(in)
	rootMenu.AddItem(2, "Root")

	fileMenu.Create(in)
	fileMenu.AddItem(3, "Open")
	fileMenu.AddItem(4, "Close")
	fileMenu.AddSeparator()

	checkList.Create(in)
	checkList.AddCheckItem(5, "Check 1")
	checkList.SetChecked(5, true)
	checkList.AddSeparator()
	checkList.AddCheckItem(6, "Check 2")
	checkList.SetChecked(6, true)
	checkList.SetEnabled(6, false)

	radioList.Create(in)
	radioList.AddRadioItem(7, "Radio 1-1", 1)
	radioList.AddRadioItem(8, "Radio 1-2", 1)
	radioList.AddSeparator()
	radioList.AddRadioItem(9, "Radio 2-1", 2)
	radioList.AddRadioItem(10, "Radio 2-2", 2)
	radioList.AddRadioItem(11, "Radio 2-3", 2)
	radioList.SetVisible(11, false)

	fileMenu.AddSubmenu(11, "CheckList", &checkList)
	fileMenu.AddSubmenu(12, "RadioList", &radioList)

	viewMenu.Create(in)
	layoutMenu := menu.Menu{}
	layoutMenu.Create(in)
	layoutStyleMenu := menu.Menu{}
	layoutStyleMenu.Create(in)
	layoutStyleMenu.AddRadioItem(13, "Horizontal", 3)
	layoutStyleMenu.AddRadioItem(14, "Vertical", 3)

	layoutMenu.AddSubmenu(15, "Styles", &layoutStyleMenu)
	viewMenu.AddSubmenu(16, "Layouts", &layoutMenu)
	rootMenu.AddSubmenu(17, "File", &fileMenu)
	rootMenu.AddSubmenu(18, "View", &viewMenu)

	if runtime.GOOS == "darwin" {
		rootMenu.SetApplicationMenu()
	} else {
		rootMenu.AttachToWindow(&thrustWindow)
	}

	thrustWindow.Maximize()

	dispatcher.RegisterHandler(func(c commands.CommandResponse) {
		thrustWindow.DispatchResponse(c)
	})

	dispatcher.RegisterHandler(func(c commands.CommandResponse) {
		rootMenu.DispatchResponse(c)
	})
	for {
		select {
		case response := <-out.CommandResponses:
			dispatcher.Dispatch(response)
			if len(fileMenu.WaitingResponses) > 0 {
				fileMenu.PrintRecursiveWaitingResponses()
			}
		default:
			break
		}
		time.Sleep(time.Microsecond * 10)

	}

}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"encoding/json"
	"github.com/darkhelmet/env"
	"github.com/stretchr/testify/assert"
	"github.com/zenazn/goji"
	"io"
	"io/ioutil"
	"log"
	"net/http"
	"net/http/httptest"
	"strings"
	"testing"
	"time"
)

func init() {
	log.SetOutput(ioutil.Discard)
	if !strings.HasSuffix(env.String("DATABASE_URL"), "-test") {
		panic("Doesn't look like a test database")
	}
	dataStart()
	webBuild()
}

func clear() {
	_, err := dataConn.Exec("DELETE from dbs")
	must(err)
	_, err = dataConn.Exec("DELETE from pins")
	must(err)
}

func mustRequest(method, url string, body io.Reader) *httptest.ResponseRecorder {
	req, err := http.NewRequest(method, url, body)
	must(err)
	res := httptest.NewRecorder()
	goji.DefaultMux.ServeHTTP(res, req)
	return res
}

func TestStatus(t *testing.T) {
	res := mustRequest("GET", "/status", nil)
	assert.Equal(t, 200, res.Code)
	status := &status{}
	must(json.NewDecoder(res.Body).Decode(status))
	assert.Equal(t, "ok", status.Message)
}

func TestDbAdd(t *testing.T) {
	defer clear()
	b := bytes.NewReader([]byte(`{"name": "pins-1", "url": "postgres://u:p@h:1234/d-1"}`))
	res := mustRequest("POST", "/dbs", b)
	assert.Equal(t, 201, res.Code)
	db := &db{}
	must(json.NewDecoder(res.Body).Decode(db))
	assert.Equal(t, "pins-1", db.Name)
	assert.Equal(t, "postgres://u:p@h:1234/d-1", db.Url)
	assert.NotEmpty(t, db.Id)
	assert.WithinDuration(t, time.Now(), db.AddedAt, 3*time.Second)
}

func TestDbGet(t *testing.T) {
	defer clear()
	dbIn, err := dataDbAdd("pins-1", "postgres://u:p@h:1234/d-1")
	must(err)
	res := mustRequest("GET", "/dbs/"+dbIn.Id, nil)
	assert.Equal(t, 200, res.Code)
	dbOut := &db{}
	must(json.NewDecoder(res.Body).Decode(dbOut))
	assert.Equal(t, dbIn.Id, dbOut.Id)
	assert.Equal(t, "pins-1", dbOut.Name)
	assert.Equal(t, "postgres://u:p@h:1234/d-1", dbOut.Url)
	assert.WithinDuration(t, time.Now(), dbOut.AddedAt, 3*time.Second)
}

func TestDbRemove(t *testing.T) {
	defer clear()
	dbIn, err := dataDbAdd("pins-1", "postgres://u:p@h:1234/d-1")
	must(err)
	res := mustRequest("DELETE", "/dbs/"+dbIn.Id, nil)
	assert.Equal(t, 200, res.Code)
	res = mustRequest("GET", "/dbs/"+dbIn.Id, nil)
	assert.Equal(t, 404, res.Code)
}

func TestDbListBasic(t *testing.T) {
	defer clear()
	dbIn, err := dataDbAdd("pins-1", "postgres://u:p@h:1234/d-1")
	must(err)
	res := mustRequest("GET", "/dbs", nil)
	assert.Equal(t, 200, res.Code)
	dbsOut := []*db{}
	must(json.NewDecoder(res.Body).Decode(&dbsOut))
	assert.Equal(t, len(dbsOut), 1)
	assert.Equal(t, dbIn.Id, dbsOut[0].Id)
	assert.Equal(t, "pins-1", dbsOut[0].Name)
}

func TestDBListDeletions(t *testing.T) {
	defer clear()
	dbIn1, err := dataDbAdd("pins-1", "postgres://u:p@h:1234/d-1")
	must(err)
	dbIn2, err := dataDbAdd("pins-2", "postgres://u:p@h:1234/d-2")
	must(err)
	_, err = dataDbRemove(dbIn2.Id)
	must(err)
	res := mustRequest("GET", "/dbs", nil)
	assert.Equal(t, 200, res.Code)
	dbsOut := []*db{}
	must(json.NewDecoder(res.Body).Decode(&dbsOut))
	assert.Equal(t, len(dbsOut), 1)
	assert.Equal(t, dbIn1.Id, dbsOut[0].Id)
}

func TestPinCreate(t *testing.T) {
	defer clear()
	dbIn, err := dataDbAdd("pins-1", "postgres://u:p@h:1234/d-1")
	must(err)
	b := bytes.NewReader([]byte(`{"name": "pin-1", "db_id": "` + dbIn.Id + `", "query": "select * from pins"`))
	res := mustRequest("POST", "/dbs", b)
	assert.Equal(t, 201, res.Code)
	workerTick()
	pinOut := &pin{}
	must(json.NewDecoder(res.Body).Decode(pinOut))
	assert.Equal(t, "pin-1", pinOut.Name)
	assert.Equal(t, "postgres://u:p@h:1234/d-1", db.Url)
	assert.NotEmpty(t, db.Id)
	assert.WithinDuration(t, time.Now(), db.AddedAt, 3*time.Second)
}

func TestPinWithoutDb(t *testing.T) {
	defer clear()
}
<commit_msg>That actually worked<commit_after>package main

import (
	"bytes"
	"encoding/json"
	"github.com/darkhelmet/env"
	"github.com/stretchr/testify/assert"
	"github.com/zenazn/goji"
	"io"
	"io/ioutil"
	"log"
	"net/http"
	"net/http/httptest"
	"strings"
	"testing"
	"time"
)

func clear() {
	_, err := dataConn.Exec("DELETE from pins")
	must(err)
		_, err = dataConn.Exec("DELETE from dbs")
	must(err)
}

func init() {
	log.SetOutput(ioutil.Discard)
	if !strings.HasSuffix(env.String("DATABASE_URL"), "-test") {
		panic("Doesn't look like a test database")
	}
	dataStart()
	clear()
	webBuild()
}

func request(method, url string, body io.Reader) *httptest.ResponseRecorder {
	req, err := http.NewRequest(method, url, body)
	must(err)
	res := httptest.NewRecorder()
	goji.DefaultMux.ServeHTTP(res, req)
	return res
}

func TestStatus(t *testing.T) {
	res := request("GET", "/status", nil)
	assert.Equal(t, 200, res.Code)
	status := &status{}
	must(json.NewDecoder(res.Body).Decode(status))
	assert.Equal(t, "ok", status.Message)
}

func TestDbAdd(t *testing.T) {
	defer clear()
	b := bytes.NewReader([]byte(`{"name": "pins-1", "url": "postgres://u:p@h:1234/d-1"}`))
	res := request("POST", "/dbs", b)
	assert.Equal(t, 201, res.Code)
	db := &db{}
	must(json.NewDecoder(res.Body).Decode(db))
	assert.Equal(t, "pins-1", db.Name)
	assert.Equal(t, "postgres://u:p@h:1234/d-1", db.Url)
	assert.NotEmpty(t, db.Id)
	assert.WithinDuration(t, time.Now(), db.AddedAt, 3*time.Second)
}

func TestDbGet(t *testing.T) {
	defer clear()
	dbIn, err := dataDbAdd("pins-1", "postgres://u:p@h:1234/d-1")
	must(err)
	res := request("GET", "/dbs/"+dbIn.Id, nil)
	assert.Equal(t, 200, res.Code)
	dbOut := &db{}
	must(json.NewDecoder(res.Body).Decode(dbOut))
	assert.Equal(t, dbIn.Id, dbOut.Id)
	assert.Equal(t, "pins-1", dbOut.Name)
	assert.Equal(t, "postgres://u:p@h:1234/d-1", dbOut.Url)
	assert.WithinDuration(t, time.Now(), dbOut.AddedAt, 3*time.Second)
}

func TestDbRemove(t *testing.T) {
	defer clear()
	dbIn, err := dataDbAdd("pins-1", "postgres://u:p@h:1234/d-1")
	must(err)
	res := request("DELETE", "/dbs/"+dbIn.Id, nil)
	assert.Equal(t, 200, res.Code)
	res = request("GET", "/dbs/"+dbIn.Id, nil)
	assert.Equal(t, 404, res.Code)
}

func TestDbListBasic(t *testing.T) {
	defer clear()
	dbIn, err := dataDbAdd("pins-1", "postgres://u:p@h:1234/d-1")
	must(err)
	res := request("GET", "/dbs", nil)
	assert.Equal(t, 200, res.Code)
	dbsOut := []*db{}
	must(json.NewDecoder(res.Body).Decode(&dbsOut))
	assert.Equal(t, len(dbsOut), 1)
	assert.Equal(t, dbIn.Id, dbsOut[0].Id)
	assert.Equal(t, "pins-1", dbsOut[0].Name)
}

func TestDBListDeletions(t *testing.T) {
	defer clear()
	dbIn1, err := dataDbAdd("pins-1", "postgres://u:p@h:1234/d-1")
	must(err)
	dbIn2, err := dataDbAdd("pins-2", "postgres://u:p@h:1234/d-2")
	must(err)
	_, err = dataDbRemove(dbIn2.Id)
	must(err)
	res := request("GET", "/dbs", nil)
	assert.Equal(t, 200, res.Code)
	dbsOut := []*db{}
	must(json.NewDecoder(res.Body).Decode(&dbsOut))
	assert.Equal(t, len(dbsOut), 1)
	assert.Equal(t, dbIn1.Id, dbsOut[0].Id)
}

func TestPinCreate(t *testing.T) {
	defer clear()
	dbIn, err := dataDbAdd("pins-1", env.String("DATABASE_URL"))
	must(err)
	b := bytes.NewReader([]byte(`{"name": "pin-1", "db_id": "` + dbIn.Id + `", "query": "select count(*) from pins"}`))
	res := request("POST", "/pins", b)
	assert.Equal(t, 201, res.Code)
	pinOut := &pin{}
	must(json.NewDecoder(res.Body).Decode(pinOut))
	workerTick()
	res = request("GET", "/pins/"+pinOut.Id, nil)
	assert.Equal(t, 200, res.Code)
	must(json.NewDecoder(res.Body).Decode(pinOut))
	assert.NotEmpty(t, pinOut.Id)
	assert.Equal(t, "pin-1", pinOut.Name)
	assert.Equal(t, dbIn.Id, pinOut.DbId)
	assert.Equal(t, "select count(*) from pins", pinOut.Query)
	assert.WithinDuration(t, time.Now(), pinOut.CreatedAt, 3*time.Second)
	assert.True(t, pinOut.QueryStartedAt.After(pinOut.CreatedAt))
	assert.True(t, pinOut.QueryFinishedAt.After(*pinOut.QueryStartedAt))
	assert.Equal(t, `["count"]`, *pinOut.ResultsFieldsJson)
	assert.Equal(t, `[[1]]`, *pinOut.ResultsRowsJson)
	assert.Nil(t, pinOut.ResultsError)
}
<|endoftext|>


<commit_before>package summultiples

import "testing"

var test35 = []struct {
	limit int
	sum   int
}{
	{1, 0},
	{4, 3},
	{10, 23},
	{1000, 233168},
}

var varTests = []struct {
	divisors []int
	limit    int
	sum      int
}{
	{[]int{7, 13, 17}, 20, 51},
	{[]int{43, 47}, 10000, 2203160},
	{[]int{5, 10, 12}, 10000, 13331672},
	{[]int{1, 1}, 10000, 49995000},
	{[]int{}, 10000, 0},
}

func Test35(t *testing.T) {
	sum35 := MultipleSummer(3, 5)
	for _, test := range test35 {
		s := sum35(test.limit)
		if s != test.sum {
			t.Fatalf("Sum to %d returned %d, want %d.", test.limit, s, test.sum)
		}
	}
}

func TestVar(t *testing.T) {
	for _, test := range varTests {
		sv := MultipleSummer(test.divisors...)
		s := sv(test.limit)
		if s != test.sum {
			t.Fatalf("Sum of multiples of %v to %d returned %d, want %d.",
				test.divisors, test.limit, s, test.sum)
		}
	}
}

func Benchmark35(b *testing.B) {
	sum35 := MultipleSummer(3, 5)
	b.ResetTimer() // bench just the sum function
	for i := 0; i < b.N; i++ {
		for _, test := range test35 {
			sum35(test.limit)
		}
	}
}

func BenchmarkVar(b *testing.B) {
	// bench combined time to bind sum function and call it.
	for i := 0; i < b.N; i++ {
		for _, test := range varTests {
			MultipleSummer(test.divisors...)(test.limit)
		}
	}
}
<commit_msg>Add missing sum of multiples test<commit_after>package summultiples

import "testing"

var test35 = []struct {
	limit int
	sum   int
}{
	{1, 0},
	{4, 3},
	{10, 23},
	{100, 2318},
	{1000, 233168},
}

var varTests = []struct {
	divisors []int
	limit    int
	sum      int
}{
	{[]int{7, 13, 17}, 20, 51},
	{[]int{43, 47}, 10000, 2203160},
	{[]int{5, 10, 12}, 10000, 13331672},
	{[]int{1, 1}, 10000, 49995000},
	{[]int{}, 10000, 0},
}

func Test35(t *testing.T) {
	sum35 := MultipleSummer(3, 5)
	for _, test := range test35 {
		s := sum35(test.limit)
		if s != test.sum {
			t.Fatalf("Sum to %d returned %d, want %d.", test.limit, s, test.sum)
		}
	}
}

func TestVar(t *testing.T) {
	for _, test := range varTests {
		sv := MultipleSummer(test.divisors...)
		s := sv(test.limit)
		if s != test.sum {
			t.Fatalf("Sum of multiples of %v to %d returned %d, want %d.",
				test.divisors, test.limit, s, test.sum)
		}
	}
}

func Benchmark35(b *testing.B) {
	sum35 := MultipleSummer(3, 5)
	b.ResetTimer() // bench just the sum function
	for i := 0; i < b.N; i++ {
		for _, test := range test35 {
			sum35(test.limit)
		}
	}
}

func BenchmarkVar(b *testing.B) {
	// bench combined time to bind sum function and call it.
	for i := 0; i < b.N; i++ {
		for _, test := range varTests {
			MultipleSummer(test.divisors...)(test.limit)
		}
	}
}
<|endoftext|>


<commit_before>package buildlog

import (
	"database/sql"
	"io"

	logstorage "github.com/fajran/buildlog/pkg/storage"
)

type BuildLog struct {
	db      *sql.DB
	storage logstorage.Storage
}

type Build struct {
	Id  int
	Key string

	buildlog *BuildLog
}

type Log struct {
	Id int

	build *Build
}

func NewBuildLog(db *sql.DB, storage logstorage.Storage) *BuildLog {
	return &BuildLog{
		db:      db,
		storage: storage,
	}
}

func (bl *BuildLog) Create(key string) (int, error) {
	var id int
	err := bl.db.QueryRow(`INSERT INTO builds (key) VALUES ($1) RETURNING id`, key).Scan(&id)
	if err != nil {
		return 0, err
	}

	return id, nil
}

func (bl *BuildLog) Get(id int) (*Build, error) {
	rows, err := bl.db.Query(`SELECT id, key FROM builds WHERE id=$1`, id)
	if err != nil {
		return nil, err
	}

	defer rows.Close()

	if rows.Next() {
		build := Build{
			buildlog: bl,
		}
		rows.Scan(&build.Id, &build.Key)
		return &build, nil
	}

	if rows.Err() != nil {
		return nil, rows.Err()
	}

	return nil, nil
}

func (b *Build) Log(logType, contentType string, content io.Reader) (int, error) {
	var id int
	err := b.buildlog.db.QueryRow(
		`INSERT INTO logs (build_id, type, content_type) VALUES ($1, $2, $3) RETURNING id`,
		b.Id, logType, contentType).
		Scan(&id)
	if err != nil {
		return 0, err
	}

	info, err := b.buildlog.storage.Store(id, content)
	if err != nil {
		return id, err
	}

	_, err = b.buildlog.db.Exec(`UPDATE logs SET identifier=$1, size=$2 WHERE id=$3`, info.Id, info.Size, id)
	if err != nil {
		return id, err
	}

	return id, nil
}
<commit_msg>Pass scanning error to the caller<commit_after>package buildlog

import (
	"database/sql"
	"io"

	logstorage "github.com/fajran/buildlog/pkg/storage"
)

type BuildLog struct {
	db      *sql.DB
	storage logstorage.Storage
}

type Build struct {
	Id  int
	Key string

	buildlog *BuildLog
}

type Log struct {
	Id int

	build *Build
}

func NewBuildLog(db *sql.DB, storage logstorage.Storage) *BuildLog {
	return &BuildLog{
		db:      db,
		storage: storage,
	}
}

func (bl *BuildLog) Create(key string) (int, error) {
	var id int
	err := bl.db.QueryRow(`INSERT INTO builds (key) VALUES ($1) RETURNING id`, key).Scan(&id)
	if err != nil {
		return 0, err
	}

	return id, nil
}

func (bl *BuildLog) Get(id int) (*Build, error) {
	rows, err := bl.db.Query(`SELECT id, key FROM builds WHERE id=$1`, id)
	if err != nil {
		return nil, err
	}

	defer rows.Close()

	if rows.Next() {
		build := Build{
			buildlog: bl,
		}
		err = rows.Scan(&build.Id, &build.Key)
		if err != nil {
			return nil, err
		}
		return &build, nil
	}

	if rows.Err() != nil {
		return nil, rows.Err()
	}

	return nil, nil
}

func (b *Build) Log(logType, contentType string, content io.Reader) (int, error) {
	var id int
	err := b.buildlog.db.QueryRow(
		`INSERT INTO logs (build_id, type, content_type) VALUES ($1, $2, $3) RETURNING id`,
		b.Id, logType, contentType).
		Scan(&id)
	if err != nil {
		return 0, err
	}

	info, err := b.buildlog.storage.Store(id, content)
	if err != nil {
		return id, err
	}

	_, err = b.buildlog.db.Exec(`UPDATE logs SET identifier=$1, size=$2 WHERE id=$3`, info.Id, info.Size, id)
	if err != nil {
		return id, err
	}

	return id, nil
}
<|endoftext|>


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

package maps

import (
	"os"
	"path"
	"path/filepath"
	"strconv"
	"strings"

	"github.com/cilium/cilium/pkg/bpf"
	"github.com/cilium/cilium/pkg/endpoint"
	"github.com/cilium/cilium/pkg/logging"
	"github.com/cilium/cilium/pkg/logging/logfields"
	"github.com/cilium/cilium/pkg/maps/callsmap"
	"github.com/cilium/cilium/pkg/maps/ctmap"
	"github.com/cilium/cilium/pkg/maps/ipmasq"
	"github.com/cilium/cilium/pkg/maps/lbmap"
	"github.com/cilium/cilium/pkg/maps/policymap"
	"github.com/cilium/cilium/pkg/option"
)

var (
	log = logging.DefaultLogger.WithField(logfields.LogSubsys, "datapath-maps")
)

// endpointManager checks against its list of the current endpoints to determine
// whether map paths should be removed, and implements map removal.
//
// This interface is provided to abstract epmanager/filesystem access for unit
// testing.
type endpointManager interface {
	EndpointExists(endpointID uint16) bool
	RemoveDatapathMapping(endpointID uint16) error
	RemoveMapPath(path string)
	HasGlobalCT() bool
}

// MapSweeper is responsible for checking stale map paths on the filesystem
// and garbage collecting the endpoint if the corresponding endpoint no longer
// exists.
type MapSweeper struct {
	endpointManager
}

// NewMapSweeper creates an object that walks map paths and garbage-collects
// them.
func NewMapSweeper(g endpointManager) *MapSweeper {
	return &MapSweeper{
		endpointManager: g,
	}
}

// deleteMapIfStale uses the endpointManager implementation to determine for
// the given path whether it should be deleted, and if so deletes the path.
func (ms *MapSweeper) deleteMapIfStale(path string, filename string, endpointID string) {
	if tmp, err := strconv.ParseUint(endpointID, 10, 16); err == nil {
		epID := uint16(tmp)
		if ms.EndpointExists(epID) {
			prefix := strings.TrimSuffix(filename, endpointID)
			if filename != bpf.LocalMapName(prefix, epID) {
				ms.RemoveMapPath(path)
			}
		} else {
			err2 := ms.RemoveDatapathMapping(epID)
			if err2 != nil {
				log.WithError(err2).Debugf("Failed to remove ID %d from global policy map", tmp)
			}
			ms.RemoveMapPath(path)
		}
	}
}

func (ms *MapSweeper) checkStaleGlobalMap(path string, filename string) {
	globalCTinUse := ms.HasGlobalCT() || option.Config.EnableNodePort ||
		!option.Config.InstallIptRules && (option.Config.EnableIPv4Masquerade ||
			option.Config.EnableIPv6Masquerade)

	if !globalCTinUse && ctmap.NameIsGlobal(filename) {
		ms.RemoveMapPath(path)
	}
}

func (ms *MapSweeper) walk(path string, _ os.FileInfo, _ error) error {
	filename := filepath.Base(path)

	mapPrefix := []string{
		policymap.MapName,
		ctmap.MapNameTCP6,
		ctmap.MapNameTCP4,
		ctmap.MapNameAny6,
		ctmap.MapNameAny4,
		callsmap.MapName,
		endpoint.IpvlanMapName,
	}

	ms.checkStaleGlobalMap(path, filename)

	for _, m := range mapPrefix {
		if strings.HasPrefix(filename, m) {
			if endpointID := strings.TrimPrefix(filename, m); endpointID != filename {
				ms.deleteMapIfStale(path, filename, endpointID)
			}
		}
	}

	return nil
}

// CollectStaleMapGarbage cleans up stale content in the BPF maps from the
// datapath.
func (ms *MapSweeper) CollectStaleMapGarbage() {
	if err := filepath.Walk(bpf.MapPrefixPath(), ms.walk); err != nil {
		log.WithError(err).Warn("Error while scanning for stale maps")
	}
}

// RemoveDisabledMaps removes BPF maps in the filesystem for features that have
// been disabled. The maps may still be in use in which case they will continue
// to live until the BPF program using them is being replaced.
func (ms *MapSweeper) RemoveDisabledMaps() {
	maps := []string{}

	if !option.Config.EnableIPv6 {
		maps = append(maps, []string{
			"cilium_ct6_global",
			"cilium_ct_any6_global",
			"cilium_lb6_reverse_nat",
			"cilium_lb6_rr_seq",
			"cilium_lb6_services",
			"cilium_lb6_services_v2",
			"cilium_lb6_rr_seq_v2",
			"cilium_lb6_backends",
			"cilium_lb6_reverse_sk",
			"cilium_snat_v6_external",
			"cilium_proxy6",
			lbmap.MaglevOuter6MapName,
			lbmap.Affinity6MapName,
			lbmap.SourceRange6MapName,
			lbmap.HealthProbe6MapName,
		}...)
	}

	if !option.Config.EnableIPv4 {
		maps = append(maps, []string{
			"cilium_ct4_global",
			"cilium_ct_any4_global",
			"cilium_lb4_reverse_nat",
			"cilium_lb4_rr_seq",
			"cilium_lb4_services",
			"cilium_lb4_services_v2",
			"cilium_lb4_rr_seq_v2",
			"cilium_lb4_backends",
			"cilium_lb4_reverse_sk",
			"cilium_snat_v4_external",
			"cilium_proxy4",
			lbmap.MaglevOuter4MapName,
			lbmap.Affinity4MapName,
			lbmap.SourceRange4MapName,
			lbmap.HealthProbe4MapName,
			ipmasq.MapName,
		}...)
	}

	if !option.Config.EnableIPv4FragmentsTracking {
		maps = append(maps, "cilium_ipv4_frag_datagrams")
	}

	if !option.Config.EnableBandwidthManager {
		maps = append(maps, "cilium_throttle")
	}

	if !option.Config.EnableHealthDatapath {
		maps = append(maps, lbmap.HealthProbe6MapName, lbmap.HealthProbe4MapName)
	}

	if option.Config.NodePortAlg != option.NodePortAlgMaglev {
		maps = append(maps, lbmap.MaglevOuter6MapName, lbmap.MaglevOuter4MapName)
	}

	if !option.Config.EnableSessionAffinity {
		maps = append(maps, lbmap.Affinity6MapName, lbmap.Affinity4MapName, lbmap.AffinityMatchMapName)
	}

	if !option.Config.EnableSVCSourceRangeCheck {
		maps = append(maps, lbmap.SourceRange6MapName, lbmap.SourceRange4MapName)
	}

	if !option.Config.EnableIPMasqAgent {
		maps = append(maps, ipmasq.MapName)
	}

	for _, m := range maps {
		p := path.Join(bpf.MapPrefixPath(), m)
		if _, err := os.Stat(p); !os.IsNotExist(err) {
			ms.RemoveMapPath(p)
		}
	}
}
<commit_msg>datapath: remove SNAT maps entries when kube-proxy is enabled<commit_after>// Copyright 2016-2020 Authors of Cilium
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package maps

import (
	"os"
	"path"
	"path/filepath"
	"strconv"
	"strings"

	"github.com/cilium/cilium/pkg/bpf"
	"github.com/cilium/cilium/pkg/endpoint"
	"github.com/cilium/cilium/pkg/logging"
	"github.com/cilium/cilium/pkg/logging/logfields"
	"github.com/cilium/cilium/pkg/maps/callsmap"
	"github.com/cilium/cilium/pkg/maps/ctmap"
	"github.com/cilium/cilium/pkg/maps/ipmasq"
	"github.com/cilium/cilium/pkg/maps/lbmap"
	"github.com/cilium/cilium/pkg/maps/policymap"
	"github.com/cilium/cilium/pkg/option"
)

var (
	log = logging.DefaultLogger.WithField(logfields.LogSubsys, "datapath-maps")
)

// endpointManager checks against its list of the current endpoints to determine
// whether map paths should be removed, and implements map removal.
//
// This interface is provided to abstract epmanager/filesystem access for unit
// testing.
type endpointManager interface {
	EndpointExists(endpointID uint16) bool
	RemoveDatapathMapping(endpointID uint16) error
	RemoveMapPath(path string)
	HasGlobalCT() bool
}

// MapSweeper is responsible for checking stale map paths on the filesystem
// and garbage collecting the endpoint if the corresponding endpoint no longer
// exists.
type MapSweeper struct {
	endpointManager
}

// NewMapSweeper creates an object that walks map paths and garbage-collects
// them.
func NewMapSweeper(g endpointManager) *MapSweeper {
	return &MapSweeper{
		endpointManager: g,
	}
}

// deleteMapIfStale uses the endpointManager implementation to determine for
// the given path whether it should be deleted, and if so deletes the path.
func (ms *MapSweeper) deleteMapIfStale(path string, filename string, endpointID string) {
	if tmp, err := strconv.ParseUint(endpointID, 10, 16); err == nil {
		epID := uint16(tmp)
		if ms.EndpointExists(epID) {
			prefix := strings.TrimSuffix(filename, endpointID)
			if filename != bpf.LocalMapName(prefix, epID) {
				ms.RemoveMapPath(path)
			}
		} else {
			err2 := ms.RemoveDatapathMapping(epID)
			if err2 != nil {
				log.WithError(err2).Debugf("Failed to remove ID %d from global policy map", tmp)
			}
			ms.RemoveMapPath(path)
		}
	}
}

func (ms *MapSweeper) checkStaleGlobalMap(path string, filename string) {
	globalCTinUse := ms.HasGlobalCT() || option.Config.EnableNodePort ||
		!option.Config.InstallIptRules && (option.Config.EnableIPv4Masquerade ||
			option.Config.EnableIPv6Masquerade)

	if !globalCTinUse && ctmap.NameIsGlobal(filename) {
		ms.RemoveMapPath(path)
	}
}

func (ms *MapSweeper) walk(path string, _ os.FileInfo, _ error) error {
	filename := filepath.Base(path)

	mapPrefix := []string{
		policymap.MapName,
		ctmap.MapNameTCP6,
		ctmap.MapNameTCP4,
		ctmap.MapNameAny6,
		ctmap.MapNameAny4,
		callsmap.MapName,
		endpoint.IpvlanMapName,
	}

	ms.checkStaleGlobalMap(path, filename)

	for _, m := range mapPrefix {
		if strings.HasPrefix(filename, m) {
			if endpointID := strings.TrimPrefix(filename, m); endpointID != filename {
				ms.deleteMapIfStale(path, filename, endpointID)
			}
		}
	}

	return nil
}

// CollectStaleMapGarbage cleans up stale content in the BPF maps from the
// datapath.
func (ms *MapSweeper) CollectStaleMapGarbage() {
	if err := filepath.Walk(bpf.MapPrefixPath(), ms.walk); err != nil {
		log.WithError(err).Warn("Error while scanning for stale maps")
	}
}

// RemoveDisabledMaps removes BPF maps in the filesystem for features that have
// been disabled. The maps may still be in use in which case they will continue
// to live until the BPF program using them is being replaced.
func (ms *MapSweeper) RemoveDisabledMaps() {
	maps := []string{}

	if !option.Config.EnableIPv6 {
		maps = append(maps, []string{
			"cilium_ct6_global",
			"cilium_ct_any6_global",
			"cilium_lb6_reverse_nat",
			"cilium_lb6_rr_seq",
			"cilium_lb6_services",
			"cilium_lb6_services_v2",
			"cilium_lb6_rr_seq_v2",
			"cilium_lb6_backends",
			"cilium_lb6_reverse_sk",
			"cilium_snat_v6_external",
			"cilium_proxy6",
			lbmap.MaglevOuter6MapName,
			lbmap.Affinity6MapName,
			lbmap.SourceRange6MapName,
			lbmap.HealthProbe6MapName,
		}...)
	}

	if !option.Config.EnableIPv4 {
		maps = append(maps, []string{
			"cilium_ct4_global",
			"cilium_ct_any4_global",
			"cilium_lb4_reverse_nat",
			"cilium_lb4_rr_seq",
			"cilium_lb4_services",
			"cilium_lb4_services_v2",
			"cilium_lb4_rr_seq_v2",
			"cilium_lb4_backends",
			"cilium_lb4_reverse_sk",
			"cilium_snat_v4_external",
			"cilium_proxy4",
			lbmap.MaglevOuter4MapName,
			lbmap.Affinity4MapName,
			lbmap.SourceRange4MapName,
			lbmap.HealthProbe4MapName,
			ipmasq.MapName,
		}...)
	}

	if !option.Config.EnableNodePort {
		maps = append(maps, []string{"cilium_snat_v4_external", "cilium_snat_v6_external"}...)
	}

	if !option.Config.EnableIPv4FragmentsTracking {
		maps = append(maps, "cilium_ipv4_frag_datagrams")
	}

	if !option.Config.EnableBandwidthManager {
		maps = append(maps, "cilium_throttle")
	}

	if !option.Config.EnableHealthDatapath {
		maps = append(maps, lbmap.HealthProbe6MapName, lbmap.HealthProbe4MapName)
	}

	if option.Config.NodePortAlg != option.NodePortAlgMaglev {
		maps = append(maps, lbmap.MaglevOuter6MapName, lbmap.MaglevOuter4MapName)
	}

	if !option.Config.EnableSessionAffinity {
		maps = append(maps, lbmap.Affinity6MapName, lbmap.Affinity4MapName, lbmap.AffinityMatchMapName)
	}

	if !option.Config.EnableSVCSourceRangeCheck {
		maps = append(maps, lbmap.SourceRange6MapName, lbmap.SourceRange4MapName)
	}

	if !option.Config.EnableIPMasqAgent {
		maps = append(maps, ipmasq.MapName)
	}

	for _, m := range maps {
		p := path.Join(bpf.MapPrefixPath(), m)
		if _, err := os.Stat(p); !os.IsNotExist(err) {
			ms.RemoveMapPath(p)
		}
	}
}
<|endoftext|>


<commit_before>package notifier

import (
	"encoding/json"

	"github.com/containous/traefik/log"
	"github.com/hellofresh/janus/pkg/store"
)

type NotificationCommand string

const (
	// NoticeAPIUpdated notifies when an API is updated
	NoticeAPIUpdated NotificationCommand = "ApiUpdated"
	// NoticeAPIRemoved notifies when an API is removed
	NoticeAPIRemoved NotificationCommand = "ApiRemoved"
	// NoticeAPIAdded notifies when an API is added
	NoticeAPIAdded NotificationCommand = "ApiAdded"
	// NoticeOAuthServerUpdated notifies when an OAuth server is updated
	NoticeOAuthServerUpdated NotificationCommand = "OAuthUpdated"
	// NoticeOAuthServerRemoved notifies when an OAuth server is removed
	NoticeOAuthServerRemoved NotificationCommand = "OAuthRemoved"
	// NoticeOAuthServerAdded notifies when an OAuth server is added
	NoticeOAuthServerAdded NotificationCommand = "OAuthAdded"
)

// RequireReload checks if a given command requires reload
func RequireReload(cmd NotificationCommand) bool {
	switch cmd {
	case NoticeAPIUpdated, NoticeAPIRemoved, NoticeAPIAdded, NoticeOAuthServerUpdated, NoticeOAuthServerRemoved, NoticeOAuthServerAdded:
		return true
	default:
		return false
	}
}

// Notification is a type that encodes a message published to a pub sub channel (shared between implementations)
type Notification struct {
	Command   NotificationCommand `json:"command"`
	Payload   string              `json:"payload"`
	Signature string              `json:"signature"`
}

// Notifier will use redis pub/sub channels to send notifications
type Notifier struct {
	publisher store.Publisher
	channel   string
}

// New creates a new instance of Notifier
func New(publisher store.Publisher, channel string) *Notifier {
	return &Notifier{publisher, channel}
}

// Notify will send a notification to a channel
func (r *Notifier) Notify(notification Notification) bool {
	toSend, err := json.Marshal(notification)
	if err != nil {
		log.Error("Problem marshalling notification: ", err)
		return false
	}
	log.Debug("Sending notification", notification)
	if err := r.publisher.Publish(r.channel, toSend); err != nil {
		log.Error("Could not send notification: ", err)
		return false
	}
	return true
}
<commit_msg>Changed the package<commit_after>package notifier

import (
	"encoding/json"

	log "github.com/Sirupsen/logrus"
	"github.com/hellofresh/janus/pkg/store"
)

type NotificationCommand string

const (
	// NoticeAPIUpdated notifies when an API is updated
	NoticeAPIUpdated NotificationCommand = "ApiUpdated"
	// NoticeAPIRemoved notifies when an API is removed
	NoticeAPIRemoved NotificationCommand = "ApiRemoved"
	// NoticeAPIAdded notifies when an API is added
	NoticeAPIAdded NotificationCommand = "ApiAdded"
	// NoticeOAuthServerUpdated notifies when an OAuth server is updated
	NoticeOAuthServerUpdated NotificationCommand = "OAuthUpdated"
	// NoticeOAuthServerRemoved notifies when an OAuth server is removed
	NoticeOAuthServerRemoved NotificationCommand = "OAuthRemoved"
	// NoticeOAuthServerAdded notifies when an OAuth server is added
	NoticeOAuthServerAdded NotificationCommand = "OAuthAdded"
)

// RequireReload checks if a given command requires reload
func RequireReload(cmd NotificationCommand) bool {
	switch cmd {
	case NoticeAPIUpdated, NoticeAPIRemoved, NoticeAPIAdded, NoticeOAuthServerUpdated, NoticeOAuthServerRemoved, NoticeOAuthServerAdded:
		return true
	default:
		return false
	}
}

// Notification is a type that encodes a message published to a pub sub channel (shared between implementations)
type Notification struct {
	Command   NotificationCommand `json:"command"`
	Payload   string              `json:"payload"`
	Signature string              `json:"signature"`
}

// Notifier will use redis pub/sub channels to send notifications
type Notifier struct {
	publisher store.Publisher
	channel   string
}

// New creates a new instance of Notifier
func New(publisher store.Publisher, channel string) *Notifier {
	return &Notifier{publisher, channel}
}

// Notify will send a notification to a channel
func (r *Notifier) Notify(notification Notification) bool {
	toSend, err := json.Marshal(notification)
	if err != nil {
		log.Error("Problem marshalling notification: ", err)
		return false
	}
	log.Debug("Sending notification", notification)
	if err := r.publisher.Publish(r.channel, toSend); err != nil {
		log.Error("Could not send notification: ", err)
		return false
	}
	return true
}
<|endoftext|>


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

package operator

import (
	"github.com/coreos/prometheus-operator/pkg/version"
)

const (
	DefaultAlertmanagerVersion    = "v0.20.0"
	DefaultAlertmanagerBaseImage  = "quay.io/prometheus/alertmanager"
	DefaultAlertmanagerImage      = DefaultAlertmanagerBaseImage + ":" + DefaultAlertmanagerVersion
	DefaultThanosVersion          = "v0.11.0"
	DefaultThanosBaseImage        = "quay.io/thanos/thanos"
	DefaultThanosImage            = DefaultThanosBaseImage + ":" + DefaultThanosVersion
	DefaultConfigMapReloaderImage = "jimmidyson/configmap-reload:v0.3.0"
)

var (
	DefaultPrometheusConfigReloaderImage = "quay.io/coreos/prometheus-config-reloader:v" + version.Version

	PrometheusCompatibilityMatrix = []string{
		"v1.4.0",
		"v1.4.1",
		"v1.5.0",
		"v1.5.1",
		"v1.5.2",
		"v1.5.3",
		"v1.6.0",
		"v1.6.1",
		"v1.6.2",
		"v1.6.3",
		"v1.7.0",
		"v1.7.1",
		"v1.7.2",
		"v1.8.0",
		"v2.0.0",
		"v2.2.1",
		"v2.3.1",
		"v2.3.2",
		"v2.4.0",
		"v2.4.1",
		"v2.4.2",
		"v2.4.3",
		"v2.5.0",
		"v2.6.0",
		"v2.6.1",
		"v2.7.0",
		"v2.7.1",
		"v2.7.2",
		"v2.8.1",
		"v2.9.2",
		"v2.10.0",
		"v2.11.0",
		"v2.14.0",
		"v2.15.2",
		"v2.16.0",
		"v2.17.2",
		"v2.18.0",
		"v2.18.1",
		"v2.18.2",
		"v2.19.0",
	}
	DefaultPrometheusVersion   = PrometheusCompatibilityMatrix[len(PrometheusCompatibilityMatrix)-1]
	DefaultPrometheusBaseImage = "quay.io/prometheus/prometheus"
	DefaultPrometheusImage     = DefaultAlertmanagerBaseImage + ":" + DefaultPrometheusVersion
)
<commit_msg>pkg/operator: bump Alertmanager default version to v0.21.0 (#3286)<commit_after>// Copyright 2020 The prometheus-operator Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package operator

import (
	"github.com/coreos/prometheus-operator/pkg/version"
)

const (
	DefaultAlertmanagerVersion    = "v0.21.0"
	DefaultAlertmanagerBaseImage  = "quay.io/prometheus/alertmanager"
	DefaultAlertmanagerImage      = DefaultAlertmanagerBaseImage + ":" + DefaultAlertmanagerVersion
	DefaultThanosVersion          = "v0.12.2"
	DefaultThanosBaseImage        = "quay.io/thanos/thanos"
	DefaultThanosImage            = DefaultThanosBaseImage + ":" + DefaultThanosVersion
	DefaultConfigMapReloaderImage = "jimmidyson/configmap-reload:v0.3.0"
)

var (
	DefaultPrometheusConfigReloaderImage = "quay.io/coreos/prometheus-config-reloader:v" + version.Version

	PrometheusCompatibilityMatrix = []string{
		"v1.4.0",
		"v1.4.1",
		"v1.5.0",
		"v1.5.1",
		"v1.5.2",
		"v1.5.3",
		"v1.6.0",
		"v1.6.1",
		"v1.6.2",
		"v1.6.3",
		"v1.7.0",
		"v1.7.1",
		"v1.7.2",
		"v1.8.0",
		"v2.0.0",
		"v2.2.1",
		"v2.3.1",
		"v2.3.2",
		"v2.4.0",
		"v2.4.1",
		"v2.4.2",
		"v2.4.3",
		"v2.5.0",
		"v2.6.0",
		"v2.6.1",
		"v2.7.0",
		"v2.7.1",
		"v2.7.2",
		"v2.8.1",
		"v2.9.2",
		"v2.10.0",
		"v2.11.0",
		"v2.14.0",
		"v2.15.2",
		"v2.16.0",
		"v2.17.2",
		"v2.18.0",
		"v2.18.1",
		"v2.18.2",
		"v2.19.0",
	}
	DefaultPrometheusVersion   = PrometheusCompatibilityMatrix[len(PrometheusCompatibilityMatrix)-1]
	DefaultPrometheusBaseImage = "quay.io/prometheus/prometheus"
	DefaultPrometheusImage     = DefaultAlertmanagerBaseImage + ":" + DefaultPrometheusVersion
)
<|endoftext|>


<commit_before>/*
Copyright 2016 The Kubernetes Authors.

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

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

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

package provider

import (
	"fmt"
	"time"

	"github.com/hashicorp/terraform/helper/schema"
	"github.com/hashicorp/terraform/terraform"
	"k8s.io/kubernetes/pkg/api"
	"k8s.io/kubernetes/pkg/client/clientset_generated/release_1_4"
	"k8s.io/kubernetes/pkg/client/restclient"
	"k8s.io/kubernetes/pkg/client/unversioned/clientcmd"
	clientcmdapi "k8s.io/kubernetes/pkg/client/unversioned/clientcmd/api"
)

const (
	UserAgent = "terraform-kubernetes"

	PollInterval = 10 * time.Second
	PollTimeout  = 10 * time.Minute
)

func Provider() terraform.ResourceProvider {
	return &schema.Provider{
		ResourcesMap: map[string]*schema.Resource{
			"kubernetes_kubeconfig": resourceKubeconfig(),
		},
	}
}

func resourceKubeconfig() *schema.Resource {
	return &schema.Resource{
		Create: CreateKubeconfig,
		Delete: DeleteKubeconfig,
		Read:   ReadKubeconfig,

		Schema: map[string]*schema.Schema{
			"server": &schema.Schema{
				Type:        schema.TypeString,
				Required:    true,
				Description: "Domain name or IP address of the API server",
				ForceNew:    true,
			},
			"configdata": &schema.Schema{
				Type:        schema.TypeString,
				Required:    true,
				Description: "kubeconfig in the serialized JSON format",
				ForceNew:    true,
			},
		},
	}
}

func CreateKubeconfig(d *schema.ResourceData, meta interface{}) error {
	server := d.Get("server").(string)
	clientConfig, err := clientcmd.BuildConfigFromKubeconfigGetter(server, kubeConfigGetter(d))
	if err != nil {
		return fmt.Errorf("couldn't parse the supplied config: %v", err)
	}
	clientset, err := release_1_4.NewForConfig(restclient.AddUserAgent(clientConfig, UserAgent))
	if err != nil {
		return fmt.Errorf("failed to initialize the cluster client: %v", err)
	}

	interval := time.NewTicker(PollInterval)
	defer interval.Stop()
	timeout := time.NewTimer(PollTimeout)
	defer timeout.Stop()

	for {
		select {
		case <-interval.C:
			if allComponentsHealthy(clientset) {
				break
			}
		case <-timeout.C:
			return fmt.Errorf("cluster components never turned healthy")
		}
	}

	configAccess := clientcmd.NewDefaultPathOptions()
	kubeConfig, err := kubeConfigGetter(d)()
	if err != nil {
		return fmt.Errorf("couldn't parse the supplied config: %v", err)
	}
	if err := modifyConfig(configAccess, kubeConfig); err != nil {
		return fmt.Errorf("couldn't update kubeconfig: %v", err)
	}

	return nil
}

func DeleteKubeconfig(d *schema.ResourceData, meta interface{}) error {
	return nil
}

func ReadKubeconfig(d *schema.ResourceData, meta interface{}) error {
	return nil
}

func allComponentsHealthy(clientset *release_1_4.Clientset) bool {
	csList, err := clientset.Core().ComponentStatuses().List(api.ListOptions{})
	if err != nil || len(csList.Items) <= 0 {
		return false
	}
	for _, cs := range csList.Items {
		if !(len(cs.Conditions) > 0 && cs.Conditions[0].Type == "Healthy" && cs.Conditions[0].Status == "True") {
			return false
		}
	}
	return true
}

func kubeConfigGetter(d *schema.ResourceData) clientcmd.KubeconfigGetter {
	return func() (*clientcmdapi.Config, error) {
		kubeConfigStr := d.Get("configdata").(string)
		return clientcmd.Load([]byte(kubeConfigStr))
	}
}

func modifyConfig(configAccess clientcmd.ConfigAccess, suppliedConfig *clientcmdapi.Config) error {
	config, err := configAccess.GetStartingConfig()
	if err != nil {
		return err
	}

	for name, cluster := range suppliedConfig.Clusters {
		initial, ok := config.Clusters[name]
		if !ok {
			initial = clientcmdapi.NewCluster()
		}
		modified := *initial

		if len(cluster.Server) > 0 {
			modified.Server = cluster.Server
		}
		if cluster.InsecureSkipTLSVerify {
			modified.InsecureSkipTLSVerify = cluster.InsecureSkipTLSVerify
			// Specifying insecure mode clears any certificate authority
			if modified.InsecureSkipTLSVerify {
				modified.CertificateAuthority = ""
				modified.CertificateAuthorityData = nil
			}
		}
		if len(cluster.CertificateAuthorityData) > 0 {
			modified.CertificateAuthorityData = cluster.CertificateAuthorityData
			modified.InsecureSkipTLSVerify = false
			modified.CertificateAuthority = ""
		} else if len(cluster.CertificateAuthority) > 0 {
			modified.CertificateAuthority = cluster.CertificateAuthority
			modified.InsecureSkipTLSVerify = false
			modified.CertificateAuthorityData = nil
		}
		config.Clusters[name] = &modified
	}

	if err := clientcmd.ModifyConfig(configAccess, *config, true); err != nil {
		return err
	}

	return nil
}
<commit_msg>Add some debug logs.<commit_after>/*
Copyright 2016 The Kubernetes Authors.

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

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

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

package provider

import (
	"fmt"
	"log"
	"time"

	"github.com/hashicorp/terraform/helper/schema"
	"github.com/hashicorp/terraform/terraform"
	"k8s.io/kubernetes/pkg/api"
	"k8s.io/kubernetes/pkg/client/clientset_generated/release_1_4"
	"k8s.io/kubernetes/pkg/client/restclient"
	"k8s.io/kubernetes/pkg/client/unversioned/clientcmd"
	clientcmdapi "k8s.io/kubernetes/pkg/client/unversioned/clientcmd/api"
)

const (
	UserAgent = "terraform-kubernetes"

	PollInterval = 10 * time.Second
	PollTimeout  = 10 * time.Minute
)

func Provider() terraform.ResourceProvider {
	return &schema.Provider{
		ResourcesMap: map[string]*schema.Resource{
			"kubernetes_kubeconfig": resourceKubeconfig(),
		},
	}
}

func resourceKubeconfig() *schema.Resource {
	return &schema.Resource{
		Create: CreateKubeconfig,
		Delete: DeleteKubeconfig,
		Read:   ReadKubeconfig,

		Schema: map[string]*schema.Schema{
			"server": &schema.Schema{
				Type:        schema.TypeString,
				Required:    true,
				Description: "Domain name or IP address of the API server",
				ForceNew:    true,
			},
			"configdata": &schema.Schema{
				Type:        schema.TypeString,
				Required:    true,
				Description: "kubeconfig in the serialized JSON format",
				ForceNew:    true,
			},
		},
	}
}

func CreateKubeconfig(d *schema.ResourceData, meta interface{}) error {
	server := d.Get("server").(string)
	clientConfig, err := clientcmd.BuildConfigFromKubeconfigGetter(server, kubeConfigGetter(d))
	if err != nil {
		return fmt.Errorf("couldn't parse the supplied config: %v", err)
	}
	clientset, err := release_1_4.NewForConfig(restclient.AddUserAgent(clientConfig, UserAgent))
	if err != nil {
		return fmt.Errorf("failed to initialize the cluster client: %v", err)
	}

	interval := time.NewTicker(PollInterval)
	defer interval.Stop()
	timeout := time.NewTimer(PollTimeout)
	defer timeout.Stop()

	for {
		select {
		case <-interval.C:
			if allComponentsHealthy(clientset) {
				break
			}
		case <-timeout.C:
			return fmt.Errorf("cluster components never turned healthy")
		}
	}

	configAccess := clientcmd.NewDefaultPathOptions()
	kubeConfig, err := kubeConfigGetter(d)()
	if err != nil {
		return fmt.Errorf("couldn't parse the supplied config: %v", err)
	}

	if err := modifyConfig(configAccess, kubeConfig); err != nil {
		return fmt.Errorf("couldn't update kubeconfig: %v", err)
	}

	return nil
}

func DeleteKubeconfig(d *schema.ResourceData, meta interface{}) error {
	return nil
}

func ReadKubeconfig(d *schema.ResourceData, meta interface{}) error {
	return nil
}

func allComponentsHealthy(clientset *release_1_4.Clientset) bool {
	csList, err := clientset.Core().ComponentStatuses().List(api.ListOptions{})
	if err != nil || len(csList.Items) <= 0 {
		log.Printf("[DEBUG] Listing components failed %s", err)
		return false
	}
	for _, cs := range csList.Items {
		if !(len(cs.Conditions) > 0 && cs.Conditions[0].Type == "Healthy" && cs.Conditions[0].Status == "True") {
			log.Printf("[DEBUG] %s isn't healthy. Conditions: %+v", cs.Name, cs.Conditions)
			return false
		}
	}
	return true
}

func kubeConfigGetter(d *schema.ResourceData) clientcmd.KubeconfigGetter {
	return func() (*clientcmdapi.Config, error) {
		kubeConfigStr := d.Get("configdata").(string)
		return clientcmd.Load([]byte(kubeConfigStr))
	}
}

func modifyConfig(configAccess clientcmd.ConfigAccess, suppliedConfig *clientcmdapi.Config) error {
	config, err := configAccess.GetStartingConfig()
	if err != nil {
		return err
	}

	for name, cluster := range suppliedConfig.Clusters {
		initial, ok := config.Clusters[name]
		if !ok {
			initial = clientcmdapi.NewCluster()
		}
		modified := *initial

		if len(cluster.Server) > 0 {
			modified.Server = cluster.Server
		}
		if cluster.InsecureSkipTLSVerify {
			modified.InsecureSkipTLSVerify = cluster.InsecureSkipTLSVerify
			// Specifying insecure mode clears any certificate authority
			if modified.InsecureSkipTLSVerify {
				modified.CertificateAuthority = ""
				modified.CertificateAuthorityData = nil
			}
		}
		if len(cluster.CertificateAuthorityData) > 0 {
			modified.CertificateAuthorityData = cluster.CertificateAuthorityData
			modified.InsecureSkipTLSVerify = false
			modified.CertificateAuthority = ""
		} else if len(cluster.CertificateAuthority) > 0 {
			modified.CertificateAuthority = cluster.CertificateAuthority
			modified.InsecureSkipTLSVerify = false
			modified.CertificateAuthorityData = nil
		}
		config.Clusters[name] = &modified
	}

	if err := clientcmd.ModifyConfig(configAccess, *config, true); err != nil {
		return err
	}

	return nil
}
<|endoftext|>


<commit_before>package main

type thing interface {
	Id() identifier
	Name() string
	Brief() string
	Long() string
}

type actualThing struct {
	id    identifier
	name  string
	brief string
	long  string
}

func (t actualThing) Id() identifier {
	return t.id
}
func (t actualThing) Name() string {
	return t.name
}
func (t actualThing) Brief() string {
	return t.brief
}
func (t actualThing) Long() string {
	return t.long
}

func getThingGetter(id identifier, getGetter chan struct {
	id       identifier
	response chan chan thing
},) chan thing {
	response := make(chan chan thing)
	getGetter <- struct {
		id       identifier
		response chan chan thing
	}{id, response}
	return <-response
}

func getThing(id identifier, getGetter chan struct {
	id       identifier
	response chan chan thing
},) thing {
	getter := getThingGetter(id, getGetter)
	return <-getter
}

func getThingSetter(id identifier, getSetter chan struct {
	id       identifier
	response chan chan chan thing
},) chan chan thing {
	response := make(chan chan chan thing)
	getSetter <- struct {
		id       identifier
		response chan chan chan thing
	}{id, response}
	return <-response
}

//func addThing

func initThingManager() (
	chan struct {
		id       identifier
		response chan chan thing
	},
	chan struct {
		id       identifier
		response chan chan chan thing
	},
	chan thing,
	chan identifier) {

	getGetter := make(chan struct {
		id       identifier
		response chan chan thing
	})
	getSetter := make(chan struct {
		id       identifier
		response chan chan chan thing
	})
	add := make(chan thing)
	del := make(chan identifier)
	go func() {
		things := make(map[identifier]struct {
			getter chan thing
			setter chan chan thing
			closer chan bool
		})
		for {
			select {
			case a := <-add:
				getter := make(chan thing)
				setter := make(chan chan thing)
				closer := make(chan bool)
				getter <- a
				go func() {
					it := <-getter
					itc := make(chan thing)
					for {
						select {
						case setter <- itc:
							it = <-itc
						case getter <- it:
						case <-closer:
							close(getter)
							close(setter)
							return
						}
					}
				}()
				things[a.Id()] = struct {
					getter chan thing
					setter chan chan thing
					closer chan bool
				}{getter, setter, closer}
			case d := <-del:
				things[d].closer <- true
				delete(things, d)
			case g := <-getGetter:
				g.response <- things[g.id].getter
			case s := <-getSetter:
				s.response <- things[s.id].setter
			}
		}
	}()
	return getGetter, getSetter, add, del
}
<commit_msg>changed data.go setter chan to also return the current thing instance<commit_after>package main

type thing interface {
	Id() identifier
	Name() string
	Brief() string
	Long() string
}

type actualThing struct {
	id    identifier
	name  string
	brief string
	long  string
}

func (t actualThing) Id() identifier {
	return t.id
}
func (t actualThing) Name() string {
	return t.name
}
func (t actualThing) Brief() string {
	return t.brief
}
func (t actualThing) Long() string {
	return t.long
}

func getThingGetter(id identifier, getGetter chan struct {
	id       identifier
	response chan chan thing
},) chan thing {
	response := make(chan chan thing)
	getGetter <- struct {
		id       identifier
		response chan chan thing
	}{id, response}
	return <-response
}

func getThing(id identifier, getGetter chan struct {
	id       identifier
	response chan chan thing
},) thing {
	getter := getThingGetter(id, getGetter)
	return <-getter
}

func getThingSetter(id identifier, getSetter chan struct {
	id       identifier
	response chan chan struct {
		it  thing
		set chan thing
	}
},) chan struct {
	it  thing
	set chan thing
} {
	response := make(chan chan struct {
		it  thing
		set chan thing
	})
	getSetter <- struct {
		id       identifier
		response chan chan struct {
			it  thing
			set chan thing
		}
	}{id, response}
	return <-response
}

//func addThing

func initThingManager() (
	chan struct {
		id       identifier
		response chan chan thing
	},
	chan struct {
		id       identifier
		response chan chan struct {
			it  thing
		        set chan thing
		}
	},
	chan thing,
	chan identifier) {

	getGetter := make(chan struct {
		id       identifier
		response chan chan thing
	})
	getSetter := make(chan struct {
		id       identifier
		response chan chan struct {
			it  thing
			set chan thing
		}
	})
	add := make(chan thing)
	del := make(chan identifier)
	go func() {
		things := make(map[identifier]struct {
			getter chan thing
			setter chan struct {
				it  thing
				set chan thing
			}
			closer chan bool
		})
		for {
			select {
			case a := <-add:
				getter := make(chan thing)
				setter := make(chan struct {
					it  thing
					set chan thing
				})
				closer := make(chan bool)
				getter <- a
				go func() {
					it := <-getter
					itc := make(chan thing)
					for {
						select {
						case setter <- struct {
							it  thing
							set chan thing
						}{it: it, set: itc}:
							it = <-itc
						case getter <- it:
						case <-closer:
							close(getter)
							close(setter)
							return
						}
					}
				}()
				things[a.Id()] = struct {
					getter chan thing
					setter chan struct {
						it  thing
						set chan thing
					}
					closer chan bool
				}{getter, setter, closer}
			case d := <-del:
				things[d].closer <- true
				delete(things, d)
			case g := <-getGetter:
				g.response <- things[g.id].getter
			case s := <-getSetter:
				s.response <- things[s.id].setter
			}
		}
	}()
	return getGetter, getSetter, add, del
}
<|endoftext|>