<commit_before>package main

import (
	"encoding/gob"
	"flag"
	"fmt"
	"log"
	"net"
	"time"

	"github.com/udhos/fugo/future"
	"github.com/udhos/fugo/msg"
)

type world struct {
	playerTab      []*player
	playerAdd      chan *player
	playerDel      chan *player
	input          chan inputMsg
	updateInterval time.Duration
	missileList    []*msg.Missile
	teams          [2]team
}

type team struct {
	count int // player count
	score int // team score
}

type inputMsg struct {
	player *player
	msg    interface{}
}

type player struct {
	conn         net.Conn
	output       chan msg.Update
	fuelStart    time.Time
	cannonStart  time.Time
	cannonSpeed  float32
	cannonCoordX float32
	cannonLife   float32
	cannonID     int
	team         int
}

func main() {

	var addr string

	flag.StringVar(&addr, "addr", ":8080", "listen address")

	flag.Parse()

	w := world{
		playerTab:      []*player{},
		playerAdd:      make(chan *player),
		playerDel:      make(chan *player),
		updateInterval: 1000 * time.Millisecond,
		input:          make(chan inputMsg),
	}
	if errListen := listenAndServe(&w, addr); errListen != nil {
		log.Printf("main: listen: %v", errListen)
		return
	}

	if errDisc := lanDiscovery(addr); errDisc != nil {
		log.Printf("main: discovery: %v", errDisc)
		return
	}

	missileID := 0
	cannonID := 0

	tickerUpdate := time.NewTicker(w.updateInterval)
	tickerCollision := time.NewTicker(250 * time.Millisecond)

	log.Printf("main: entering service loop")
SERVICE:
	for {
		select {
		case p := <-w.playerAdd:
			p.team = 0
			if w.teams[0].count > w.teams[1].count {
				p.team = 1
			}
			log.Printf("player add: %v team=%d team0=%d team1=%d", p, p.team, w.teams[0].count, w.teams[1].count)
			w.playerTab = append(w.playerTab, p)

			playerFuelSet(p, time.Now(), 5) // reset fuel to 50%
			p.cannonStart = p.fuelStart
			p.cannonSpeed = float32(.1 / 1.0) // 10% every 1 second
			p.cannonCoordX = .5               // 50%
			p.cannonID = cannonID
			p.cannonLife = 1 // 100%
			cannonID++
			w.teams[p.team].count++
		case p := <-w.playerDel:
			log.Printf("player del: %v team=%d team0=%d team1=%d", p, p.team, w.teams[0].count, w.teams[1].count)
			for i, pl := range w.playerTab {
				if pl == p {
					//w.playerTab = append(w.playerTab[:i], w.playerTab[i+1:]...)
					if i < len(w.playerTab)-1 {
						w.playerTab[i] = w.playerTab[len(w.playerTab)-1]
					}
					w.playerTab = w.playerTab[:len(w.playerTab)-1]
					w.teams[p.team].count--
					log.Printf("player removed: %v", p)
					continue SERVICE
				}
			}
			log.Printf("player not found: %v", p)
		case i := <-w.input:
			//log.Printf("input: %v", i)

			switch m := i.msg.(type) {
			case msg.Button:
				log.Printf("input button: %v", m)

				if m.ID == msg.ButtonTurn {
					p := i.player
					//p.cannonCoordX, p.cannonSpeed = future.CannonX(p.cannonCoordX, p.cannonSpeed, time.Since(p.cannonStart))
					updateCannon(p, time.Now())
					p.cannonSpeed = -p.cannonSpeed
					updateWorld(&w)
					continue SERVICE
				}

				if m.ID != msg.ButtonFire {
					continue SERVICE // non-fire button
				}

				fuel := playerFuel(i.player)
				if fuel < 1 {
					continue SERVICE // not enough fuel
				}

				if fuel >= 10 {
					playerFuelSet(i.player, time.Now(), 9)
				} else {
					playerFuelSet(i.player, time.Now(), fuel-1)
				}

				now := time.Now()
				updateCannon(i.player, now)
				miss1 := &msg.Missile{
					ID:     missileID,
					CoordX: i.player.cannonCoordX,
					Speed:  .5, // 50% every 1 second
					Team:   i.player.team,
					Start:  now,
				}
				missileID++
				w.missileList = append(w.missileList, miss1)

				log.Printf("input fire - fuel was=%v is=%v missiles=%d", fuel, playerFuel(i.player), len(w.missileList))

				updateWorld(&w)
			}

		case <-tickerUpdate.C:
			//log.Printf("tick: %v", t)

			updateWorld(&w)
		case <-tickerCollision.C:
			if detectCollision(&w, time.Now()) {
				updateWorld(&w)
			}
		}
	}
}

func updateCannon(p *player, now time.Time) {
	p.cannonCoordX, p.cannonSpeed = future.CannonX(p.cannonCoordX, p.cannonSpeed, time.Since(p.cannonStart))
	p.cannonStart = now
}

func removeMissile(w *world, i int) {
	last := len(w.missileList) - 1
	if i < last {
		w.missileList[i] = w.missileList[last]
	}
	w.missileList = w.missileList[:last]
}

func updateWorld(w *world) {
	now := time.Now()

	for _, p := range w.playerTab {
		updateCannon(p, now)
	}

	//size := len(w.missileList)
	for i := 0; i < len(w.missileList); i++ {
		m := w.missileList[i]
		m.CoordY = future.MissileY(m.CoordY, m.Speed, time.Since(m.Start))
		m.Start = now
		if m.CoordY >= 1 {
			/*
				size--
				if i >= size {
					// last element
					break
				}
				w.missileList[i] = w.missileList[size]
			*/
			removeMissile(w, i)
			i--
		}
	}
	//w.missileList = w.missileList[:size]

	for _, p := range w.playerTab {
		sendUpdatesToPlayer(w, p)
	}
}

func playerFuel(p *player) float32 {
	return future.Fuel(0, time.Since(p.fuelStart))
}

func playerFuelSet(p *player, now time.Time, fuel float32) {
	p.fuelStart = now.Add(-time.Duration(float32(time.Second) * fuel / future.FuelRechargeRate))
}

func sendUpdatesToPlayer(w *world, p *player) {
	update := msg.Update{
		Fuel:          playerFuel(p),
		Interval:      w.updateInterval,
		WorldMissiles: w.missileList,
		Team:          p.team,
		Scores:        [2]int{w.teams[0].score, w.teams[1].score},
	}

	for _, p1 := range w.playerTab {
		cannon := msg.Cannon{
			ID:     p1.cannonID,
			Start:  p1.cannonStart,
			CoordX: p1.cannonCoordX,
			Speed:  p1.cannonSpeed,
			Team:   p1.team,
			Life:   p1.cannonLife,
			Player: p1 == p,
		}
		update.Cannons = append(update.Cannons, &cannon)
	}

	//log.Printf("sending updates to player %v", p)

	p.output <- update
}

func listenAndServe(w *world, addr string) error {

	proto := "tcp"

	log.Printf("serving on %s %s", proto, addr)

	listener, errListen := net.Listen(proto, addr)
	if errListen != nil {
		return fmt.Errorf("listenAndServe: %s: %v", addr, errListen)
	}

	gob.Register(msg.Update{})
	gob.Register(msg.Button{})

	go func() {
		for {
			conn, err := listener.Accept()
			if err != nil {
				log.Printf("accept on TCP %s: %s", addr, err)
				continue
			}
			c, _ := conn.(*net.TCPConn)
			go connHandler(w, c)
		}
	}()

	return nil
}

func connHandler(w *world, conn *net.TCPConn) {
	log.Printf("handler for connection %v", conn.RemoteAddr())

	defer conn.Close()

	p := &player{
		conn:   conn,
		output: make(chan msg.Update),
	}

	w.playerAdd <- p // register player
	quitWriter := make(chan struct{})

	go func() {
		// copy from socket into input channel
		dec := gob.NewDecoder(conn)
		for {
			var m msg.Button
			if err := dec.Decode(&m); err != nil {
				log.Printf("handler: Decode: %v", err)
				break
			}
			w.input <- inputMsg{player: p, msg: m}
		}
		close(quitWriter) // send quit request to output goroutine
		log.Printf("handler: reader goroutine exiting")
	}()

	// copy from output channel into socket
	enc := gob.NewEncoder(conn)
LOOP:
	for {
		select {
		case <-quitWriter:
			log.Printf("handler: quit request")
			break LOOP
		case m := <-p.output:
			if err := enc.Encode(&m); err != nil {
				log.Printf("handler: Encode: %v", err)
				break LOOP
			}
		}
	}
	w.playerDel <- p // deregister player
	log.Printf("handler: writer goroutine exiting")
}
<commit_msg>Ignore button for dead cannon.<commit_after>package main

import (
	"encoding/gob"
	"flag"
	"fmt"
	"log"
	"net"
	"time"

	"github.com/udhos/fugo/future"
	"github.com/udhos/fugo/msg"
)

type world struct {
	playerTab      []*player
	playerAdd      chan *player
	playerDel      chan *player
	input          chan inputMsg
	updateInterval time.Duration
	missileList    []*msg.Missile
	teams          [2]team
}

type team struct {
	count int // player count
	score int // team score
}

type inputMsg struct {
	player *player
	msg    interface{}
}

type player struct {
	conn         net.Conn
	output       chan msg.Update
	fuelStart    time.Time
	cannonStart  time.Time
	cannonSpeed  float32
	cannonCoordX float32
	cannonLife   float32
	cannonID     int
	team         int
}

func main() {

	var addr string

	flag.StringVar(&addr, "addr", ":8080", "listen address")

	flag.Parse()

	w := world{
		playerTab:      []*player{},
		playerAdd:      make(chan *player),
		playerDel:      make(chan *player),
		updateInterval: 1000 * time.Millisecond,
		input:          make(chan inputMsg),
	}
	if errListen := listenAndServe(&w, addr); errListen != nil {
		log.Printf("main: listen: %v", errListen)
		return
	}

	if errDisc := lanDiscovery(addr); errDisc != nil {
		log.Printf("main: discovery: %v", errDisc)
		return
	}

	missileID := 0
	cannonID := 0

	tickerUpdate := time.NewTicker(w.updateInterval)
	tickerCollision := time.NewTicker(250 * time.Millisecond)

	log.Printf("main: entering service loop")
SERVICE:
	for {
		select {
		case p := <-w.playerAdd:
			p.team = 0
			if w.teams[0].count > w.teams[1].count {
				p.team = 1
			}
			log.Printf("player add: %v team=%d team0=%d team1=%d", p, p.team, w.teams[0].count, w.teams[1].count)
			w.playerTab = append(w.playerTab, p)

			playerFuelSet(p, time.Now(), 5) // reset fuel to 50%
			p.cannonStart = p.fuelStart
			p.cannonSpeed = float32(.1 / 1.0) // 10% every 1 second
			p.cannonCoordX = .5               // 50%
			p.cannonID = cannonID
			p.cannonLife = 1 // 100%
			cannonID++
			w.teams[p.team].count++
		case p := <-w.playerDel:
			log.Printf("player del: %v team=%d team0=%d team1=%d", p, p.team, w.teams[0].count, w.teams[1].count)
			for i, pl := range w.playerTab {
				if pl == p {
					//w.playerTab = append(w.playerTab[:i], w.playerTab[i+1:]...)
					if i < len(w.playerTab)-1 {
						w.playerTab[i] = w.playerTab[len(w.playerTab)-1]
					}
					w.playerTab = w.playerTab[:len(w.playerTab)-1]
					w.teams[p.team].count--
					log.Printf("player removed: %v", p)
					continue SERVICE
				}
			}
			log.Printf("player not found: %v", p)
		case i := <-w.input:
			//log.Printf("input: %v", i)

			switch m := i.msg.(type) {
			case msg.Button:
				log.Printf("input button: %v", m)

				if i.player.cannonLife <= 0 {
					continue // cannon destroyed
				}

				if m.ID == msg.ButtonTurn {
					p := i.player
					//p.cannonCoordX, p.cannonSpeed = future.CannonX(p.cannonCoordX, p.cannonSpeed, time.Since(p.cannonStart))
					updateCannon(p, time.Now())
					p.cannonSpeed = -p.cannonSpeed
					updateWorld(&w)
					continue SERVICE
				}

				if m.ID != msg.ButtonFire {
					continue SERVICE // non-fire button
				}

				fuel := playerFuel(i.player)
				if fuel < 1 {
					continue SERVICE // not enough fuel
				}

				if fuel >= 10 {
					playerFuelSet(i.player, time.Now(), 9)
				} else {
					playerFuelSet(i.player, time.Now(), fuel-1)
				}

				now := time.Now()
				updateCannon(i.player, now)
				miss1 := &msg.Missile{
					ID:     missileID,
					CoordX: i.player.cannonCoordX,
					Speed:  .5, // 50% every 1 second
					Team:   i.player.team,
					Start:  now,
				}
				missileID++
				w.missileList = append(w.missileList, miss1)

				log.Printf("input fire - fuel was=%v is=%v missiles=%d", fuel, playerFuel(i.player), len(w.missileList))

				updateWorld(&w)
			}

		case <-tickerUpdate.C:
			//log.Printf("tick: %v", t)

			updateWorld(&w)
		case <-tickerCollision.C:
			if detectCollision(&w, time.Now()) {
				updateWorld(&w)
			}
		}
	}
}

