<commit_before>package main

import (
	//"appengine"
	"appengine/datastore"
	"github.com/GoogleCloudPlatform/go-endpoints/endpoints"
	//"log"
	//"net/url"
	"time"
)

// API for Match
type APIMatch struct{}

// Type of Match
type Match struct {
	UID          *datastore.Key `json:"uid" datastore:"-"`
	UIDCountryA  *datastore.Key `json:"uidCountryA" `
	UIDCountryB  *datastore.Key `json:"uidCountryB" `
	UIDWinner    *datastore.Key `json:"uidWinner" `
	UIDUser      *datastore.Key `json:"uidUser" `
	Round        int            `json:"round"`
	DateCreation time.Time      `json:"dateCreation"`
}

// List of Match
type Matchs struct {
	Matchs []Match `json:"matchs"`
}

// Type that is use for creating a Match
type MatchToCreate struct {
	UIDCountryA *datastore.Key
	UIDCountryB *datastore.Key
	UIDUser     *datastore.Key
	UIDWinner   *datastore.Key
	Round       int
}

// Create allow you to create a match
// waiting for a context and all data that are editable by the client side
// give back the current created Match or an error
func (APIMatch) Create(c endpoints.Context, r *MatchToCreate) (*Match, error) {

	k := datastore.NewIncompleteKey(c, "Match", nil)

	m := &Match{
		UIDCountryA:  r.UIDCountryA,
		UIDCountryB:  r.UIDCountryB,
		UIDUser:      r.UIDUser,
		UIDWinner:    r.UIDWinner,
		Round:        r.Round,
		DateCreation: time.Now(),
	}

	k, err := datastore.Put(c, k, m)

	if err != nil {
		return nil, err
	}

	m.UID = k

	return m, nil
}

// type for upgrading a Match
type MatchToUpgrate struct {
	UID         *datastore.Key
	UIDCountryA *datastore.Key
	UIDCountryB *datastore.Key
}

// Update allow you to update a Match
// waiting for a context and all data that are editable for the client side
// give back the updated Match or an error
func (APIMatch) Update(c endpoints.Context, r *MatchToUpgrate) (*Match, error) {

	var m Match

	if err := datastore.Get(c, r.UID, &m); err == datastore.ErrNoSuchEntity {
		return nil, err
	} else if err != nil {
		return nil, err
	}

	m.UIDCountryA = r.UIDCountryA
	m.UIDCountryB = r.UIDCountryB

	_, err := datastore.Put(c, r.UID, &m)

	if err != nil {
		return nil, err
	}

	return &m, nil

}

// type for getting a Match by UID
type MatchToGet struct {
	UID *datastore.Key
}

// Get give all data from the Match
// waiting for a context and a key
// give back a Match or an error
func (APIMatch) Get(c endpoints.Context, r *MatchToGet) (*Match, error) {

	var m Match

	if err := datastore.Get(c, r.UID, &m); err == datastore.ErrNoSuchEntity {
		return nil, endpoints.NewNotFoundError("User not found")
	} else if err != nil {
		return nil, err
	}

	m.UID = r.UID

	return &m, nil

}

// List give all Matchs that are stored into the datastore
// waiting for a context
// give back a list of Matchs or an error
func (APIMatch) List(c endpoints.Context) (*Matchs, error) {

	matchs := []Match{}

	keys, err := datastore.NewQuery("Match").GetAll(c, &matchs)

	if err != nil {
		return nil, err
	}
	for i, k := range keys {
		matchs[i].UID = k
	}

	return &Matchs{matchs}, nil
}

// type for getting a Match by UID
type ListByRoundRequest struct {
	Round int
}

// List give all Matchs that are stored into the datastore
// waiting for a context
// give back a list of Matchs or an error
func (APIMatch) ListByRound(c endpoints.Context, r *ListByRoundRequest) (*Matchs, error) {

	matchs := []Match{}

	q := datastore.NewQuery("Match").Filter("Round =", r.Round)
	keys, err := q.GetAll(c, &matchs)

	if err != nil {
		return nil, err
	}

	for i, k := range keys {
		matchs[i].UID = k
	}

	return &Matchs{matchs}, nil
}

// Delete allow you to delete a Match
// waiging for a context and a Match key
// give back an error if something went wrong

/*
func (APIMatch) RandomCreate(c endpoints) Matchs {

}
*/
<commit_msg>add fields into match update<commit_after>package main

import (
	//"appengine"
	"appengine/datastore"
	"github.com/GoogleCloudPlatform/go-endpoints/endpoints"
	//"log"
	//"net/url"
	"time"
)

// API for Match
type APIMatch struct{}

// Type of Match
type Match struct {
	UID          *datastore.Key `json:"uid" datastore:"-"`
	UIDCountryA  *datastore.Key `json:"uidCountryA" `
	UIDCountryB  *datastore.Key `json:"uidCountryB" `
	UIDWinner    *datastore.Key `json:"uidWinner" `
	UIDUser      *datastore.Key `json:"uidUser" `
	Round        int            `json:"round"`
	DateCreation time.Time      `json:"dateCreation"`
}

// List of Match
type Matchs struct {
	Matchs []Match `json:"matchs"`
}

// Type that is use for creating a Match
type MatchToCreate struct {
	UIDCountryA *datastore.Key
	UIDCountryB *datastore.Key
	UIDUser     *datastore.Key
	UIDWinner   *datastore.Key
	Round       int
}

// Create allow you to create a match
// waiting for a context and all data that are editable by the client side
// give back the current created Match or an error
func (APIMatch) Create(c endpoints.Context, r *MatchToCreate) (*Match, error) {

	k := datastore.NewIncompleteKey(c, "Match", nil)

	m := &Match{
		UIDCountryA:  r.UIDCountryA,
		UIDCountryB:  r.UIDCountryB,
		UIDUser:      r.UIDUser,
		UIDWinner:    r.UIDWinner,
		Round:        r.Round,
		DateCreation: time.Now(),
	}

	k, err := datastore.Put(c, k, m)

	if err != nil {
		return nil, err
	}

	m.UID = k

	return m, nil
}

// type for upgrading a Match
type MatchToUpdate struct {
	UID         *datastore.Key
	UIDCountryA *datastore.Key
	UIDCountryB *datastore.Key
	UIDWinner   *datastore.Key
	UIDUser     *datastore.Key
	Round       int
}

// Update allow you to update a Match
// waiting for a context and all data that are editable for the client side
// give back the updated Match or an error
func (APIMatch) Update(c endpoints.Context, r *MatchToUpdate) (*Match, error) {

	var m Match

	if err := datastore.Get(c, r.UID, &m); err == datastore.ErrNoSuchEntity {
		return nil, err
	} else if err != nil {
		return nil, err
	}

	m.UIDCountryA = r.UIDCountryA
	m.UIDCountryB = r.UIDCountryB
	m.UIDWinner = r.UIDWinner
	m.UIDUser = r.UIDUser
	m.Round = r.Round

	_, err := datastore.Put(c, r.UID, &m)

	if err != nil {
		return nil, err
	}

	return &m, nil

}

// type for getting a Match by UID
type MatchToGet struct {
	UID *datastore.Key
}

// Get give all data from the Match
// waiting for a context and a key
// give back a Match or an error
func (APIMatch) Get(c endpoints.Context, r *MatchToGet) (*Match, error) {

	var m Match

	if err := datastore.Get(c, r.UID, &m); err == datastore.ErrNoSuchEntity {
		return nil, endpoints.NewNotFoundError("User not found")
	} else if err != nil {
		return nil, err
	}

	m.UID = r.UID

	return &m, nil

}

// List give all Matchs that are stored into the datastore
// waiting for a context
// give back a list of Matchs or an error
func (APIMatch) List(c endpoints.Context) (*Matchs, error) {

	matchs := []Match{}

	keys, err := datastore.NewQuery("Match").GetAll(c, &matchs)

	if err != nil {
		return nil, err
	}
	for i, k := range keys {
		matchs[i].UID = k
	}

	return &Matchs{matchs}, nil
}

// type for getting a Match by UID
type ListByRoundRequest struct {
	Round int
}

// List give all Matchs that are stored into the datastore
// waiting for a context
// give back a list of Matchs or an error
func (APIMatch) ListByRound(c endpoints.Context, r *ListByRoundRequest) (*Matchs, error) {

	matchs := []Match{}

	q := datastore.NewQuery("Match").Filter("Round =", r.Round)
	keys, err := q.GetAll(c, &matchs)

	if err != nil {
		return nil, err
	}

	for i, k := range keys {
		matchs[i].UID = k
	}

	return &Matchs{matchs}, nil
}

// Delete allow you to delete a Match
// waiging for a context and a Match key
// give back an error if something went wrong

/*
func (APIMatch) RandomCreate(c endpoints) Matchs {

}
*/
<|endoftext|>


<commit_before>package bot

import (
	"fmt"
	"strings"

	"github.com/svenwiltink/go-musicbot/pkg/music"
	"strconv"
	"time"
)

type Command struct {
	Name       string
	MasterOnly bool
	Function   func(bot *MusicBot, message Message)
}

var helpCommand = Command{
	Name: "help",
	Function: func(bot *MusicBot, message Message) {
		helpString := "Available commands: "
		for _, command := range bot.commands {
			helpString += command.Name + " "
		}

		bot.ReplyToMessage(message, helpString)
	},
}

var addCommand = Command{
	Name: "add",
	Function: func(bot *MusicBot, message Message) {
		words := strings.SplitN(message.Message, " ", 3)
		if len(words) <= 2 {
			bot.ReplyToMessage(message, "No song provided")
			return
		}

		song := music.Song{
			Path: strings.TrimSpace(words[2]),
		}

		song, err := bot.musicPlayer.AddSong(song)
		if err != nil {
			bot.ReplyToMessage(message, err.Error())
			return
		}

		if message.IsPrivate {
			bot.BroadcastMessage(fmt.Sprintf("%s: %s added by %s", song.Artist, song.Name, message.Sender.NickName))
		}
		bot.ReplyToMessage(message, fmt.Sprintf("%s: %s added", song.Artist, song.Name))

	},
}

var searchCommand = Command{
	Name: "search",
	Function: func(bot *MusicBot, message Message) {
		words := strings.SplitN(message.Message, " ", 3)
		if len(words) <= 2 {
			bot.ReplyToMessage(message, "No song provided")
			return
		}

		songs, err := bot.musicPlayer.Search(words[2])

		if err != nil {
			bot.ReplyToMessage(message, fmt.Sprintf("error: %v", err))
		}

		if len(songs) == 0 {
			bot.ReplyToMessage(message, "No song found")
			return
		}

		var builder strings.Builder

		for number, song := range songs {
			builder.WriteString(fmt.Sprintf("%d  %s - %s (%s)\n", number+1, song.Artist, song.Name, song.Duration))
		}

		bot.ReplyToMessage(message, builder.String())

	},
}

var searchAddCommand = Command{
	Name: "search-add",
	Function: func(bot *MusicBot, message Message) {
		words := strings.SplitN(message.Message, " ", 3)
		if len(words) <= 2 {
			bot.ReplyToMessage(message, "No song provided")
			return
		}

		songs, err := bot.musicPlayer.Search(words[2])

		if err != nil {
			bot.ReplyToMessage(message, fmt.Sprintf("error: %v", err))
		}

		if len(songs) == 0 {
			bot.ReplyToMessage(message, "No song found")
			return
		}

		song := songs[0]
		song, err = bot.musicPlayer.AddSong(song)

		if err != nil {
			bot.ReplyToMessage(message, fmt.Sprintf("Error: %v", err))
			return
		}

		if message.IsPrivate {
			bot.BroadcastMessage(fmt.Sprintf("%s: %s added by %s", song.Artist, song.Name, message.Sender.NickName))
		}

		bot.ReplyToMessage(message, fmt.Sprintf("%s: %s added", song.Artist, song.Name))
	},
}

