<commit_before>package towerfall

import (
	"fmt"
	"log"
	"math/rand"
	"sort"

	"github.com/deckarep/golang-set"
)

// AllColors is a list of the available player colors
var AllColors = []interface{}{
	"green",
	"blue",
	"pink",
	"orange",
	"white",
	"yellow",
	"cyan",
	"purple",
	"red",
}

// Colors is the definitive set of all the colors
var Colors = mapset.NewSetFromSlice(AllColors)

const scoreMultiplier = 7
const scoreSweep = (97 * scoreMultiplier)
const scoreKill = (21 * scoreMultiplier)
const scoreSelf = (-35 * scoreMultiplier) // Negative 1.66 times of a kill
const scoreWinner = (350 * scoreMultiplier)
const scoreSecond = (150 * scoreMultiplier)
const scoreThird = (70 * scoreMultiplier)
const scoreFourth = (30 * scoreMultiplier)
const finalMultiplier = 2.5

// ScoreData is a structured Key/Value pair list for scores
type ScoreData struct {
	Key    string
	Value  int
	Player *Player
}

// Player is a representation of one player in a match
type Player struct {
	ID             uint `json:"id"`
	MatchID        uint
	PersonID       string      `sql:",pk"`
	Person         *Person     `json:"person" sql:"-"`
	Color          string      `json:"color"`
	PreferredColor string      `json:"preferred_color"`
	ArcherType     int         `json:"archer_type"`
	Shots          int         `json:"shots"`
	Sweeps         int         `json:"sweeps"`
	Kills          int         `json:"kills"`
	Self           int         `json:"self"`
	MatchScore     int         `json:"match_score"`
	TotalScore     int         `json:"total_score"`
	State          PlayerState `json:"state" sql:"-"`
	Match          *Match      `json:"-" sql:"-"`
	DisplayNames   []string    `sql:",array"`
}

// A PlayerSummary is a tournament-wide summary of the scores a player has
type PlayerSummary struct {
	ID uint `json:"id"`

	TournamentID uint
	PersonID     string  `json:"person_id"`
	Person       *Person `json:"person" sql:"-"`
	Shots        int     `json:"shots"`
	Sweeps       int     `json:"sweeps"`
	Kills        int     `json:"kills"`
	Self         int     `json:"self"`
	Matches      int     `json:"matches"`
	TotalScore   int     `json:"score"`
	SkillScore   int     `json:"skill_score"`
}

type PlayerState struct {
	Arrows    Arrows `json:"arrows"`
	Shield    bool   `json:"shield"`
	Wings     bool   `json:"wings"`
	Hat       bool   `json:"hat"`
	Invisible bool   `json:"invisible"`
	Speed     bool   `json:"speed"`
	Alive     bool   `json:"alive"`
	Lava      bool   `json:"lava"`
	Killer    int    `json:"killer"`
}

// NewPlayer returns a new instance of a player
func NewPlayer(ps *Person) *Player {
	p := &Player{
		PersonID:   ps.PersonID,
		Person:     ps,
		ArcherType: ps.ArcherType,
		State:      NewPlayerState(),
	}
	if len(ps.ColorPreference) > 0 {
		p.PreferredColor = ps.PreferredColor
	} else {
		p.PreferredColor = RandomColor(Colors)
	}

	return p
}

func NewPlayerState() PlayerState {
	ps := PlayerState{
		Arrows: make(Arrows, 0),
		Alive:  true,
		Hat:    true,
		Killer: -2,
	}
	return ps
}

// NewPlayerSummary returns a new instance of a tournament player
func NewPlayerSummary(ps *Person) *PlayerSummary {
	p := &PlayerSummary{
		PersonID: ps.PersonID,
		Person:   ps,
	}
	return p
}

func (p *Player) String() string {
	return fmt.Sprintf(
		"<(%d) %s: %dsh %dsw %dk %ds>",
		p.ID,
		p.Name(),
		p.Shots,
		p.Sweeps,
		p.Kills,
		p.Self,
	)
}

// Name returns the nickname
func (p *Player) Name() string {
	return p.Person.Nick
}

// NumericColor is the numeric representation of the color the player has
func (p *Player) NumericColor() int {
	for x, c := range AllColors {
		if p.Color == c {
			return x
		}
	}

	// No color was found - this is a bug. Return default.
	log.Printf("Player '%s' did not match a color for '%s'", p.Name(), p.Color)
	return 0
}

// Score calculates the score to determine runnerup positions.
func (p *PlayerSummary) Score() (out int) {
	out += p.Sweeps * scoreSweep
	out += p.Kills * scoreKill
	out += p.Self * scoreSelf

	// Negative score is not allowed
	if out <= 0 {
		out = 0
	}

	return
}

// Score calculates the score to determine runnerup positions.
func (p *Player) Score() (out int) {
	out += p.Sweeps * scoreSweep
	out += p.Kills * scoreKill
	out += p.Self * scoreSelf

	// Negative score is not allowed
	if out <= 0 {
		out = 0
	}

	// Match score is added afterwards so that no one is stuck on 0.
	out += p.MatchScore

	return
}

// Summary resturns a Summary{} object for the player
func (p *Player) Summary() PlayerSummary {
	return PlayerSummary{
		PersonID: p.PersonID,
		Person:   p.Person,
		Shots:    p.Shots,
		Sweeps:   p.Sweeps,
		Kills:    p.Kills,
		Self:     p.Self,
	}
}

// Player resturns a Player{} object from the summary
func (p *PlayerSummary) Player() Player {
	return *NewPlayer(p.Person)
}

// ScoreData returns this players set of ScoreData
func (p *Player) ScoreData() []ScoreData {
	sd := []ScoreData{
		{Key: "kills", Value: p.Kills, Player: p},
		{Key: "shots", Value: p.Shots, Player: p},
		{Key: "sweeps", Value: p.Sweeps, Player: p},
		{Key: "self", Value: p.Self, Player: p},
	}
	return sd
}

// URL returns the URL to this player
//
// Used for action URLs
func (p *Player) URL() string {
	out := fmt.Sprintf(
		"%s/%d",
		p.Match.URL(),
		p.Index(),
	)
	return out
}

// Classes returns the CSS color classes for the player
func (p *Player) Classes() string {
	if p.Match != nil && p.Match.IsEnded() {
		ps := ByScore(p.Match.Players)
		if ps[0].Name() == p.Name() {
			// Always gold for the winner
			return "gold"
		} else if ps[1].Name() == p.Name() {
			// Silver for the second, unless there is a short amount of playoffs
			if p.Match.Kind != playoff || len(p.Match.Tournament.Matches)-3 <= 4 {
				return "silver"
			}
		} else if ps[2].Name() == p.Name() && p.Match.Kind == final {
			return "bronze"
		}

		return "out"
	}
	return p.PreferredColor
}

// Index returns the index in the current match
func (p *Player) Index() int {
	if p.Match != nil {
		for i, o := range p.Match.Players {
			if p.Name() == o.Name() {
				return i
			}
		}
	}
	return -1
}

// AddShot increases the shot count
func (p *Player) AddShot() {
	log.Printf("Adding shot to %s", p.Name())
	p.Shots++
}

// RemoveShot decreases the shot count
// Fails silently if shots are zero.
func (p *Player) RemoveShot() {

	if p.Shots == 0 {
		log.Printf("Not removing shot from %s; already at zero", p.Name())
		return
	}
	log.Printf("Removing shot from %s", p.Name())
	p.Shots--
}

// AddSweep increases the sweep count
func (p *Player) AddSweep() {
	log.Printf("Adding sweep to %s", p.Name())
	p.Sweeps++
}

// AddKills increases the kill count and adds a sweep if necessary
func (p *Player) AddKills(kills int) {
	log.Printf("Adding %d kills to %s", kills, p.Name())
	p.Kills += kills
	if kills == 3 {
		p.AddSweep()
	}
}

// RemoveKill decreases the kill count
// Fails silently if kills are zero.
func (p *Player) RemoveKill() {
	if p.Kills == 0 {
		log.Printf("Not removing kill from %s; already at zero", p.Name())
		return
	}
	log.Printf("Removing kill from %s", p.Name())
	p.Kills--
}

// AddSelf increases the self count and decreases the kill
func (p *Player) AddSelf() {
	log.Printf("Adding self to %s", p.Name())
	p.Self++
	p.RemoveKill()
}

// Reset resets the stats on a PlayerSummary to 0
//
// It is to be run in Match.Start()
func (p *Player) Reset() {
	p.Shots = 0
	p.Sweeps = 0
	p.Kills = 0
	p.Self = 0
	p.State = NewPlayerState()
}

// HTML renders the HTML of a player
func (p *Player) HTML() (out string) {
	return
}

// ByColorConflict is a sort.Interface that sorts players by their score
type ByColorConflict []PlayerSummary

func (s ByColorConflict) Len() int { return len(s) }

func (s ByColorConflict) Swap(i, j int) { s[i], s[j] = s[j], s[i] }

func (s ByColorConflict) Less(i, j int) bool {
	if s[i].Person.Userlevel != s[j].Person.Userlevel {
		return s[i].Person.Userlevel > s[j].Person.Userlevel
	}
	return s[i].TotalScore > s[j].TotalScore
}

// ByScore is a sort.Interface that sorts players by their score
type ByScore []Player

func (s ByScore) Len() int {
	return len(s)

}
func (s ByScore) Swap(i, j int) {
	s[i], s[j] = s[j], s[i]

}
func (s ByScore) Less(i, j int) bool {
	// Technically not Less, but we want biggest first...
	return s[i].Score() > s[j].Score()
}

// SortByColorConflicts returns a list in an unspecified order,
// Probably by User level and then score.
func SortByColorConflicts(m *Match, ps []Person) (tmp []PlayerSummary, err error) {
	var tp *PlayerSummary
	tmp = make([]PlayerSummary, len(ps))
	for i, p := range ps {
		// TODO(thiderman): This is not very elegant and should be replaced.
		tp, err = m.Tournament.getTournamentPlayerObject(&p)
		if err != nil {
			return
		}
		tmp[i] = *tp
	}
	sort.Sort(ByColorConflict(tmp))
	return
}

// ByKills is a sort.Interface that sorts players by their kills
type ByKills []Player

func (s ByKills) Len() int {
	return len(s)

}
func (s ByKills) Swap(i, j int) {
	s[i], s[j] = s[j], s[i]

}
func (s ByKills) Less(i, j int) bool {
	// Technically not Less, but we want biggest first...
	iKills := s[i].Kills
	jKills := s[j].Kills
	if iKills == jKills {
		return s[i].Score() > s[j].Score()
	}
	return iKills > jKills
}

// SortByKills returns a list in order of the kills the players have
func SortByKills(ps []Player) []Player {
	tmp := make([]Player, len(ps))
	copy(tmp, ps)
	sort.Sort(ByKills(tmp))
	return tmp
}

// ByRunnerup is a sort.Interface that sorts players by their runnerup status
//
// This is almost exactly the same as score, but the number of matches a player
// has played factors in, and players that have played less matches are sorted
// favorably.
type ByRunnerup []PlayerSummary

func (s ByRunnerup) Len() int {
	return len(s)

}
func (s ByRunnerup) Swap(i, j int) {
	s[i], s[j] = s[j], s[i]

}
func (s ByRunnerup) Less(i, j int) bool {
	if s[i].Matches == s[j].Matches {
		// Same as by kills
		return s[i].Score() > s[j].Score()
	}
	// Lower is better - the ones that have not played should be at the top
	return s[i].Matches < s[j].Matches
}

// SortByRunnerup returns a list in order of the kills the players have
func SortByRunnerup(ps []PlayerSummary) []PlayerSummary {
	sort.Sort(ByRunnerup(ps))
	return ps
}

// RandomColor returns a random color from the ColorList
func RandomColor(s mapset.Set) string {
	colors := s.ToSlice()
	x := len(colors)
	return colors[rand.Intn(x)].(string)
}

// AvailableColors returns a ColorList with the colors not used in a match
func AvailableColors(m *Match) mapset.Set {
	colors := mapset.NewSetFromSlice(AllColors)
	ret := colors.Difference(m.presentColors)
	return ret
}

// Reset resets the stats on a PlayerSummary to 0
//
// It is to be run in Match.Start()
func (p *PlayerSummary) Reset() {
	p.Shots = 0
	p.Sweeps = 0
	p.Kills = 0
	p.Self = 0
	p.Matches = 0
}