func updateCannon(p *player, now time.Time) {
	p.cannonCoordX, p.cannonSpeed = future.CannonX(p.cannonCoordX, p.cannonSpeed, time.Since(p.cannonStart))
	p.cannonStart = now
}

func removeMissile(w *world, i int) {
	last := len(w.missileList) - 1
	if i < last {
		w.missileList[i] = w.missileList[last]
	}
	w.missileList = w.missileList[:last]
}

func updateWorld(w *world) {
	now := time.Now()

	for _, p := range w.playerTab {
		updateCannon(p, now)
	}

	//size := len(w.missileList)
	for i := 0; i < len(w.missileList); i++ {
		m := w.missileList[i]
		m.CoordY = future.MissileY(m.CoordY, m.Speed, time.Since(m.Start))
		m.Start = now
		if m.CoordY >= 1 {
			/*
				size--
				if i >= size {
					// last element
					break
				}
				w.missileList[i] = w.missileList[size]
			*/
			removeMissile(w, i)
			i--
		}
	}
	//w.missileList = w.missileList[:size]

	for _, p := range w.playerTab {
		sendUpdatesToPlayer(w, p)
	}
}

func playerFuel(p *player) float32 {
	return future.Fuel(0, time.Since(p.fuelStart))
}

func playerFuelSet(p *player, now time.Time, fuel float32) {
	p.fuelStart = now.Add(-time.Duration(float32(time.Second) * fuel / future.FuelRechargeRate))
}

func sendUpdatesToPlayer(w *world, p *player) {
	update := msg.Update{
		Fuel:          playerFuel(p),
		Interval:      w.updateInterval,
		WorldMissiles: w.missileList,
		Team:          p.team,
		Scores:        [2]int{w.teams[0].score, w.teams[1].score},
	}

	for _, p1 := range w.playerTab {
		cannon := msg.Cannon{
			ID:     p1.cannonID,
			Start:  p1.cannonStart,
			CoordX: p1.cannonCoordX,
			Speed:  p1.cannonSpeed,
			Team:   p1.team,
			Life:   p1.cannonLife,
			Player: p1 == p,
		}
		update.Cannons = append(update.Cannons, &cannon)
	}

	//log.Printf("sending updates to player %v", p)

	p.output <- update
}

func listenAndServe(w *world, addr string) error {

	proto := "tcp"

	log.Printf("serving on %s %s", proto, addr)

	listener, errListen := net.Listen(proto, addr)
	if errListen != nil {
		return fmt.Errorf("listenAndServe: %s: %v", addr, errListen)
	}

	gob.Register(msg.Update{})
	gob.Register(msg.Button{})

	go func() {
		for {
			conn, err := listener.Accept()
			if err != nil {
				log.Printf("accept on TCP %s: %s", addr, err)
				continue
			}
			c, _ := conn.(*net.TCPConn)
			go connHandler(w, c)
		}
	}()

	return nil
}

func connHandler(w *world, conn *net.TCPConn) {
	log.Printf("handler for connection %v", conn.RemoteAddr())

	defer conn.Close()

	p := &player{
		conn:   conn,
		output: make(chan msg.Update),
	}

	w.playerAdd <- p // register player
	quitWriter := make(chan struct{})

	go func() {
		// copy from socket into input channel
		dec := gob.NewDecoder(conn)
		for {
			var m msg.Button
			if err := dec.Decode(&m); err != nil {
				log.Printf("handler: Decode: %v", err)
				break
			}
			w.input <- inputMsg{player: p, msg: m}
		}
		close(quitWriter) // send quit request to output goroutine
		log.Printf("handler: reader goroutine exiting")
	}()

	// copy from output channel into socket
	enc := gob.NewEncoder(conn)
LOOP:
	for {
		select {
		case <-quitWriter:
			log.Printf("handler: quit request")
			break LOOP
		case m := <-p.output:
			if err := enc.Encode(&m); err != nil {
				log.Printf("handler: Encode: %v", err)
				break LOOP
			}
		}
	}
	w.playerDel <- p // deregister player
	log.Printf("handler: writer goroutine exiting")
}
<|endoftext|>


<commit_before>/*
Package vow provides a promise like api for executing
a batch of external commands
*/
package vow

import (
	"bytes"
	"io"
	"log"
	"os"
	"os/exec"
	"strings"
)

// Vow represents a batch of commands being prepared to run
type Vow struct {
	cmds   []*exec.Cmd
	errlog *log.Logger
}

// To returns a new Vow that is configured to execute command given.
func To(name string, args ...string) *Vow {
	cmd := exec.Command(name, args...)
	return &Vow{
		cmds:   []*exec.Cmd{cmd},
		errlog: log.New(os.Stderr, "To - ", log.Lshortfile),
	}
}

// Then adds the given command to the list of commands the Vow will execute
func (vow *Vow) Then(name string, args ...string) {
	vow.cmds = append(vow.cmds, exec.Command(name, args...))
}

// Exec runs all of the commands a Vow has with all output redirected
// to the given writer and returns a Result
func (vow *Vow) Exec(w io.Writer) *Result {
	r := new(Result)
	var runCount int
	for runCount < len(vow.cmds) {
		command := vow.runCmd(vow.cmds[runCount], w)
		r.results = append(r.results, command)

		// manually increment the counter so that
		// in the case the command.failed is true
		// the loop below that adds an empty cmdResult
		// to the result doesn't add an extra result
		runCount++
		if command.failed {
			r.Failed = true
			break
		}
	}

	r.executed = runCount

	// add the remaining commands
	for ; runCount < len(vow.cmds); runCount++ {
		cmd := vow.cmds[runCount]
		command := cmdResult{
			command: cmd.Path,
			args:    cmd.Args,
		}
		r.results = append(r.results, command)
	}

	return r
}

func (vow *Vow) runCmd(cmd *exec.Cmd, w io.Writer) (result cmdResult) {
	var b bytes.Buffer
	mw := io.MultiWriter(&b, w)

	cmd.Stdout = mw
	cmd.Stderr = mw

	cmd.Stdout.Write([]byte(strings.Join(cmd.Args, " ") + "\n"))
	if err := cmd.Start(); err != nil {
		vow.errlog.Println("err start", err)
		// could not start cmd
		return
	}

	if err := cmd.Wait(); err != nil {
		result.failed = true
	}

	result.ps = cmd.ProcessState
	result.output = b.Bytes()
	result.command = cmd.Path
	result.args = cmd.Args[1:]

	return
}
<commit_msg>writing to command output if there was an error starting the command<commit_after>/*
Package vow provides a promise like api for executing
a batch of external commands
*/
package vow

import (
	"bytes"
	"io"
	"log"
	"os"
	"os/exec"
	"strings"
)

// Vow represents a batch of commands being prepared to run
type Vow struct {
	cmds   []*exec.Cmd
	errlog *log.Logger
}

// To returns a new Vow that is configured to execute command given.
func To(name string, args ...string) *Vow {
	cmd := exec.Command(name, args...)
	return &Vow{
		cmds:   []*exec.Cmd{cmd},
		errlog: log.New(os.Stderr, "To - ", log.Lshortfile),
	}
}

// Then adds the given command to the list of commands the Vow will execute
func (vow *Vow) Then(name string, args ...string) {
	vow.cmds = append(vow.cmds, exec.Command(name, args...))
}

// Exec runs all of the commands a Vow has with all output redirected
// to the given writer and returns a Result
func (vow *Vow) Exec(w io.Writer) *Result {
	r := new(Result)
	var runCount int
	for runCount < len(vow.cmds) {
		command := vow.runCmd(vow.cmds[runCount], w)
		r.results = append(r.results, command)

		// manually increment the counter so that
		// in the case the command.failed is true
		// the loop below that adds an empty cmdResult
		// to the result doesn't add an extra result
		runCount++
		if command.failed {
			r.Failed = true
			break
		}
	}

	r.executed = runCount

	// add the remaining commands
	for ; runCount < len(vow.cmds); runCount++ {
		cmd := vow.cmds[runCount]
		command := cmdResult{
			command: cmd.Path,
			args:    cmd.Args,
		}
		r.results = append(r.results, command)
	}

	return r
}

func (vow *Vow) runCmd(cmd *exec.Cmd, w io.Writer) (result cmdResult) {
	var b bytes.Buffer
	mw := io.MultiWriter(&b, w)

	cmd.Stdout = mw
	cmd.Stderr = mw

	cmd.Stdout.Write([]byte(strings.Join(cmd.Args, " ") + "\n"))
	if err := cmd.Start(); err != nil {
		mw.Write([]byte(err.Error() + "\n"))
		result.failed = true
		return
	}

	if err := cmd.Wait(); err != nil {
		result.failed = true
	}

	result.ps = cmd.ProcessState
	result.output = b.Bytes()
	result.command = cmd.Path
	result.args = cmd.Args[1:]

	return
}
<|endoftext|>


<commit_before>package audio

import (
	"path/filepath"
	"strings"

	"github.com/200sc/klangsynthese/audio"
	"github.com/200sc/klangsynthese/mp3"
	"github.com/200sc/klangsynthese/wav"

	"github.com/oakmound/oak/dlog"
	"github.com/oakmound/oak/fileutil"
	"github.com/oakmound/oak/oakerr"
)

// Data is an alias for an interface supporting the built in filters in our
// external audio playing library
type Data audio.FullAudio

// GetSounds returns a set of Data for a set of input filenames
func GetSounds(fileNames ...string) ([]Data, error) {
	var err error
	sounds := make([]Data, len(fileNames))
	for i, f := range fileNames {
		sounds[i], err = Get(f)
		if err != nil {
			return nil, err
		}
	}
	if len(sounds) == 0 {
		return sounds, oakerr.InsufficientInputs{AtLeast: 1, InputName: "fileName"}
	}
	return sounds, nil
}

// Get without a font will just return the raw audio data
func Get(filename string) (Data, error) {
	if IsLoaded(filename) {
		return loaded[filename], nil
	}
	return nil, oakerr.NotFound{filename}
}

// Load joins the directory and filename, attempts to find
// the input file, and stores it as filename in the set of
// loaded files.
// This can cause a conflict when multiple files have the same
// name but different directories-- the first file loaded wil be the
// one stored in the loeaded map.
func Load(directory, filename string) (Data, error) {
	dlog.Verb("Loading", directory, filename)
	if !IsLoaded(filename) {
		f, err := fileutil.Open(filepath.Join(directory, filename))
		if err != nil {
			return nil, err
		}
		defer f.Close()
		var buffer audio.Audio
		end := strings.ToLower(filename[len(filename)-4:])
		switch end {
		case ".wav":
			buffer, err = wav.Load(f)
		case ".mp3":
			buffer, err = mp3.Load(f)
		default:
			return nil, oakerr.UnsupportedFormat{Format: end}
		}
		if err != nil {
			return nil, err
		}
		loaded[filename] = buffer.(audio.FullAudio)
	}
	return loaded[filename], nil
}

// Unload removes an element from the loaded map. If the element does not
// exist, it does nothing.
func Unload(filename string) {
	delete(loaded, filename)
}

// IsLoaded is shorthand for (if _, ok := loaded[filename]; ok)
func IsLoaded(filename string) bool {
	_, ok := loaded[filename]
	return ok
}