var nextCommand = Command{
	Name: "next",
	Function: func(bot *MusicBot, message Message) {
		err := bot.musicPlayer.Next()
		if err != nil {
			bot.ReplyToMessage(message, fmt.Sprintf("Could not skip song: %v", err))
		} else {
			if message.IsPrivate {
				bot.BroadcastMessage(fmt.Sprintf("%s skipped the song", message.Sender.NickName))
			}
			bot.ReplyToMessage(message, "Skipping song")
		}
	},
}

var pausedCommand = Command{
	Name: "pause",
	Function: func(bot *MusicBot, message Message) {
		err := bot.musicPlayer.Pause()
		if err != nil {
			bot.ReplyToMessage(message, fmt.Sprintf("Error: %v", err))
			return
		}

		if message.IsPrivate {
			bot.BroadcastMessage(fmt.Sprintf("%s stopped the music", message.Sender.NickName))
		}

		bot.ReplyToMessage(message, "Music paused")

	},
}

var playCommand = Command{
	Name: "play",
	Function: func(bot *MusicBot, message Message) {
		err := bot.musicPlayer.Play()
		if err != nil {
			bot.ReplyToMessage(message, fmt.Sprintf("Error: %v", err))
			return
		}

		if message.IsPrivate {
			bot.BroadcastMessage(fmt.Sprintf("%s resumed the music", message.Sender.NickName))
		}

		bot.ReplyToMessage(message, "Music resumed")

	},
}

var currentCommand = Command{
	Name: "current",
	Function: func(bot *MusicBot, message Message) {
		song, durationLeft := bot.musicPlayer.GetCurrentSong()
		if song == nil {
			bot.ReplyToMessage(message, "Nothing currently playing")
			return
		}

		if song.SongType == music.SongTypeSong {
			bot.ReplyToMessage(
				message,
				fmt.Sprintf("Current song: %s %s. %s remaining (%s)", song.Artist, song.Name, durationLeft.String(), song.Duration.Round(time.Second).String()))
		} else {
			bot.ReplyToMessage(
				message,
				fmt.Sprintf("Current song: %s %s. This is a livestream, use the next command to skip", song.Artist, song.Name))
		}
	},
}

var queueCommand = Command{
	Name: "queue",
	Function: func(bot *MusicBot, message Message) {
		queue := bot.GetMusicPlayer().GetQueue()

		queueLength := queue.GetLength()
		nextSongs, _ := queue.GetNextN(5)
		duration := queue.GetTotalDuration()

		bot.ReplyToMessage(message, fmt.Sprintf("%d songs in the queue. Total duration %s", queueLength, duration.String()))

		for index, song := range nextSongs {
			bot.ReplyToMessage(message, fmt.Sprintf("#%d, %s: %s (%s)\n", index+1, song.Artist, song.Name, song.Duration.String()))
		}

		if queueLength > 5 {
			bot.ReplyToMessage(message, fmt.Sprintf("and %d more", queueLength-5))
		}

	},
}

var flushCommand = Command{
	Name: "flush",
	Function: func(bot *MusicBot, message Message) {
		bot.musicPlayer.GetQueue().Flush()

		if message.IsPrivate {
			bot.BroadcastMessage(fmt.Sprintf("%s flushed the queue", message.Sender.NickName))
		}

		bot.ReplyToMessage(message, "Queue flushed")
	},
}

var shuffleCommand = Command{
	Name: "shuffle",
	Function: func(bot *MusicBot, message Message) {
		bot.musicPlayer.GetQueue().Shuffle()

		if message.IsPrivate {
			bot.BroadcastMessage(fmt.Sprintf("%s shuffled the queue", message.Sender.NickName))
		}

		bot.ReplyToMessage(message, "Queue shuffled")
	},
}

var whiteListCommand = Command{
	Name:       "whitelist",
	MasterOnly: true,
	Function: func(bot *MusicBot, message Message) {
		words := strings.SplitN(message.Message, " ", 4)
		if len(words) <= 3 {
			bot.ReplyToMessage(message, "whitelist <add|remove> <name>")
			return
		}

		name := strings.TrimSpace(words[3])
		if len(name) == 0 {
			bot.ReplyToMessage(message, "whitelist <add|remove> <name>")
			return
		}

		if words[2] == "add" {
			err := bot.whitelist.Add(name)
			if err == nil {
				bot.ReplyToMessage(message, fmt.Sprintf("added %s to the whitelist", name))
			} else {
				bot.ReplyToMessage(message, fmt.Sprintf("error: %v", err))
			}
		} else if words[2] == "remove" {
			err := bot.whitelist.Remove(name)
			if err == nil {
				bot.ReplyToMessage(message, fmt.Sprintf("removed %s from the whitelist", name))
			} else {
				bot.ReplyToMessage(message, fmt.Sprintf("error: %v", err))
			}
		} else {
			bot.ReplyToMessage(message, "whitelist <add|remove> <name>")
			return
		}
	},
}

var volCommand = Command{
	Name: "vol",
	Function: func(bot *MusicBot, message Message) {
		words := strings.SplitN(message.Message, " ", 3)

		if len(words) == 2 {
			volume, err := bot.musicPlayer.GetVolume()

			if err != nil {
				bot.ReplyToMessage(message, fmt.Sprintf("unable to get volume: %v", err))
				return
			}

			bot.ReplyToMessage(message, fmt.Sprintf("Current volume: %d", volume))
			return
		}

		// init vars here so we can use them after the switch statement
		volumeString := strings.TrimSpace(words[2])
		var volume int
		var err error

		switch volumeString {
		case "++":
			{
				volume, err = bot.musicPlayer.IncreaseVolume(10)
				if err != nil {
					bot.ReplyToMessage(message, fmt.Sprintf("unable to increase volume: %s", err))
					return
				}
			}
		case "--":
			{
				volume, err = bot.musicPlayer.DecreaseVolume(10)
				if err != nil {
					bot.ReplyToMessage(message, fmt.Sprintf("unable to decrease volume: %s", err))
					return
				}
			}
		default:
			{
				volume, err = strconv.Atoi(strings.TrimSpace(volumeString))

				if err != nil {
					bot.ReplyToMessage(message, fmt.Sprintf("%s is not a valid number", volumeString))
					return
				}

				if volume >= 0 && volume <= 100 {
					bot.musicPlayer.SetVolume(volume)
				} else {
					bot.ReplyToMessage(message, fmt.Sprintf("%s is not a valid volume", volumeString))
					return
				}
			}
		}

		if message.IsPrivate {
			bot.BroadcastMessage(fmt.Sprintf("Volume set to %d by %s", volume, message.Sender.NickName))
		}

		bot.ReplyToMessage(message, fmt.Sprintf("Volume set to %d", volume))
	},
}

