<commit_before>package graph

import (
	"errors"
	"fmt"
	"testing"

	"github.com/pachyderm/pachyderm/src/pps"
	"github.com/pachyderm/pachyderm/src/pps/parse"
	"github.com/stretchr/testify/require"
)

func TestGetNameToNodeInfo(t *testing.T) {
	pipeline, err := parse.NewParser().ParsePipeline("../parse/testdata/basic", "")
	require.NoError(t, err)
	nodes := pps.GetNameToNode(pipeline)
	nodeInfos, err := GetNameToNodeInfo(nodes)
	require.NoError(t, err)
	require.Equal(t, []string{"bar-node"}, nodeInfos["baz-node-bar-in-bar-out-in"].Parents)
}

func TestBuild(t *testing.T) {
	intC := make(chan int, 8)
	nameToNodeInfo := map[string]*NodeInfo{
		"1": &NodeInfo{
			Parents: []string{},
		},
		"2": &NodeInfo{
			Parents: []string{},
		},
		"3-1": &NodeInfo{
			Parents: []string{
				"1",
				"2",
			},
		},
		"3-2": &NodeInfo{
			Parents: []string{
				"1",
				"2",
			},
		},
		"3-3": &NodeInfo{
			Parents: []string{
				"1",
				"2",
			},
		},
		"4-1": &NodeInfo{
			Parents: []string{
				"3-1",
				"3-2",
				"3-3",
			},
		},
		"4-2": &NodeInfo{
			Parents: []string{
				"3-1",
				"3-2",
				"3-3",
			},
		},
		"5": &NodeInfo{
			Parents: []string{
				"4-1",
				"4-2",
			},
		},
	}
	nameToNodeFunc := map[string]func() error{
		"1":   testNodeFunc(intC, "1", 1, ""),
		"2":   testNodeFunc(intC, "2", 2, ""),
		"3-1": testNodeFunc(intC, "3-1", 3, ""),
		"3-2": testNodeFunc(intC, "3-2", 4, ""),
		"3-3": testNodeFunc(intC, "3-3", 5, ""),
		"4-1": testNodeFunc(intC, "4-1", 6, ""),
		"4-2": testNodeFunc(intC, "4-2", 7, ""),
		"5":   testNodeFunc(intC, "5", 8, ""),
	}

	run, err := build(newTestNodeErrorRecorder(), nameToNodeInfo, nameToNodeFunc)
	require.NoError(t, err)
	run.Do()

	i := <-intC
	require.True(t, i == 1 || i == 2)
	i = <-intC
	require.True(t, i == 1 || i == 2)
	i = <-intC
	require.True(t, i == 3 || i == 4 || i == 5)
	i = <-intC
	require.True(t, i == 3 || i == 4 || i == 5)
	i = <-intC
	require.True(t, i == 3 || i == 4 || i == 5)
	i = <-intC
	require.True(t, i == 6 || i == 7)
	i = <-intC
	require.True(t, i == 6 || i == 7)
	i = <-intC
	require.True(t, i == 8)
}

func testNodeFunc(intC chan int, nodeName string, i int, errString string) func() error {
	var err error
	if errString != "" {
		err = errors.New(errString)
	}
	return func() error {
		intC <- i
		fmt.Printf("ran %s, sent %d, returning %v\n", nodeName, i, err)
		return err
	}
}

type testNodeErrorRecorder struct {
	stringC chan string
}

func newTestNodeErrorRecorder() *testNodeErrorRecorder {
	return &testNodeErrorRecorder{make(chan string)}
}

func (t *testNodeErrorRecorder) Record(nodeName string, err error) {
	t.stringC <- fmt.Sprintf("%s:%s", nodeName, err.Error())
}

func (t *testNodeErrorRecorder) strings() []string {
	close(t.stringC)
	var slice []string
	for s := range t.stringC {
		slice = append(slice, s)
	}
	return slice
}
<commit_msg>TestBuildWithError<commit_after>package graph

import (
	"errors"
	"fmt"
	"sync"
	"sync/atomic"
	"testing"

	"github.com/pachyderm/pachyderm/src/pps"
	"github.com/pachyderm/pachyderm/src/pps/parse"
	"github.com/stretchr/testify/require"
)

func TestGetNameToNodeInfo(t *testing.T) {
	pipeline, err := parse.NewParser().ParsePipeline("../parse/testdata/basic", "")
	require.NoError(t, err)
	nodes := pps.GetNameToNode(pipeline)
	nodeInfos, err := GetNameToNodeInfo(nodes)
	require.NoError(t, err)
	require.Equal(t, []string{"bar-node"}, nodeInfos["baz-node-bar-in-bar-out-in"].Parents)
}

func TestBuild(t *testing.T) {
	intC := make(chan int, 8)
	nameToNodeInfo := map[string]*NodeInfo{
		"1": &NodeInfo{
			Parents: []string{},
		},
		"2": &NodeInfo{
			Parents: []string{},
		},
		"3-1": &NodeInfo{
			Parents: []string{
				"1",
				"2",
			},
		},
		"3-2": &NodeInfo{
			Parents: []string{
				"1",
				"2",
			},
		},
		"3-3": &NodeInfo{
			Parents: []string{
				"1",
				"2",
			},
		},
		"4-1": &NodeInfo{
			Parents: []string{
				"3-1",
				"3-2",
				"3-3",
			},
		},
		"4-2": &NodeInfo{
			Parents: []string{
				"3-1",
				"3-2",
				"3-3",
			},
		},
		"5": &NodeInfo{
			Parents: []string{
				"4-1",
				"4-2",
			},
		},
	}
	counter := int32(0)
	nameToNodeFunc := map[string]func() error{
		"1":   testNodeFunc(&counter, intC, "1", 1, ""),
		"2":   testNodeFunc(&counter, intC, "2", 2, ""),
		"3-1": testNodeFunc(&counter, intC, "3-1", 3, ""),
		"3-2": testNodeFunc(&counter, intC, "3-2", 4, ""),
		"3-3": testNodeFunc(&counter, intC, "3-3", 5, ""),
		"4-1": testNodeFunc(&counter, intC, "4-1", 6, ""),
		"4-2": testNodeFunc(&counter, intC, "4-2", 7, ""),
		"5":   testNodeFunc(&counter, intC, "5", 8, ""),
	}

	run, err := build(newTestNodeErrorRecorder(), nameToNodeInfo, nameToNodeFunc)
	require.NoError(t, err)
	run.Do()

	require.Equal(t, int32(8), counter)
	i := <-intC
	require.True(t, i == 1 || i == 2)
	i = <-intC
	require.True(t, i == 1 || i == 2)
	i = <-intC
	require.True(t, i == 3 || i == 4 || i == 5)
	i = <-intC
	require.True(t, i == 3 || i == 4 || i == 5)
	i = <-intC
	require.True(t, i == 3 || i == 4 || i == 5)
	i = <-intC
	require.True(t, i == 6 || i == 7)
	i = <-intC
	require.True(t, i == 6 || i == 7)
	i = <-intC
	require.True(t, i == 8)
}

func TestBuildWithError(t *testing.T) {
	intC := make(chan int, 5)
	nameToNodeInfo := map[string]*NodeInfo{
		"1": &NodeInfo{
			Parents: []string{},
		},
		"2": &NodeInfo{
			Parents: []string{},
		},
		"3-1": &NodeInfo{
			Parents: []string{
				"1",
				"2",
			},
		},
		"3-2": &NodeInfo{
			Parents: []string{
				"1",
				"2",
			},
		},
		"3-3": &NodeInfo{
			Parents: []string{
				"1",
				"2",
			},
		},
		"4-1": &NodeInfo{
			Parents: []string{
				"3-1",
				"3-2",
				"3-3",
			},
		},
		"4-2": &NodeInfo{
			Parents: []string{
				"3-1",
				"3-2",
				"3-3",
			},
		},
		"5": &NodeInfo{
			Parents: []string{
				"4-1",
				"4-2",
			},
		},
	}
	counter := int32(0)
	nameToNodeFunc := map[string]func() error{
		"1":   testNodeFunc(&counter, intC, "1", 1, ""),
		"2":   testNodeFunc(&counter, intC, "2", 2, ""),
		"3-1": testNodeFunc(&counter, intC, "3-1", 3, "error"),
		"3-2": testNodeFunc(&counter, intC, "3-2", 4, ""),
		"3-3": testNodeFunc(&counter, intC, "3-3", 5, ""),
		"4-1": testNodeFunc(&counter, intC, "4-1", 6, ""),
		"4-2": testNodeFunc(&counter, intC, "4-2", 7, ""),
		"5":   testNodeFunc(&counter, intC, "5", 8, ""),
	}

	testNodeErrorRecorder := newTestNodeErrorRecorder()
	run, err := build(testNodeErrorRecorder, nameToNodeInfo, nameToNodeFunc)
	require.NoError(t, err)
	run.Do()

	require.Equal(t, int32(5), counter)
	i := <-intC
	require.True(t, i == 1 || i == 2)
	i = <-intC
	require.True(t, i == 1 || i == 2)
	i = <-intC
	require.True(t, i == 3 || i == 4 || i == 5)
	i = <-intC
	require.True(t, i == 3 || i == 4 || i == 5)
	i = <-intC
	require.True(t, i == 3 || i == 4 || i == 5)

	require.Equal(t, []string{"3-1:error"}, testNodeErrorRecorder.slice)
}

func testNodeFunc(counter *int32, intC chan int, nodeName string, i int, errString string) func() error {
	var err error
	if errString != "" {
		err = errors.New(errString)
	}
	return func() error {
		atomic.AddInt32(counter, 1)
		intC <- i
		fmt.Printf("ran %s, sent %d, returning %v\n", nodeName, i, err)
		return err
	}
}

type testNodeErrorRecorder struct {
	slice []string
	lock  *sync.Mutex
}

func newTestNodeErrorRecorder() *testNodeErrorRecorder {
	return &testNodeErrorRecorder{make([]string, 0), &sync.Mutex{}}
}

func (t *testNodeErrorRecorder) Record(nodeName string, err error) {
	t.lock.Lock()
	defer t.lock.Unlock()
	t.slice = append(t.slice, fmt.Sprintf("%s:%s", nodeName, err.Error()))
}
<|endoftext|>


<commit_before>package mario

import (
	"fmt"
	neural "github.com/poseidon4o/go-neural/src/neural"
	util "github.com/poseidon4o/go-neural/src/util"
	"math"
	"math/rand"
	"sort"
)

type NeuronName int

const (
	posX      NeuronName = iota
	posY      NeuronName = iota
	velY      NeuronName = iota
	velX      NeuronName = iota
	H1        NeuronName = iota
	H2        NeuronName = iota
	H3        NeuronName = iota
	H4        NeuronName = iota
	H5        NeuronName = iota
	H6        NeuronName = iota
	H7        NeuronName = iota
	H8        NeuronName = iota
	R1        NeuronName = iota
	R2        NeuronName = iota
	R3        NeuronName = iota
	R4        NeuronName = iota
	R5        NeuronName = iota
	R6        NeuronName = iota
	R7        NeuronName = iota
	R8        NeuronName = iota
	jump      NeuronName = iota
	xMove     NeuronName = iota
	NRN_COUNT int        = iota
)