// BatchLoad attempts to load all files within a given directory
// depending on their file ending (currently supporting .wav and .mp3)
func BatchLoad(baseFolder string) error {

	files, err := fileutil.ReadDir(baseFolder)

	if err != nil {
		dlog.Error(err)
		return err
	}

	for _, file := range files {
		if !file.IsDir() {
			n := file.Name()
			dlog.Verb(n)
			switch strings.ToLower(n[len(n)-4:]) {
			case ".wav", ".mp3":
				dlog.Verb("loading file ", n)
				_, err := Load(baseFolder, n)
				if err != nil {
					dlog.Error(err)
					return err
				}
			default:
				dlog.Error("Unsupported file ending for batchLoad: ", n)
			}
		}
	}
	dlog.Verb("Loading complete")
	return nil
}
<commit_msg>Specify struct field for NotFound<commit_after>package audio

import (
	"path/filepath"
	"strings"

	"github.com/200sc/klangsynthese/audio"
	"github.com/200sc/klangsynthese/mp3"
	"github.com/200sc/klangsynthese/wav"

	"github.com/oakmound/oak/dlog"
	"github.com/oakmound/oak/fileutil"
	"github.com/oakmound/oak/oakerr"
)

// Data is an alias for an interface supporting the built in filters in our
// external audio playing library
type Data audio.FullAudio

// GetSounds returns a set of Data for a set of input filenames
func GetSounds(fileNames ...string) ([]Data, error) {
	var err error
	sounds := make([]Data, len(fileNames))
	for i, f := range fileNames {
		sounds[i], err = Get(f)
		if err != nil {
			return nil, err
		}
	}
	if len(sounds) == 0 {
		return sounds, oakerr.InsufficientInputs{AtLeast: 1, InputName: "fileName"}
	}
	return sounds, nil
}

// Get without a font will just return the raw audio data
func Get(filename string) (Data, error) {
	if IsLoaded(filename) {
		return loaded[filename], nil
	}
	return nil, oakerr.NotFound{InputName: filename}
}

// Load joins the directory and filename, attempts to find
// the input file, and stores it as filename in the set of
// loaded files.
// This can cause a conflict when multiple files have the same
// name but different directories-- the first file loaded wil be the
// one stored in the loeaded map.
func Load(directory, filename string) (Data, error) {
	dlog.Verb("Loading", directory, filename)
	if !IsLoaded(filename) {
		f, err := fileutil.Open(filepath.Join(directory, filename))
		if err != nil {
			return nil, err
		}
		defer f.Close()
		var buffer audio.Audio
		end := strings.ToLower(filename[len(filename)-4:])
		switch end {
		case ".wav":
			buffer, err = wav.Load(f)
		case ".mp3":
			buffer, err = mp3.Load(f)
		default:
			return nil, oakerr.UnsupportedFormat{Format: end}
		}
		if err != nil {
			return nil, err
		}
		loaded[filename] = buffer.(audio.FullAudio)
	}
	return loaded[filename], nil
}

// Unload removes an element from the loaded map. If the element does not
// exist, it does nothing.
func Unload(filename string) {
	delete(loaded, filename)
}

// IsLoaded is shorthand for (if _, ok := loaded[filename]; ok)
func IsLoaded(filename string) bool {
	_, ok := loaded[filename]
	return ok
}

// BatchLoad attempts to load all files within a given directory
// depending on their file ending (currently supporting .wav and .mp3)
func BatchLoad(baseFolder string) error {

	files, err := fileutil.ReadDir(baseFolder)

	if err != nil {
		dlog.Error(err)
		return err
	}

	for _, file := range files {
		if !file.IsDir() {
			n := file.Name()
			dlog.Verb(n)
			switch strings.ToLower(n[len(n)-4:]) {
			case ".wav", ".mp3":
				dlog.Verb("loading file ", n)
				_, err := Load(baseFolder, n)
				if err != nil {
					dlog.Error(err)
					return err
				}
			default:
				dlog.Error("Unsupported file ending for batchLoad: ", n)
			}
		}
	}
	dlog.Verb("Loading complete")
	return nil
}
<|endoftext|>


<commit_before>package main

import (
	"crypto/rsa"
	"crypto/x509"
	"encoding/json"
	"encoding/pem"
	"flag"
	"fmt"
	"io/ioutil"
	"log"

	"github.com/lestrrat/go-jwx/jwk"
)

var privateRSAKeyPath = flag.String("private-key", "", "Path to RSA private key PEM file")

func main() {
	flag.Parse()

	d, err := ioutil.ReadFile(*privateRSAKeyPath)
	if err != nil {
		log.Fatal(err)
	}

	pemBlock, _ := pem.Decode(d)
	if len(pemBlock.Bytes) == 0 || pemBlock.Type != "PRIVATE KEY" {
		log.Fatal("Failed to read PEM")
	}

	key, err := x509.ParsePKCS8PrivateKey(pemBlock.Bytes)
	if err != nil {
		log.Fatal(err)
	}
	rsaKey, ok := key.(*rsa.PrivateKey)
	if !ok {
		log.Fatal("Failed to extract RSA key")
	}
	jKey, err := jwk.New(rsaKey)
	if err != nil {
		log.Fatal(err)
	}
	out, err := json.Marshal(jwk.Set{
		Keys: []jwk.Key{jKey},
	})
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println(string(out))
}
<commit_msg>Output JWK rather than JWKS<commit_after>package main

import (
	"crypto/rsa"
	"crypto/x509"
	"encoding/json"
	"encoding/pem"
	"flag"
	"fmt"
	"io/ioutil"
	"log"

	"github.com/lestrrat/go-jwx/jwk"
)

var privateRSAKeyPath = flag.String("private-key", "", "Path to RSA private key PEM file")

func main() {
	flag.Parse()

	d, err := ioutil.ReadFile(*privateRSAKeyPath)
	if err != nil {
		log.Fatal(err)
	}

	pemBlock, _ := pem.Decode(d)
	if len(pemBlock.Bytes) == 0 || pemBlock.Type != "PRIVATE KEY" {
		log.Fatal("Failed to read PEM")
	}

	key, err := x509.ParsePKCS8PrivateKey(pemBlock.Bytes)
	if err != nil {
		log.Fatal(err)
	}
	rsaKey, ok := key.(*rsa.PrivateKey)
	if !ok {
		log.Fatal("Failed to extract RSA key")
	}
	jKey, err := jwk.New(rsaKey)
	if err != nil {
		log.Fatal(err)
	}
	out, err := json.Marshal(jKey)
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println(string(out))
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"

	"github.com/restic/restic/backend"
	"github.com/restic/restic/debug"
	"github.com/restic/restic/pack"
	"github.com/restic/restic/repository"
)

type CmdRebuildIndex struct {
	global *GlobalOptions

	repo *repository.Repository
}

func init() {
	_, err := parser.AddCommand("rebuild-index",
		"rebuild the index",
		"The rebuild-index command builds a new index",
		&CmdRebuildIndex{global: &globalOpts})
	if err != nil {
		panic(err)
	}
}

func (cmd CmdRebuildIndex) storeIndex(index *repository.Index) (*repository.Index, error) {
	debug.Log("RebuildIndex.RebuildIndex", "saving index")

	cmd.global.Printf("  saving new index\n")
	id, err := repository.SaveIndex(cmd.repo, index)
	if err != nil {
		debug.Log("RebuildIndex.RebuildIndex", "error saving index: %v", err)
		return nil, err
	}

	debug.Log("RebuildIndex.RebuildIndex", "index saved as %v", id.Str())
	index = repository.NewIndex()

	return index, nil
}

func (cmd CmdRebuildIndex) RebuildIndex() error {
	debug.Log("RebuildIndex.RebuildIndex", "start")

	done := make(chan struct{})
	defer close(done)

	indexIDs := backend.NewIDSet()
	for id := range cmd.repo.List(backend.Index, done) {
		indexIDs.Insert(id)
	}

	cmd.global.Printf("rebuilding index from %d indexes\n", len(indexIDs))

	debug.Log("RebuildIndex.RebuildIndex", "found %v indexes", len(indexIDs))

	combinedIndex := repository.NewIndex()
	packsDone := backend.NewIDSet()

	type Blob struct {
		id  backend.ID
		tpe pack.BlobType
	}
	blobsDone := make(map[Blob]struct{})

	i := 0
	for indexID := range indexIDs {
		cmd.global.Printf("  loading index %v\n", i)

		debug.Log("RebuildIndex.RebuildIndex", "load index %v", indexID.Str())
		idx, err := repository.LoadIndex(cmd.repo, indexID.String())
		if err != nil {
			return err
		}

		debug.Log("RebuildIndex.RebuildIndex", "adding blobs from index %v", indexID.Str())

		for packedBlob := range idx.Each(done) {
			packsDone.Insert(packedBlob.PackID)
			b := Blob{
				id:  packedBlob.ID,
				tpe: packedBlob.Type,
			}
			if _, ok := blobsDone[b]; ok {
				continue
			}

			blobsDone[b] = struct{}{}
			combinedIndex.Store(packedBlob)
		}

		combinedIndex.AddToSupersedes(indexID)

		if repository.IndexFull(combinedIndex) {
			combinedIndex, err = cmd.storeIndex(combinedIndex)
			if err != nil {
				return err
			}
		}

		i++
	}

	var err error
	if combinedIndex.Length() > 0 {
		combinedIndex, err = cmd.storeIndex(combinedIndex)
		if err != nil {
			return err
		}
	}

	cmd.global.Printf("removing %d old indexes\n", len(indexIDs))
	for id := range indexIDs {
		debug.Log("RebuildIndex.RebuildIndex", "remove index %v", id.Str())

		err := cmd.repo.Backend().Remove(backend.Index, id.String())
		if err != nil {
			debug.Log("RebuildIndex.RebuildIndex", "error removing index %v: %v", id.Str(), err)
			return err
		}
	}

	cmd.global.Printf("checking for additional packs\n")
	newPacks := 0
	var buf []byte
	for packID := range cmd.repo.List(backend.Data, done) {
		if packsDone.Has(packID) {
			continue
		}

		debug.Log("RebuildIndex.RebuildIndex", "pack %v not indexed", packID.Str())
		newPacks++

		var err error

		h := backend.Handle{Type: backend.Data, Name: packID.String()}
		buf, err = backend.LoadAll(cmd.repo.Backend(), h, buf)

		up, err := pack.NewUnpacker(cmd.repo.Key(), bytes.NewReader(buf))
		if err != nil {
			debug.Log("RebuildIndex.RebuildIndex", "error while unpacking pack %v", packID.Str())
			return err
		}

		for _, blob := range up.Entries {
			debug.Log("RebuildIndex.RebuildIndex", "pack %v: blob %v", packID.Str(), blob)
			combinedIndex.Store(repository.PackedBlob{
				Type:   blob.Type,
				ID:     blob.ID,
				PackID: packID,
				Offset: blob.Offset,
				Length: blob.Length,
			})
		}

		if repository.IndexFull(combinedIndex) {
			combinedIndex, err = cmd.storeIndex(combinedIndex)
			if err != nil {
				return err
			}
		}
	}

	if combinedIndex.Length() > 0 {
		combinedIndex, err = cmd.storeIndex(combinedIndex)
		if err != nil {
			return err
		}
	}

	cmd.global.Printf("added %d packs to the index\n", newPacks)

	debug.Log("RebuildIndex.RebuildIndex", "done")
	return nil
}

func (cmd CmdRebuildIndex) Execute(args []string) error {
	repo, err := cmd.global.OpenRepository()
	if err != nil {
		return err
	}
	cmd.repo = repo

	lock, err := lockRepoExclusive(repo)
	defer unlockRepo(lock)
	if err != nil {
		return err
	}

	return cmd.RebuildIndex()
}
<commit_msg>Handle pack loading errors in rebuild-index<commit_after>package main

import (
	"bytes"
	"fmt"

	"github.com/restic/restic/backend"
	"github.com/restic/restic/debug"
	"github.com/restic/restic/pack"
	"github.com/restic/restic/repository"
)

type CmdRebuildIndex struct {
	global *GlobalOptions

	repo *repository.Repository
}

func init() {
	_, err := parser.AddCommand("rebuild-index",
		"rebuild the index",
		"The rebuild-index command builds a new index",
		&CmdRebuildIndex{global: &globalOpts})
	if err != nil {
		panic(err)
	}
}

func (cmd CmdRebuildIndex) storeIndex(index *repository.Index) (*repository.Index, error) {
	debug.Log("RebuildIndex.RebuildIndex", "saving index")

	cmd.global.Printf("  saving new index\n")
	id, err := repository.SaveIndex(cmd.repo, index)
	if err != nil {
		debug.Log("RebuildIndex.RebuildIndex", "error saving index: %v", err)
		return nil, err
	}

	debug.Log("RebuildIndex.RebuildIndex", "index saved as %v", id.Str())
	index = repository.NewIndex()

	return index, nil
}

