<commit_before>package database

import (
	"fmt"
	"labix.org/v2/mgo"
	"labix.org/v2/mgo/bson"
	"mud/utils"
)

type dbError struct {
	message string
}

func (self dbError) Error() string {
	return self.message
}

func newDbError(message string) dbError {
	var err dbError
	err.message = message
	return err
}

type collectionName string

func getCollection(session *mgo.Session, collection collectionName) *mgo.Collection {
	return session.DB("mud").C(string(collection))
}

// Collection names
const (
	cUsers      = collectionName("users")
	cCharacters = collectionName("characters")
	cRooms      = collectionName("rooms")
)

// Field names
const (
	fId          = "_id"
	fName        = "name"
	fCharacters  = "characters"
	fRoom        = "room"
	fLocation    = "location"
	fTitle       = "title"
	fDescription = "description"
	fNorth       = "exit_north"
	fEast        = "exit_east"
	fSouth       = "exit_south"
	fWest        = "exit_west"
	fUp          = "exit_up"
	fDown        = "exit_down"
	fDefault     = "default"
)

// DB commands
const (
	SET  = "$set"
	PUSH = "$push"
	PULL = "$pull"
)

func FindUser(session *mgo.Session, name string) (bool, error) {
	c := getCollection(session, cUsers)
	q := c.Find(bson.M{fName: name})

	count, err := q.Count()

	if err != nil {
		return false, err
	}

	return count > 0, nil
}

func NewUser(session *mgo.Session, name string) error {

	found, err := FindUser(session, name)

	if err != nil {
		return err
	}

	if found {
		return newDbError("That user already exists")
	}

	c := getCollection(session, cUsers)
	c.Insert(bson.M{fName: name})

	return nil
}

func GetCharacterRoom(session *mgo.Session, character Character) (Room, error) {
	return GetRoom(session, character.RoomId)
}

func FindRoom(session *mgo.Session, query interface{}) (Room, error) {
	c := getCollection(session, cRooms)
	q := c.Find(query)

	count, err := q.Count()

	var room Room
	if err != nil {
		return room, err
	}

	if count == 0 {
		return room, newDbError(fmt.Sprintf("Room not found, query: %v", query))
	}

	err = q.One(&room)

	return room, err
}

func FindCharacter(session *mgo.Session, query interface{}) (Character, error) {
	c := getCollection(session, cCharacters)
	q := c.Find(query)

	count, err := q.Count()

	var character Character
	if err != nil {
		return character, err
	}

	if count == 0 {
		return character, newDbError(fmt.Sprintf("Character not found, query: %v", query))
	}

	err = q.One(&character)

	return character, err
}

func GetCharacter(session *mgo.Session, id bson.ObjectId) (Character, error) {
	return FindCharacter(session, bson.M{fId: id})
}

func GetCharacterByName(session *mgo.Session, name string) (Character, error) {
	return FindCharacter(session, bson.M{fName: name})
}

func GetRoom(session *mgo.Session, id bson.ObjectId) (Room, error) {
	return FindRoom(session, bson.M{fId: id})
}

func GetRoomByLocation(session *mgo.Session, location Coordinate) (Room, error) {
	return FindRoom(session, bson.M{fLocation: location})
}

func CreateRoom(session *mgo.Session, room Room) (Room, error) {
	c := getCollection(session, cRooms)
	err := c.Insert(room)

	if err != nil {
		fmt.Printf("Error creating room: %v\n", err)
		return room, err
	}

	room, err = GetRoomByLocation(session, room.Location)

	return room, err
}

func CreateCharacter(session *mgo.Session, userName string, characterName string) (Character, error) {
	character, err := GetCharacterByName(session, characterName)

	if err == nil {
		return character, newDbError("That character already exists")
	}

	character = newCharacter(characterName)

	characterCollection := getCollection(session, cCharacters)
	err = characterCollection.Insert(character)

	if err != nil {
		fmt.Printf("Error inserting new character object into database: %v\n", err)
		return character, err
	}

	character, err = GetCharacterByName(session, character.Name)

	startingRoom, err := StartingRoom(session)

	if err != nil {
		fmt.Printf("Error getting starting room: %v\n", err)
		return character, err
	}

	character.RoomId = startingRoom.Id
	err = CommitCharacter(session, character)

	if err != nil {
		fmt.Printf("Error committing character object: %v\n", err)
		return character, err
	}

	if err == nil {
		userCollection := getCollection(session, cUsers)
		err = userCollection.Update(bson.M{fName: userName}, bson.M{PUSH: bson.M{fCharacters: character.Id}})

		if err != nil {
			fmt.Printf("Error updating user with new character data: %v\n", err)
		}
	}

	return character, err
}

func SetCharacterRoom(session *mgo.Session, character string, roomId bson.ObjectId) error {
	c := getCollection(session, cCharacters)
	err := c.Update(bson.M{fName: character}, bson.M{SET: bson.M{fRoom: roomId}})

	if err != nil {
		fmt.Printf("Failed setting character room :%v\n", err)
	}

	return err
}

func GetUserCharacters(session *mgo.Session, userName string) ([]Character, error) {
	c := getCollection(session, cUsers)
	q := c.Find(bson.M{fName: userName})

	result := map[string][]bson.ObjectId{}
	err := q.One(&result)

	var characters []Character
	for _, charId := range result[fCharacters] {
		character, err := GetCharacter(session, charId)

		if err != nil {
			fmt.Printf("Failed to find character with id %s, belonging to user %s: %s\n", charId, userName, err)
		} else {
			characters = append(characters, character)
		}
	}

	return characters, err
}

func DeleteCharacter(session *mgo.Session, user string, character string) error {
	c := getCollection(session, cUsers)
	c.Update(bson.M{fName: user}, bson.M{PULL: bson.M{fCharacters: utils.Simplify(character)}})

	c = getCollection(session, cCharacters)
	c.Remove(bson.M{fName: character})

	return nil
}

func StartingRoom(session *mgo.Session) (Room, error) {
	c := getCollection(session, cRooms)
	q := c.Find(bson.M{fDefault: true})

	count, err := q.Count()

	var room Room
	if err != nil {
		return room, err
	}

	if count == 0 {
		return room, newDbError("No default room found")
	}

	if count > 1 {
		fmt.Printf("Warning: More than one default room found\n")
	}

	err = q.One(&room)

	return room, err
}

func GenerateDefaultMap(session *mgo.Session) {
	c := getCollection(session, cRooms)
	c.DropCollection()

	room := newRoom()
	room.Location = Coordinate{0, 0, 0}
	room.Default = true

	CreateRoom(session, room)
}

func SetRoomTitle(session *mgo.Session, room Room, title string) error {
	c := getCollection(session, cRooms)
	return c.Update(bson.M{fId: room.Id}, bson.M{SET: bson.M{fTitle: title}})
}

func SetRoomDescription(session *mgo.Session, room Room, description string) error {
	c := getCollection(session, cRooms)
	return c.Update(bson.M{fId: room.Id}, bson.M{SET: bson.M{fDescription: description}})
}

func directionToFieldName(direction ExitDirection) string {
	switch direction {
	case DirectionNorth:
		return fNorth
	case DirectionEast:
		return fEast
	case DirectionSouth:
		return fSouth
	case DirectionWest:
		return fWest
	case DirectionUp:
		return fUp
	case DirectionDown:
		return fDown
	}

	// Wouldn't ever expect DirectionNone to be passed here
	panic("Unexpected code path")
}

func CommitRoom(session *mgo.Session, room Room) error {
	c := getCollection(session, cRooms)
	return c.Update(bson.M{fId: room.Id}, room)
}

func CommitCharacter(session *mgo.Session, character Character) error {
	c := getCollection(session, cCharacters)
	return c.Update(bson.M{fId: character.Id}, character)
}

func MoveCharacter(session *mgo.Session, character *Character, direction ExitDirection) (Room, error) {
	room, err := GetRoom(session, character.RoomId)

	if err != nil {
		return room, err
	}

	newLocation := room.Location

	switch direction {
	case DirectionNorth:
		newLocation.Y -= 1
	case DirectionEast:
		newLocation.X += 1
	case DirectionSouth:
		newLocation.Y += 1
	case DirectionWest:
		newLocation.X -= 1
	case DirectionUp:
		newLocation.Z -= 1
	case DirectionDown:
		newLocation.Z += 1
	default:
		panic("Unexpected code path")
	}

	room, err = GetRoomByLocation(session, newLocation)

	if err != nil {
		fmt.Printf("No room found at location %v, creating a new one\n", newLocation)
		room = newRoom()

		switch direction {
		case DirectionNorth:
			room.ExitSouth = true
		case DirectionEast:
			room.ExitWest = true
		case DirectionSouth:
			room.ExitNorth = true
		case DirectionWest:
			room.ExitEast = true
		case DirectionUp:
			room.ExitDown = true
		case DirectionDown:
			room.ExitUp = true
		default:
			panic("Unexpected code path")
		}

		room.Location = newLocation
		room, err = CreateRoom(session, room)
	} else {
		character.RoomId = room.Id
		err = CommitCharacter(session, *character)
	}

	return room, err
}

// vim: nocindent
<commit_msg>Consolodated some duplicate code<commit_after>package database

import (
	"fmt"
	"labix.org/v2/mgo"
	"labix.org/v2/mgo/bson"
	"mud/utils"
)

type dbError struct {
	message string
}

func (self dbError) Error() string {
	return self.message
}

func newDbError(message string) dbError {
	var err dbError
	err.message = message
	return err
}

type collectionName string

func getCollection(session *mgo.Session, collection collectionName) *mgo.Collection {
	return session.DB("mud").C(string(collection))
}

// Collection names
const (
	cUsers      = collectionName("users")
	cCharacters = collectionName("characters")
	cRooms      = collectionName("rooms")
)

// Field names
const (
	fId          = "_id"
	fName        = "name"
	fCharacters  = "characters"
	fRoom        = "room"
	fLocation    = "location"
	fTitle       = "title"
	fDescription = "description"
	fNorth       = "exit_north"
	fEast        = "exit_east"
	fSouth       = "exit_south"
	fWest        = "exit_west"
	fUp          = "exit_up"
	fDown        = "exit_down"
	fDefault     = "default"
)

// DB commands
const (
	SET  = "$set"
	PUSH = "$push"
	PULL = "$pull"
)

func FindUser(session *mgo.Session, name string) (bool, error) {
	c := getCollection(session, cUsers)
	q := c.Find(bson.M{fName: name})

	count, err := q.Count()

	if err != nil {
		return false, err
	}

	return count > 0, nil
}

func NewUser(session *mgo.Session, name string) error {

	found, err := FindUser(session, name)

	if err != nil {
		return err
	}

	if found {
		return newDbError("That user already exists")
	}

	c := getCollection(session, cUsers)
	c.Insert(bson.M{fName: name})

	return nil
}

func GetCharacterRoom(session *mgo.Session, character Character) (Room, error) {
	return GetRoom(session, character.RoomId)
}

func FindObject(session *mgo.Session, collection collectionName, query interface{}, object interface{}) error {
	c := getCollection(session, collection)
	q := c.Find(query)

	count, err := q.Count()

	if err != nil {
		return err
	}

	if count == 0 {
		return newDbError(fmt.Sprintf("Query return no results: %v", query))
	}

	err = q.One(object)

	return err
}

func FindRoom(session *mgo.Session, query interface{}) (Room, error) {
	var room Room
	err := FindObject(session, cRooms, query, &room)
	return room, err
}

func FindCharacter(session *mgo.Session, query interface{}) (Character, error) {
	var character Character
	err := FindObject(session, cCharacters, query, &character)
	return character, err
}

func GetCharacter(session *mgo.Session, id bson.ObjectId) (Character, error) {
	return FindCharacter(session, bson.M{fId: id})
}

func GetCharacterByName(session *mgo.Session, name string) (Character, error) {
	return FindCharacter(session, bson.M{fName: name})
}

func GetRoom(session *mgo.Session, id bson.ObjectId) (Room, error) {
	return FindRoom(session, bson.M{fId: id})
}