var aboutCommand = Command{
	Name: "about",
	Function: func(bot *MusicBot, message Message) {
		bot.ReplyToMessage(message, "go-MusicBot by Sven Wiltink: https://github.com/svenwiltink/go-MusicBot")
		bot.ReplyToMessage(message, fmt.Sprintf("Version: %s", Version))
		bot.ReplyToMessage(message, fmt.Sprintf("Go: %s", GoVersion))
		bot.ReplyToMessage(message, fmt.Sprintf("Build date: %s", BuildDate))
	},
}
<commit_msg>use Name instead of Nickname because there can be duplicates (#70)<commit_after>package bot

import (
	"fmt"
	"strings"

	"github.com/svenwiltink/go-musicbot/pkg/music"
	"strconv"
	"time"
)

type Command struct {
	Name       string
	MasterOnly bool
	Function   func(bot *MusicBot, message Message)
}

var helpCommand = Command{
	Name: "help",
	Function: func(bot *MusicBot, message Message) {
		helpString := "Available commands: "
		for _, command := range bot.commands {
			helpString += command.Name + " "
		}

		bot.ReplyToMessage(message, helpString)
	},
}

var addCommand = Command{
	Name: "add",
	Function: func(bot *MusicBot, message Message) {
		words := strings.SplitN(message.Message, " ", 3)
		if len(words) <= 2 {
			bot.ReplyToMessage(message, "No song provided")
			return
		}

		song := music.Song{
			Path: strings.TrimSpace(words[2]),
		}

		song, err := bot.musicPlayer.AddSong(song)
		if err != nil {
			bot.ReplyToMessage(message, err.Error())
			return
		}

		if message.IsPrivate {
			bot.BroadcastMessage(fmt.Sprintf("%s: %s added by %s", song.Artist, song.Name, message.Sender.Name))
		}
		bot.ReplyToMessage(message, fmt.Sprintf("%s: %s added", song.Artist, song.Name))

	},
}

var searchCommand = Command{
	Name: "search",
	Function: func(bot *MusicBot, message Message) {
		words := strings.SplitN(message.Message, " ", 3)
		if len(words) <= 2 {
			bot.ReplyToMessage(message, "No song provided")
			return
		}

		songs, err := bot.musicPlayer.Search(words[2])

		if err != nil {
			bot.ReplyToMessage(message, fmt.Sprintf("error: %v", err))
		}

		if len(songs) == 0 {
			bot.ReplyToMessage(message, "No song found")
			return
		}

		var builder strings.Builder

		for number, song := range songs {
			builder.WriteString(fmt.Sprintf("%d  %s - %s (%s)\n", number+1, song.Artist, song.Name, song.Duration))
		}

		bot.ReplyToMessage(message, builder.String())

	},
}

var searchAddCommand = Command{
	Name: "search-add",
	Function: func(bot *MusicBot, message Message) {
		words := strings.SplitN(message.Message, " ", 3)
		if len(words) <= 2 {
			bot.ReplyToMessage(message, "No song provided")
			return
		}

		songs, err := bot.musicPlayer.Search(words[2])

		if err != nil {
			bot.ReplyToMessage(message, fmt.Sprintf("error: %v", err))
		}

		if len(songs) == 0 {
			bot.ReplyToMessage(message, "No song found")
			return
		}

		song := songs[0]
		song, err = bot.musicPlayer.AddSong(song)

		if err != nil {
			bot.ReplyToMessage(message, fmt.Sprintf("Error: %v", err))
			return
		}

		if message.IsPrivate {
			bot.BroadcastMessage(fmt.Sprintf("%s: %s added by %s", song.Artist, song.Name, message.Sender.Name))
		}

		bot.ReplyToMessage(message, fmt.Sprintf("%s: %s added", song.Artist, song.Name))
	},
}

var nextCommand = Command{
	Name: "next",
	Function: func(bot *MusicBot, message Message) {
		err := bot.musicPlayer.Next()
		if err != nil {
			bot.ReplyToMessage(message, fmt.Sprintf("Could not skip song: %v", err))
		} else {
			if message.IsPrivate {
				bot.BroadcastMessage(fmt.Sprintf("%s skipped the song", message.Sender.Name))
			}
			bot.ReplyToMessage(message, "Skipping song")
		}
	},
}

var pausedCommand = Command{
	Name: "pause",
	Function: func(bot *MusicBot, message Message) {
		err := bot.musicPlayer.Pause()
		if err != nil {
			bot.ReplyToMessage(message, fmt.Sprintf("Error: %v", err))
			return
		}

		if message.IsPrivate {
			bot.BroadcastMessage(fmt.Sprintf("%s stopped the music", message.Sender.Name))
		}

		bot.ReplyToMessage(message, "Music paused")

	},
}

var playCommand = Command{
	Name: "play",
	Function: func(bot *MusicBot, message Message) {
		err := bot.musicPlayer.Play()
		if err != nil {
			bot.ReplyToMessage(message, fmt.Sprintf("Error: %v", err))
			return
		}

		if message.IsPrivate {
			bot.BroadcastMessage(fmt.Sprintf("%s resumed the music", message.Sender.Name))
		}

		bot.ReplyToMessage(message, "Music resumed")

	},
}

var currentCommand = Command{
	Name: "current",
	Function: func(bot *MusicBot, message Message) {
		song, durationLeft := bot.musicPlayer.GetCurrentSong()
		if song == nil {
			bot.ReplyToMessage(message, "Nothing currently playing")
			return
		}

		if song.SongType == music.SongTypeSong {
			bot.ReplyToMessage(
				message,
				fmt.Sprintf("Current song: %s %s. %s remaining (%s)", song.Artist, song.Name, durationLeft.String(), song.Duration.Round(time.Second).String()))
		} else {
			bot.ReplyToMessage(
				message,
				fmt.Sprintf("Current song: %s %s. This is a livestream, use the next command to skip", song.Artist, song.Name))
		}
	},
}

var queueCommand = Command{
	Name: "queue",
	Function: func(bot *MusicBot, message Message) {
		queue := bot.GetMusicPlayer().GetQueue()

		queueLength := queue.GetLength()
		nextSongs, _ := queue.GetNextN(5)
		duration := queue.GetTotalDuration()

		bot.ReplyToMessage(message, fmt.Sprintf("%d songs in the queue. Total duration %s", queueLength, duration.String()))

		for index, song := range nextSongs {
			bot.ReplyToMessage(message, fmt.Sprintf("#%d, %s: %s (%s)\n", index+1, song.Artist, song.Name, song.Duration.String()))
		}

		if queueLength > 5 {
			bot.ReplyToMessage(message, fmt.Sprintf("and %d more", queueLength-5))
		}

	},
}

var flushCommand = Command{
	Name: "flush",
	Function: func(bot *MusicBot, message Message) {
		bot.musicPlayer.GetQueue().Flush()

		if message.IsPrivate {
			bot.BroadcastMessage(fmt.Sprintf("%s flushed the queue", message.Sender.Name))
		}

		bot.ReplyToMessage(message, "Queue flushed")
	},
}

var shuffleCommand = Command{
	Name: "shuffle",
	Function: func(bot *MusicBot, message Message) {
		bot.musicPlayer.GetQueue().Shuffle()

		if message.IsPrivate {
			bot.BroadcastMessage(fmt.Sprintf("%s shuffled the queue", message.Sender.Name))
		}

		bot.ReplyToMessage(message, "Queue shuffled")
	},
}

var whiteListCommand = Command{
	Name:       "whitelist",
	MasterOnly: true,
	Function: func(bot *MusicBot, message Message) {
		words := strings.SplitN(message.Message, " ", 4)
		if len(words) <= 3 {
			bot.ReplyToMessage(message, "whitelist <add|remove> <name>")
			return
		}

		name := strings.TrimSpace(words[3])
		if len(name) == 0 {
			bot.ReplyToMessage(message, "whitelist <add|remove> <name>")
			return
		}

		if words[2] == "add" {
			err := bot.whitelist.Add(name)
			if err == nil {
				bot.ReplyToMessage(message, fmt.Sprintf("added %s to the whitelist", name))
			} else {
				bot.ReplyToMessage(message, fmt.Sprintf("error: %v", err))
			}
		} else if words[2] == "remove" {
			err := bot.whitelist.Remove(name)
			if err == nil {
				bot.ReplyToMessage(message, fmt.Sprintf("removed %s from the whitelist", name))
			} else {
				bot.ReplyToMessage(message, fmt.Sprintf("error: %v", err))
			}
		} else {
			bot.ReplyToMessage(message, "whitelist <add|remove> <name>")
			return
		}
	},
}

var volCommand = Command{
	Name: "vol",
	Function: func(bot *MusicBot, message Message) {
		words := strings.SplitN(message.Message, " ", 3)

		if len(words) == 2 {
			volume, err := bot.musicPlayer.GetVolume()

			if err != nil {
				bot.ReplyToMessage(message, fmt.Sprintf("unable to get volume: %v", err))
				return
			}

			bot.ReplyToMessage(message, fmt.Sprintf("Current volume: %d", volume))
			return
		}

		// init vars here so we can use them after the switch statement
		volumeString := strings.TrimSpace(words[2])
		var volume int
		var err error

		switch volumeString {
		case "++":
			{
				volume, err = bot.musicPlayer.IncreaseVolume(10)
				if err != nil {
					bot.ReplyToMessage(message, fmt.Sprintf("unable to increase volume: %s", err))
					return
				}
			}
		case "--":
			{
				volume, err = bot.musicPlayer.DecreaseVolume(10)
				if err != nil {
					bot.ReplyToMessage(message, fmt.Sprintf("unable to decrease volume: %s", err))
					return
				}
			}
		default:
			{
				volume, err = strconv.Atoi(strings.TrimSpace(volumeString))

				if err != nil {
					bot.ReplyToMessage(message, fmt.Sprintf("%s is not a valid number", volumeString))
					return
				}

				if volume >= 0 && volume <= 100 {
					bot.musicPlayer.SetVolume(volume)
				} else {
					bot.ReplyToMessage(message, fmt.Sprintf("%s is not a valid volume", volumeString))
					return
				}
			}
		}

		if message.IsPrivate {
			bot.BroadcastMessage(fmt.Sprintf("Volume set to %d by %s", volume, message.Sender.Name))
		}

		bot.ReplyToMessage(message, fmt.Sprintf("Volume set to %d", volume))
	},
}

var aboutCommand = Command{
	Name: "about",
	Function: func(bot *MusicBot, message Message) {
		bot.ReplyToMessage(message, "go-MusicBot by Sven Wiltink: https://github.com/svenwiltink/go-MusicBot")
		bot.ReplyToMessage(message, fmt.Sprintf("Version: %s", Version))
		bot.ReplyToMessage(message, fmt.Sprintf("Go: %s", GoVersion))
		bot.ReplyToMessage(message, fmt.Sprintf("Build date: %s", BuildDate))
	},
}
<|endoftext|>


<commit_before>// SPDX-License-Identifier: Apache-2.0
// Copyright 2018-2019 Authors of Cilium

package ipcache

import (
	"context"
	"fmt"
	"net"
	"strings"

	"github.com/cilium/cilium/pkg/identity"
	"github.com/cilium/cilium/pkg/identity/cache"
	"github.com/cilium/cilium/pkg/ip"
	"github.com/cilium/cilium/pkg/labels"
	"github.com/cilium/cilium/pkg/labels/cidr"
	"github.com/cilium/cilium/pkg/logging/logfields"
	"github.com/cilium/cilium/pkg/option"
	"github.com/cilium/cilium/pkg/source"

	"github.com/sirupsen/logrus"
)

var (
	// IdentityAllocator is a package-level variable which is used to allocate
	// identities for CIDRs.
	// TODO: plumb an allocator in from callers of these functions vs. having
	// this as a package-level variable.
	IdentityAllocator cache.IdentityAllocator
)

// AllocateCIDRs attempts to allocate identities for a list of CIDRs. If any
// allocation fails, all allocations are rolled back and the error is returned.
// When an identity is freshly allocated for a CIDR, it is added to the
// ipcache if 'newlyAllocatedIdentities' is 'nil', otherwise the newly allocated
// identities are placed in 'newlyAllocatedIdentities' and it is the caller's
// responsibility to upsert them into ipcache by calling UpsertGeneratedIdentities().
//
// Upon success, the caller must also arrange for the resulting identities to
// be released via a subsequent call to ReleaseCIDRIdentitiesByCIDR().
func AllocateCIDRs(prefixes []*net.IPNet, newlyAllocatedIdentities map[string]*identity.Identity) ([]*identity.Identity, error) {
	return allocateCIDRs(prefixes, newlyAllocatedIdentities)
}

// AllocateCIDRsForIPs attempts to allocate identities for a list of CIDRs. If
// any allocation fails, all allocations are rolled back and the error is
// returned. When an identity is freshly allocated for a CIDR, it is added to
// the ipcache if 'newlyAllocatedIdentities' is 'nil', otherwise the newly allocated
// identities are placed in 'newlyAllocatedIdentities' and it is the caller's
// responsibility to upsert them into ipcache by calling UpsertGeneratedIdentities().
//
// Upon success, the caller must also arrange for the resulting identities to
// be released via a subsequent call to ReleaseCIDRIdentitiesByID().
func AllocateCIDRsForIPs(prefixes []net.IP, newlyAllocatedIdentities map[string]*identity.Identity) ([]*identity.Identity, error) {
	return allocateCIDRs(ip.GetCIDRPrefixesFromIPs(prefixes), newlyAllocatedIdentities)
}

func UpsertGeneratedIdentities(newlyAllocatedIdentities map[string]*identity.Identity) {
	for prefixString, id := range newlyAllocatedIdentities {
		IPIdentityCache.Upsert(prefixString, nil, 0, nil, Identity{
			ID:     id.ID,
			Source: source.Generated,
		})
	}
}

func allocateCIDRs(prefixes []*net.IPNet, newlyAllocatedIdentities map[string]*identity.Identity) ([]*identity.Identity, error) {
	// maintain list of used identities to undo on error
	usedIdentities := make([]*identity.Identity, 0, len(prefixes))

	allocatedIdentities := make(map[string]*identity.Identity, len(prefixes))
	// Maintain list of newly allocated identities to update ipcache,
	// but upsert them to ipcache only if no map was given by the caller.
	upsert := false
	if newlyAllocatedIdentities == nil {
		upsert = true
		newlyAllocatedIdentities = map[string]*identity.Identity{}
	}

	for _, prefix := range prefixes {
		if prefix == nil {
			continue
		}

		prefixStr := prefix.String()

		// Figure out if this call needs to be able to update the selector cache synchronously.
		allocateCtx, cancel := context.WithTimeout(context.Background(), option.Config.IPAllocationTimeout)
		defer cancel()

		if IdentityAllocator == nil {
			return nil, fmt.Errorf("IdentityAllocator not initialized!")
		}

		id, isNew, err := IdentityAllocator.AllocateIdentity(allocateCtx, cidr.GetCIDRLabels(prefix), false)
		if err != nil {
			IdentityAllocator.ReleaseSlice(context.Background(), nil, usedIdentities)
			return nil, fmt.Errorf("failed to allocate identity for cidr %s: %s", prefixStr, err)
		}

		id.CIDRLabel = labels.NewLabelsFromModel([]string{labels.LabelSourceCIDR + ":" + prefixStr})

		usedIdentities = append(usedIdentities, id)
		allocatedIdentities[prefixStr] = id
		if isNew {
			newlyAllocatedIdentities[prefixStr] = id
		}
	}

	allocatedIdentitiesSlice := make([]*identity.Identity, 0, len(allocatedIdentities))

	// Only upsert into ipcache if identity wasn't allocated
	// before and the caller does not care doing this
	if upsert {
		UpsertGeneratedIdentities(newlyAllocatedIdentities)
	}

	for _, id := range allocatedIdentities {
		allocatedIdentitiesSlice = append(allocatedIdentitiesSlice, id)
	}

	return allocatedIdentitiesSlice, nil
}

func releaseCIDRIdentities(ctx context.Context, identities map[string]*identity.Identity) {
	for prefix, id := range identities {
		released, err := IdentityAllocator.Release(ctx, id)
		if err != nil {
			log.WithFields(logrus.Fields{
				logfields.Identity: id,
				logfields.CIDR:     prefix,
			}).WithError(err).Warning("Unable to release CIDR identity. Ignoring error. Identity may be leaked")
		}

		if released {
			IPIdentityCache.Delete(prefix, source.Generated)
		}
	}
}

// ReleaseCIDRIdentitiesByCIDR releases the identities of a list of CIDRs.
// When the last use of the identity is released, the ipcache entry is deleted.
func ReleaseCIDRIdentitiesByCIDR(prefixes []*net.IPNet) {
	// TODO: Structure the code to pass context down from the Daemon.
	releaseCtx, cancel := context.WithTimeout(context.TODO(), option.Config.KVstoreConnectivityTimeout)
	defer cancel()

	identities := make(map[string]*identity.Identity, len(prefixes))
	for _, prefix := range prefixes {
		if prefix == nil {
			continue
		}

		if id := IdentityAllocator.LookupIdentity(releaseCtx, cidr.GetCIDRLabels(prefix)); id != nil {
			identities[prefix.String()] = id
		} else {
			log.Errorf("Unable to find identity of previously used CIDR %s", prefix.String())
		}
	}

	releaseCIDRIdentities(releaseCtx, identities)
}

// ReleaseCIDRIdentitiesByID releases the specified identities.
// When the last use of the identity is released, the ipcache entry is deleted.
func ReleaseCIDRIdentitiesByID(ctx context.Context, identities []identity.NumericIdentity) {
	fullIdentities := make(map[string]*identity.Identity, len(identities))
	for _, nid := range identities {
		if id := IdentityAllocator.LookupIdentityByID(ctx, nid); id != nil {
			cidr := id.CIDRLabel.String()
			if !strings.HasPrefix(cidr, labels.LabelSourceCIDR) {
				log.WithFields(logrus.Fields{
					logfields.Identity: nid,
					logfields.Labels:   id.Labels,
				}).Warn("Unexpected release of non-CIDR identity, will leak this identity. Please report this issue to the developers.")
				continue
			}
			fullIdentities[strings.TrimPrefix(cidr, labels.LabelSourceCIDR+":")] = id
		} else {
			log.WithFields(logrus.Fields{
				logfields.Identity: nid,
			}).Warn("Unexpected release of numeric identity that is no longer allocated")
		}
	}

	releaseCIDRIdentities(ctx, fullIdentities)
}
<commit_msg>ipcache: Refactor CIDR identity allocation to accept labels from caller<commit_after>// SPDX-License-Identifier: Apache-2.0
// Copyright 2018-2019 Authors of Cilium

package ipcache

import (
	"context"
	"fmt"
	"net"
	"strings"

	"github.com/cilium/cilium/pkg/identity"
	"github.com/cilium/cilium/pkg/identity/cache"
	"github.com/cilium/cilium/pkg/ip"
	"github.com/cilium/cilium/pkg/labels"
	"github.com/cilium/cilium/pkg/labels/cidr"
	"github.com/cilium/cilium/pkg/logging/logfields"
	"github.com/cilium/cilium/pkg/option"
	"github.com/cilium/cilium/pkg/source"

	"github.com/sirupsen/logrus"
)

var (
	// IdentityAllocator is a package-level variable which is used to allocate
	// identities for CIDRs.
	// TODO: plumb an allocator in from callers of these functions vs. having
	// this as a package-level variable.
	IdentityAllocator cache.IdentityAllocator
)

// AllocateCIDRs attempts to allocate identities for a list of CIDRs. If any
// allocation fails, all allocations are rolled back and the error is returned.
// When an identity is freshly allocated for a CIDR, it is added to the
// ipcache if 'newlyAllocatedIdentities' is 'nil', otherwise the newly allocated
// identities are placed in 'newlyAllocatedIdentities' and it is the caller's
// responsibility to upsert them into ipcache by calling UpsertGeneratedIdentities().
//
// Upon success, the caller must also arrange for the resulting identities to
// be released via a subsequent call to ReleaseCIDRIdentitiesByCIDR().
func AllocateCIDRs(
	prefixes []*net.IPNet, newlyAllocatedIdentities map[string]*identity.Identity,
) ([]*identity.Identity, error) {
	// maintain list of used identities to undo on error
	usedIdentities := make([]*identity.Identity, 0, len(prefixes))

	// Maintain list of newly allocated identities to update ipcache,
	// but upsert them to ipcache only if no map was given by the caller.
	upsert := false
	if newlyAllocatedIdentities == nil {
		upsert = true
		newlyAllocatedIdentities = map[string]*identity.Identity{}
	}

	allocatedIdentities := make(map[string]*identity.Identity, len(prefixes))
	for _, p := range prefixes {
		if p == nil {
			continue
		}

		prefixStr := p.String()

		id, isNew, err := allocate(prefixStr, cidr.GetCIDRLabels(p))
		if err != nil {
			IdentityAllocator.ReleaseSlice(context.Background(), nil, usedIdentities)
			return nil, err
		}

		usedIdentities = append(usedIdentities, id)
		allocatedIdentities[prefixStr] = id
		if isNew {
			newlyAllocatedIdentities[prefixStr] = id
		}
	}

	// Only upsert into ipcache if identity wasn't allocated
	// before and the caller does not care doing this
	if upsert {
		UpsertGeneratedIdentities(newlyAllocatedIdentities)
	}

	identities := make([]*identity.Identity, 0, len(allocatedIdentities))
	for _, id := range allocatedIdentities {
		identities = append(identities, id)
	}
	return identities, nil
}

// AllocateCIDRsForIPs performs the same action as AllocateCIDRs but for IP
// addresses instead of CIDRs.
//
// Upon success, the caller must also arrange for the resulting identities to
// be released via a subsequent call to ReleaseCIDRIdentitiesByID().
func AllocateCIDRsForIPs(
	prefixes []net.IP, newlyAllocatedIdentities map[string]*identity.Identity,
) ([]*identity.Identity, error) {
	return AllocateCIDRs(ip.GetCIDRPrefixesFromIPs(prefixes), newlyAllocatedIdentities)
}

func UpsertGeneratedIdentities(newlyAllocatedIdentities map[string]*identity.Identity) {
	for prefixString, id := range newlyAllocatedIdentities {
		IPIdentityCache.Upsert(prefixString, nil, 0, nil, Identity{
			ID:     id.ID,
			Source: source.Generated,
		})
	}
}

func allocate(prefix string, lbls labels.Labels) (*identity.Identity, bool, error) {
	allocateCtx, cancel := context.WithTimeout(context.Background(), option.Config.IPAllocationTimeout)
	defer cancel()

	id, isNew, err := IdentityAllocator.AllocateIdentity(allocateCtx, lbls, false)
	if err != nil {
		return nil, isNew, fmt.Errorf("failed to allocate identity for cidr %s: %s", prefix, err)
	}

	if lbls.Has(labels.LabelWorld[labels.IDNameWorld]) {
		id.CIDRLabel = labels.NewLabelsFromModel([]string{labels.LabelSourceCIDR + ":" + prefix})
	}

	return id, isNew, err
}

func releaseCIDRIdentities(ctx context.Context, identities map[string]*identity.Identity) {
	for prefix, id := range identities {
		released, err := IdentityAllocator.Release(ctx, id)
		if err != nil {
			log.WithFields(logrus.Fields{
				logfields.Identity: id,
				logfields.CIDR:     prefix,
			}).WithError(err).Warning("Unable to release CIDR identity. Ignoring error. Identity may be leaked")
		}

		if released {
			IPIdentityCache.Delete(prefix, source.Generated)
		}
	}
}

// ReleaseCIDRIdentitiesByCIDR releases the identities of a list of CIDRs.
// When the last use of the identity is released, the ipcache entry is deleted.
func ReleaseCIDRIdentitiesByCIDR(prefixes []*net.IPNet) {
	// TODO: Structure the code to pass context down from the Daemon.
	releaseCtx, cancel := context.WithTimeout(context.TODO(), option.Config.KVstoreConnectivityTimeout)
	defer cancel()

	identities := make(map[string]*identity.Identity, len(prefixes))
	for _, prefix := range prefixes {
		if prefix == nil {
			continue
		}

		if id := IdentityAllocator.LookupIdentity(releaseCtx, cidr.GetCIDRLabels(prefix)); id != nil {
			identities[prefix.String()] = id
		} else {
			log.Errorf("Unable to find identity of previously used CIDR %s", prefix.String())
		}
	}

	releaseCIDRIdentities(releaseCtx, identities)
}

// ReleaseCIDRIdentitiesByID releases the specified identities.
// When the last use of the identity is released, the ipcache entry is deleted.
func ReleaseCIDRIdentitiesByID(ctx context.Context, identities []identity.NumericIdentity) {
	fullIdentities := make(map[string]*identity.Identity, len(identities))
	for _, nid := range identities {
		if id := IdentityAllocator.LookupIdentityByID(ctx, nid); id != nil {
			cidr := id.CIDRLabel.String()
			if !strings.HasPrefix(cidr, labels.LabelSourceCIDR) {
				log.WithFields(logrus.Fields{
					logfields.Identity: nid,
					logfields.Labels:   id.Labels,
				}).Warn("Unexpected release of non-CIDR identity, will leak this identity. Please report this issue to the developers.")
				continue
			}
			fullIdentities[strings.TrimPrefix(cidr, labels.LabelSourceCIDR+":")] = id
		} else {
			log.WithFields(logrus.Fields{
				logfields.Identity: nid,
			}).Warn("Unexpected release of numeric identity that is no longer allocated")
		}
	}

	releaseCIDRIdentities(ctx, fullIdentities)
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"fmt"
	"io"
	"os"
	"sort"

	"github.com/golang/snappy"
)

// TODO: Tests schreiben (leere dateien, blockgröße -1, +0, +1 etc.)
// TODO: linter durchlaufen lassen.
// TODO: Seek.

type reader struct {
	rawR  io.ReadSeeker
	zipR  io.Reader
	index []Block
	// TODO: Noch benötigt?
	fileEndOff   int64
	tailBuf      []byte
	readBuf      *bytes.Buffer
	headerParsed bool
	trailer      *Trailer
}

func (r *reader) Seek(offset int64, whence int) (int64, error) {
	return offset, nil
}

// Return start (prev offset) and end (curr offset) of the block currOff is
// located in. If currOff is 0, the startoffset of the first and second block is
// returned. If currOff is at the end of file the end offset of the last block
// is returned twice.  The difference between prev block and curr block is then
// equal to 0.
func (r *reader) blockLookup(currOff int64) (*Block, *Block) {
	i := sort.Search(len(r.index), func(i int) bool {
		return r.index[i].zipOff > currOff
	})
	// Beginning of the file, first block: prev offset is 0, curr offset is 1
	if i == 0 {
		return &r.index[i], &r.index[i+1]
	}
	// End of the file, last block: prev and curr offset is the last index.
	if i == len(r.index) {
		return &r.index[i-1], &r.index[i-1]
	}
	return &r.index[i-1], &r.index[i]
}

//TODO: Clean code.
func (r *reader) parseHeaderIfNeeded() error {
	if r.headerParsed {
		return nil
	}

	if _, err := r.rawR.Seek(-TailSize, os.SEEK_END); err != nil {
		return err
	}

	buf := [TailSize + 16]byte{}
	if n, err := r.rawR.Read(buf[:]); err != nil || n != TailSize {
		return err
	}
	r.trailer.unmarshal(buf[:])
	r.tailBuf = make([]byte, r.trailer.indexSize)

	var err error
	seekIdx := -(int64(r.trailer.indexSize) + TailSize)
	if r.fileEndOff, err = r.rawR.Seek(seekIdx, os.SEEK_END); err != nil {
		fmt.Println(err)
		return err
	}

	if _, err := r.rawR.Read(r.tailBuf); err != nil {
		fmt.Println(err)
		return err
	}

	//Build Index
	prevBlock := Block{-1, -1}
	for i := uint64(0); i < (r.trailer.indexSize / IndexBlockSize); i++ {
		currBlock := Block{}
		currBlock.unmarshal(r.tailBuf)

		if prevBlock.rawOff >= currBlock.rawOff && prevBlock.zipOff >= currBlock.zipOff {
			return ErrBadIndex
		}

		r.index = append(r.index, currBlock)
		r.tailBuf = r.tailBuf[IndexBlockSize:]
	}
	if _, err := r.rawR.Seek(0, os.SEEK_SET); err != nil {
		return err
	}
	r.headerParsed = true

	return nil
}

func (r *reader) Read(p []byte) (int, error) {
	if err := r.parseHeaderIfNeeded(); err != nil {
		fmt.Println(err)
		return 0, err
	}

	read := 0
	for {
		fmt.Println("READBUF LEN:", r.readBuf.Len())
		if r.readBuf.Len() != 0 {
			n := copy(p, r.readBuf.Next(len(p)))
			read += n
			p = p[n:]
			fmt.Println("P:", len(p))
		}
		if len(p) == 0 {
			break
		}

		if _, err := r.readBlockBuffered(); err != nil {
			fmt.Println("EOF?", read, err)
			return read, err
		}
	}
	fmt.Println("END:", read)
	return read, nil
}

func (r *reader) readBlockBuffered() (int64, error) {
	// Get current raw position
	currOff, err := r.rawR.Seek(0, os.SEEK_CUR)
	if err != nil {
		return 0, err
	}

	// Get compressed offset and set cursor to that position.
	prevBlock, currBlock := r.blockLookup(currOff)
	fmt.Println("#########################", currOff, prevBlock, currBlock)
	if currBlock == nil || prevBlock == nil {
		return 0, ErrBadIndex
	}

	// Blocksize should only be 0 on empty file or at the end of file.
	blockSize := currBlock.rawOff - prevBlock.rawOff
	if blockSize == 0 {
		return 0, io.EOF
	}

	currZipOff := prevBlock.zipOff
	if _, err = r.rawR.Seek(currZipOff, os.SEEK_SET); err != nil {
		return 0, err
	}

	return io.CopyN(r.readBuf, r.zipR, blockSize)
}

func NewReader(r io.ReadSeeker) io.ReadSeeker {
	return &reader{
		rawR:    r,
		zipR:    snappy.NewReader(r),
		readBuf: &bytes.Buffer{},
		trailer: &Trailer{},
	}
}
<commit_msg>reader.go: Reader struct simplified.<commit_after>package main

import (
	"bytes"
	"fmt"
	"io"
	"os"
	"sort"

	"github.com/golang/snappy"
)

// TODO: Tests schreiben (leere dateien, blockgröße -1, +0, +1 etc.)
// TODO: linter durchlaufen lassen.
// TODO: Seek.

type reader struct {
	rawR    io.ReadSeeker
	zipR    io.Reader
	index   []Block
	readBuf *bytes.Buffer
	trailer *Trailer
}

func (r *reader) Seek(offset int64, whence int) (int64, error) {
	return offset, nil
}

// Return start (prev offset) and end (curr offset) of the block currOff is
// located in. If currOff is 0, the startoffset of the first and second block is
// returned. If currOff is at the end of file the end offset of the last block
// is returned twice.  The difference between prev block and curr block is then
// equal to 0.
func (r *reader) blockLookup(currOff int64) (*Block, *Block) {
	i := sort.Search(len(r.index), func(i int) bool {
		return r.index[i].zipOff > currOff
	})
	// Beginning of the file, first block: prev offset is 0, curr offset is 1
	if i == 0 {
		return &r.index[i], &r.index[i+1]
	}
	// End of the file, last block: prev and curr offset is the last index.
	if i == len(r.index) {
		return &r.index[i-1], &r.index[i-1]
	}
	return &r.index[i-1], &r.index[i]
}

//TODO: Clean code.
func (r *reader) parseHeaderIfNeeded() error {
	if r.trailer != nil {
		return nil
	}

	if _, err := r.rawR.Seek(-TailSize, os.SEEK_END); err != nil {
		return err
	}

	buf := [TailSize]byte{}
	if n, err := r.rawR.Read(buf[:]); err != nil || n != TailSize {
		return err
	}

	r.trailer = &Trailer{}
	r.trailer.unmarshal(buf[:])
	tailBuf := make([]byte, r.trailer.indexSize)

	var err error
	seekIdx := -(int64(r.trailer.indexSize) + TailSize)
	if _, err = r.rawR.Seek(seekIdx, os.SEEK_END); err != nil {
		fmt.Println(err)
		return err
	}

	if _, err := r.rawR.Read(tailBuf); err != nil {
		fmt.Println(err)
		return err
	}

	//Build Index
	prevBlock := Block{-1, -1}
	for i := uint64(0); i < (r.trailer.indexSize / IndexBlockSize); i++ {
		currBlock := Block{}
		currBlock.unmarshal(tailBuf)

		if prevBlock.rawOff >= currBlock.rawOff && prevBlock.zipOff >= currBlock.zipOff {
			return ErrBadIndex
		}

		r.index = append(r.index, currBlock)
		tailBuf = tailBuf[IndexBlockSize:]
	}

	if _, err := r.rawR.Seek(0, os.SEEK_SET); err != nil {
		return err
	}

	return nil
}

func (r *reader) Read(p []byte) (int, error) {
	if err := r.parseHeaderIfNeeded(); err != nil {
		fmt.Println(err)
		return 0, err
	}

	read := 0
	for {
		fmt.Println("READBUF LEN:", r.readBuf.Len())
		if r.readBuf.Len() != 0 {
			n := copy(p, r.readBuf.Next(len(p)))
			read += n
			p = p[n:]
			fmt.Println("P:", len(p))
		}
		if len(p) == 0 {
			break
		}

		if _, err := r.readBlockBuffered(); err != nil {
			fmt.Println("EOF?", read, err)
			return read, err
		}
	}
	fmt.Println("END:", read)
	return read, nil
}

// TODO: Ist das noch "buffered"?
func (r *reader) readBlockBuffered() (int64, error) {
	// Get current raw position
	currOff, err := r.rawR.Seek(0, os.SEEK_CUR)
	if err != nil {
		return 0, err
	}

	// Get compressed offset and set cursor to that position.
	prevBlock, currBlock := r.blockLookup(currOff)
	fmt.Println("#########################", currOff, prevBlock, currBlock)
	if currBlock == nil || prevBlock == nil {
		return 0, ErrBadIndex
	}

	// Blocksize should only be 0 on empty file or at the end of file.
	blockSize := currBlock.rawOff - prevBlock.rawOff
	if blockSize == 0 {
		return 0, io.EOF
	}

	currZipOff := prevBlock.zipOff
	if _, err = r.rawR.Seek(currZipOff, os.SEEK_SET); err != nil {
		return 0, err
	}

	return io.CopyN(r.readBuf, r.zipR, blockSize)
}

func NewReader(r io.ReadSeeker) io.ReadSeeker {
	return &reader{
		rawR:    r,
		zipR:    snappy.NewReader(r),
		readBuf: &bytes.Buffer{},
	}
}
<|endoftext|>


<commit_before>package lfs

import (
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"path/filepath"
	"runtime"
	"strings"
)

type CallbackReader struct {
	C         CopyCallback
	TotalSize int64
	ReadSize  int64
	io.Reader
}

type Platform int

const (
	PlatformWindows      = Platform(iota)
	PlatformLinux        = Platform(iota)
	PlatformOSX          = Platform(iota)
	PlatformOther        = Platform(iota) // most likely a *nix variant e.g. freebsd
	PlatformUndetermined = Platform(iota)
)

var currentPlatform = PlatformUndetermined

type CopyCallback func(totalSize int64, readSoFar int64, readSinceLast int) error

func (w *CallbackReader) Read(p []byte) (int, error) {
	n, err := w.Reader.Read(p)

	if n > 0 {
		w.ReadSize += int64(n)
	}

	if err == nil && w.C != nil {
		err = w.C(w.TotalSize, w.ReadSize, n)
	}

	return n, err
}

func CopyWithCallback(writer io.Writer, reader io.Reader, totalSize int64, cb CopyCallback) (int64, error) {
	if success, _ := CloneFile(writer, reader); success {
		if cb != nil {
			cb(totalSize, totalSize, 0)
		}
		return totalSize, nil
	}
	if cb == nil {
		return io.Copy(writer, reader)
	}

	cbReader := &CallbackReader{
		C:         cb,
		TotalSize: totalSize,
		Reader:    reader,
	}
	return io.Copy(writer, cbReader)
}

func CopyCallbackFile(event, filename string, index, totalFiles int) (CopyCallback, *os.File, error) {
	logPath := Config.Getenv("GIT_LFS_PROGRESS")
	if len(logPath) == 0 || len(filename) == 0 || len(event) == 0 {
		return nil, nil, nil
	}

	if !filepath.IsAbs(logPath) {
		return nil, nil, fmt.Errorf("GIT_LFS_PROGRESS must be an absolute path")
	}

	cbDir := filepath.Dir(logPath)
	if err := os.MkdirAll(cbDir, 0755); err != nil {
		return nil, nil, wrapProgressError(err, event, logPath)
	}

	file, err := os.OpenFile(logPath, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0666)
	if err != nil {
		return nil, file, wrapProgressError(err, event, logPath)
	}

	var prevWritten int64

	cb := CopyCallback(func(total int64, written int64, current int) error {
		if written != prevWritten {
			_, err := file.Write([]byte(fmt.Sprintf("%s %d/%d %d/%d %s\n", event, index, totalFiles, written, total, filename)))
			file.Sync()
			prevWritten = written
			return wrapProgressError(err, event, logPath)
		}

		return nil
	})

	return cb, file, nil
}

func wrapProgressError(err error, event, filename string) error {
	if err != nil {
		return fmt.Errorf("Error writing Git LFS %s progress to %s: %s", event, filename, err.Error())
	}

	return nil
}

var localDirSet = NewStringSetFromSlice([]string{".", "./", ".\\"})

// Return whether a given filename passes the include / exclude path filters
// Only paths that are in includePaths and outside excludePaths are passed
// If includePaths is empty that filter always passes and the same with excludePaths
// Both path lists support wildcard matches
func FilenamePassesIncludeExcludeFilter(filename string, includePaths, excludePaths []string) bool {
	if len(includePaths) == 0 && len(excludePaths) == 0 {
		return true
	}

	// For Win32, because git reports files with / separators
	cleanfilename := filepath.Clean(filename)
	if len(includePaths) > 0 {
		matched := false
		for _, inc := range includePaths {
			// Special case local dir, matches all (inc subpaths)
			if _, local := localDirSet[inc]; local {
				matched = true
				break
			}
			matched, _ = filepath.Match(inc, filename)
			if !matched && IsWindows() {
				// Also Win32 match
				matched, _ = filepath.Match(inc, cleanfilename)
			}
			if !matched {
				// Also support matching a parent directory without a wildcard
				if strings.HasPrefix(cleanfilename, inc+string(filepath.Separator)) {
					matched = true
				}
			}
			if matched {
				break
			}

		}
		if !matched {
			return false
		}
	}

	if len(excludePaths) > 0 {
		for _, ex := range excludePaths {
			// Special case local dir, matches all (inc subpaths)
			if _, local := localDirSet[ex]; local {
				return false
			}
			matched, _ := filepath.Match(ex, filename)
			if !matched && IsWindows() {
				// Also Win32 match
				matched, _ = filepath.Match(ex, cleanfilename)
			}
			if matched {
				return false
			}
			// Also support matching a parent directory without a wildcard
			if strings.HasPrefix(cleanfilename, ex+string(filepath.Separator)) {
				return false
			}

		}
	}

	return true
}

func GetPlatform() Platform {
	if currentPlatform == PlatformUndetermined {
		switch runtime.GOOS {
		case "windows":
			currentPlatform = PlatformWindows
		case "linux":
			currentPlatform = PlatformLinux
		case "darwin":
			currentPlatform = PlatformOSX
		default:
			currentPlatform = PlatformOther
		}
	}
	return currentPlatform
}

// Convert filenames expressed relative to the root of the repo relative to the
// current working dir. Useful when needing to calling git with results from a rooted command,
// but the user is in a subdir of their repo
// Pass in a channel which you will fill with relative files & receive a channel which will get results
func ConvertRepoFilesRelativeToCwd(repochan <-chan string) (<-chan string, error) {
	wd, err := os.Getwd()
	if err != nil {
		return nil, fmt.Errorf("Unable to get working dir: %v", err)
	}
	wd = ResolveSymlinks(wd)

	// Early-out if working dir is root dir, same result
	passthrough := false
	if LocalWorkingDir == wd {
		passthrough = true
	}

	outchan := make(chan string, 1)

	go func() {
		for f := range repochan {
			if passthrough {
				outchan <- f
				continue
			}
			abs := filepath.Join(LocalWorkingDir, f)
			rel, err := filepath.Rel(wd, abs)
			if err != nil {
				// Use absolute file instead
				outchan <- abs
			} else {
				outchan <- rel
			}
		}
		close(outchan)
	}()

	return outchan, nil
}

// Convert filenames expressed relative to the current directory to be
// relative to the repo root. Useful when calling git with arguments that requires them
// to be rooted but the user is in a subdir of their repo & expects to use relative args
// Pass in a channel which you will fill with relative files & receive a channel which will get results
func ConvertCwdFilesRelativeToRepo(cwdchan <-chan string) (<-chan string, error) {
	curdir, err := os.Getwd()
	if err != nil {
		return nil, fmt.Errorf("Could not retrieve current directory: %v", err)
	}
	// Make sure to resolve symlinks
	curdir = ResolveSymlinks(curdir)

	// Early-out if working dir is root dir, same result
	passthrough := false
	if LocalWorkingDir == curdir {
		passthrough = true
	}

	outchan := make(chan string, 1)
	go func() {
		for p := range cwdchan {
			if passthrough {
				outchan <- p
				continue
			}
			var abs string
			if filepath.IsAbs(p) {
				abs = ResolveSymlinks(p)
			} else {
				abs = filepath.Join(curdir, p)
			}
			reltoroot, err := filepath.Rel(LocalWorkingDir, abs)
			if err != nil {
				// Can't do this, use absolute as best fallback
				outchan <- abs
			} else {
				outchan <- reltoroot
			}
		}
		close(outchan)
	}()

	return outchan, nil

}

// ResolveSymlinks ensures that if the path supplied is a symlink, it is
// resolved to the actual concrete path
func ResolveSymlinks(path string) string {
	if len(path) == 0 {
		return path
	}

	if resolved, err := filepath.EvalSymlinks(path); err == nil {
		return resolved
	}
	return path
}

// Are we running on Windows? Need to handle some extra path shenanigans
func IsWindows() bool {
	return GetPlatform() == PlatformWindows
}

// FileOrDirExists determines if a file/dir exists, returns IsDir() results too.
func FileOrDirExists(path string) (exists bool, isDir bool) {
	fi, err := os.Stat(path)
	if err != nil {
		return false, false
	} else {
		return true, fi.IsDir()
	}
}

// FileExists determines if a file (NOT dir) exists.
func FileExists(path string) bool {
	ret, isDir := FileOrDirExists(path)
	return ret && !isDir
}

// DirExists determines if a dir (NOT file) exists.
func DirExists(path string) bool {
	ret, isDir := FileOrDirExists(path)
	return ret && isDir
}

// FileExistsOfSize determines if a file exists and is of a specific size.
func FileExistsOfSize(path string, sz int64) bool {
	fi, err := os.Stat(path)

	if err != nil {
		return false
	}

	return !fi.IsDir() && fi.Size() == sz
}

func CopyFileContents(src string, dst string) error {
	tmp, err := ioutil.TempFile(TempDir, filepath.Base(dst))
	if err != nil {
		return err
	}
	defer func() {
		tmp.Close()
		_ = os.Remove(tmp.Name())
	}()
	in, err := os.Open(src)
	if err != nil {
		return err
	}
	defer in.Close()
	_, err = io.Copy(tmp, in)
	if err != nil {
		return err
	}
	err = tmp.Sync()
	if err != nil {
		return err
	}
	return os.Rename(tmp.Name(), dst)
}

func LinkOrCopy(src string, dst string) error {
	if src == dst {
		return nil
	}
	err := os.Link(src, dst)
	if err == nil {
		return err
	}
	return CopyFileContents(src, dst)
}
<commit_msg>Review fixes<commit_after>package lfs

import (
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"path/filepath"
	"runtime"
	"strings"
)

type CallbackReader struct {
	C         CopyCallback
	TotalSize int64
	ReadSize  int64
	io.Reader
}

type Platform int

const (
	PlatformWindows      = Platform(iota)
	PlatformLinux        = Platform(iota)
	PlatformOSX          = Platform(iota)
	PlatformOther        = Platform(iota) // most likely a *nix variant e.g. freebsd
	PlatformUndetermined = Platform(iota)
)

var currentPlatform = PlatformUndetermined

type CopyCallback func(totalSize int64, readSoFar int64, readSinceLast int) error

func (w *CallbackReader) Read(p []byte) (int, error) {
	n, err := w.Reader.Read(p)

	if n > 0 {
		w.ReadSize += int64(n)
	}

	if err == nil && w.C != nil {
		err = w.C(w.TotalSize, w.ReadSize, n)
	}

	return n, err
}

func CopyWithCallback(writer io.Writer, reader io.Reader, totalSize int64, cb CopyCallback) (int64, error) {
	if success, _ := CloneFile(writer, reader); success {
		if cb != nil {
			cb(totalSize, totalSize, 0)
		}
		return totalSize, nil
	}
	if cb == nil {
		return io.Copy(writer, reader)
	}

	cbReader := &CallbackReader{
		C:         cb,
		TotalSize: totalSize,
		Reader:    reader,
	}
	return io.Copy(writer, cbReader)
}

func CopyCallbackFile(event, filename string, index, totalFiles int) (CopyCallback, *os.File, error) {
	logPath := Config.Getenv("GIT_LFS_PROGRESS")
	if len(logPath) == 0 || len(filename) == 0 || len(event) == 0 {
		return nil, nil, nil
	}

	if !filepath.IsAbs(logPath) {
		return nil, nil, fmt.Errorf("GIT_LFS_PROGRESS must be an absolute path")
	}

	cbDir := filepath.Dir(logPath)
	if err := os.MkdirAll(cbDir, 0755); err != nil {
		return nil, nil, wrapProgressError(err, event, logPath)
	}

	file, err := os.OpenFile(logPath, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0666)
	if err != nil {
		return nil, file, wrapProgressError(err, event, logPath)
	}

	var prevWritten int64

	cb := CopyCallback(func(total int64, written int64, current int) error {
		if written != prevWritten {
			_, err := file.Write([]byte(fmt.Sprintf("%s %d/%d %d/%d %s\n", event, index, totalFiles, written, total, filename)))
			file.Sync()
			prevWritten = written
			return wrapProgressError(err, event, logPath)
		}

		return nil
	})

	return cb, file, nil
}

func wrapProgressError(err error, event, filename string) error {
	if err != nil {
		return fmt.Errorf("Error writing Git LFS %s progress to %s: %s", event, filename, err.Error())
	}

	return nil
}

var localDirSet = NewStringSetFromSlice([]string{".", "./", ".\\"})

// Return whether a given filename passes the include / exclude path filters
// Only paths that are in includePaths and outside excludePaths are passed
// If includePaths is empty that filter always passes and the same with excludePaths
// Both path lists support wildcard matches
func FilenamePassesIncludeExcludeFilter(filename string, includePaths, excludePaths []string) bool {
	if len(includePaths) == 0 && len(excludePaths) == 0 {
		return true
	}

	// For Win32, because git reports files with / separators
	cleanfilename := filepath.Clean(filename)
	if len(includePaths) > 0 {
		matched := false
		for _, inc := range includePaths {
			// Special case local dir, matches all (inc subpaths)
			if _, local := localDirSet[inc]; local {
				matched = true
				break
			}
			matched, _ = filepath.Match(inc, filename)
			if !matched && IsWindows() {
				// Also Win32 match
				matched, _ = filepath.Match(inc, cleanfilename)
			}
			if !matched {
				// Also support matching a parent directory without a wildcard
				if strings.HasPrefix(cleanfilename, inc+string(filepath.Separator)) {
					matched = true
				}
			}
			if matched {
				break
			}

		}
		if !matched {
			return false
		}
	}

	if len(excludePaths) > 0 {
		for _, ex := range excludePaths {
			// Special case local dir, matches all (inc subpaths)
			if _, local := localDirSet[ex]; local {
				return false
			}
			matched, _ := filepath.Match(ex, filename)
			if !matched && IsWindows() {
				// Also Win32 match
				matched, _ = filepath.Match(ex, cleanfilename)
			}
			if matched {
				return false
			}
			// Also support matching a parent directory without a wildcard
			if strings.HasPrefix(cleanfilename, ex+string(filepath.Separator)) {
				return false
			}

		}
	}

	return true
}

func GetPlatform() Platform {
	if currentPlatform == PlatformUndetermined {
		switch runtime.GOOS {
		case "windows":
			currentPlatform = PlatformWindows
		case "linux":
			currentPlatform = PlatformLinux
		case "darwin":
			currentPlatform = PlatformOSX
		default:
			currentPlatform = PlatformOther
		}
	}
	return currentPlatform
}

// Convert filenames expressed relative to the root of the repo relative to the
// current working dir. Useful when needing to calling git with results from a rooted command,
// but the user is in a subdir of their repo
// Pass in a channel which you will fill with relative files & receive a channel which will get results
func ConvertRepoFilesRelativeToCwd(repochan <-chan string) (<-chan string, error) {
	wd, err := os.Getwd()
	if err != nil {
		return nil, fmt.Errorf("Unable to get working dir: %v", err)
	}
	wd = ResolveSymlinks(wd)

	// Early-out if working dir is root dir, same result
	passthrough := false
	if LocalWorkingDir == wd {
		passthrough = true
	}

	outchan := make(chan string, 1)

	go func() {
		for f := range repochan {
			if passthrough {
				outchan <- f
				continue
			}
			abs := filepath.Join(LocalWorkingDir, f)
			rel, err := filepath.Rel(wd, abs)
			if err != nil {
				// Use absolute file instead
				outchan <- abs
			} else {
				outchan <- rel
			}
		}
		close(outchan)
	}()

	return outchan, nil
}

// Convert filenames expressed relative to the current directory to be
// relative to the repo root. Useful when calling git with arguments that requires them
// to be rooted but the user is in a subdir of their repo & expects to use relative args
// Pass in a channel which you will fill with relative files & receive a channel which will get results
func ConvertCwdFilesRelativeToRepo(cwdchan <-chan string) (<-chan string, error) {
	curdir, err := os.Getwd()
	if err != nil {
		return nil, fmt.Errorf("Could not retrieve current directory: %v", err)
	}
	// Make sure to resolve symlinks
	curdir = ResolveSymlinks(curdir)

	// Early-out if working dir is root dir, same result
	passthrough := false
	if LocalWorkingDir == curdir {
		passthrough = true
	}

	outchan := make(chan string, 1)
	go func() {
		for p := range cwdchan {
			if passthrough {
				outchan <- p
				continue
			}
			var abs string
			if filepath.IsAbs(p) {
				abs = ResolveSymlinks(p)
			} else {
				abs = filepath.Join(curdir, p)
			}
			reltoroot, err := filepath.Rel(LocalWorkingDir, abs)
			if err != nil {
				// Can't do this, use absolute as best fallback
				outchan <- abs
			} else {
				outchan <- reltoroot
			}
		}
		close(outchan)
	}()

	return outchan, nil

}

// ResolveSymlinks ensures that if the path supplied is a symlink, it is
// resolved to the actual concrete path
func ResolveSymlinks(path string) string {
	if len(path) == 0 {
		return path
	}

	if resolved, err := filepath.EvalSymlinks(path); err == nil {
		return resolved
	}
	return path
}

// Are we running on Windows? Need to handle some extra path shenanigans
func IsWindows() bool {
	return GetPlatform() == PlatformWindows
}

// FileOrDirExists determines if a file/dir exists, returns IsDir() results too.
func FileOrDirExists(path string) (exists bool, isDir bool) {
	fi, err := os.Stat(path)
	if err != nil {
		return false, false
	} else {
		return true, fi.IsDir()
	}
}

// FileExists determines if a file (NOT dir) exists.
func FileExists(path string) bool {
	ret, isDir := FileOrDirExists(path)
	return ret && !isDir
}

// DirExists determines if a dir (NOT file) exists.
func DirExists(path string) bool {
	ret, isDir := FileOrDirExists(path)
	return ret && isDir
}

// FileExistsOfSize determines if a file exists and is of a specific size.
func FileExistsOfSize(path string, sz int64) bool {
	fi, err := os.Stat(path)

	if err != nil {
		return false
	}

	return !fi.IsDir() && fi.Size() == sz
}

func CopyFileContents(src string, dst string) error {
	tmp, err := ioutil.TempFile(TempDir, filepath.Base(dst))
	if err != nil {
		return err
	}
	defer func() {
		tmp.Close()
		os.Remove(tmp.Name())
	}()
	in, err := os.Open(src)
	if err != nil {
		return err
	}
	defer in.Close()
	_, err = io.Copy(tmp, in)
	if err != nil {
		return err
	}
	err = tmp.Close()
	if err != nil {
		return err
	}
	return os.Rename(tmp.Name(), dst)
}

func LinkOrCopy(src string, dst string) error {
	if src == dst {
		return nil
	}
	err := os.Link(src, dst)
	if err == nil {
		return err
	}
	return CopyFileContents(src, dst)
}
<|endoftext|>


<commit_before>package main

func main()
	var c1 c2 c2 chan int
	// START0 OMIT
	select {
	case v1 := <-c1:
		fmt.Printf("received %v from c1\n", v1)
	case v2 := <-c2:
		fmt.Printf("received %v from c2\n", v1)
	case c3 <- 23:
		fmt.Printf("sent %v to c3\n", 23)
	default:
		fmt.Printf("no one was ready to communicate\n")
	}
	// STOP0 OMIT
}
<commit_msg>      go.talk: Content fixes for GAE deployment.  appcfg.py wants to compile everything, and select.go has some errors in it preventing deploment. The part being cleaned-up here isn't present in the content of the presentation:<commit_after>package main