func nrn(name NeuronName) int {
	return int(name)
}

type MarioNode struct {
	fig        *Figure
	brain      *neural.Net
	bestX      float64
	idleX      float64
	dead       bool
	idleFrames uint32
}

type MarioCol []MarioNode

func (figs MarioCol) Len() int {
	return len(figs)
}

func (figs MarioCol) Less(c, r int) bool {
	return figs[c].bestX > figs[r].bestX
}

func (figs MarioCol) Swap(c, r int) {
	figs[c], figs[r] = figs[r], figs[c]
}

type Mario struct {
	figures  MarioCol
	lvl      Level
	drawCb   func(pos, size *util.Vector, color uint32)
	drawSize int
}

func (m *Mario) Complete() float64 {
	return m.figures[0].bestX / m.lvl.size.X
}

func (m *Mario) Done() bool {
	return false
}

func (m *Mario) SetDrawRectCb(cb func(pos, size *util.Vector, color uint32)) {
	m.drawCb = cb
}

func (m *Mario) LogicTick(dt float64) {
	m.lvl.Step(dt)
	sort.Sort(m.figures)

	wg := make(chan struct{}, len(m.figures))

	stepC := func(r int) {
		m.checkStep(r)
		m.mutateStep(r)
		m.thnikStep(r)
		wg <- struct{}{}
	}

	for c := range m.figures {
		go stepC(c)
	}

	for c := 0; c < len(m.figures); c++ {
		<-wg
	}
}

func (m *Mario) Jump() {
	m.figures[0].fig.Jump()
}

func (m *Mario) Move(dir int) {
	m.figures[0].fig.Move(dir)
}

func (m *Mario) Figs() MarioCol {
	return m.figures
}

func NewMario(figCount int, size *util.Vector) *Mario {
	fmt.Println("")
	level := NewLevel(int(size.X), int(size.Y))
	level.AddFigures(figCount)

	nets := make([]*neural.Net, figCount, figCount)
	for c := range nets {
		nets[c] = neural.NewNet(NRN_COUNT)

		for r := 0; r < (nrn(H8) - nrn(H1)); r++ {
			// input to H
			*nets[c].Synapse(nrn(posX), r+nrn(H1)) = 0.0
			*nets[c].Synapse(nrn(posY), r+nrn(H1)) = 0.0
			*nets[c].Synapse(nrn(velX), r+nrn(H1)) = 0.0
			*nets[c].Synapse(nrn(velY), r+nrn(H1)) = 0.0

			// R to output
			*nets[c].Synapse(r+nrn(R1), nrn(jump)) = 0.0
			*nets[c].Synapse(r+nrn(R1), nrn(xMove)) = 0.0
		}

		for r := 0; r < (nrn(H8) - nrn(H1)); r++ {
			for q := 0; q < (nrn(H8) - nrn(H1)); q++ {
				*nets[c].Synapse(r+nrn(H1), q+nrn(R1)) = 0.0
			}
		}

		nets[c].Randomize()
	}

	figs := make(MarioCol, figCount, figCount)
	for c := range figs {
		figs[c].brain = nets[c]
		figs[c].dead = false
		figs[c].bestX = 0
		figs[c].fig = level.figures[c]
	}

	return &Mario{
		figures:  figs,
		lvl:      *level,
		drawCb:   func(pos, size *util.Vector, color uint32) {},
		drawSize: 5,
	}
}

func (m *Mario) DrawTick() {
	var (
		red   = uint32(0xffff0000)
		green = uint32(0xff00ff00)
		blue  = uint32(0xff0000ff)
	)

	blSize := util.NewVector(float64(BLOCK_SIZE), float64(BLOCK_SIZE))
	blSizeSmall := blSize.Scale(0.5)

	translate := util.NewVector(6, 6)

	size := util.NewVector(float64(m.drawSize), float64(m.drawSize))

	for c := range m.lvl.blocks {
		for r := range m.lvl.blocks[c] {
			if m.lvl.blocks[c][r] != nil {
				m.drawCb(m.lvl.blocks[c][r], blSize, red)
				m.drawCb(m.lvl.blocks[c][r].Add(translate), blSizeSmall, green)
			}
		}
	}

	for c := range m.figures {
		m.drawCb(m.figures[c].fig.pos.Add(size.Scale(0.5).Neg()), size, blue)
	}
}

func (m *Mario) checkStep(c int) {
	fig := m.figures[c].fig

	if fig.nextPos.Y > m.lvl.size.Y || fig.nextPos.Y < 0 {
		m.figures[c].dead = true
		return
	}

	if fig.nextPos.X < 0 {
		fig.nextPos.X = 0
	} else if fig.nextPos.X > m.lvl.size.X {
		fig.nextPos.X = m.lvl.size.X
	}

	block := m.lvl.FloorAt(&fig.pos)

	if block == nil || fig.nextPos.Y < block.Y {
		fig.pos.Y = fig.nextPos.Y
	} else {
		// m.drawCb(block, util.NewVector(float64(BLOCK_SIZE), float64(BLOCK_SIZE)), 0xff00ffff)
		// land on block
		fig.vel.Y = 0
		fig.pos.Y = block.Y - 0.1
		fig.Land()
	}

	if fig.pos.X != fig.nextPos.X {
		fig.nextPos.Y = fig.pos.Y
		colide := m.lvl.CubeAt(&fig.nextPos)
		if colide != nil {
			// m.drawCb(colide, util.NewVector(float64(BLOCK_SIZE), float64(BLOCK_SIZE)), 0xff00ffff)
			if fig.pos.X < fig.nextPos.X {
				// collide right
				fig.pos.X = colide.X - 0.1
			} else {
				// colide left
				fig.pos.X = colide.X + float64(BLOCK_SIZE) + 0.1
			}
		} else {
			fig.pos.X = fig.nextPos.X
		}
	}

}

func (m *Mario) thnikStep(c int) {
	discreteX := float64(int(m.figures[c].fig.pos.X / float64(OBSTACLE_SPACING*BLOCK_SIZE)))
	m.figures[c].brain.Stimulate(nrn(posX), discreteX)

	m.figures[c].brain.Stimulate(nrn(posY), m.figures[c].fig.pos.Y)
	m.figures[c].brain.Stimulate(nrn(velX), m.figures[c].fig.vel.X)
	m.figures[c].brain.Stimulate(nrn(velY), m.figures[c].fig.vel.Y)

	m.figures[c].brain.Step()

	if m.figures[c].brain.ValueOf(nrn(jump)) > 0.9 {
		m.figures[c].fig.Jump()
	}

	xMoveValue := m.figures[c].brain.ValueOf(nrn(xMove))
	if math.Abs(xMoveValue) > 0.9 {
		m.figures[c].fig.Move(int(xMoveValue * 10))
	}

	m.figures[c].brain.Clear()
}

const idleThreshold uint32 = 2000

func (m *Mario) randNet() *neural.Net {
	cutOff := 10.0
	idx := 0
	for {
		r := rand.ExpFloat64()
		if r <= cutOff {
			idx = int((r * float64(len(m.figures))) / cutOff)
			break
		}
	}
	return m.figures[idx].brain
}

func (m *Mario) mutateStep(c int) {

	if m.figures[c].dead {
		m.figures[c].dead = false
		m.figures[c].fig.pos = *m.lvl.NewFigurePos()
		m.figures[c].fig.vel = *util.NewVector(0, 0)

		if m.figures[c].idleFrames >= idleThreshold {
			m.figures[c].brain.Mutate(0.75)
			m.figures[c].bestX *= 0.25
		} else {
			swapChance := (float64(c) / float64(len(m.figures))) * 2.0
			if neural.Chance(swapChance) {
				*m.figures[c].brain = *neural.Cross2(m.randNet(), m.randNet())
			}
			m.figures[c].brain.MutateWithMagnitude(0.01, 0.1)
			m.figures[c].bestX *= 0.975
		}

		m.figures[c].idleFrames = 0
		m.figures[c].idleX = 0
	} else {
		if m.figures[c].fig.pos.X > m.figures[c].bestX {
			m.figures[c].bestX = m.figures[c].fig.pos.X
		}

		if m.figures[c].fig.pos.X > m.figures[c].idleX {
			m.figures[c].idleX = m.figures[c].fig.pos.X
		} else {
			m.figures[c].idleFrames++
			if m.figures[c].idleFrames >= idleThreshold {
				m.figures[c].dead = true
				// c--
			}
		}

	}
}
<commit_msg>Make mario action threshold 0.95<commit_after>package mario

import (
	"fmt"
	neural "github.com/poseidon4o/go-neural/src/neural"
	util "github.com/poseidon4o/go-neural/src/util"
	"math"
	"math/rand"
	"sort"
)

type NeuronName int

const (
	posX      NeuronName = iota
	posY      NeuronName = iota
	velY      NeuronName = iota
	velX      NeuronName = iota
	H1        NeuronName = iota
	H2        NeuronName = iota
	H3        NeuronName = iota
	H4        NeuronName = iota
	H5        NeuronName = iota
	H6        NeuronName = iota
	H7        NeuronName = iota
	H8        NeuronName = iota
	R1        NeuronName = iota
	R2        NeuronName = iota
	R3        NeuronName = iota
	R4        NeuronName = iota
	R5        NeuronName = iota
	R6        NeuronName = iota
	R7        NeuronName = iota
	R8        NeuronName = iota
	jump      NeuronName = iota
	xMove     NeuronName = iota
	NRN_COUNT int        = iota
)

func nrn(name NeuronName) int {
	return int(name)
}

type MarioNode struct {
	fig        *Figure
	brain      *neural.Net
	bestX      float64
	idleX      float64
	dead       bool
	idleFrames uint32
}

type MarioCol []MarioNode

func (figs MarioCol) Len() int {
	return len(figs)
}

func (figs MarioCol) Less(c, r int) bool {
	return figs[c].bestX > figs[r].bestX
}

func (figs MarioCol) Swap(c, r int) {
	figs[c], figs[r] = figs[r], figs[c]
}

type Mario struct {
	figures  MarioCol
	lvl      Level
	drawCb   func(pos, size *util.Vector, color uint32)
	drawSize int
}

func (m *Mario) Complete() float64 {
	return m.figures[0].bestX / m.lvl.size.X
}

func (m *Mario) Done() bool {
	return false
}

func (m *Mario) SetDrawRectCb(cb func(pos, size *util.Vector, color uint32)) {
	m.drawCb = cb
}

func (m *Mario) LogicTick(dt float64) {
	m.lvl.Step(dt)
	sort.Sort(m.figures)

	wg := make(chan struct{}, len(m.figures))

	stepC := func(r int) {
		m.checkStep(r)
		m.mutateStep(r)
		m.thnikStep(r)
		wg <- struct{}{}
	}

	for c := range m.figures {
		go stepC(c)
	}

	for c := 0; c < len(m.figures); c++ {
		<-wg
	}
}

func (m *Mario) Jump() {
	m.figures[0].fig.Jump()
}

func (m *Mario) Move(dir int) {
	m.figures[0].fig.Move(dir)
}

func (m *Mario) Figs() MarioCol {
	return m.figures
}