func GetRoomByLocation(session *mgo.Session, location Coordinate) (Room, error) {
	return FindRoom(session, bson.M{fLocation: location})
}

func CreateRoom(session *mgo.Session, room Room) (Room, error) {
	c := getCollection(session, cRooms)
	err := c.Insert(room)

	if err != nil {
		fmt.Printf("Error creating room: %v\n", err)
		return room, err
	}

	room, err = GetRoomByLocation(session, room.Location)

	return room, err
}

func CreateCharacter(session *mgo.Session, userName string, characterName string) (Character, error) {
	character, err := GetCharacterByName(session, characterName)

	if err == nil {
		return character, newDbError("That character already exists")
	}

	character = newCharacter(characterName)

	characterCollection := getCollection(session, cCharacters)
	err = characterCollection.Insert(character)

	if err != nil {
		fmt.Printf("Error inserting new character object into database: %v\n", err)
		return character, err
	}

	character, err = GetCharacterByName(session, character.Name)

	startingRoom, err := StartingRoom(session)

	if err != nil {
		fmt.Printf("Error getting starting room: %v\n", err)
		return character, err
	}

	character.RoomId = startingRoom.Id
	err = CommitCharacter(session, character)

	if err != nil {
		fmt.Printf("Error committing character object: %v\n", err)
		return character, err
	}

	if err == nil {
		userCollection := getCollection(session, cUsers)
		err = userCollection.Update(bson.M{fName: userName}, bson.M{PUSH: bson.M{fCharacters: character.Id}})

		if err != nil {
			fmt.Printf("Error updating user with new character data: %v\n", err)
		}
	}

	return character, err
}

func SetCharacterRoom(session *mgo.Session, character string, roomId bson.ObjectId) error {
	c := getCollection(session, cCharacters)
	err := c.Update(bson.M{fName: character}, bson.M{SET: bson.M{fRoom: roomId}})

	if err != nil {
		fmt.Printf("Failed setting character room :%v\n", err)
	}

	return err
}

func GetUserCharacters(session *mgo.Session, userName string) ([]Character, error) {
	c := getCollection(session, cUsers)
	q := c.Find(bson.M{fName: userName})

	result := map[string][]bson.ObjectId{}
	err := q.One(&result)

	var characters []Character
	for _, charId := range result[fCharacters] {
		character, err := GetCharacter(session, charId)

		if err != nil {
			fmt.Printf("Failed to find character with id %s, belonging to user %s: %s\n", charId, userName, err)
		} else {
			characters = append(characters, character)
		}
	}

	return characters, err
}

func DeleteCharacter(session *mgo.Session, user string, character string) error {
	c := getCollection(session, cUsers)
	c.Update(bson.M{fName: user}, bson.M{PULL: bson.M{fCharacters: utils.Simplify(character)}})

	c = getCollection(session, cCharacters)
	c.Remove(bson.M{fName: character})

	return nil
}

func StartingRoom(session *mgo.Session) (Room, error) {
	c := getCollection(session, cRooms)
	q := c.Find(bson.M{fDefault: true})

	count, err := q.Count()

	var room Room
	if err != nil {
		return room, err
	}

	if count == 0 {
		return room, newDbError("No default room found")
	}

	if count > 1 {
		fmt.Printf("Warning: More than one default room found\n")
	}

	err = q.One(&room)

	return room, err
}

func GenerateDefaultMap(session *mgo.Session) {
	c := getCollection(session, cRooms)
	c.DropCollection()

	room := newRoom()
	room.Location = Coordinate{0, 0, 0}
	room.Default = true

	CreateRoom(session, room)
}

func SetRoomTitle(session *mgo.Session, room Room, title string) error {
	c := getCollection(session, cRooms)
	return c.Update(bson.M{fId: room.Id}, bson.M{SET: bson.M{fTitle: title}})
}

func SetRoomDescription(session *mgo.Session, room Room, description string) error {
	c := getCollection(session, cRooms)
	return c.Update(bson.M{fId: room.Id}, bson.M{SET: bson.M{fDescription: description}})
}

func directionToFieldName(direction ExitDirection) string {
	switch direction {
	case DirectionNorth:
		return fNorth
	case DirectionEast:
		return fEast
	case DirectionSouth:
		return fSouth
	case DirectionWest:
		return fWest
	case DirectionUp:
		return fUp
	case DirectionDown:
		return fDown
	}

	// Wouldn't ever expect DirectionNone to be passed here
	panic("Unexpected code path")
}

func CommitRoom(session *mgo.Session, room Room) error {
	c := getCollection(session, cRooms)
	return c.Update(bson.M{fId: room.Id}, room)
}

func CommitCharacter(session *mgo.Session, character Character) error {
	c := getCollection(session, cCharacters)
	return c.Update(bson.M{fId: character.Id}, character)
}

func MoveCharacter(session *mgo.Session, character *Character, direction ExitDirection) (Room, error) {
	room, err := GetRoom(session, character.RoomId)

	if err != nil {
		return room, err
	}

	newLocation := room.Location

	switch direction {
	case DirectionNorth:
		newLocation.Y -= 1
	case DirectionEast:
		newLocation.X += 1
	case DirectionSouth:
		newLocation.Y += 1
	case DirectionWest:
		newLocation.X -= 1
	case DirectionUp:
		newLocation.Z -= 1
	case DirectionDown:
		newLocation.Z += 1
	default:
		panic("Unexpected code path")
	}

	room, err = GetRoomByLocation(session, newLocation)

	if err != nil {
		fmt.Printf("No room found at location %v, creating a new one\n", newLocation)
		room = newRoom()

		switch direction {
		case DirectionNorth:
			room.ExitSouth = true
		case DirectionEast:
			room.ExitWest = true
		case DirectionSouth:
			room.ExitNorth = true
		case DirectionWest:
			room.ExitEast = true
		case DirectionUp:
			room.ExitDown = true
		case DirectionDown:
			room.ExitUp = true
		default:
			panic("Unexpected code path")
		}

		room.Location = newLocation
		room, err = CreateRoom(session, room)
	} else {
		character.RoomId = room.Id
		err = CommitCharacter(session, *character)
	}

	return room, err
}

// vim: nocindent
<|endoftext|>


<commit_before>// Copyright 2017-2018 gf Author(https://github.com/gogf/gf). All Rights Reserved.
//
// This Source Code Form is subject to the terms of the MIT License.
// If a copy of the MIT was not distributed with this file,
// You can obtain one at https://github.com/gogf/gf.

// go test *.go -bench=".*"

package gregex_test

import (
    "github.com/gogf/gf/g/text/gregex"
    "testing"
)

var pattern = `(.+):(\d+)`
var src     = "johng.cn:80"
var replace = "johng.cn"

func BenchmarkValidate(b *testing.B) {
    for i := 0; i < b.N; i++ {
        gregex.Validate(pattern)
    }
}

func BenchmarkIsMatch(b *testing.B) {
    for i := 0; i < b.N; i++ {
        gregex.IsMatch(pattern, []byte(src))
    }
}

func BenchmarkIsMatchString(b *testing.B) {
    for i := 0; i < b.N; i++ {
        gregex.IsMatchString(pattern, src)
    }
}

func BenchmarkMatchString(b *testing.B) {
    for i := 0; i < b.N; i++ {
        gregex.MatchString(pattern, src)
    }
}

func BenchmarkMatchAllString(b *testing.B) {
    for i := 0; i < b.N; i++ {
        gregex.MatchAllString(pattern, src)
    }
}

func BenchmarkReplace(b *testing.B) {
    for i := 0; i < b.N; i++ {
        gregex.Replace(pattern, []byte(replace), []byte(src))
    }
}

func BenchmarkReplaceString(b *testing.B) {
    for i := 0; i < b.N; i++ {
        gregex.ReplaceString(pattern, replace, src)
    }
}
<commit_msg>update benchmark test cases for gregex<commit_after>// Copyright 2017-2018 gf Author(https://github.com/gogf/gf). All Rights Reserved.
//
// This Source Code Form is subject to the terms of the MIT License.
// If a copy of the MIT was not distributed with this file,
// You can obtain one at https://github.com/gogf/gf.

// go test *.go -bench=".*"

package gregex_test

import (
    "github.com/gogf/gf/g/text/gregex"
	"regexp"
	"testing"
)

var pattern = `(\w+).+\-\-\s*(.+)`
var src     = `GF is best! -- John`

func Benchmark_GF(b *testing.B) {
	for i := 0; i < b.N; i++ {
		gregex.IsMatchString(pattern, src)
	}
}

func Benchmark_Compile(b *testing.B) {
	var wcdRegexp = regexp.MustCompile(pattern)
	for i := 0; i < b.N; i++ {
		wcdRegexp.MatchString(src)
	}
}

func Benchmark_Compile_Actual(b *testing.B) {
	for i := 0; i < b.N; i++ {
		wcdRegexp := regexp.MustCompile(pattern)
		wcdRegexp.MatchString(src)
	}
}
<|endoftext|>


<commit_before>package mid

import (
	"github.com/gomidi/midi/midimessage/meta/meter"
	// "bytes"
	"fmt"
	"github.com/gomidi/midi"
	"github.com/gomidi/midi/midimessage/channel"
	"github.com/gomidi/midi/midimessage/meta"
	"github.com/gomidi/midi/midimessage/realtime"
	"github.com/gomidi/midi/midimessage/syscommon"
	"github.com/gomidi/midi/midimessage/sysex"
	"github.com/gomidi/midi/midiwriter"
	"github.com/gomidi/midi/smf"
	"github.com/gomidi/midi/smf/smfwriter"
	"io"
	"os"
	// "time"
)

type LiveWriter struct {
	*midiWriter
}

func (l *LiveWriter) ActiveSensing() error {
	_, err := l.midiWriter.wr.Write(realtime.ActiveSensing)
	return err
}

func (l *LiveWriter) Continue() error {
	_, err := l.midiWriter.wr.Write(realtime.Continue)
	return err
}

func (l *LiveWriter) Reset() error {
	_, err := l.midiWriter.wr.Write(realtime.Reset)
	return err
}

func (l *LiveWriter) Start() error {
	_, err := l.midiWriter.wr.Write(realtime.Start)
	return err
}

func (l *LiveWriter) Stop() error {
	_, err := l.midiWriter.wr.Write(realtime.Stop)
	return err
}

func (l *LiveWriter) Tick() error {
	_, err := l.midiWriter.wr.Write(realtime.Tick)
	return err
}

func (l *LiveWriter) TimingClock() error {
	_, err := l.midiWriter.wr.Write(realtime.TimingClock)
	return err
}

func (l *LiveWriter) MIDITimingCode(code uint8) error {
	_, err := l.midiWriter.wr.Write(syscommon.MIDITimingCode(code))
	return err
}

func (l *LiveWriter) SongPositionPointer(ptr uint16) error {
	_, err := l.midiWriter.wr.Write(syscommon.SongPositionPointer(ptr))
	return err
}

func (l *LiveWriter) SongSelect(song uint8) error {
	_, err := l.midiWriter.wr.Write(syscommon.SongSelect(song))
	return err
}

func (l *LiveWriter) TuneRequest() error {
	_, err := l.midiWriter.wr.Write(syscommon.TuneRequest)
	return err
}

type midiWriter struct {
	wr midi.Writer
	ch channel.Channel
}

func (m *midiWriter) SetChannel(no uint8 /* 0-15 */) {
	m.ch = channel.New(no)
}

func (m *midiWriter) ChannelPressure(pressure uint8) error {
	_, err := m.wr.Write(m.ch.ChannelPressure(pressure))
	return err
}

func (m *midiWriter) KeyPressure(key, pressure uint8) error {
	_, err := m.wr.Write(m.ch.KeyPressure(key, pressure))
	return err
}

func (m *midiWriter) NoteOff(key uint8) error {
	_, err := m.wr.Write(m.ch.NoteOff(key))
	return err
}

func (m *midiWriter) NoteOn(key, veloctiy uint8) error {
	_, err := m.wr.Write(m.ch.NoteOn(key, veloctiy))
	return err
}