func main() {
	var c1, c2, c3 chan int
	// START0 OMIT
	select {
	case v1 := <-c1:
		fmt.Printf("received %v from c1\n", v1)
	case v2 := <-c2:
		fmt.Printf("received %v from c2\n", v1)
	case c3 <- 23:
		fmt.Printf("sent %v to c3\n", 23)
	default:
		fmt.Printf("no one was ready to communicate\n")
	}
	// STOP0 OMIT
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"strings"

	log "github.com/Sirupsen/logrus"
)

type patchBlock struct {
	original     string
	translations []translationBlock
}

type translationBlock struct {
	contexts   []string
	text       string
	touched    bool
	translated bool
}

func parseBlock(block patchBlock) patchBlock {
	var items []item
	var err error

	parsed := false

	for i, t := range block.translations {
		if shouldTranslateContext(t) && shouldTranslateText(block.original) {
			if !parsed {
				items, err = parseText(block.original)

				if err != nil {
					logBlockError(err, block, items)

					return block
				}

				parsed = true
			}

			t.text = translateItems(items)
			t.translated = true
			t.touched = true

			block.translations[i] = t

			log.Debugf("'%s' => '%s'\n", block.original, t.text)
		}
	}

	return block
}

func shouldTranslateContext(block translationBlock) bool {
	if block.translated {
		log.Debug("Skipping translated block")
		return false
	}

	for _, c := range block.contexts {
		if engine == engineRPGMVX {
			//log.Debugf("%q", c)
			if strings.HasSuffix(c, "_se/name/") ||
				strings.HasSuffix(c, "/bgm/name/") ||
				strings.HasSuffix(c, "_me/name/") ||
				strings.Contains(c, "/InlineScript/") {
				return false
			}

			if strings.HasPrefix(c, ": Scripts/") {
				if strings.Contains(c, "Vocab/") {
					break
				} else {
					return false
				}
			}
		} else if engine == engineWolf {
			if strings.HasSuffix(c, "/Database") {
				return false
			} else if strings.HasPrefix(c, " DB:DataBase") {
				if strings.Contains(c, "アクター/") || //Actor
					strings.Contains(c, "NPC/") ||
					strings.Contains(c, "ステート/") || // State
					strings.Contains(c, "技能/") || // Skill
					strings.Contains(c, "敵/") || // Enemy
					strings.Contains(c, "武器/") || // Weapon
					strings.Contains(c, "称号/") || // Title
					strings.Contains(c, "衣装/") || // Clothing
					strings.Contains(c, "防具/") || // Armor
					strings.Contains(c, "道具/") || // Tools
					strings.Contains(c, "メニュー設計/") || // Menu
					strings.Contains(c, "コンフィグ/") || // Config
					strings.Contains(c, "クエスト/") || // Quest
					strings.Contains(c, "マップ選択画面") || // Map selection
					strings.Contains(c, "回想モード/") { // Recollection
					break
				}

				return false
			}
		}
	}

	return true
}