// Update updates a player with the scores of another
//
// This is primarily used by the tournament score calculator
func (p *PlayerSummary) Update(other PlayerSummary) {
	p.Shots += other.Shots
	p.Sweeps += other.Sweeps
	p.Kills += other.Kills
	p.Self += other.Self
	p.TotalScore = p.Score()

	// Every call to this method is per match. Count every call
	// as if a match.
	p.Matches++
	// log.Printf("Updated player: %d, %d", p.TotalScore, p.Matches)
}
<commit_msg>Add person fallback for PlayerSummary -> Player conversion<commit_after>package towerfall

import (
	"fmt"
	"log"
	"math/rand"
	"sort"

	"github.com/deckarep/golang-set"
)

// AllColors is a list of the available player colors
var AllColors = []interface{}{
	"green",
	"blue",
	"pink",
	"orange",
	"white",
	"yellow",
	"cyan",
	"purple",
	"red",
}

// Colors is the definitive set of all the colors
var Colors = mapset.NewSetFromSlice(AllColors)

const scoreMultiplier = 7
const scoreSweep = (97 * scoreMultiplier)
const scoreKill = (21 * scoreMultiplier)
const scoreSelf = (-35 * scoreMultiplier) // Negative 1.66 times of a kill
const scoreWinner = (350 * scoreMultiplier)
const scoreSecond = (150 * scoreMultiplier)
const scoreThird = (70 * scoreMultiplier)
const scoreFourth = (30 * scoreMultiplier)
const finalMultiplier = 2.5

// ScoreData is a structured Key/Value pair list for scores
type ScoreData struct {
	Key    string
	Value  int
	Player *Player
}

// Player is a representation of one player in a match
type Player struct {
	ID             uint `json:"id"`
	MatchID        uint
	PersonID       string      `sql:",pk"`
	Person         *Person     `json:"person" sql:"-"`
	Color          string      `json:"color"`
	PreferredColor string      `json:"preferred_color"`
	ArcherType     int         `json:"archer_type"`
	Shots          int         `json:"shots"`
	Sweeps         int         `json:"sweeps"`
	Kills          int         `json:"kills"`
	Self           int         `json:"self"`
	MatchScore     int         `json:"match_score"`
	TotalScore     int         `json:"total_score"`
	State          PlayerState `json:"state" sql:"-"`
	Match          *Match      `json:"-" sql:"-"`
	DisplayNames   []string    `sql:",array"`
}

// A PlayerSummary is a tournament-wide summary of the scores a player has
type PlayerSummary struct {
	ID uint `json:"id"`

	TournamentID uint
	PersonID     string  `json:"person_id"`
	Person       *Person `json:"person" sql:"-"`
	Shots        int     `json:"shots"`
	Sweeps       int     `json:"sweeps"`
	Kills        int     `json:"kills"`
	Self         int     `json:"self"`
	Matches      int     `json:"matches"`
	TotalScore   int     `json:"score"`
	SkillScore   int     `json:"skill_score"`
}

type PlayerState struct {
	Arrows    Arrows `json:"arrows"`
	Shield    bool   `json:"shield"`
	Wings     bool   `json:"wings"`
	Hat       bool   `json:"hat"`
	Invisible bool   `json:"invisible"`
	Speed     bool   `json:"speed"`
	Alive     bool   `json:"alive"`
	Lava      bool   `json:"lava"`
	Killer    int    `json:"killer"`
}

// NewPlayer returns a new instance of a player
func NewPlayer(ps *Person) *Player {
	p := &Player{
		PersonID:   ps.PersonID,
		Person:     ps,
		ArcherType: ps.ArcherType,
		State:      NewPlayerState(),
	}
	if len(ps.ColorPreference) > 0 {
		p.PreferredColor = ps.PreferredColor
	} else {
		p.PreferredColor = RandomColor(Colors)
	}

	return p
}

func NewPlayerState() PlayerState {
	ps := PlayerState{
		Arrows: make(Arrows, 0),
		Alive:  true,
		Hat:    true,
		Killer: -2,
	}
	return ps
}

// NewPlayerSummary returns a new instance of a tournament player
func NewPlayerSummary(ps *Person) *PlayerSummary {
	p := &PlayerSummary{
		PersonID: ps.PersonID,
		Person:   ps,
	}
	return p
}

func (p *Player) String() string {
	return fmt.Sprintf(
		"<(%d) %s: %dsh %dsw %dk %ds>",
		p.ID,
		p.Name(),
		p.Shots,
		p.Sweeps,
		p.Kills,
		p.Self,
	)
}

// Name returns the nickname
func (p *Player) Name() string {
	return p.Person.Nick
}

// NumericColor is the numeric representation of the color the player has
func (p *Player) NumericColor() int {
	for x, c := range AllColors {
		if p.Color == c {
			return x
		}
	}

	// No color was found - this is a bug. Return default.
	log.Printf("Player '%s' did not match a color for '%s'", p.Name(), p.Color)
	return 0
}

// Score calculates the score to determine runnerup positions.
func (p *PlayerSummary) Score() (out int) {
	out += p.Sweeps * scoreSweep
	out += p.Kills * scoreKill
	out += p.Self * scoreSelf

	// Negative score is not allowed
	if out <= 0 {
		out = 0
	}

	return
}

// Score calculates the score to determine runnerup positions.
func (p *Player) Score() (out int) {
	out += p.Sweeps * scoreSweep
	out += p.Kills * scoreKill
	out += p.Self * scoreSelf

	// Negative score is not allowed
	if out <= 0 {
		out = 0
	}

	// Match score is added afterwards so that no one is stuck on 0.
	out += p.MatchScore

	return
}

// Summary resturns a Summary{} object for the player
func (p *Player) Summary() PlayerSummary {
	return PlayerSummary{
		PersonID: p.PersonID,
		Person:   p.Person,
		Shots:    p.Shots,
		Sweeps:   p.Sweeps,
		Kills:    p.Kills,
		Self:     p.Self,
	}
}

// Player returns a new Player{} object from the summary
func (p *PlayerSummary) Player() Player {
	// TODO(thiderman): It would be better to always make sure that the
	// person object is set
	if p.Person == nil {
		var err error
		p.Person, err = globalDB.GetPerson(p.PersonID)
		if err != nil {
			log.Fatal(err)
		}
	}

	return *NewPlayer(p.Person)
}

// ScoreData returns this players set of ScoreData
func (p *Player) ScoreData() []ScoreData {
	sd := []ScoreData{
		{Key: "kills", Value: p.Kills, Player: p},
		{Key: "shots", Value: p.Shots, Player: p},
		{Key: "sweeps", Value: p.Sweeps, Player: p},
		{Key: "self", Value: p.Self, Player: p},
	}
	return sd
}

// URL returns the URL to this player
//
// Used for action URLs
func (p *Player) URL() string {
	out := fmt.Sprintf(
		"%s/%d",
		p.Match.URL(),
		p.Index(),
	)
	return out
}

// Classes returns the CSS color classes for the player
func (p *Player) Classes() string {
	if p.Match != nil && p.Match.IsEnded() {
		ps := ByScore(p.Match.Players)
		if ps[0].Name() == p.Name() {
			// Always gold for the winner
			return "gold"
		} else if ps[1].Name() == p.Name() {
			// Silver for the second, unless there is a short amount of playoffs
			if p.Match.Kind != playoff || len(p.Match.Tournament.Matches)-3 <= 4 {
				return "silver"
			}
		} else if ps[2].Name() == p.Name() && p.Match.Kind == final {
			return "bronze"
		}

		return "out"
	}
	return p.PreferredColor
}

// Index returns the index in the current match
func (p *Player) Index() int {
	if p.Match != nil {
		for i, o := range p.Match.Players {
			if p.Name() == o.Name() {
				return i
			}
		}
	}
	return -1
}

// AddShot increases the shot count
func (p *Player) AddShot() {
	log.Printf("Adding shot to %s", p.Name())
	p.Shots++
}

// RemoveShot decreases the shot count
// Fails silently if shots are zero.
func (p *Player) RemoveShot() {

	if p.Shots == 0 {
		log.Printf("Not removing shot from %s; already at zero", p.Name())
		return
	}
	log.Printf("Removing shot from %s", p.Name())
	p.Shots--
}

// AddSweep increases the sweep count
func (p *Player) AddSweep() {
	log.Printf("Adding sweep to %s", p.Name())
	p.Sweeps++
}

// AddKills increases the kill count and adds a sweep if necessary
func (p *Player) AddKills(kills int) {
	log.Printf("Adding %d kills to %s", kills, p.Name())
	p.Kills += kills
	if kills == 3 {
		p.AddSweep()
	}
}

// RemoveKill decreases the kill count
// Fails silently if kills are zero.
func (p *Player) RemoveKill() {
	if p.Kills == 0 {
		log.Printf("Not removing kill from %s; already at zero", p.Name())
		return
	}
	log.Printf("Removing kill from %s", p.Name())
	p.Kills--
}

// AddSelf increases the self count and decreases the kill
func (p *Player) AddSelf() {
	log.Printf("Adding self to %s", p.Name())
	p.Self++
	p.RemoveKill()
}

// Reset resets the stats on a PlayerSummary to 0
//
// It is to be run in Match.Start()
func (p *Player) Reset() {
	p.Shots = 0
	p.Sweeps = 0
	p.Kills = 0
	p.Self = 0
	p.State = NewPlayerState()
}

// HTML renders the HTML of a player
func (p *Player) HTML() (out string) {
	return
}

// ByColorConflict is a sort.Interface that sorts players by their score
type ByColorConflict []PlayerSummary

func (s ByColorConflict) Len() int { return len(s) }

func (s ByColorConflict) Swap(i, j int) { s[i], s[j] = s[j], s[i] }

func (s ByColorConflict) Less(i, j int) bool {
	if s[i].Person.Userlevel != s[j].Person.Userlevel {
		return s[i].Person.Userlevel > s[j].Person.Userlevel
	}
	return s[i].TotalScore > s[j].TotalScore
}

// ByScore is a sort.Interface that sorts players by their score
type ByScore []Player

func (s ByScore) Len() int {
	return len(s)

}
func (s ByScore) Swap(i, j int) {
	s[i], s[j] = s[j], s[i]

}
func (s ByScore) Less(i, j int) bool {
	// Technically not Less, but we want biggest first...
	return s[i].Score() > s[j].Score()
}

// SortByColorConflicts returns a list in an unspecified order,
// Probably by User level and then score.
func SortByColorConflicts(m *Match, ps []Person) (tmp []PlayerSummary, err error) {
	var tp *PlayerSummary
	tmp = make([]PlayerSummary, len(ps))
	for i, p := range ps {
		// TODO(thiderman): This is not very elegant and should be replaced.
		tp, err = m.Tournament.getTournamentPlayerObject(&p)
		if err != nil {
			return
		}
		tmp[i] = *tp
	}
	sort.Sort(ByColorConflict(tmp))
	return
}

// ByKills is a sort.Interface that sorts players by their kills
type ByKills []Player

func (s ByKills) Len() int {
	return len(s)

}
func (s ByKills) Swap(i, j int) {
	s[i], s[j] = s[j], s[i]

}
func (s ByKills) Less(i, j int) bool {
	// Technically not Less, but we want biggest first...
	iKills := s[i].Kills
	jKills := s[j].Kills
	if iKills == jKills {
		return s[i].Score() > s[j].Score()
	}
	return iKills > jKills
}

// SortByKills returns a list in order of the kills the players have
func SortByKills(ps []Player) []Player {
	tmp := make([]Player, len(ps))
	copy(tmp, ps)
	sort.Sort(ByKills(tmp))
	return tmp
}

// ByRunnerup is a sort.Interface that sorts players by their runnerup status
//
// This is almost exactly the same as score, but the number of matches a player
// has played factors in, and players that have played less matches are sorted
// favorably.
type ByRunnerup []PlayerSummary

func (s ByRunnerup) Len() int {
	return len(s)

}
func (s ByRunnerup) Swap(i, j int) {
	s[i], s[j] = s[j], s[i]

}
func (s ByRunnerup) Less(i, j int) bool {
	if s[i].Matches == s[j].Matches {
		// Higher is better - if you have a high score you'll play again
		return s[i].Score() > s[j].Score()
	}
	// Lower is better - the ones that have not played should be at the top
	return s[i].Matches < s[j].Matches
}

// SortByRunnerup returns a list in order of the kills the players have
func SortByRunnerup(ps []PlayerSummary) []PlayerSummary {
	sort.Sort(ByRunnerup(ps))
	return ps
}

// RandomColor returns a random color from the ColorList
func RandomColor(s mapset.Set) string {
	colors := s.ToSlice()
	x := len(colors)
	return colors[rand.Intn(x)].(string)
}

