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

package ssagen

import (
	"internal/race"
	"math/rand"
	"sort"
	"sync"
	"time"

	"cmd/compile/internal/base"
	"cmd/compile/internal/ir"
	"cmd/compile/internal/objw"
	"cmd/compile/internal/ssa"
	"cmd/compile/internal/types"
	"cmd/internal/obj"
	"cmd/internal/objabi"
	"cmd/internal/src"
	"cmd/internal/sys"
)

// cmpstackvarlt reports whether the stack variable a sorts before b.
//
// Sort the list of stack variables. Autos after anything else,
// within autos, unused after used, within used, things with
// pointers first, zeroed things first, and then decreasing size.
// Because autos are laid out in decreasing addresses
// on the stack, pointers first, zeroed things first and decreasing size
// really means, in memory, things with pointers needing zeroing at
// the top of the stack and increasing in size.
// Non-autos sort on offset.
func cmpstackvarlt(a, b *ir.Name) bool {
	if (a.Class == ir.PAUTO) != (b.Class == ir.PAUTO) {
		return b.Class == ir.PAUTO
	}

	if a.Class != ir.PAUTO {
		return a.FrameOffset() < b.FrameOffset()
	}

	if a.Used() != b.Used() {
		return a.Used()
	}

	ap := a.Type().HasPointers()
	bp := b.Type().HasPointers()
	if ap != bp {
		return ap
	}

	ap = a.Needzero()
	bp = b.Needzero()
	if ap != bp {
		return ap
	}

	if a.Type().Width != b.Type().Width {
		return a.Type().Width > b.Type().Width
	}

	return a.Sym().Name < b.Sym().Name
}

// byStackvar implements sort.Interface for []*Node using cmpstackvarlt.
type byStackVar []*ir.Name

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

func (s *ssafn) AllocFrame(f *ssa.Func) {
	s.stksize = 0
	s.stkptrsize = 0
	fn := s.curfn

	// Mark the PAUTO's unused.
	for _, ln := range fn.Dcl {
		if ln.Class == ir.PAUTO {
			ln.SetUsed(false)
		}
	}

	for _, l := range f.RegAlloc {
		if ls, ok := l.(ssa.LocalSlot); ok {
			ls.N.SetUsed(true)
		}
	}

	for _, b := range f.Blocks {
		for _, v := range b.Values {
			if n, ok := v.Aux.(*ir.Name); ok {
				switch n.Class {
				case ir.PPARAM, ir.PPARAMOUT, ir.PAUTO:
					n.SetUsed(true)
				}
			}
		}
	}

	sort.Sort(byStackVar(fn.Dcl))

	// Reassign stack offsets of the locals that are used.
	lastHasPtr := false
	for i, n := range fn.Dcl {
		if n.Op() != ir.ONAME || n.Class != ir.PAUTO {
			continue
		}
		if !n.Used() {
			fn.Dcl = fn.Dcl[:i]
			break
		}

		types.CalcSize(n.Type())
		w := n.Type().Width
		if w >= types.MaxWidth || w < 0 {
			base.Fatalf("bad width")
		}
		if w == 0 && lastHasPtr {
			// Pad between a pointer-containing object and a zero-sized object.
			// This prevents a pointer to the zero-sized object from being interpreted
			// as a pointer to the pointer-containing object (and causing it
			// to be scanned when it shouldn't be). See issue 24993.
			w = 1
		}
		s.stksize += w
		s.stksize = types.Rnd(s.stksize, int64(n.Type().Align))
		if n.Type().HasPointers() {
			s.stkptrsize = s.stksize
			lastHasPtr = true
		} else {
			lastHasPtr = false
		}
		if Arch.LinkArch.InFamily(sys.ARM, sys.PPC64) {
			s.stksize = types.Rnd(s.stksize, int64(types.PtrSize))
		}
		n.SetFrameOffset(-s.stksize)
	}

	s.stksize = types.Rnd(s.stksize, int64(types.RegSize))
	s.stkptrsize = types.Rnd(s.stkptrsize, int64(types.RegSize))
}

const maxStackSize = 1 << 30

// Compile builds an SSA backend function,
// uses it to generate a plist,
// and flushes that plist to machine code.
// worker indicates which of the backend workers is doing the processing.
func Compile(fn *ir.Func, worker int) {
	f := buildssa(fn, worker)
	// Note: check arg size to fix issue 25507.
	if f.Frontend().(*ssafn).stksize >= maxStackSize || fn.Type().ArgWidth() >= maxStackSize {
		largeStackFramesMu.Lock()
		largeStackFrames = append(largeStackFrames, largeStack{locals: f.Frontend().(*ssafn).stksize, args: fn.Type().ArgWidth(), pos: fn.Pos()})
		largeStackFramesMu.Unlock()
		return
	}
	pp := objw.NewProgs(fn, worker)
	defer pp.Free()
	genssa(f, pp)
	// Check frame size again.
	// The check above included only the space needed for local variables.
	// After genssa, the space needed includes local variables and the callee arg region.
	// We must do this check prior to calling pp.Flush.
	// If there are any oversized stack frames,
	// the assembler may emit inscrutable complaints about invalid instructions.
	if pp.Text.To.Offset >= maxStackSize {
		largeStackFramesMu.Lock()
		locals := f.Frontend().(*ssafn).stksize
		largeStackFrames = append(largeStackFrames, largeStack{locals: locals, args: fn.Type().ArgWidth(), callee: pp.Text.To.Offset - locals, pos: fn.Pos()})
		largeStackFramesMu.Unlock()
		return
	}

	pp.Flush() // assemble, fill in boilerplate, etc.
	// fieldtrack must be called after pp.Flush. See issue 20014.
	fieldtrack(pp.Text.From.Sym, fn.FieldTrack)
}

func init() {
	if race.Enabled {
		rand.Seed(time.Now().UnixNano())
	}
}

// StackOffset returns the stack location of a LocalSlot relative to the
// stack pointer, suitable for use in a DWARF location entry. This has nothing
// to do with its offset in the user variable.
func StackOffset(slot ssa.LocalSlot) int32 {
	n := slot.N
	var off int64
	switch n.Class {
	case ir.PAUTO:
		off = n.FrameOffset()
		if base.Ctxt.FixedFrameSize() == 0 {
			off -= int64(types.PtrSize)
		}
		if objabi.Framepointer_enabled {
			off -= int64(types.PtrSize)
		}
	case ir.PPARAM, ir.PPARAMOUT:
		off = n.FrameOffset() + base.Ctxt.FixedFrameSize()
	}
	return int32(off + slot.Off)
}

// fieldtrack adds R_USEFIELD relocations to fnsym to record any
// struct fields that it used.
func fieldtrack(fnsym *obj.LSym, tracked map[*obj.LSym]struct{}) {
	if fnsym == nil {
		return
	}
	if objabi.Fieldtrack_enabled == 0 || len(tracked) == 0 {
		return
	}

	trackSyms := make([]*obj.LSym, 0, len(tracked))
	for sym := range tracked {
		trackSyms = append(trackSyms, sym)
	}
	sort.Slice(trackSyms, func(i, j int) bool { return trackSyms[i].Name < trackSyms[j].Name })
	for _, sym := range trackSyms {
		r := obj.Addrel(fnsym)
		r.Sym = sym
		r.Type = objabi.R_USEFIELD
	}
}

// largeStack is info about a function whose stack frame is too large (rare).
type largeStack struct {
	locals int64
	args   int64
	callee int64
	pos    src.XPos
}

var (
	largeStackFramesMu sync.Mutex // protects largeStackFrames
	largeStackFrames   []largeStack
)

func CheckLargeStacks() {
	// Check whether any of the functions we have compiled have gigantic stack frames.
	sort.Slice(largeStackFrames, func(i, j int) bool {
		return largeStackFrames[i].pos.Before(largeStackFrames[j].pos)
	})
	for _, large := range largeStackFrames {
		if large.callee != 0 {
			base.ErrorfAt(large.pos, "stack frame too large (>1GB): %d MB locals + %d MB args + %d MB callee", large.locals>>20, large.args>>20, large.callee>>20)
		} else {
			base.ErrorfAt(large.pos, "stack frame too large (>1GB): %d MB locals + %d MB args", large.locals>>20, large.args>>20)
		}
	}
}
<commit_msg>cmd/compile: remove 4-byte alignment requirement of stack slot on arm<commit_after>// Copyright 2011 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package ssagen

import (
	"internal/race"
	"math/rand"
	"sort"
	"sync"
	"time"

	"cmd/compile/internal/base"
	"cmd/compile/internal/ir"
	"cmd/compile/internal/objw"
	"cmd/compile/internal/ssa"
	"cmd/compile/internal/types"
	"cmd/internal/obj"
	"cmd/internal/objabi"
	"cmd/internal/src"
	"cmd/internal/sys"
)

// cmpstackvarlt reports whether the stack variable a sorts before b.
//
// Sort the list of stack variables. Autos after anything else,
// within autos, unused after used, within used, things with
// pointers first, zeroed things first, and then decreasing size.
// Because autos are laid out in decreasing addresses
// on the stack, pointers first, zeroed things first and decreasing size
// really means, in memory, things with pointers needing zeroing at
// the top of the stack and increasing in size.
// Non-autos sort on offset.
func cmpstackvarlt(a, b *ir.Name) bool {
	if (a.Class == ir.PAUTO) != (b.Class == ir.PAUTO) {
		return b.Class == ir.PAUTO
	}

	if a.Class != ir.PAUTO {
		return a.FrameOffset() < b.FrameOffset()
	}

	if a.Used() != b.Used() {
		return a.Used()
	}

	ap := a.Type().HasPointers()
	bp := b.Type().HasPointers()
	if ap != bp {
		return ap
	}

	ap = a.Needzero()
	bp = b.Needzero()
	if ap != bp {
		return ap
	}

	if a.Type().Width != b.Type().Width {
		return a.Type().Width > b.Type().Width
	}

	return a.Sym().Name < b.Sym().Name
}

// byStackvar implements sort.Interface for []*Node using cmpstackvarlt.
type byStackVar []*ir.Name

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

func (s *ssafn) AllocFrame(f *ssa.Func) {
	s.stksize = 0
	s.stkptrsize = 0
	fn := s.curfn

	// Mark the PAUTO's unused.
	for _, ln := range fn.Dcl {
		if ln.Class == ir.PAUTO {
			ln.SetUsed(false)
		}
	}

	for _, l := range f.RegAlloc {
		if ls, ok := l.(ssa.LocalSlot); ok {
			ls.N.SetUsed(true)
		}
	}

	for _, b := range f.Blocks {
		for _, v := range b.Values {
			if n, ok := v.Aux.(*ir.Name); ok {
				switch n.Class {
				case ir.PPARAM, ir.PPARAMOUT, ir.PAUTO:
					n.SetUsed(true)
				}
			}
		}
	}

	sort.Sort(byStackVar(fn.Dcl))

	// Reassign stack offsets of the locals that are used.
	lastHasPtr := false
	for i, n := range fn.Dcl {
		if n.Op() != ir.ONAME || n.Class != ir.PAUTO {
			continue
		}
		if !n.Used() {
			fn.Dcl = fn.Dcl[:i]
			break
		}

		types.CalcSize(n.Type())
		w := n.Type().Width
		if w >= types.MaxWidth || w < 0 {
			base.Fatalf("bad width")
		}
		if w == 0 && lastHasPtr {
			// Pad between a pointer-containing object and a zero-sized object.
			// This prevents a pointer to the zero-sized object from being interpreted
			// as a pointer to the pointer-containing object (and causing it
			// to be scanned when it shouldn't be). See issue 24993.
			w = 1
		}
		s.stksize += w
		s.stksize = types.Rnd(s.stksize, int64(n.Type().Align))
		if n.Type().HasPointers() {
			s.stkptrsize = s.stksize
			lastHasPtr = true
		} else {
			lastHasPtr = false
		}
		if Arch.LinkArch.InFamily(sys.PPC64) {
			s.stksize = types.Rnd(s.stksize, int64(types.PtrSize))
		}
		n.SetFrameOffset(-s.stksize)
	}

	s.stksize = types.Rnd(s.stksize, int64(types.RegSize))
	s.stkptrsize = types.Rnd(s.stkptrsize, int64(types.RegSize))
}

const maxStackSize = 1 << 30