func NewMario(figCount int, size *util.Vector) *Mario {
	fmt.Println("")
	level := NewLevel(int(size.X), int(size.Y))
	level.AddFigures(figCount)

	nets := make([]*neural.Net, figCount, figCount)
	for c := range nets {
		nets[c] = neural.NewNet(NRN_COUNT)

		for r := 0; r < (nrn(H8) - nrn(H1)); r++ {
			// input to H
			*nets[c].Synapse(nrn(posX), r+nrn(H1)) = 0.0
			*nets[c].Synapse(nrn(posY), r+nrn(H1)) = 0.0
			*nets[c].Synapse(nrn(velX), r+nrn(H1)) = 0.0
			*nets[c].Synapse(nrn(velY), r+nrn(H1)) = 0.0

			// R to output
			*nets[c].Synapse(r+nrn(R1), nrn(jump)) = 0.0
			*nets[c].Synapse(r+nrn(R1), nrn(xMove)) = 0.0
		}

		for r := 0; r < (nrn(H8) - nrn(H1)); r++ {
			for q := 0; q < (nrn(H8) - nrn(H1)); q++ {
				*nets[c].Synapse(r+nrn(H1), q+nrn(R1)) = 0.0
			}
		}

		nets[c].Randomize()
	}

	figs := make(MarioCol, figCount, figCount)
	for c := range figs {
		figs[c].brain = nets[c]
		figs[c].dead = false
		figs[c].bestX = 0
		figs[c].fig = level.figures[c]
	}

	return &Mario{
		figures:  figs,
		lvl:      *level,
		drawCb:   func(pos, size *util.Vector, color uint32) {},
		drawSize: 5,
	}
}

func (m *Mario) DrawTick() {
	var (
		red   = uint32(0xffff0000)
		green = uint32(0xff00ff00)
		blue  = uint32(0xff0000ff)
	)

	blSize := util.NewVector(float64(BLOCK_SIZE), float64(BLOCK_SIZE))
	blSizeSmall := blSize.Scale(0.5)

	translate := util.NewVector(6, 6)

	size := util.NewVector(float64(m.drawSize), float64(m.drawSize))

	for c := range m.lvl.blocks {
		for r := range m.lvl.blocks[c] {
			if m.lvl.blocks[c][r] != nil {
				m.drawCb(m.lvl.blocks[c][r], blSize, red)
				m.drawCb(m.lvl.blocks[c][r].Add(translate), blSizeSmall, green)
			}
		}
	}

	for c := range m.figures {
		m.drawCb(m.figures[c].fig.pos.Add(size.Scale(0.5).Neg()), size, blue)
	}
}

func (m *Mario) checkStep(c int) {
	fig := m.figures[c].fig

	if fig.nextPos.Y > m.lvl.size.Y || fig.nextPos.Y < 0 {
		m.figures[c].dead = true
		return
	}

	if fig.nextPos.X < 0 {
		fig.nextPos.X = 0
	} else if fig.nextPos.X > m.lvl.size.X {
		fig.nextPos.X = m.lvl.size.X
	}

	block := m.lvl.FloorAt(&fig.pos)

	if block == nil || fig.nextPos.Y < block.Y {
		fig.pos.Y = fig.nextPos.Y
	} else {
		// m.drawCb(block, util.NewVector(float64(BLOCK_SIZE), float64(BLOCK_SIZE)), 0xff00ffff)
		// land on block
		fig.vel.Y = 0
		fig.pos.Y = block.Y - 0.1
		fig.Land()
	}

	if fig.pos.X != fig.nextPos.X {
		fig.nextPos.Y = fig.pos.Y
		colide := m.lvl.CubeAt(&fig.nextPos)
		if colide != nil {
			// m.drawCb(colide, util.NewVector(float64(BLOCK_SIZE), float64(BLOCK_SIZE)), 0xff00ffff)
			if fig.pos.X < fig.nextPos.X {
				// collide right
				fig.pos.X = colide.X - 0.1
			} else {
				// colide left
				fig.pos.X = colide.X + float64(BLOCK_SIZE) + 0.1
			}
		} else {
			fig.pos.X = fig.nextPos.X
		}
	}

}

func (m *Mario) thnikStep(c int) {
	discreteX := float64(int(m.figures[c].fig.pos.X / float64(OBSTACLE_SPACING*BLOCK_SIZE)))
	m.figures[c].brain.Stimulate(nrn(posX), discreteX)

	m.figures[c].brain.Stimulate(nrn(posY), m.figures[c].fig.pos.Y)
	m.figures[c].brain.Stimulate(nrn(velX), m.figures[c].fig.vel.X)
	m.figures[c].brain.Stimulate(nrn(velY), m.figures[c].fig.vel.Y)

	m.figures[c].brain.Step()

	if m.figures[c].brain.ValueOf(nrn(jump)) > 0.95 {
		m.figures[c].fig.Jump()
	}

	xMoveValue := m.figures[c].brain.ValueOf(nrn(xMove))
	if math.Abs(xMoveValue) > 0.95 {
		m.figures[c].fig.Move(int(xMoveValue * 10))
	}

	m.figures[c].brain.Clear()
}

const idleThreshold uint32 = 2000

func (m *Mario) randNet() *neural.Net {
	cutOff := 10.0
	idx := 0
	for {
		r := rand.ExpFloat64()
		if r <= cutOff {
			idx = int((r * float64(len(m.figures))) / cutOff)
			break
		}
	}
	return m.figures[idx].brain
}

func (m *Mario) mutateStep(c int) {

	if m.figures[c].dead {
		m.figures[c].dead = false
		m.figures[c].fig.pos = *m.lvl.NewFigurePos()
		m.figures[c].fig.vel = *util.NewVector(0, 0)

		if m.figures[c].idleFrames >= idleThreshold {
			m.figures[c].brain.Mutate(0.75)
			m.figures[c].bestX *= 0.25
		} else {
			swapChance := (float64(c) / float64(len(m.figures))) * 2.0
			if neural.Chance(swapChance) {
				*m.figures[c].brain = *neural.Cross2(m.randNet(), m.randNet())
			}
			m.figures[c].brain.MutateWithMagnitude(0.01, 0.1)
			m.figures[c].bestX *= 0.975
		}

		m.figures[c].idleFrames = 0
		m.figures[c].idleX = 0
	} else {
		if m.figures[c].fig.pos.X > m.figures[c].bestX {
			m.figures[c].bestX = m.figures[c].fig.pos.X
		}

		if m.figures[c].fig.pos.X > m.figures[c].idleX {
			m.figures[c].idleX = m.figures[c].fig.pos.X
		} else {
			m.figures[c].idleFrames++
			if m.figures[c].idleFrames >= idleThreshold {
				m.figures[c].dead = true
				// c--
			}
		}

	}
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
)

func main() {
	fmt.Printf("Starting Ansel control program...")
}
<commit_msg>Reading sensor data over serial<commit_after>package main

import (
	"fmt"

	"github.com/tarm/serial"

	"bufio"
	"log"
)

func main() {
	fmt.Printf("Starting Ansel control program...\n")

	c := &serial.Config{Name: "/dev/ttyUSB1", Baud: 9600}
	s, err := serial.OpenPort(c)

	if err != nil {
		log.Fatal(err)
	}

	reader := bufio.NewReader(s)

	for {
		reply, err := reader.ReadString('\n')
		if err != nil {
			log.Fatal(err)
		}

		fmt.Printf(reply)
	}

}
<|endoftext|>


<commit_before>// +build ignore

package main

import (
	"bytes"
	"flag"
	"fmt"
	"go/format"
	"io"
	"io/ioutil"
	"net"
	"net/http"
	"os"
	"regexp"
	"sort"
	"strings"

	"github.com/miekg/dns"
)

var (
	url, whois  string
	v, quick    bool
	concurrency int
	dnsClient   *dns.Client
)

type ZoneWhois struct {
	zone   string
	server string
	msg    string
	viaDNS bool
}

var exceptions = map[string]ZoneWhois{
	"bv": ZoneWhois{server: "whois.norid.no", msg: "http://www.norid.no/navnepolitikk.en.html#link1"},
	"nr": ZoneWhois{server: "cenpac.net.nr", msg: "http://cenpac.net.nr/dns/"},
	"sj": ZoneWhois{server: "whois.norid.no", msg: "http://www.norid.no/navnepolitikk.en.html#link1"},
}

func init() {
	flag.StringVar(
		&url,
		"url",
		"http://www.internic.net/domain/root.zone",
		"URL of the IANA root zone file. If empty, read from stdin",
	)
	flag.StringVar(
		&whois,
		"whois",
		"whois.iana.org",
		"Address of the root whois server to query",
	)
	flag.BoolVar(&v, "v", false, "verbose output (to stderr)")
	flag.BoolVar(&quick, "quick", false, "Only work on a subset of zones")
	flag.IntVar(&concurrency, "concurrency", 8, "Set maximum number of concurrent requests")
}

func main() {
	flag.Parse()

	if err := main1(); err != nil {
		fmt.Fprintln(os.Stderr, err)
		os.Exit(1)
	}
}

func main1() error {
	var input io.Reader = os.Stdin

	if url != "" {
		fmt.Fprintf(os.Stderr, "Fetching %s\n", url)
		res, err := http.Get(url)
		if err != nil {
			return err
		}
		if res.StatusCode != http.StatusOK {
			return fmt.Errorf("Bad GET status for %s: %d", url, res.Status)
		}
		input = res.Body
		defer res.Body.Close()
	}

	zoneMap := make(map[string]ZoneWhois)

	fmt.Fprintf(os.Stderr, "Parsing root.zone\n")
	for token := range dns.ParseZone(input, "", "") {
		if token.Error != nil {
			return token.Error
		}
		header := token.RR.Header()
		if header.Rrtype != dns.TypeNS {
			continue
		}
		domain := strings.TrimSuffix(strings.ToLower(header.Name), ".")
		if domain == "" {
			continue
		}
		zoneMap[domain] = ZoneWhois{}
	}

	// Sort zones
	i := 0
	zones := make([]string, len(zoneMap))
	for zone, _ := range zoneMap {
		zones[i] = zone
		i++
	}
	sort.Strings(zones)

	// Quick for debugging?
	if quick {
		zones = zones[0:50]
	}

	// Get whois servers for each zone
	re := regexp.MustCompile("whois:\\s+([a-z0-9\\-\\.]+)")
	c := make(chan ZoneWhois, len(zones))
	limiter := make(chan struct{}, concurrency) // semaphore to limit concurrency

	fmt.Fprintf(os.Stderr, "Querying whois and DNS for %d zones\n", len(zones))

	// Create 1 goroutine for each zone
	for i, zone := range zones {
		go func(zone string, i int) {
			limiter <- struct{}{} // acquire semaphore

			zw := ZoneWhois{zone, "", "", false}
			defer func() { // send result and release semaphore
				c <- zw
				<-limiter
			}()

			res, err := querySocket(whois, zone)
			if err != nil {
				return
			}

			// Look for whois: string
			matches := re.FindStringSubmatch(res)
			if matches != nil {
				zw.server = matches[1]
				zw.msg = fmt.Sprintf("whois -h %s %s", whois, zw.zone)
				return
			}

			// Check whois-servers.net
			host := zone + ".whois-servers.net"
			zw.server, err = queryCNAME(host)
			if zw.server != "" {
				zw.msg = fmt.Sprintf("dig %s CNAME", host)
				zw.viaDNS = true
				return
			}

			// Check exception list
			zw = exceptions[zone]
			zw.zone = zone
		}(zone, i)
	}

	numMissing, numDNS := 0, 0

	// Collect from goroutines
	for i := 0; i < len(zones); i++ {
		select {
		case zw := <-c:
			if zw.msg == "" {
				fmt.Fprintf(os.Stderr, "No match for %s\n", zw.zone)
			} else if v && zw.msg != "" {
				fmt.Fprintf(os.Stderr, "%s\t\t%s\n", zw.msg, zw.server)
			}

			zw.server = strings.TrimSuffix(strings.ToLower(zw.server), ".")
			zoneMap[zw.zone] = zw

			if zw.server == "" {
				numMissing++
			}
			if zw.viaDNS {
				numDNS++
			}
		}
	}

	// Print stats
	fmt.Fprintf(os.Stderr, "Zones with whois servers:    %d (%d via DNS)\n",
		len(zones)-numMissing, numDNS)
	fmt.Fprintf(os.Stderr, "Zones without whois servers: %d (%.0f%%)\n",
		numMissing, float32(numMissing)/float32(len(zones))*float32(100))
	fmt.Fprintf(os.Stderr, "Total number of zones:       %d\n",
		len(zones))

	// Generate zones.go
	buf := new(bytes.Buffer)
	const header = `// Generated by go run tools/generate.go > zones.go
// DO NOT EDIT

package whois

var zones = map[string]string{
`
	const footer = `}`

	buf.WriteString(header)
	for _, zone := range zones {
		zw := zoneMap[zone]
		fmt.Fprintf(buf, "\t%q: %q, // %s\n", zw.zone, zw.server, zw.msg)
	}
	buf.WriteString(footer)

	// Write to stdout
	formatted, err := format.Source(buf.Bytes())
	if err != nil {
		return err
	}
	_, err = os.Stdout.Write(formatted)
	return err
}