// AvailableColors returns a ColorList with the colors not used in a match
func AvailableColors(m *Match) mapset.Set {
	colors := mapset.NewSetFromSlice(AllColors)
	ret := colors.Difference(m.presentColors)
	return ret
}

// Reset resets the stats on a PlayerSummary to 0
//
// It is to be run in Match.Start()
func (p *PlayerSummary) Reset() {
	p.Shots = 0
	p.Sweeps = 0
	p.Kills = 0
	p.Self = 0
	p.Matches = 0
}

// Update updates a player with the scores of another
//
// This is primarily used by the tournament score calculator
func (p *PlayerSummary) Update(other PlayerSummary) {
	p.Shots += other.Shots
	p.Sweeps += other.Sweeps
	p.Kills += other.Kills
	p.Self += other.Self
	p.TotalScore = p.Score()

	// Every call to this method is per match. Count every call
	// as if a match.
	p.Matches++
	// log.Printf("Updated player: %d, %d", p.TotalScore, p.Matches)
}
<|endoftext|>


<commit_before>// Copyright 2018, OpenCensus 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.

// +build go1.11

package trace

import (
	"context"
	t "runtime/trace"
)

func startExecutionTracerTask(ctx context.Context, name string) (context.Context, func()) {
	return t.NewContext(ctx, name)
}
<commit_msg>Don't enable execution tracer tasks if tracer is not enabled (#725)<commit_after>// Copyright 2018, OpenCensus 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.

// +build go1.11

package trace

import (
	"context"
	t "runtime/trace"
)

func startExecutionTracerTask(ctx context.Context, name string) (context.Context, func()) {
	if !t.IsEnabled() {
		// Avoid additional overhead if
		// runtime/trace is not enabled.
		return ctx, func() {}
	}
	return t.NewContext(ctx, name)
}
<|endoftext|>


<commit_before>package goxlsx

import (
	"archive/zip"
	"encoding/xml"
	"errors"
	"fmt"
	"io"
	"log"
	"strconv"
	"strings"
)

type Worksheet struct {
	Name        string
	filename    string
	id          string
	rows        map[int]*row
	spreadsheet *Spreadsheet
}

type cell struct {
	Name  string
	Type  string
	Value string
}

type row struct {
	Num   int
	Cells map[int]*cell
}

type Spreadsheet struct {
	filepath        string
	compressedFiles []zip.File
	Worksheets      []*Worksheet
	sharedStrings   []string
}

func readWorkbook(d *xml.Decoder, s *Spreadsheet) []*Worksheet {
	worksheets := make([]*Worksheet, 0, 5)
	var (
		err   error
		token xml.Token
	)

	for {
		token, err = d.Token()
		if err != nil {
			if err != io.EOF {
				log.Fatal(err)
			}
			break
		}
		switch x := token.(type) {
		case xml.StartElement:
			switch x.Name.Local {
			case "sheet":
				ws := new(Worksheet)
				ws.spreadsheet = s
				for _, a := range x.Attr {
					if a.Name.Local == "name" {
						ws.Name = a.Value
					}
					if a.Name.Local == "sheetId" {
						ws.id = a.Value
					}
				}
				worksheets = append(worksheets, ws)
			}
		}
	}
	return worksheets
}

func readStrings(d *xml.Decoder, s *Spreadsheet) {
	var (
		err   error
		data  []byte
		token xml.Token
	)
	for {
		token, err = d.Token()
		if err != nil {
			if err != io.EOF {
				log.Fatal(err)
			}
			break
		}
		switch x := token.(type) {
		case xml.StartElement:
			switch x.Name.Local {
			case "sst":
				// root element
				for i := 0; i < len(x.Attr); i++ {
					if x.Attr[i].Name.Local == "uniqueCount" {
						count, err := strconv.Atoi(x.Attr[i].Value)
						if err != nil {
							log.Fatal(err)
						}
						s.sharedStrings = make([]string, 0, count)
					}
				}
			default:
				// log.Println(x.Name.Local)
			}
		case xml.CharData:
			data = x.Copy()
		case xml.EndElement:
			switch x.Name.Local {
			case "t":
				s.sharedStrings = append(s.sharedStrings, string(data))
			}
		}

	}
}

func OpenFile(path string) (*Spreadsheet, error) {
	xlsx := new(Spreadsheet)
	xlsx.filepath = path

	r, err := zip.OpenReader(path)
	if err != nil {
		return nil, err
	}
	defer r.Close()

	for _, f := range r.File {
		if f.Name == "xl/workbook.xml" {
			rc, err := f.Open()
			if err != nil {
				return nil, err
			}
			xlsx.Worksheets = readWorkbook(xml.NewDecoder(rc), xlsx)
			rc.Close()
		}
		if f.Name == "xl/sharedStrings.xml" {
			rc, err := f.Open()
			if err != nil {
				return nil, err
			}
			readStrings(xml.NewDecoder(rc), xlsx)
			rc.Close()
		}
	}
	return xlsx, nil
}

func readWorksheetXML(dec *xml.Decoder, s *Spreadsheet) (map[int]*row, error) {
	rows := make(map[int]*row)
	var (
		err         error
		token       xml.Token
		rownum      int
		currentCell *cell
		currentRow  *row
	)
	for {
		token, err = dec.Token()
		if err != nil {
			if err != io.EOF {
				return nil, err
			}
			break
		}
		switch x := token.(type) {
		case xml.StartElement:
			switch x.Name.Local {
			case "row":
				currentRow = &row{}
				currentRow.Cells = make(map[int]*cell)
				for _, a := range x.Attr {
					if a.Name.Local == "r" {
						rownum, err = strconv.Atoi(a.Value)
						if err != nil {
							return nil, err
						}
					}
				}
				currentRow.Num = rownum
				rows[rownum] = currentRow
			case "c":
				currentCell = &cell{}
				var cellnumber rune
				for _, a := range x.Attr {
					switch a.Name.Local {
					case "r":
						for _, v := range a.Value {
							if v >= 'A' && v <= 'Z' {
								cellnumber = cellnumber*26 + v - 'A' + 1
							}
						}
					case "t":
						if a.Value == "s" {
							currentCell.Type = "s"
						} else if a.Value == "n" {
							currentCell.Type = "n"
						}

					}

				}
				currentRow.Cells[int(cellnumber)] = currentCell
			}
		case xml.EndElement:
			switch x.Name.Local {
			case "c":
				currentCell = nil
			}
		case xml.CharData:
			if currentCell != nil {
				val := string(x.Copy())
				if currentCell.Type == "s" {
					valInt, _ := strconv.Atoi(val)
					currentCell.Value = s.sharedStrings[valInt]
				} else if currentCell.Type == "n" {
					currentCell.Value = strings.TrimSuffix(val, ".0")
				} else {
					currentCell.Value = val
				}
			}
		}
	}
	return rows, nil
}

func (ws *Worksheet) readWorksheetZIP() error {
	r, err := zip.OpenReader(ws.spreadsheet.filepath)
	if err != nil {
		return err
	}
	defer r.Close()

	for _, f := range r.File {
		if f.Name == ws.filename {
			rc, err := f.Open()
			if err != nil {
				return err
			}
			defer rc.Close()
			rows, err := readWorksheetXML(xml.NewDecoder(rc), ws.spreadsheet)
			ws.rows = rows
			if err != nil {
				return err
			}
		}
	}
	return nil
}

func (ws *Worksheet) Cell(row, column int) string {
	xrow := ws.rows[row]
	if xrow == nil {
		return ""
	}
	if xrow.Cells[column] == nil {
		return ""
	}
	return xrow.Cells[column].Value
}

func (s *Spreadsheet) GetWorksheet(number int) (*Worksheet, error) {
	if number >= len(s.Worksheets) || number < 0 {
		return nil, errors.New("Index out of range")
	}
	ws := s.Worksheets[number]
	ws.filename = "xl/worksheets" + "/" + fmt.Sprintf("sheet%s.xml", ws.id)
	err := ws.readWorksheetZIP()
	if err != nil {
		return nil, err
	}
	return ws, nil
}
<commit_msg>Documentation<commit_after>package goxlsx

import (
	"archive/zip"
	"encoding/xml"
	"errors"
	"fmt"
	"io"
	"log"
	"path"
	"strconv"
	"strings"
)

type Worksheet struct {
	Name        string
	filename    string
	id          string
	rows        map[int]*row
	spreadsheet *Spreadsheet
}

type cell struct {
	Name  string
	Type  string
	Value string
}

type row struct {
	Num   int
	Cells map[int]*cell
}

type Spreadsheet struct {
	filepath        string
	compressedFiles []zip.File
	worksheets      []*Worksheet
	sharedStrings   []string
}

func readWorkbook(d *xml.Decoder, s *Spreadsheet) []*Worksheet {
	worksheets := make([]*Worksheet, 0, 5)
	var (
		err   error
		token xml.Token
	)

	for {
		token, err = d.Token()
		if err != nil {
			if err != io.EOF {
				log.Fatal(err)
			}
			break
		}
		switch x := token.(type) {
		case xml.StartElement:
			switch x.Name.Local {
			case "sheet":
				ws := new(Worksheet)
				ws.spreadsheet = s
				for _, a := range x.Attr {
					if a.Name.Local == "name" {
						ws.Name = a.Value
					}
					if a.Name.Local == "sheetId" {
						ws.id = a.Value
					}
				}
				worksheets = append(worksheets, ws)
			}
		}
	}
	return worksheets
}

func readStrings(d *xml.Decoder, s *Spreadsheet) {
	var (
		err   error
		data  []byte
		token xml.Token
	)
	for {
		token, err = d.Token()
		if err != nil {
			if err != io.EOF {
				log.Fatal(err)
			}
			break
		}
		switch x := token.(type) {
		case xml.StartElement:
			switch x.Name.Local {
			case "sst":
				// root element
				for i := 0; i < len(x.Attr); i++ {
					if x.Attr[i].Name.Local == "uniqueCount" {
						count, err := strconv.Atoi(x.Attr[i].Value)
						if err != nil {
							log.Fatal(err)
						}
						s.sharedStrings = make([]string, 0, count)
					}
				}
			default:
				// log.Println(x.Name.Local)
			}
		case xml.CharData:
			data = x.Copy()
		case xml.EndElement:
			switch x.Name.Local {
			case "t":
				s.sharedStrings = append(s.sharedStrings, string(data))
			}
		}

	}
}

// Read the Excel file located at the given path.
func OpenFile(path string) (*Spreadsheet, error) {
	xlsx := new(Spreadsheet)
	xlsx.filepath = path

	r, err := zip.OpenReader(path)
	if err != nil {
		return nil, err
	}
	defer r.Close()

	for _, f := range r.File {
		if f.Name == "xl/workbook.xml" {
			rc, err := f.Open()
			if err != nil {
				return nil, err
			}
			xlsx.worksheets = readWorkbook(xml.NewDecoder(rc), xlsx)
			rc.Close()
		}
		if f.Name == "xl/sharedStrings.xml" {
			rc, err := f.Open()
			if err != nil {
				return nil, err
			}
			readStrings(xml.NewDecoder(rc), xlsx)
			rc.Close()
		}
	}
	return xlsx, nil
}

func readWorksheetXML(dec *xml.Decoder, s *Spreadsheet) (map[int]*row, error) {
	rows := make(map[int]*row)
	var (
		err         error
		token       xml.Token
		rownum      int
		currentCell *cell
		currentRow  *row
	)
	for {
		token, err = dec.Token()
		if err != nil {
			if err != io.EOF {
				return nil, err
			}
			break
		}
		switch x := token.(type) {
		case xml.StartElement:
			switch x.Name.Local {
			case "row":
				currentRow = &row{}
				currentRow.Cells = make(map[int]*cell)
				for _, a := range x.Attr {
					if a.Name.Local == "r" {
						rownum, err = strconv.Atoi(a.Value)
						if err != nil {
							return nil, err
						}
					}
				}
				currentRow.Num = rownum
				rows[rownum] = currentRow
			case "c":
				currentCell = &cell{}
				var cellnumber rune
				for _, a := range x.Attr {
					switch a.Name.Local {
					case "r":
						for _, v := range a.Value {
							if v >= 'A' && v <= 'Z' {
								cellnumber = cellnumber*26 + v - 'A' + 1
							}
						}
					case "t":
						if a.Value == "s" {
							currentCell.Type = "s"
						} else if a.Value == "n" {
							currentCell.Type = "n"
						}

					}

				}
				currentRow.Cells[int(cellnumber)] = currentCell
			}
		case xml.EndElement:
			switch x.Name.Local {
			case "c":
				currentCell = nil
			}
		case xml.CharData:
			if currentCell != nil {
				val := string(x.Copy())
				if currentCell.Type == "s" {
					valInt, _ := strconv.Atoi(val)
					currentCell.Value = s.sharedStrings[valInt]
				} else if currentCell.Type == "n" {
					currentCell.Value = strings.TrimSuffix(val, ".0")
				} else {
					currentCell.Value = val
				}
			}
		}
	}
	return rows, nil
}