// Compile builds an SSA backend function,
// uses it to generate a plist,
// and flushes that plist to machine code.
// worker indicates which of the backend workers is doing the processing.
func Compile(fn *ir.Func, worker int) {
	f := buildssa(fn, worker)
	// Note: check arg size to fix issue 25507.
	if f.Frontend().(*ssafn).stksize >= maxStackSize || fn.Type().ArgWidth() >= maxStackSize {
		largeStackFramesMu.Lock()
		largeStackFrames = append(largeStackFrames, largeStack{locals: f.Frontend().(*ssafn).stksize, args: fn.Type().ArgWidth(), pos: fn.Pos()})
		largeStackFramesMu.Unlock()
		return
	}
	pp := objw.NewProgs(fn, worker)
	defer pp.Free()
	genssa(f, pp)
	// Check frame size again.
	// The check above included only the space needed for local variables.
	// After genssa, the space needed includes local variables and the callee arg region.
	// We must do this check prior to calling pp.Flush.
	// If there are any oversized stack frames,
	// the assembler may emit inscrutable complaints about invalid instructions.
	if pp.Text.To.Offset >= maxStackSize {
		largeStackFramesMu.Lock()
		locals := f.Frontend().(*ssafn).stksize
		largeStackFrames = append(largeStackFrames, largeStack{locals: locals, args: fn.Type().ArgWidth(), callee: pp.Text.To.Offset - locals, pos: fn.Pos()})
		largeStackFramesMu.Unlock()
		return
	}

	pp.Flush() // assemble, fill in boilerplate, etc.
	// fieldtrack must be called after pp.Flush. See issue 20014.
	fieldtrack(pp.Text.From.Sym, fn.FieldTrack)
}

func init() {
	if race.Enabled {
		rand.Seed(time.Now().UnixNano())
	}
}

// StackOffset returns the stack location of a LocalSlot relative to the
// stack pointer, suitable for use in a DWARF location entry. This has nothing
// to do with its offset in the user variable.
func StackOffset(slot ssa.LocalSlot) int32 {
	n := slot.N
	var off int64
	switch n.Class {
	case ir.PAUTO:
		off = n.FrameOffset()
		if base.Ctxt.FixedFrameSize() == 0 {
			off -= int64(types.PtrSize)
		}
		if objabi.Framepointer_enabled {
			off -= int64(types.PtrSize)
		}
	case ir.PPARAM, ir.PPARAMOUT:
		off = n.FrameOffset() + base.Ctxt.FixedFrameSize()
	}
	return int32(off + slot.Off)
}

// fieldtrack adds R_USEFIELD relocations to fnsym to record any
// struct fields that it used.
func fieldtrack(fnsym *obj.LSym, tracked map[*obj.LSym]struct{}) {
	if fnsym == nil {
		return
	}
	if objabi.Fieldtrack_enabled == 0 || len(tracked) == 0 {
		return
	}

	trackSyms := make([]*obj.LSym, 0, len(tracked))
	for sym := range tracked {
		trackSyms = append(trackSyms, sym)
	}
	sort.Slice(trackSyms, func(i, j int) bool { return trackSyms[i].Name < trackSyms[j].Name })
	for _, sym := range trackSyms {
		r := obj.Addrel(fnsym)
		r.Sym = sym
		r.Type = objabi.R_USEFIELD
	}
}

// largeStack is info about a function whose stack frame is too large (rare).
type largeStack struct {
	locals int64
	args   int64
	callee int64
	pos    src.XPos
}

var (
	largeStackFramesMu sync.Mutex // protects largeStackFrames
	largeStackFrames   []largeStack
)

func CheckLargeStacks() {
	// Check whether any of the functions we have compiled have gigantic stack frames.
	sort.Slice(largeStackFrames, func(i, j int) bool {
		return largeStackFrames[i].pos.Before(largeStackFrames[j].pos)
	})
	for _, large := range largeStackFrames {
		if large.callee != 0 {
			base.ErrorfAt(large.pos, "stack frame too large (>1GB): %d MB locals + %d MB args + %d MB callee", large.locals>>20, large.args>>20, large.callee>>20)
		} else {
			base.ErrorfAt(large.pos, "stack frame too large (>1GB): %d MB locals + %d MB args", large.locals>>20, large.args>>20)
		}
	}
}
<|endoftext|>


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

// The time package provides functionality for measuring and
// displaying time.
package time

// Days of the week.
const (
	Sunday = iota
	Monday
	Tuesday
	Wednesday
	Thursday
	Friday
	Saturday
)

// Time is the struct representing a parsed time value.
type Time struct {
	Year                 int64  // 2006 is 2006
	Month, Day           int    // Jan-2 is 1, 2
	Hour, Minute, Second int    // 15:04:05 is 15, 4, 5.
	Weekday              int    // Sunday, Monday, ...
	ZoneOffset           int    // seconds east of UTC, e.g. -7*60 for -0700
	Zone                 string // e.g., "MST"
}

var nonleapyear = []int{31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}
var leapyear = []int{31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}

func months(year int64) []int {
	if year%4 == 0 && (year%100 != 0 || year%400 == 0) {
		return leapyear
	}
	return nonleapyear
}

const (
	secondsPerDay   = 24 * 60 * 60
	daysPer400Years = 365*400 + 97
	daysPer100Years = 365*100 + 24
	daysPer4Years   = 365*4 + 1
	days1970To2001  = 31*365 + 8
)

// SecondsToUTC converts sec, in number of seconds since the Unix epoch,
// into a parsed Time value in the UTC time zone.
func SecondsToUTC(sec int64) *Time {
	t := new(Time)

	// Split into time and day.
	day := sec / secondsPerDay
	sec -= day * secondsPerDay
	if sec < 0 {
		day--
		sec += secondsPerDay
	}

	// Time
	t.Hour = int(sec / 3600)
	t.Minute = int((sec / 60) % 60)
	t.Second = int(sec % 60)

	// Day 0 = January 1, 1970 was a Thursday
	t.Weekday = int((day + Thursday) % 7)
	if t.Weekday < 0 {
		t.Weekday += 7
	}

	// Change day from 0 = 1970 to 0 = 2001,
	// to make leap year calculations easier
	// (2001 begins 4-, 100-, and 400-year cycles ending in a leap year.)
	day -= days1970To2001

	year := int64(2001)
	if day < 0 {
		// Go back enough 400 year cycles to make day positive.
		n := -day/daysPer400Years + 1
		year -= 400 * n
		day += daysPer400Years * n
	}

	// Cut off 400 year cycles.
	n := day / daysPer400Years
	year += 400 * n
	day -= daysPer400Years * n

	// Cut off 100-year cycles
	n = day / daysPer100Years
	if n > 3 { // happens on last day of 400th year
		n = 3
	}
	year += 100 * n
	day -= daysPer100Years * n

	// Cut off 4-year cycles
	n = day / daysPer4Years
	if n > 24 { // happens on last day of 100th year
		n = 24
	}
	year += 4 * n
	day -= daysPer4Years * n

	// Cut off non-leap years.
	n = day / 365
	if n > 3 { // happens on last day of 4th year
		n = 3
	}
	year += n
	day -= 365 * n

	t.Year = year

	// If someone ever needs yearday,
	// tyearday = day (+1?)

	months := months(year)
	var m int
	yday := int(day)
	for m = 0; m < 12 && yday >= months[m]; m++ {
		yday -= months[m]
	}
	t.Month = m + 1
	t.Day = yday + 1
	t.Zone = "UTC"

	return t
}

// UTC returns the current time as a parsed Time value in the UTC time zone.
func UTC() *Time { return SecondsToUTC(Seconds()) }

// SecondsToLocalTime converts sec, in number of seconds since the Unix epoch,
// into a parsed Time value in the local time zone.
func SecondsToLocalTime(sec int64) *Time {
	z, offset := lookupTimezone(sec)
	t := SecondsToUTC(sec + int64(offset))
	t.Zone = z
	t.ZoneOffset = offset
	return t
}

// LocalTime returns the current time as a parsed Time value in the local time zone.
func LocalTime() *Time { return SecondsToLocalTime(Seconds()) }

// Seconds returns the number of seconds since January 1, 1970 represented by the
// parsed Time value.
func (t *Time) Seconds() int64 {
	// First, accumulate days since January 1, 2001.
	// Using 2001 instead of 1970 makes the leap-year
	// handling easier (see SecondsToUTC), because
	// it is at the beginning of the 4-, 100-, and 400-year cycles.
	day := int64(0)

	// Rewrite year to be >= 2001.
	year := t.Year
	if year < 2001 {
		n := (2001-year)/400 + 1
		year += 400 * n
		day -= daysPer400Years * n
	}

	// Add in days from 400-year cycles.
	n := (year - 2001) / 400
	year -= 400 * n
	day += daysPer400Years * n

	// Add in 100-year cycles.
	n = (year - 2001) / 100
	year -= 100 * n
	day += daysPer100Years * n

	// Add in 4-year cycles.
	n = (year - 2001) / 4
	year -= 4 * n
	day += daysPer4Years * n

	// Add in non-leap years.
	n = year - 2001
	day += 365 * n

	// Add in days this year.
	months := months(t.Year)
	for m := 0; m < t.Month-1; m++ {
		day += int64(months[m])
	}
	day += int64(t.Day - 1)

	// Convert days to seconds since January 1, 2001.
	sec := day * secondsPerDay

	// Add in time elapsed today.
	sec += int64(t.Hour) * 3600
	sec += int64(t.Minute) * 60
	sec += int64(t.Second)

	// Convert from seconds since 2001 to seconds since 1970.
	sec += days1970To2001 * secondsPerDay

	// Account for local time zone.
	sec -= int64(t.ZoneOffset)
	return sec
}
<commit_msg>time: fix Time.ZoneOffset documentation<commit_after>// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// The time package provides functionality for measuring and
// displaying time.
package time

// Days of the week.
const (
	Sunday = iota
	Monday
	Tuesday
	Wednesday
	Thursday
	Friday
	Saturday
)

// Time is the struct representing a parsed time value.
type Time struct {
	Year                 int64  // 2006 is 2006
	Month, Day           int    // Jan-2 is 1, 2
	Hour, Minute, Second int    // 15:04:05 is 15, 4, 5.
	Weekday              int    // Sunday, Monday, ...
	ZoneOffset           int    // seconds east of UTC, e.g. -7*60*60 for -0700
	Zone                 string // e.g., "MST"
}

var nonleapyear = []int{31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}
var leapyear = []int{31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}

func months(year int64) []int {
	if year%4 == 0 && (year%100 != 0 || year%400 == 0) {
		return leapyear
	}
	return nonleapyear
}

const (
	secondsPerDay   = 24 * 60 * 60
	daysPer400Years = 365*400 + 97
	daysPer100Years = 365*100 + 24
	daysPer4Years   = 365*4 + 1
	days1970To2001  = 31*365 + 8
)

// SecondsToUTC converts sec, in number of seconds since the Unix epoch,
// into a parsed Time value in the UTC time zone.
func SecondsToUTC(sec int64) *Time {
	t := new(Time)

	// Split into time and day.
	day := sec / secondsPerDay
	sec -= day * secondsPerDay
	if sec < 0 {
		day--
		sec += secondsPerDay
	}

	// Time
	t.Hour = int(sec / 3600)
	t.Minute = int((sec / 60) % 60)
	t.Second = int(sec % 60)

	// Day 0 = January 1, 1970 was a Thursday
	t.Weekday = int((day + Thursday) % 7)
	if t.Weekday < 0 {
		t.Weekday += 7
	}

	// Change day from 0 = 1970 to 0 = 2001,
	// to make leap year calculations easier
	// (2001 begins 4-, 100-, and 400-year cycles ending in a leap year.)
	day -= days1970To2001

	year := int64(2001)
	if day < 0 {
		// Go back enough 400 year cycles to make day positive.
		n := -day/daysPer400Years + 1
		year -= 400 * n
		day += daysPer400Years * n
	}

	// Cut off 400 year cycles.
	n := day / daysPer400Years
	year += 400 * n
	day -= daysPer400Years * n

	// Cut off 100-year cycles
	n = day / daysPer100Years
	if n > 3 { // happens on last day of 400th year
		n = 3
	}
	year += 100 * n
	day -= daysPer100Years * n

	// Cut off 4-year cycles
	n = day / daysPer4Years
	if n > 24 { // happens on last day of 100th year
		n = 24
	}
	year += 4 * n
	day -= daysPer4Years * n

	// Cut off non-leap years.
	n = day / 365
	if n > 3 { // happens on last day of 4th year
		n = 3
	}
	year += n
	day -= 365 * n

	t.Year = year

	// If someone ever needs yearday,
	// tyearday = day (+1?)

	months := months(year)
	var m int
	yday := int(day)
	for m = 0; m < 12 && yday >= months[m]; m++ {
		yday -= months[m]
	}
	t.Month = m + 1
	t.Day = yday + 1
	t.Zone = "UTC"

	return t
}