func querySocket(addr, query string) (string, error) {
	if !strings.Contains(addr, ":") {
		addr = addr + ":43"
	}
	c, err := net.Dial("tcp", addr)
	if err != nil {
		return "", err
	}
	defer c.Close()
	if _, err = fmt.Fprint(c, query, "\r\n"); err != nil {
		return "", err
	}
	res, err := ioutil.ReadAll(c)
	if err != nil {
		return "", err
	}
	return string(res), nil
}

func queryCNAME(host string) (string, error) {
	m := new(dns.Msg)
	m.RecursionDesired = true // embedded field
	m.SetQuestion(dns.Fqdn(host), dns.TypeCNAME)
	dnsClient = new(dns.Client)
	r, _, err := dnsClient.Exchange(m, "8.8.8.8:53")
	if err != nil {
		return "", err
	}
	if r.Rcode == dns.RcodeSuccess && r.Answer != nil && len(r.Answer) >= 1 {
		if cname, ok := r.Answer[0].(*dns.CNAME); ok {
			return cname.Target, nil
		}
	}
	return "", nil
}
<commit_msg>New whois exceptions.<commit_after>// +build ignore

package main

import (
	"bytes"
	"flag"
	"fmt"
	"go/format"
	"io"
	"io/ioutil"
	"net"
	"net/http"
	"os"
	"regexp"
	"sort"
	"strings"

	"github.com/miekg/dns"
)

var (
	url, whois  string
	v, quick    bool
	concurrency int
	dnsClient   *dns.Client
)

type ZoneWhois struct {
	zone   string
	server string
	msg    string
	viaDNS bool
}

var exceptions = map[string]ZoneWhois{
	"bv":         ZoneWhois{server: "whois.norid.no", msg: "http://www.norid.no/navnepolitikk.en.html#link1"},
	"gmo":        ZoneWhois{server: "whois.gmoregistry.net", msg: "http://en.wikipedia.org/wiki/.gmo"},
	"nr":         ZoneWhois{server: "cenpac.net.nr", msg: "http://cenpac.net.nr/dns/"},
	"sj":         ZoneWhois{server: "whois.norid.no", msg: "http://www.norid.no/navnepolitikk.en.html#link1"},
	"xn--90a3ac": ZoneWhois{server: "whois.rnids.rs", msg: "http://en.wikipedia.org/wiki/.xn--90a3ac"},
	"za":         ZoneWhois{server: "whois.registry.net.za", msg: "http://en.wikipedia.org/wiki/.za"},
}

func init() {
	flag.StringVar(
		&url,
		"url",
		"http://www.internic.net/domain/root.zone",
		"URL of the IANA root zone file. If empty, read from stdin",
	)
	flag.StringVar(
		&whois,
		"whois",
		"whois.iana.org",
		"Address of the root whois server to query",
	)
	flag.BoolVar(&v, "v", false, "verbose output (to stderr)")
	flag.BoolVar(&quick, "quick", false, "Only work on a subset of zones")
	flag.IntVar(&concurrency, "concurrency", 8, "Set maximum number of concurrent requests")
}

func main() {
	flag.Parse()

	if err := main1(); err != nil {
		fmt.Fprintln(os.Stderr, err)
		os.Exit(1)
	}
}

func main1() error {
	var input io.Reader = os.Stdin

	if url != "" {
		fmt.Fprintf(os.Stderr, "Fetching %s\n", url)
		res, err := http.Get(url)
		if err != nil {
			return err
		}
		if res.StatusCode != http.StatusOK {
			return fmt.Errorf("Bad GET status for %s: %d", url, res.Status)
		}
		input = res.Body
		defer res.Body.Close()
	}

	zoneMap := make(map[string]ZoneWhois)

	fmt.Fprintf(os.Stderr, "Parsing root.zone\n")
	for token := range dns.ParseZone(input, "", "") {
		if token.Error != nil {
			return token.Error
		}
		header := token.RR.Header()
		if header.Rrtype != dns.TypeNS {
			continue
		}
		domain := strings.TrimSuffix(strings.ToLower(header.Name), ".")
		if domain == "" {
			continue
		}
		zoneMap[domain] = ZoneWhois{}
	}

	// Sort zones
	i := 0
	zones := make([]string, len(zoneMap))
	for zone, _ := range zoneMap {
		zones[i] = zone
		i++
	}
	sort.Strings(zones)

	// Quick for debugging?
	if quick {
		zones = zones[0:50]
	}

	// Get whois servers for each zone
	re := regexp.MustCompile("whois:\\s+([a-z0-9\\-\\.]+)")
	c := make(chan ZoneWhois, len(zones))
	limiter := make(chan struct{}, concurrency) // semaphore to limit concurrency

	fmt.Fprintf(os.Stderr, "Querying whois and DNS for %d zones\n", len(zones))

	// Create 1 goroutine for each zone
	for i, zone := range zones {
		go func(zone string, i int) {
			limiter <- struct{}{} // acquire semaphore

			zw := ZoneWhois{zone, "", "", false}
			defer func() { // send result and release semaphore
				c <- zw
				<-limiter
			}()

			res, err := querySocket(whois, zone)
			if err != nil {
				return
			}

			// Look for whois: string
			matches := re.FindStringSubmatch(res)
			if matches != nil {
				zw.server = matches[1]
				zw.msg = fmt.Sprintf("whois -h %s %s", whois, zw.zone)
				return
			}

			// Check whois-servers.net
			host := zone + ".whois-servers.net"
			zw.server, err = queryCNAME(host)
			if zw.server != "" {
				zw.msg = fmt.Sprintf("dig %s CNAME", host)
				zw.viaDNS = true
				return
			}

			// Check exception list
			zw = exceptions[zone]
			zw.zone = zone
		}(zone, i)
	}

	numMissing, numDNS := 0, 0

	// Collect from goroutines
	for i := 0; i < len(zones); i++ {
		select {
		case zw := <-c:
			if zw.msg == "" {
				fmt.Fprintf(os.Stderr, "No match for %s\n", zw.zone)
			} else if v && zw.msg != "" {
				fmt.Fprintf(os.Stderr, "%s\t\t%s\n", zw.msg, zw.server)
			}

			zw.server = strings.TrimSuffix(strings.ToLower(zw.server), ".")
			zoneMap[zw.zone] = zw

			if zw.server == "" {
				numMissing++
			}
			if zw.viaDNS {
				numDNS++
			}
		}
	}

	// Print stats
	fmt.Fprintf(os.Stderr, "Zones with whois servers:    %d (%d via DNS)\n",
		len(zones)-numMissing, numDNS)
	fmt.Fprintf(os.Stderr, "Zones without whois servers: %d (%.0f%%)\n",
		numMissing, float32(numMissing)/float32(len(zones))*float32(100))
	fmt.Fprintf(os.Stderr, "Total number of zones:       %d\n",
		len(zones))

	// Generate zones.go
	buf := new(bytes.Buffer)
	const header = `// Generated by go run tools/generate.go > zones.go
// DO NOT EDIT

package whois

var zones = map[string]string{
`
	const footer = `}`

	buf.WriteString(header)
	for _, zone := range zones {
		zw := zoneMap[zone]
		fmt.Fprintf(buf, "\t%q: %q, // %s\n", zw.zone, zw.server, zw.msg)
	}
	buf.WriteString(footer)

	// Write to stdout
	formatted, err := format.Source(buf.Bytes())
	if err != nil {
		return err
	}
	_, err = os.Stdout.Write(formatted)
	return err
}

func querySocket(addr, query string) (string, error) {
	if !strings.Contains(addr, ":") {
		addr = addr + ":43"
	}
	c, err := net.Dial("tcp", addr)
	if err != nil {
		return "", err
	}
	defer c.Close()
	if _, err = fmt.Fprint(c, query, "\r\n"); err != nil {
		return "", err
	}
	res, err := ioutil.ReadAll(c)
	if err != nil {
		return "", err
	}
	return string(res), nil
}

func queryCNAME(host string) (string, error) {
	m := new(dns.Msg)
	m.RecursionDesired = true // embedded field
	m.SetQuestion(dns.Fqdn(host), dns.TypeCNAME)
	dnsClient = new(dns.Client)
	r, _, err := dnsClient.Exchange(m, "8.8.8.8:53")
	if err != nil {
		return "", err
	}
	if r.Rcode == dns.RcodeSuccess && r.Answer != nil && len(r.Answer) >= 1 {
		if cname, ok := r.Answer[0].(*dns.CNAME); ok {
			return cname.Target, nil
		}
	}
	return "", nil
}
<|endoftext|>


<commit_before>package api

import (
	"log"
	"net/http"
	"time"

	//"github.com/MyHomeworkSpace/api-server/auth"

	"github.com/labstack/echo"
)

// structs for data
type PlannerAnnouncement struct {
	ID int `json:"id"`
	Date string `json:"date"`
	Text string `json:"text"`
}

type PlannerFriday struct {
	ID int `json:"id"`
	Date string `json:"date"`
	Index int `json:"index"`
}

// responses
type MultiPlannerAnnouncementResponse struct {
	Status string `json:"status"`
	Announcements []PlannerAnnouncement `json:"announcements"`
}