func (m *midiWriter) PitchBend(value int16) error {
	_, err := m.wr.Write(m.ch.PitchBend(value))
	return err
}

func (m *midiWriter) ProgramChange(program uint8) error {
	_, err := m.wr.Write(m.ch.ProgramChange(program))
	return err
}

func (m *midiWriter) CC(cch channel.ControlChange) error {
	_, err := m.wr.Write(cch)
	return err
}

func (m *midiWriter) ControlChange(controller, value uint8) error {
	_, err := m.wr.Write(m.ch.ControlChange(controller, value))
	return err
}

func (m *midiWriter) SysEx(data []byte) error {
	_, err := m.wr.Write(sysex.SysEx(data))
	return err
}

type SMFWriter struct {
	wr smf.Writer
	*midiWriter
	finishedTracks uint16
	dest           io.Writer
}

func (s *SMFWriter) SetDelta(deltatime uint32) {
	s.wr.SetDelta(deltatime)
}

func (s *SMFWriter) EndOfTrack() error {

	if no := s.wr.Header().NumTracks; s.finishedTracks >= no {
		return fmt.Errorf("too many tracks: in header: %v, closed: %v", no, s.finishedTracks+1)
	}
	s.finishedTracks++
	_, err := s.wr.Write(meta.EndOfTrack)
	return err
}

func (s *SMFWriter) Copyright(text string) error {
	_, err := s.wr.Write(meta.Copyright(text))
	return err
}

func (s *SMFWriter) Cuepoint(text string) error {
	_, err := s.wr.Write(meta.Cuepoint(text))
	return err
}

func (s *SMFWriter) DevicePort(port string) error {
	_, err := s.wr.Write(meta.DevicePort(port))
	return err
}

func (s *SMFWriter) KeySignature(key uint8, ismajor bool, num uint8, isflat bool) error {
	_, err := s.wr.Write(meta.KeySignature{Key: key, IsMajor: ismajor, Num: num, IsFlat: isflat})
	return err
}

// Key is supposed to be used with the midi/midimessage/meta/key package
func (s *SMFWriter) Key(keysig meta.KeySignature) error {
	_, err := s.wr.Write(keysig)
	return err
}

func (s *SMFWriter) Lyric(text string) error {
	_, err := s.wr.Write(meta.Lyric(text))
	return err
}

func (s *SMFWriter) Marker(text string) error {
	_, err := s.wr.Write(meta.Marker(text))
	return err
}

func (s *SMFWriter) MIDIChannel(ch uint8) error {
	_, err := s.wr.Write(meta.MIDIChannel(ch))
	return err
}

func (s *SMFWriter) MIDIPort(port uint8) error {
	_, err := s.wr.Write(meta.MIDIPort(port))
	return err
}

func (s *SMFWriter) ProgramName(text string) error {
	_, err := s.wr.Write(meta.ProgramName(text))
	return err
}

func (s *SMFWriter) Sequence(text string) error {
	_, err := s.wr.Write(meta.Sequence(text))
	return err
}

func (s *SMFWriter) SequenceNumber(no uint16) error {
	_, err := s.wr.Write(meta.SequenceNumber(no))
	return err
}

func (s *SMFWriter) SequencerSpecific(data []byte) error {
	_, err := s.wr.Write(meta.SequencerSpecific(data))
	return err
}

func (s *SMFWriter) SMPTEOffset(hour, minute, second, frame, fractionalFrame byte) error {
	_, err := s.wr.Write(meta.SMPTEOffset{
		Hour:            hour,
		Minute:          minute,
		Second:          second,
		Frame:           frame,
		FractionalFrame: fractionalFrame,
	})
	return err
}

func (s *SMFWriter) Tempo(bpm uint32) error {
	_, err := s.wr.Write(meta.Tempo(bpm))
	return err
}

func (s *SMFWriter) Text(text string) error {
	_, err := s.wr.Write(meta.Text(text))
	return err
}

func (s *SMFWriter) Meter(numerator, denominator uint8) error {
	_, err := s.wr.Write(meter.Meter(numerator, denominator))
	return err
}

// If you don't want to deal with clocks per click and demisemiquaverperquarter,
// user the Meter method instead
func (s *SMFWriter) TimeSignature(numerator, denominator, clocksPerClick, demiSemiQuaverPerQuarter uint8) error {
	_, err := s.wr.Write(meta.TimeSignature{
		Numerator:                numerator,
		Denominator:              denominator,
		ClocksPerClick:           clocksPerClick,
		DemiSemiQuaverPerQuarter: demiSemiQuaverPerQuarter,
	})
	return err
}

func (s *SMFWriter) Track(track string) error {
	_, err := s.wr.Write(meta.Track(track))
	return err
}

// panics if numtracks is == 0
func NewSMFWriter(dest io.Writer, numtracks uint16) *SMFWriter {
	if numtracks == 0 {
		panic("numtracks must be > 0")
	}
	wr := smfwriter.New(dest, smfwriter.NumTracks(numtracks), smfwriter.TimeFormat(smf.MetricTicks(0)))
	return &SMFWriter{
		dest:       dest,
		wr:         wr,
		midiWriter: &midiWriter{wr: wr, ch: channel.Ch0},
	}
}

// Creates a new SMF file and allows writer to write to it.
// The file is guaranteed to be closed when returning.
// The last track is closed automatically, if needed.
func NewSMFFile(file string, numtracks uint16, writer func(*SMFWriter) error) error {
	f, err := os.Create(file)
	if err != nil {
		return err
	}

	defer f.Close()

	wr := NewSMFWriter(f, numtracks)
	if writer != nil {
		err = writer(wr)
		if err != nil {
			return err
		}
	}

	if no := wr.wr.Header().NumTracks; wr.finishedTracks < no {
		err := wr.EndOfTrack()
		if err != nil {
			return err
		}
	}

	return err
}

// NewLiveWriter creates and new LiveWriter
func NewLiveWriter(dest io.Writer) *LiveWriter {
	wr := midiwriter.New(dest, midiwriter.NoRunningStatus())
	return &LiveWriter{&midiWriter{wr: wr, ch: channel.Ch0}}
}

/*
func init() {
	var bf bytes.Buffer
	wr := NewLiveWriter(&bf)
	wr.SetChannel(2)
	wr.NoteOn(102, 80)
	time.Sleep(time.Second)
	wr.NoteOff(102)
}

func init() {
	err := NewSMFFile("test.mid", 2, func(wr *SMFWriter) (err error) {
		for {
			err = wr.Copyright("just a test")

			if err != nil {
				break
			}

			err = wr.Tempo(144)

			if err != nil {
				break
			}

			err = wr.TimeSignature(3, 4)

			if err != nil {
				break
			}

			wr.SetDelta(12)

			err = wr.NoteOn(60, 110)

			if err != nil {
				break
			}

			wr.SetDelta(32)

			err = wr.NoteOff(60)

			if err != nil {
				break
			}

			break // leave at the end
		}
		return
	})

	if err != nil {
		fmt.Printf("Error: %v\n", err)
	}
}

*/
<commit_msg>improve docs for mid writers<commit_after>package mid

import (
	"github.com/gomidi/midi/midimessage/meta/meter"
	// "bytes"
	"fmt"
	"github.com/gomidi/midi"
	"github.com/gomidi/midi/midimessage/channel"
	"github.com/gomidi/midi/midimessage/meta"
	"github.com/gomidi/midi/midimessage/realtime"
	"github.com/gomidi/midi/midimessage/syscommon"
	"github.com/gomidi/midi/midimessage/sysex"
	"github.com/gomidi/midi/midiwriter"
	"github.com/gomidi/midi/smf"
	"github.com/gomidi/midi/smf/smfwriter"
	"io"
	"os"
	// "time"
)

// LiveWriter writes live MIDI data. Its methods must not be called concurrently
type LiveWriter struct {
	*midiWriter
}

// ActiveSensing writes the active sensing realtime message
func (l *LiveWriter) ActiveSensing() error {
	_, err := l.midiWriter.wr.Write(realtime.ActiveSensing)
	return err
}

// Continue writes the continue realtime message
func (l *LiveWriter) Continue() error {
	_, err := l.midiWriter.wr.Write(realtime.Continue)
	return err
}

// Reset writes the reset realtime message
func (l *LiveWriter) Reset() error {
	_, err := l.midiWriter.wr.Write(realtime.Reset)
	return err
}

// Start writes the start realtime message
func (l *LiveWriter) Start() error {
	_, err := l.midiWriter.wr.Write(realtime.Start)
	return err
}

// Stop writes the stop realtime message
func (l *LiveWriter) Stop() error {
	_, err := l.midiWriter.wr.Write(realtime.Stop)
	return err
}

// Tick writes the tick realtime message
func (l *LiveWriter) Tick() error {
	_, err := l.midiWriter.wr.Write(realtime.Tick)
	return err
}

// TimingClock writes the timing clock realtime message
func (l *LiveWriter) TimingClock() error {
	_, err := l.midiWriter.wr.Write(realtime.TimingClock)
	return err
}

// MIDITimingCode writes the MIDI Timing Code system message
func (l *LiveWriter) MIDITimingCode(code uint8) error {
	_, err := l.midiWriter.wr.Write(syscommon.MIDITimingCode(code))
	return err
}

// SongPositionPointer writes the song position pointer system message
func (l *LiveWriter) SongPositionPointer(ptr uint16) error {
	_, err := l.midiWriter.wr.Write(syscommon.SongPositionPointer(ptr))
	return err
}

// SongSelect writes the song select system message
func (l *LiveWriter) SongSelect(song uint8) error {
	_, err := l.midiWriter.wr.Write(syscommon.SongSelect(song))
	return err
}

// TuneRequest writes the tune request system message
func (l *LiveWriter) TuneRequest() error {
	_, err := l.midiWriter.wr.Write(syscommon.TuneRequest)
	return err
}

type midiWriter struct {
	wr midi.Writer
	ch channel.Channel
}

// SetChannel sets the channel for the following midi messages
// Channel numbers are counted from 0 to 15 (MIDI channel 1 to 16).
// The initial channel number is 0.
func (m *midiWriter) SetChannel(no uint8 /* 0-15 */) {
	m.ch = channel.New(no)
}

// ChannelPressure writes a channel pressure message for the current channel
func (m *midiWriter) ChannelPressure(pressure uint8) error {
	_, err := m.wr.Write(m.ch.ChannelPressure(pressure))
	return err
}

// KeyPressure writes a key pressure message for the current channel
func (m *midiWriter) KeyPressure(key, pressure uint8) error {
	_, err := m.wr.Write(m.ch.KeyPressure(key, pressure))
	return err
}

// NoteOff writes a note off message for the current channel
func (m *midiWriter) NoteOff(key uint8) error {
	_, err := m.wr.Write(m.ch.NoteOff(key))
	return err
}

// NoteOn writes a note on message for the current channel
func (m *midiWriter) NoteOn(key, veloctiy uint8) error {
	_, err := m.wr.Write(m.ch.NoteOn(key, veloctiy))
	return err
}

// PitchBend writes a pitch bend message for the current channel
func (m *midiWriter) PitchBend(value int16) error {
	_, err := m.wr.Write(m.ch.PitchBend(value))
	return err
}

// ProgramChange writes a program change message for the current channel
// Program numbers start with 0 for program 1.
func (m *midiWriter) ProgramChange(program uint8) error {
	_, err := m.wr.Write(m.ch.ProgramChange(program))
	return err
}

// CC writes a control change message. It is meant to be used in conjunction
// with the midimessages/cc package.
func (m *midiWriter) CC(cch channel.ControlChange) error {
	_, err := m.wr.Write(cch)
	return err
}

// ControlChange writes a control change message for the current channel
func (m *midiWriter) ControlChange(controller, value uint8) error {
	_, err := m.wr.Write(m.ch.ControlChange(controller, value))
	return err
}

// SysEx writes sysex data
func (m *midiWriter) SysEx(data []byte) error {
	_, err := m.wr.Write(sysex.SysEx(data))
	return err
}

// SMFWriter writes SMF MIDI data. Its methods must not be called concurrently
type SMFWriter struct {
	wr smf.Writer
	*midiWriter
	finishedTracks uint16
	dest           io.Writer
}