func (cmd CmdRebuildIndex) RebuildIndex() error {
	debug.Log("RebuildIndex.RebuildIndex", "start")

	done := make(chan struct{})
	defer close(done)

	indexIDs := backend.NewIDSet()
	for id := range cmd.repo.List(backend.Index, done) {
		indexIDs.Insert(id)
	}

	cmd.global.Printf("rebuilding index from %d indexes\n", len(indexIDs))

	debug.Log("RebuildIndex.RebuildIndex", "found %v indexes", len(indexIDs))

	combinedIndex := repository.NewIndex()
	packsDone := backend.NewIDSet()

	type Blob struct {
		id  backend.ID
		tpe pack.BlobType
	}
	blobsDone := make(map[Blob]struct{})

	i := 0
	for indexID := range indexIDs {
		cmd.global.Printf("  loading index %v\n", i)

		debug.Log("RebuildIndex.RebuildIndex", "load index %v", indexID.Str())
		idx, err := repository.LoadIndex(cmd.repo, indexID.String())
		if err != nil {
			return err
		}

		debug.Log("RebuildIndex.RebuildIndex", "adding blobs from index %v", indexID.Str())

		for packedBlob := range idx.Each(done) {
			packsDone.Insert(packedBlob.PackID)
			b := Blob{
				id:  packedBlob.ID,
				tpe: packedBlob.Type,
			}
			if _, ok := blobsDone[b]; ok {
				continue
			}

			blobsDone[b] = struct{}{}
			combinedIndex.Store(packedBlob)
		}

		combinedIndex.AddToSupersedes(indexID)

		if repository.IndexFull(combinedIndex) {
			combinedIndex, err = cmd.storeIndex(combinedIndex)
			if err != nil {
				return err
			}
		}

		i++
	}

	var err error
	if combinedIndex.Length() > 0 {
		combinedIndex, err = cmd.storeIndex(combinedIndex)
		if err != nil {
			return err
		}
	}

	cmd.global.Printf("removing %d old indexes\n", len(indexIDs))
	for id := range indexIDs {
		debug.Log("RebuildIndex.RebuildIndex", "remove index %v", id.Str())

		err := cmd.repo.Backend().Remove(backend.Index, id.String())
		if err != nil {
			debug.Log("RebuildIndex.RebuildIndex", "error removing index %v: %v", id.Str(), err)
			return err
		}
	}

	cmd.global.Printf("checking for additional packs\n")
	newPacks := 0
	var buf []byte
	for packID := range cmd.repo.List(backend.Data, done) {
		if packsDone.Has(packID) {
			continue
		}

		debug.Log("RebuildIndex.RebuildIndex", "pack %v not indexed", packID.Str())
		newPacks++

		var err error

		h := backend.Handle{Type: backend.Data, Name: packID.String()}
		buf, err = backend.LoadAll(cmd.repo.Backend(), h, buf)
		if err != nil {
			debug.Log("RebuildIndex.RebuildIndex", "error while loading pack %v", packID.Str())
			return fmt.Errorf("error while loading pack %v: %v", packID.Str(), err)
		}

		hash := backend.Hash(buf)
		if !hash.Equal(packID) {
			debug.Log("RebuildIndex.RebuildIndex", "Pack ID does not match, want %v, got %v", packID.Str(), hash.Str())
			return fmt.Errorf("Pack ID does not match, want %v, got %v", packID.Str(), hash.Str())
		}

		up, err := pack.NewUnpacker(cmd.repo.Key(), bytes.NewReader(buf))
		if err != nil {
			debug.Log("RebuildIndex.RebuildIndex", "error while unpacking pack %v", packID.Str())
			return err
		}

		for _, blob := range up.Entries {
			debug.Log("RebuildIndex.RebuildIndex", "pack %v: blob %v", packID.Str(), blob)
			combinedIndex.Store(repository.PackedBlob{
				Type:   blob.Type,
				ID:     blob.ID,
				PackID: packID,
				Offset: blob.Offset,
				Length: blob.Length,
			})
		}

		if repository.IndexFull(combinedIndex) {
			combinedIndex, err = cmd.storeIndex(combinedIndex)
			if err != nil {
				return err
			}
		}
	}

	if combinedIndex.Length() > 0 {
		combinedIndex, err = cmd.storeIndex(combinedIndex)
		if err != nil {
			return err
		}
	}

	cmd.global.Printf("added %d packs to the index\n", newPacks)

	debug.Log("RebuildIndex.RebuildIndex", "done")
	return nil
}

func (cmd CmdRebuildIndex) Execute(args []string) error {
	repo, err := cmd.global.OpenRepository()
	if err != nil {
		return err
	}
	cmd.repo = repo

	lock, err := lockRepoExclusive(repo)
	defer unlockRepo(lock)
	if err != nil {
		return err
	}

	return cmd.RebuildIndex()
}
<|endoftext|>


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

// legacy_boot allows to handover a system running linuxboot/u-root
// to a legacy preinstalled operating system by replacing the traditional
// bootloader path

//
// Synopsis:
//	legacy_boot
//
// Description:
//	If returns to u-root shell, the code didn't found a local bootable option
//
// Notes:
//	The code is looking for boot/grub/grub.cfg file as to identify the
//	boot option.
//	The first bootable device found in the block device tree is the one used
//	Windows is not supported (that is a work in progress)
//
// Example:
//	legacy_boot -v 	- Start the script in verbose mode for debugging purpose

package main

import (
	"bufio"
	"fmt"
	"github.com/u-root/u-root/pkg/kexec"
	"io"
	"io/ioutil"
	"log"
	"os"
	"strings"
	"flag"
	"syscall"
)

var verbose bool
type options struct {
        verbose bool
}

func check(e error) {
	if e != nil {
		panic(e)
	}
}

func blkDevicesList(blkpath string, devpath string) []string {
	var blkDevices []string
	files, err := ioutil.ReadDir(blkpath)
	if err != nil {
		log.Fatal(err)
	}
	for _, file := range files {
		deviceEntry, err := ioutil.ReadDir(blkpath + file.Name() + devpath)
		if err != nil {
			println("can t read directory")
		}
		blkDevices = append(blkDevices, deviceEntry[0].Name())
	}
	return (blkDevices)
}

// checkForBootableMbr is looking for bootable MBR signature
// Current support is limited to Hard disk devices and USB devices
func checkForBootableMbr(path string) int {
	var b511, b510 byte
	var err error
	f, err := os.Open(path)
	check(err)
	b1 := make([]byte, 512)
	_,err=f.Read(b1)
	check(err)
	b511 = b1[511]
	b510 = b1[510]
	err=f.Close()
	check(err)
	if ((b511 == 0xaa) && (b510 == 0x55)) == true {
		return 1
	}
	return 0
}

// getDevicePartList returns all devices attached to a specific name like /dev/sdaX where X can move from 0 to 127
// FIXME no support for devices which are included into subdirectory within /dev
func getDevicePartList(path string) []string {
	var returnValue []string
	files, err := ioutil.ReadDir("/dev/")
	if err != nil {
		log.Fatal(err)
	}
	for _, file := range files {
		if strings.HasPrefix(file.Name(), path) {
			// We shall not return full device name
			if file.Name() != path {
				// We shall check that the remaining part is a number
				returnValue = append(returnValue, file.Name())
			}
		}
	}
	return returnValue
}

// getSupportedFilesystem returns all block file system supported by the linuxboot kernel
func getSupportedFilesystem() []string {
	var returnValue []string
	var err error
	file, err := os.Open("/proc/filesystems")
	check(err)
	scanner := bufio.NewScanner(file)
	if err = scanner.Err(); err != nil {
		log.Fatal(err)
	}

	for scanner.Scan() {
		fields := strings.Fields(scanner.Text())
		if fields[0] == "nodev" {
			continue
		}
		if fields[1] != "" {
			returnValue = append(returnValue, fields[1])
    		}
	}

	err=file.Close()
	check(err)
	return returnValue

}

// mountEntry tries to mount a specific block device
func mountEntry(path string, supportedFilesystem []string) bool {
	var returnValue bool
	var err error
	err=syscall.Mkdir("/u-root", 0777)
	check(err)
	var flags uintptr
	// Was supposed to be unecessary for kernel 4.x.x
	if verbose {
		println("/dev/" + path)
	}
	for _, filesystem := range supportedFilesystem {
		flags = syscall.MS_MGC_VAL
		// Need to load the filesystem kind supported
		err = syscall.Mkdir("/u-root/"+path, 0777)
		check(err)
		err := syscall.Mount("/dev/"+path, "/u-root/"+path, filesystem, flags, "")
		if err == nil {
			return true
		}
	}
	returnValue = false
	return returnValue
}

func umountEntry(path string) bool {
	var returnValue bool
	var flags int
	// Was supposed to be unecessary for kernel 4.x.x
	flags = syscall.MNT_DETACH
	err := syscall.Unmount(path, flags)
	if err == nil {
		return true
	}
	returnValue = false
	return returnValue
}

// checkBootEntry is looking for grub.cfg file
// and return absolute path to it
func checkBootEntry(mountPoint string) string {
	_, err := os.Stat(mountPoint + "/boot")
	if err == nil {
		// The boot directory is there
		_, err2 := os.Stat(mountPoint + "/boot" + "/grub")
		if err2 == nil {
			_, err3 := os.Stat(mountPoint + "/boot" + "/grub" + "/grub.cfg")
			if err3 == nil {
				// found
				return (mountPoint + "/boot" + "/grub")
			}
		}
	}
	return ""

}

// getFileMenuContent is parsing a grub.cfg file
// input: absolute directory path to grub.cfg
// output: Return a list of strings with the following format
//	 line[3*x] - menuconfig
//	 line[3*x+1] - linux kernel + boot options
// 	 line[3*x+2] - initrd
// and the default boot entry configured into grub.cfg
func getFileMenuContent(path string) ([]string, int) {
	var returnValue []string
	var err error
	file, err := os.Open(path + "/grub.cfg")
	check(err)
	scanner := bufio.NewScanner(file)
	if err = scanner.Err(); err != nil {
		log.Fatal(err)
	}
	var status int
	var intReturn int
	intReturn = 0
	status = 0
	// When status = 0 we are looking for a menu entry
	// When status = 1 we are looking for a linux entry
	// When status = 2 we are looking for a initrd entry
	var trimmedLine string
	for scanner.Scan() {
		trimmedLine = strings.TrimSpace(scanner.Text())
		trimmedLine = strings.Join(strings.Fields(trimmedLine), " ")
		if !strings.HasPrefix(trimmedLine, "#") {
			if (strings.HasPrefix(trimmedLine, "set default=") ) && (status == 0) {
				fmt.Sscanf(trimmedLine, "set default=\"%d\"", &intReturn)
			}
			if (strings.HasPrefix(trimmedLine, "menuentry ")) && (status == 0) {
				status = 1
				returnValue = append(returnValue, trimmedLine)
			}
			if (strings.HasPrefix(trimmedLine, "linux ")) && (status == 1) {
				status = 2
				returnValue = append(returnValue, trimmedLine)
			}
			if (strings.HasPrefix(trimmedLine, "initrd ")) && (status == 2) {
				status = 0
				returnValue = append(returnValue, trimmedLine)
			}
		}
	}
	err = file.Close()
	check(err)
	return returnValue, intReturn

}

func copyLocal(path string) string {
	var dest string
	var err error
	result := strings.Split(path, "/")
	for _, entry := range result {
		dest = entry
	}
	dest = "/tmp/" + dest
	srcFile, err := os.Open(path)
	check(err)

	destFile, err := os.Create(dest) // creates if file doesn't exist
	check(err)

	_, err = io.Copy(destFile, srcFile) // check first var for number of bytes copied
	check(err)

	err = destFile.Sync()
	check(err)
	err = destFile.Close()
	check(err)
	err = srcFile.Close()
	check(err)
	return dest
}