type PlannerFridayResponse struct {
	Status string `json:"status"`
	Friday PlannerFriday `json:"friday"`
}

type PlannerWeekInfoResponse struct {
	Status string `json:"status"`
	Announcements []PlannerAnnouncement `json:"announcements"`
	Friday PlannerFriday `json:"friday"`
}

func InitPlannerAPI(e *echo.Echo) {
	e.GET("/planner/getWeekInfo/:date", func(c echo.Context) error {
		startDate, err := time.Parse("2006-01-02", c.Param("date"))
		if err != nil {
			jsonResp := ErrorResponse{"error", "Invalid date."}
			return c.JSON(http.StatusBadRequest, jsonResp)
		}
		endDate := startDate.Add(time.Hour * 24 * 7)

		announcementRows, err := DB.Query("SELECT id, date, text FROM announcements WHERE date >= ? AND date < ?", startDate.Format("2006-01-02"), endDate.Format("2006-01-02"))
		if err != nil {
			log.Println("Error while getting announcement information: ")
			log.Println(err)
			jsonResp := StatusResponse{"error"}
			return c.JSON(http.StatusInternalServerError, jsonResp)
		}
		defer announcementRows.Close()
		announcements := []PlannerAnnouncement{}
		for announcementRows.Next() {
			resp := PlannerAnnouncement{-1, "", ""}
			announcementRows.Scan(&resp.ID, &resp.Date, &resp.Text)
			announcements = append(announcements, resp)
		}

		fridayDate := startDate.Add(time.Hour * 24 * 4)

		fridayRows, err := DB.Query("SELECT * FROM fridays WHERE date = ?", fridayDate)
		if err != nil {
			log.Println("Error while getting friday information: ")
			log.Println(err)
			jsonResp := StatusResponse{"error"}
			return c.JSON(http.StatusInternalServerError, jsonResp)
		}
		defer fridayRows.Close()
		friday := PlannerFriday{-1, "", -1}
		if fridayRows.Next() {
			fridayRows.Scan(&friday.ID, &friday.Date, &friday.Index)
		}

		jsonResp := PlannerWeekInfoResponse{"ok", announcements, friday}
		return c.JSON(http.StatusOK, jsonResp)
	})

	e.GET("/planner/announcements/getWeek/:date", func(c echo.Context) error {
		startDate, err := time.Parse("2006-01-02", c.Param("date"))
		if err != nil {
			jsonResp := ErrorResponse{"error", "Invalid date."}
			return c.JSON(http.StatusBadRequest, jsonResp)
		}
		endDate := startDate.Add(time.Hour * 24 * 7)
		rows, err := DB.Query("SELECT id, date, text FROM announcements WHERE date >= ? AND date < ?", startDate.Format("2006-01-02"), endDate.Format("2006-01-02"))
		if err != nil {
			log.Println("Error while getting announcement information: ")
			log.Println(err)
			jsonResp := StatusResponse{"error"}
			return c.JSON(http.StatusInternalServerError, jsonResp)
		}
		defer rows.Close()
		announcements := []PlannerAnnouncement{}
		for rows.Next() {
			resp := PlannerAnnouncement{-1, "", ""}
			rows.Scan(&resp.ID, &resp.Date, &resp.Text)
			announcements = append(announcements, resp)
		}
		jsonResp := MultiPlannerAnnouncementResponse{"ok", announcements}
		return c.JSON(http.StatusOK, jsonResp)
	})

	e.GET("/planner/fridays/get/:date", func(c echo.Context) error {
		rows, err := DB.Query("SELECT * FROM fridays WHERE date = ?", c.Param("date"))
		if err != nil {
			log.Println("Error while getting friday information: ")
			log.Println(err)
			jsonResp := StatusResponse{"error"}
			return c.JSON(http.StatusInternalServerError, jsonResp)
		}
		defer rows.Close()
		if rows.Next() {
			resp := PlannerFriday{-1, "", -1}
			rows.Scan(&resp.ID, &resp.Date, &resp.Index)
			jsonResp := PlannerFridayResponse{"ok", resp}
			return c.JSON(http.StatusOK, jsonResp)
		} else {
			jsonResp := StatusResponse{"ok"}
			return c.JSON(http.StatusOK, jsonResp)
		}
	})
}
<commit_msg>format planner.go<commit_after>package api

import (
	"log"
	"net/http"
	"time"

	//"github.com/MyHomeworkSpace/api-server/auth"

	"github.com/labstack/echo"
)

// structs for data
type PlannerAnnouncement struct {
	ID   int    `json:"id"`
	Date string `json:"date"`
	Text string `json:"text"`
}

type PlannerFriday struct {
	ID    int    `json:"id"`
	Date  string `json:"date"`
	Index int    `json:"index"`
}

// responses
type MultiPlannerAnnouncementResponse struct {
	Status        string                `json:"status"`
	Announcements []PlannerAnnouncement `json:"announcements"`
}

type PlannerFridayResponse struct {
	Status string        `json:"status"`
	Friday PlannerFriday `json:"friday"`
}

type PlannerWeekInfoResponse struct {
	Status        string                `json:"status"`
	Announcements []PlannerAnnouncement `json:"announcements"`
	Friday        PlannerFriday         `json:"friday"`
}

func InitPlannerAPI(e *echo.Echo) {
	e.GET("/planner/getWeekInfo/:date", func(c echo.Context) error {
		startDate, err := time.Parse("2006-01-02", c.Param("date"))
		if err != nil {
			jsonResp := ErrorResponse{"error", "Invalid date."}
			return c.JSON(http.StatusBadRequest, jsonResp)
		}
		endDate := startDate.Add(time.Hour * 24 * 7)

		announcementRows, err := DB.Query("SELECT id, date, text FROM announcements WHERE date >= ? AND date < ?", startDate.Format("2006-01-02"), endDate.Format("2006-01-02"))
		if err != nil {
			log.Println("Error while getting announcement information: ")
			log.Println(err)
			jsonResp := StatusResponse{"error"}
			return c.JSON(http.StatusInternalServerError, jsonResp)
		}
		defer announcementRows.Close()
		announcements := []PlannerAnnouncement{}
		for announcementRows.Next() {
			resp := PlannerAnnouncement{-1, "", ""}
			announcementRows.Scan(&resp.ID, &resp.Date, &resp.Text)
			announcements = append(announcements, resp)
		}

		fridayDate := startDate.Add(time.Hour * 24 * 4)

		fridayRows, err := DB.Query("SELECT * FROM fridays WHERE date = ?", fridayDate)
		if err != nil {
			log.Println("Error while getting friday information: ")
			log.Println(err)
			jsonResp := StatusResponse{"error"}
			return c.JSON(http.StatusInternalServerError, jsonResp)
		}
		defer fridayRows.Close()
		friday := PlannerFriday{-1, "", -1}
		if fridayRows.Next() {
			fridayRows.Scan(&friday.ID, &friday.Date, &friday.Index)
		}

		jsonResp := PlannerWeekInfoResponse{"ok", announcements, friday}
		return c.JSON(http.StatusOK, jsonResp)
	})

	e.GET("/planner/announcements/getWeek/:date", func(c echo.Context) error {
		startDate, err := time.Parse("2006-01-02", c.Param("date"))
		if err != nil {
			jsonResp := ErrorResponse{"error", "Invalid date."}
			return c.JSON(http.StatusBadRequest, jsonResp)
		}
		endDate := startDate.Add(time.Hour * 24 * 7)
		rows, err := DB.Query("SELECT id, date, text FROM announcements WHERE date >= ? AND date < ?", startDate.Format("2006-01-02"), endDate.Format("2006-01-02"))
		if err != nil {
			log.Println("Error while getting announcement information: ")
			log.Println(err)
			jsonResp := StatusResponse{"error"}
			return c.JSON(http.StatusInternalServerError, jsonResp)
		}
		defer rows.Close()
		announcements := []PlannerAnnouncement{}
		for rows.Next() {
			resp := PlannerAnnouncement{-1, "", ""}
			rows.Scan(&resp.ID, &resp.Date, &resp.Text)
			announcements = append(announcements, resp)
		}
		jsonResp := MultiPlannerAnnouncementResponse{"ok", announcements}
		return c.JSON(http.StatusOK, jsonResp)
	})

	e.GET("/planner/fridays/get/:date", func(c echo.Context) error {
		rows, err := DB.Query("SELECT * FROM fridays WHERE date = ?", c.Param("date"))
		if err != nil {
			log.Println("Error while getting friday information: ")
			log.Println(err)
			jsonResp := StatusResponse{"error"}
			return c.JSON(http.StatusInternalServerError, jsonResp)
		}
		defer rows.Close()
		if rows.Next() {
			resp := PlannerFriday{-1, "", -1}
			rows.Scan(&resp.ID, &resp.Date, &resp.Index)
			jsonResp := PlannerFridayResponse{"ok", resp}
			return c.JSON(http.StatusOK, jsonResp)
		} else {
			jsonResp := StatusResponse{"ok"}
			return c.JSON(http.StatusOK, jsonResp)
		}
	})
}
<|endoftext|>


<commit_before>package api

import (
	"fmt"
	"net/http"
	"strings"

	"github.com/aptly-dev/aptly/aptly"
	"github.com/aptly-dev/aptly/deb"
	"github.com/aptly-dev/aptly/pgp"
	"github.com/aptly-dev/aptly/task"
	"github.com/aptly-dev/aptly/utils"
	"github.com/gin-gonic/gin"
)

// SigningOptions is a shared between publish API GPG options structure
type SigningOptions struct {
	Skip           bool
	Batch          bool
	GpgKey         string
	Keyring        string
	SecretKeyring  string
	Passphrase     string
	PassphraseFile string
}

func getSigner(options *SigningOptions) (pgp.Signer, error) {
	if options.Skip {
		return nil, nil
	}

	signer := context.GetSigner()
	signer.SetKey(options.GpgKey)
	signer.SetKeyRing(options.Keyring, options.SecretKeyring)
	signer.SetPassphrase(options.Passphrase, options.PassphraseFile)
	signer.SetBatch(options.Batch)

	err := signer.Init()
	if err != nil {
		return nil, err
	}

	return signer, nil
}

// Replace '_' with '/' and double '__' with single '_'
func parseEscapedPath(path string) string {
	result := strings.Replace(strings.Replace(path, "_", "/", -1), "//", "_", -1)
	if result == "" {
		result = "."
	}
	return result
}

// GET /publish
func apiPublishList(c *gin.Context) {
	collectionFactory := context.NewCollectionFactory()
	collection := collectionFactory.PublishedRepoCollection()

	result := make([]*deb.PublishedRepo, 0, collection.Len())

	err := collection.ForEach(func(repo *deb.PublishedRepo) error {
		err := collection.LoadComplete(repo, collectionFactory)
		if err != nil {
			return err
		}

		result = append(result, repo)

		return nil
	})

	if err != nil {
		c.AbortWithError(500, err)
		return
	}

	c.JSON(200, result)
}