// SetDelta sets the delta ticks to the next message
func (s *SMFWriter) SetDelta(deltatime uint32) {
	s.wr.SetDelta(deltatime)
}

// EndOfTrack signals the end of a track
func (s *SMFWriter) EndOfTrack() error {

	if no := s.wr.Header().NumTracks; s.finishedTracks >= no {
		return fmt.Errorf("too many tracks: in header: %v, closed: %v", no, s.finishedTracks+1)
	}
	s.finishedTracks++
	_, err := s.wr.Write(meta.EndOfTrack)
	return err
}

// Copyright writes the copyright meta message
func (s *SMFWriter) Copyright(text string) error {
	_, err := s.wr.Write(meta.Copyright(text))
	return err
}

// Cuepoint writes the cuepoint meta message
func (s *SMFWriter) Cuepoint(text string) error {
	_, err := s.wr.Write(meta.Cuepoint(text))
	return err
}

// DevicePort writes the device port meta message
func (s *SMFWriter) DevicePort(port string) error {
	_, err := s.wr.Write(meta.DevicePort(port))
	return err
}

// KeySignature writes the key signature meta message.
// A more comfortable way is to use the Key method in conjunction
// with the midimessage/meta/key package
func (s *SMFWriter) KeySignature(key uint8, ismajor bool, num uint8, isflat bool) error {
	_, err := s.wr.Write(meta.KeySignature{Key: key, IsMajor: ismajor, Num: num, IsFlat: isflat})
	return err
}

// Key writes the given key signature meta message.
// It is supposed to be used with the midimessage/meta/key package
func (s *SMFWriter) Key(keysig meta.KeySignature) error {
	_, err := s.wr.Write(keysig)
	return err
}

// Lyric writes the lyric meta message
func (s *SMFWriter) Lyric(text string) error {
	_, err := s.wr.Write(meta.Lyric(text))
	return err
}

// Marker writes the marker meta message
func (s *SMFWriter) Marker(text string) error {
	_, err := s.wr.Write(meta.Marker(text))
	return err
}

// MIDIChannel writes the MIDI channel meta message
func (s *SMFWriter) MIDIChannel(ch uint8) error {
	_, err := s.wr.Write(meta.MIDIChannel(ch))
	return err
}

// MIDIPort writes the MIDI port meta message
func (s *SMFWriter) MIDIPort(port uint8) error {
	_, err := s.wr.Write(meta.MIDIPort(port))
	return err
}

// ProgramName writes the program name meta message
func (s *SMFWriter) ProgramName(text string) error {
	_, err := s.wr.Write(meta.ProgramName(text))
	return err
}

// Sequence writes the sequence (name) meta message
func (s *SMFWriter) Sequence(text string) error {
	_, err := s.wr.Write(meta.Sequence(text))
	return err
}

// SequenceNumber writes the sequence number meta message
func (s *SMFWriter) SequenceNumber(no uint16) error {
	_, err := s.wr.Write(meta.SequenceNumber(no))
	return err
}

// SequencerSpecific writes a custom sequences specific meta message
func (s *SMFWriter) SequencerSpecific(data []byte) error {
	_, err := s.wr.Write(meta.SequencerSpecific(data))
	return err
}

// SMPTEOffset writes the SMPTE offset meta message
func (s *SMFWriter) SMPTEOffset(hour, minute, second, frame, fractionalFrame byte) error {
	_, err := s.wr.Write(meta.SMPTEOffset{
		Hour:            hour,
		Minute:          minute,
		Second:          second,
		Frame:           frame,
		FractionalFrame: fractionalFrame,
	})
	return err
}

// Tempo writes the tempo meta message
func (s *SMFWriter) Tempo(bpm uint32) error {
	_, err := s.wr.Write(meta.Tempo(bpm))
	return err
}

// Text writes the text meta message
func (s *SMFWriter) Text(text string) error {
	_, err := s.wr.Write(meta.Text(text))
	return err
}

// Meter writes the time signature meta message i a more comfortable way.
// Numerator and Denominator are decimals.
func (s *SMFWriter) Meter(numerator, denominator uint8) error {
	_, err := s.wr.Write(meter.Meter(numerator, denominator))
	return err
}

// TimeSignature writes the time signature meta message.
// Numerator and Denominator are decimals.
// If you don't want to deal with clocks per click and demisemiquaverperquarter,
// user the Meter method instead.
func (s *SMFWriter) TimeSignature(numerator, denominator, clocksPerClick, demiSemiQuaverPerQuarter uint8) error {
	_, err := s.wr.Write(meta.TimeSignature{
		Numerator:                numerator,
		Denominator:              denominator,
		ClocksPerClick:           clocksPerClick,
		DemiSemiQuaverPerQuarter: demiSemiQuaverPerQuarter,
	})
	return err
}

// Track writes the track name aka instrument name meta message
func (s *SMFWriter) Track(track string) error {
	_, err := s.wr.Write(meta.Track(track))
	return err
}

// NewSMFWriter returns a new SMFWriter that writes to dest.
// It panics if numtracks is == 0.
func NewSMFWriter(dest io.Writer, numtracks uint16) *SMFWriter {
	if numtracks == 0 {
		panic("numtracks must be > 0")
	}
	wr := smfwriter.New(dest, smfwriter.NumTracks(numtracks), smfwriter.TimeFormat(smf.MetricTicks(0)))
	return &SMFWriter{
		dest:       dest,
		wr:         wr,
		midiWriter: &midiWriter{wr: wr, ch: channel.Ch0},
	}
}

// NewSMFFile creates a new SMF file and allows writer to write to it.
// The file is guaranteed to be closed when returning.
// The last track is closed automatically, if needed.
func NewSMFFile(file string, numtracks uint16, writer func(*SMFWriter) error) error {
	f, err := os.Create(file)
	if err != nil {
		return err
	}

	defer f.Close()

	wr := NewSMFWriter(f, numtracks)
	if writer != nil {
		err = writer(wr)
		if err != nil {
			return err
		}
	}

	if no := wr.wr.Header().NumTracks; wr.finishedTracks < no {
		err := wr.EndOfTrack()
		if err != nil {
			return err
		}
	}

	return err
}

// NewLiveWriter creates and new LiveWriter
func NewLiveWriter(dest io.Writer) *LiveWriter {
	wr := midiwriter.New(dest, midiwriter.NoRunningStatus())
	return &LiveWriter{&midiWriter{wr: wr, ch: channel.Ch0}}
}
<|endoftext|>


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

package oboe

// Disable AAudio (#1634).
// AAudio doesn't care about plugging in/out of a headphone.
// See https://github.com/google/oboe/blob/master/docs/notes/disconnect.md

// #cgo CXXFLAGS: -std=c++17 -DOBOE_ENABLE_AAUDIO=0
// #cgo LDFLAGS: -llog -lOpenSLES -static-libstdc++
//
// #include "binding_android.h"
import "C"

import (
	"fmt"
	"runtime"
	"unsafe"
)

func Suspend() error {
	if msg := C.ebiten_oboe_Suspend(); msg != nil {
		return fmt.Errorf("oboe: Suspend failed: %s", C.GoString(msg))
	}
	return nil
}

func Resume() error {
	if msg := C.ebiten_oboe_Resume(); msg != nil {
		return fmt.Errorf("oboe: Resume failed: %s", C.GoString(msg))
	}
	return nil
}

type Player struct {
	player    C.PlayerID
	onWritten func()
}

func NewPlayer(sampleRate, channelNum, bitDepthInBytes int, volume float64, onWritten func()) *Player {
	p := &Player{
		onWritten: onWritten,
	}
	p.player = C.ebiten_oboe_Player_Create(C.int(sampleRate), C.int(channelNum), C.int(bitDepthInBytes), C.double(volume), C.uintptr_t(uintptr(unsafe.Pointer(p))))
	runtime.SetFinalizer(p, (*Player).Close)
	return p
}

//export onWrittenCallback
func onWrittenCallback(player C.uintptr_t) {
	p := (*Player)(unsafe.Pointer(uintptr(player)))
	p.onWritten()
}

func (p *Player) IsPlaying() bool {
	return bool(C.ebiten_oboe_Player_IsPlaying(p.player))
}

func (p *Player) AppendBuffer(buf []byte) {
	ptr := C.CBytes(buf)
	defer C.free(ptr)

	C.ebiten_oboe_Player_AppendBuffer(p.player, (*C.uint8_t)(ptr), C.int(len(buf)))
}

func (p *Player) Play() error {
	if p.player == 0 {
		return fmt.Errorf("oboe: player is already closed at Play")
	}
	if msg := C.ebiten_oboe_Player_Play(p.player); msg != nil {
		return fmt.Errorf("oboe: Player_Play failed: %s", C.GoString(msg))
	}
	return nil
}

func (p *Player) Pause() error {
	if p.player == 0 {
		return fmt.Errorf("oboe: player is already closed at Pause")
	}
	if msg := C.ebiten_oboe_Player_Pause(p.player); msg != nil {
		return fmt.Errorf("oboe: Player_Pause failed: %s", C.GoString(msg))
	}
	return nil
}

func (p *Player) SetVolume(volume float64) {
	C.ebiten_oboe_Player_SetVolume(p.player, C.double(volume))
}

func (p *Player) Close() error {
	runtime.SetFinalizer(p, nil)
	if p.player == 0 {
		return fmt.Errorf("oboe: player is already closed at Close")
	}
	if msg := C.ebiten_oboe_Player_Close(p.player); msg != nil {
		return fmt.Errorf("oboe: Player_Close failed: %s", C.GoString(msg))
	}
	p.player = 0
	return nil
}

func (p *Player) UnplayedBufferSize() int {
	return int(C.ebiten_oboe_Player_UnplayedBufferSize(p.player))
}
<commit_msg>audio/internal/oboe: Bug fix: Player must be protected by a mutex<commit_after>// Copyright 2021 The Ebiten Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package oboe

// Disable AAudio (#1634).
// AAudio doesn't care about plugging in/out of a headphone.
// See https://github.com/google/oboe/blob/master/docs/notes/disconnect.md

// #cgo CXXFLAGS: -std=c++17 -DOBOE_ENABLE_AAUDIO=0
// #cgo LDFLAGS: -llog -lOpenSLES -static-libstdc++
//
// #include "binding_android.h"
import "C"

import (
	"fmt"
	"runtime"
	"sync"
	"unsafe"
)

func Suspend() error {
	if msg := C.ebiten_oboe_Suspend(); msg != nil {
		return fmt.Errorf("oboe: Suspend failed: %s", C.GoString(msg))
	}
	return nil
}

func Resume() error {
	if msg := C.ebiten_oboe_Resume(); msg != nil {
		return fmt.Errorf("oboe: Resume failed: %s", C.GoString(msg))
	}
	return nil
}

type Player struct {
	player    C.PlayerID
	onWritten func()

	// m is the mutex for this player.
	// This is necessary as Close can be invoked from the finalizer goroutine.
	m sync.Mutex
}

func NewPlayer(sampleRate, channelNum, bitDepthInBytes int, volume float64, onWritten func()) *Player {
	p := &Player{
		onWritten: onWritten,
	}
	p.player = C.ebiten_oboe_Player_Create(C.int(sampleRate), C.int(channelNum), C.int(bitDepthInBytes), C.double(volume), C.uintptr_t(uintptr(unsafe.Pointer(p))))
	runtime.SetFinalizer(p, (*Player).Close)
	return p
}

//export onWrittenCallback
func onWrittenCallback(player C.uintptr_t) {
	p := (*Player)(unsafe.Pointer(uintptr(player)))
	p.onWritten()
}

func (p *Player) IsPlaying() bool {
	p.m.Lock()
	defer p.m.Unlock()
	return bool(C.ebiten_oboe_Player_IsPlaying(p.player))
}

func (p *Player) AppendBuffer(buf []byte) {
	p.m.Lock()
	defer p.m.Unlock()

	ptr := C.CBytes(buf)
	defer C.free(ptr)

	C.ebiten_oboe_Player_AppendBuffer(p.player, (*C.uint8_t)(ptr), C.int(len(buf)))
}