func translateItems(items []item) string {
	var out string

	for _, item := range items {
		log.Debugf("%14s: %q", item.typ, item.val)

		// Translate
		if item.typ == itemText {
			translation, err := translateString(item.val)
			check(err)

			if strings.HasPrefix(item.val, " ") && !strings.HasPrefix(translation, " ") {
				out += " "
			}

			out += translation

			if strings.HasSuffix(item.val, " ") && !strings.HasSuffix(translation, " ") {
				out += " "
			}
		} else if item.typ == itemEOF {
			continue
		} else if item.typ != itemError {
			// Add space before '(' since translation might make it get parsed as function
			if item.typ == itemRawString && item.val == "(" &&
				(!strings.HasSuffix(out, " ") && !strings.HasSuffix(out, "　")) {
				out += " "
			}

			// Add raw
			out += item.val
		}
	}

	return out
}

func parseText(text string) ([]item, error) {
	l := lex(text)

	var items []item
	var err error

	for {
		item := l.nextItem()
		items = append(items, item)

		if item.typ == itemError {
			err = fmt.Errorf("Failed to parse text")
		}

		if item.typ == itemEOF || item.typ == itemError {
			break
		}
	}

	return items, err
}
<commit_msg>Add more wolf contexts to ignore<commit_after>package main