func (ws *Worksheet) readWorksheetZIP() error {
	r, err := zip.OpenReader(ws.spreadsheet.filepath)
	if err != nil {
		return err
	}
	defer r.Close()

	for _, f := range r.File {
		if f.Name == ws.filename {
			rc, err := f.Open()
			if err != nil {
				return err
			}
			defer rc.Close()
			rows, err := readWorksheetXML(xml.NewDecoder(rc), ws.spreadsheet)
			ws.rows = rows
			if err != nil {
				return err
			}
		}
	}
	return nil
}

// Get the contents of cell at row / column, where 1,1 is the top left corner. The return value is always a string.
// The user is in charge to convert this value to a number, if necessary. Formulae are not returned.
func (ws *Worksheet) Cell(row, column int) string {
	xrow := ws.rows[row]
	if xrow == nil {
		return ""
	}
	if xrow.Cells[column] == nil {
		return ""
	}
	return xrow.Cells[column].Value
}

// Get the worksheet with the given number, starting at 0.
func (s *Spreadsheet) GetWorksheet(number int) (*Worksheet, error) {
	if number >= len(s.worksheets) || number < 0 {
		return nil, errors.New("Index out of range")
	}
	ws := s.worksheets[number]
	ws.filename = path.Join("xl", "worksheets", fmt.Sprintf("sheet%s.xml", ws.id))
	err := ws.readWorksheetZIP()
	if err != nil {
		return nil, err
	}
	return ws, nil
}
<|endoftext|>