// UTC returns the current time as a parsed Time value in the UTC time zone.
func UTC() *Time { return SecondsToUTC(Seconds()) }

// SecondsToLocalTime converts sec, in number of seconds since the Unix epoch,
// into a parsed Time value in the local time zone.
func SecondsToLocalTime(sec int64) *Time {
	z, offset := lookupTimezone(sec)
	t := SecondsToUTC(sec + int64(offset))
	t.Zone = z
	t.ZoneOffset = offset
	return t
}

// LocalTime returns the current time as a parsed Time value in the local time zone.
func LocalTime() *Time { return SecondsToLocalTime(Seconds()) }

// Seconds returns the number of seconds since January 1, 1970 represented by the
// parsed Time value.
func (t *Time) Seconds() int64 {
	// First, accumulate days since January 1, 2001.
	// Using 2001 instead of 1970 makes the leap-year
	// handling easier (see SecondsToUTC), because
	// it is at the beginning of the 4-, 100-, and 400-year cycles.
	day := int64(0)

	// Rewrite year to be >= 2001.
	year := t.Year
	if year < 2001 {
		n := (2001-year)/400 + 1
		year += 400 * n
		day -= daysPer400Years * n
	}

	// Add in days from 400-year cycles.
	n := (year - 2001) / 400
	year -= 400 * n
	day += daysPer400Years * n

	// Add in 100-year cycles.
	n = (year - 2001) / 100
	year -= 100 * n
	day += daysPer100Years * n

	// Add in 4-year cycles.
	n = (year - 2001) / 4
	year -= 4 * n
	day += daysPer4Years * n

	// Add in non-leap years.
	n = year - 2001
	day += 365 * n

	// Add in days this year.
	months := months(t.Year)
	for m := 0; m < t.Month-1; m++ {
		day += int64(months[m])
	}
	day += int64(t.Day - 1)

	// Convert days to seconds since January 1, 2001.
	sec := day * secondsPerDay

	// Add in time elapsed today.
	sec += int64(t.Hour) * 3600
	sec += int64(t.Minute) * 60
	sec += int64(t.Second)

	// Convert from seconds since 2001 to seconds since 1970.
	sec += days1970To2001 * secondsPerDay

	// Account for local time zone.
	sec -= int64(t.ZoneOffset)
	return sec
}
<|endoftext|>


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

// Functions and constants to support text encoded in UTF-8.
// This package calls a Unicode character a rune for brevity.
package utf8

import "unicode"	// only needed for a couple of constants

// Numbers fundamental to the encoding.
const (
	RuneError	= unicode.ReplacementChar;	// the "error" Rune or "replacement character".
	RuneSelf	= 0x80;				// characters below Runeself are represented as themselves in a single byte.
	UTFMax		= 4;				// maximum number of bytes of a UTF-8 encoded Unicode character.
)

const (
	_T1	= 0x00;	// 0000 0000
	_Tx	= 0x80;	// 1000 0000
	_T2	= 0xC0;	// 1100 0000
	_T3	= 0xE0;	// 1110 0000
	_T4	= 0xF0;	// 1111 0000
	_T5	= 0xF8;	// 1111 1000

	_Maskx	= 0x3F;	// 0011 1111
	_Mask2	= 0x1F;	// 0001 1111
	_Mask3	= 0x0F;	// 0000 1111
	_Mask4	= 0x07;	// 0000 0111

	_Rune1Max	= 1<<7 - 1;
	_Rune2Max	= 1<<11 - 1;
	_Rune3Max	= 1<<16 - 1;
	_Rune4Max	= 1<<21 - 1;
)

func decodeRuneInternal(p []byte) (rune, size int, short bool) {
	n := len(p);
	if n < 1 {
		return RuneError, 0, true
	}
	c0 := p[0];

	// 1-byte, 7-bit sequence?
	if c0 < _Tx {
		return int(c0), 1, false
	}

	// unexpected continuation byte?
	if c0 < _T2 {
		return RuneError, 1, false
	}

	// need first continuation byte
	if n < 2 {
		return RuneError, 1, true
	}
	c1 := p[1];
	if c1 < _Tx || _T2 <= c1 {
		return RuneError, 1, false
	}

	// 2-byte, 11-bit sequence?
	if c0 < _T3 {
		rune = int(c0&_Mask2)<<6 | int(c1&_Maskx);
		if rune <= _Rune1Max {
			return RuneError, 1, false
		}
		return rune, 2, false;
	}

	// need second continuation byte
	if n < 3 {
		return RuneError, 1, true
	}
	c2 := p[2];
	if c2 < _Tx || _T2 <= c2 {
		return RuneError, 1, false
	}

	// 3-byte, 16-bit sequence?
	if c0 < _T4 {
		rune = int(c0&_Mask3)<<12 | int(c1&_Maskx)<<6 | int(c2&_Maskx);
		if rune <= _Rune2Max {
			return RuneError, 1, false
		}
		return rune, 3, false;
	}

	// need third continuation byte
	if n < 4 {
		return RuneError, 1, true
	}
	c3 := p[3];
	if c3 < _Tx || _T2 <= c3 {
		return RuneError, 1, false
	}

	// 4-byte, 21-bit sequence?
	if c0 < _T5 {
		rune = int(c0&_Mask4)<<18 | int(c1&_Maskx)<<12 | int(c2&_Maskx)<<6 | int(c3&_Maskx);
		if rune <= _Rune3Max {
			return RuneError, 1, false
		}
		return rune, 4, false;
	}

	// error
	return RuneError, 1, false;
}

func decodeRuneInStringInternal(s string) (rune, size int, short bool) {
	n := len(s);
	if n < 1 {
		return RuneError, 0, true
	}
	c0 := s[0];

	// 1-byte, 7-bit sequence?
	if c0 < _Tx {
		return int(c0), 1, false
	}

	// unexpected continuation byte?
	if c0 < _T2 {
		return RuneError, 1, false
	}

	// need first continuation byte
	if n < 2 {
		return RuneError, 1, true
	}
	c1 := s[1];
	if c1 < _Tx || _T2 <= c1 {
		return RuneError, 1, false
	}

	// 2-byte, 11-bit sequence?
	if c0 < _T3 {
		rune = int(c0&_Mask2)<<6 | int(c1&_Maskx);
		if rune <= _Rune1Max {
			return RuneError, 1, false
		}
		return rune, 2, false;
	}

	// need second continuation byte
	if n < 3 {
		return RuneError, 1, true
	}
	c2 := s[2];
	if c2 < _Tx || _T2 <= c2 {
		return RuneError, 1, false
	}

	// 3-byte, 16-bit sequence?
	if c0 < _T4 {
		rune = int(c0&_Mask3)<<12 | int(c1&_Maskx)<<6 | int(c2&_Maskx);
		if rune <= _Rune2Max {
			return RuneError, 1, false
		}
		return rune, 3, false;
	}

	// need third continuation byte
	if n < 4 {
		return RuneError, 1, true
	}
	c3 := s[3];
	if c3 < _Tx || _T2 <= c3 {
		return RuneError, 1, false
	}

	// 4-byte, 21-bit sequence?
	if c0 < _T5 {
		rune = int(c0&_Mask4)<<18 | int(c1&_Maskx)<<12 | int(c2&_Maskx)<<6 | int(c3&_Maskx);
		if rune <= _Rune3Max {
			return RuneError, 1, false
		}
		return rune, 4, false;
	}

	// error
	return RuneError, 1, false;
}

// FullRune reports whether the bytes in p begin with a full UTF-8 encoding of a rune.
// An invalid encoding is considered a full Rune since it will convert as a width-1 error rune.
func FullRune(p []byte) bool {
	_, _, short := decodeRuneInternal(p);
	return !short;
}

// FullRuneInString is like FullRune but its input is a string.
func FullRuneInString(s string) bool {
	_, _, short := decodeRuneInStringInternal(s);
	return !short;
}

// DecodeRune unpacks the first UTF-8 encoding in p and returns the rune and its width in bytes.
func DecodeRune(p []byte) (rune, size int) {
	rune, size, _ = decodeRuneInternal(p);
	return;
}

// DecodeRuneInString is like DecodeRune but its input is a string.
func DecodeRuneInString(s string) (rune, size int) {
	rune, size, _ = decodeRuneInStringInternal(s);
	return;
}

// RuneLen returns the number of bytes required to encode the rune.
func RuneLen(rune int) int {
	switch {
	case rune <= _Rune1Max:
		return 1
	case rune <= _Rune2Max:
		return 2
	case rune <= _Rune3Max:
		return 3
	case rune <= _Rune4Max:
		return 4
	}
	return -1;
}

// EncodeRune writes into p (which must be large enough) the UTF-8 encoding of the rune.
// It returns the number of bytes written.
func EncodeRune(rune int, p []byte) int {
	// Negative values are erroneous.
	if rune < 0 {
		rune = RuneError
	}

	if rune <= _Rune1Max {
		p[0] = byte(rune);
		return 1;
	}

	if rune <= _Rune2Max {
		p[0] = _T2 | byte(rune>>6);
		p[1] = _Tx | byte(rune)&_Maskx;
		return 2;
	}

	if rune > unicode.MaxRune {
		rune = RuneError
	}

	if rune <= _Rune3Max {
		p[0] = _T3 | byte(rune>>12);
		p[1] = _Tx | byte(rune>>6)&_Maskx;
		p[2] = _Tx | byte(rune)&_Maskx;
		return 3;
	}

	p[0] = _T4 | byte(rune>>18);
	p[1] = _Tx | byte(rune>>12)&_Maskx;
	p[2] = _Tx | byte(rune>>6)&_Maskx;
	p[3] = _Tx | byte(rune)&_Maskx;
	return 4;
}

// RuneCount returns the number of runes in p.  Erroneous and short
// encodings are treated as single runes of width 1 byte.
func RuneCount(p []byte) int {
	i := 0;
	var n int;
	for n = 0; i < len(p); n++ {
		if p[i] < RuneSelf {
			i++
		} else {
			_, size := DecodeRune(p[i:]);
			i += size;
		}
	}
	return n;
}

// RuneCountInString is like RuneCount but its input is a string.
func RuneCountInString(s string) (n int) {
	for _ = range s {
		n++
	}
	return;
}

// RuneStart reports whether the byte could be the first byte of
// an encoded rune.  Second and subsequent bytes always have the top
// two bits set to 10.
func RuneStart(b byte) bool	{ return b&0xC0 != 0x80 }
<commit_msg>simpler fix for the negative rune problem, spotted seconds after submitting the previous fix.<commit_after>// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Functions and constants to support text encoded in UTF-8.
// This package calls a Unicode character a rune for brevity.
package utf8

import "unicode"	// only needed for a couple of constants

// Numbers fundamental to the encoding.
const (
	RuneError	= unicode.ReplacementChar;	// the "error" Rune or "replacement character".
	RuneSelf	= 0x80;				// characters below Runeself are represented as themselves in a single byte.
	UTFMax		= 4;				// maximum number of bytes of a UTF-8 encoded Unicode character.
)

const (
	_T1	= 0x00;	// 0000 0000
	_Tx	= 0x80;	// 1000 0000
	_T2	= 0xC0;	// 1100 0000
	_T3	= 0xE0;	// 1110 0000
	_T4	= 0xF0;	// 1111 0000
	_T5	= 0xF8;	// 1111 1000

	_Maskx	= 0x3F;	// 0011 1111
	_Mask2	= 0x1F;	// 0001 1111
	_Mask3	= 0x0F;	// 0000 1111
	_Mask4	= 0x07;	// 0000 0111

	_Rune1Max	= 1<<7 - 1;
	_Rune2Max	= 1<<11 - 1;
	_Rune3Max	= 1<<16 - 1;
	_Rune4Max	= 1<<21 - 1;
)