import (
	"fmt"
	"strings"

	log "github.com/Sirupsen/logrus"
)

type patchBlock struct {
	original     string
	translations []translationBlock
}

type translationBlock struct {
	contexts   []string
	text       string
	touched    bool
	translated bool
}

func parseBlock(block patchBlock) patchBlock {
	var items []item
	var err error

	parsed := false

	for i, t := range block.translations {
		if shouldTranslateContext(t, block.original) && shouldTranslateText(block.original) {
			if !parsed {
				items, err = parseText(block.original)

				if err != nil {
					logBlockError(err, block, items)

					return block
				}

				parsed = true
			}

			t.text = translateItems(items)
			t.translated = true
			t.touched = true

			block.translations[i] = t

			log.Debugf("'%s' => '%s'\n", block.original, t.text)
		}
	}

	return block
}

func shouldTranslateContext(block translationBlock, text string) bool {
	if block.translated {
		log.Debug("Skipping translated block")
		return false
	}

	for _, c := range block.contexts {
		if engine == engineRPGMVX {
			//log.Debugf("%q", c)
			if strings.HasSuffix(c, "_se/name/") ||
				strings.HasSuffix(c, "/bgm/name/") ||
				strings.HasSuffix(c, "_me/name/") ||
				strings.Contains(c, "/InlineScript/") {
				return false
			}

			if strings.HasPrefix(c, ": Scripts/") {
				if strings.Contains(c, "Vocab/") {
					break
				} else {
					return false
				}
			}
		} else if engine == engineWolf {
			if strings.HasSuffix(c, "/Database") {
				return false
			} else if strings.HasPrefix(c, " DB:DataBase") {
				if strings.Contains(c, "アクター/") || //Actor
					strings.Contains(c, "NPC/") ||
					strings.Contains(c, "ステート/") || // State
					strings.Contains(c, "技能/") || // Skill
					strings.Contains(c, "敵/") || // Enemy
					strings.Contains(c, "武器/") || // Weapon
					strings.Contains(c, "称号/") || // Title
					strings.Contains(c, "衣装/") || // Clothing
					strings.Contains(c, "防具/") || // Armor
					strings.Contains(c, "道具/") || // Tools
					strings.Contains(c, "メニュー設計/") || // Menu
					strings.Contains(c, "コンフィグ/") || // Config
					strings.Contains(c, "クエスト/") || // Quest
					strings.Contains(c, "マップ選択画面") || // Map selection
					strings.Contains(c, "回想モード/") { // Recollection
					break
				}

				return false
			} else if strings.HasPrefix(c, " COMMONEVENT:") {
				if (strings.HasSuffix(c, "/SetString") && strings.Contains(text, "/")) || strings.HasSuffix(c, "/StringCondition") {
					return false
				}
			}
		}
	}

	return true
}