// POST /publish/:prefix
func apiPublishRepoOrSnapshot(c *gin.Context) {
	param := parseEscapedPath(c.Params.ByName("prefix"))
	storage, prefix := deb.ParsePrefix(param)

	var b struct {
		SourceKind string `binding:"required"`
		Sources    []struct {
			Component string
			Name      string `binding:"required"`
		} `binding:"required"`
		Distribution         string
		Label                string
		Origin               string
		NotAutomatic         string
		ButAutomaticUpgrades string
		ForceOverwrite       bool
		SkipContents         *bool
		SkipBz2              *bool
		Architectures        []string
		Signing              SigningOptions
		AcquireByHash        *bool
	}

	if c.Bind(&b) != nil {
		return
	}

	signer, err := getSigner(&b.Signing)
	if err != nil {
		c.AbortWithError(500, fmt.Errorf("unable to initialize GPG signer: %s", err))
		return
	}

	if len(b.Sources) == 0 {
		c.AbortWithError(400, fmt.Errorf("unable to publish: soures are empty"))
		return
	}

	var components []string
	var names []string
	var sources []interface{}
	var resources []string
	collectionFactory := context.NewCollectionFactory()

	if b.SourceKind == "snapshot" {
		var snapshot *deb.Snapshot

		snapshotCollection := collectionFactory.SnapshotCollection()

		for _, source := range b.Sources {
			components = append(components, source.Component)
			names = append(names, source.Name)

			snapshot, err = snapshotCollection.ByName(source.Name)
			if err != nil {
				c.AbortWithError(404, fmt.Errorf("unable to publish: %s", err))
				return
			}

			resources = append(resources, string(snapshot.ResourceKey()))
			err = snapshotCollection.LoadComplete(snapshot)
			if err != nil {
				c.AbortWithError(500, fmt.Errorf("unable to publish: %s", err))
				return
			}

			sources = append(sources, snapshot)
		}
	} else if b.SourceKind == deb.SourceLocalRepo {
		var localRepo *deb.LocalRepo

		localCollection := collectionFactory.LocalRepoCollection()

		for _, source := range b.Sources {
			components = append(components, source.Component)
			names = append(names, source.Name)

			localRepo, err = localCollection.ByName(source.Name)
			if err != nil {
				c.AbortWithError(404, fmt.Errorf("unable to publish: %s", err))
				return
			}

			resources = append(resources, string(localRepo.Key()))
			err = localCollection.LoadComplete(localRepo)
			if err != nil {
				c.AbortWithError(500, fmt.Errorf("unable to publish: %s", err))
			}

			sources = append(sources, localRepo)
		}
	} else {
		c.AbortWithError(400, fmt.Errorf("unknown SourceKind"))
		return
	}

	published, err := deb.NewPublishedRepo(storage, prefix, b.Distribution, b.Architectures, components, sources, collectionFactory)
	if err != nil {
		c.AbortWithError(500, fmt.Errorf("unable to publish: %s", err))
		return
	}

	resources = append(resources, string(published.Key()))
	collection := collectionFactory.PublishedRepoCollection()

	taskName := fmt.Sprintf("Publish %s: %s", b.SourceKind, strings.Join(names, ", "))
	maybeRunTaskInBackground(c, taskName, resources, func(out aptly.Progress, detail *task.Detail) (*task.ProcessReturnValue, error) {
		taskDetail := task.PublishDetail{
			Detail: detail,
		}
		publishOutput := &task.PublishOutput{
			Progress:      out,
			PublishDetail: taskDetail,
		}

		if b.Origin != "" {
			published.Origin = b.Origin
		}
		if b.NotAutomatic != "" {
			published.NotAutomatic = b.NotAutomatic
		}
		if b.ButAutomaticUpgrades != "" {
			published.ButAutomaticUpgrades = b.ButAutomaticUpgrades
		}
		published.Label = b.Label

		published.SkipContents = context.Config().SkipContentsPublishing
		if b.SkipContents != nil {
			published.SkipContents = *b.SkipContents
		}

		published.SkipBz2 = context.Config().SkipBz2Publishing
		if b.SkipContents != nil {
			published.SkipBz2 = *b.SkipBz2
		}

		if b.AcquireByHash != nil {
			published.AcquireByHash = *b.AcquireByHash
		}

		duplicate := collection.CheckDuplicate(published)
		if duplicate != nil {
			collectionFactory.PublishedRepoCollection().LoadComplete(duplicate, collectionFactory)
			return &task.ProcessReturnValue{Code: http.StatusBadRequest, Value: nil}, fmt.Errorf("prefix/distribution already used by another published repo: %s", duplicate)
		}

		err := published.Publish(context.PackagePool(), context, collectionFactory, signer, publishOutput, b.ForceOverwrite)
		if err != nil {
			return &task.ProcessReturnValue{Code: http.StatusInternalServerError, Value: nil}, fmt.Errorf("unable to publish: %s", err)
		}

		err = collection.Add(published)
		if err != nil {
			return &task.ProcessReturnValue{Code: http.StatusInternalServerError, Value: nil}, fmt.Errorf("unable to save to DB: %s", err)
		}

		return &task.ProcessReturnValue{Code: http.StatusCreated, Value: published}, nil
	})
}

// PUT /publish/:prefix/:distribution
func apiPublishUpdateSwitch(c *gin.Context) {
	param := parseEscapedPath(c.Params.ByName("prefix"))
	storage, prefix := deb.ParsePrefix(param)
	distribution := c.Params.ByName("distribution")

	var b struct {
		ForceOverwrite bool
		Signing        SigningOptions
		SkipContents   *bool
		SkipBz2        *bool
		SkipCleanup    *bool
		Snapshots      []struct {
			Component string `binding:"required"`
			Name      string `binding:"required"`
		}
		AcquireByHash *bool
	}

	if c.Bind(&b) != nil {
		return
	}

	signer, err := getSigner(&b.Signing)
	if err != nil {
		c.AbortWithError(500, fmt.Errorf("unable to initialize GPG signer: %s", err))
		return
	}

	collectionFactory := context.NewCollectionFactory()
	collection := collectionFactory.PublishedRepoCollection()

	published, err := collection.ByStoragePrefixDistribution(storage, prefix, distribution)
	if err != nil {
		c.AbortWithError(404, fmt.Errorf("unable to update: %s", err))
		return
	}
	err = collection.LoadComplete(published, collectionFactory)
	if err != nil {
		c.AbortWithError(500, fmt.Errorf("unable to update: %s", err))
		return
	}

	var updatedComponents []string
	var updatedSnapshots []string
	var resources []string

	if published.SourceKind == deb.SourceLocalRepo {
		if len(b.Snapshots) > 0 {
			c.AbortWithError(400, fmt.Errorf("snapshots shouldn't be given when updating local repo"))
			return
		}
		updatedComponents = published.Components()
		for _, component := range updatedComponents {
			published.UpdateLocalRepo(component)
		}
	} else if published.SourceKind == "snapshot" {
		publishedComponents := published.Components()
		for _, snapshotInfo := range b.Snapshots {
			if !utils.StrSliceHasItem(publishedComponents, snapshotInfo.Component) {
				c.AbortWithError(404, fmt.Errorf("component %s is not in published repository", snapshotInfo.Component))
				return
			}

			snapshotCollection := collectionFactory.SnapshotCollection()
			snapshot, err2 := snapshotCollection.ByName(snapshotInfo.Name)
			if err2 != nil {
				c.AbortWithError(404, err2)
				return
			}

			err2 = snapshotCollection.LoadComplete(snapshot)
			if err2 != nil {
				c.AbortWithError(500, err2)
				return
			}

			published.UpdateSnapshot(snapshotInfo.Component, snapshot)
			updatedComponents = append(updatedComponents, snapshotInfo.Component)
			updatedSnapshots = append(updatedSnapshots, snapshot.Name)
		}
	} else {
		c.AbortWithError(500, fmt.Errorf("unknown published repository type"))
		return
	}

	if b.SkipContents != nil {
		published.SkipContents = *b.SkipContents
	}

	if b.SkipBz2 != nil {
		published.SkipBz2 = *b.SkipBz2
	}

	if b.AcquireByHash != nil {
		published.AcquireByHash = *b.AcquireByHash
	}

	resources = append(resources, string(published.Key()))
	taskName := fmt.Sprintf("Update published %s (%s): %s", published.SourceKind, strings.Join(updatedComponents, " "), strings.Join(updatedSnapshots, ", "))
	maybeRunTaskInBackground(c, taskName, resources, func(out aptly.Progress, detail *task.Detail) (*task.ProcessReturnValue, error) {
		err := published.Publish(context.PackagePool(), context, collectionFactory, signer, out, b.ForceOverwrite)
		if err != nil {
			return &task.ProcessReturnValue{Code: http.StatusInternalServerError, Value: nil}, fmt.Errorf("unable to update: %s", err)
		}

		err = collection.Update(published)
		if err != nil {
			return &task.ProcessReturnValue{Code: http.StatusInternalServerError, Value: nil}, fmt.Errorf("unable to save to DB: %s", err)
		}

		if b.SkipCleanup == nil || !*b.SkipCleanup {
			err = collection.CleanupPrefixComponentFiles(published.Prefix, updatedComponents,
				context.GetPublishedStorage(storage), collectionFactory, out)
			if err != nil {
				return &task.ProcessReturnValue{Code: http.StatusInternalServerError, Value: nil}, fmt.Errorf("unable to update: %s", err)
			}
		}

		return &task.ProcessReturnValue{Code: http.StatusOK, Value: published}, nil
	})
}

// DELETE /publish/:prefix/:distribution
func apiPublishDrop(c *gin.Context) {
	force := c.Request.URL.Query().Get("force") == "1"
	skipCleanup := c.Request.URL.Query().Get("SkipCleanup") == "1"

	param := parseEscapedPath(c.Params.ByName("prefix"))
	storage, prefix := deb.ParsePrefix(param)
	distribution := c.Params.ByName("distribution")

	collectionFactory := context.NewCollectionFactory()
	collection := collectionFactory.PublishedRepoCollection()

	published, err := collection.ByStoragePrefixDistribution(storage, prefix, distribution)
	if err != nil {
		c.AbortWithError(http.StatusInternalServerError, fmt.Errorf("unable to drop: %s", err))
		return
	}

	resources := []string{string(published.Key())}

	taskName := fmt.Sprintf("Delete published %s (%s)", prefix, distribution)
	maybeRunTaskInBackground(c, taskName, resources, func(out aptly.Progress, detail *task.Detail) (*task.ProcessReturnValue, error) {
		err := collection.Remove(context, storage, prefix, distribution,
			collectionFactory, out, force, skipCleanup)
		if err != nil {
			return &task.ProcessReturnValue{Code: http.StatusInternalServerError, Value: nil}, fmt.Errorf("unable to drop: %s", err)
		}

		return &task.ProcessReturnValue{Code: http.StatusOK, Value: gin.H{}}, nil
	})
}
<commit_msg>Fix wrong nil check for SkipBz2<commit_after>package api

import (
	"fmt"
	"net/http"
	"strings"

	"github.com/aptly-dev/aptly/aptly"
	"github.com/aptly-dev/aptly/deb"
	"github.com/aptly-dev/aptly/pgp"
	"github.com/aptly-dev/aptly/task"
	"github.com/aptly-dev/aptly/utils"
	"github.com/gin-gonic/gin"
)