func decodeRuneInternal(p []byte) (rune, size int, short bool) {
	n := len(p);
	if n < 1 {
		return RuneError, 0, true
	}
	c0 := p[0];

	// 1-byte, 7-bit sequence?
	if c0 < _Tx {
		return int(c0), 1, false
	}

	// unexpected continuation byte?
	if c0 < _T2 {
		return RuneError, 1, false
	}

	// need first continuation byte
	if n < 2 {
		return RuneError, 1, true
	}
	c1 := p[1];
	if c1 < _Tx || _T2 <= c1 {
		return RuneError, 1, false
	}

	// 2-byte, 11-bit sequence?
	if c0 < _T3 {
		rune = int(c0&_Mask2)<<6 | int(c1&_Maskx);
		if rune <= _Rune1Max {
			return RuneError, 1, false
		}
		return rune, 2, false;
	}

	// need second continuation byte
	if n < 3 {
		return RuneError, 1, true
	}
	c2 := p[2];
	if c2 < _Tx || _T2 <= c2 {
		return RuneError, 1, false
	}

	// 3-byte, 16-bit sequence?
	if c0 < _T4 {
		rune = int(c0&_Mask3)<<12 | int(c1&_Maskx)<<6 | int(c2&_Maskx);
		if rune <= _Rune2Max {
			return RuneError, 1, false
		}
		return rune, 3, false;
	}

	// need third continuation byte
	if n < 4 {
		return RuneError, 1, true
	}
	c3 := p[3];
	if c3 < _Tx || _T2 <= c3 {
		return RuneError, 1, false
	}

	// 4-byte, 21-bit sequence?
	if c0 < _T5 {
		rune = int(c0&_Mask4)<<18 | int(c1&_Maskx)<<12 | int(c2&_Maskx)<<6 | int(c3&_Maskx);
		if rune <= _Rune3Max {
			return RuneError, 1, false
		}
		return rune, 4, false;
	}

	// error
	return RuneError, 1, false;
}

func decodeRuneInStringInternal(s string) (rune, size int, short bool) {
	n := len(s);
	if n < 1 {
		return RuneError, 0, true
	}
	c0 := s[0];

	// 1-byte, 7-bit sequence?
	if c0 < _Tx {
		return int(c0), 1, false
	}

	// unexpected continuation byte?
	if c0 < _T2 {
		return RuneError, 1, false
	}

	// need first continuation byte
	if n < 2 {
		return RuneError, 1, true
	}
	c1 := s[1];
	if c1 < _Tx || _T2 <= c1 {
		return RuneError, 1, false
	}

	// 2-byte, 11-bit sequence?
	if c0 < _T3 {
		rune = int(c0&_Mask2)<<6 | int(c1&_Maskx);
		if rune <= _Rune1Max {
			return RuneError, 1, false
		}
		return rune, 2, false;
	}

	// need second continuation byte
	if n < 3 {
		return RuneError, 1, true
	}
	c2 := s[2];
	if c2 < _Tx || _T2 <= c2 {
		return RuneError, 1, false
	}

	// 3-byte, 16-bit sequence?
	if c0 < _T4 {
		rune = int(c0&_Mask3)<<12 | int(c1&_Maskx)<<6 | int(c2&_Maskx);
		if rune <= _Rune2Max {
			return RuneError, 1, false
		}
		return rune, 3, false;
	}

	// need third continuation byte
	if n < 4 {
		return RuneError, 1, true
	}
	c3 := s[3];
	if c3 < _Tx || _T2 <= c3 {
		return RuneError, 1, false
	}

	// 4-byte, 21-bit sequence?
	if c0 < _T5 {
		rune = int(c0&_Mask4)<<18 | int(c1&_Maskx)<<12 | int(c2&_Maskx)<<6 | int(c3&_Maskx);
		if rune <= _Rune3Max {
			return RuneError, 1, false
		}
		return rune, 4, false;
	}

	// error
	return RuneError, 1, false;
}

// FullRune reports whether the bytes in p begin with a full UTF-8 encoding of a rune.
// An invalid encoding is considered a full Rune since it will convert as a width-1 error rune.
func FullRune(p []byte) bool {
	_, _, short := decodeRuneInternal(p);
	return !short;
}

// FullRuneInString is like FullRune but its input is a string.
func FullRuneInString(s string) bool {
	_, _, short := decodeRuneInStringInternal(s);
	return !short;
}

// DecodeRune unpacks the first UTF-8 encoding in p and returns the rune and its width in bytes.
func DecodeRune(p []byte) (rune, size int) {
	rune, size, _ = decodeRuneInternal(p);
	return;
}

// DecodeRuneInString is like DecodeRune but its input is a string.
func DecodeRuneInString(s string) (rune, size int) {
	rune, size, _ = decodeRuneInStringInternal(s);
	return;
}

// RuneLen returns the number of bytes required to encode the rune.
func RuneLen(rune int) int {
	switch {
	case rune <= _Rune1Max:
		return 1
	case rune <= _Rune2Max:
		return 2
	case rune <= _Rune3Max:
		return 3
	case rune <= _Rune4Max:
		return 4
	}
	return -1;
}

// EncodeRune writes into p (which must be large enough) the UTF-8 encoding of the rune.
// It returns the number of bytes written.
func EncodeRune(rune int, p []byte) int {
	// Negative values are erroneous.  Making it unsigned addresses the problem.
	r := uint(rune);

	if r <= _Rune1Max {
		p[0] = byte(r);
		return 1;
	}

	if r <= _Rune2Max {
		p[0] = _T2 | byte(r>>6);
		p[1] = _Tx | byte(r)&_Maskx;
		return 2;
	}

	if r > unicode.MaxRune {
		r = RuneError
	}

	if r <= _Rune3Max {
		p[0] = _T3 | byte(r>>12);
		p[1] = _Tx | byte(r>>6)&_Maskx;
		p[2] = _Tx | byte(r)&_Maskx;
		return 3;
	}

	p[0] = _T4 | byte(r>>18);
	p[1] = _Tx | byte(r>>12)&_Maskx;
	p[2] = _Tx | byte(r>>6)&_Maskx;
	p[3] = _Tx | byte(r)&_Maskx;
	return 4;
}

// RuneCount returns the number of runes in p.  Erroneous and short
// encodings are treated as single runes of width 1 byte.
func RuneCount(p []byte) int {
	i := 0;
	var n int;
	for n = 0; i < len(p); n++ {
		if p[i] < RuneSelf {
			i++
		} else {
			_, size := DecodeRune(p[i:]);
			i += size;
		}
	}
	return n;
}

// RuneCountInString is like RuneCount but its input is a string.
func RuneCountInString(s string) (n int) {
	for _ = range s {
		n++
	}
	return;
}

// RuneStart reports whether the byte could be the first byte of
// an encoded rune.  Second and subsequent bytes always have the top
// two bits set to 10.
func RuneStart(b byte) bool	{ return b&0xC0 != 0x80 }
<|endoftext|>