func translateItems(items []item) string {
	var out string

	for _, item := range items {
		log.Debugf("%14s: %q", item.typ, item.val)

		// Translate
		if item.typ == itemText {
			translation, err := translateString(item.val)
			check(err)

			if strings.HasPrefix(item.val, " ") && !strings.HasPrefix(translation, " ") {
				out += " "
			}

			out += translation

			if strings.HasSuffix(item.val, " ") && !strings.HasSuffix(translation, " ") {
				out += " "
			}
		} else if item.typ == itemEOF {
			continue
		} else if item.typ != itemError {
			// Add space before '(' since translation might make it get parsed as function
			if item.typ == itemRawString && item.val == "(" &&
				(!strings.HasSuffix(out, " ") && !strings.HasSuffix(out, "　")) {
				out += " "
			}

			// Add raw
			out += item.val
		}
	}

	return out
}

func parseText(text string) ([]item, error) {
	l := lex(text)

	var items []item
	var err error

	for {
		item := l.nextItem()
		items = append(items, item)

		if item.typ == itemError {
			err = fmt.Errorf("Failed to parse text")
		}

		if item.typ == itemEOF || item.typ == itemError {
			break
		}
	}

	return items, err
}
<|endoftext|>


<commit_before>// Copyright 2017 The Cockroach 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. See the AUTHORS file
// for names of contributors.
//
// Author: Arjun Narayan

package main

import (
	"database/sql"
	"fmt"
)

var queryStmts = [...]string{
	1:  query1,
	2:  query2,
	3:  query3,
	4:  query4,
	5:  query5,
	6:  query6,
	7:  query7,
	8:  query8,
	9:  query9,
	10: query10,
	11: query11,
	12: query12,
	13: query13,
	14: query14,
	15: query15,
	16: query16,
	17: query17,
	18: query18,
	19: query19,
	20: query20,
	21: query21,
	22: query22,
}

func runQuery(db *sql.DB, query int) (int, error) {
	var queryString string
	if *distsql {
		queryString = "SET dist_sql = 'always'; "
	}
	queryString = fmt.Sprintf("%s%s", queryString, queryStmts[query])

	switch query {
	case 2, 4, 13, 16, 17, 18, 20, 21, 22:
		fmt.Println("Warning: query is unsupported")
	case 5, 6, 10, 12, 14:
		fmt.Println("Warning: query causes Cockroach to panic (see #13692)")
	case 11:
		fmt.Println("Warning: group with having not supported yet")
	}

	rows, err := db.Query(queryString)
	if err != nil {
		return 0, err
	}
	var rowCount int
	for rows.Next() {
		rowCount++
	}

	return rowCount, nil
}
<commit_msg>tpch: don't run queries that break cockroach.<commit_after>// Copyright 2017 The Cockroach 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. See the AUTHORS file
// for names of contributors.
//
// Author: Arjun Narayan

package main

import (
	"database/sql"
	"fmt"
)