// SigningOptions is a shared between publish API GPG options structure
type SigningOptions struct {
	Skip           bool
	Batch          bool
	GpgKey         string
	Keyring        string
	SecretKeyring  string
	Passphrase     string
	PassphraseFile string
}

func getSigner(options *SigningOptions) (pgp.Signer, error) {
	if options.Skip {
		return nil, nil
	}

	signer := context.GetSigner()
	signer.SetKey(options.GpgKey)
	signer.SetKeyRing(options.Keyring, options.SecretKeyring)
	signer.SetPassphrase(options.Passphrase, options.PassphraseFile)
	signer.SetBatch(options.Batch)

	err := signer.Init()
	if err != nil {
		return nil, err
	}

	return signer, nil
}

// Replace '_' with '/' and double '__' with single '_'
func parseEscapedPath(path string) string {
	result := strings.Replace(strings.Replace(path, "_", "/", -1), "//", "_", -1)
	if result == "" {
		result = "."
	}
	return result
}

// GET /publish
func apiPublishList(c *gin.Context) {
	collectionFactory := context.NewCollectionFactory()
	collection := collectionFactory.PublishedRepoCollection()

	result := make([]*deb.PublishedRepo, 0, collection.Len())

	err := collection.ForEach(func(repo *deb.PublishedRepo) error {
		err := collection.LoadComplete(repo, collectionFactory)
		if err != nil {
			return err
		}

		result = append(result, repo)

		return nil
	})

	if err != nil {
		c.AbortWithError(500, err)
		return
	}

	c.JSON(200, result)
}

// POST /publish/:prefix
func apiPublishRepoOrSnapshot(c *gin.Context) {
	param := parseEscapedPath(c.Params.ByName("prefix"))
	storage, prefix := deb.ParsePrefix(param)

	var b struct {
		SourceKind string `binding:"required"`
		Sources    []struct {
			Component string
			Name      string `binding:"required"`
		} `binding:"required"`
		Distribution         string
		Label                string
		Origin               string
		NotAutomatic         string
		ButAutomaticUpgrades string
		ForceOverwrite       bool
		SkipContents         *bool
		SkipBz2              *bool
		Architectures        []string
		Signing              SigningOptions
		AcquireByHash        *bool
	}

	if c.Bind(&b) != nil {
		return
	}

	signer, err := getSigner(&b.Signing)
	if err != nil {
		c.AbortWithError(500, fmt.Errorf("unable to initialize GPG signer: %s", err))
		return
	}

	if len(b.Sources) == 0 {
		c.AbortWithError(400, fmt.Errorf("unable to publish: soures are empty"))
		return
	}

	var components []string
	var names []string
	var sources []interface{}
	var resources []string
	collectionFactory := context.NewCollectionFactory()

	if b.SourceKind == "snapshot" {
		var snapshot *deb.Snapshot

		snapshotCollection := collectionFactory.SnapshotCollection()

		for _, source := range b.Sources {
			components = append(components, source.Component)
			names = append(names, source.Name)

			snapshot, err = snapshotCollection.ByName(source.Name)
			if err != nil {
				c.AbortWithError(404, fmt.Errorf("unable to publish: %s", err))
				return
			}

			resources = append(resources, string(snapshot.ResourceKey()))
			err = snapshotCollection.LoadComplete(snapshot)
			if err != nil {
				c.AbortWithError(500, fmt.Errorf("unable to publish: %s", err))
				return
			}

			sources = append(sources, snapshot)
		}
	} else if b.SourceKind == deb.SourceLocalRepo {
		var localRepo *deb.LocalRepo

		localCollection := collectionFactory.LocalRepoCollection()

		for _, source := range b.Sources {
			components = append(components, source.Component)
			names = append(names, source.Name)

			localRepo, err = localCollection.ByName(source.Name)
			if err != nil {
				c.AbortWithError(404, fmt.Errorf("unable to publish: %s", err))
				return
			}

			resources = append(resources, string(localRepo.Key()))
			err = localCollection.LoadComplete(localRepo)
			if err != nil {
				c.AbortWithError(500, fmt.Errorf("unable to publish: %s", err))
			}

			sources = append(sources, localRepo)
		}
	} else {
		c.AbortWithError(400, fmt.Errorf("unknown SourceKind"))
		return
	}

	published, err := deb.NewPublishedRepo(storage, prefix, b.Distribution, b.Architectures, components, sources, collectionFactory)
	if err != nil {
		c.AbortWithError(500, fmt.Errorf("unable to publish: %s", err))
		return
	}

	resources = append(resources, string(published.Key()))
	collection := collectionFactory.PublishedRepoCollection()

	taskName := fmt.Sprintf("Publish %s: %s", b.SourceKind, strings.Join(names, ", "))
	maybeRunTaskInBackground(c, taskName, resources, func(out aptly.Progress, detail *task.Detail) (*task.ProcessReturnValue, error) {
		taskDetail := task.PublishDetail{
			Detail: detail,
		}
		publishOutput := &task.PublishOutput{
			Progress:      out,
			PublishDetail: taskDetail,
		}

		if b.Origin != "" {
			published.Origin = b.Origin
		}
		if b.NotAutomatic != "" {
			published.NotAutomatic = b.NotAutomatic
		}
		if b.ButAutomaticUpgrades != "" {
			published.ButAutomaticUpgrades = b.ButAutomaticUpgrades
		}
		published.Label = b.Label

		published.SkipContents = context.Config().SkipContentsPublishing
		if b.SkipContents != nil {
			published.SkipContents = *b.SkipContents
		}

		published.SkipBz2 = context.Config().SkipBz2Publishing
		if b.SkipBz2 != nil {
			published.SkipBz2 = *b.SkipBz2
		}

		if b.AcquireByHash != nil {
			published.AcquireByHash = *b.AcquireByHash
		}

		duplicate := collection.CheckDuplicate(published)
		if duplicate != nil {
			collectionFactory.PublishedRepoCollection().LoadComplete(duplicate, collectionFactory)
			return &task.ProcessReturnValue{Code: http.StatusBadRequest, Value: nil}, fmt.Errorf("prefix/distribution already used by another published repo: %s", duplicate)
		}

		err := published.Publish(context.PackagePool(), context, collectionFactory, signer, publishOutput, b.ForceOverwrite)
		if err != nil {
			return &task.ProcessReturnValue{Code: http.StatusInternalServerError, Value: nil}, fmt.Errorf("unable to publish: %s", err)
		}

		err = collection.Add(published)
		if err != nil {
			return &task.ProcessReturnValue{Code: http.StatusInternalServerError, Value: nil}, fmt.Errorf("unable to save to DB: %s", err)
		}

		return &task.ProcessReturnValue{Code: http.StatusCreated, Value: published}, nil
	})
}

// PUT /publish/:prefix/:distribution
func apiPublishUpdateSwitch(c *gin.Context) {
	param := parseEscapedPath(c.Params.ByName("prefix"))
	storage, prefix := deb.ParsePrefix(param)
	distribution := c.Params.ByName("distribution")

	var b struct {
		ForceOverwrite bool
		Signing        SigningOptions
		SkipContents   *bool
		SkipBz2        *bool
		SkipCleanup    *bool
		Snapshots      []struct {
			Component string `binding:"required"`
			Name      string `binding:"required"`
		}
		AcquireByHash *bool
	}

	if c.Bind(&b) != nil {
		return
	}

	signer, err := getSigner(&b.Signing)
	if err != nil {
		c.AbortWithError(500, fmt.Errorf("unable to initialize GPG signer: %s", err))
		return
	}

	collectionFactory := context.NewCollectionFactory()
	collection := collectionFactory.PublishedRepoCollection()

	published, err := collection.ByStoragePrefixDistribution(storage, prefix, distribution)
	if err != nil {
		c.AbortWithError(404, fmt.Errorf("unable to update: %s", err))
		return
	}
	err = collection.LoadComplete(published, collectionFactory)
	if err != nil {
		c.AbortWithError(500, fmt.Errorf("unable to update: %s", err))
		return
	}

	var updatedComponents []string
	var updatedSnapshots []string
	var resources []string

	if published.SourceKind == deb.SourceLocalRepo {
		if len(b.Snapshots) > 0 {
			c.AbortWithError(400, fmt.Errorf("snapshots shouldn't be given when updating local repo"))
			return
		}
		updatedComponents = published.Components()
		for _, component := range updatedComponents {
			published.UpdateLocalRepo(component)
		}
	} else if published.SourceKind == "snapshot" {
		publishedComponents := published.Components()
		for _, snapshotInfo := range b.Snapshots {
			if !utils.StrSliceHasItem(publishedComponents, snapshotInfo.Component) {
				c.AbortWithError(404, fmt.Errorf("component %s is not in published repository", snapshotInfo.Component))
				return
			}

			snapshotCollection := collectionFactory.SnapshotCollection()
			snapshot, err2 := snapshotCollection.ByName(snapshotInfo.Name)
			if err2 != nil {
				c.AbortWithError(404, err2)
				return
			}

			err2 = snapshotCollection.LoadComplete(snapshot)
			if err2 != nil {
				c.AbortWithError(500, err2)
				return
			}

			published.UpdateSnapshot(snapshotInfo.Component, snapshot)
			updatedComponents = append(updatedComponents, snapshotInfo.Component)
			updatedSnapshots = append(updatedSnapshots, snapshot.Name)
		}
	} else {
		c.AbortWithError(500, fmt.Errorf("unknown published repository type"))
		return
	}

	if b.SkipContents != nil {
		published.SkipContents = *b.SkipContents
	}

	if b.SkipBz2 != nil {
		published.SkipBz2 = *b.SkipBz2
	}

	if b.AcquireByHash != nil {
		published.AcquireByHash = *b.AcquireByHash
	}

	resources = append(resources, string(published.Key()))
	taskName := fmt.Sprintf("Update published %s (%s): %s", published.SourceKind, strings.Join(updatedComponents, " "), strings.Join(updatedSnapshots, ", "))
	maybeRunTaskInBackground(c, taskName, resources, func(out aptly.Progress, detail *task.Detail) (*task.ProcessReturnValue, error) {
		err := published.Publish(context.PackagePool(), context, collectionFactory, signer, out, b.ForceOverwrite)
		if err != nil {
			return &task.ProcessReturnValue{Code: http.StatusInternalServerError, Value: nil}, fmt.Errorf("unable to update: %s", err)
		}

		err = collection.Update(published)
		if err != nil {
			return &task.ProcessReturnValue{Code: http.StatusInternalServerError, Value: nil}, fmt.Errorf("unable to save to DB: %s", err)
		}

		if b.SkipCleanup == nil || !*b.SkipCleanup {
			err = collection.CleanupPrefixComponentFiles(published.Prefix, updatedComponents,
				context.GetPublishedStorage(storage), collectionFactory, out)
			if err != nil {
				return &task.ProcessReturnValue{Code: http.StatusInternalServerError, Value: nil}, fmt.Errorf("unable to update: %s", err)
			}
		}

		return &task.ProcessReturnValue{Code: http.StatusOK, Value: published}, nil
	})
}