<commit_before>/*
 * Groovy music player daemon.
 *
 * Copyright (c) 2014, Alessandro Ghedini
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

package player

// #cgo pkg-config: mpv
// #include <mpv/client.h>
import "C"

import "fmt"
import "log"
import "strconv"
import "sync"

import "github.com/vaughan0/go-ini"

import "library"
import "notify"
import "util"

type Event byte
type Status byte

const (
	StatusPlaying Status = iota
	StatusPaused
	StatusStopped
)

func (s Status) String() string {
	switch s {
	case StatusPlaying:
		return "play"

	case StatusPaused:
		return "pause"

	case StatusStopped:
		return "stop"
	}

	return "invalid"
}

type Player struct {
	handle *C.mpv_handle
	Status Status

	library string
	notify  bool
	started bool

	Verbose bool

	HandleStatusChange func()
	HandleTrackChange  func()
	HandleTracksChange func()
	HandleVolumeChange func()

	Wait sync.WaitGroup
}

func (p *Player) ChangeStatus(status Status) {
	p.Status = status
	p.HandleStatusChange()
}

func (p *Player) Play() error {
	switch p.Status {
	case StatusPlaying:
		return nil

	case StatusStopped:
		count, err := p.GetProperty("playlist-count")
		if err == nil && count.(int64) > 0 {
			return p.GotoTrack(0)
		}

		p.AddTrack("", true)
		fallthrough

	case StatusPaused:
		return p.SetProperty("pause", "no")
	}

	return fmt.Errorf("Invalid player state")
}

func (p *Player) Pause() error {
	switch p.Status {
	case StatusPaused, StatusStopped:
		return nil

	case StatusPlaying:
		return p.SetProperty("pause", "yes")
	}

	return fmt.Errorf("Invalid player state")
}

func (p *Player) Toggle() error {
	switch p.Status {
	case StatusPaused, StatusStopped:
		return p.Play()

	case StatusPlaying:
		return p.Pause()
	}

	return fmt.Errorf("Invalid player state")
}

func (p *Player) Next() error {
	return p.Command([]string{"playlist_next", "force"})
}

func (p *Player) Prev() error {
	return p.Command([]string{"playlist_prev", "weak"})
}

func (p *Player) Stop() error {
	err := p.Command([]string{"stop"})

	p.ChangeStatus(StatusStopped)
	p.HandleTrackChange()

	return err
}

func (p *Player) Seek(seconds int64) error {
	secs := strconv.FormatInt(seconds, 10)
	return p.Command([]string{"seek", secs})
}

func (p *Player) List() ([]string, error) {
	playlist, err := p.GetProperty("playlist")
	if err != nil {
		return nil, nil
	}

	var files []string

	for _, entry := range playlist.([]interface{}) {
		if entry == nil {
			continue
		}

		entry_map := entry.(map[string]interface{})

		files = append(files, entry_map["filename"].(string))
	}

	return files, nil
}

func (p *Player) AddTrack(path string, play bool) error {
	var mode string

	if play {
		mode = "append-play"
	} else {
		mode = "append"
	}

	if path == "" {
		var err error

		path, err = library.Random(p.library)
		if err != nil {
			return fmt.Errorf("Could not get random track: %s", err)
		}
	}

	return p.Command([]string{"loadfile", path, mode})
}

func (p *Player) AddList(path string) error {
	return p.Command([]string{"loadlist", path, "append"})
}

func (p *Player) GotoTrack(index int64) error {
	return p.SetProperty("playlist-pos", index)
}

func (p *Player) RemoveTrack(index int64) error {
	var track string

	if index < 0 {
		track = "current"
	} else {
		track = strconv.FormatInt(index, 10)
	}

	return p.Command([]string{"playlist_remove", track})
}

func (p *Player) Quit() error {
	return p.Command([]string{"quit"})
}

func (p *Player) GetTrackMetadata() (map[string]string, error) {
	metadata, err := p.GetProperty("metadata")
	if err != nil {
		return nil, err
	}

	metadata_str := map[string]string{}

	for key, val := range metadata.(map[string]interface{}) {
		metadata_str[key] = val.(string)
	}

	return metadata_str, err
}

func (p *Player) GetTrackLength() (float64, error) {
	length, err := p.GetProperty("length")
	if err != nil {
		return 0.0, err
	}

	return length.(float64), nil
}

func (p *Player) GetTrackPath() (string, error) {
	path, err := p.GetProperty("path")
	if err != nil {
		return "", err
	}

	return path.(string), nil
}

func (p *Player) GetTrackPosition(percent bool) (float64, error) {
	var err error
	var pos interface{}

	if !percent {
		pos, err = p.GetProperty("time-pos")
	} else {
		pos, err = p.GetProperty("percent-pos")
	}

	if err != nil {
		return 0.0, err
	}

	return pos.(float64), nil
}

func (p *Player) GetTrackTitle() (string, error) {
	title, err := p.GetProperty("media-title")
	if err != nil {
		return "", nil
	}

	metadata, err := p.GetTrackMetadata()
	if err != nil {
		return title.(string), nil
	}

	artist := metadata["artist"]
	if artist == "" {
		artist = metadata["ARTIST"]
	}

	if artist != "" {
		return fmt.Sprintf("%s - %s", artist, title.(string)), nil
	}

	return title.(string), nil
}

func (p *Player) SetLoopStatus(mode string) error {
	switch mode {
	case "none":
		p.SetProperty("loop-file", false)
		p.SetProperty("loop", "no")

	case "track":
		p.SetLoopStatus("none")
		p.SetProperty("loop-file", true)

	case "list":
		p.SetLoopStatus("none")
		p.SetProperty("loop", "inf")

	case "force":
		p.SetLoopStatus("none")
		p.SetProperty("loop", "force")

	default:
		return fmt.Errorf("Invalid mode")
	}

	return nil
}

func (p *Player) GetOutputList() ([]string, error) {
	outputs, err := p.GetProperty("option-info/ao/choices")
	if err != nil {
		return nil, err
	}

	outs := []string{}
	for _, output := range outputs.([]interface{}) {
		outs = append(outs, output.(string))
	}

	return outs, nil
}

func Init(cfg ini.File) (*Player, error) {
	p := &Player{
		Status:  StatusStopped,
		started: false,
	}

	p.handle = C.mpv_create()
	if p.handle == nil {
		return nil, fmt.Errorf("Could not create player")
	}

	err := p.SetOptionString("audio-client-name", "grooved")
	if err != nil {
		return nil, fmt.Errorf("Could not set option 'audio-client-name': %s", err)
	}

	err = p.SetOptionString("title", "${?media-title:${media-title}}${!media-title:No file.}")
	if err != nil {
		return nil, fmt.Errorf("Could not set option 'title': %s", err)
	}

	err = p.SetOptionString("no-config", "")
	if err != nil {
		return nil, fmt.Errorf("Could not set option 'no-config': %s", err)
	}

	err = p.SetOptionString("no-video", "")
	if err != nil {
		return nil, fmt.Errorf("Could not set option 'no-video': %s", err)
	}

	err = p.SetOptionString("no-sub", "")
	if err != nil {
		return nil, fmt.Errorf("Could not set option 'no-sub': %s", err)
	}

	err = p.SetOptionString("no-softvol", "")
	if err != nil {
		return nil, fmt.Errorf("Could not set option 'no-softvol': %s", err)
	}

	if cfg["default"]["cache"] != "" {
		p.SetOptionString("cache", cfg["default"]["cache"])
	}

	if cfg["default"]["gapless"] != "" {
		p.SetOptionString("gapless-audio", cfg["default"]["gapless"])
	}

	p.library, _ = util.ExpandUser(cfg["default"]["library"])

	if cfg["default"]["notify"] == "yes" {
		p.notify = true
	} else {
		p.notify = false
	}

	if cfg["default"]["replaygain"] != "" {
		rgain_af := fmt.Sprintf("volume=replaygain-%s", cfg["default"]["replaygain"])
		if cfg["default"]["filters"] != "" {
			cfg["default"]["filters"] += "," + rgain_af
		} else {
			cfg["default"]["filters"] = rgain_af
		}
	}

	if cfg["default"]["output"] != "" {
		p.SetOptionString("ao", cfg["default"]["output"])
	}

	if cfg["default"]["ytdl"] != "" {
		p.SetOptionString("ytdl", cfg["default"]["ytdl"])
	}

	if cfg["default"]["verbose"] != "" {
		p.Verbose = true
	}

	if cfg["default"]["filters"] != "" {
		p.SetOptionString("af", cfg["default"]["filters"])
	}

	if cfg["default"]["scripts"] != "" {
		p.SetOptionString("lua", cfg["default"]["scripts"])
	}

	C.mpv_request_log_messages(p.handle, C.CString("warn"))

	mp_err := C.mpv_initialize(p.handle)
	if mp_err != 0 {
		return nil, ErrorString(mp_err)
	}

	return p, nil
}

func (p *Player) Run() error {
	p.Wait.Add(1)

	go p.EventLoop()

	return nil
}

func (p *Player) HandlePauseChange() {
	if !p.started {
		return
	}

	pause, err := p.GetProperty("pause")
	if err != nil {
		return
	}

	if pause.(bool) {
		p.ChangeStatus(StatusPaused)
	} else {
		p.ChangeStatus(StatusPlaying)
	}
}

func (p *Player) HandleMetadataChange() {
	if !p.started {
		return
	}

	if p.notify {
		msg, _ := p.GetTrackTitle()
		notify.Notify("Now Playing:", msg, "media-playback-start")
	}

	p.HandleTrackChange()
}

func (p *Player) EventLoop() {
	p.ObserveProperty("pause",    FormatFlag)
	p.ObserveProperty("metadata", FormatNode)
	p.ObserveProperty("playlist", FormatNode)
	p.ObserveProperty("volume", FormatNode)

	for {
		ev := C.mpv_wait_event(p.handle, -1)
		ev_name := C.GoString(C.mpv_event_name(ev.event_id))

		if p.Verbose {
			log.Printf("Event %s\n", ev_name)
		}

		switch ev_name {
		case "idle":
			if p.Status == StatusStopped {
				break
			}

			err := p.AddTrack("", true)
			if err != nil {
				log.Println("Could not add track: %s", err)
				p.ChangeStatus(StatusStopped)
			}

		case "start-file":
			p.started = true
			p.HandlePauseChange()

		case "property-change":
			prop := (*C.mpv_event_property)(ev.data)
			prop_name := C.GoString(prop.name)

			if prop.format == FormatNone {
				break
			}

			if p.Verbose {
				log.Printf("Property %s\n", prop_name)
			}

			switch prop_name {
			case "pause":
				p.HandlePauseChange()

			case "metadata":
				p.HandleMetadataChange()

			case "playlist":
				p.HandleTracksChange()

			case "volume":
				p.HandleVolumeChange()
			}

		case "log-message":
			mp_log := (*C.mpv_event_log_message)(ev.data)
			log.Printf("%s: %s: %s",
			           C.GoString(mp_log.level),
			           C.GoString(mp_log.prefix),
			           C.GoString(mp_log.text))

		case "shutdown":
			p.Wait.Done()
			return
		}
	}
}
<commit_msg>player: fix Printf() call<commit_after>/*
 * Groovy music player daemon.
 *
 * Copyright (c) 2014, Alessandro Ghedini
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

package player

// #cgo pkg-config: mpv
// #include <mpv/client.h>
import "C"

import "fmt"
import "log"
import "strconv"
import "sync"

import "github.com/vaughan0/go-ini"

import "library"
import "notify"
import "util"

type Event byte
type Status byte

const (
	StatusPlaying Status = iota
	StatusPaused
	StatusStopped
)

func (s Status) String() string {
	switch s {
	case StatusPlaying:
		return "play"

	case StatusPaused:
		return "pause"

	case StatusStopped:
		return "stop"
	}

	return "invalid"
}

type Player struct {
	handle *C.mpv_handle
	Status Status

	library string
	notify  bool
	started bool

	Verbose bool

	HandleStatusChange func()
	HandleTrackChange  func()
	HandleTracksChange func()
	HandleVolumeChange func()

	Wait sync.WaitGroup
}

func (p *Player) ChangeStatus(status Status) {
	p.Status = status
	p.HandleStatusChange()
}

func (p *Player) Play() error {
	switch p.Status {
	case StatusPlaying:
		return nil

	case StatusStopped:
		count, err := p.GetProperty("playlist-count")
		if err == nil && count.(int64) > 0 {
			return p.GotoTrack(0)
		}

		p.AddTrack("", true)
		fallthrough

	case StatusPaused:
		return p.SetProperty("pause", "no")
	}

	return fmt.Errorf("Invalid player state")
}

func (p *Player) Pause() error {
	switch p.Status {
	case StatusPaused, StatusStopped:
		return nil

	case StatusPlaying:
		return p.SetProperty("pause", "yes")
	}

	return fmt.Errorf("Invalid player state")
}

func (p *Player) Toggle() error {
	switch p.Status {
	case StatusPaused, StatusStopped:
		return p.Play()

	case StatusPlaying:
		return p.Pause()
	}

	return fmt.Errorf("Invalid player state")
}

func (p *Player) Next() error {
	return p.Command([]string{"playlist_next", "force"})
}

func (p *Player) Prev() error {
	return p.Command([]string{"playlist_prev", "weak"})
}

func (p *Player) Stop() error {
	err := p.Command([]string{"stop"})

	p.ChangeStatus(StatusStopped)
	p.HandleTrackChange()

	return err
}

func (p *Player) Seek(seconds int64) error {
	secs := strconv.FormatInt(seconds, 10)
	return p.Command([]string{"seek", secs})
}

func (p *Player) List() ([]string, error) {
	playlist, err := p.GetProperty("playlist")
	if err != nil {
		return nil, nil
	}

	var files []string

	for _, entry := range playlist.([]interface{}) {
		if entry == nil {
			continue
		}

		entry_map := entry.(map[string]interface{})

		files = append(files, entry_map["filename"].(string))
	}

	return files, nil
}

func (p *Player) AddTrack(path string, play bool) error {
	var mode string

	if play {
		mode = "append-play"
	} else {
		mode = "append"
	}

	if path == "" {
		var err error

		path, err = library.Random(p.library)
		if err != nil {
			return fmt.Errorf("Could not get random track: %s", err)
		}
	}

	return p.Command([]string{"loadfile", path, mode})
}

func (p *Player) AddList(path string) error {
	return p.Command([]string{"loadlist", path, "append"})
}

func (p *Player) GotoTrack(index int64) error {
	return p.SetProperty("playlist-pos", index)
}

func (p *Player) RemoveTrack(index int64) error {
	var track string

	if index < 0 {
		track = "current"
	} else {
		track = strconv.FormatInt(index, 10)
	}

	return p.Command([]string{"playlist_remove", track})
}

func (p *Player) Quit() error {
	return p.Command([]string{"quit"})
}

func (p *Player) GetTrackMetadata() (map[string]string, error) {
	metadata, err := p.GetProperty("metadata")
	if err != nil {
		return nil, err
	}

	metadata_str := map[string]string{}

	for key, val := range metadata.(map[string]interface{}) {
		metadata_str[key] = val.(string)
	}

	return metadata_str, err
}

func (p *Player) GetTrackLength() (float64, error) {
	length, err := p.GetProperty("length")
	if err != nil {
		return 0.0, err
	}

	return length.(float64), nil
}

func (p *Player) GetTrackPath() (string, error) {
	path, err := p.GetProperty("path")
	if err != nil {
		return "", err
	}

	return path.(string), nil
}

func (p *Player) GetTrackPosition(percent bool) (float64, error) {
	var err error
	var pos interface{}

	if !percent {
		pos, err = p.GetProperty("time-pos")
	} else {
		pos, err = p.GetProperty("percent-pos")
	}

	if err != nil {
		return 0.0, err
	}

	return pos.(float64), nil
}

func (p *Player) GetTrackTitle() (string, error) {
	title, err := p.GetProperty("media-title")
	if err != nil {
		return "", nil
	}

	metadata, err := p.GetTrackMetadata()
	if err != nil {
		return title.(string), nil
	}

	artist := metadata["artist"]
	if artist == "" {
		artist = metadata["ARTIST"]
	}

	if artist != "" {
		return fmt.Sprintf("%s - %s", artist, title.(string)), nil
	}

	return title.(string), nil
}

func (p *Player) SetLoopStatus(mode string) error {
	switch mode {
	case "none":
		p.SetProperty("loop-file", false)
		p.SetProperty("loop", "no")

	case "track":
		p.SetLoopStatus("none")
		p.SetProperty("loop-file", true)

	case "list":
		p.SetLoopStatus("none")
		p.SetProperty("loop", "inf")

	case "force":
		p.SetLoopStatus("none")
		p.SetProperty("loop", "force")

	default:
		return fmt.Errorf("Invalid mode")
	}

	return nil
}

func (p *Player) GetOutputList() ([]string, error) {
	outputs, err := p.GetProperty("option-info/ao/choices")
	if err != nil {
		return nil, err
	}

	outs := []string{}
	for _, output := range outputs.([]interface{}) {
		outs = append(outs, output.(string))
	}

	return outs, nil
}

func Init(cfg ini.File) (*Player, error) {
	p := &Player{
		Status:  StatusStopped,
		started: false,
	}

	p.handle = C.mpv_create()
	if p.handle == nil {
		return nil, fmt.Errorf("Could not create player")
	}

	err := p.SetOptionString("audio-client-name", "grooved")
	if err != nil {
		return nil, fmt.Errorf("Could not set option 'audio-client-name': %s", err)
	}

	err = p.SetOptionString("title", "${?media-title:${media-title}}${!media-title:No file.}")
	if err != nil {
		return nil, fmt.Errorf("Could not set option 'title': %s", err)
	}

	err = p.SetOptionString("no-config", "")
	if err != nil {
		return nil, fmt.Errorf("Could not set option 'no-config': %s", err)
	}

	err = p.SetOptionString("no-video", "")
	if err != nil {
		return nil, fmt.Errorf("Could not set option 'no-video': %s", err)
	}

	err = p.SetOptionString("no-sub", "")
	if err != nil {
		return nil, fmt.Errorf("Could not set option 'no-sub': %s", err)
	}

	err = p.SetOptionString("no-softvol", "")
	if err != nil {
		return nil, fmt.Errorf("Could not set option 'no-softvol': %s", err)
	}

	if cfg["default"]["cache"] != "" {
		p.SetOptionString("cache", cfg["default"]["cache"])
	}

	if cfg["default"]["gapless"] != "" {
		p.SetOptionString("gapless-audio", cfg["default"]["gapless"])
	}

	p.library, _ = util.ExpandUser(cfg["default"]["library"])

	if cfg["default"]["notify"] == "yes" {
		p.notify = true
	} else {
		p.notify = false
	}

	if cfg["default"]["replaygain"] != "" {
		rgain_af := fmt.Sprintf("volume=replaygain-%s", cfg["default"]["replaygain"])
		if cfg["default"]["filters"] != "" {
			cfg["default"]["filters"] += "," + rgain_af
		} else {
			cfg["default"]["filters"] = rgain_af
		}
	}

	if cfg["default"]["output"] != "" {
		p.SetOptionString("ao", cfg["default"]["output"])
	}

	if cfg["default"]["ytdl"] != "" {
		p.SetOptionString("ytdl", cfg["default"]["ytdl"])
	}

	if cfg["default"]["verbose"] != "" {
		p.Verbose = true
	}

	if cfg["default"]["filters"] != "" {
		p.SetOptionString("af", cfg["default"]["filters"])
	}

	if cfg["default"]["scripts"] != "" {
		p.SetOptionString("lua", cfg["default"]["scripts"])
	}

	C.mpv_request_log_messages(p.handle, C.CString("warn"))

	mp_err := C.mpv_initialize(p.handle)
	if mp_err != 0 {
		return nil, ErrorString(mp_err)
	}

	return p, nil
}

func (p *Player) Run() error {
	p.Wait.Add(1)

	go p.EventLoop()

	return nil
}

func (p *Player) HandlePauseChange() {
	if !p.started {
		return
	}

	pause, err := p.GetProperty("pause")
	if err != nil {
		return
	}

	if pause.(bool) {
		p.ChangeStatus(StatusPaused)
	} else {
		p.ChangeStatus(StatusPlaying)
	}
}

func (p *Player) HandleMetadataChange() {
	if !p.started {
		return
	}

	if p.notify {
		msg, _ := p.GetTrackTitle()
		notify.Notify("Now Playing:", msg, "media-playback-start")
	}

	p.HandleTrackChange()
}

func (p *Player) EventLoop() {
	p.ObserveProperty("pause",    FormatFlag)
	p.ObserveProperty("metadata", FormatNode)
	p.ObserveProperty("playlist", FormatNode)
	p.ObserveProperty("volume", FormatNode)

	for {
		ev := C.mpv_wait_event(p.handle, -1)
		ev_name := C.GoString(C.mpv_event_name(ev.event_id))

		if p.Verbose {
			log.Printf("Event %s\n", ev_name)
		}

		switch ev_name {
		case "idle":
			if p.Status == StatusStopped {
				break
			}

			err := p.AddTrack("", true)
			if err != nil {
				log.Printf("Could not add track: %s\n", err)
				p.ChangeStatus(StatusStopped)
			}

		case "start-file":
			p.started = true
			p.HandlePauseChange()

		case "property-change":
			prop := (*C.mpv_event_property)(ev.data)
			prop_name := C.GoString(prop.name)

			if prop.format == FormatNone {
				break
			}

			if p.Verbose {
				log.Printf("Property %s\n", prop_name)
			}

			switch prop_name {
			case "pause":
				p.HandlePauseChange()

			case "metadata":
				p.HandleMetadataChange()

			case "playlist":
				p.HandleTracksChange()

			case "volume":
				p.HandleVolumeChange()
			}

		case "log-message":
			mp_log := (*C.mpv_event_log_message)(ev.data)
			log.Printf("%s: %s: %s",
			           C.GoString(mp_log.level),
			           C.GoString(mp_log.prefix),
			           C.GoString(mp_log.text))

		case "shutdown":
			p.Wait.Done()
			return
		}
	}
}
<|endoftext|>


<commit_before>package version

var (
	// Version should be updated by hand at each release
	Version = "0.5.0-dev"

	// GitCommit will be overwritten automatically by the build system
	GitCommit = "HEAD"
)
<commit_msg>Bump version for release candidate<commit_after>package version

var (
	// Version should be updated by hand at each release
	Version = "0.5.0-rc1"

	// GitCommit will be overwritten automatically by the build system
	GitCommit = "HEAD"
)
<|endoftext|>


<commit_before>/*
Copyright 2017 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 model

import (
	"errors"
	"fmt"
	"strings"

	"k8s.io/kops/pkg/apis/kops"
	"k8s.io/kops/pkg/systemd"
	"k8s.io/kops/upup/pkg/fi"
	"k8s.io/kops/upup/pkg/fi/nodeup/nodetasks"

	"github.com/golang/glog"
)

// HookBuilder configures the hooks
type HookBuilder struct {
	*NodeupModelContext
}

var _ fi.ModelBuilder = &HookBuilder{}

// Build is responsible for implementing the cluster hook
func (h *HookBuilder) Build(c *fi.ModelBuilderContext) error {
	// we keep a list of hooks name so we can allow local instanceGroup hooks override the cluster ones
	hookNames := make(map[string]bool, 0)
	for i, spec := range []*[]kops.HookSpec{&h.InstanceGroup.Spec.Hooks, &h.Cluster.Spec.Hooks} {
		for j, hook := range *spec {
			isInstanceGroup := i == 0
			// filter roles if required
			if len(hook.Roles) > 0 && !containsRole(h.InstanceGroup.Spec.Role, hook.Roles) {
				continue
			}

			// i dont want to effect those whom are already using the hooks, so i'm gonna try an keep the name for now
			// i.e. use the default naming convention - kops-hook-<index>, only those using the Name or hooks in IG should alter
			var name string
			switch hook.Name {
			case "":
				name = fmt.Sprintf("kops-hook-%d.service", j)
				if isInstanceGroup {
					name = fmt.Sprintf("%s-ig.service", name)
				}
			default:
				name = fmt.Sprintf("%s.service", hook.Name)
			}

			if _, found := hookNames[name]; found {
				glog.V(2).Infof("Skipping the hook: %v as we've already processed a similar service name", name)
				continue
			}
			hookNames[name] = true

			// are we disabling the service?
			if hook.Disabled {
				enabled := false
				managed := true
				c.AddTask(&nodetasks.Service{
					Name:        hook.Name,
					ManageState: &managed,
					Enabled:     &enabled,
					Running:     &enabled,
				})
				continue
			}

			service, err := h.buildSystemdService(name, &hook)
			if err != nil {
				return err
			}

			if service != nil {
				c.AddTask(service)
			}
		}
	}

	return nil
}

// buildSystemdService is responsible for generating the service
func (h *HookBuilder) buildSystemdService(name string, hook *kops.HookSpec) (*nodetasks.Service, error) {
	// perform some basic validation
	if hook.ExecContainer == nil && hook.Manifest == "" {
		glog.Warningf("hook: %s has neither a raw unit or exec image configured", name)
		return nil, nil
	}
	if hook.ExecContainer != nil {
		if err := isValidExecContainerAction(hook.ExecContainer); err != nil {
			glog.Warningf("invalid hook action, name: %s, error: %v", name, err)
			return nil, nil
		}
	}
	// build the base unit file
	unit := &systemd.Manifest{}
	unit.Set("Unit", "Description", "Kops Hook "+name)

	// add any service dependencies to the unit
	for _, x := range hook.Requires {
		unit.Set("Unit", "Requires", x)
	}
	for _, x := range hook.Before {
		unit.Set("Unit", "Before", x)
	}

	// are we a raw unit file or a docker exec?
	switch hook.ExecContainer {
	case nil:
		unit.SetSection("Service", hook.Manifest)
	default:
		if err := h.buildDockerService(unit, hook); err != nil {
			return nil, err
		}
	}

	service := &nodetasks.Service{
		Name:       name,
		Definition: s(unit.Render()),
	}

	service.InitDefaults()

	return service, nil
}

// buildDockerService is responsible for generating a docker exec unit file
func (h *HookBuilder) buildDockerService(unit *systemd.Manifest, hook *kops.HookSpec) error {
	dockerArgs := []string{
		"/usr/bin/docker", "run",
		"-v", "/:/rootfs/",
		"-v", "/var/run/dbus:/var/run/dbus",
		"-v", "/run/systemd:/run/systemd",
		"--net=host",
		"--privileged",
	}
	dockerArgs = append(dockerArgs, buildDockerEnvironmentVars(hook.ExecContainer.Environment)...)
	dockerArgs = append(dockerArgs, hook.ExecContainer.Image)
	dockerArgs = append(dockerArgs, hook.ExecContainer.Command...)

	dockerRunCommand := systemd.EscapeCommand(dockerArgs)
	dockerPullCommand := systemd.EscapeCommand([]string{"/usr/bin/docker", "pull", hook.ExecContainer.Image})

	unit.Set("Unit", "Requires", "docker.service")
	unit.Set("Service", "ExecStartPre", dockerPullCommand)
	unit.Set("Service", "ExecStart", dockerRunCommand)
	unit.Set("Service", "Type", "oneshot")
	unit.Set("Install", "WantedBy", "multi-user.target")

	return nil
}

// isValidExecContainerAction checks the validatity of the execContainer - personally i think this validation
// should be done high up the chain, but
func isValidExecContainerAction(action *kops.ExecContainerAction) error {
	action.Image = strings.TrimSpace(action.Image)
	if action.Image == "" {
		return errors.New("the image for the hook exec action not set")
	}

	return nil
}
<commit_msg>Don't add .service extension if already there<commit_after>/*
Copyright 2017 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 model

import (
	"errors"
	"fmt"
	"strings"

	"k8s.io/kops/pkg/apis/kops"
	"k8s.io/kops/pkg/systemd"
	"k8s.io/kops/upup/pkg/fi"
	"k8s.io/kops/upup/pkg/fi/nodeup/nodetasks"

	"github.com/golang/glog"
)

// HookBuilder configures the hooks
type HookBuilder struct {
	*NodeupModelContext
}

var _ fi.ModelBuilder = &HookBuilder{}

// Build is responsible for implementing the cluster hook
func (h *HookBuilder) Build(c *fi.ModelBuilderContext) error {
	// we keep a list of hooks name so we can allow local instanceGroup hooks override the cluster ones
	hookNames := make(map[string]bool, 0)
	for i, spec := range []*[]kops.HookSpec{&h.InstanceGroup.Spec.Hooks, &h.Cluster.Spec.Hooks} {
		for j, hook := range *spec {
			isInstanceGroup := i == 0
			// filter roles if required
			if len(hook.Roles) > 0 && !containsRole(h.InstanceGroup.Spec.Role, hook.Roles) {
				continue
			}

			// i dont want to effect those whom are already using the hooks, so i'm gonna try an keep the name for now
			// i.e. use the default naming convention - kops-hook-<index>, only those using the Name or hooks in IG should alter
			var name string
			switch hook.Name {
			case "":
				name = fmt.Sprintf("kops-hook-%d", j)
				if isInstanceGroup {
					name += "-ig"
				}
			default:
				name = hook.Name
			}

			if _, found := hookNames[name]; found {
				glog.V(2).Infof("Skipping the hook: %v as we've already processed a similar service name", name)
				continue
			}
			hookNames[name] = true

			// are we disabling the service?
			if hook.Disabled {
				enabled := false
				managed := true
				c.AddTask(&nodetasks.Service{
					Name:        ensureSystemdSuffix(name),
					ManageState: &managed,
					Enabled:     &enabled,
					Running:     &enabled,
				})
				continue
			}

			service, err := h.buildSystemdService(name, &hook)
			if err != nil {
				return err
			}

			if service != nil {
				c.AddTask(service)
			}
		}
	}

	return nil
}

// ensureSystemdSuffix makes sure that we have a .service suffix on the name, needed on needed versions of systems
func ensureSystemdSuffix(name string) string {
	if !strings.HasSuffix(name, ".service") && !strings.HasSuffix(name, ".timer") {
		name += ".service"
	}
	return name
}

// buildSystemdService is responsible for generating the service
func (h *HookBuilder) buildSystemdService(name string, hook *kops.HookSpec) (*nodetasks.Service, error) {
	// perform some basic validation
	if hook.ExecContainer == nil && hook.Manifest == "" {
		glog.Warningf("hook: %s has neither a raw unit or exec image configured", name)
		return nil, nil
	}
	if hook.ExecContainer != nil {
		if err := isValidExecContainerAction(hook.ExecContainer); err != nil {
			glog.Warningf("invalid hook action, name: %s, error: %v", name, err)
			return nil, nil
		}
	}
	// build the base unit file
	unit := &systemd.Manifest{}
	unit.Set("Unit", "Description", "Kops Hook "+name)

	// add any service dependencies to the unit
	for _, x := range hook.Requires {
		unit.Set("Unit", "Requires", x)
	}
	for _, x := range hook.Before {
		unit.Set("Unit", "Before", x)
	}

	// are we a raw unit file or a docker exec?
	switch hook.ExecContainer {
	case nil:
		unit.SetSection("Service", hook.Manifest)
	default:
		if err := h.buildDockerService(unit, hook); err != nil {
			return nil, err
		}
	}

	service := &nodetasks.Service{
		Name:       ensureSystemdSuffix(name),
		Definition: s(unit.Render()),
	}

	service.InitDefaults()

	return service, nil
}

// buildDockerService is responsible for generating a docker exec unit file
func (h *HookBuilder) buildDockerService(unit *systemd.Manifest, hook *kops.HookSpec) error {
	dockerArgs := []string{
		"/usr/bin/docker", "run",
		"-v", "/:/rootfs/",
		"-v", "/var/run/dbus:/var/run/dbus",
		"-v", "/run/systemd:/run/systemd",
		"--net=host",
		"--privileged",
	}
	dockerArgs = append(dockerArgs, buildDockerEnvironmentVars(hook.ExecContainer.Environment)...)
	dockerArgs = append(dockerArgs, hook.ExecContainer.Image)
	dockerArgs = append(dockerArgs, hook.ExecContainer.Command...)

	dockerRunCommand := systemd.EscapeCommand(dockerArgs)
	dockerPullCommand := systemd.EscapeCommand([]string{"/usr/bin/docker", "pull", hook.ExecContainer.Image})

	unit.Set("Unit", "Requires", "docker.service")
	unit.Set("Service", "ExecStartPre", dockerPullCommand)
	unit.Set("Service", "ExecStart", dockerRunCommand)
	unit.Set("Service", "Type", "oneshot")
	unit.Set("Install", "WantedBy", "multi-user.target")

	return nil
}

// isValidExecContainerAction checks the validatity of the execContainer - personally i think this validation
// should be done high up the chain, but
func isValidExecContainerAction(action *kops.ExecContainerAction) error {
	action.Image = strings.TrimSpace(action.Image)
	if action.Image == "" {
		return errors.New("the image for the hook exec action not set")
	}

	return nil
}
<|endoftext|>


<commit_before>package version

// VERSION ...
const VERSION = "1.1.25"
<commit_msg>v1.1.26<commit_after>package version

// VERSION ...
const VERSION = "1.1.26"
<|endoftext|>


<commit_before>package version

import "strings"

// Version describes the Goad version.
const Version = "1.2.0"

// LambdaVersion returns a version string that can be used as a Lambda function
// alias.
func LambdaVersion() string {
	return "v" + strings.Replace(Version, ".", "-", -1)
}
<commit_msg>missed version bump<commit_after>package version

import "strings"

// Version describes the Goad version.
const Version = "1.3.0"

// LambdaVersion returns a version string that can be used as a Lambda function
// alias.
func LambdaVersion() string {
	return "v" + strings.Replace(Version, ".", "-", -1)
}
<|endoftext|>


<commit_before>package version

var (
	// Package is filled at linking time
	Package = "github.com/containerd/containerd"

	// Version holds the complete version number. Filled in at linking time.
	Version = "1.0.0-alpha2+unknown"

	// Revision is filled with the VCS (e.g. git) revision being used to build
	// the program at linking time.
	Revision = ""
)
<commit_msg>release: prepare for 1.0.0-alpha3<commit_after>package version

var (
	// Package is filled at linking time
	Package = "github.com/containerd/containerd"

	// Version holds the complete version number. Filled in at linking time.
	Version = "1.0.0-alpha3+unknown"

	// Revision is filled with the VCS (e.g. git) revision being used to build
	// the program at linking time.
	Revision = ""
)
<|endoftext|>


<commit_before>package version

const Version = "0.11.2"
<commit_msg>version bump develop<commit_after>package version

const Version = "0.11.3"
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"encoding/json"
	"errors"
	"flag"
	"fmt"
	"io"
	logging "log"
	"net"
	"os"
	"syscall"
)

var log *logging.Logger = logging.New(os.Stderr, "bi: ", 0)

type readWriter struct {
	io.Reader
	io.Writer
}

func NewReadWriter(r io.Reader, w io.Writer) io.ReadWriter {
	return &readWriter{r, w}
}

// Flags are only used for online mode
var onlineMode = flag.Bool("online", false, "Use online mode")
var server = flag.String("server", "punter.inf.ed.ac.uk", "server ip")
var port = flag.Int("port", 9001, "server port")
var name = flag.String("name", "blueiris", "bot name")

type HandshakeRequest struct {
	Me string `json:"me"`
}

type HandshakeResponse struct {
	You string `json:"you"`
}

type PunterID uint
type SiteID uint

type Site struct {
	ID SiteID `json:"id"`
}

type River struct {
	Source  SiteID   `json:"source"`
	Target  SiteID   `json:"target"`
	Claimed bool     `json:"claimed",omitempty`
	Owner   PunterID `json:"owner",omitempty`
}

type Map struct {
	Sites  []Site   `json:"sites"`
	Rivers []River  `json:"rivers"`
	Mines  []SiteID `json:"mines"`
}

type SetupRequest struct {
	Punter  PunterID `json:"punter"`
	Punters int      `json:"punters"`
	Map     Map      `json:"map"`
}

type State struct {
	Punter  PunterID `json:"punter"`
	Punters int      `json:"punters"`
	Map     Map      `json:"map"`
}

type SetupResponse struct {
	Ready PunterID `json:"ready"`
	State *State   `json:"state",omitempty`
}

type Claim struct {
	Punter PunterID `json:"punter"`
	Source SiteID   `json:"source"`
	Target SiteID   `json:"target"`
}

type Pass struct {
	Punter PunterID `json:"punter"`
}

// Poor man's union type. Only one of Claim or Pass is non-nil
type Move struct {
	Claim *Claim `json:"claim",omitempty`
	Pass  *Pass  `json:"pass",omitempty`
	State *State `json:"state",omitempty`
}

func (m Move) String() string {
	if m.Claim != nil {
		return fmt.Sprintf("claim:%+v", m.Claim)
	} else if m.Pass != nil {
		return fmt.Sprintf("pass:%+v", m.Pass)
	} else {
		return "empty"
	}
}

type Moves struct {
	Moves []Move `json:"moves"`
}

type Score struct {
	Punter PunterID `json:"punter"`
	Score  int      `json:"score"`
}

type Stop struct {
	Moves  []Move  `json:"moves"`
	Scores []Score `json:"scores"`
}

// Poor man's union. Only one of Move or Stop is non-nil
type ServerMove struct {
	Move  *Moves `json:"move",omitempty`
	Stop  *Stop  `json:"stop",omitempty`
	State *State `json:"state",omitempty`
}

func findServer() (conn net.Conn, err error) {
	p := *port
	serverAddress := fmt.Sprintf("%s:%d", *server, p)
	log.Printf("Trying %s", serverAddress)
	conn, err = net.Dial("tcp", serverAddress)
	if err == nil {
		return
	}
	log.Fatal()
	return
}

func send(writer io.Writer, d interface{}) (err error) {
	var b []byte
	buf := bytes.NewBuffer(nil)
	err = json.NewEncoder(buf).Encode(d)
	if err != nil {
		return
	}
	b = buf.Bytes()
	// Don't need to send linefeed at end
	b = b[:len(b)-1]
	msg := fmt.Sprintf("%d:%s", len(b), b)
	log.Printf("Sending: %s", msg)
	var n int
	n, err = io.WriteString(writer, msg)
	log.Printf("sent %d bytes", n)
	if err != nil {
		return
	}
	return err
}

func receiveRaw(reader io.Reader) (b1 []byte, err error) {
	var i int
	_, err = fmt.Fscanf(reader, "%d:", &i)
	if err != nil {
		return
	}
	log.Printf("Reading %d bytes", i)
	b1 = make([]byte, i)
	offset := 0
	for offset < i {
		var n int
		n, err = reader.Read(b1[offset:])
		if err != nil {
			return
		}
		offset += n
	}
	log.Printf("Bytes: %d %s", len(b1), string(b1))
	// listen for reply
	return
}

func receive(conn io.Reader, d interface{}) (err error) {
	var b1 []byte
	b1, err = receiveRaw(conn)
	if err != nil {
		return
	}
	log.Printf("Received Bytes: %d %s", len(b1), string(b1))
	err = json.Unmarshal(b1, d)
	return err
}

func handshake(conn io.ReadWriter) (err error) {
	handshakeRequest := HandshakeRequest{*name}
	err = send(conn, &handshakeRequest)
	if err != nil {
		return
	}

	log.Printf("Waiting for reply")
	// listen for reply
	var handshakeResponse HandshakeResponse
	err = receive(conn, &handshakeResponse)
	// log.Printf("response %v\n", handshakeResponse)
	if err != nil {
		return
	}
	return
}

func setup(conn io.ReadWriter) (state State, err error) {
	var setupRequest SetupRequest
	err = receive(conn, &setupRequest)
	if err != nil {
		return
	}
	log.Printf("Received setupRequest %v", setupRequest)
	state, err = doSetup(conn, setupRequest)
	return
}

func doSetup(writer io.Writer, setupRequest SetupRequest) (state State, err error) {
	state.Punter = setupRequest.Punter
	state.Punters = setupRequest.Punters
	state.Map = setupRequest.Map
	setupResponse := SetupResponse{setupRequest.Punter, nil}
	if !*onlineMode {
		setupResponse.State = &state
	}
	err = send(writer, &setupResponse)
	return
}

func processServerMove(conn io.ReadWriter, state State, serverMove ServerMove) (err error) {
	if serverMove.Move != nil {
		return doMoves(conn, state, *serverMove.Move)
	} else if serverMove.Stop != nil {
		return doStop(conn, *serverMove.Stop)
	} else {
		return
	}
}

func doMoves(conn io.ReadWriter, state State, moves Moves) (err error) {
	err = processServerMoves(conn, state, moves)
	if err != nil {
		return
	}
	err = pickMove(conn, state)
	if err != nil {
		return
	}
	return
}

func processServerMoves(conn io.ReadWriter, state State, moves Moves) (err error) {
	for _, move := range moves.Moves {
		if move.Claim != nil {
			for riverIndex, river := range state.Map.Rivers {
				if river.Source == move.Claim.Source &&
					river.Target == move.Claim.Target {
					river.Claimed = true
					river.Owner = move.Claim.Punter
					state.Map.Rivers[riverIndex] = river
					break
				}
			}
		}
	}
	return
}

func pickMove(conn io.ReadWriter, state State) (err error) {
	var move Move
	move, err = pickFirstUnclaimed(state)
	if err != nil {
		return
	}
	if !*onlineMode {
		move.State = &state
	}
	log.Printf("Move: %v", move)
	err = send(conn, move)
	if err != nil {
		return
	}
	return
}

func doStop(conn io.ReadWriter, stop Stop) (err error) {
	for _, score := range stop.Scores {
		log.Printf("Punter: %d score: %d", score.Punter, score.Score)
	}
	return
}

func pickPass(state State) (move Move, err error) {
	move.Pass = &Pass{state.Punter}
	return
}

func pickFirstUnclaimed(state State) (move Move, err error) {
	for _, river := range state.Map.Rivers {
		if river.Claimed == false {
			move.Claim = &Claim{state.Punter, river.Source, river.Target}
			return
		}
	}
	return pickPass(state)
}

func runOnlineMode() (err error) {
	conn, err := findServer()
	if err != nil {
		return
	}
	log.Printf("connected")
	err = handshake(conn)
	if err != nil {
		return
	}

	log.Printf("setup")

	setupRequest, err := setup(conn)
	if err != nil {
		return
	}

	log.Printf("game")
	for {
		log.Printf("Setup %+v", setupRequest)
		var serverMove ServerMove
		err = receive(conn, &serverMove)
		if err != nil {
			return
		}
		err = processServerMove(conn, setupRequest, serverMove)
		if err != nil {
			return
		}
	}
	return
}

func runOfflineMode() (err error) {
	conn := NewReadWriter(os.Stdin, os.Stdout)
	log.Printf("connected")
	err = handshake(conn)
	if err != nil {
		return
	}

	var b1 []byte
	b1, err = receiveRaw(conn)
	if err != nil {
		return
	}
	var serverRequest map[string]interface{}
	err = json.Unmarshal(b1, &serverRequest)
	if err != nil {
		return
	}

	if serverRequest["punter"] != nil {
		log.Printf("setup")
		var setupRequest SetupRequest
		err = json.Unmarshal(b1, &setupRequest)
		if err != nil {
			return
		}
		_, err = doSetup(conn, setupRequest)
		return
	} else if serverRequest["move"] != nil {
		log.Printf("move")
		var serverMove ServerMove
		err = json.Unmarshal(b1, &serverMove)
		if err != nil {
			return
		}
		return doMoves(conn, *serverMove.State, *serverMove.Move)
	} else if serverRequest["stop"] != nil {
		log.Printf("stop")
		var serverMove ServerMove
		err = json.Unmarshal(b1, &serverMove)
		if err != nil {
			return
		}
		return doStop(conn, *serverMove.Stop)
	} else {
		err = errors.New("Unknown server request")
	}
	return
}

// This is needed when running under lamduct on VM. Otherwise
// EAGAIN.
func fixIO() {
	fd := int(os.Stdin.Fd())
	syscall.SetNonblock(fd, false)
}

func main() {
	var err error
	flag.Parse()
	fixIO()
	if *onlineMode {
		log.Printf("online mode")
		err = runOnlineMode()
	} else {
		log.Printf("offline mode")
		err = runOfflineMode()
	}
	if err != nil {
		log.Fatal(err)
	}
}
<commit_msg>Created accelleration data structures<commit_after>package main

import (
	"bytes"
	"encoding/json"
	"errors"
	"flag"
	"fmt"
	"io"
	logging "log"
	"net"
	"os"
	"syscall"
)

var log *logging.Logger = logging.New(os.Stderr, "bi: ", 0)

type readWriter struct {
	io.Reader
	io.Writer
}

func NewReadWriter(r io.Reader, w io.Writer) io.ReadWriter {
	return &readWriter{r, w}
}

// Flags are only used for online mode
var onlineMode = flag.Bool("online", false, "Use online mode")
var server = flag.String("server", "punter.inf.ed.ac.uk", "server ip")
var port = flag.Int("port", 9001, "server port")
var name = flag.String("name", "blueiris", "bot name")

type HandshakeRequest struct {
	Me string `json:"me"`
}

type HandshakeResponse struct {
	You string `json:"you"`
}

type PunterID uint
type SiteID uint

// Offset of river in Map.Rivers
type RiverOffset int
type RiverOffsets []RiverOffset

// Offset of site in Map.Sites
type SiteOffset int

type ScoreValue int

type Site struct {
	ID     SiteID       `json:"id"`
	Rivers RiverOffsets `json:"rivers",omitempty`
}

type River struct {
	Source  SiteID   `json:"source"`
	Target  SiteID   `json:"target"`
	Claimed bool     `json:"claimed",omitempty`
	Owner   PunterID `json:"owner",omitempty`
}

type Map struct {
	Sites  []Site   `json:"sites"`
	Rivers []River  `json:"rivers"`
	Mines  []SiteID `json:"mines"`
	// Lookup site from siteID
	SiteMap map[SiteID]SiteOffset `json:siteMap,omitEmpty`
}

func (m *Map) DecorateMap() (err error) {
	m.SiteMap = make(map[SiteID]SiteOffset)
	for i, site := range m.Sites {
		m.SiteMap[site.ID] = SiteOffset(i)
	}
	for i, river := range m.Rivers {
		{
			sourceIndex := m.SiteMap[river.Source]
			m.Sites[sourceIndex].Rivers = append(m.Sites[sourceIndex].Rivers, RiverOffset(i))
		}
		{
			targetIndex := m.SiteMap[river.Target]
			m.Sites[targetIndex].Rivers = append(m.Sites[targetIndex].Rivers, RiverOffset(i))
		}
	}
	return
}

type SetupRequest struct {
	Punter  PunterID `json:"punter"`
	Punters int      `json:"punters"`
	Map     Map      `json:"map"`
}

type State struct {
	Punter  PunterID `json:"punter"`
	Punters int      `json:"punters"`
	Map     Map      `json:"map"`
}

type SetupResponse struct {
	Ready PunterID `json:"ready"`
	State *State   `json:"state",omitempty`
}

type Claim struct {
	Punter PunterID `json:"punter"`
	Source SiteID   `json:"source"`
	Target SiteID   `json:"target"`
}

type Pass struct {
	Punter PunterID `json:"punter"`
}

// Poor man's union type. Only one of Claim or Pass is non-nil
type Move struct {
	Claim *Claim `json:"claim",omitempty`
	Pass  *Pass  `json:"pass",omitempty`
	State *State `json:"state",omitempty`
}

func (m Move) String() string {
	if m.Claim != nil {
		return fmt.Sprintf("claim:%+v", m.Claim)
	} else if m.Pass != nil {
		return fmt.Sprintf("pass:%+v", m.Pass)
	} else {
		return "empty"
	}
}

type Moves struct {
	Moves []Move `json:"moves"`
}

type Score struct {
	Punter PunterID   `json:"punter"`
	Score  ScoreValue `json:"score"`
}

type Stop struct {
	Moves  []Move  `json:"moves"`
	Scores []Score `json:"scores"`
}

// Poor man's union. Only one of Move or Stop is non-nil
type ServerMove struct {
	Move  *Moves `json:"move",omitempty`
	Stop  *Stop  `json:"stop",omitempty`
	State *State `json:"state",omitempty`
}

func findServer() (conn net.Conn, err error) {
	p := *port
	serverAddress := fmt.Sprintf("%s:%d", *server, p)
	log.Printf("Trying %s", serverAddress)
	conn, err = net.Dial("tcp", serverAddress)
	if err == nil {
		return
	}
	log.Fatal()
	return
}

func send(writer io.Writer, d interface{}) (err error) {
	var b []byte
	buf := bytes.NewBuffer(nil)
	err = json.NewEncoder(buf).Encode(d)
	if err != nil {
		return
	}
	b = buf.Bytes()
	// Don't need to send linefeed at end
	b = b[:len(b)-1]
	msg := fmt.Sprintf("%d:%s", len(b), b)
	log.Printf("Sending: %s", msg)
	var n int
	n, err = io.WriteString(writer, msg)
	log.Printf("sent %d bytes", n)
	if err != nil {
		return
	}
	return err
}

func receiveRaw(reader io.Reader) (b1 []byte, err error) {
	var i int
	_, err = fmt.Fscanf(reader, "%d:", &i)
	if err != nil {
		return
	}
	log.Printf("Reading %d bytes", i)
	b1 = make([]byte, i)
	offset := 0
	for offset < i {
		var n int
		n, err = reader.Read(b1[offset:])
		if err != nil {
			return
		}
		offset += n
	}
	log.Printf("Bytes: %d %s", len(b1), string(b1))
	// listen for reply
	return
}

func receive(conn io.Reader, d interface{}) (err error) {
	var b1 []byte
	b1, err = receiveRaw(conn)
	if err != nil {
		return
	}
	log.Printf("Received Bytes: %d %s", len(b1), string(b1))
	err = json.Unmarshal(b1, d)
	return err
}

func handshake(conn io.ReadWriter) (err error) {
	handshakeRequest := HandshakeRequest{*name}
	err = send(conn, &handshakeRequest)
	if err != nil {
		return
	}

	log.Printf("Waiting for reply")
	// listen for reply
	var handshakeResponse HandshakeResponse
	err = receive(conn, &handshakeResponse)
	// log.Printf("response %v\n", handshakeResponse)
	if err != nil {
		return
	}
	return
}

func setup(conn io.ReadWriter) (state State, err error) {
	var setupRequest SetupRequest
	err = receive(conn, &setupRequest)
	if err != nil {
		return
	}
	log.Printf("Received setupRequest %v", setupRequest)
	state, err = doSetup(conn, setupRequest)
	return
}

func doSetup(writer io.Writer, setupRequest SetupRequest) (state State, err error) {
	state.Punter = setupRequest.Punter
	state.Punters = setupRequest.Punters
	state.Map = setupRequest.Map
	state.Map.DecorateMap()
	setupResponse := SetupResponse{setupRequest.Punter, nil}
	if !*onlineMode {
		setupResponse.State = &state
	}
	err = send(writer, &setupResponse)
	return
}

func processServerMove(conn io.ReadWriter, state State, serverMove ServerMove) (err error) {
	if serverMove.Move != nil {
		return doMoves(conn, state, *serverMove.Move)
	} else if serverMove.Stop != nil {
		return doStop(conn, *serverMove.Stop)
	} else {
		return
	}
}

func doMoves(conn io.ReadWriter, state State, moves Moves) (err error) {
	err = processServerMoves(conn, state, moves)
	if err != nil {
		return
	}
	err = pickMove(conn, state)
	if err != nil {
		return
	}
	return
}

func processServerMoves(conn io.ReadWriter, state State, moves Moves) (err error) {
	for _, move := range moves.Moves {
		if move.Claim != nil {
			for riverIndex, river := range state.Map.Rivers {
				if river.Source == move.Claim.Source &&
					river.Target == move.Claim.Target {
					river.Claimed = true
					river.Owner = move.Claim.Punter
					state.Map.Rivers[riverIndex] = river
					break
				}
			}
		}
	}
	return
}

func pickMove(conn io.ReadWriter, state State) (err error) {
	var move Move
	move, err = pickFirstUnclaimed(state)
	if err != nil {
		return
	}
	if !*onlineMode {
		move.State = &state
	}
	log.Printf("Move: %v", move)
	err = send(conn, move)
	if err != nil {
		return
	}
	return
}

func doStop(conn io.ReadWriter, stop Stop) (err error) {
	for _, score := range stop.Scores {
		log.Printf("Punter: %d score: %d", score.Punter, score.Score)
	}
	return
}

func pickPass(state State) (move Move, err error) {
	move.Pass = &Pass{state.Punter}
	return
}

func pickFirstUnclaimed(state State) (move Move, err error) {
	for _, river := range state.Map.Rivers {
		if river.Claimed == false {
			move.Claim = &Claim{state.Punter, river.Source, river.Target}
			return
		}
	}
	return pickPass(state)
}

func runOnlineMode() (err error) {
	conn, err := findServer()
	if err != nil {
		return
	}
	log.Printf("connected")
	err = handshake(conn)
	if err != nil {
		return
	}

	log.Printf("setup")

	setupRequest, err := setup(conn)
	if err != nil {
		return
	}

	log.Printf("game")
	for {
		log.Printf("Setup %+v", setupRequest)
		var serverMove ServerMove
		err = receive(conn, &serverMove)
		if err != nil {
			return
		}
		err = processServerMove(conn, setupRequest, serverMove)
		if err != nil {
			return
		}
	}
	return
}

func runOfflineMode() (err error) {
	conn := NewReadWriter(os.Stdin, os.Stdout)
	log.Printf("connected")
	err = handshake(conn)
	if err != nil {
		return
	}

	var b1 []byte
	b1, err = receiveRaw(conn)
	if err != nil {
		return
	}
	var serverRequest map[string]interface{}
	err = json.Unmarshal(b1, &serverRequest)
	if err != nil {
		return
	}

	if serverRequest["punter"] != nil {
		log.Printf("setup")
		var setupRequest SetupRequest
		err = json.Unmarshal(b1, &setupRequest)
		if err != nil {
			return
		}
		_, err = doSetup(conn, setupRequest)
		return
	} else if serverRequest["move"] != nil {
		log.Printf("move")
		var serverMove ServerMove
		err = json.Unmarshal(b1, &serverMove)
		if err != nil {
			return
		}
		return doMoves(conn, *serverMove.State, *serverMove.Move)
	} else if serverRequest["stop"] != nil {
		log.Printf("stop")
		var serverMove ServerMove
		err = json.Unmarshal(b1, &serverMove)
		if err != nil {
			return
		}
		return doStop(conn, *serverMove.Stop)
	} else {
		err = errors.New("Unknown server request")
	}
	return
}

// This is needed when running under lamduct on VM. Otherwise
// EAGAIN.
func fixIO() {
	fd := int(os.Stdin.Fd())
	syscall.SetNonblock(fd, false)
}

func main() {
	var err error
	flag.Parse()
	fixIO()
	if *onlineMode {
		log.Printf("online mode")
		err = runOnlineMode()
	} else {
		log.Printf("offline mode")
		err = runOfflineMode()
	}
	if err != nil {
		log.Fatal(err)
	}
}
<|endoftext|>