var queryStmts = [...]string{
	1:  query1,
	2:  query2,
	3:  query3,
	4:  query4,
	5:  query5,
	6:  query6,
	7:  query7,
	8:  query8,
	9:  query9,
	10: query10,
	11: query11,
	12: query12,
	13: query13,
	14: query14,
	15: query15,
	16: query16,
	17: query17,
	18: query18,
	19: query19,
	20: query20,
	21: query21,
	22: query22,
}

func runQuery(db *sql.DB, query int) (int, error) {
	var queryString string
	if *distsql {
		queryString = "SET dist_sql = 'always'; "
	}
	queryString = fmt.Sprintf("%s%s", queryString, queryStmts[query])

	switch query {
	case 2, 4, 13, 16, 17, 18, 20, 21, 22:
		fmt.Println("Warning: query is unsupported")
	case 5, 6, 10, 12, 14:
		fmt.Println("Warning: query causes Cockroach to panic (see #13692), not running query.")
		return 0, nil
	case 11:
		fmt.Println("Warning: group with having not supported yet")
	}

	rows, err := db.Query(queryString)
	if err != nil {
		return 0, err
	}
	var rowCount int
	for rows.Next() {
		rowCount++
	}

	return rowCount, nil
}
<|endoftext|>


<commit_before>package query

import (
	"fmt"
	"strings"
	"time"

	"golang.org/x/sync/errgroup"

	"github.com/pkg/errors"
	"github.com/yuuki/diamondb/pkg/model"
	"github.com/yuuki/diamondb/pkg/storage"
)

// UnsupportedFunctionError represents the error of unsupported query function.
type UnsupportedFunctionError struct {
	funcName string
}

// Error returns the error message for UnsupportedFunctionError.
// UnsupportedFunctionError satisfies error interface.
func (e *UnsupportedFunctionError) Error() string {
	return fmt.Sprintf("unsupported function %s", e.funcName)
}

type funcArg struct {
	expr        Expr
	seriesSlice model.SeriesSlice
}

// EvalTargets evaluates the targets concurrently. It is guaranteed that the order
// of the targets as input value and SeriesSlice as retuen value is the same.
func EvalTargets(reader storage.ReadWriter, targets []string, startTime, endTime time.Time) (model.SeriesSlice, error) {
	var eg errgroup.Group
	ordered := make([]model.SeriesSlice, len(targets))
	for i, target := range targets {
		i, target := i, target
		eg.Go(func() error {
			ss, err := EvalTarget(reader, target, startTime, endTime)
			if err != nil {
				return err
			}
			ordered[i] = ss
			return nil
		})
	}
	if err := eg.Wait(); err != nil {
		return nil, err
	}
	var results model.SeriesSlice
	for _, ss := range ordered {
		results = append(results, ss...)
	}
	return results, nil
}

// EvalTarget evaluates the target. It parses the target into AST structure and fetches datapoints from storage.
//
// ex. target: "alias(sumSeries(server1.loadavg5,server2.loadavg5),\"server_loadavg5\")"
func EvalTarget(reader storage.ReadWriter, target string, startTime, endTime time.Time) (model.SeriesSlice, error) {
	expr, err := ParseTarget(target)
	if err != nil {
		return nil, err
	}
	ss, err := invokeExpr(reader, expr, startTime, endTime)
	if err != nil {
		return nil, err
	}
	return ss, err
}

func invokeExpr(reader storage.ReadWriter, expr Expr, startTime, endTime time.Time) (model.SeriesSlice, error) {
	switch e := expr.(type) {
	case SeriesListExpr:
		ss, err := reader.Fetch(e.Literal, startTime, endTime)
		if err != nil {
			return nil, err
		}
		return ss, nil
	case GroupSeriesExpr:
		joinedValues := make([]string, 0, len(e.ValueList))
		for _, value := range e.ValueList {
			joinedValues = append(joinedValues, e.Prefix+value+e.Postfix)
		}
		expr = SeriesListExpr{Literal: strings.Join(joinedValues, ",")}
		ss, err := invokeExpr(reader, expr, startTime, endTime)
		if err != nil {
			return nil, err
		}
		return ss, nil
	case FuncExpr:
		var (
			ss  model.SeriesSlice
			err error
		)

		args, err := invokeSubExprs(reader, e.SubExprs, startTime, endTime)
		if err != nil {
			return nil, err
		}
		switch e.Name {
		case "alias":
			ss, err = doAlias(args)
		case "offset":
			ss, err = doOffset(args)
		case "scale":
			ss, err = doScale(args)
		case "group":
			ss, err = doGroup(args)
		case "averageSeries", "avg":
			ss, err = doAverageSeries(args)
		case "sumSeries", "sum":
			ss, err = doSumSeries(args)
		case "minSeries":
			ss, err = doMinSeries(args)
		case "maxSeries":
			ss, err = doMaxSeries(args)
		case "multiplySeries":
			ss, err = doMultiplySeries(args)
		case "divideSeries":
			ss, err = doDivideSeries(args)
		case "percentileOfSeries":
			ss, err = doPercentileOfSeries(args)
		case "summarize":
			ss, err = doSummarize(args)
		case "sumSeriesWithWildcards":
			ss, err = doSumSeriesWithWildcards(args)
		case "doLinerRegression":
			ss, err = doLinerRegression(reader, args, startTime, endTime)
		default:
			return nil, &UnsupportedFunctionError{funcName: e.Name}
		}
		if err != nil {
			return nil, err
		}
		return ss, err
	default:
		return nil, errors.Errorf("unknown expression (%s)", expr)
	}
}

func invokeSubExprs(reader storage.ReadWriter, exprs []Expr, startTime, endTime time.Time) ([]*funcArg, error) {
	type result struct {
		value *funcArg
		err   error
		index int
	}

	c := make(chan *result, len(exprs))
	args := make([]*funcArg, len(exprs))
	numTasks := 0

	for i, expr := range exprs {
		switch expr.(type) {
		case BoolExpr, NumberExpr, StringExpr:
			args[i] = &funcArg{expr: expr}
		case SeriesListExpr, GroupSeriesExpr, FuncExpr:
			numTasks++
			go func(e Expr, start, end time.Time, i int) {
				ss, err := invokeExpr(reader, e, start, end)
				c <- &result{
					value: &funcArg{
						expr:        SeriesListExpr{Literal: ss.FormattedName()},
						seriesSlice: ss,
					},
					err:   err,
					index: i,
				}
			}(expr, startTime, endTime, i)
		default:
			return nil, errors.Errorf("unknown expression (%s)", expr)
		}
	}

	for i := 0; i < numTasks; i++ {
		ret := <-c
		if ret.err != nil {
			// return err that is found firstly.
			return nil, ret.err
		}
		args[ret.index] = ret.value
	}

	return args, nil
}
<commit_msg>Use errgroup instead of channel to simplify code<commit_after>package query

import (
	"fmt"
	"strings"
	"time"

	"golang.org/x/sync/errgroup"

	"github.com/pkg/errors"
	"github.com/yuuki/diamondb/pkg/model"
	"github.com/yuuki/diamondb/pkg/storage"
)

// UnsupportedFunctionError represents the error of unsupported query function.
type UnsupportedFunctionError struct {
	funcName string
}

// Error returns the error message for UnsupportedFunctionError.
// UnsupportedFunctionError satisfies error interface.
func (e *UnsupportedFunctionError) Error() string {
	return fmt.Sprintf("unsupported function %s", e.funcName)
}

type funcArg struct {
	expr        Expr
	seriesSlice model.SeriesSlice
}

// EvalTargets evaluates the targets concurrently. It is guaranteed that the order
// of the targets as input value and SeriesSlice as retuen value is the same.
func EvalTargets(reader storage.ReadWriter, targets []string, startTime, endTime time.Time) (model.SeriesSlice, error) {
	var eg errgroup.Group
	ordered := make([]model.SeriesSlice, len(targets))
	for i, target := range targets {
		i, target := i, target
		eg.Go(func() error {
			ss, err := EvalTarget(reader, target, startTime, endTime)
			if err != nil {
				return err
			}
			ordered[i] = ss
			return nil
		})
	}
	if err := eg.Wait(); err != nil {
		return nil, err
	}
	var results model.SeriesSlice
	for _, ss := range ordered {
		results = append(results, ss...)
	}
	return results, nil
}

// EvalTarget evaluates the target. It parses the target into AST structure and fetches datapoints from storage.
//
// ex. target: "alias(sumSeries(server1.loadavg5,server2.loadavg5),\"server_loadavg5\")"
func EvalTarget(reader storage.ReadWriter, target string, startTime, endTime time.Time) (model.SeriesSlice, error) {
	expr, err := ParseTarget(target)
	if err != nil {
		return nil, err
	}
	ss, err := invokeExpr(reader, expr, startTime, endTime)
	if err != nil {
		return nil, err
	}
	return ss, err
}

func invokeExpr(reader storage.ReadWriter, expr Expr, startTime, endTime time.Time) (model.SeriesSlice, error) {
	switch e := expr.(type) {
	case SeriesListExpr:
		ss, err := reader.Fetch(e.Literal, startTime, endTime)
		if err != nil {
			return nil, err
		}
		return ss, nil
	case GroupSeriesExpr:
		joinedValues := make([]string, 0, len(e.ValueList))
		for _, value := range e.ValueList {
			joinedValues = append(joinedValues, e.Prefix+value+e.Postfix)
		}
		expr = SeriesListExpr{Literal: strings.Join(joinedValues, ",")}
		ss, err := invokeExpr(reader, expr, startTime, endTime)
		if err != nil {
			return nil, err
		}
		return ss, nil
	case FuncExpr:
		var (
			ss  model.SeriesSlice
			err error
		)

		args, err := invokeSubExprs(reader, e.SubExprs, startTime, endTime)
		if err != nil {
			return nil, err
		}
		switch e.Name {
		case "alias":
			ss, err = doAlias(args)
		case "offset":
			ss, err = doOffset(args)
		case "scale":
			ss, err = doScale(args)
		case "group":
			ss, err = doGroup(args)
		case "averageSeries", "avg":
			ss, err = doAverageSeries(args)
		case "sumSeries", "sum":
			ss, err = doSumSeries(args)
		case "minSeries":
			ss, err = doMinSeries(args)
		case "maxSeries":
			ss, err = doMaxSeries(args)
		case "multiplySeries":
			ss, err = doMultiplySeries(args)
		case "divideSeries":
			ss, err = doDivideSeries(args)
		case "percentileOfSeries":
			ss, err = doPercentileOfSeries(args)
		case "summarize":
			ss, err = doSummarize(args)
		case "sumSeriesWithWildcards":
			ss, err = doSumSeriesWithWildcards(args)
		case "doLinerRegression":
			ss, err = doLinerRegression(reader, args, startTime, endTime)
		default:
			return nil, &UnsupportedFunctionError{funcName: e.Name}
		}
		if err != nil {
			return nil, err
		}
		return ss, err
	default:
		return nil, errors.Errorf("unknown expression (%s)", expr)
	}
}

func invokeSubExprs(reader storage.ReadWriter, exprs []Expr, startTime, endTime time.Time) ([]*funcArg, error) {
	var eg errgroup.Group
	args := make([]*funcArg, len(exprs))
	for i, expr := range exprs {
		switch expr.(type) {
		case BoolExpr, NumberExpr, StringExpr:
			args[i] = &funcArg{expr: expr}
		case SeriesListExpr, GroupSeriesExpr, FuncExpr:
			i, expr := i, expr
			eg.Go(func() error {
				ss, err := invokeExpr(reader, expr, startTime, endTime)
				if err != nil {
					return err
				}
				args[i] = &funcArg{
					expr:        SeriesListExpr{Literal: ss.FormattedName()},
					seriesSlice: ss,
				}
				return nil
			})
		default:
			return nil, errors.Errorf("unknown expression (%s)", expr)
		}
	}
	if err := eg.Wait(); err != nil {
		return nil, err
	}
	return args, nil
}
<|endoftext|>