// DELETE /publish/:prefix/:distribution
func apiPublishDrop(c *gin.Context) {
	force := c.Request.URL.Query().Get("force") == "1"
	skipCleanup := c.Request.URL.Query().Get("SkipCleanup") == "1"

	param := parseEscapedPath(c.Params.ByName("prefix"))
	storage, prefix := deb.ParsePrefix(param)
	distribution := c.Params.ByName("distribution")

	collectionFactory := context.NewCollectionFactory()
	collection := collectionFactory.PublishedRepoCollection()

	published, err := collection.ByStoragePrefixDistribution(storage, prefix, distribution)
	if err != nil {
		c.AbortWithError(http.StatusInternalServerError, fmt.Errorf("unable to drop: %s", err))
		return
	}

	resources := []string{string(published.Key())}

	taskName := fmt.Sprintf("Delete published %s (%s)", prefix, distribution)
	maybeRunTaskInBackground(c, taskName, resources, func(out aptly.Progress, detail *task.Detail) (*task.ProcessReturnValue, error) {
		err := collection.Remove(context, storage, prefix, distribution,
			collectionFactory, out, force, skipCleanup)
		if err != nil {
			return &task.ProcessReturnValue{Code: http.StatusInternalServerError, Value: nil}, fmt.Errorf("unable to drop: %s", err)
		}

		return &task.ProcessReturnValue{Code: http.StatusOK, Value: gin.H{}}, nil
	})
}
<|endoftext|>


<commit_before>package torrent

import (
	"fmt"
	gateway "github.com/jackpal/go-gateway"
	"log"
	"net"
	"strconv"
)

// btConn wraps an incoming network connection and contains metadata that helps
// identify which active torrentSession it's relevant for.
type BtConn struct {
	conn       net.Conn
	RemoteAddr net.Addr
	header     []byte
	Infohash   string
	id         string
}

// listenForPeerConnections listens on a TCP port for incoming connections and
// demuxes them to the appropriate active torrentSession based on the InfoHash
// in the header.
func ListenForPeerConnections(flags *TorrentFlags) (conChan chan *BtConn, listenPort int, err error) {
	listener, listenPort, err := CreateListener(flags)
	if err != nil {
		return
	}
	conChan = make(chan *BtConn)
	_, portstring, err := net.SplitHostPort(listener.Addr().String())
	if err != nil {
		log.Printf("Listener failed while finding the host/port for %v: %v", portstring, err)
		return
	}
	go func() {
		for {
			var conn net.Conn
			conn, err := listener.Accept()
			if err != nil {
				log.Println("Listener accept failed:", err)
				continue
			}
			header, err := readHeader(conn)
			if err != nil {
				log.Println("Error reading header: ", err)
				continue
			}
			peersInfoHash := string(header[8:28])
			id := string(header[28:48])
			conChan <- &BtConn{
				header:     header,
				Infohash:   peersInfoHash,
				id:         id,
				conn:       conn,
				RemoteAddr: conn.RemoteAddr(),
			}
		}
	}()
	return
}

func CreateListener(flags *TorrentFlags) (listener net.Listener, externalPort int, err error) {
	nat, err := CreatePortMapping(flags)
	if err != nil {
		err = fmt.Errorf("Unable to create NAT: %v", err)
		return
	}
	listenPort := flags.Port
	if nat != nil {
		var external net.IP
		if external, err = nat.GetExternalAddress(); err != nil {
			err = fmt.Errorf("Unable to get external IP address from NAT: %v", err)
			return
		}
		log.Println("External ip address: ", external)
		if listenPort, err = chooseListenPort(nat, listenPort); err != nil {
			log.Println("Could not choose listen port.", err)
			log.Println("Peer connectivity will be affected.")
		}
	}
	listener, err = net.ListenTCP("tcp", &net.TCPAddr{Port: listenPort})
	if err != nil {
		log.Fatal("Listen failed:", err)
	}
	log.Println("Listening for peers on port:", listenPort)
	externalPort = listenPort
	return
}

// createPortMapping creates a NAT port mapping, or nil if none requested or found.
func CreatePortMapping(flags *TorrentFlags) (nat NAT, err error) {
	if flags.UseUPnP && flags.UseNATPMP {
		err = fmt.Errorf("Cannot specify both -useUPnP and -useNATPMP")
		return
	}
	if flags.UseUPnP {
		log.Println("Using UPnP to open port.")
		nat, err = Discover()
	}
	if flags.UseNATPMP {
		var gatewayIP net.IP
		if flags.Gateway == "" {
			log.Printf("useNATPMP but gateway not provided, trying discovery")
			gatewayIP, err = gateway.DiscoverGateway()
			if err != nil {
				return
			}
			log.Printf("...discovered gateway IP: %s", gatewayIP)
		} else {
			gatewayIP = net.ParseIP(flags.Gateway)
		}
		log.Println("Using NAT-PMP to open port.")
		if gatewayIP == nil {
			err = fmt.Errorf("Could not parse gateway %q", flags.Gateway)
		}
		nat = NewNatPMP(gatewayIP)
	}
	return
}

func chooseListenPort(nat NAT, externalPort int) (listenPort int, err error) {
	// TODO: Unmap port when exiting. (Right now we never exit cleanly.)
	// TODO: Defend the port, remap when router reboots
	listenPort, err = nat.AddPortMapping("tcp", externalPort, externalPort,
		"Taipei-Torrent port "+strconv.Itoa(externalPort), 360000)
	if err != nil {
		return
	}
	return
}

func readHeader(conn net.Conn) (h []byte, err error) {
	header := make([]byte, 68)
	_, err = conn.Read(header[0:1])
	if err != nil {
		err = fmt.Errorf("Couldn't read 1st byte: %v", err)
		return
	}
	if header[0] != 19 {
		err = fmt.Errorf("First byte is not 19")
		return
	}
	_, err = conn.Read(header[1:20])
	if err != nil {
		err = fmt.Errorf("Couldn't read magic string: %v", err)
		return
	}
	if string(header[1:20]) != "BitTorrent protocol" {
		err = fmt.Errorf("Magic string is not correct: %v", string(header[1:20]))
		return
	}
	// Read rest of header
	_, err = conn.Read(header[20:])
	if err != nil {
		err = fmt.Errorf("Couldn't read rest of header")
		return
	}

	h = make([]byte, 48)
	copy(h, header[20:])
	return
}
<commit_msg>Rename gateway repository<commit_after>package torrent

import (
	"fmt"
	"github.com/jackpal/gateway"
	"log"
	"net"
	"strconv"
)

// btConn wraps an incoming network connection and contains metadata that helps
// identify which active torrentSession it's relevant for.
type BtConn struct {
	conn       net.Conn
	RemoteAddr net.Addr
	header     []byte
	Infohash   string
	id         string
}

// listenForPeerConnections listens on a TCP port for incoming connections and
// demuxes them to the appropriate active torrentSession based on the InfoHash
// in the header.
func ListenForPeerConnections(flags *TorrentFlags) (conChan chan *BtConn, listenPort int, err error) {
	listener, listenPort, err := CreateListener(flags)
	if err != nil {
		return
	}
	conChan = make(chan *BtConn)
	_, portstring, err := net.SplitHostPort(listener.Addr().String())
	if err != nil {
		log.Printf("Listener failed while finding the host/port for %v: %v", portstring, err)
		return
	}
	go func() {
		for {
			var conn net.Conn
			conn, err := listener.Accept()
			if err != nil {
				log.Println("Listener accept failed:", err)
				continue
			}
			header, err := readHeader(conn)
			if err != nil {
				log.Println("Error reading header: ", err)
				continue
			}
			peersInfoHash := string(header[8:28])
			id := string(header[28:48])
			conChan <- &BtConn{
				header:     header,
				Infohash:   peersInfoHash,
				id:         id,
				conn:       conn,
				RemoteAddr: conn.RemoteAddr(),
			}
		}
	}()
	return
}

func CreateListener(flags *TorrentFlags) (listener net.Listener, externalPort int, err error) {
	nat, err := CreatePortMapping(flags)
	if err != nil {
		err = fmt.Errorf("Unable to create NAT: %v", err)
		return
	}
	listenPort := flags.Port
	if nat != nil {
		var external net.IP
		if external, err = nat.GetExternalAddress(); err != nil {
			err = fmt.Errorf("Unable to get external IP address from NAT: %v", err)
			return
		}
		log.Println("External ip address: ", external)
		if listenPort, err = chooseListenPort(nat, listenPort); err != nil {
			log.Println("Could not choose listen port.", err)
			log.Println("Peer connectivity will be affected.")
		}
	}
	listener, err = net.ListenTCP("tcp", &net.TCPAddr{Port: listenPort})
	if err != nil {
		log.Fatal("Listen failed:", err)
	}
	log.Println("Listening for peers on port:", listenPort)
	externalPort = listenPort
	return
}

// createPortMapping creates a NAT port mapping, or nil if none requested or found.
func CreatePortMapping(flags *TorrentFlags) (nat NAT, err error) {
	if flags.UseUPnP && flags.UseNATPMP {
		err = fmt.Errorf("Cannot specify both -useUPnP and -useNATPMP")
		return
	}
	if flags.UseUPnP {
		log.Println("Using UPnP to open port.")
		nat, err = Discover()
	}
	if flags.UseNATPMP {
		var gatewayIP net.IP
		if flags.Gateway == "" {
			log.Printf("useNATPMP but gateway not provided, trying discovery")
			gatewayIP, err = gateway.DiscoverGateway()
			if err != nil {
				return
			}
			log.Printf("...discovered gateway IP: %s", gatewayIP)
		} else {
			gatewayIP = net.ParseIP(flags.Gateway)
		}
		log.Println("Using NAT-PMP to open port.")
		if gatewayIP == nil {
			err = fmt.Errorf("Could not parse gateway %q", flags.Gateway)
		}
		nat = NewNatPMP(gatewayIP)
	}
	return
}

func chooseListenPort(nat NAT, externalPort int) (listenPort int, err error) {
	// TODO: Unmap port when exiting. (Right now we never exit cleanly.)
	// TODO: Defend the port, remap when router reboots
	listenPort, err = nat.AddPortMapping("tcp", externalPort, externalPort,
		"Taipei-Torrent port "+strconv.Itoa(externalPort), 360000)
	if err != nil {
		return
	}
	return
}

func readHeader(conn net.Conn) (h []byte, err error) {
	header := make([]byte, 68)
	_, err = conn.Read(header[0:1])
	if err != nil {
		err = fmt.Errorf("Couldn't read 1st byte: %v", err)
		return
	}
	if header[0] != 19 {
		err = fmt.Errorf("First byte is not 19")
		return
	}
	_, err = conn.Read(header[1:20])
	if err != nil {
		err = fmt.Errorf("Couldn't read magic string: %v", err)
		return
	}
	if string(header[1:20]) != "BitTorrent protocol" {
		err = fmt.Errorf("Magic string is not correct: %v", string(header[1:20]))
		return
	}
	// Read rest of header
	_, err = conn.Read(header[20:])
	if err != nil {
		err = fmt.Errorf("Couldn't read rest of header")
		return
	}

	h = make([]byte, 48)
	copy(h, header[20:])
	return
}
<|endoftext|>