// kexecEntry is booting new kernel based on the content of grub.cfg
func kexecEntry(grubConfPath string, mountPoint string) {
	var fileMenuContent []string
	var entry int
	var localKernelPath string
	var localInitrdPath string
	if verbose {
		println(grubConfPath)
	}
	fileMenuContent, entry = getFileMenuContent(grubConfPath)
	var kernel string
	var kernelParameter string
	var initrd string
	var kernelInfos []string
	kernelInfos = strings.Fields(fileMenuContent[3*entry+1])
	kernel = kernelInfos[1]
	var count int
	count = 0
	for _, field := range kernelInfos {
		if count > 1 {
			kernelParameter = kernelParameter + " " + field
		}
		count = count + 1
	}
	fmt.Sscanf(fileMenuContent[3*entry+2], "initrd %s", &initrd)
	if verbose {
		println("************** boot parameters  ********************")
		println(kernel)
		println(kernelParameter)
		println(initrd)
		println("****************************************************")
	}
	localKernelPath = copyLocal(mountPoint + kernel)
	localInitrdPath = copyLocal(mountPoint + initrd)
	if verbose {
		println(localKernelPath)
	}
	umountEntry(mountPoint)
	// We can kexec the kernel with localKernelPath as kernel entry, kernelParameter as parameter and initrd as initrd !
	log.Printf("Loading %s for kernel\n", localKernelPath)

	kernelDesc, err := os.OpenFile(localKernelPath, os.O_RDONLY, 0)
	if err != nil {
		log.Fatalf("open(%q): %v", localKernelPath, err)
	}
	// defer kernelDesc.Close()

	var ramfs *os.File
	ramfs, err = os.OpenFile(localInitrdPath, os.O_RDONLY, 0)
	if err != nil {
		log.Fatalf("open(%q): %v", localInitrdPath, err)
	}
	// defer ramfs.Close()

	if err := kexec.FileLoad(kernelDesc, ramfs, kernelParameter); err != nil {
		log.Fatalf("%v", err)
	}
 	err = ramfs.Close()
	check(err)
	err = kernelDesc.Close()
	check(err)
	if err := kexec.Reboot(); err != nil {
		log.Fatalf("%v", err)
	}

}

func registerFlags(f *flag.FlagSet) *options {
        o := &options{}
        f.BoolVar(&o.verbose, "v", false, "Set verbose output")
        return o
}