func (p *Player) Play() error {
	p.m.Lock()
	defer p.m.Unlock()

	if p.player == 0 {
		return fmt.Errorf("oboe: player is already closed at Play")
	}
	if msg := C.ebiten_oboe_Player_Play(p.player); msg != nil {
		return fmt.Errorf("oboe: Player_Play failed: %s", C.GoString(msg))
	}
	return nil
}

func (p *Player) Pause() error {
	p.m.Lock()
	defer p.m.Unlock()

	if p.player == 0 {
		return fmt.Errorf("oboe: player is already closed at Pause")
	}
	if msg := C.ebiten_oboe_Player_Pause(p.player); msg != nil {
		return fmt.Errorf("oboe: Player_Pause failed: %s", C.GoString(msg))
	}
	return nil
}

func (p *Player) SetVolume(volume float64) {
	p.m.Lock()
	defer p.m.Unlock()
	C.ebiten_oboe_Player_SetVolume(p.player, C.double(volume))
}

func (p *Player) Close() error {
	p.m.Lock()
	defer p.m.Unlock()

	runtime.SetFinalizer(p, nil)
	if p.player == 0 {
		return fmt.Errorf("oboe: player is already closed at Close")
	}
	if msg := C.ebiten_oboe_Player_Close(p.player); msg != nil {
		return fmt.Errorf("oboe: Player_Close failed: %s", C.GoString(msg))
	}
	p.player = 0
	return nil
}

func (p *Player) UnplayedBufferSize() int {
	p.m.Lock()
	defer p.m.Unlock()
	return int(C.ebiten_oboe_Player_UnplayedBufferSize(p.player))
}
<|endoftext|>


<commit_before>package ast

import "fmt"

// === Start of Boolean Expressions

//BoolValExp wrap boolean
type BoolValExp struct {
	b bool
}

//Eval for BoolValExp return boolean
func (v BoolValExp) Eval(s State) bool {
	return v.b
}

func (v BoolValExp) String() string {
	return fmt.Sprintf("%v", v.b)
}

// BoolEqExp represent  left equal to right
type BoolEqExp struct {
	l ArithExp
	r ArithExp
}

// BoolLesExp represent left strict less than right
type BoolLesExp struct {
	l ArithExp
	r ArithExp
}

// TODO: we have < but don't have >

//
type BoolNotExp struct {
	b BoolExp
}

//
type BoolAndExp struct {
	l BoolExp
	r BoolExp
}

//
type BoolOrExp struct {
	l BoolExp
	r BoolExp
}

// Eval for BoolEqExp evaluate left equal right
func (equ BoolEqExp) Eval(s State) bool {
	return equ.l.Eval(s) == equ.r.Eval(s)
}

func (equ BoolEqExp) String() string {
	return fmt.Sprintf("%s = %s", equ.l, equ.r)
}

// Eval for BoolLesExp evaluate left less than right
func (les BoolLesExp) Eval(s State) bool {
	return les.l.Eval(s) < les.r.Eval(s)
}

func (les BoolLesExp) String() string {
	return fmt.Sprintf("%s < %s", les.l, les.r)
}

//
func (not BoolNotExp) Eval(s State) bool {
	return !not.b.Eval(s)
}

func (not BoolNotExp) String() string {
	return fmt.Sprintf("!%s", not.b)
}

//
func (and BoolAndExp) Eval(s State) bool {
	return and.l.Eval(s) && and.r.Eval(s)
}

func (and BoolAndExp) String() string {
	return fmt.Sprintf("%s and %s", and.l, and.r)
}

func (or BoolOrExp) Eval(s State) bool {
	return or.l.Eval(s) || or.r.Eval(s)
}

func (or BoolOrExp) String() string {
	return fmt.Sprintf("%s or %s", or.l, or.r)
}

// === End of Boolean Expressions
<commit_msg>[play][while][ast] add parentheses<commit_after>package ast

import "fmt"

// === Start of Boolean Expressions

//BoolValExp wrap boolean
type BoolValExp struct {
	b bool
}

//Eval for BoolValExp return boolean
func (v BoolValExp) Eval(s State) bool {
	return v.b
}

func (v BoolValExp) String() string {
	return fmt.Sprintf("%v", v.b)
}

// BoolEqExp represent  left equal to right
type BoolEqExp struct {
	l ArithExp
	r ArithExp
}

// BoolLesExp represent left strict less than right
type BoolLesExp struct {
	l ArithExp
	r ArithExp
}

// TODO: we have < but don't have >

//
type BoolNotExp struct {
	b BoolExp
}

//
type BoolAndExp struct {
	l BoolExp
	r BoolExp
}

//
type BoolOrExp struct {
	l BoolExp
	r BoolExp
}

// Eval for BoolEqExp evaluate left equal right
func (equ BoolEqExp) Eval(s State) bool {
	return equ.l.Eval(s) == equ.r.Eval(s)
}

func (equ BoolEqExp) String() string {
	return fmt.Sprintf("(%s = %s)", equ.l, equ.r)
}

// Eval for BoolLesExp evaluate left less than right
func (les BoolLesExp) Eval(s State) bool {
	return les.l.Eval(s) < les.r.Eval(s)
}

func (les BoolLesExp) String() string {
	return fmt.Sprintf("(%s < %s)", les.l, les.r)
}

//
func (not BoolNotExp) Eval(s State) bool {
	return !not.b.Eval(s)
}

func (not BoolNotExp) String() string {
	return fmt.Sprintf("(!%s)", not.b)
}

//
func (and BoolAndExp) Eval(s State) bool {
	return and.l.Eval(s) && and.r.Eval(s)
}

func (and BoolAndExp) String() string {
	return fmt.Sprintf("(%s and %s)", and.l, and.r)
}

func (or BoolOrExp) Eval(s State) bool {
	return or.l.Eval(s) || or.r.Eval(s)
}

func (or BoolOrExp) String() string {
	return fmt.Sprintf("(%s or %s)", or.l, or.r)
}

// === End of Boolean Expressions
<|endoftext|>


<commit_before>package cmd

const Version = "3.38.1"
<commit_msg>version bump<commit_after>package cmd

const Version = "3.38.2"
<|endoftext|>