<commit_before>/*
Copyright 2015 The Kubernetes Authors All rights reserved.

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 e2e

import (
	"fmt"
	"os/exec"
	"time"

	"k8s.io/kubernetes/pkg/api"
	"k8s.io/kubernetes/pkg/fields"
	"k8s.io/kubernetes/pkg/labels"

	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
)

var _ = Describe("Autoscaling", func() {
	f := NewFramework("autoscaling")
	var nodeCount int
	var coresPerNode int
	var memCapacityMb int

	BeforeEach(func() {
		SkipUnlessProviderIs("gce")

		nodes, err := f.Client.Nodes().List(labels.Everything(), fields.Everything())
		expectNoError(err)
		nodeCount = len(nodes.Items)
		Expect(nodeCount).NotTo(BeZero())
		cpu := nodes.Items[0].Status.Capacity[api.ResourceCPU]
		mem := nodes.Items[0].Status.Capacity[api.ResourceMemory]
		coresPerNode = int((&cpu).MilliValue() / 1000)
		memCapacityMb = int((&mem).Value() / 1024 / 1024)
	})

	AfterEach(func() {
		cleanUpAutoscaler()
	})

	It("[Skipped][Autoscaling Suite] should scale cluster size based on cpu utilization", func() {
		setUpAutoscaler("cpu/node_utilization", 0.4, nodeCount, nodeCount+1)

		// Consume 50% CPU
		millicoresPerReplica := 500
		rc := NewStaticResourceConsumer("cpu-utilization", nodeCount*coresPerNode, millicoresPerReplica*nodeCount*coresPerNode, 0, int64(millicoresPerReplica), 100, f)
		expectNoError(waitForClusterSize(f.Client, nodeCount+1, 20*time.Minute))

		rc.CleanUp()
		expectNoError(waitForClusterSize(f.Client, nodeCount, 20*time.Minute))
	})

	It("[Skipped] should scale cluster size based on cpu reservation", func() {
		setUpAutoscaler("cpu/node_reservation", 0.5, nodeCount, nodeCount+1)

		ReserveCpu(f, "cpu-reservation", 600*nodeCount*coresPerNode)
		expectNoError(waitForClusterSize(f.Client, nodeCount+1, 20*time.Minute))

		expectNoError(DeleteRC(f.Client, f.Namespace.Name, "cpu-reservation"))
		expectNoError(waitForClusterSize(f.Client, nodeCount, 20*time.Minute))
	})

	It("[Skipped][Autoscaling Suite] should scale cluster size based on memory utilization", func() {
		setUpAutoscaler("memory/node_utilization", 0.5, nodeCount, nodeCount+1)

		// Consume 60% of total memory capacity
		megabytesPerReplica := int(memCapacityMb * 6 / 10 / coresPerNode)
		rc := NewStaticResourceConsumer("mem-utilization", nodeCount*coresPerNode, 0, megabytesPerReplica*nodeCount*coresPerNode, 100, int64(megabytesPerReplica+100), f)
		expectNoError(waitForClusterSize(f.Client, nodeCount+1, 20*time.Minute))

		rc.CleanUp()
		expectNoError(waitForClusterSize(f.Client, nodeCount, 20*time.Minute))
	})

	It("[Skipped] should scale cluster size based on memory reservation", func() {
		setUpAutoscaler("memory/node_reservation", 0.5, nodeCount, nodeCount+1)

		ReserveMemory(f, "memory-reservation", nodeCount*memCapacityMb*6/10)
		expectNoError(waitForClusterSize(f.Client, nodeCount+1, 20*time.Minute))

		expectNoError(DeleteRC(f.Client, f.Namespace.Name, "memory-reservation"))
		expectNoError(waitForClusterSize(f.Client, nodeCount, 20*time.Minute))
	})
})

func setUpAutoscaler(metric string, target float64, min, max int) {
	// TODO integrate with kube-up.sh script once it will support autoscaler setup.
	By("Setting up autoscaler to scale based on " + metric)
	out, err := exec.Command("gcloud", "compute", "instance-groups", "managed", "set-autoscaling",
		testContext.CloudConfig.NodeInstanceGroup,
		"--project="+testContext.CloudConfig.ProjectID,
		"--zone="+testContext.CloudConfig.Zone,
		"--custom-metric-utilization=metric=custom.cloudmonitoring.googleapis.com/kubernetes.io/"+metric+fmt.Sprintf(",utilization-target=%v", target)+",utilization-target-type=GAUGE",
		fmt.Sprintf("--min-num-replicas=%v", min),
		fmt.Sprintf("--max-num-replicas=%v", max),
	).CombinedOutput()
	expectNoError(err, "Output: "+string(out))
}

func cleanUpAutoscaler() {
	By("Removing autoscaler")
	out, err := exec.Command("gcloud", "compute", "instance-groups", "managed", "stop-autoscaling",
		testContext.CloudConfig.NodeInstanceGroup,
		"--project="+testContext.CloudConfig.ProjectID,
		"--zone="+testContext.CloudConfig.Zone,
	).CombinedOutput()
	expectNoError(err, "Output: "+string(out))
}

func ReserveCpu(f *Framework, id string, millicores int) {
	By(fmt.Sprintf("Running RC which reserves %v millicores", millicores))
	config := &RCConfig{
		Client:     f.Client,
		Name:       id,
		Namespace:  f.Namespace.Name,
		Timeout:    10 * time.Minute,
		Image:      "gcr.io/google_containers/pause",
		Replicas:   millicores / 100,
		CpuRequest: 100,
	}
	expectNoError(RunRC(*config))
}

func ReserveMemory(f *Framework, id string, megabytes int) {
	By(fmt.Sprintf("Running RC which reserves %v MB of memory", megabytes))
	config := &RCConfig{
		Client:     f.Client,
		Name:       id,
		Namespace:  f.Namespace.Name,
		Timeout:    10 * time.Minute,
		Image:      "gcr.io/google_containers/pause",
		Replicas:   megabytes / 500,
		MemRequest: 500 * 1024 * 1024,
	}
	expectNoError(RunRC(*config))
}
<commit_msg>Another try to fix flaky autoscaling test.<commit_after>/*
Copyright 2015 The Kubernetes Authors All rights reserved.

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 e2e

import (
	"fmt"
	"os/exec"
	"time"

	"k8s.io/kubernetes/pkg/api"
	"k8s.io/kubernetes/pkg/fields"
	"k8s.io/kubernetes/pkg/labels"

	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
)

var _ = Describe("Autoscaling", func() {
	f := NewFramework("autoscaling")
	var nodeCount int
	var coresPerNode int
	var memCapacityMb int

	BeforeEach(func() {
		SkipUnlessProviderIs("gce")

		nodes, err := f.Client.Nodes().List(labels.Everything(), fields.Everything())
		expectNoError(err)
		nodeCount = len(nodes.Items)
		Expect(nodeCount).NotTo(BeZero())
		cpu := nodes.Items[0].Status.Capacity[api.ResourceCPU]
		mem := nodes.Items[0].Status.Capacity[api.ResourceMemory]
		coresPerNode = int((&cpu).MilliValue() / 1000)
		memCapacityMb = int((&mem).Value() / 1024 / 1024)
	})

	AfterEach(func() {
		cleanUpAutoscaler()
	})

	It("[Skipped][Autoscaling Suite] should scale cluster size based on cpu utilization", func() {
		setUpAutoscaler("cpu/node_utilization", 0.4, nodeCount, nodeCount+1)

		// Consume 50% CPU
		millicoresPerReplica := 500
		rc := NewStaticResourceConsumer("cpu-utilization", nodeCount*coresPerNode, millicoresPerReplica*nodeCount*coresPerNode, 0, int64(millicoresPerReplica), 100, f)
		expectNoError(waitForClusterSize(f.Client, nodeCount+1, 20*time.Minute))

		rc.CleanUp()
		expectNoError(waitForClusterSize(f.Client, nodeCount, 20*time.Minute))
	})

	It("[Skipped] should scale cluster size based on cpu reservation", func() {
		setUpAutoscaler("cpu/node_reservation", 0.5, nodeCount, nodeCount+1)

		ReserveCpu(f, "cpu-reservation", 600*nodeCount*coresPerNode)
		expectNoError(waitForClusterSize(f.Client, nodeCount+1, 20*time.Minute))

		expectNoError(DeleteRC(f.Client, f.Namespace.Name, "cpu-reservation"))
		expectNoError(waitForClusterSize(f.Client, nodeCount, 20*time.Minute))
	})

	It("[Skipped][Autoscaling Suite] should scale cluster size based on memory utilization", func() {
		setUpAutoscaler("memory/node_utilization", 0.6, nodeCount, nodeCount+1)

		// Consume 60% of total memory capacity
		megabytesPerReplica := int(memCapacityMb * 6 / 10 / coresPerNode)
		rc := NewStaticResourceConsumer("mem-utilization", nodeCount*coresPerNode, 0, megabytesPerReplica*nodeCount*coresPerNode, 100, int64(megabytesPerReplica+100), f)
		expectNoError(waitForClusterSize(f.Client, nodeCount+1, 20*time.Minute))

		rc.CleanUp()
		expectNoError(waitForClusterSize(f.Client, nodeCount, 20*time.Minute))
	})

	It("[Skipped] should scale cluster size based on memory reservation", func() {
		setUpAutoscaler("memory/node_reservation", 0.5, nodeCount, nodeCount+1)

		ReserveMemory(f, "memory-reservation", nodeCount*memCapacityMb*6/10)
		expectNoError(waitForClusterSize(f.Client, nodeCount+1, 20*time.Minute))

		expectNoError(DeleteRC(f.Client, f.Namespace.Name, "memory-reservation"))
		expectNoError(waitForClusterSize(f.Client, nodeCount, 20*time.Minute))
	})
})

func setUpAutoscaler(metric string, target float64, min, max int) {
	// TODO integrate with kube-up.sh script once it will support autoscaler setup.
	By("Setting up autoscaler to scale based on " + metric)
	out, err := exec.Command("gcloud", "compute", "instance-groups", "managed", "set-autoscaling",
		testContext.CloudConfig.NodeInstanceGroup,
		"--project="+testContext.CloudConfig.ProjectID,
		"--zone="+testContext.CloudConfig.Zone,
		"--custom-metric-utilization=metric=custom.cloudmonitoring.googleapis.com/kubernetes.io/"+metric+fmt.Sprintf(",utilization-target=%v", target)+",utilization-target-type=GAUGE",
		fmt.Sprintf("--min-num-replicas=%v", min),
		fmt.Sprintf("--max-num-replicas=%v", max),
	).CombinedOutput()
	expectNoError(err, "Output: "+string(out))
}

func cleanUpAutoscaler() {
	By("Removing autoscaler")
	out, err := exec.Command("gcloud", "compute", "instance-groups", "managed", "stop-autoscaling",
		testContext.CloudConfig.NodeInstanceGroup,
		"--project="+testContext.CloudConfig.ProjectID,
		"--zone="+testContext.CloudConfig.Zone,
	).CombinedOutput()
	expectNoError(err, "Output: "+string(out))
}

func ReserveCpu(f *Framework, id string, millicores int) {
	By(fmt.Sprintf("Running RC which reserves %v millicores", millicores))
	config := &RCConfig{
		Client:     f.Client,
		Name:       id,
		Namespace:  f.Namespace.Name,
		Timeout:    10 * time.Minute,
		Image:      "gcr.io/google_containers/pause",
		Replicas:   millicores / 100,
		CpuRequest: 100,
	}
	expectNoError(RunRC(*config))
}

func ReserveMemory(f *Framework, id string, megabytes int) {
	By(fmt.Sprintf("Running RC which reserves %v MB of memory", megabytes))
	config := &RCConfig{
		Client:     f.Client,
		Name:       id,
		Namespace:  f.Namespace.Name,
		Timeout:    10 * time.Minute,
		Image:      "gcr.io/google_containers/pause",
		Replicas:   megabytes / 500,
		MemRequest: 500 * 1024 * 1024,
	}
	expectNoError(RunRC(*config))
}
<|endoftext|>


<commit_before>// Copyright 2015 Google Inc.
//
// 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.

// Program yang parses YANG files, displays errors, and possibly writes
// something related to the input on output.
//
// Usage: yang [--path DIR] [--format FORMAT] [FORMAT OPTIONS] [MODULE] [FILE ...]
//
// If MODULE is specified (an argument that does not end in .yang), it is taken
// as the name of the module to display.  Any FILEs specified are read, and the
// tree for MODULE is displayed.  If MODULE was not defined in FILEs (or no
// files were specified), then the file MODULES.yang is read as well.  An error
// is displayed if no definition for MODULE was found.
//
// If MODULE is missing, then all base modules read from the FILEs are
// displayed.  If there are no arguments then standard input is parsed.
//
// If DIR is specified, it is considered a comma separated list of paths
// to append to the search directory.
//
// FORMAT, which defaults to "tree", specifes the format of output to produce.
// Use "goyang --help" for a list of available formats.
//
// FORMAT OPTIONS are flags that apply to a specific format.  They must follow
// --format.
//
// THIS PROGRAM IS STILL JUST A DEVELOPMENT TOOL.
package main

import (
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"runtime/trace"
	"sort"
	"strings"

	"github.com/openconfig/goyang/pkg/yang"
	"github.com/openconfig/goyang/pkg/indent"
	"github.com/pborman/getopt"
)

// Each format must register a formatter with register.  The function f will
// be called once with the set of yang Entry trees generated.
type formatter struct {
	name  string
	f     func(io.Writer, []*yang.Entry)
	help  string
	flags *getopt.Set
}

var formatters = map[string]*formatter{}

func register(f *formatter) {
	formatters[f.name] = f
}

// exitIfError writes errs to standard error and exits with an exit status of 1.
// If errs is empty then exitIfError does nothing and simply returns.
func exitIfError(errs []error) {
	if len(errs) > 0 {
		for _, err := range errs {
			fmt.Fprintln(os.Stderr, err)
		}
		stop(1)
	}
}

var stop = os.Exit

func main() {
	var format string
	formats := make([]string, 0, len(formatters))
	for k := range formatters {
		formats = append(formats, k)
	}
	sort.Strings(formats)

	var traceP string
	var help bool
	getopt.ListVarLong(&yang.Path, "path", 0, "comma separated list of directories to add to search path", "DIR[,DIR...]")
	getopt.StringVarLong(&format, "format", 0, "format to display: "+strings.Join(formats, ", "), "FORMAT")
	getopt.StringVarLong(&traceP, "trace", 0, "write trace into to TRACEFILE", "TRACEFILE")
	getopt.BoolVarLong(&help, "help", '?', "display help")
	getopt.SetParameters("[FORMAT OPTIONS] [SOURCE] [...]")

	if err := getopt.Getopt(func(o getopt.Option) bool {
		if o.Name() == "--format" {
			f, ok := formatters[format]
			if !ok {
				fmt.Fprintf(os.Stderr, "%s: invalid format.  Choices are %s\n", format, strings.Join(formats, ", "))
				stop(1)
			}
			if f.flags != nil {
				f.flags.VisitAll(func(o getopt.Option) {
					getopt.AddOption(o)
				})
			}
		}
		return true
	}); err != nil {
		fmt.Fprintln(os.Stderr, err)
		getopt.PrintUsage(os.Stderr)
	}

	if traceP != "" {
		fp, err := os.Create(traceP)
		if err != nil {
			fmt.Fprintln(os.Stderr, err)
			os.Exit(1)
		}
		trace.Start(fp)
		stop = func(c int) { trace.Stop(); os.Exit(c) }
		defer func() { trace.Stop() }()
	}

	if help {
		getopt.CommandLine.PrintUsage(os.Stderr)
		fmt.Fprintf(os.Stderr, `
SOURCE may be a module name or a .yang file.

Formats:
`)
		for _, fn := range formats {
			f := formatters[fn]
			fmt.Fprintf(os.Stderr, "    %s - %s\n", f.name, f.help)
			if f.flags != nil {
				f.flags.PrintOptions(indent.NewWriter(os.Stderr, "   "))
			}
			fmt.Fprintln(os.Stderr)
		}
		stop(0)
	}

	if format == "" {
		format = "tree"
	}
	if _, ok := formatters[format]; !ok {
		fmt.Fprintf(os.Stderr, "%s: invalid format.  Choices are %s\n", format, strings.Join(formats, ", "))
		stop(1)

	}

	files := getopt.Args()

	if len(files) > 0 && !strings.HasSuffix(files[0], ".yang") {
		e, errs := yang.GetModule(files[0], files[1:]...)
		exitIfError(errs)
		Write(os.Stdout, e)
		return
	}

	// Okay, either there are no arguments and we read stdin, or there
	// is one or more file names listed.  Read them in and display them.

	ms := yang.NewModules()

	if len(files) == 0 {
		data, err := ioutil.ReadAll(os.Stdin)
		if err == nil {
			err = ms.Parse(string(data), "<STDIN>")
		}
		if err != nil {
			fmt.Fprintln(os.Stderr, err)
			stop(1)
		}
	}

	for _, name := range files {
		if err := ms.Read(name); err != nil {
			fmt.Fprintln(os.Stderr, err)
			continue
		}
	}

	// Process the read files, exiting if any errors were found.
	exitIfError(ms.Process())

	// Keep track of the top level modules we read in.
	// Those are the only modules we want to print below.
	mods := map[string]*yang.Module{}
	var names []string

	for _, m := range ms.Modules {
		if mods[m.Name] == nil {
			mods[m.Name] = m
			names = append(names, m.Name)
		}
	}
	sort.Strings(names)
	entries := make([]*yang.Entry, len(names))
	for x, n := range names {
		entries[x] = yang.ToEntry(mods[n])
	}

	formatters[format].f(os.Stdout, entries)
}
<commit_msg>More doc on --path DIR/...<commit_after>// Copyright 2015 Google Inc.
//
// 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.

// Program yang parses YANG files, displays errors, and possibly writes
// something related to the input on output.
//
// Usage: yang [--path DIR] [--format FORMAT] [FORMAT OPTIONS] [MODULE] [FILE ...]
//
// If MODULE is specified (an argument that does not end in .yang), it is taken
// as the name of the module to display.  Any FILEs specified are read, and the
// tree for MODULE is displayed.  If MODULE was not defined in FILEs (or no
// files were specified), then the file MODULES.yang is read as well.  An error
// is displayed if no definition for MODULE was found.
//
// If MODULE is missing, then all base modules read from the FILEs are
// displayed.  If there are no arguments then standard input is parsed.
//
// If DIR is specified, it is considered a comma separated list of paths
// to append to the search directory.  If DIR appears as DIR/... then
// DIR and all direct and indirect subdirectories are checked.
//
// FORMAT, which defaults to "tree", specifes the format of output to produce.
// Use "goyang --help" for a list of available formats.
//
// FORMAT OPTIONS are flags that apply to a specific format.  They must follow
// --format.
//
// THIS PROGRAM IS STILL JUST A DEVELOPMENT TOOL.
package main

import (
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"runtime/trace"
	"sort"
	"strings"

	"github.com/openconfig/goyang/pkg/yang"
	"github.com/openconfig/goyang/pkg/indent"
	"github.com/pborman/getopt"
)

// Each format must register a formatter with register.  The function f will
// be called once with the set of yang Entry trees generated.
type formatter struct {
	name  string
	f     func(io.Writer, []*yang.Entry)
	help  string
	flags *getopt.Set
}

var formatters = map[string]*formatter{}

func register(f *formatter) {
	formatters[f.name] = f
}

// exitIfError writes errs to standard error and exits with an exit status of 1.
// If errs is empty then exitIfError does nothing and simply returns.
func exitIfError(errs []error) {
	if len(errs) > 0 {
		for _, err := range errs {
			fmt.Fprintln(os.Stderr, err)
		}
		stop(1)
	}
}

var stop = os.Exit

func main() {
	var format string
	formats := make([]string, 0, len(formatters))
	for k := range formatters {
		formats = append(formats, k)
	}
	sort.Strings(formats)

	var traceP string
	var help bool
	getopt.ListVarLong(&yang.Path, "path", 0, "comma separated list of directories to add to search path", "DIR[,DIR...]")
	getopt.StringVarLong(&format, "format", 0, "format to display: "+strings.Join(formats, ", "), "FORMAT")
	getopt.StringVarLong(&traceP, "trace", 0, "write trace into to TRACEFILE", "TRACEFILE")
	getopt.BoolVarLong(&help, "help", '?', "display help")
	getopt.SetParameters("[FORMAT OPTIONS] [SOURCE] [...]")

	if err := getopt.Getopt(func(o getopt.Option) bool {
		if o.Name() == "--format" {
			f, ok := formatters[format]
			if !ok {
				fmt.Fprintf(os.Stderr, "%s: invalid format.  Choices are %s\n", format, strings.Join(formats, ", "))
				stop(1)
			}
			if f.flags != nil {
				f.flags.VisitAll(func(o getopt.Option) {
					getopt.AddOption(o)
				})
			}
		}
		return true
	}); err != nil {
		fmt.Fprintln(os.Stderr, err)
		getopt.PrintUsage(os.Stderr)
	}

	if traceP != "" {
		fp, err := os.Create(traceP)
		if err != nil {
			fmt.Fprintln(os.Stderr, err)
			os.Exit(1)
		}
		trace.Start(fp)
		stop = func(c int) { trace.Stop(); os.Exit(c) }
		defer func() { trace.Stop() }()
	}

	if help {
		getopt.CommandLine.PrintUsage(os.Stderr)
		fmt.Fprintf(os.Stderr, `
SOURCE may be a module name or a .yang file.

Formats:
`)
		for _, fn := range formats {
			f := formatters[fn]
			fmt.Fprintf(os.Stderr, "    %s - %s\n", f.name, f.help)
			if f.flags != nil {
				f.flags.PrintOptions(indent.NewWriter(os.Stderr, "   "))
			}
			fmt.Fprintln(os.Stderr)
		}
		stop(0)
	}

	if format == "" {
		format = "tree"
	}
	if _, ok := formatters[format]; !ok {
		fmt.Fprintf(os.Stderr, "%s: invalid format.  Choices are %s\n", format, strings.Join(formats, ", "))
		stop(1)

	}

	files := getopt.Args()

	if len(files) > 0 && !strings.HasSuffix(files[0], ".yang") {
		e, errs := yang.GetModule(files[0], files[1:]...)
		exitIfError(errs)
		Write(os.Stdout, e)
		return
	}

	// Okay, either there are no arguments and we read stdin, or there
	// is one or more file names listed.  Read them in and display them.

	ms := yang.NewModules()

	if len(files) == 0 {
		data, err := ioutil.ReadAll(os.Stdin)
		if err == nil {
			err = ms.Parse(string(data), "<STDIN>")
		}
		if err != nil {
			fmt.Fprintln(os.Stderr, err)
			stop(1)
		}
	}

	for _, name := range files {
		if err := ms.Read(name); err != nil {
			fmt.Fprintln(os.Stderr, err)
			continue
		}
	}

	// Process the read files, exiting if any errors were found.
	exitIfError(ms.Process())

	// Keep track of the top level modules we read in.
	// Those are the only modules we want to print below.
	mods := map[string]*yang.Module{}
	var names []string

	for _, m := range ms.Modules {
		if mods[m.Name] == nil {
			mods[m.Name] = m
			names = append(names, m.Name)
		}
	}
	sort.Strings(names)
	entries := make([]*yang.Entry, len(names))
	for x, n := range names {
		entries[x] = yang.ToEntry(mods[n])
	}

	formatters[format].f(os.Stdout, entries)
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"io/ioutil"
	"log"
	"math/rand"
	"net/http"
	"net/url"
	"os"
	"strconv"
	"strings"
	"time"

	"github.com/JustinBeckwith/go-yelp/yelp"
	"github.com/guregu/null"
	"github.com/line/line-bot-sdk-go/linebot"
)

var o *yelp.AuthOptions

type UrlShortener struct {
	ShortUrl    string
	OriginalUrl string
}

func yelp_init() {
	rand.Seed(time.Now().UnixNano())

	// check environment variables
	o = &yelp.AuthOptions{
		ConsumerKey:       os.Getenv("CONSUMER_KEY"),
		ConsumerSecret:    os.Getenv("CONSUMER_SECRET"),
		AccessToken:       os.Getenv("ACCESS_TOKEN"),
		AccessTokenSecret: os.Getenv("ACCESS_TOKEN_SECRET"),
	}

	if o.ConsumerKey == "" || o.ConsumerSecret == "" || o.AccessToken == "" || o.AccessTokenSecret == "" {
		log.Fatal("Wrong environment setting about yelp-api-keys")
	}
}

func yelp_parse(bot *linebot.Client, token string, loc *linebot.LocationMessage, food string) {
	var err error
	var results yelp.SearchResult
//	var msgs []linebot.Message

	// create a new yelp client with the auth keys
	client := yelp.New(o, nil)

	if loc == nil {
		// make a simple query for food and location
		results, err := client.DoSimpleSearch(food, "台北市通化街")
	} else {
		// Build an advanced set of search criteria that include
		// general options, and coordinate options.
		s := yelp.SearchOptions{
			GeneralOptions: &yelp.GeneralOptions{
				Term: food,
			},
			CoordinateOptions: &yelp.CoordinateOptions{
				Latitude:  null.FloatFrom(loc.Latitude),
				Longitude: null.FloatFrom(loc.Longitude),
			},
		}

		// Perform the search using the search options
		results, err := client.DoSearch(s)
	}
	if err != nil {
		log.Println(err)
		_, err = bot.ReplyMessage(token, linebot.NewTextMessage("查無資料！\n請重新輸入\n\n吃吃 牛肉麵;台北市通化街")).Do()
	}

	for j := 0; j < 3; j++ {
		i := 0
		if results.Total >= 20 {
			i = rand.Intn(20)
		} else if results.Total >= 10 {
			i = rand.Intn(10)
		} else if results.Total > j {
			i = j
		} else if results.Total <= j && results.Total != 0 {
			_, err = bot.ReplyMessage(token, linebot.NewTextMessage("已無更多資料！")).Do()
			break
		}
		urlOrig := UrlShortener{}
		urlOrig.short(results.Businesses[i].MobileURL)
		address := strings.Join(results.Businesses[i].Location.DisplayAddress, ",")
		var largeImageURL = strings.Replace(results.Businesses[i].ImageURL, "ms.jpg", "l.jpg", 1)

		_, err = bot.ReplyMessage(token, linebot.NewImageMessage(largeImageURL, largeImageURL), linebot.NewTextMessage("店名："+results.Businesses[i].Name+"\n電話："+results.Businesses[i].Phone+"\n評比："+strconv.FormatFloat(float64(results.Businesses[i].Rating), 'f', 1, 64)+"\n更多資訊："+urlOrig.ShortUrl), linebot.NewLocationMessage(results.Businesses[i].Name+"\n", address, float64(results.Businesses[i].Location.Coordinate.Latitude), float64(results.Businesses[i].Location.Coordinate.Longitude)) ).Do()
//		msgs = append(msgs, linebot.NewImageMessage(largeImageURL, largeImageURL))
//		msgs = append(msgs, linebot.NewTextMessage("店名："+results.Businesses[i].Name+"\n電話："+results.Businesses[i].Phone+"\n評比："+strconv.FormatFloat(float64(results.Businesses[i].Rating), 'f', 1, 64)+"\n更多資訊："+urlOrig.ShortUrl))
//		msgs = append(msgs, linebot.NewLocationMessage(results.Businesses[i].Name+"\n", address, float64(results.Businesses[i].Location.Coordinate.Latitude), float64(results.Businesses[i].Location.Coordinate.Longitude)))
//		_, err = bot.ReplyMessage(token, linebot.NewImageMessage(largeImageURL, largeImageURL)).Do()
//		_, err = bot.ReplyMessage(token, linebot.NewTextMessage("店名："+results.Businesses[i].Name+"\n電話："+results.Businesses[i].Phone+"\n評比："+strconv.FormatFloat(float64(results.Businesses[i].Rating), 'f', 1, 64)+"\n更多資訊："+urlOrig.ShortUrl)).Do()
//		_, err = bot.ReplyMessage(token, linebot.NewLocationMessage(results.Businesses[i].Name+"\n", address, float64(results.Businesses[i].Location.Coordinate.Latitude), float64(results.Businesses[i].Location.Coordinate.Longitude))).Do()
	}

//	if len(msgs) > 0 {
//		_, err = bot.ReplyMessage(token, msgs).Do()
//	}
}

func getResponseData(urlOrig string) string {
	response, err := http.Get(urlOrig)
	if err != nil {
		log.Println(err)
	}
	defer response.Body.Close()
	contents, err := ioutil.ReadAll(response.Body)
	return string(contents)
}

func isGdShortener(urlOrig string) (string, string) {
	escapedUrl := url.QueryEscape(urlOrig)
	isGdUrl := fmt.Sprintf("http://is.gd/create.php?url=%s&format=simple", escapedUrl)
	return getResponseData(isGdUrl), urlOrig
}

func (u *UrlShortener) short(urlOrig string) *UrlShortener {
	shortUrl, originalUrl := isGdShortener(urlOrig)
	u.ShortUrl = shortUrl
	u.OriginalUrl = originalUrl
	return u
}
<commit_msg>test location<commit_after>package main

import (
	"fmt"
	"io/ioutil"
	"log"
	"math/rand"
	"net/http"
	"net/url"
	"os"
	"strconv"
	"strings"
	"time"

	"github.com/JustinBeckwith/go-yelp/yelp"
	"github.com/guregu/null"
	"github.com/line/line-bot-sdk-go/linebot"
)

var o *yelp.AuthOptions

type UrlShortener struct {
	ShortUrl    string
	OriginalUrl string
}

func yelp_init() {
	rand.Seed(time.Now().UnixNano())

	// check environment variables
	o = &yelp.AuthOptions{
		ConsumerKey:       os.Getenv("CONSUMER_KEY"),
		ConsumerSecret:    os.Getenv("CONSUMER_SECRET"),
		AccessToken:       os.Getenv("ACCESS_TOKEN"),
		AccessTokenSecret: os.Getenv("ACCESS_TOKEN_SECRET"),
	}

	if o.ConsumerKey == "" || o.ConsumerSecret == "" || o.AccessToken == "" || o.AccessTokenSecret == "" {
		log.Fatal("Wrong environment setting about yelp-api-keys")
	}
}

func yelp_parse(bot *linebot.Client, token string, loc *linebot.LocationMessage, food string) {
	var err error
//	var msgs []linebot.Message

	// create a new yelp client with the auth keys
	client := yelp.New(o, nil)

	if loc == nil {
		// make a simple query for food and location
		results, err := client.DoSimpleSearch(food, "台北市通化街")
	} else {
		// Build an advanced set of search criteria that include
		// general options, and coordinate options.
		s := yelp.SearchOptions{
			GeneralOptions: &yelp.GeneralOptions{
				Term: food,
			},
			CoordinateOptions: &yelp.CoordinateOptions{
				Latitude:  null.FloatFrom(loc.Latitude),
				Longitude: null.FloatFrom(loc.Longitude),
			},
		}

		// Perform the search using the search options
		results, err := client.DoSearch(s)
	}
	if err != nil {
		log.Println(err)
		_, err = bot.ReplyMessage(token, linebot.NewTextMessage("查無資料！\n請重新輸入\n\n吃吃 牛肉麵;台北市通化街")).Do()
	}

	for j := 0; j < 3; j++ {
		i := 0
		if results.Total >= 20 {
			i = rand.Intn(20)
		} else if results.Total >= 10 {
			i = rand.Intn(10)
		} else if results.Total > j {
			i = j
		} else if results.Total <= j && results.Total != 0 {
			_, err = bot.ReplyMessage(token, linebot.NewTextMessage("已無更多資料！")).Do()
			break
		}
		urlOrig := UrlShortener{}
		urlOrig.short(results.Businesses[i].MobileURL)
		address := strings.Join(results.Businesses[i].Location.DisplayAddress, ",")
		var largeImageURL = strings.Replace(results.Businesses[i].ImageURL, "ms.jpg", "l.jpg", 1)

		_, err = bot.ReplyMessage(token, linebot.NewImageMessage(largeImageURL, largeImageURL), linebot.NewTextMessage("店名："+results.Businesses[i].Name+"\n電話："+results.Businesses[i].Phone+"\n評比："+strconv.FormatFloat(float64(results.Businesses[i].Rating), 'f', 1, 64)+"\n更多資訊："+urlOrig.ShortUrl), linebot.NewLocationMessage(results.Businesses[i].Name+"\n", address, float64(results.Businesses[i].Location.Coordinate.Latitude), float64(results.Businesses[i].Location.Coordinate.Longitude)) ).Do()
//		msgs = append(msgs, linebot.NewImageMessage(largeImageURL, largeImageURL))
//		msgs = append(msgs, linebot.NewTextMessage("店名："+results.Businesses[i].Name+"\n電話："+results.Businesses[i].Phone+"\n評比："+strconv.FormatFloat(float64(results.Businesses[i].Rating), 'f', 1, 64)+"\n更多資訊："+urlOrig.ShortUrl))
//		msgs = append(msgs, linebot.NewLocationMessage(results.Businesses[i].Name+"\n", address, float64(results.Businesses[i].Location.Coordinate.Latitude), float64(results.Businesses[i].Location.Coordinate.Longitude)))
//		_, err = bot.ReplyMessage(token, linebot.NewImageMessage(largeImageURL, largeImageURL)).Do()
//		_, err = bot.ReplyMessage(token, linebot.NewTextMessage("店名："+results.Businesses[i].Name+"\n電話："+results.Businesses[i].Phone+"\n評比："+strconv.FormatFloat(float64(results.Businesses[i].Rating), 'f', 1, 64)+"\n更多資訊："+urlOrig.ShortUrl)).Do()
//		_, err = bot.ReplyMessage(token, linebot.NewLocationMessage(results.Businesses[i].Name+"\n", address, float64(results.Businesses[i].Location.Coordinate.Latitude), float64(results.Businesses[i].Location.Coordinate.Longitude))).Do()
	}

//	if len(msgs) > 0 {
//		_, err = bot.ReplyMessage(token, msgs).Do()
//	}
}

func getResponseData(urlOrig string) string {
	response, err := http.Get(urlOrig)
	if err != nil {
		log.Println(err)
	}
	defer response.Body.Close()
	contents, err := ioutil.ReadAll(response.Body)
	return string(contents)
}

func isGdShortener(urlOrig string) (string, string) {
	escapedUrl := url.QueryEscape(urlOrig)
	isGdUrl := fmt.Sprintf("http://is.gd/create.php?url=%s&format=simple", escapedUrl)
	return getResponseData(isGdUrl), urlOrig
}

func (u *UrlShortener) short(urlOrig string) *UrlShortener {
	shortUrl, originalUrl := isGdShortener(urlOrig)
	u.ShortUrl = shortUrl
	u.OriginalUrl = originalUrl
	return u
}
<|endoftext|>


<commit_before>package lbrelease

import (
	"fmt"

	"github.com/lhcb-org/lbx/lbx"
)

type GetPack struct {
	ReqPkg     string // requested package
	ReqPkgVers string

	pkgs  map[string][]lbx.RepoInfo
	projs []string
	repos lbx.RepoInfos

	sel_repo string // selected repository
	sel_hat  string // selected repository hat

	proj_name string
	proj_vers string

	init bool
}

func (gp *GetPack) setup() error {
	var err error
	if gp.init {
		return err
	}

	err = gp.initRepos(nil, "", "")
	if err != nil {
		return err
	}

	err = gp.initPkgs()
	if err != nil {
		return err
	}

	gp.init = true
	return err
}

func (gp *GetPack) initRepos(excludes []string, user, protocol string) error {
	var err error
	if gp.repos != nil {
		return err
	}

	excl := map[string]struct{}{}
	for _, v := range excludes {
		excl[v] = struct{}{}
	}

	gp.repos = make(lbx.RepoInfos, 3)

	// prepare repositories urls
	// filter the requested protocols for the known repositories
	for k, v := range lbx.Repositories(user, protocol) {
		if _, dup := excl[k]; dup {
			continue
		}
		gp.repos[k] = v
	}

	if len(gp.repos) <= 0 {
		return fmt.Errorf("getpack: unable to find a repository for the specified protocol")
	}

	return err
}

func (gp *GetPack) initPkgs() error {
	var err error
	if gp.pkgs != nil {
		return err
	}

	gp.pkgs = make(map[string][]lbx.RepoInfo)

	for _, repo := range gp.repos {
		for _, p := range repo.ListPackages(gp.sel_hat) {
			if _, ok := gp.pkgs[p]; !ok {
				gp.pkgs[p] = make([]lbx.RepoInfo, 0, 1)
			}
			gp.pkgs[p] = append(gp.pkgs[p], repo)
		}
	}
	return err
}

func (gp *GetPack) Run() error {
	var err error
	err = gp.setup()
	if err != nil {
		return err
	}

	return err
}
<commit_msg>getpack: typos<commit_after>package lbrelease

import (
	"fmt"

	"github.com/lhcb-org/lbx/lbx"
)

type GetPack struct {
	ReqPkg     string // requested package
	ReqPkgVers string

	pkgs  map[string][]lbx.RepoInfo
	projs []string
	repos lbx.RepoInfos

	sel_repo string // selected repository
	sel_hat  string // selected repository hat

	proj_name string
	proj_vers string

	init bool
}

func (gp *GetPack) setup() error {
	var err error
	if gp.init {
		return err
	}

	err = gp.initRepos(nil, "", "")
	if err != nil {
		return err
	}

	err = gp.initPkgs()
	if err != nil {
		return err
	}

	gp.init = true
	return err
}

func (gp *GetPack) initRepos(excludes []string, user, protocol string) error {
	var err error
	if gp.repos != nil {
		return err
	}

	excl := map[string]struct{}{}
	for _, v := range excludes {
		excl[v] = struct{}{}
	}

	gp.repos = make(lbx.RepoInfos, 3)

	// prepare repositories urls
	// filter the requested protocols for the known repositories
	for k, v := range lbx.Repositories(user, protocol) {
		if _, dup := excl[k]; dup {
			continue
		}
		gp.repos[k] = v
	}

	if len(gp.repos) <= 0 {
		return fmt.Errorf("getpack: unable to find a repository for the specified protocol")
	}

	return err
}

func (gp *GetPack) initPkgs() error {
	var err error
	if gp.pkgs != nil {
		return err
	}

	gp.pkgs = make(map[string][]lbx.RepoInfo)

	for _, repo := range gp.repos {
		for _, p := range repo[0].ListPackages(gp.sel_hat) {
			if _, ok := gp.pkgs[p]; !ok {
				gp.pkgs[p] = make([]lbx.RepoInfo, 0, 1)
			}
			gp.pkgs[p] = append(gp.pkgs[p], repo[0])
		}
	}
	return err
}

func (gp *GetPack) Run() error {
	var err error
	err = gp.setup()
	if err != nil {
		return err
	}

	return err
}
<|endoftext|>


<commit_before>package cli

import (
	"fmt"
	"io"
	"os"
	"os/exec"
	"os/signal"
	"strings"

	sys "golang.org/x/sys/unix"

	"github.com/derekparker/delve/command"
	"github.com/derekparker/delve/proctl"

	"github.com/peterh/liner"
)

const historyFile string = ".dbg_history"

func Run(run bool, pid int, args []string) {
	var (
		dbp  *proctl.DebuggedProcess
		err  error
		line = liner.NewLiner()
	)
	defer line.Close()

	switch {
	case run:
		const debugname = "debug"
		cmd := exec.Command("go", "build", "-o", debugname, "-gcflags", "-N -l")
		err := cmd.Run()
		if err != nil {
			die(1, "Could not compile program:", err)
		}
		defer os.Remove(debugname)

		dbp, err = proctl.Launch(append([]string{"./" + debugname}, args...))
		if err != nil {
			die(1, "Could not launch program:", err)
		}
	case pid != 0:
		dbp, err = proctl.Attach(pid)
		if err != nil {
			die(1, "Could not attach to process:", err)
		}
	default:
		dbp, err = proctl.Launch(args)
		if err != nil {
			die(1, "Could not launch program:", err)
		}
	}

	ch := make(chan os.Signal)
	signal.Notify(ch, sys.SIGINT)
	go func() {
		for _ = range ch {
			if dbp.Running() {
				dbp.RequestManualStop()
			}
		}
	}()

	cmds := command.DebugCommands()
	if f, err := os.Open(historyFile); err == nil {
		line.ReadHistory(f)
		f.Close()
	}
	fmt.Println("Type 'help' for list of commands.")

	for {
		cmdstr, err := promptForInput(line)
		if err != nil {
			if err == io.EOF {
				handleExit(dbp, line, 0)
			}
			die(1, "Prompt for input failed.\n")
		}

		cmdstr, args := parseCommand(cmdstr)

		if cmdstr == "exit" {
			handleExit(dbp, line, 0)
		}

		cmd := cmds.Find(cmdstr)
		err = cmd(dbp, args...)
		if err != nil {
			fmt.Fprintf(os.Stderr, "Command failed: %s\n", err)
		}
	}
}

func handleExit(dbp *proctl.DebuggedProcess, line *liner.State, status int) {
	if f, err := os.Open(historyFile); err == nil {
		line.WriteHistory(f)
		f.Close()
	}

	answer, err := line.Prompt("Would you like to kill the process? [y/n]")
	if err != nil {
		die(2, io.EOF)
	}
	answer = strings.TrimSuffix(answer, "\n")

	for _, bp := range dbp.HWBreakPoints {
		if bp == nil {
			continue
		}
		if _, err := dbp.Clear(bp.Addr); err != nil {
			fmt.Printf("Can't clear breakpoint @%x: %s\n", bp.Addr, err)
		}
	}

	for pc := range dbp.BreakPoints {
		if _, err := dbp.Clear(pc); err != nil {
			fmt.Printf("Can't clear breakpoint @%x: %s\n", pc, err)
		}
	}

	fmt.Println("Detaching from process...")
	err = sys.PtraceDetach(dbp.Process.Pid)
	if err != nil {
		die(2, "Could not detach", err)
	}

	if answer == "y" {
		fmt.Println("Killing process", dbp.Process.Pid)

		err := dbp.Process.Kill()
		if err != nil {
			fmt.Println("Could not kill process", err)
		}
	}

	die(status, "Hope I was of service hunting your bug!")
}

func die(status int, args ...interface{}) {
	fmt.Fprint(os.Stderr, args)
	fmt.Fprint(os.Stderr, "\n")
	os.Exit(status)
}

func parseCommand(cmdstr string) (string, []string) {
	vals := strings.Split(cmdstr, " ")
	return vals[0], vals[1:]
}

func promptForInput(line *liner.State) (string, error) {
	l, err := line.Prompt("(dlv) ")
	if err != nil {
		return "", err
	}

	l = strings.TrimSuffix(l, "\n")
	if l != "" {
		line.AppendHistory(l)
	}

	return l, nil
}
<commit_msg>Fix readline history<commit_after>package cli

import (
	"fmt"
	"io"
	"os"
	"os/exec"
	"os/signal"
	"strings"

	sys "golang.org/x/sys/unix"

	"github.com/derekparker/delve/command"
	"github.com/derekparker/delve/proctl"

	"github.com/peterh/liner"
)

const historyFile string = ".dbg_history"

func Run(run bool, pid int, args []string) {
	var (
		dbp  *proctl.DebuggedProcess
		err  error
		line = liner.NewLiner()
	)
	defer line.Close()

	switch {
	case run:
		const debugname = "debug"
		cmd := exec.Command("go", "build", "-o", debugname, "-gcflags", "-N -l")
		err := cmd.Run()
		if err != nil {
			die(1, "Could not compile program:", err)
		}
		defer os.Remove(debugname)

		dbp, err = proctl.Launch(append([]string{"./" + debugname}, args...))
		if err != nil {
			die(1, "Could not launch program:", err)
		}
	case pid != 0:
		dbp, err = proctl.Attach(pid)
		if err != nil {
			die(1, "Could not attach to process:", err)
		}
	default:
		dbp, err = proctl.Launch(args)
		if err != nil {
			die(1, "Could not launch program:", err)
		}
	}

	ch := make(chan os.Signal)
	signal.Notify(ch, sys.SIGINT)
	go func() {
		for _ = range ch {
			if dbp.Running() {
				dbp.RequestManualStop()
			}
		}
	}()

	cmds := command.DebugCommands()
	f, err := os.Open(historyFile)
	if err != nil {
		f, _ = os.Create(historyFile)
	}
	line.ReadHistory(f)
	f.Close()
	fmt.Println("Type 'help' for list of commands.")

	for {
		cmdstr, err := promptForInput(line)
		if err != nil {
			if err == io.EOF {
				handleExit(dbp, line, 0)
			}
			die(1, "Prompt for input failed.\n")
		}

		cmdstr, args := parseCommand(cmdstr)

		if cmdstr == "exit" {
			handleExit(dbp, line, 0)
		}

		cmd := cmds.Find(cmdstr)
		err = cmd(dbp, args...)
		if err != nil {
			fmt.Fprintf(os.Stderr, "Command failed: %s\n", err)
		}
	}
}

func handleExit(dbp *proctl.DebuggedProcess, line *liner.State, status int) {
	if f, err := os.OpenFile(historyFile, os.O_RDWR, 0666); err == nil {
		_, err := line.WriteHistory(f)
		if err != nil {
			fmt.Println("readline histroy: ", err)
		}
		f.Close()
	}

	answer, err := line.Prompt("Would you like to kill the process? [y/n]")
	if err != nil {
		die(2, io.EOF)
	}
	answer = strings.TrimSuffix(answer, "\n")

	for _, bp := range dbp.HWBreakPoints {
		if bp == nil {
			continue
		}
		if _, err := dbp.Clear(bp.Addr); err != nil {
			fmt.Printf("Can't clear breakpoint @%x: %s\n", bp.Addr, err)
		}
	}

	for pc := range dbp.BreakPoints {
		if _, err := dbp.Clear(pc); err != nil {
			fmt.Printf("Can't clear breakpoint @%x: %s\n", pc, err)
		}
	}

	fmt.Println("Detaching from process...")
	err = sys.PtraceDetach(dbp.Process.Pid)
	if err != nil {
		die(2, "Could not detach", err)
	}

	if answer == "y" {
		fmt.Println("Killing process", dbp.Process.Pid)

		err := dbp.Process.Kill()
		if err != nil {
			fmt.Println("Could not kill process", err)
		}
	}

	die(status, "Hope I was of service hunting your bug!")
}

func die(status int, args ...interface{}) {
	fmt.Fprint(os.Stderr, args)
	fmt.Fprint(os.Stderr, "\n")
	os.Exit(status)
}

func parseCommand(cmdstr string) (string, []string) {
	vals := strings.Split(cmdstr, " ")
	return vals[0], vals[1:]
}

func promptForInput(line *liner.State) (string, error) {
	l, err := line.Prompt("(dlv) ")
	if err != nil {
		return "", err
	}

	l = strings.TrimSuffix(l, "\n")
	if l != "" {
		line.AppendHistory(l)
	}

	return l, nil
}
<|endoftext|>


<commit_before><commit_msg>kubetcl create --validate crashes when no apiVersion or kind is provided<commit_after><|endoftext|>


<commit_before>package bootconfig

import (
	"encoding/json"
	"log"
	"os"

	"github.com/systemboot/systemboot/pkg/crypto"
	"github.com/u-root/u-root/pkg/kexec"
	"github.com/u-root/u-root/pkg/kexecbin"
)

// BootConfig is a general-purpose boot configuration. It draws some
// characteristics from FIT but it's not compatible with it. It uses
// JSON for interoperability.
type BootConfig struct {
	Name       string `json:"name,omitempty"`
	Kernel     string `json:"kernel"`
	Initramfs  string `json:"initramfs,omitempty"`
	KernelArgs string `json:"kernel_args,omitempty"`
	DeviceTree string `json:"devicetree,omitempty"`
}

// IsValid returns true if a BootConfig object has valid content, and false
// otherwise
func (bc *BootConfig) IsValid() bool {
	return bc.Kernel != ""
}

// Boot tries to boot the kernel with optional initramfs and command line
// options. If a device-tree is specified, that will be used too
func (bc *BootConfig) Boot() error {
	// kexec: try the kexecbin executable first, and if it fails, use the native
	// Go implementation of kexec from u-root
	log.Printf("Trying KexecBin on %+v", bc)
	crypto.TryMeasureBootConfig(bc.Name, bc.Kernel, bc.Initramfs, bc.KernelArgs, bc.DeviceTree)
	if err := kexecbin.KexecBin(bc.Kernel, bc.KernelArgs, bc.Initramfs, bc.DeviceTree); err != nil {
		if os.IsNotExist(err) {
			log.Printf("BootConfig: KexecBin failed, trying pure-Go kexec. Error: %v", err)
		} else {
			return err
		}
	}
	kernel, err := os.Open(bc.Kernel)
	if err != nil {
		return err
	}
	var initramfs *os.File
	if bc.Initramfs != "" {
		initramfs, err = os.Open(bc.Initramfs)
		if err != nil {
			return err
		}
	}
	defer func() {
		// clean up
		if kernel != nil {
			if err := kernel.Close(); err != nil {
				log.Printf("Error closing kernel file descriptor: %v", err)
			}
		}
		if initramfs != nil {
			if err := initramfs.Close(); err != nil {
				log.Printf("Error closing initramfs file descriptor: %v", err)
			}
		}
	}()
	return kexec.FileLoad(kernel, initramfs, bc.KernelArgs)
}

// NewBootConfig parses a boot configuration in JSON format and returns a
// BootConfig object.
func NewBootConfig(data []byte) (*BootConfig, error) {
	var bootconfig BootConfig
	if err := json.Unmarshal(data, &bootconfig); err != nil {
		return nil, err
	}
	return &bootconfig, nil
}
<commit_msg>Bootconfig fixes/improvements (#79)<commit_after>package bootconfig

import (
	"encoding/json"
	"errors"
	"log"
	"os"
	"os/exec"

	"github.com/systemboot/systemboot/pkg/crypto"
	"github.com/u-root/u-root/pkg/kexec"
	"github.com/u-root/u-root/pkg/kexecbin"
)

// BootConfig is a general-purpose boot configuration. It draws some
// characteristics from FIT but it's not compatible with it. It uses
// JSON for interoperability.
type BootConfig struct {
	Name       string `json:"name,omitempty"`
	Kernel     string `json:"kernel"`
	Initramfs  string `json:"initramfs,omitempty"`
	KernelArgs string `json:"kernel_args,omitempty"`
	DeviceTree string `json:"devicetree,omitempty"`
}

// IsValid returns true if a BootConfig object has valid content, and false
// otherwise
func (bc *BootConfig) IsValid() bool {
	return bc.Kernel != ""
}

// Boot tries to boot the kernel with optional initramfs and command line
// options. If a device-tree is specified, that will be used too
func (bc *BootConfig) Boot() error {
	crypto.TryMeasureBootConfig(bc.Name, bc.Kernel, bc.Initramfs, bc.KernelArgs, bc.DeviceTree)

	// kexec: try the kexecbin executable first
	// if it is not available fallback to the Go implementation of kexec from u-root
	log.Printf("Trying KexecBin on %+v", bc)
	if err := kexecbin.KexecBin(bc.Kernel, bc.KernelArgs, bc.Initramfs, bc.DeviceTree); err != nil {
		// If it was found nowhere in PATH it will be exec.Error{exec.ErrNotFound}, which we have to unpack
		execErr, ok := err.(*exec.Error)
		if (ok && execErr.Err == exec.ErrNotFound) || os.IsNotExist(err) {
			log.Printf("BootConfig: KexecBin is not available, trying pure-Go kexec. Error: %v", err)
		} else {
			return err
		}
	}

	kernel, err := os.Open(bc.Kernel)
	if err != nil {
		return err
	}
	var initramfs *os.File
	if bc.Initramfs != "" {
		initramfs, err = os.Open(bc.Initramfs)
		if err != nil {
			return err
		}
	}
	defer func() {
		// clean up
		if kernel != nil {
			if err := kernel.Close(); err != nil {
				log.Printf("Error closing kernel file descriptor: %v", err)
			}
		}
		if initramfs != nil {
			if err := initramfs.Close(); err != nil {
				log.Printf("Error closing initramfs file descriptor: %v", err)
			}
		}
	}()
	if err := kexec.FileLoad(kernel, initramfs, bc.KernelArgs); err != nil {
		return err
	}

	err = kexec.Reboot()
	if err == nil {
		return errors.New("Unexpectedly returned from Reboot() without error. The system did not reboot")
	}
	return err

}

// NewBootConfig parses a boot configuration in JSON format and returns a
// BootConfig object.
func NewBootConfig(data []byte) (*BootConfig, error) {
	var bootconfig BootConfig
	if err := json.Unmarshal(data, &bootconfig); err != nil {
		return nil, err
	}
	return &bootconfig, nil
}
<|endoftext|>


<commit_before>package byteutil

import "bytes"

// ReverseByteSlice reverses a byte slice
func ReverseByteSlice(s []byte) []byte {
	// make a copy of s
	l := len(s)
	t := make([]byte, l)
	for i := 0; i < l; i++ {
		t[i] = s[i]
	}

	// reverse
	for i, j := 0, len(t)-1; i < j; i, j = i+1, j-1 {
		t[i], t[j] = t[j], t[i]
	}
	return t
}

// WrapByteSlice wraps byte slice
func WrapByteSlice(s []byte, width int) []byte {
	if width < 1 {
		return s
	}
	var buffer bytes.Buffer
	l := len(s)
	var lines int
	if l%width == 0 {
		lines = l/width - 1
	} else {
		lines = int(l / width)
	}
	var start, end int
	for i := 0; i <= lines; i++ {
		start = i * width
		end = (i + 1) * width
		if end > l {
			end = l
		}

		buffer.Write(s[start:end])
		if i < lines {
			buffer.WriteString("\n")
		}
	}
	return buffer.Bytes()
}

// SubSlice provides similar slice indexing as python with one exception
// that end could be equal to 0.
// So we could get the last element by SubSlice(s, -1, 0)
// or get the whole element by SubSlice(s, 0, 0)
func SubSlice(slice []byte, start int, end int) []byte {
	if start == 0 && end == 0 {
		return slice
	}
	if start == end || (start < 0 && end > 0) {
		return []byte{}
	}
	l := len(slice)
	s, e := start, end

	if s < 0 {
		s = l + s
		if s < 1 {
			s = 0
		}
	}
	if e < 0 {
		e = l + e
		if e < 0 {
			e = 0
		}
	}
	if e == 0 || e > l {
		e = l
	}
	return slice[s:e]
}

// ByteToLower lowers a byte
func ByteToLower(b byte) byte {
	if b <= '\u007F' {
		if 'A' <= b && b <= 'Z' {
			b += 'a' - 'A'
		}
		return b
	}
	return b
}

// ByteToUpper upper a byte
func ByteToUpper(b byte) byte {
	if b <= '\u007F' {
		if 'a' <= b && b <= 'z' {
			b -= 'a' - 'A'
		}
		return b
	}
	return b
}

// MakeQuerySlice is used to replace map.
// see: http://blog.shenwei.me/map-is-not-the-fastest-in-go/
func MakeQuerySlice(letters []byte) []byte {
	max := -1
	for i := 0; i < len(letters); i++ {
		j := int(letters[i])
		if max < j {
			max = j
		}
	}
	querySlice := make([]byte, max+1)
	for i := 0; i < len(letters); i++ {
		querySlice[int(letters[i])] = letters[i]
	}
	return querySlice
}

// Split splits a byte slice by giveen letters.
// It's much faster than regexp.Split
func Split(slice []byte, letters []byte) [][]byte {
	querySlice := MakeQuerySlice(letters)
	results := [][]byte{}
	tmp := []byte{}

	var j int
	var value byte
	var sliceSize = len(querySlice)
	for _, b := range slice {
		j = int(b)
		if j >= sliceSize { // not delimiter byte
			tmp = append(tmp, b)
			continue
		}
		value = querySlice[j]
		if value == 0 { // not delimiter byte
			tmp = append(tmp, b)
			continue
		} else {
			if len(tmp) > 0 {
				results = append(results, tmp)
				tmp = []byte{}
			}
		}
	}
	if len(tmp) > 0 {
		results = append(results, tmp)
	}
	return results
}
<commit_msg>add inplace replace reverse function<commit_after>package byteutil

import "bytes"

// ReverseByteSlice reverses a byte slice
func ReverseByteSlice(s []byte) []byte {
	// make a copy of s
	l := len(s)
	t := make([]byte, l)
	for i := 0; i < l; i++ {
		t[i] = s[i]
	}

	// reverse
	for i, j := 0, l-1; i < j; i, j = i+1, j-1 {
		t[i], t[j] = t[j], t[i]
	}
	return t
}

// ReverseByteSliceInplace reverses a byte slice
func ReverseByteSliceInplace(s []byte) {
	// reverse
	for i, j := 0, len(s)-1; i < j; i, j = i+1, j-1 {
		s[i], s[j] = s[j], s[i]
	}
}

// WrapByteSlice wraps byte slice
func WrapByteSlice(s []byte, width int) []byte {
	if width < 1 {
		return s
	}
	var buffer bytes.Buffer
	l := len(s)
	var lines int
	if l%width == 0 {
		lines = l/width - 1
	} else {
		lines = int(l / width)
	}
	var start, end int
	for i := 0; i <= lines; i++ {
		start = i * width
		end = (i + 1) * width
		if end > l {
			end = l
		}

		buffer.Write(s[start:end])
		if i < lines {
			buffer.WriteString("\n")
		}
	}
	return buffer.Bytes()
}

// SubSlice provides similar slice indexing as python with one exception
// that end could be equal to 0.
// So we could get the last element by SubSlice(s, -1, 0)
// or get the whole element by SubSlice(s, 0, 0)
func SubSlice(slice []byte, start int, end int) []byte {
	if start == 0 && end == 0 {
		return slice
	}
	if start == end || (start < 0 && end > 0) {
		return []byte{}
	}
	l := len(slice)
	s, e := start, end

	if s < 0 {
		s = l + s
		if s < 1 {
			s = 0
		}
	}
	if e < 0 {
		e = l + e
		if e < 0 {
			e = 0
		}
	}
	if e == 0 || e > l {
		e = l
	}
	return slice[s:e]
}

// ByteToLower lowers a byte
func ByteToLower(b byte) byte {
	if b <= '\u007F' {
		if 'A' <= b && b <= 'Z' {
			b += 'a' - 'A'
		}
		return b
	}
	return b
}

// ByteToUpper upper a byte
func ByteToUpper(b byte) byte {
	if b <= '\u007F' {
		if 'a' <= b && b <= 'z' {
			b -= 'a' - 'A'
		}
		return b
	}
	return b
}

// MakeQuerySlice is used to replace map.
// see: http://blog.shenwei.me/map-is-not-the-fastest-in-go/
func MakeQuerySlice(letters []byte) []byte {
	max := -1
	for i := 0; i < len(letters); i++ {
		j := int(letters[i])
		if max < j {
			max = j
		}
	}
	querySlice := make([]byte, max+1)
	for i := 0; i < len(letters); i++ {
		querySlice[int(letters[i])] = letters[i]
	}
	return querySlice
}

// Split splits a byte slice by giveen letters.
// It's much faster than regexp.Split
func Split(slice []byte, letters []byte) [][]byte {
	querySlice := MakeQuerySlice(letters)
	results := [][]byte{}
	tmp := []byte{}

	var j int
	var value byte
	var sliceSize = len(querySlice)
	for _, b := range slice {
		j = int(b)
		if j >= sliceSize { // not delimiter byte
			tmp = append(tmp, b)
			continue
		}
		value = querySlice[j]
		if value == 0 { // not delimiter byte
			tmp = append(tmp, b)
			continue
		} else {
			if len(tmp) > 0 {
				results = append(results, tmp)
				tmp = []byte{}
			}
		}
	}
	if len(tmp) > 0 {
		results = append(results, tmp)
	}
	return results
}
<|endoftext|>