func main() {
	var blkList []string
	var supportedFilesystem []string
	verbose = false
        opts := registerFlags(flag.CommandLine)
	flag.Parse()

        if opts.verbose != false {
		verbose = true
        }

	supportedFilesystem = getSupportedFilesystem()
	if verbose {
		println("************** Supported Filesystem by current linuxboot ********************")
		for _, filesystem := range supportedFilesystem {
			println(filesystem)
		}
		println("*****************************************************************************")
	}
	blkList = blkDevicesList("/sys/dev/block/", "/device/block/")
	// We must validate if the MBR is bootable or not and keep the
	// devices which do have such support
	// drive are easy to detect
	for _, entry := range blkList {
		if checkForBootableMbr("/dev/"+entry) == 1 {
			fmt.Println("Bootable device found")
			// We need to loop on the device entries which are into /dev/<device>X
			// and mount each partitions as to find /boot entry if it is available somewhere
			var devicePartList []string
			devicePartList = getDevicePartList(entry)
			for _, deviceList := range devicePartList {
				if mountEntry(deviceList, supportedFilesystem) {
					if verbose {
						println("mount succeed")
					}
					var grubConfPath = checkBootEntry("/u-root/" + deviceList)
					if grubConfPath != "" {
						if verbose {
							println("calling basic kexec")
						}
						kexecEntry(grubConfPath, "/u-root/"+deviceList)
					}
				}
				umountEntry("/u-root/" + deviceList)
			}
		}
	}
	println("Sorry no bootable device found")
}
<commit_msg>Fix error handling when directory soon exist (aka doesn't report any error)<commit_after>// Copyright 2012-2017 the u-root Authors. All rights reserved
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// legacy_boot allows to handover a system running linuxboot/u-root
// to a legacy preinstalled operating system by replacing the traditional
// bootloader path

//
// Synopsis:
//	legacy_boot
//
// Description:
//	If returns to u-root shell, the code didn't found a local bootable option
//
// Notes:
//	The code is looking for boot/grub/grub.cfg file as to identify the
//	boot option.
//	The first bootable device found in the block device tree is the one used
//	Windows is not supported (that is a work in progress)
//
// Example:
//	legacy_boot -v 	- Start the script in verbose mode for debugging purpose

package main

import (
	"bufio"
	"fmt"
	"github.com/u-root/u-root/pkg/kexec"
	"io"
	"io/ioutil"
	"log"
	"os"
	"strings"
	"flag"
	"syscall"
)

var verbose bool
type options struct {
        verbose bool
}

func check(e error) {
	if e != nil {
		panic(e)
	}
}
func check_fs(e error) {
}

func blkDevicesList(blkpath string, devpath string) []string {
	var blkDevices []string
	files, err := ioutil.ReadDir(blkpath)
	if err != nil {
		log.Fatal(err)
	}
	for _, file := range files {
		deviceEntry, err := ioutil.ReadDir(blkpath + file.Name() + devpath)
		if err != nil {
			if ( verbose ) {
				println("can t read directory")
			}
			continue
		}
		blkDevices = append(blkDevices, deviceEntry[0].Name())
	}
	return (blkDevices)
}

// checkForBootableMbr is looking for bootable MBR signature
// Current support is limited to Hard disk devices and USB devices
func checkForBootableMbr(path string) int {
	var b511, b510 byte
	var err error
	f, err := os.Open(path)
	check(err)
	b1 := make([]byte, 512)
	_,err=f.Read(b1)
	check(err)
	b511 = b1[511]
	b510 = b1[510]
	err=f.Close()
	check(err)
	if ((b511 == 0xaa) && (b510 == 0x55)) == true {
		return 1
	}
	return 0
}

// getDevicePartList returns all devices attached to a specific name like /dev/sdaX where X can move from 0 to 127
// FIXME no support for devices which are included into subdirectory within /dev
func getDevicePartList(path string) []string {
	var returnValue []string
	files, err := ioutil.ReadDir("/dev/")
	if err != nil {
		log.Fatal(err)
	}
	for _, file := range files {
		if strings.HasPrefix(file.Name(), path) {
			// We shall not return full device name
			if file.Name() != path {
				// We shall check that the remaining part is a number
				returnValue = append(returnValue, file.Name())
			}
		}
	}
	return returnValue
}

// getSupportedFilesystem returns all block file system supported by the linuxboot kernel
func getSupportedFilesystem() []string {
	var returnValue []string
	var err error
	file, err := os.Open("/proc/filesystems")
	check(err)
	scanner := bufio.NewScanner(file)
	if err = scanner.Err(); err != nil {
		log.Fatal(err)
	}

	for scanner.Scan() {
		fields := strings.Fields(scanner.Text())
		if fields[0] == "nodev" {
			continue
		}
		if fields[0] != "" {
			returnValue = append(returnValue, fields[0])
    		}
	}

	err=file.Close()
	check(err)
	return returnValue

}

// mountEntry tries to mount a specific block device
func mountEntry(path string, supportedFilesystem []string) bool {
	var returnValue bool
	var err error
	err=syscall.Mkdir("/u-root", 0777)
	check_fs(err)
	var flags uintptr
	// Was supposed to be unecessary for kernel 4.x.x
	if verbose {
		println("/dev/" + path)
	}
	for _, filesystem := range supportedFilesystem {
		flags = syscall.MS_MGC_VAL
		// Need to load the filesystem kind supported
		err = syscall.Mkdir("/u-root/"+path, 0777)
		check_fs(err)
		err := syscall.Mount("/dev/"+path, "/u-root/"+path, filesystem, flags, "")
		if err == nil {
			return true
		}
	}
	returnValue = false
	return returnValue
}

func umountEntry(path string) bool {
	var returnValue bool
	var flags int
	// Was supposed to be unecessary for kernel 4.x.x
	flags = syscall.MNT_DETACH
	err := syscall.Unmount(path, flags)
	if err == nil {
		return true
	}
	returnValue = false
	return returnValue
}

// checkBootEntry is looking for grub.cfg file
// and return absolute path to it
func checkBootEntry(mountPoint string) string {
	_, err := os.Stat(mountPoint + "/boot")
	if err == nil {
		// The boot directory is there
		_, err2 := os.Stat(mountPoint + "/boot" + "/grub")
		if err2 == nil {
			_, err3 := os.Stat(mountPoint + "/boot" + "/grub" + "/grub.cfg")
			if err3 == nil {
				// found
				return (mountPoint + "/boot" + "/grub")
			}
		}
	}
	return ""

}

// getFileMenuContent is parsing a grub.cfg file
// input: absolute directory path to grub.cfg
// output: Return a list of strings with the following format
//	 line[3*x] - menuconfig
//	 line[3*x+1] - linux kernel + boot options
// 	 line[3*x+2] - initrd
// and the default boot entry configured into grub.cfg
func getFileMenuContent(path string) ([]string, int) {
	var returnValue []string
	var err error
	file, err := os.Open(path + "/grub.cfg")
	check(err)
	scanner := bufio.NewScanner(file)
	if err = scanner.Err(); err != nil {
		log.Fatal(err)
	}
	var status int
	var intReturn int
	intReturn = 0
	status = 0
	// When status = 0 we are looking for a menu entry
	// When status = 1 we are looking for a linux entry
	// When status = 2 we are looking for a initrd entry
	var trimmedLine string
	for scanner.Scan() {
		trimmedLine = strings.TrimSpace(scanner.Text())
		trimmedLine = strings.Join(strings.Fields(trimmedLine), " ")
		if !strings.HasPrefix(trimmedLine, "#") {
			if (strings.HasPrefix(trimmedLine, "set default=") ) && (status == 0) {
				fmt.Sscanf(trimmedLine, "set default=\"%d\"", &intReturn)
			}
			if (strings.HasPrefix(trimmedLine, "menuentry ")) && (status == 0) {
				status = 1
				returnValue = append(returnValue, trimmedLine)
			}
			if (strings.HasPrefix(trimmedLine, "linux ")) && (status == 1) {
				status = 2
				returnValue = append(returnValue, trimmedLine)
			}
			if (strings.HasPrefix(trimmedLine, "initrd ")) && (status == 2) {
				status = 0
				returnValue = append(returnValue, trimmedLine)
			}
		}
	}
	err = file.Close()
	check(err)
	return returnValue, intReturn

}

func copyLocal(path string) string {
	var dest string
	var err error
	result := strings.Split(path, "/")
	for _, entry := range result {
		dest = entry
	}
	dest = "/tmp/" + dest
	srcFile, err := os.Open(path)
	check(err)

	destFile, err := os.Create(dest) // creates if file doesn't exist
	check(err)

	_, err = io.Copy(destFile, srcFile) // check first var for number of bytes copied
	check(err)

	err = destFile.Sync()
	check(err)
	err = destFile.Close()
	check(err)
	err = srcFile.Close()
	check(err)
	return dest
}

// kexecEntry is booting new kernel based on the content of grub.cfg
func kexecEntry(grubConfPath string, mountPoint string) {
	var fileMenuContent []string
	var entry int
	var localKernelPath string
	var localInitrdPath string
	if verbose {
		println(grubConfPath)
	}
	fileMenuContent, entry = getFileMenuContent(grubConfPath)
	var kernel string
	var kernelParameter string
	var initrd string
	var kernelInfos []string
	kernelInfos = strings.Fields(fileMenuContent[3*entry+1])
	kernel = kernelInfos[1]
	var count int
	count = 0
	for _, field := range kernelInfos {
		if count > 1 {
			kernelParameter = kernelParameter + " " + field
		}
		count = count + 1
	}
	fmt.Sscanf(fileMenuContent[3*entry+2], "initrd %s", &initrd)
	if verbose {
		println("************** boot parameters  ********************")
		println(kernel)
		println(kernelParameter)
		println(initrd)
		println("****************************************************")
	}
	localKernelPath = copyLocal(mountPoint + kernel)
	localInitrdPath = copyLocal(mountPoint + initrd)
	if verbose {
		println(localKernelPath)
	}
	umountEntry(mountPoint)
	// We can kexec the kernel with localKernelPath as kernel entry, kernelParameter as parameter and initrd as initrd !
	log.Printf("Loading %s for kernel\n", localKernelPath)

	kernelDesc, err := os.OpenFile(localKernelPath, os.O_RDONLY, 0)
	if err != nil {
		log.Fatalf("open(%q): %v", localKernelPath, err)
	}
	// defer kernelDesc.Close()

	var ramfs *os.File
	ramfs, err = os.OpenFile(localInitrdPath, os.O_RDONLY, 0)
	if err != nil {
		log.Fatalf("open(%q): %v", localInitrdPath, err)
	}
	// defer ramfs.Close()

	if err := kexec.FileLoad(kernelDesc, ramfs, kernelParameter); err != nil {
		log.Fatalf("%v", err)
	}
 	err = ramfs.Close()
	check(err)
	err = kernelDesc.Close()
	check(err)
	if err := kexec.Reboot(); err != nil {
		log.Fatalf("%v", err)
	}

}

func registerFlags(f *flag.FlagSet) *options {
        o := &options{}
        f.BoolVar(&o.verbose, "v", false, "Set verbose output")
        return o
}

func main() {
	var blkList []string
	var supportedFilesystem []string
	verbose = false
        opts := registerFlags(flag.CommandLine)
	flag.Parse()

        if opts.verbose != false {
		verbose = true
        }

	supportedFilesystem = getSupportedFilesystem()
	if verbose {
		println("************** Supported Filesystem by current linuxboot ********************")
		for _, filesystem := range supportedFilesystem {
			println(filesystem)
		}
		println("*****************************************************************************")
	}
	blkList = blkDevicesList("/sys/dev/block/", "/device/block/")
	// We must validate if the MBR is bootable or not and keep the
	// devices which do have such support
	// drive are easy to detect
	for _, entry := range blkList {
		if checkForBootableMbr("/dev/"+entry) == 1 {
			fmt.Println("Bootable device found")
			// We need to loop on the device entries which are into /dev/<device>X
			// and mount each partitions as to find /boot entry if it is available somewhere
			var devicePartList []string
			devicePartList = getDevicePartList(entry)
			for _, deviceList := range devicePartList {
				if mountEntry(deviceList, supportedFilesystem) {
					if verbose {
						println("mount succeed")
					}
					var grubConfPath = checkBootEntry("/u-root/" + deviceList)
					if grubConfPath != "" {
						if verbose {
							println("calling basic kexec")
						}
						kexecEntry(grubConfPath, "/u-root/"+deviceList)
					}
				}
				umountEntry("/u-root/" + deviceList)
			}
		}
	}
	println("Sorry no bootable device found")
}
<|endoftext|>


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

import (
	"encoding/json"
	"path"
	"strconv"

	"github.com/cilium/cilium/common"
	"github.com/cilium/cilium/common/types"
)

func (d *Daemon) updateServiceL4IDRef(svcl4ID types.ServiceL4ID) error {
	key := path.Join(common.ServiceIDKeyPath, strconv.FormatUint(uint64(svcl4ID.ServiceID), 10))
	return d.kvClient.SetValue(key, svcl4ID)
}

// gasNewServiceL4ID gets and sets a New ServiceL4 ID.
func (d *Daemon) gasNewServiceL4ID(svcl4 *types.ServiceL4ID) error {
	baseID, err := d.GetMaxServiceID()
	if err != nil {
		return err
	}

	return d.kvClient.GASNewServiceL4ID(common.ServiceIDKeyPath, baseID, svcl4)
}

// PutServiceL4 stores the given service in the kvstore and returns the ServiceL4ID
// created for the given servicel4.
func (d *Daemon) PutServiceL4(svcl4 types.ServiceL4) (*types.ServiceL4ID, error) {
	log.Debugf("Resolving service %+v", svcl4)

	// Retrieve unique SHA256Sum for service
	sha256Sum, err := svcl4.SHA256Sum()
	if err != nil {
		return nil, err
	}
	svcPath := path.Join(common.ServicesKeyPath, sha256Sum)

	// Lock that sha256Sum
	lockKey, err := d.kvClient.LockPath(svcPath)
	if err != nil {
		return nil, err
	}
	defer lockKey.Unlock()

	// After lock complete, get svc's path
	rmsg, err := d.kvClient.GetValue(svcPath)
	if err != nil {
		return nil, err
	}

	sl4KV := types.ServiceL4ID{}
	if rmsg == nil {
		sl4KV.ServiceL4 = svcl4
		if err := d.gasNewServiceL4ID(&sl4KV); err != nil {
			return nil, err
		}
		err = d.kvClient.SetValue(svcPath, sl4KV)
	} else {
		err = json.Unmarshal(rmsg, &sl4KV)
	}

	return &sl4KV, err
}

func (d *Daemon) getServiceL4ID(keyPath string) (*types.ServiceL4ID, error) {
	rmsg, err := d.kvClient.GetValue(keyPath)
	if err != nil {
		return nil, err
	}
	if rmsg == nil {
		return nil, nil
	}

	var svcl4ID types.ServiceL4ID
	err = json.Unmarshal(rmsg, &svcl4ID)
	return &svcl4ID, err
}

// GetServiceL4ID returns the ServiceL4ID that belongs to the given id.
func (d *Daemon) GetServiceL4ID(id uint32) (*types.ServiceL4ID, error) {
	strID := strconv.FormatUint(uint64(id), 10)
	return d.getServiceL4ID(path.Join(common.ServiceIDKeyPath, strID))
}

// GetServiceL4IDBySHA256 returns the ServiceL4ID that have the given SHA256SUM.
func (d *Daemon) GetServiceL4IDBySHA256(sha256sum string) (*types.ServiceL4ID, error) {
	return d.getServiceL4ID(path.Join(common.ServicesKeyPath, sha256sum))
}

// DeleteServiceL4IDByUUID deletes the ServiceL4ID belonging to the given id.
func (d *Daemon) DeleteServiceL4IDByUUID(id uint32) error {
	svcl4ID, err := d.GetServiceL4ID(id)
	if err != nil {
		return err
	}
	if svcl4ID == nil {
		return nil
	}
	sha256sum, err := svcl4ID.SHA256Sum()
	if err != nil {
		return err
	}

	return d.DeleteServiceL4IDBySHA256(sha256sum)
}

// DeleteServiceL4IDBySHA256 deletes the ServiceL4ID that belong to the serviceL4ID'
// sha256Sum.
func (d *Daemon) DeleteServiceL4IDBySHA256(sha256Sum string) error {
	if sha256Sum == "" {
		return nil
	}
	svcPath := path.Join(common.ServicesKeyPath, sha256Sum)
	// Lock that sha256Sum
	lockKey, err := d.kvClient.LockPath(svcPath)
	if err != nil {
		return err
	}
	defer lockKey.Unlock()

	return d.kvClient.SetValue(svcPath, types.ServiceL4ID{ServiceID: 0})
}

// GetMaxServiceID returns the maximum possible free UUID stored in the kvstore.
func (d *Daemon) GetMaxServiceID() (uint32, error) {
	return d.kvClient.GetMaxID(common.LastFreeServiceIDKeyPath, common.FirstFreeServiceID)
}
<commit_msg>daemon: fix put services l4 bug<commit_after>//
// Copyright 2016 Authors of Cilium
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
package daemon

import (
	"encoding/json"
	"path"
	"strconv"

	"github.com/cilium/cilium/common"
	"github.com/cilium/cilium/common/types"
)

func (d *Daemon) updateServiceL4IDRef(svcl4ID types.ServiceL4ID) error {
	key := path.Join(common.ServiceIDKeyPath, strconv.FormatUint(uint64(svcl4ID.ServiceID), 10))
	return d.kvClient.SetValue(key, svcl4ID)
}

// gasNewServiceL4ID gets and sets a New ServiceL4 ID.
func (d *Daemon) gasNewServiceL4ID(svcl4 *types.ServiceL4ID) error {
	baseID, err := d.GetMaxServiceID()
	if err != nil {
		return err
	}

	return d.kvClient.GASNewServiceL4ID(common.ServiceIDKeyPath, baseID, svcl4)
}

// PutServiceL4 stores the given service in the kvstore and returns the ServiceL4ID
// created for the given servicel4.
func (d *Daemon) PutServiceL4(svcl4 types.ServiceL4) (*types.ServiceL4ID, error) {
	log.Debugf("Resolving service %+v", svcl4)

	// Retrieve unique SHA256Sum for service
	sha256Sum, err := svcl4.SHA256Sum()
	if err != nil {
		return nil, err
	}
	svcPath := path.Join(common.ServicesKeyPath, sha256Sum)

	// Lock that sha256Sum
	lockKey, err := d.kvClient.LockPath(svcPath)
	if err != nil {
		return nil, err
	}
	defer lockKey.Unlock()

	// After lock complete, get svc's path
	rmsg, err := d.kvClient.GetValue(svcPath)
	if err != nil {
		return nil, err
	}

	sl4KV := types.ServiceL4ID{}
	if rmsg != nil {
		if err := json.Unmarshal(rmsg, &sl4KV); err != nil {
			return nil, err
		}
	}
	if sl4KV.ServiceID == 0 {
		sl4KV.ServiceL4 = svcl4
		if err := d.gasNewServiceL4ID(&sl4KV); err != nil {
			return nil, err
		}
		err = d.kvClient.SetValue(svcPath, sl4KV)
	}

	return &sl4KV, err
}

func (d *Daemon) getServiceL4ID(keyPath string) (*types.ServiceL4ID, error) {
	rmsg, err := d.kvClient.GetValue(keyPath)
	if err != nil {
		return nil, err
	}
	if rmsg == nil {
		return nil, nil
	}

	var svcl4ID types.ServiceL4ID
	err = json.Unmarshal(rmsg, &svcl4ID)
	return &svcl4ID, err
}

// GetServiceL4ID returns the ServiceL4ID that belongs to the given id.
func (d *Daemon) GetServiceL4ID(id uint32) (*types.ServiceL4ID, error) {
	strID := strconv.FormatUint(uint64(id), 10)
	return d.getServiceL4ID(path.Join(common.ServiceIDKeyPath, strID))
}

// GetServiceL4IDBySHA256 returns the ServiceL4ID that have the given SHA256SUM.
func (d *Daemon) GetServiceL4IDBySHA256(sha256sum string) (*types.ServiceL4ID, error) {
	return d.getServiceL4ID(path.Join(common.ServicesKeyPath, sha256sum))
}

// DeleteServiceL4IDByUUID deletes the ServiceL4ID belonging to the given id.
func (d *Daemon) DeleteServiceL4IDByUUID(id uint32) error {
	svcl4ID, err := d.GetServiceL4ID(id)
	if err != nil {
		return err
	}
	if svcl4ID == nil {
		return nil
	}
	sha256sum, err := svcl4ID.SHA256Sum()
	if err != nil {
		return err
	}

	return d.DeleteServiceL4IDBySHA256(sha256sum)
}

// DeleteServiceL4IDBySHA256 deletes the ServiceL4ID that belong to the serviceL4ID'
// sha256Sum.
func (d *Daemon) DeleteServiceL4IDBySHA256(sha256Sum string) error {
	if sha256Sum == "" {
		return nil
	}
	svcPath := path.Join(common.ServicesKeyPath, sha256Sum)
	// Lock that sha256Sum
	lockKey, err := d.kvClient.LockPath(svcPath)
	if err != nil {
		return err
	}
	defer lockKey.Unlock()

	return d.kvClient.SetValue(svcPath, types.ServiceL4ID{ServiceID: 0})
}

// GetMaxServiceID returns the maximum possible free UUID stored in the kvstore.
func (d *Daemon) GetMaxServiceID() (uint32, error) {
	return d.kvClient.GetMaxID(common.LastFreeServiceIDKeyPath, common.FirstFreeServiceID)
}
<|endoftext|>


<commit_before>package stats // import "github.com/docker/docker/daemon/stats"

import (
	"bufio"
	"sync"
	"time"

	"github.com/docker/docker/api/types"
	"github.com/docker/docker/container"
	"github.com/docker/docker/pkg/pubsub"
	"github.com/sirupsen/logrus"
)

// Collector manages and provides container resource stats
type Collector struct {
	m          sync.Mutex
	supervisor supervisor
	interval   time.Duration
	publishers map[*container.Container]*pubsub.Publisher
	bufReader  *bufio.Reader

	// The following fields are not set on Windows currently.
	clockTicksPerSecond uint64
}

// NewCollector creates a stats collector that will poll the supervisor with the specified interval
func NewCollector(supervisor supervisor, interval time.Duration) *Collector {
	s := &Collector{
		interval:   interval,
		supervisor: supervisor,
		publishers: make(map[*container.Container]*pubsub.Publisher),
		bufReader:  bufio.NewReaderSize(nil, 128),
	}

	platformNewStatsCollector(s)

	return s
}

type supervisor interface {
	// GetContainerStats collects all the stats related to a container
	GetContainerStats(container *container.Container) (*types.StatsJSON, error)
}

// Collect registers the container with the collector and adds it to
// the event loop for collection on the specified interval returning
// a channel for the subscriber to receive on.
func (s *Collector) Collect(c *container.Container) chan interface{} {
	s.m.Lock()
	defer s.m.Unlock()
	publisher, exists := s.publishers[c]
	if !exists {
		publisher = pubsub.NewPublisher(100*time.Millisecond, 1024)
		s.publishers[c] = publisher
	}
	return publisher.Subscribe()
}

// StopCollection closes the channels for all subscribers and removes
// the container from metrics collection.
func (s *Collector) StopCollection(c *container.Container) {
	s.m.Lock()
	if publisher, exists := s.publishers[c]; exists {
		publisher.Close()
		delete(s.publishers, c)
	}
	s.m.Unlock()
}

// Unsubscribe removes a specific subscriber from receiving updates for a container's stats.
func (s *Collector) Unsubscribe(c *container.Container, ch chan interface{}) {
	s.m.Lock()
	publisher := s.publishers[c]
	if publisher != nil {
		publisher.Evict(ch)
		if publisher.Len() == 0 {
			delete(s.publishers, c)
		}
	}
	s.m.Unlock()
}

// Run starts the collectors and will indefinitely collect stats from the supervisor
func (s *Collector) Run() {
	type publishersPair struct {
		container *container.Container
		publisher *pubsub.Publisher
	}
	// we cannot determine the capacity here.
	// it will grow enough in first iteration
	var pairs []publishersPair

	for {
		// Put sleep at the start so that it will always be hit,
		// preventing a tight loop if no stats are collected.
		time.Sleep(s.interval)

		// it does not make sense in the first iteration,
		// but saves allocations in further iterations
		pairs = pairs[:0]

		s.m.Lock()
		for container, publisher := range s.publishers {
			// copy pointers here to release the lock ASAP
			pairs = append(pairs, publishersPair{container, publisher})
		}
		s.m.Unlock()
		if len(pairs) == 0 {
			continue
		}

		onlineCPUs, err := s.getNumberOnlineCPUs()
		if err != nil {
			logrus.Errorf("collecting system online cpu count: %v", err)
			continue
		}

		for _, pair := range pairs {
			stats, err := s.supervisor.GetContainerStats(pair.container)

			switch err.(type) {
			case nil:
				// Sample system CPU usage close to container usage to avoid
				// noise in metric calculations.
				systemUsage, err := s.getSystemCPUUsage()
				if err != nil {
					logrus.WithError(err).WithField("container_id", pair.container.ID).Errorf("collecting system cpu usage")
					continue
				}

				// FIXME: move to containerd on Linux (not Windows)
				stats.CPUStats.SystemUsage = systemUsage
				stats.CPUStats.OnlineCPUs = onlineCPUs

				pair.publisher.Publish(*stats)

			case notRunningErr, notFoundErr:
				// publish empty stats containing only name and ID if not running or not found
				pair.publisher.Publish(types.StatsJSON{
					Name: pair.container.Name,
					ID:   pair.container.ID,
				})

			default:
				logrus.Errorf("collecting stats for %s: %v", pair.container.ID, err)
				pair.publisher.Publish(types.StatsJSON{
					Name: pair.container.Name,
					ID:   pair.container.ID,
				})
			}
		}
	}
}

type notRunningErr interface {
	error
	Conflict()
}

type notFoundErr interface {
	error
	NotFound()
}
<commit_msg>Use condition variable to wake stats collector.<commit_after>package stats // import "github.com/docker/docker/daemon/stats"

import (
	"bufio"
	"sync"
	"time"

	"github.com/docker/docker/api/types"
	"github.com/docker/docker/container"
	"github.com/docker/docker/pkg/pubsub"
	"github.com/sirupsen/logrus"
)

// Collector manages and provides container resource stats
type Collector struct {
	m          sync.Mutex
	cond       *sync.Cond
	supervisor supervisor
	interval   time.Duration
	publishers map[*container.Container]*pubsub.Publisher
	bufReader  *bufio.Reader

	// The following fields are not set on Windows currently.
	clockTicksPerSecond uint64
}

// NewCollector creates a stats collector that will poll the supervisor with the specified interval
func NewCollector(supervisor supervisor, interval time.Duration) *Collector {
	s := &Collector{
		interval:   interval,
		supervisor: supervisor,
		publishers: make(map[*container.Container]*pubsub.Publisher),
		bufReader:  bufio.NewReaderSize(nil, 128),
	}
	s.cond = sync.NewCond(&s.m)

	platformNewStatsCollector(s)

	return s
}

type supervisor interface {
	// GetContainerStats collects all the stats related to a container
	GetContainerStats(container *container.Container) (*types.StatsJSON, error)
}

// Collect registers the container with the collector and adds it to
// the event loop for collection on the specified interval returning
// a channel for the subscriber to receive on.
func (s *Collector) Collect(c *container.Container) chan interface{} {
	s.cond.L.Lock()
	defer s.cond.L.Unlock()

	publisher, exists := s.publishers[c]
	if !exists {
		publisher = pubsub.NewPublisher(100*time.Millisecond, 1024)
		s.publishers[c] = publisher
	}

	s.cond.Broadcast()
	return publisher.Subscribe()
}

// StopCollection closes the channels for all subscribers and removes
// the container from metrics collection.
func (s *Collector) StopCollection(c *container.Container) {
	s.m.Lock()
	if publisher, exists := s.publishers[c]; exists {
		publisher.Close()
		delete(s.publishers, c)
	}
	s.m.Unlock()
}

// Unsubscribe removes a specific subscriber from receiving updates for a container's stats.
func (s *Collector) Unsubscribe(c *container.Container, ch chan interface{}) {
	s.m.Lock()
	publisher := s.publishers[c]
	if publisher != nil {
		publisher.Evict(ch)
		if publisher.Len() == 0 {
			delete(s.publishers, c)
		}
	}
	s.m.Unlock()
}

// Run starts the collectors and will indefinitely collect stats from the supervisor
func (s *Collector) Run() {
	type publishersPair struct {
		container *container.Container
		publisher *pubsub.Publisher
	}
	// we cannot determine the capacity here.
	// it will grow enough in first iteration
	var pairs []publishersPair

	for {
		s.cond.L.Lock()
		for len(s.publishers) == 0 {
			s.cond.Wait()
		}

		// it does not make sense in the first iteration,
		// but saves allocations in further iterations
		pairs = pairs[:0]

		for container, publisher := range s.publishers {
			// copy pointers here to release the lock ASAP
			pairs = append(pairs, publishersPair{container, publisher})
		}

		s.cond.L.Unlock()

		onlineCPUs, err := s.getNumberOnlineCPUs()
		if err != nil {
			logrus.Errorf("collecting system online cpu count: %v", err)
			continue
		}

		for _, pair := range pairs {
			stats, err := s.supervisor.GetContainerStats(pair.container)

			switch err.(type) {
			case nil:
				// Sample system CPU usage close to container usage to avoid
				// noise in metric calculations.
				systemUsage, err := s.getSystemCPUUsage()
				if err != nil {
					logrus.WithError(err).WithField("container_id", pair.container.ID).Errorf("collecting system cpu usage")
					continue
				}

				// FIXME: move to containerd on Linux (not Windows)
				stats.CPUStats.SystemUsage = systemUsage
				stats.CPUStats.OnlineCPUs = onlineCPUs

				pair.publisher.Publish(*stats)

			case notRunningErr, notFoundErr:
				// publish empty stats containing only name and ID if not running or not found
				pair.publisher.Publish(types.StatsJSON{
					Name: pair.container.Name,
					ID:   pair.container.ID,
				})

			default:
				logrus.Errorf("collecting stats for %s: %v", pair.container.ID, err)
				pair.publisher.Publish(types.StatsJSON{
					Name: pair.container.Name,
					ID:   pair.container.ID,
				})
			}
		}

		time.Sleep(s.interval)
	}
}

type notRunningErr interface {
	error
	Conflict()
}

type notFoundErr interface {
	error
	NotFound()
}
<|endoftext|>


<commit_before>// Same copyright and license as the rest of the files in this project

//GVariant : GVariant — strongly typed value datatype
// https://developer.gnome.org/glib/2.26/glib-GVariant.html
package glib

// #cgo pkg-config: glib-2.0 gobject-2.0
// #include <glib.h>
// #include <glib-object.h>
// #include "glib.go.h"
import "C"
import "unsafe"

/*
 * GVariantClass
 */

type VariantClass int

const (
	VARIANT_CLASS_BOOLEAN     VariantClass = C.G_VARIANT_CLASS_BOOLEAN     //The GVariant is a boolean.
	VARIANT_CLASS_BYTE        VariantClass = C.G_VARIANT_CLASS_BYTE        //The GVariant is a byte.
	VARIANT_CLASS_INT16       VariantClass = C.G_VARIANT_CLASS_INT16       //The GVariant is a signed 16 bit integer.
	VARIANT_CLASS_UINT16      VariantClass = C.G_VARIANT_CLASS_UINT16      //The GVariant is an unsigned 16 bit integer.
	VARIANT_CLASS_INT32       VariantClass = C.G_VARIANT_CLASS_INT32       //The GVariant is a signed 32 bit integer.
	VARIANT_CLASS_UINT32      VariantClass = C.G_VARIANT_CLASS_UINT32      //The GVariant is an unsigned 32 bit integer.
	VARIANT_CLASS_INT64       VariantClass = C.G_VARIANT_CLASS_INT64       //The GVariant is a signed 64 bit integer.
	VARIANT_CLASS_UINT64      VariantClass = C.G_VARIANT_CLASS_UINT64      //The GVariant is an unsigned 64 bit integer.
	VARIANT_CLASS_HANDLE      VariantClass = C.G_VARIANT_CLASS_HANDLE      //The GVariant is a file handle index.
	VARIANT_CLASS_DOUBLE      VariantClass = C.G_VARIANT_CLASS_DOUBLE      //The GVariant is a double precision floating point value.
	VARIANT_CLASS_STRING      VariantClass = C.G_VARIANT_CLASS_STRING      //The GVariant is a normal string.
	VARIANT_CLASS_OBJECT_PATH VariantClass = C.G_VARIANT_CLASS_OBJECT_PATH //The GVariant is a D-Bus object path string.
	VARIANT_CLASS_SIGNATURE   VariantClass = C.G_VARIANT_CLASS_SIGNATURE   //The GVariant is a D-Bus signature string.
	VARIANT_CLASS_VARIANT     VariantClass = C.G_VARIANT_CLASS_VARIANT     //The GVariant is a variant.
	VARIANT_CLASS_MAYBE       VariantClass = C.G_VARIANT_CLASS_MAYBE       //The GVariant is a maybe-typed value.
	VARIANT_CLASS_ARRAY       VariantClass = C.G_VARIANT_CLASS_ARRAY       //The GVariant is an array.
	VARIANT_CLASS_TUPLE       VariantClass = C.G_VARIANT_CLASS_TUPLE       //The GVariant is a tuple.
	VARIANT_CLASS_DICT_ENTRY  VariantClass = C.G_VARIANT_CLASS_DICT_ENTRY  //The GVariant is a dictionary entry.
)
<commit_msg>remove unused reference<commit_after>// Same copyright and license as the rest of the files in this project

//GVariant : GVariant — strongly typed value datatype
// https://developer.gnome.org/glib/2.26/glib-GVariant.html
package glib

// #cgo pkg-config: glib-2.0 gobject-2.0
// #include <glib.h>
// #include <glib-object.h>
// #include "glib.go.h"
import "C"

/*
 * GVariantClass
 */

type VariantClass int

const (
	VARIANT_CLASS_BOOLEAN     VariantClass = C.G_VARIANT_CLASS_BOOLEAN     //The GVariant is a boolean.
	VARIANT_CLASS_BYTE        VariantClass = C.G_VARIANT_CLASS_BYTE        //The GVariant is a byte.
	VARIANT_CLASS_INT16       VariantClass = C.G_VARIANT_CLASS_INT16       //The GVariant is a signed 16 bit integer.
	VARIANT_CLASS_UINT16      VariantClass = C.G_VARIANT_CLASS_UINT16      //The GVariant is an unsigned 16 bit integer.
	VARIANT_CLASS_INT32       VariantClass = C.G_VARIANT_CLASS_INT32       //The GVariant is a signed 32 bit integer.
	VARIANT_CLASS_UINT32      VariantClass = C.G_VARIANT_CLASS_UINT32      //The GVariant is an unsigned 32 bit integer.
	VARIANT_CLASS_INT64       VariantClass = C.G_VARIANT_CLASS_INT64       //The GVariant is a signed 64 bit integer.
	VARIANT_CLASS_UINT64      VariantClass = C.G_VARIANT_CLASS_UINT64      //The GVariant is an unsigned 64 bit integer.
	VARIANT_CLASS_HANDLE      VariantClass = C.G_VARIANT_CLASS_HANDLE      //The GVariant is a file handle index.
	VARIANT_CLASS_DOUBLE      VariantClass = C.G_VARIANT_CLASS_DOUBLE      //The GVariant is a double precision floating point value.
	VARIANT_CLASS_STRING      VariantClass = C.G_VARIANT_CLASS_STRING      //The GVariant is a normal string.
	VARIANT_CLASS_OBJECT_PATH VariantClass = C.G_VARIANT_CLASS_OBJECT_PATH //The GVariant is a D-Bus object path string.
	VARIANT_CLASS_SIGNATURE   VariantClass = C.G_VARIANT_CLASS_SIGNATURE   //The GVariant is a D-Bus signature string.
	VARIANT_CLASS_VARIANT     VariantClass = C.G_VARIANT_CLASS_VARIANT     //The GVariant is a variant.
	VARIANT_CLASS_MAYBE       VariantClass = C.G_VARIANT_CLASS_MAYBE       //The GVariant is a maybe-typed value.
	VARIANT_CLASS_ARRAY       VariantClass = C.G_VARIANT_CLASS_ARRAY       //The GVariant is an array.
	VARIANT_CLASS_TUPLE       VariantClass = C.G_VARIANT_CLASS_TUPLE       //The GVariant is a tuple.
	VARIANT_CLASS_DICT_ENTRY  VariantClass = C.G_VARIANT_CLASS_DICT_ENTRY  //The GVariant is a dictionary entry.
)
<|endoftext|>


<commit_before>package koding

import (
	"time"
)

type Instance struct {
	CPU int
	Mem int
}

type InstanceType int

const (
	T2Micro InstanceType = iota + 1
	T2Small
	T2Medium
)

var instances = map[string]InstanceType{
	"t2.micro":  T2Micro,
	"t2.small":  T2Small,
	"t2.medium": T2Medium,
}

func (i InstanceType) String() string {
	switch i {
	case T2Micro:
		return "t2.micro"
	case T2Small:
		return "t2.small"
	case T2Medium:
		return "t2.medium"
	default:
		return "UnknownInstance"
	}
}

// http://aws.amazon.com/ec2/instance-types/
// Model		vCPU	Mem (GiB)
// t2.micro		1		1
// t2.small		1		2
// t2.medium	2		4
func (i InstanceType) Instance() Instance {
	switch i {
	case T2Micro:
		return Instance{CPU: 1, Mem: 1}
	case T2Small:
		return Instance{CPU: 1, Mem: 2}
	case T2Medium:
		return Instance{CPU: 2, Mem: 4}
	}

	return Instance{}
}

// Limits defines several independent limits that are applied to a Plan.
type Limits struct {
	// Total defines the total limit of machines a a plan can have
	Total int

	// AlwaysOn defines the total limit of machines that can be always on.
	// These machines are not subject to the Timeout mechanism and are never
	// shut down
	AlwaysOn int

	// Storage defines the total storage a plan can have. A user might split
	// this storage into three instances if the Total limit is three. An example:
	// User has a 25GB storage plan and a Total limit of 3 machines. He/she can use:
	// 10GB for the first machine
	// 10GB for the second machine
	// 5GB for the third machine
	Storage int

	// Timeout defines the timeout in which a machine is shutdown after an
	// inactivity. AlwaysOn vm's are not subject to this limitation
	Timeout time.Duration

	// AllowedInstances defines the instance types a plan can have when building a
	// machine.
	AllowedInstances map[InstanceType]struct{}
}

// Plan defines a single koding plan. All plans have:
// 1. 60 min timeout for non-always on vms
// 2. only t2.micro's as vm type
type Plan int

const (
	// Free: 1 VM, 0 Always On, 3GB total storage
	Free Plan = iota + 1

	// Hobbyist: 1 VM, 1 Always On, 10GB total storage
	Hobbyist

	// Developer: 3 VMs, 1 Always On,  25GB total storage
	Developer

	// Professional: 5 VMs, 2 Always On, 50GB total Storage
	Professional

	// Super: 10 VMs, 5 Always On, 100GB total Storage
	Super

	// Koding: 100 VMs, 100 Always On, 1000GB total Storage
	// Internal use only
	Koding

	// Betatester: 1 VM, 1 Always On, 3GB total storage
	Betatester Plan = iota + 1
)

var plans = map[string]Plan{
	"free":         Free,
	"hobbyist":     Hobbyist,
	"developer":    Developer,
	"professional": Professional,
	"super":        Super,
	"koding":       Koding,
	"betatester":   Betatester,
}

var planLimits = map[Plan]Limits{
	Free: {
		Total:    1,
		AlwaysOn: 0,
		Storage:  3,
		Timeout:  60 * time.Minute,
		AllowedInstances: map[InstanceType]struct{}{
			T2Micro: {},
		},
	},
	Hobbyist: {
		Total:    1,
		AlwaysOn: 1,
		Storage:  10,
		Timeout:  60 * time.Minute,
		AllowedInstances: map[InstanceType]struct{}{
			T2Micro: {},
		},
	},
	Developer: {
		Total:    3,
		AlwaysOn: 1,
		Storage:  25,
		Timeout:  60 * time.Minute,
		AllowedInstances: map[InstanceType]struct{}{
			T2Micro: {},
		},
	},
	Professional: {
		Total:    5,
		AlwaysOn: 2,
		Storage:  50,
		Timeout:  60 * time.Minute,
		AllowedInstances: map[InstanceType]struct{}{
			T2Micro: {},
		},
	},
	Super: {
		Total:    10,
		AlwaysOn: 5,
		Storage:  100,
		Timeout:  60 * time.Minute,
		AllowedInstances: map[InstanceType]struct{}{
			T2Micro: {},
		},
	},
	Koding: {
		Total:    100,
		AlwaysOn: 100,
		Storage:  1000,
		Timeout:  60 * time.Minute,
		AllowedInstances: map[InstanceType]struct{}{
			T2Micro: {}, T2Small: {}, T2Medium: {},
		},
	},
	Betatester: {
		Total:    1,
		AlwaysOn: 1,
		Storage:  3,
		Timeout:  60 * time.Minute,
		AllowedInstances: map[InstanceType]struct{}{
			T2Micro: {},
		},
	},
}

func (p Plan) Limits() Limits {
	return planLimits[p]
}

func (p Plan) String() string {
	switch p {
	case Free:
		return "Free"
	case Hobbyist:
		return "Hobbyist"
	case Developer:
		return "Developer"
	case Professional:
		return "Professional"
	case Super:
		return "Super"
	case Koding:
		return "Koding"
	case Betatester:
		return "Betatester"
	default:
		return "Unknown"
	}
}
<commit_msg>payment: minor fix<commit_after>package koding

import (
	"time"
)

type Instance struct {
	CPU int
	Mem int
}

type InstanceType int

const (
	T2Micro InstanceType = iota + 1
	T2Small
	T2Medium
)

var instances = map[string]InstanceType{
	"t2.micro":  T2Micro,
	"t2.small":  T2Small,
	"t2.medium": T2Medium,
}

func (i InstanceType) String() string {
	switch i {
	case T2Micro:
		return "t2.micro"
	case T2Small:
		return "t2.small"
	case T2Medium:
		return "t2.medium"
	default:
		return "UnknownInstance"
	}
}

// http://aws.amazon.com/ec2/instance-types/
// Model		vCPU	Mem (GiB)
// t2.micro		1		1
// t2.small		1		2
// t2.medium	2		4
func (i InstanceType) Instance() Instance {
	switch i {
	case T2Micro:
		return Instance{CPU: 1, Mem: 1}
	case T2Small:
		return Instance{CPU: 1, Mem: 2}
	case T2Medium:
		return Instance{CPU: 2, Mem: 4}
	}

	return Instance{}
}

// Limits defines several independent limits that are applied to a Plan.
type Limits struct {
	// Total defines the total limit of machines a a plan can have
	Total int

	// AlwaysOn defines the total limit of machines that can be always on.
	// These machines are not subject to the Timeout mechanism and are never
	// shut down
	AlwaysOn int

	// Storage defines the total storage a plan can have. A user might split
	// this storage into three instances if the Total limit is three. An example:
	// User has a 25GB storage plan and a Total limit of 3 machines. He/she can use:
	// 10GB for the first machine
	// 10GB for the second machine
	// 5GB for the third machine
	Storage int

	// Timeout defines the timeout in which a machine is shutdown after an
	// inactivity. AlwaysOn vm's are not subject to this limitation
	Timeout time.Duration

	// AllowedInstances defines the instance types a plan can have when building a
	// machine.
	AllowedInstances map[InstanceType]struct{}
}

// Plan defines a single koding plan. All plans have:
// 1. 60 min timeout for non-always on vms
// 2. only t2.micro's as vm type
type Plan int

const (
	// Free: 1 VM, 0 Always On, 3GB total storage
	Free Plan = iota + 1

	// Hobbyist: 1 VM, 1 Always On, 10GB total storage
	Hobbyist

	// Developer: 3 VMs, 1 Always On,  25GB total storage
	Developer

	// Professional: 5 VMs, 2 Always On, 50GB total Storage
	Professional

	// Super: 10 VMs, 5 Always On, 100GB total Storage
	Super

	// Koding: 100 VMs, 100 Always On, 1000GB total Storage
	// Internal use only
	Koding

	// Betatester: 1 VM, 1 Always On, 3GB total storage
	Betatester
)

var plans = map[string]Plan{
	"free":         Free,
	"hobbyist":     Hobbyist,
	"developer":    Developer,
	"professional": Professional,
	"super":        Super,
	"koding":       Koding,
	"betatester":   Betatester,
}

var planLimits = map[Plan]Limits{
	Free: {
		Total:    1,
		AlwaysOn: 0,
		Storage:  3,
		Timeout:  60 * time.Minute,
		AllowedInstances: map[InstanceType]struct{}{
			T2Micro: {},
		},
	},
	Hobbyist: {
		Total:    1,
		AlwaysOn: 1,
		Storage:  10,
		Timeout:  60 * time.Minute,
		AllowedInstances: map[InstanceType]struct{}{
			T2Micro: {},
		},
	},
	Developer: {
		Total:    3,
		AlwaysOn: 1,
		Storage:  25,
		Timeout:  60 * time.Minute,
		AllowedInstances: map[InstanceType]struct{}{
			T2Micro: {},
		},
	},
	Professional: {
		Total:    5,
		AlwaysOn: 2,
		Storage:  50,
		Timeout:  60 * time.Minute,
		AllowedInstances: map[InstanceType]struct{}{
			T2Micro: {},
		},
	},
	Super: {
		Total:    10,
		AlwaysOn: 5,
		Storage:  100,
		Timeout:  60 * time.Minute,
		AllowedInstances: map[InstanceType]struct{}{
			T2Micro: {},
		},
	},
	Koding: {
		Total:    100,
		AlwaysOn: 100,
		Storage:  1000,
		Timeout:  60 * time.Minute,
		AllowedInstances: map[InstanceType]struct{}{
			T2Micro: {}, T2Small: {}, T2Medium: {},
		},
	},
	Betatester: {
		Total:    1,
		AlwaysOn: 1,
		Storage:  3,
		Timeout:  60 * time.Minute,
		AllowedInstances: map[InstanceType]struct{}{
			T2Micro: {},
		},
	},
}

func (p Plan) Limits() Limits {
	return planLimits[p]
}

func (p Plan) String() string {
	switch p {
	case Free:
		return "Free"
	case Hobbyist:
		return "Hobbyist"
	case Developer:
		return "Developer"
	case Professional:
		return "Professional"
	case Super:
		return "Super"
	case Koding:
		return "Koding"
	case Betatester:
		return "Betatester"
	default:
		return "Unknown"
	}
}
<|endoftext|>