<commit_before>/*
Copyright 2016 The Kubernetes Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package servicecatalog

import (
	kapi "k8s.io/kubernetes/pkg/api"
	"k8s.io/kubernetes/pkg/api/v1"
	metav1 "k8s.io/kubernetes/pkg/apis/meta/v1"
	"k8s.io/kubernetes/pkg/runtime"
)

// TODO: all metadata and parametersfields need to be refactored to real
// types; skipping for now to get very large generation PR in.

// +genclient=true
// +nonNamespaced=true

// Broker represents an entity that provides ServiceClasses for use in the
// service catalog.
type Broker struct {
	metav1.TypeMeta
	kapi.ObjectMeta

	Spec   BrokerSpec
	Status BrokerStatus
}

// BrokerList is a list of Brokers.
type BrokerList struct {
	metav1.TypeMeta
	metav1.ListMeta

	Items []Broker
}

// BrokerSpec represents a description of a Broker.
type BrokerSpec struct {
	// The URL to communicate with the Broker via..
	URL string

	// AuthSecret is a reference to a Secret containing auth information the
	// catalog should use to authenticate to this Broker.
	AuthSecret *v1.ObjectReference
}

// BrokerStatus represents the current status of a Broker.
type BrokerStatus struct {
	Conditions []BrokerCondition
}

// BrokerCondition represents an aspect of a Broker's status.
type BrokerCondition struct {
	Type    BrokerConditionType
	Status  ConditionStatus
	Reason  string
	Message string
}

// BrokerConditionType represents a broker condition value
type BrokerConditionType string

const (
	// BrokerConditionReady represents the fact that a given broker condition is in ready state
	BrokerConditionReady BrokerConditionType = "Ready"
)

// ConditionStatus represents a condition's status
type ConditionStatus string

// These are valid condition statuses. "ConditionTrue" means a resource is in
// the condition; "ConditionFalse" means a resource is not in the condition;
// "ConditionUnknown" means kubernetes can't decide if a resource is in the
// condition or not. In the future, we could add other intermediate
// conditions, e.g. ConditionDegraded.
const (
	// ConditionTrue represents the fact that a given condition is true
	ConditionTrue ConditionStatus = "True"
	// ConditionFalse represents the fact that a given condition is false
	ConditionFalse ConditionStatus = "False"
	// ConditionUnknown represents the fact that a given condition is unknown
	ConditionUnknown ConditionStatus = "Unknown"
)

// ServiceClassList is a list of ServiceClasses
type ServiceClassList struct {
	metav1.TypeMeta
	metav1.ListMeta

	Items []ServiceClass
}

// +genclient=true
// +nonNamespaced=true

// ServiceClass represents an offering in the service catalog.
type ServiceClass struct {
	metav1.TypeMeta
	kapi.ObjectMeta

	// BrokerName is the reference to the Broker that provides this service.
	// Immutable.
	BrokerName string

	Bindable      bool
	Plans         []ServicePlan
	PlanUpdatable bool // Do we support this?

	// OSB-specific
	// OSBGUID is the identity of this object for use with the OSB API.
	// Immutable.
	OSBGUID string

	// OSB-specific
	OSBTags                    []string
	OSBRequires                []string
	OSBMaxDBPerNode            *string
	OSBDashboardOAuth2ClientID *string
	OSBDashboardSecret         *string
	OSBDashboardRedirectURI    *string

	// Metadata fields
	Description         *string
	DisplayName         *string
	ImageURL            *string
	LongDescription     *string
	ProviderDisplayName *string
	DocumentationURL    *string
	SupportURL          *string
}

// ServicePlan represents a tier of a ServiceClass.
type ServicePlan struct {
	// CLI-friendly name of this plan
	Name string

	// OSB-specific
	// OSBGUID is the identity of this object for use with the OSB API.
	// Immutable.
	OSBGUID string

	// OSB-specific
	OSBFree     bool
	Description *string
	Bullets     []string
	DisplayName *string

	// TODO: add costs
}

// InstanceList is a list of instances.
type InstanceList struct {
	metav1.TypeMeta
	metav1.ListMeta

	Items []Instance
}

// +genclient=true

// Instance represents a provisioned instance of a ServiceClass.
type Instance struct {
	metav1.TypeMeta
	kapi.ObjectMeta

	Spec   InstanceSpec
	Status InstanceStatus
}

// InstanceSpec represents a description of an Instance.
type InstanceSpec struct {
	// ServiceClassName is the reference to the ServiceClass this is an
	// instance of.  Immutable.
	ServiceClassName string
	// ServicePlanName is the reference to the ServicePlan for this instance.
	PlanName string

	// Parameters is a YAML representation of the properties to be
	// passed to the underlying broker.
	Parameters *runtime.RawExtension

	// OSB-specific
	// OSBGUID is the identity of this object for use with the OSB API.
	// Immutable.
	OSBGUID string

	// OSB-specific
	OSBDashboardURL  *string
	OSBLastOperation *string
}

// InstanceStatus represents the current status of an Instance.
type InstanceStatus struct {
	Conditions []InstanceCondition
}

// InstanceCondition represents an aspect of an Instance's status.
type InstanceCondition struct {
	Type    InstanceConditionType
	Status  ConditionStatus
	Reason  string
	Message string
}

// InstanceConditionType represents a instance condition value
type InstanceConditionType string

const (
	// InstanceConditionProvisioning represents that a given instance condition is in
	// provisioning state
	InstanceConditionProvisioning InstanceConditionType = "Provisioning"
	// InstanceConditionReady represents that a given instance condition is in
	// ready state
	InstanceConditionReady InstanceConditionType = "Ready"
	// InstanceConditionProvisionFailed represents that a given instance condition is in
	// failed state
	InstanceConditionProvisionFailed InstanceConditionType = "ProvisionFailed"
	// InstanceConditionDeprovisioning represents that a given instance condition is in
	// deprovisioning state
	InstanceConditionDeprovisioning InstanceConditionType = "Deprovisioning"
	// InstanceConditionDeprovisionFailed represents that a given instance condition is in
	// deprovision failed state
	InstanceConditionDeprovisionFailed InstanceConditionType = "DeprovisioningFailed"
)

// BindingList is a list of Bindings
type BindingList struct {
	metav1.TypeMeta
	metav1.ListMeta

	Items []Binding
}

// +genclient=true

// Binding represents a "used by" relationship between an application and an
// Instance.
type Binding struct {
	metav1.TypeMeta
	kapi.ObjectMeta

	Spec   BindingSpec
	Status BindingStatus
}

// BindingSpec represents a description of a Binding.
type BindingSpec struct {
	// InstanceRef is the reference to the Instance this binding is to.
	// Immutable.
	InstanceRef v1.LocalObjectReference

	// Parameters is a YAML representation of the properties to be
	// passed to the underlying broker.
	Parameters *runtime.RawExtension

	// Names of subordinate objects to create
	SecretName string

	// OSB-specific
	// OSBGUID is the identity of this object for use with the OSB API.
	// Immutable.
	OSBGUID string
}

// BindingStatus represents the current status of a Binding.
type BindingStatus struct {
	Conditions []BindingCondition
}

// BindingCondition represents an aspect of a Binding's status.
type BindingCondition struct {
	Type    BindingConditionType
	Status  ConditionStatus
	Reason  string
	Message string
}

// BindingConditionType represents a binding condition value
type BindingConditionType string

const (
	// BindingConditionReady represents a binding condition is in ready state
	BindingConditionReady BindingConditionType = "Ready"
	// BindingConditionFailed represents a binding condition is in failed state
	BindingConditionFailed BindingConditionType = "Failed"
	// BindingConditionUninjected represents a binding condition that the binding credentials have
	// been deleted. It is the first condition recorded when a binding is removed
	BindingConditionUninjected BindingConditionType = "Uninjected"
	// BindingConditionUnbound represents a binding condition that the service catalog has performed
	// the unbind operation on the backing CF broker. It is the second condition recorded when a
	// binding is removed
	BindingConditionUnbound BindingConditionType = "Unbound"
	// BindingConditionDeleted represents a binding condition that the service catalog has
	// intentionally deleted the binding. It is the third condition recorded when a binding is
	// removed
	BindingConditionDeleted BindingConditionType = "Deleted"
)
<commit_msg>Remove unused conditions from internal types.go (#535)<commit_after>/*
Copyright 2016 The Kubernetes Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package servicecatalog

import (
	kapi "k8s.io/kubernetes/pkg/api"
	"k8s.io/kubernetes/pkg/api/v1"
	metav1 "k8s.io/kubernetes/pkg/apis/meta/v1"
	"k8s.io/kubernetes/pkg/runtime"
)

// TODO: all metadata and parametersfields need to be refactored to real
// types; skipping for now to get very large generation PR in.

// +genclient=true
// +nonNamespaced=true

// Broker represents an entity that provides ServiceClasses for use in the
// service catalog.
type Broker struct {
	metav1.TypeMeta
	kapi.ObjectMeta

	Spec   BrokerSpec
	Status BrokerStatus
}

// BrokerList is a list of Brokers.
type BrokerList struct {
	metav1.TypeMeta
	metav1.ListMeta

	Items []Broker
}

// BrokerSpec represents a description of a Broker.
type BrokerSpec struct {
	// The URL to communicate with the Broker via..
	URL string

	// AuthSecret is a reference to a Secret containing auth information the
	// catalog should use to authenticate to this Broker.
	AuthSecret *v1.ObjectReference
}

// BrokerStatus represents the current status of a Broker.
type BrokerStatus struct {
	Conditions []BrokerCondition
}

// BrokerCondition represents an aspect of a Broker's status.
type BrokerCondition struct {
	Type    BrokerConditionType
	Status  ConditionStatus
	Reason  string
	Message string
}

// BrokerConditionType represents a broker condition value
type BrokerConditionType string

const (
	// BrokerConditionReady represents the fact that a given broker condition is in ready state
	BrokerConditionReady BrokerConditionType = "Ready"
)

// ConditionStatus represents a condition's status
type ConditionStatus string

// These are valid condition statuses. "ConditionTrue" means a resource is in
// the condition; "ConditionFalse" means a resource is not in the condition;
// "ConditionUnknown" means kubernetes can't decide if a resource is in the
// condition or not. In the future, we could add other intermediate
// conditions, e.g. ConditionDegraded.
const (
	// ConditionTrue represents the fact that a given condition is true
	ConditionTrue ConditionStatus = "True"
	// ConditionFalse represents the fact that a given condition is false
	ConditionFalse ConditionStatus = "False"
	// ConditionUnknown represents the fact that a given condition is unknown
	ConditionUnknown ConditionStatus = "Unknown"
)

// ServiceClassList is a list of ServiceClasses
type ServiceClassList struct {
	metav1.TypeMeta
	metav1.ListMeta

	Items []ServiceClass
}

// +genclient=true
// +nonNamespaced=true

// ServiceClass represents an offering in the service catalog.
type ServiceClass struct {
	metav1.TypeMeta
	kapi.ObjectMeta

	// BrokerName is the reference to the Broker that provides this service.
	// Immutable.
	BrokerName string

	Bindable      bool
	Plans         []ServicePlan
	PlanUpdatable bool // Do we support this?

	// OSB-specific
	// OSBGUID is the identity of this object for use with the OSB API.
	// Immutable.
	OSBGUID string

	// OSB-specific
	OSBTags                    []string
	OSBRequires                []string
	OSBMaxDBPerNode            *string
	OSBDashboardOAuth2ClientID *string
	OSBDashboardSecret         *string
	OSBDashboardRedirectURI    *string

	// Metadata fields
	Description         *string
	DisplayName         *string
	ImageURL            *string
	LongDescription     *string
	ProviderDisplayName *string
	DocumentationURL    *string
	SupportURL          *string
}

// ServicePlan represents a tier of a ServiceClass.
type ServicePlan struct {
	// CLI-friendly name of this plan
	Name string

	// OSB-specific
	// OSBGUID is the identity of this object for use with the OSB API.
	// Immutable.
	OSBGUID string

	// OSB-specific
	OSBFree     bool
	Description *string
	Bullets     []string
	DisplayName *string

	// TODO: add costs
}

// InstanceList is a list of instances.
type InstanceList struct {
	metav1.TypeMeta
	metav1.ListMeta

	Items []Instance
}

// +genclient=true

// Instance represents a provisioned instance of a ServiceClass.
type Instance struct {
	metav1.TypeMeta
	kapi.ObjectMeta

	Spec   InstanceSpec
	Status InstanceStatus
}

// InstanceSpec represents a description of an Instance.
type InstanceSpec struct {
	// ServiceClassName is the reference to the ServiceClass this is an
	// instance of.  Immutable.
	ServiceClassName string
	// ServicePlanName is the reference to the ServicePlan for this instance.
	PlanName string

	// Parameters is a YAML representation of the properties to be
	// passed to the underlying broker.
	Parameters *runtime.RawExtension

	// OSB-specific
	// OSBGUID is the identity of this object for use with the OSB API.
	// Immutable.
	OSBGUID string

	// OSB-specific
	OSBDashboardURL  *string
	OSBLastOperation *string
}

// InstanceStatus represents the current status of an Instance.
type InstanceStatus struct {
	Conditions []InstanceCondition
}

// InstanceCondition represents an aspect of an Instance's status.
type InstanceCondition struct {
	Type    InstanceConditionType
	Status  ConditionStatus
	Reason  string
	Message string
}

// InstanceConditionType represents a instance condition value
type InstanceConditionType string

const (
	// InstanceConditionReady represents that a given instance condition is in
	// ready state
	InstanceConditionReady InstanceConditionType = "Ready"
)

// BindingList is a list of Bindings
type BindingList struct {
	metav1.TypeMeta
	metav1.ListMeta

	Items []Binding
}

// +genclient=true

// Binding represents a "used by" relationship between an application and an
// Instance.
type Binding struct {
	metav1.TypeMeta
	kapi.ObjectMeta

	Spec   BindingSpec
	Status BindingStatus
}

// BindingSpec represents a description of a Binding.
type BindingSpec struct {
	// InstanceRef is the reference to the Instance this binding is to.
	// Immutable.
	InstanceRef v1.LocalObjectReference

	// Parameters is a YAML representation of the properties to be
	// passed to the underlying broker.
	Parameters *runtime.RawExtension

	// Names of subordinate objects to create
	SecretName string

	// OSB-specific
	// OSBGUID is the identity of this object for use with the OSB API.
	// Immutable.
	OSBGUID string
}

// BindingStatus represents the current status of a Binding.
type BindingStatus struct {
	Conditions []BindingCondition
}

// BindingCondition represents an aspect of a Binding's status.
type BindingCondition struct {
	Type    BindingConditionType
	Status  ConditionStatus
	Reason  string
	Message string
}

// BindingConditionType represents a binding condition value
type BindingConditionType string

const (
	// BindingConditionReady represents a binding condition is in ready state
	BindingConditionReady BindingConditionType = "Ready"
)
<|endoftext|>


<commit_before>package typewriter

import (
	"bytes"
	"fmt"
)

type Config struct {
	ShowLineNumbers          bool
	MarkFirstDifference      bool
	MarkFirstLineDifferences bool

	Padding   int
	Separator string
}

func maxInt(a, b int) int {
	if a > b {
		return a
	}
	return b
}

// Returns the length of the longest string.
func maxWidth(lines []string) int {
	max := 0
	for _, line := range lines {
		max = maxInt(len(line), max)
	}
	return max
}

func getOrEmpty(strings []string, index int) string {
	if index >= len(strings) {
		return ""
	}
	return strings[index]
}

func rightZero(s string, desiredLength int, padChar string) string {
	if len(s) > desiredLength {
		panic(fmt.Sprintf("Length of string (%d) is greater than desired length (%d)", len(s), desiredLength))
	}

	// TODO: Optimize
	padding := desiredLength - len(s)
	for i := 0; i < padding; i++ {
		s = s + padChar
	}

	return s
}

func Run(lines1, lines2 []string, config Config) string {
	var buf bytes.Buffer

	leftColumnWidth := maxWidth(lines1)

	padding := rightZero("", config.Padding, " ")

	for i := 0; i < maxInt(len(lines1), len(lines2)); i++ {
		s1 := getOrEmpty(lines1, i)
		s2 := getOrEmpty(lines2, i)

		s1 = rightZero(s1, leftColumnWidth, " ")

		buf.WriteString(s1 + padding + config.Separator + s2 + "\n")
	}

	return buf.String()
}
<commit_msg>Support marking the first difference found<commit_after>package typewriter

import (
	"bytes"
	"fmt"
)

const (
	colorOff     = "\033[0m"
	colorDefault = "\033[41m"
)

type Config struct {
	ShowLineNumbers bool

	// If true, marks the first spot where the two columns diverge.
	MarkFirstDifference bool

	// The escape sequence to use to mark a difference. If not specified
	// defaults to a red background.
	Marking string

	Padding   int
	Separator string
}

func maxInt(a, b int) int {
	if a > b {
		return a
	}
	return b
}

func minInt(a, b int) int {
	if a < b {
		return a
	}
	return b
}

// Returns the length of the longest string.
func maxWidth(lines []string) int {
	max := 0
	for _, line := range lines {
		max = maxInt(len(line), max)
	}
	return max
}

func getOrEmpty(strings []string, index int) string {
	if index >= len(strings) {
		return ""
	}
	return strings[index]
}

func rightZero(s string, desiredLength int, padChar string) string {
	if len(s) > desiredLength {
		panic(fmt.Sprintf("Length of string (%d) is greater than desired length (%d)", len(s), desiredLength))
	}

	// TODO: Optimize
	padding := desiredLength - len(s)
	for i := 0; i < padding; i++ {
		s = s + padChar
	}

	return s
}

func findDifference(s1, s2 string) (index int, found bool) {
	minLen := minInt(len(s1), len(s2))
	for i := 0; i < minLen; i++ {
		c1 := s1[i]
		c2 := s2[i]

		if c1 != c2 {
			return i, true
		}
	}

	if len(s1) > len(s2) {
		return len(s2), true
	} else if len(s2) > len(s1) {
		return len(s1), true
	}

	return -1, false
}

func Run(lines1, lines2 []string, config Config) string {
	var buf bytes.Buffer

	leftColumnWidth := maxWidth(lines1)

	padding := rightZero("", config.Padding, " ")

	if config.Marking == "" {
		config.Marking = colorDefault
	}

	differenceFound := false
	for i := 0; i < maxInt(len(lines1), len(lines2)); i++ {
		s1 := getOrEmpty(lines1, i)
		s2 := getOrEmpty(lines2, i)

		extraWidth := 0
		if config.MarkFirstDifference && !differenceFound {
			diffIndex, found := findDifference(s1, s2)
			if found {
				differenceFound = true
				s1 = s1[:diffIndex] + config.Marking + s1[diffIndex:] + colorOff
				s2 = s2[:diffIndex] + config.Marking + s2[diffIndex:] + colorOff
				extraWidth = len(config.Marking) + len(colorOff)
			}
		}

		s1 = rightZero(s1, leftColumnWidth+extraWidth, " ")

		buf.WriteString(s1 + padding + config.Separator + s2 + "\n")
	}

	return buf.String()
}
<|endoftext|>


<commit_before>package conveyor

import (
	"fmt"
	"log"
	"os"
	"strings"
	"time"

	"code.google.com/p/go-uuid/uuid"

	"github.com/fsouza/go-dockerclient"
	"github.com/google/go-github/github"
	"github.com/remind101/pkg/reporter"

	"golang.org/x/net/context"
)

const (
	// Context is used for the commit status context.
	Context = "container/docker"

	// DefaultBuilderImage is the docker image used to build docker images.
	DefaultBuilderImage = "remind101/conveyor-builder"

	// DefaultDataVolume is the default name of a container serving as a
	// data volume for ssh keys and docker credentials. In general, you
	// shouldn't need to change this.
	DefaultDataVolume = "data"
)

type BuildOptions struct {
	// Repository is the repo to build.
	Repository string
	// Sha is the git commit to build.
	Sha string
	// Branch is the name of the branch that this build relates to.
	Branch string
	// Set to true to disable the layer cache. The zero value is to enable
	// caching.
	NoCache bool
}

// Builder represents something that can build a Docker image.
type Builder interface {
	// Build should build the docker image, tag it and push it to the docker
	// registry. This should return the sha256 digest of the image.
	Build(context.Context, Logger, BuildOptions) (string, error)
}

// BuilderFunc is a function that implements the Builder interface.
type BuilderFunc func(context.Context, Logger, BuildOptions) (string, error)

func (fn BuilderFunc) Build(ctx context.Context, w Logger, opts BuildOptions) (string, error) {
	return fn(ctx, w, opts)
}

// Conveyor serves as a builder.
type Conveyor struct {
	Builder

	// A Reporter to use to report errors.
	Reporter reporter.Reporter
}

// New returns a new Conveyor instance.
func New(b Builder) *Conveyor {
	return &Conveyor{
		Builder: b,
	}
}

func (c *Conveyor) Build(ctx context.Context, w Logger, opts BuildOptions) (id string, err error) {
	// Embed the reporter in the context.Context.
	ctx = reporter.WithReporter(ctx, c.reporter())
	reporter.AddContext(ctx, "options", opts)
	defer reporter.Monitor(ctx)

	defer func() {
		if err != nil {
			reporter.Report(ctx, err)
		}
	}()

	id, err = c.build(ctx, w, opts)
	return
}

// Build performs the build and ensures that the output stream is closed.
func (c *Conveyor) build(ctx context.Context, w Logger, opts BuildOptions) (id string, err error) {
	defer func() {
		var closeErr error
		if w != nil {
			closeErr = w.Close()
		}
		if err == nil {
			// If there was no error from the builder, let the
			// downstream know that there was an error closing the
			// output stream.
			err = closeErr
		}
	}()

	id, err = c.Builder.Build(ctx, w, opts)
	return
}

func (c *Conveyor) reporter() reporter.Reporter {
	if c.Reporter == nil {
		return reporter.ReporterFunc(func(ctx context.Context, err error) error {
			fmt.Fprintf(os.Stderr, "reporting err: %v", err)
			return nil
		})
	}

	return c.Reporter
}

// DockerBuilder is a Builder implementation that runs the build in a docker
// container.
type DockerBuilder struct {
	// dataVolume is the name of the volume that contains ssh keys and
	// configuration data.
	DataVolume string
	// Name of the image to use to build the docker image. Defaults to
	// DefaultBuilderImage.
	Image string
	// Set to true to enable dry runs. This sets the `DRY` environment
	// variable within the builder container to `true`. The behavior of this
	// flag depends on how the builder image handles the `DRY` environment
	// variable.
	DryRun bool

	client *docker.Client
}

// NewDockerBuilder returns a new DockerBuilder backed by the docker client.
func NewDockerBuilder(c *docker.Client) *DockerBuilder {
	return &DockerBuilder{client: c}
}

// NewDockerBuilderFromEnv returns a new DockerBuilder with a docker client
// configured from the standard Docker environment variables.
func NewDockerBuilderFromEnv() (*DockerBuilder, error) {
	c, err := docker.NewClientFromEnv()
	if err != nil {
		return nil, err
	}

	return NewDockerBuilder(c), nil
}

// Build executes the docker image.
func (b *DockerBuilder) Build(ctx context.Context, w Logger, opts BuildOptions) (string, error) {
	env := []string{
		fmt.Sprintf("REPOSITORY=%s", opts.Repository),
		fmt.Sprintf("BRANCH=%s", opts.Branch),
		fmt.Sprintf("SHA=%s", opts.Sha),
		fmt.Sprintf("DRY=%s", b.dryRun()),
		fmt.Sprintf("CACHE=%s", b.cache(opts)),
	}

	name := strings.Join([]string{
		strings.Replace(opts.Repository, "/", "-", -1),
		opts.Branch,
		opts.Sha,
		uuid.New(),
	}, "-")

	c, err := b.client.CreateContainer(docker.CreateContainerOptions{
		Name: name,
		Config: &docker.Config{
			Tty:          true,
			AttachStdout: true,
			AttachStderr: true,
			OpenStdin:    true,
			Image:        b.image(),
			Hostname:     hostname,
			Env:          env,
		},
	})
	if err != nil {
		return "", fmt.Errorf("create container: %v", err)
	}

	reporter.AddContext(ctx, "container_id", c.ID)

	if err := b.client.StartContainer(c.ID, &docker.HostConfig{
		Privileged:  true,
		VolumesFrom: []string{b.dataVolume()},
	}); err != nil {
		return "", fmt.Errorf("start container: %v", err)
	}

	if err := b.client.AttachToContainer(docker.AttachToContainerOptions{
		Container:    c.ID,
		OutputStream: w,
		ErrorStream:  w,
		Logs:         true,
		Stream:       true,
		Stdout:       true,
		Stderr:       true,
		RawTerminal:  true,
	}); err != nil {
		return "", fmt.Errorf("attach: %v", err)
	}

	exit, err := b.client.WaitContainer(c.ID)
	if err != nil {
		return "", fmt.Errorf("wait container: %v", err)
	}

	// A non-zero exit status means the build failed.
	if exit != 0 {
		return "", fmt.Errorf("container returned a non-zero exit code: %d", exit)
	}

	// TODO: Return sha256
	return "", nil
}

func (b *DockerBuilder) dryRun() string {
	if b.DryRun {
		return "true"
	}
	return ""
}

func (b *DockerBuilder) image() string {
	if b.Image == "" {
		return DefaultBuilderImage
	}
	return b.Image
}

func (b *DockerBuilder) dataVolume() string {
	if b.DataVolume == "" {
		return DefaultDataVolume
	}
	return b.DataVolume
}

func (b *DockerBuilder) cache(opts BuildOptions) string {
	if opts.NoCache {
		return "off"
	}

	return "on"
}

// statusUpdaterBuilder is a Builder implementation that updates the commit
// status in github.
type statusUpdaterBuilder struct {
	Builder
	github GitHubClient
	since  func(time.Time) time.Duration
}

// UpdateGitHubCommitStatus wraps b to update the GitHub commit status when a
// build starts, and stops.
func UpdateGitHubCommitStatus(b Builder, g GitHubClient) *statusUpdaterBuilder {
	return &statusUpdaterBuilder{
		Builder: b,
		github:  g,
		since:   time.Since,
	}
}

func (b *statusUpdaterBuilder) Build(ctx context.Context, w Logger, opts BuildOptions) (id string, err error) {
	t := time.Now()

	defer func() {
		duration := b.since(t)
		description := fmt.Sprintf("Image built in %v.", duration)
		status := "success"
		if err != nil {
			status = "failure"
			description = err.Error()
		}
		b.updateStatus(w, opts, status, description)
	}()

	if err = b.updateStatus(w, opts, "pending", "Image building."); err != nil {
		err = fmt.Errorf("status: %v", err)
		return
	}

	id, err = b.Builder.Build(ctx, w, opts)
	return
}

// updateStatus updates the given commit with a new status.
func (b *statusUpdaterBuilder) updateStatus(w Logger, opts BuildOptions, status string, description string) error {
	context := Context
	parts := strings.SplitN(opts.Repository, "/", 2)

	var desc *string
	if description != "" {
		desc = &description
	}
	var url *string
	if status == "success" || status == "failure" || status == "error" {
		url = github.String(w.URL())
	}

	_, _, err := b.github.CreateStatus(parts[0], parts[1], opts.Sha, &github.RepoStatus{
		State:       &status,
		Context:     &context,
		Description: desc,
		TargetURL:   url,
	})
	return err
}

// BuildAsync wraps a Builder to run the build in a goroutine.
func BuildAsync(b Builder) Builder {
	build := func(ctx context.Context, w Logger, opts BuildOptions) {
		if _, err := b.Build(ctx, w, opts); err != nil {
			log.Printf("build err: %v", err)
		}
	}

	return BuilderFunc(func(ctx context.Context, w Logger, opts BuildOptions) (string, error) {
		go build(ctx, w, opts)
		return "", nil
	})
}

var hostname string

func init() {
	hostname, _ = os.Hostname()
}
<commit_msg>Revert "Don't remove container so we can inspect it later."<commit_after>package conveyor

import (
	"fmt"
	"log"
	"os"
	"strings"
	"time"

	"code.google.com/p/go-uuid/uuid"

	"github.com/fsouza/go-dockerclient"
	"github.com/google/go-github/github"
	"github.com/remind101/pkg/reporter"

	"golang.org/x/net/context"
)

const (
	// Context is used for the commit status context.
	Context = "container/docker"

	// DefaultBuilderImage is the docker image used to build docker images.
	DefaultBuilderImage = "remind101/conveyor-builder"

	// DefaultDataVolume is the default name of a container serving as a
	// data volume for ssh keys and docker credentials. In general, you
	// shouldn't need to change this.
	DefaultDataVolume = "data"
)

type BuildOptions struct {
	// Repository is the repo to build.
	Repository string
	// Sha is the git commit to build.
	Sha string
	// Branch is the name of the branch that this build relates to.
	Branch string
	// Set to true to disable the layer cache. The zero value is to enable
	// caching.
	NoCache bool
}

// Builder represents something that can build a Docker image.
type Builder interface {
	// Build should build the docker image, tag it and push it to the docker
	// registry. This should return the sha256 digest of the image.
	Build(context.Context, Logger, BuildOptions) (string, error)
}

// BuilderFunc is a function that implements the Builder interface.
type BuilderFunc func(context.Context, Logger, BuildOptions) (string, error)

func (fn BuilderFunc) Build(ctx context.Context, w Logger, opts BuildOptions) (string, error) {
	return fn(ctx, w, opts)
}

// Conveyor serves as a builder.
type Conveyor struct {
	Builder

	// A Reporter to use to report errors.
	Reporter reporter.Reporter
}

// New returns a new Conveyor instance.
func New(b Builder) *Conveyor {
	return &Conveyor{
		Builder: b,
	}
}

func (c *Conveyor) Build(ctx context.Context, w Logger, opts BuildOptions) (id string, err error) {
	// Embed the reporter in the context.Context.
	ctx = reporter.WithReporter(ctx, c.reporter())
	reporter.AddContext(ctx, "options", opts)
	defer reporter.Monitor(ctx)

	defer func() {
		if err != nil {
			reporter.Report(ctx, err)
		}
	}()

	id, err = c.build(ctx, w, opts)
	return
}

// Build performs the build and ensures that the output stream is closed.
func (c *Conveyor) build(ctx context.Context, w Logger, opts BuildOptions) (id string, err error) {
	defer func() {
		var closeErr error
		if w != nil {
			closeErr = w.Close()
		}
		if err == nil {
			// If there was no error from the builder, let the
			// downstream know that there was an error closing the
			// output stream.
			err = closeErr
		}
	}()

	id, err = c.Builder.Build(ctx, w, opts)
	return
}

func (c *Conveyor) reporter() reporter.Reporter {
	if c.Reporter == nil {
		return reporter.ReporterFunc(func(ctx context.Context, err error) error {
			fmt.Fprintf(os.Stderr, "reporting err: %v", err)
			return nil
		})
	}

	return c.Reporter
}

// DockerBuilder is a Builder implementation that runs the build in a docker
// container.
type DockerBuilder struct {
	// dataVolume is the name of the volume that contains ssh keys and
	// configuration data.
	DataVolume string
	// Name of the image to use to build the docker image. Defaults to
	// DefaultBuilderImage.
	Image string
	// Set to true to enable dry runs. This sets the `DRY` environment
	// variable within the builder container to `true`. The behavior of this
	// flag depends on how the builder image handles the `DRY` environment
	// variable.
	DryRun bool

	client *docker.Client
}

// NewDockerBuilder returns a new DockerBuilder backed by the docker client.
func NewDockerBuilder(c *docker.Client) *DockerBuilder {
	return &DockerBuilder{client: c}
}

// NewDockerBuilderFromEnv returns a new DockerBuilder with a docker client
// configured from the standard Docker environment variables.
func NewDockerBuilderFromEnv() (*DockerBuilder, error) {
	c, err := docker.NewClientFromEnv()
	if err != nil {
		return nil, err
	}

	return NewDockerBuilder(c), nil
}

// Build executes the docker image.
func (b *DockerBuilder) Build(ctx context.Context, w Logger, opts BuildOptions) (string, error) {
	env := []string{
		fmt.Sprintf("REPOSITORY=%s", opts.Repository),
		fmt.Sprintf("BRANCH=%s", opts.Branch),
		fmt.Sprintf("SHA=%s", opts.Sha),
		fmt.Sprintf("DRY=%s", b.dryRun()),
		fmt.Sprintf("CACHE=%s", b.cache(opts)),
	}

	name := strings.Join([]string{
		strings.Replace(opts.Repository, "/", "-", -1),
		opts.Branch,
		opts.Sha,
		uuid.New(),
	}, "-")

	c, err := b.client.CreateContainer(docker.CreateContainerOptions{
		Name: name,
		Config: &docker.Config{
			Tty:          true,
			AttachStdout: true,
			AttachStderr: true,
			OpenStdin:    true,
			Image:        b.image(),
			Hostname:     hostname,
			Env:          env,
		},
	})
	if err != nil {
		return "", fmt.Errorf("create container: %v", err)
	}
	defer b.client.RemoveContainer(docker.RemoveContainerOptions{
		ID:            c.ID,
		RemoveVolumes: true,
		Force:         true,
	})

	reporter.AddContext(ctx, "container_id", c.ID)

	if err := b.client.StartContainer(c.ID, &docker.HostConfig{
		Privileged:  true,
		VolumesFrom: []string{b.dataVolume()},
	}); err != nil {
		return "", fmt.Errorf("start container: %v", err)
	}

	if err := b.client.AttachToContainer(docker.AttachToContainerOptions{
		Container:    c.ID,
		OutputStream: w,
		ErrorStream:  w,
		Logs:         true,
		Stream:       true,
		Stdout:       true,
		Stderr:       true,
		RawTerminal:  true,
	}); err != nil {
		return "", fmt.Errorf("attach: %v", err)
	}

	exit, err := b.client.WaitContainer(c.ID)
	if err != nil {
		return "", fmt.Errorf("wait container: %v", err)
	}

	// A non-zero exit status means the build failed.
	if exit != 0 {
		return "", fmt.Errorf("container returned a non-zero exit code: %d", exit)
	}

	// TODO: Return sha256
	return "", nil
}

func (b *DockerBuilder) dryRun() string {
	if b.DryRun {
		return "true"
	}
	return ""
}

func (b *DockerBuilder) image() string {
	if b.Image == "" {
		return DefaultBuilderImage
	}
	return b.Image
}

func (b *DockerBuilder) dataVolume() string {
	if b.DataVolume == "" {
		return DefaultDataVolume
	}
	return b.DataVolume
}

func (b *DockerBuilder) cache(opts BuildOptions) string {
	if opts.NoCache {
		return "off"
	}

	return "on"
}

// statusUpdaterBuilder is a Builder implementation that updates the commit
// status in github.
type statusUpdaterBuilder struct {
	Builder
	github GitHubClient
	since  func(time.Time) time.Duration
}

// UpdateGitHubCommitStatus wraps b to update the GitHub commit status when a
// build starts, and stops.
func UpdateGitHubCommitStatus(b Builder, g GitHubClient) *statusUpdaterBuilder {
	return &statusUpdaterBuilder{
		Builder: b,
		github:  g,
		since:   time.Since,
	}
}

func (b *statusUpdaterBuilder) Build(ctx context.Context, w Logger, opts BuildOptions) (id string, err error) {
	t := time.Now()

	defer func() {
		duration := b.since(t)
		description := fmt.Sprintf("Image built in %v.", duration)
		status := "success"
		if err != nil {
			status = "failure"
			description = err.Error()
		}
		b.updateStatus(w, opts, status, description)
	}()

	if err = b.updateStatus(w, opts, "pending", "Image building."); err != nil {
		err = fmt.Errorf("status: %v", err)
		return
	}

	id, err = b.Builder.Build(ctx, w, opts)
	return
}

// updateStatus updates the given commit with a new status.
func (b *statusUpdaterBuilder) updateStatus(w Logger, opts BuildOptions, status string, description string) error {
	context := Context
	parts := strings.SplitN(opts.Repository, "/", 2)

	var desc *string
	if description != "" {
		desc = &description
	}
	var url *string
	if status == "success" || status == "failure" || status == "error" {
		url = github.String(w.URL())
	}

	_, _, err := b.github.CreateStatus(parts[0], parts[1], opts.Sha, &github.RepoStatus{
		State:       &status,
		Context:     &context,
		Description: desc,
		TargetURL:   url,
	})
	return err
}

// BuildAsync wraps a Builder to run the build in a goroutine.
func BuildAsync(b Builder) Builder {
	build := func(ctx context.Context, w Logger, opts BuildOptions) {
		if _, err := b.Build(ctx, w, opts); err != nil {
			log.Printf("build err: %v", err)
		}
	}

	return BuilderFunc(func(ctx context.Context, w Logger, opts BuildOptions) (string, error) {
		go build(ctx, w, opts)
		return "", nil
	})
}

var hostname string

func init() {
	hostname, _ = os.Hostname()
}
<|endoftext|>


<commit_before>package bongo

import (
	"fmt"
	"github.com/koding/logging"

	"github.com/jinzhu/gorm"
)

type EventBus interface {
	Connect() error
	Close() error
	Publish(messageType string, data []byte) error
}

var B *Bongo

type Bongo struct {
	Broker EventBus
	DB     *gorm.DB
	log    logging.Logger
}

func New(b EventBus, db *gorm.DB, l logging.Logger) *Bongo {
	return &Bongo{
		Broker: b,
		DB:     db,
		log:    l,
	}
}

func (b *Bongo) Connect() error {
	if err := b.Broker.Connect(); err != nil {
		return err
	}
	B = b

	b.log.Info("Bongo connected %t", true)
	// todo add gorm Connect()
	return nil
}

func (b *Bongo) Close() error {

	if err := b.Broker.Close(); err != nil {
		return err
	}
	b.log.Info("Bongo dis-connected %t", true)

	// todo add gorm Close()
	return nil
}
<commit_msg>bongo : remove fmt<commit_after>package bongo

import (
	"github.com/koding/logging"

	"github.com/jinzhu/gorm"
)

type EventBus interface {
	Connect() error
	Close() error
	Publish(messageType string, data []byte) error
}

var B *Bongo

type Bongo struct {
	Broker EventBus
	DB     *gorm.DB
	log    logging.Logger
}

func New(b EventBus, db *gorm.DB, l logging.Logger) *Bongo {
	return &Bongo{
		Broker: b,
		DB:     db,
		log:    l,
	}
}

func (b *Bongo) Connect() error {
	if err := b.Broker.Connect(); err != nil {
		return err
	}
	B = b

	b.log.Info("Bongo connected %t", true)
	// todo add gorm Connect()
	return nil
}

func (b *Bongo) Close() error {
	if err := b.Broker.Close(); err != nil {
		return err
	}
	b.log.Info("Bongo dis-connected %t", true)

	// todo add gorm Close()
	return nil
}
<|endoftext|>


<commit_before>package util

import (
	log "github.com/cihub/seelog"
	"pilosa/config"

	"github.com/cactus/go-statsd-client/statsd"
)

type args struct {
	stat  string
	delta int64
	rate  float32
}

var (
	timer chan args
	count chan string
	end   chan bool
)

func init() {
	timer = make(chan args, 32768)
	count = make(chan string, 32768)
	end = make(chan bool)
	stat_config := config.GetStringDefault("statsd_server", "127.0.0.1:8125")
	log.Warn("New Stats", stat_config)
	stats, _ := statsd.New(stat_config, "")
	go func() {
		for {
			select {
			case ci := <-timer:
				stats.Gauge(ci.stat, ci.delta, ci.rate)
				stats.Timing(ci.stat, ci.delta, ci.rate)
			case stat := <-count:
				stats.Inc(stat, 1, 1.0)
			case <-end:
				log.Warn("DONE Stats")
				return

			}
		}
	}()
}

func SendTimer(stat string, delta int64) {
	pstat := "pilosa." + stat
	milli := delta / time.Millisecond
	timer <- args{pstat, milli, 1.0}
}
func SendInc(stat string) {
	pstat := "pilosa." + stat
	count <- pstat
}

func ShutdownStats() {
	log.Warn("Shutdown Stats")
	end <- true
}
<commit_msg>convert to timing stat<commit_after>package util

import (
	log "github.com/cihub/seelog"
	"pilosa/config"
	"time"

	"github.com/cactus/go-statsd-client/statsd"
)

type args struct {
	stat  string
	delta int64
	rate  float32
}

var (
	timer chan args
	count chan string
	end   chan bool
)

func init() {
	timer = make(chan args, 32768)
	count = make(chan string, 32768)
	end = make(chan bool)
	stat_config := config.GetStringDefault("statsd_server", "127.0.0.1:8125")
	log.Warn("New Stats", stat_config)
	stats, _ := statsd.New(stat_config, "")
	go func() {
		for {
			select {
			case ci := <-timer:
				stats.Gauge(ci.stat, ci.delta, ci.rate)
				stats.Timing(ci.stat, ci.delta, ci.rate)
			case stat := <-count:
				stats.Inc(stat, 1, 1.0)
			case <-end:
				log.Warn("DONE Stats")
				return

			}
		}
	}()
}

func SendTimer(stat string, delta int64) {
	pstat := "pilosa." + stat
	milli := time.Duration(delta) / time.Millisecond
	timer <- args{pstat, int64(milli), 1.0}
}
func SendInc(stat string) {
	pstat := "pilosa." + stat
	count <- pstat
}

func ShutdownStats() {
	log.Warn("Shutdown Stats")
	end <- true
}
<|endoftext|>