<commit_before>package pool

import (
	"log"
	"net/url"
	"sync"
	"time"
)

var timeout = time.Duration(5) * time.Second

// Pool - pool of goroutines
type Pool struct {
	m              sync.RWMutex
	timerIsRunning bool
	numWorkers     int
	freeWorkers    int
	inputJobs      int
	quitTimeout    time.Duration
	workChan       chan *Task
	inputChan      chan *Task
	ResultChan     chan Task
	quitChan       chan bool
	endTaskChan    chan bool
	queue          taskList
	timer          *time.Timer
}

// New - create new pool
func New(numWorkers int) *Pool {
	p := new(Pool)
	p.numWorkers = numWorkers
	p.freeWorkers = numWorkers
	p.inputJobs = 0
	p.workChan = make(chan *Task, numWorkers+1)
	p.inputChan = make(chan *Task)
	p.ResultChan = make(chan Task)
	p.endTaskChan = make(chan bool, numWorkers+1)
	p.quitChan = make(chan bool)
	for i := 0; i < numWorkers; i++ {
		go p.worker(i)
	}
	go p.run()
	return p
}

// Add - add new task to pool
func (p *Pool) Add(hostname string, proxy *url.URL) {
	t := new(Task)
	t.Hostname = hostname
	t.Proxy = proxy
	p.inputJobs++
	t.ID = p.inputJobs
	log.Println("try to pushtask", t.Hostname)
	p.inputChan <- t
	log.Println("sucess pushtask", t.Hostname)
}

func (p *Pool) run() {
runLoop:
	for {
		select {
		case task := <-p.inputChan:
			log.Println("try to queue.put", task.Hostname)
			_ = p.queue.put(task)
			log.Println("end pushtask, poptask", task.Hostname)
			p.popTask()
			log.Println("end poptask")
		case <-p.endTaskChan:
			p.popTask()
		case <-p.quitChan:
			close(p.ResultChan)
			close(p.workChan)
			break runLoop
		}
	}
}

// SetHTTPTimeout - set http client timeout in second
func (p *Pool) SetHTTPTimeout(t int) {
	timeout = time.Duration(t) * time.Second
}

// SetTaskTimeout - set task timeout in second before send quit signal
func (p *Pool) SetTaskTimeout(t int) {
	p.quitTimeout = time.Duration(t) * time.Second
	p.timer = time.NewTimer(p.quitTimeout)
	p.timerIsRunning = true
	go func() {
		<-p.timer.C
		p.quitChan <- true
		log.Println("End with timeout")
	}()
}

// Quit - send quit signal to pool
func (p *Pool) Quit() {
	p.quitChan <- true
}
<commit_msg>debug<commit_after>package pool

import (
	"log"
	"net/url"
	"sync"
	"time"
)

var timeout = time.Duration(5) * time.Second

// Pool - pool of goroutines
type Pool struct {
	m              sync.RWMutex
	timerIsRunning bool
	numWorkers     int
	freeWorkers    int
	inputJobs      int
	quitTimeout    time.Duration
	workChan       chan *Task
	inputChan      chan *Task
	ResultChan     chan Task
	quitChan       chan bool
	endTaskChan    chan bool
	queue          taskList
	timer          *time.Timer
}

// New - create new pool
func New(numWorkers int) *Pool {
	p := new(Pool)
	p.numWorkers = numWorkers
	p.freeWorkers = numWorkers
	p.inputJobs = 0
	p.workChan = make(chan *Task, numWorkers+1)
	p.inputChan = make(chan *Task)
	p.ResultChan = make(chan Task)
	p.endTaskChan = make(chan bool, numWorkers+1)
	p.quitChan = make(chan bool)
	for i := 0; i < numWorkers; i++ {
		go p.worker(i)
	}
	go p.run()
	return p
}

// Add - add new task to pool
func (p *Pool) Add(hostname string, proxy *url.URL) {
	t := new(Task)
	t.Hostname = hostname
	t.Proxy = proxy
	p.inputJobs++
	t.ID = p.inputJobs
	log.Println("try to pushtask", t.ID)
	p.inputChan <- t
	log.Println("sucess pushtask", t.ID)
}

func (p *Pool) run() {
runLoop:
	for {
		select {
		case task := <-p.inputChan:
			log.Println("try to queue.put", task.ID)
			_ = p.queue.put(task)
			log.Println("end queue.put, poptask", task.ID)
			p.popTask()
			log.Println("end poptask")
		case <-p.endTaskChan:
			p.popTask()
		case <-p.quitChan:
			close(p.ResultChan)
			close(p.workChan)
			break runLoop
		}
	}
}

// SetHTTPTimeout - set http client timeout in second
func (p *Pool) SetHTTPTimeout(t int) {
	timeout = time.Duration(t) * time.Second
}

// SetTaskTimeout - set task timeout in second before send quit signal
func (p *Pool) SetTaskTimeout(t int) {
	p.quitTimeout = time.Duration(t) * time.Second
	p.timer = time.NewTimer(p.quitTimeout)
	p.timerIsRunning = true
	go func() {
		<-p.timer.C
		p.quitChan <- true
		log.Println("End with timeout")
	}()
}

// Quit - send quit signal to pool
func (p *Pool) Quit() {
	p.quitChan <- true
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"log"
	"strings"
)

type proc struct {
	Pid    int
	Login  []string
	Shell  bool
	Logger *log.Logger

	buf       bytes.Buffer
	lastStdin []byte
}

func (p *proc) LoginData(data []byte) {
	p.Login = append(p.Login, string(data))
}

func (p *proc) Stdin(data []byte) {
	if len(data) == 1 {
		b := data[0]
		if b != '\r' && b != '\n' {
			p.lastStdin = append(p.lastStdin, b)
		}
	}
}

func (p *proc) Stdout(data []byte) {
	if len(p.lastStdin) >= 3 {
		p.buf.Write(p.lastStdin)
		p.lastStdin = nil
	} else {
		max := 0
		// could be improved (sequential scan?)
		// but does its job fairly well as is
		for i, v := range p.lastStdin {
			if bytes.Contains(data, []byte{v}) {
				max = i + 1
			} else {
				break
			}
		}
		p.lastStdin = p.lastStdin[max:]
	}
	p.buf.Write(data)
	if bytes.Contains(p.buf.Bytes(), []byte("\r\n")) {
		split := bytes.Split(p.buf.Bytes(), []byte("\r\n"))
		for _, v := range split[:len(split)-1] {
			p.logline(v)
		}
		p.buf.Reset()
		p.buf.Write(split[len(split)-1])
	}
}

func (p *proc) Flush() {
	line := p.buf.Bytes()
	if len(line) > 0 {
		p.logline(p.buf.Bytes())
	}
}

func (p *proc) Exit() {
	p.Flush()
	p.Logger.Printf("[%d] <logout>", p.Pid)
}

func (p *proc) LogLogin(login []string, success bool) {
	if success {
		p.Logger.Printf("[%d] <login as: %s>", p.Pid, strings.Join(login, ", "))
	} else {
		p.Logger.Printf("[%d] <login attempt: %s>", p.Pid, strings.Join(login, ", "))
	}
}

func (p *proc) logline(line []byte) {
	p.Logger.Printf("[%d] %#v", p.Pid, string(line))
}
<commit_msg>fix detecting pasted passwords<commit_after>package main

import (
	"bytes"
	"log"
	"strings"
)

type proc struct {
	Pid    int
	Login  []string
	Shell  bool
	Logger *log.Logger

	buf       bytes.Buffer
	lastStdin []byte
}

func (p *proc) LoginData(data []byte) {
	p.Login = append(p.Login, string(data))
}

func (p *proc) Stdin(data []byte) {
	for _, b := range data {
		if b != '\r' && b != '\n' {
			p.lastStdin = append(p.lastStdin, b)
		}
	}
}

func (p *proc) Stdout(data []byte) {
	if len(p.lastStdin) >= 3 {
		p.buf.Write(p.lastStdin)
		p.lastStdin = nil
	} else {
		max := 0
		// could be improved (sequential scan?)
		// but does its job fairly well as is
		for i, v := range p.lastStdin {
			if bytes.Contains(data, []byte{v}) {
				max = i + 1
			} else {
				break
			}
		}
		p.lastStdin = p.lastStdin[max:]
	}
	p.buf.Write(data)
	if bytes.Contains(p.buf.Bytes(), []byte("\r\n")) {
		split := bytes.Split(p.buf.Bytes(), []byte("\r\n"))
		for _, v := range split[:len(split)-1] {
			p.logline(v)
		}
		p.buf.Reset()
		p.buf.Write(split[len(split)-1])
	}
}

func (p *proc) Flush() {
	line := p.buf.Bytes()
	if len(line) > 0 {
		p.logline(p.buf.Bytes())
	}
}

func (p *proc) Exit() {
	p.Flush()
	p.Logger.Printf("[%d] <logout>", p.Pid)
}

func (p *proc) LogLogin(login []string, success bool) {
	if success {
		p.Logger.Printf("[%d] <login as: %s>", p.Pid, strings.Join(login, ", "))
	} else {
		p.Logger.Printf("[%d] <login attempt: %s>", p.Pid, strings.Join(login, ", "))
	}
}

func (p *proc) logline(line []byte) {
	p.Logger.Printf("[%d] %#v", p.Pid, string(line))
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"encoding/json"
	"flag"
	"fmt"
	"github.com/pkg/errors"
	"log"
	"math/rand"
	"net"
	"os"
	"strings"
	"time"
)

const road_width = 40
const road_lenght = 20
const car_width = 14
const car_lenght = 7
const result_width = 76
const max_players_in_top = 10

type Config struct {
	Log                 *log.Logger
	AcidPath, ScorePath string
}

type Point struct {
	X, Y int
}

type Player struct {
	Name  string
	Score int64
}

type GameData struct {
	Roads      [][]byte
	Car, Clear []byte
	Top        []Player
}

type RoundData struct {
	player                                   Player
	CarPosition, bombPosition, bonusPosition Point
	BombFactor, BonusFactor, Speed           int
	GameOver                                 []byte
}

func generateRoad(reverse bool) []byte {
	road := make([]byte, road_width*road_lenght)
	midline := reverse
	for row := 0; row < road_lenght; row++ {
		for column := 0; column < road_width; column++ {
			var symbol byte
			if column == 0 || column == road_width-2 {
				symbol = byte('|')
			} else if column == road_width-1 {
				symbol = byte('\n')
			} else if column == road_width/2-1 {
				if midline {
					symbol = byte('|')
				} else {
					symbol = byte(' ')
				}
				midline = !midline
			} else {
				symbol = byte(' ')
			}
			road[row*road_width+column] = symbol
		}

	}
	return road
}

func getAcid(conf *Config, fileName string) ([]byte, error) {
	fileStat, err := os.Stat(conf.AcidPath + "/" + fileName)
	if err != nil {
		conf.Log.Printf("Acid %s does not exist: %v\n", fileName, err)
		return []byte{}, err
	}

	acid := make([]byte, fileStat.Size())
	f, err := os.OpenFile(conf.AcidPath+"/"+fileName, os.O_RDONLY, os.ModePerm)
	if err != nil {
		conf.Log.Printf("Error while opening %s: %v\n", fileName, err)
		os.Exit(1)
	}
	defer f.Close()

	f.Read(acid)

	return acid, nil
}

func updatePosition(conn net.Conn, position *Point) {
	for {
		direction := make([]byte, 1)

		_, err := conn.Read(direction)
		if err != nil {
			return
		}

		switch direction[0] {
		case 68:
			// Left
			position.X--
		case 67:
			// Right
			position.X++
		case 65:
			// Up
			position.Y--
		case 66:
			// Down
			position.Y++
		}
	}
}

func updateScore(roundData *RoundData) {
	for {
		roundData.player.Score++
		time.Sleep(time.Duration(roundData.Speed) * time.Millisecond)
	}

}

func readName(conf *Config, conn net.Conn) (string, error) {
	conn.Write([]byte("Enter your name:"))
	io := bufio.NewReader(conn)
	name, err := io.ReadString('\n')
	if err != nil {
		conf.Log.Println("Error while name reading", err)
		return "", err
	}
	if name == "" {
		conf.Log.Println("Empty name")
		return "", errors.New("Empty name")
	}
	if len(name) > result_width/2 {
		conf.Log.Println("Too long name")
		return "", errors.New("Too long name")
	}
	return strings.Replace(name, "\n", "", -1), nil
}

func gameOver(conf *Config, conn net.Conn, roundData *RoundData, gameData *GameData) {

	conn.Write(gameData.Clear)

	// First we print current player result:
	// Score
	scoreStr := fmt.Sprintf("%d", roundData.player.Score)
	for i, char := range scoreStr {
		roundData.GameOver[i] = byte(char)
	}
	//:
	roundData.GameOver[result_width/2] = byte(':')
	//Name
	for i, char := range []byte(roundData.player.Name) {
		roundData.GameOver[result_width-1-len(roundData.player.Name)+i] = byte(char)
	}

	// Then we check on which place is current player
	inserted := false
	for i, player := range gameData.Top {
		if roundData.player.Score >= player.Score {
			// Insert new record
			gameData.Top = append(gameData.Top[:i], append([]Player{roundData.player}, gameData.Top[i:]...)...)
			inserted = true
			break
		}
	}
	if !inserted {
		gameData.Top = append(gameData.Top, roundData.player)
	}

	// Remove slowest user if top is full
	if len(gameData.Top) >= max_players_in_top {
		gameData.Top = gameData.Top[:max_players_in_top]
	}

	//TOP
	copy(roundData.GameOver[1*result_width+result_width/2-1:2*result_width+result_width/2+2], []byte("TOP"))

	// Then print new top
	for place, player := range gameData.Top {
		// Score
		scoreStr := fmt.Sprintf("%d", player.Score)
		for i, char := range scoreStr {
			roundData.GameOver[(2+place)*result_width+i] = byte(char)
		}
		//:
		roundData.GameOver[(2+place)*result_width+result_width/2] = byte(':')
		//Name
		for i, char := range []byte(player.Name) {
			roundData.GameOver[(2+place)*result_width+result_width-1-len(player.Name)+i] = byte(char)
		}
	}

	conn.Write(roundData.GameOver)
	// We do not need to check for error because user should not care, but logs are written
	saveScore(conf, gameData)
}

func saveScore(conf *Config, gameData *GameData) error {
	b, err := json.Marshal(gameData.Top)
	if err != nil {
		conf.Log.Println(err)
		return err
	}

	// Being sure file was not there
	os.Remove(conf.ScorePath + "/score.json")
	scoreFile, err := os.OpenFile(conf.ScorePath+"/score.json", os.O_RDWR|os.O_CREATE, 0600)
	if err != nil {
		conf.Log.Println(err)
		return err
	}
	defer scoreFile.Close()

	scoreFile.Write(b)
	return nil
}

func round(conf *Config, conn net.Conn, gameData *GameData) {
	defer conn.Close()

	roundData := RoundData{}
	roundData.CarPosition = Point{road_width/2 - car_width/2, road_lenght - car_lenght - 1}
	roundData.bombPosition = Point{road_width, road_lenght}
	roundData.bonusPosition = Point{road_width, road_lenght}
	roundData.GameOver, _ = getAcid(conf, "game_over.txt")

	roundData.BombFactor = 10
	roundData.BonusFactor = 10
	roundData.Speed = 200

	name, err := readName(conf, conn)
	if err != nil {
		return
	}
	roundData.player.Name = name
	go updateScore(&roundData)
	go updatePosition(conn, &roundData.CarPosition)

	for {
		if roundData.CarPosition.X < 1 || roundData.CarPosition.X > road_width-car_width-1 || roundData.CarPosition.Y < 1 || roundData.CarPosition.Y > road_lenght-car_lenght-1 {
			// Hit the wall
			gameOver(conf, conn, &roundData, gameData)
			return
		} else if roundData.CarPosition.X <= roundData.bombPosition.X && roundData.CarPosition.X+car_width-1 > roundData.bombPosition.X &&
			roundData.CarPosition.Y <= roundData.bombPosition.Y && roundData.CarPosition.Y+car_lenght-1 > roundData.bombPosition.Y {
			// Hit the bomb
			gameOver(conf, conn, &roundData, gameData)
			return
		} else if roundData.CarPosition.X <= roundData.bonusPosition.X && roundData.CarPosition.X+car_width-1 > roundData.bonusPosition.X &&
			roundData.CarPosition.Y <= roundData.bonusPosition.Y && roundData.CarPosition.Y+car_lenght-1 > roundData.bonusPosition.Y {
			// Get the bonus
			roundData.player.Score += 10
			roundData.bonusPosition = Point{road_width, road_lenght}
		}

		for i := range gameData.Roads {
			data := make([]byte, len(gameData.Roads[i]))
			copy(data, gameData.Roads[i])

			// Moving cursor at the beginning
			_, err := conn.Write(gameData.Clear)
			if err != nil {
				return
			}

			// Checking and updating complexity
			if roundData.player.Score > 100 && roundData.player.Score < 200 {
				roundData.Speed = 150
			} else if roundData.player.Score >= 200 && roundData.player.Score < 400 {
				roundData.BonusFactor = 5
				roundData.Speed = 100
			} else if roundData.player.Score >= 400 && roundData.player.Score < 600 {
				roundData.BonusFactor = 10
				roundData.BombFactor = 5
			} else if roundData.player.Score >= 600 {
				roundData.BonusFactor = 123
				roundData.BombFactor = 1
				roundData.Speed = 80
			}

			// Applying the bonus
			if roundData.bonusPosition.Y < road_lenght {
				data[roundData.bonusPosition.Y*road_width+roundData.bonusPosition.X] = byte('$')
				roundData.bonusPosition.Y++
			} else if rand.Int()%roundData.BonusFactor == 0 {
				roundData.bonusPosition.X, roundData.bonusPosition.Y = rand.Intn(road_width-3)+1, 0
			}

			// Applying the bomb
			if roundData.bombPosition.Y < road_lenght {
				data[roundData.bombPosition.Y*road_width+roundData.bombPosition.X] = byte('X')
				roundData.bombPosition.Y++
			} else if rand.Int()%roundData.BombFactor == 0 {
				roundData.bombPosition.X, roundData.bombPosition.Y = rand.Intn(road_width-3)+1, 0
			}

			// Applying the Car
			for line := 0; line < car_lenght; line++ {
				copy(data[((roundData.CarPosition.Y+line)*road_width+roundData.CarPosition.X):((roundData.CarPosition.Y+line)*road_width+roundData.CarPosition.X)+car_width-1],
					gameData.Car[line*car_width:line*car_width+car_width-1])
			}

			// Applying the score
			scoreStr := fmt.Sprintf("%d", roundData.player.Score)
			for i := range scoreStr {
				data[i] = byte(scoreStr[i])

			}

			_, err = conn.Write(data)
			if err != nil {
				return
			}
			time.Sleep(time.Duration(roundData.Speed) * time.Millisecond)
		}
	}
}

func main() {
	var logFile string
	conf := &Config{}

	flag.StringVar(&logFile, "l", "/var/log/race.log", "Log file")
	flag.StringVar(&conf.AcidPath, "a", "/Users/leoleovich/go/src/github.com/leoleovich/race/artifacts", "Artifacts location")
	flag.StringVar(&conf.ScorePath, "s", "/Users/leoleovich/go/src/github.com/leoleovich/race/artifacts", "Score location")
	flag.Parse()

	logfile, err := os.OpenFile(logFile, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0600)
	conf.Log = log.New(logfile, "", log.Ldate|log.Lmicroseconds|log.Lshortfile)

	l, err := net.Listen("tcp", ":4242")
	if err != nil {
		conf.Log.Println(err)
		os.Exit(2)
	}
	defer l.Close()

	gameData := GameData{}
	gameData.Roads = [][]byte{generateRoad(false), generateRoad(true)}
	gameData.Car, _ = getAcid(conf, "car.txt")
	gameData.Clear, _ = getAcid(conf, "clear.txt")
	scoreData, _ := getAcid(conf, "score.json")
	err = json.Unmarshal(scoreData, &gameData.Top)

	for {
		conn, err := l.Accept()
		if err != nil {
			conf.Log.Println("Failed to accept request", err)
		}
		go round(conf, conn, &gameData)
	}
}
<commit_msg>Create functions for checking position and complexity<commit_after>package main

import (
	"bufio"
	"encoding/json"
	"flag"
	"fmt"
	"github.com/pkg/errors"
	"log"
	"math/rand"
	"net"
	"os"
	"strings"
	"time"
)

const road_width = 40
const road_lenght = 20
const car_width = 14
const car_lenght = 7
const result_width = 76
const max_players_in_top = 10

type Config struct {
	Log                 *log.Logger
	AcidPath, ScorePath string
}

type Point struct {
	X, Y int
}

type Player struct {
	Name  string
	Score int64
}

type GameData struct {
	Roads      [][]byte
	Car, Clear []byte
	Top        []Player
}

type RoundData struct {
	player                                   Player
	CarPosition, bombPosition, bonusPosition Point
	BombFactor, BonusFactor, Speed           int
	GameOver                                 []byte
}

func generateRoad(reverse bool) []byte {
	road := make([]byte, road_width*road_lenght)
	midline := reverse
	for row := 0; row < road_lenght; row++ {
		for column := 0; column < road_width; column++ {
			var symbol byte
			if column == 0 || column == road_width-2 {
				symbol = byte('|')
			} else if column == road_width-1 {
				symbol = byte('\n')
			} else if column == road_width/2-1 {
				if midline {
					symbol = byte('|')
				} else {
					symbol = byte(' ')
				}
				midline = !midline
			} else {
				symbol = byte(' ')
			}
			road[row*road_width+column] = symbol
		}

	}
	return road
}

func getAcid(conf *Config, fileName string) ([]byte, error) {
	fileStat, err := os.Stat(conf.AcidPath + "/" + fileName)
	if err != nil {
		conf.Log.Printf("Acid %s does not exist: %v\n", fileName, err)
		return []byte{}, err
	}

	acid := make([]byte, fileStat.Size())
	f, err := os.OpenFile(conf.AcidPath+"/"+fileName, os.O_RDONLY, os.ModePerm)
	if err != nil {
		conf.Log.Printf("Error while opening %s: %v\n", fileName, err)
		os.Exit(1)
	}
	defer f.Close()

	f.Read(acid)

	return acid, nil
}

func updatePosition(conn net.Conn, position *Point) {
	for {
		direction := make([]byte, 1)

		_, err := conn.Read(direction)
		if err != nil {
			return
		}

		switch direction[0] {
		case 68:
			// Left
			position.X--
		case 67:
			// Right
			position.X++
		case 65:
			// Up
			position.Y--
		case 66:
			// Down
			position.Y++
		}
	}
}

func updateScore(roundData *RoundData) {
	for {
		roundData.player.Score++
		time.Sleep(time.Duration(roundData.Speed) * time.Millisecond)
	}

}

func readName(conf *Config, conn net.Conn) (string, error) {
	conn.Write([]byte("Enter your name:"))
	io := bufio.NewReader(conn)
	name, err := io.ReadString('\n')
	if err != nil {
		conf.Log.Println("Error while name reading", err)
		return "", err
	}
	if name == "" {
		conf.Log.Println("Empty name")
		return "", errors.New("Empty name")
	}
	if len(name) > result_width/2 {
		conf.Log.Println("Too long name")
		return "", errors.New("Too long name")
	}
	return strings.Replace(name, "\n", "", -1), nil
}

func gameOver(conf *Config, conn net.Conn, roundData *RoundData, gameData *GameData) {

	conn.Write(gameData.Clear)

	// First we print current player result:
	// Score
	scoreStr := fmt.Sprintf("%d", roundData.player.Score)
	for i, char := range scoreStr {
		roundData.GameOver[i] = byte(char)
	}
	//:
	roundData.GameOver[result_width/2] = byte(':')
	//Name
	for i, char := range []byte(roundData.player.Name) {
		roundData.GameOver[result_width-1-len(roundData.player.Name)+i] = byte(char)
	}

	// Then we check on which place is current player
	inserted := false
	for i, player := range gameData.Top {
		if roundData.player.Score >= player.Score {
			// Insert new record
			gameData.Top = append(gameData.Top[:i], append([]Player{roundData.player}, gameData.Top[i:]...)...)
			inserted = true
			break
		}
	}
	if !inserted {
		gameData.Top = append(gameData.Top, roundData.player)
	}

	// Remove slowest user if top is full
	if len(gameData.Top) >= max_players_in_top {
		gameData.Top = gameData.Top[:max_players_in_top]
	}

	//TOP
	copy(roundData.GameOver[1*result_width+result_width/2-1:2*result_width+result_width/2+2], []byte("TOP"))

	// Then print new top
	for place, player := range gameData.Top {
		// Score
		scoreStr := fmt.Sprintf("%d", player.Score)
		for i, char := range scoreStr {
			roundData.GameOver[(2+place)*result_width+i] = byte(char)
		}
		//:
		roundData.GameOver[(2+place)*result_width+result_width/2] = byte(':')
		//Name
		for i, char := range []byte(player.Name) {
			roundData.GameOver[(2+place)*result_width+result_width-1-len(player.Name)+i] = byte(char)
		}
	}

	conn.Write(roundData.GameOver)
	// We do not need to check for error because user should not care, but logs are written
	saveScore(conf, gameData)
}

func saveScore(conf *Config, gameData *GameData) error {
	b, err := json.Marshal(gameData.Top)
	if err != nil {
		conf.Log.Println(err)
		return err
	}

	// Being sure file was not there
	os.Remove(conf.ScorePath + "/score.json")
	scoreFile, err := os.OpenFile(conf.ScorePath+"/score.json", os.O_RDWR|os.O_CREATE, 0600)
	if err != nil {
		conf.Log.Println(err)
		return err
	}
	defer scoreFile.Close()

	scoreFile.Write(b)
	return nil
}

func checkComplexity(roundData *RoundData) {
	// Checking and updating complexity
	if roundData.player.Score >= 600 {
		roundData.BonusFactor = 100
		roundData.BombFactor = 1
		roundData.Speed = 80
	} else if roundData.player.Score >= 400 {
		roundData.BonusFactor = 10
		roundData.BombFactor = 5
	} else if roundData.player.Score >= 200 {
		roundData.BonusFactor = 5
		roundData.Speed = 100
	} else if roundData.player.Score > 50 {
		roundData.Speed = 150
	}

}

func checkPosition(conf *Config, conn net.Conn, roundData *RoundData, gameData *GameData) bool {
	if roundData.CarPosition.X < 1 || roundData.CarPosition.X > road_width-car_width-1 || roundData.CarPosition.Y < 1 || roundData.CarPosition.Y > road_lenght-car_lenght-1 {
		// Hit the wall
		gameOver(conf, conn, roundData, gameData)
		return false
	} else if roundData.CarPosition.X <= roundData.bombPosition.X && roundData.CarPosition.X+car_width-1 > roundData.bombPosition.X &&
		roundData.CarPosition.Y <= roundData.bombPosition.Y && roundData.CarPosition.Y+car_lenght-1 > roundData.bombPosition.Y {
		// Hit the bomb
		gameOver(conf, conn, roundData, gameData)
		return false
	} else if roundData.CarPosition.X <= roundData.bonusPosition.X && roundData.CarPosition.X+car_width-1 > roundData.bonusPosition.X &&
		roundData.CarPosition.Y <= roundData.bonusPosition.Y && roundData.CarPosition.Y+car_lenght-1 > roundData.bonusPosition.Y {
		// Get the bonus
		roundData.player.Score += 10
		roundData.bonusPosition = Point{road_width, road_lenght}
	}
	return true
}

func round(conf *Config, conn net.Conn, gameData *GameData) {
	defer conn.Close()

	roundData := RoundData{}
	roundData.CarPosition = Point{road_width/2 - car_width/2, road_lenght - car_lenght - 1}
	roundData.bombPosition = Point{road_width, road_lenght}
	roundData.bonusPosition = Point{road_width, road_lenght}
	roundData.GameOver, _ = getAcid(conf, "game_over.txt")

	roundData.BombFactor = 10
	roundData.BonusFactor = 10
	roundData.Speed = 200

	name, err := readName(conf, conn)
	if err != nil {
		return
	}
	roundData.player.Name = name
	go updateScore(&roundData)
	go updatePosition(conn, &roundData.CarPosition)

	for {
		if !checkPosition(conf, conn, &roundData, gameData) {
			return
		}

		for i := range gameData.Roads {
			data := make([]byte, len(gameData.Roads[i]))
			copy(data, gameData.Roads[i])

			// Moving cursor at the beginning
			_, err := conn.Write(gameData.Clear)
			if err != nil {
				return
			}

			// Checking and updating complexity
			checkComplexity(&roundData)

			// Applying the bonus
			if roundData.bonusPosition.Y < road_lenght {
				data[roundData.bonusPosition.Y*road_width+roundData.bonusPosition.X] = byte('$')
				roundData.bonusPosition.Y++
			} else if rand.Int()%roundData.BonusFactor == 0 {
				roundData.bonusPosition.X, roundData.bonusPosition.Y = rand.Intn(road_width-3)+1, 0
			}

			// Applying the bomb
			if roundData.bombPosition.Y < road_lenght {
				data[roundData.bombPosition.Y*road_width+roundData.bombPosition.X] = byte('X')
				roundData.bombPosition.Y++
			} else if rand.Int()%roundData.BombFactor == 0 {
				roundData.bombPosition.X, roundData.bombPosition.Y = rand.Intn(road_width-3)+1, 0
			}

			// Applying the Car
			for line := 0; line < car_lenght; line++ {
				copy(data[((roundData.CarPosition.Y+line)*road_width+roundData.CarPosition.X):((roundData.CarPosition.Y+line)*road_width+roundData.CarPosition.X)+car_width-1],
					gameData.Car[line*car_width:line*car_width+car_width-1])
			}

			// Applying the score
			scoreStr := fmt.Sprintf("%d", roundData.player.Score)
			for i := range scoreStr {
				data[i] = byte(scoreStr[i])

			}

			_, err = conn.Write(data)
			if err != nil {
				return
			}
			time.Sleep(time.Duration(roundData.Speed) * time.Millisecond)
		}
	}
}

func main() {
	var logFile string
	conf := &Config{}

	flag.StringVar(&logFile, "l", "/var/log/race.log", "Log file")
	flag.StringVar(&conf.AcidPath, "a", "/Users/leoleovich/go/src/github.com/leoleovich/race/artifacts", "Artifacts location")
	flag.StringVar(&conf.ScorePath, "s", "/Users/leoleovich/go/src/github.com/leoleovich/race/artifacts", "Score location")
	flag.Parse()

	logfile, err := os.OpenFile(logFile, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0600)
	conf.Log = log.New(logfile, "", log.Ldate|log.Lmicroseconds|log.Lshortfile)

	l, err := net.Listen("tcp", ":4242")
	if err != nil {
		conf.Log.Println(err)
		os.Exit(2)
	}
	defer l.Close()

	gameData := GameData{}
	gameData.Roads = [][]byte{generateRoad(false), generateRoad(true)}
	gameData.Car, _ = getAcid(conf, "car.txt")
	gameData.Clear, _ = getAcid(conf, "clear.txt")
	scoreData, _ := getAcid(conf, "score.json")
	err = json.Unmarshal(scoreData, &gameData.Top)

	for {
		conn, err := l.Accept()
		if err != nil {
			conf.Log.Println("Failed to accept request", err)
		}
		go round(conf, conn, &gameData)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"encoding/json"
	"flag"
	"fmt"
	"github.com/pkg/errors"
	"log"
	"math/rand"
	"net"
	"os"
	"sort"
	"strings"
	"time"
)

const road_width = 40
const road_lenght = 20
const car_width = 14
const car_lenght = 7
const result_width = 76
const max_players_in_top = 10
const speed_factor = 10500

type Config struct {
	Log                 *log.Logger
	AcidPath, ScorePath string
}

type Point struct {
	X, Y int
}

type GameData struct {
	Roads              [][]byte
	Car, Clear, Splash []byte
	Top                []Player
}

type RoundData struct {
	player                                   Player
	CarPosition, bombPosition, bonusPosition Point
	BombFactor, BonusFactor, Speed           int
	GameOver                                 []byte
}

type Player struct {
	Name  string
	Score int64
}

type Players []Player

func (p Players) Len() int           { return len(p) }
func (p Players) Swap(i, j int)      { p[i], p[j] = p[j], p[i] }
func (p Players) Less(i, j int) bool { return p[i].Score > p[j].Score }

func generateRoad(reverse bool) []byte {
	road := make([]byte, road_width*road_lenght)
	midline := reverse
	for row := 0; row < road_lenght; row++ {
		for column := 0; column < road_width; column++ {
			var symbol byte
			if column == 0 || column == road_width-2 {
				symbol = byte('|')
			} else if column == road_width-1 {
				symbol = byte('\n')
			} else if column == road_width/2-1 {
				if midline {
					symbol = byte('|')
				} else {
					symbol = byte(' ')
				}
				midline = !midline
			} else {
				symbol = byte(' ')
			}
			road[row*road_width+column] = symbol
		}
	}
	return road
}

func getAcid(conf *Config, fileName string) ([]byte, error) {
	fileStat, err := os.Stat(conf.AcidPath + "/" + fileName)
	if err != nil {
		conf.Log.Printf("Acid %s does not exist: %v\n", fileName, err)
		return []byte{}, err
	}

	acid := make([]byte, fileStat.Size())
	f, err := os.OpenFile(conf.AcidPath+"/"+fileName, os.O_RDONLY, os.ModePerm)
	if err != nil {
		conf.Log.Printf("Error while opening %s: %v\n", fileName, err)
		os.Exit(1)
	}
	defer f.Close()

	f.Read(acid)

	return acid, nil
}

func updatePosition(conn net.Conn, position *Point) {
	for {
		direction := make([]byte, 1)

		_, err := conn.Read(direction)
		if err != nil {
			return
		}

		switch direction[0] {
		case 68:
			// Left
			position.X--
		case 67:
			// Right
			position.X++
		case 65:
			// Up
			position.Y--
		case 66:
			// Down
			position.Y++
		}
	}
}

func updateScore(roundData *RoundData) {
	for {
		roundData.player.Score++
		time.Sleep(time.Duration(roundData.Speed) * time.Millisecond)
	}

}

func readName(conf *Config, conn net.Conn, gameData *GameData) (string, error) {
	conn.Write(gameData.Splash)
	io := bufio.NewReader(conn)
	line, err := io.ReadString('\n')
	if err != nil {
		conf.Log.Println("Error while name reading", err)
		return "", err
	}
	name := strings.Replace(line, "\n", "", -1)
	if name == "" {
		conf.Log.Println("Empty name")
		return "", errors.New("Empty name")
	}
	if len(name) > result_width/2 {
		conf.Log.Println("Too long name")
		return "", errors.New("Too long name")
	}
	return name, nil
}

func gameOver(conf *Config, conn net.Conn, roundData *RoundData, gameData *GameData) {

	conn.Write(gameData.Clear)

	// First we print current player result:
	// Score
	scoreStr := fmt.Sprintf("%d", roundData.player.Score)
	for i, char := range scoreStr {
		roundData.GameOver[i] = byte(char)
	}
	//:
	roundData.GameOver[result_width/2] = byte(':')
	//Name
	for i, char := range []byte(roundData.player.Name) {
		roundData.GameOver[result_width-1-len(roundData.player.Name)+i] = byte(char)
	}

	// Then we check on which place is current player
	inserted := false
	for _, player := range gameData.Top {
		if roundData.player.Score >= player.Score {
			// Protection from fair bots
			if strings.Contains(roundData.player.Name, "BOT") {
				for i, player := range gameData.Top {
					if roundData.player.Name == player.Name {
						gameData.Top[i].Score = roundData.player.Score
						inserted = true
						break
					}
				}
			}

			// Insert new record to the end of slice
			if !inserted {
				gameData.Top = append(gameData.Top, roundData.player)
			}

			// Resort the slice
			sort.Sort(Players(gameData.Top))

			// Remove slowest user if top is full
			if len(gameData.Top) >= max_players_in_top {
				gameData.Top = gameData.Top[:max_players_in_top]
			}
			break
		}
	}

	//TOP
	copy(roundData.GameOver[1*result_width+result_width/2-1:2*result_width+result_width/2+2], []byte("TOP"))

	// Then print new top
	for place, player := range gameData.Top {
		// Score
		scoreStr := fmt.Sprintf("%d", player.Score)
		for i, char := range scoreStr {
			roundData.GameOver[(2+place)*result_width+i] = byte(char)
		}
		//:
		roundData.GameOver[(2+place)*result_width+result_width/2] = byte(':')
		//Name
		for i, char := range []byte(player.Name) {
			roundData.GameOver[(2+place)*result_width+result_width-1-len(player.Name)+i] = byte(char)
		}
	}

	conn.Write(roundData.GameOver)
	// We do not need to check for error because user should not care, but logs are written
	saveScore(conf, gameData)
}

func saveScore(conf *Config, gameData *GameData) error {
	b, err := json.Marshal(gameData.Top)
	if err != nil {
		conf.Log.Println(err)
		return err
	}

	// Being sure file was not there
	os.Remove(conf.ScorePath + "/score.json")
	scoreFile, err := os.OpenFile(conf.ScorePath+"/score.json", os.O_RDWR|os.O_CREATE, 0600)
	if err != nil {
		conf.Log.Println(err)
		return err
	}
	defer scoreFile.Close()

	scoreFile.Write(b)
	return nil
}

func checkComplexity(roundData *RoundData) {
	// Checking and updating complexity
	if roundData.player.Score >= 1000 {
		roundData.Speed = 70
	} else if roundData.player.Score >= 600 {
		roundData.BonusFactor = 100
		roundData.BombFactor = 1
		roundData.Speed = 80
	} else if roundData.player.Score >= 400 {
		roundData.BonusFactor = 10
		roundData.BombFactor = 5
	} else if roundData.player.Score >= 200 {
		roundData.BonusFactor = 5
		roundData.Speed = 100
	} else if roundData.player.Score >= 50 {
		roundData.Speed = 150
	}

}

func checkPosition(conf *Config, conn net.Conn, roundData *RoundData, gameData *GameData) bool {
	if roundData.CarPosition.X < 1 || roundData.CarPosition.X > road_width-car_width-1 || roundData.CarPosition.Y < 1 || roundData.CarPosition.Y > road_lenght-car_lenght-1 {
		// Hit the wall
		gameOver(conf, conn, roundData, gameData)
		return false
	} else if roundData.CarPosition.X <= roundData.bombPosition.X && roundData.CarPosition.X+car_width-1 > roundData.bombPosition.X &&
		roundData.CarPosition.Y <= roundData.bombPosition.Y && roundData.CarPosition.Y+car_lenght-1 > roundData.bombPosition.Y {
		// Hit the bomb
		gameOver(conf, conn, roundData, gameData)
		return false
	} else if roundData.CarPosition.X <= roundData.bonusPosition.X && roundData.CarPosition.X+car_width-1 > roundData.bonusPosition.X &&
		roundData.CarPosition.Y <= roundData.bonusPosition.Y && roundData.CarPosition.Y+car_lenght-1 > roundData.bonusPosition.Y {
		// Get the bonus
		roundData.player.Score += 10
		roundData.bonusPosition = Point{road_width, road_lenght}
	}
	return true
}

func round(conf *Config, conn net.Conn, gameData *GameData) {
	defer conn.Close()

	roundData := RoundData{}
	roundData.CarPosition = Point{road_width/2 - car_width/2, road_lenght - car_lenght - 1}
	roundData.bombPosition = Point{road_width, road_lenght}
	roundData.bonusPosition = Point{road_width, road_lenght}
	roundData.GameOver, _ = getAcid(conf, "game_over.txt")

	roundData.BombFactor = 10
	roundData.BonusFactor = 10
	roundData.Speed = 200

	name, err := readName(conf, conn, gameData)
	if err != nil {
		return
	}
	roundData.player.Name = name
	go updateScore(&roundData)
	go updatePosition(conn, &roundData.CarPosition)

	for {
		if !checkPosition(conf, conn, &roundData, gameData) {
			return
		}

		for i := range gameData.Roads {
			data := make([]byte, len(gameData.Roads[i]))
			copy(data, gameData.Roads[i])

			// Moving cursor at the beginning
			_, err := conn.Write(gameData.Clear)
			if err != nil {
				return
			}

			// Checking and updating complexity
			checkComplexity(&roundData)

			// Applying the bonus
			if roundData.bonusPosition.Y < road_lenght {
				data[roundData.bonusPosition.Y*road_width+roundData.bonusPosition.X] = byte('$')
				roundData.bonusPosition.Y++
			} else if rand.Int()%roundData.BonusFactor == 0 {
				roundData.bonusPosition.X, roundData.bonusPosition.Y = rand.Intn(road_width-3)+1, 0
			}

			// Applying the bomb
			if roundData.bombPosition.Y < road_lenght {
				data[roundData.bombPosition.Y*road_width+roundData.bombPosition.X] = byte('X')
				roundData.bombPosition.Y++
			} else if rand.Int()%roundData.BombFactor == 0 {
				roundData.bombPosition.X, roundData.bombPosition.Y = rand.Intn(road_width-3)+1, 0
			}

			// Applying the Car
			for line := 0; line < car_lenght; line++ {
				copy(data[((roundData.CarPosition.Y+line)*road_width+roundData.CarPosition.X):((roundData.CarPosition.Y+line)*road_width+roundData.CarPosition.X)+car_width-1],
					gameData.Car[line*car_width:line*car_width+car_width-1])
			}

			// Applying the score
			scoreStr := fmt.Sprintf("Score: %d", roundData.player.Score)
			for i := range scoreStr {
				data[(road_lenght-1)*road_width+i] = byte(scoreStr[i])
			}
			// Applying the speed
			speedStr := fmt.Sprintf("Speed: %d km/h", speed_factor/roundData.Speed)
			for i := range speedStr {
				data[road_lenght*road_width-len(speedStr)-1+i] = byte(speedStr[i])
			}

			_, err = conn.Write(data)
			if err != nil {
				return
			}
			time.Sleep(time.Duration(roundData.Speed) * time.Millisecond)
		}
	}
}

func main() {
	var logFile string
	conf := &Config{}

	flag.StringVar(&logFile, "l", "/var/log/race.log", "Log file")
	flag.StringVar(&conf.AcidPath, "a", "/Users/leoleovich/go/src/github.com/leoleovich/race/artifacts", "Artifacts location")
	flag.StringVar(&conf.ScorePath, "s", "/Users/leoleovich/go/src/github.com/leoleovich/race/artifacts", "Score location")
	flag.Parse()

	logfile, err := os.OpenFile(logFile, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0600)
	conf.Log = log.New(logfile, "", log.Ldate|log.Lmicroseconds|log.Lshortfile)

	l, err := net.Listen("tcp", ":4242")
	if err != nil {
		conf.Log.Println(err)
		os.Exit(2)
	}
	defer l.Close()

	gameData := GameData{}
	gameData.Roads = [][]byte{generateRoad(false), generateRoad(true)}
	gameData.Car, _ = getAcid(conf, "car.txt")
	gameData.Clear, _ = getAcid(conf, "clear.txt")
	gameData.Splash, _ = getAcid(conf, "splash.txt")
	scoreData, _ := getAcid(conf, "score.json")
	err = json.Unmarshal(scoreData, &gameData.Top)

	for {
		conn, err := l.Accept()
		if err != nil {
			conf.Log.Println("Failed to accept request", err)
		}
		go round(conf, conn, &gameData)
	}
}
<commit_msg>Multi-roads generator<commit_after>package main

import (
	"bufio"
	"encoding/json"
	"flag"
	"fmt"
	"github.com/pkg/errors"
	"log"
	"math/rand"
	"net"
	"os"
	"sort"
	"strings"
	"time"
)

const road_width = 40
const road_lenght = 20
const car_width = 14
const car_lenght = 7
const result_width = 76
const max_players_in_top = 10
const speed_factor = 10500

type Config struct {
	Log                 *log.Logger
	AcidPath, ScorePath string
}

type Point struct {
	X, Y int
}

type GameData struct {
	Roads              [][]byte
	Car, Clear, Splash []byte
	Top                []Player
}

type RoundData struct {
	player                                   Player
	CarPosition, bombPosition, bonusPosition Point
	BombFactor, BonusFactor, Speed           int
	GameOver                                 []byte
}

type Player struct {
	Name  string
	Score int64
}

type Players []Player

func (p Players) Len() int           { return len(p) }
func (p Players) Swap(i, j int)      { p[i], p[j] = p[j], p[i] }
func (p Players) Less(i, j int) bool { return p[i].Score > p[j].Score }

func generateRoads(size int) [][]byte {
	roads := make([][]byte, size)
	for offset := 0; offset < size; offset++ {
		roads[offset] = make([]byte, road_width*road_lenght)
		for row := 0; row < road_lenght; row++ {
			for column := 0; column < road_width; column++ {
				var symbol byte
				if column == 0 || column == road_width-2 {
					symbol = byte('|')
				} else if column == road_width-1 {
					symbol = byte('\n')
				} else if column == road_width/2-1 {
					if (row-offset)%size == 0 {
						symbol = byte('|')
					} else {
						symbol = byte(' ')
					}
				} else {
					symbol = byte(' ')
				}
				roads[offset][row*road_width+column] = symbol
			}
		}
	}
	return roads
}

func getAcid(conf *Config, fileName string) ([]byte, error) {
	fileStat, err := os.Stat(conf.AcidPath + "/" + fileName)
	if err != nil {
		conf.Log.Printf("Acid %s does not exist: %v\n", fileName, err)
		return []byte{}, err
	}

	acid := make([]byte, fileStat.Size())
	f, err := os.OpenFile(conf.AcidPath+"/"+fileName, os.O_RDONLY, os.ModePerm)
	if err != nil {
		conf.Log.Printf("Error while opening %s: %v\n", fileName, err)
		os.Exit(1)
	}
	defer f.Close()

	f.Read(acid)

	return acid, nil
}

func updatePosition(conn net.Conn, position *Point) {
	for {
		direction := make([]byte, 1)

		_, err := conn.Read(direction)
		if err != nil {
			return
		}

		switch direction[0] {
		case 68:
			// Left
			position.X--
		case 67:
			// Right
			position.X++
		case 65:
			// Up
			position.Y--
		case 66:
			// Down
			position.Y++
		}
	}
}

func updateScore(roundData *RoundData) {
	for {
		roundData.player.Score++
		time.Sleep(time.Duration(roundData.Speed) * time.Millisecond)
	}

}

func readName(conf *Config, conn net.Conn, gameData *GameData) (string, error) {
	conn.Write(gameData.Splash)
	io := bufio.NewReader(conn)
	line, err := io.ReadString('\n')
	if err != nil {
		conf.Log.Println("Error while name reading", err)
		return "", err
	}
	name := strings.Replace(line, "\n", "", -1)
	if name == "" {
		conf.Log.Println("Empty name")
		return "", errors.New("Empty name")
	}
	if len(name) > result_width/2 {
		conf.Log.Println("Too long name")
		return "", errors.New("Too long name")
	}
	return name, nil
}

func gameOver(conf *Config, conn net.Conn, roundData *RoundData, gameData *GameData) {

	conn.Write(gameData.Clear)

	// First we print current player result:
	// Score
	scoreStr := fmt.Sprintf("%d", roundData.player.Score)
	for i, char := range scoreStr {
		roundData.GameOver[i] = byte(char)
	}
	//:
	roundData.GameOver[result_width/2] = byte(':')
	//Name
	for i, char := range []byte(roundData.player.Name) {
		roundData.GameOver[result_width-1-len(roundData.player.Name)+i] = byte(char)
	}

	// Then we check on which place is current player
	inserted := false
	for _, player := range gameData.Top {
		if roundData.player.Score >= player.Score {
			// Protection from fair bots
			if strings.Contains(roundData.player.Name, "BOT") {
				for i, player := range gameData.Top {
					if roundData.player.Name == player.Name {
						gameData.Top[i].Score = roundData.player.Score
						inserted = true
						break
					}
				}
			}

			// Insert new record to the end of slice
			if !inserted {
				gameData.Top = append(gameData.Top, roundData.player)
			}

			// Resort the slice
			sort.Sort(Players(gameData.Top))

			// Remove slowest user if top is full
			if len(gameData.Top) >= max_players_in_top {
				gameData.Top = gameData.Top[:max_players_in_top]
			}
			break
		}
	}

	//TOP
	copy(roundData.GameOver[1*result_width+result_width/2-1:2*result_width+result_width/2+2], []byte("TOP"))

	// Then print new top
	for place, player := range gameData.Top {
		// Score
		scoreStr := fmt.Sprintf("%d", player.Score)
		for i, char := range scoreStr {
			roundData.GameOver[(2+place)*result_width+i] = byte(char)
		}
		//:
		roundData.GameOver[(2+place)*result_width+result_width/2] = byte(':')
		//Name
		for i, char := range []byte(player.Name) {
			roundData.GameOver[(2+place)*result_width+result_width-1-len(player.Name)+i] = byte(char)
		}
	}

	conn.Write(roundData.GameOver)
	// We do not need to check for error because user should not care, but logs are written
	saveScore(conf, gameData)
}

func saveScore(conf *Config, gameData *GameData) error {
	b, err := json.Marshal(gameData.Top)
	if err != nil {
		conf.Log.Println(err)
		return err
	}

	// Being sure file was not there
	os.Remove(conf.ScorePath + "/score.json")
	scoreFile, err := os.OpenFile(conf.ScorePath+"/score.json", os.O_RDWR|os.O_CREATE, 0600)
	if err != nil {
		conf.Log.Println(err)
		return err
	}
	defer scoreFile.Close()

	scoreFile.Write(b)
	return nil
}

func checkComplexity(roundData *RoundData) {
	// Checking and updating complexity
	if roundData.player.Score >= 1000 {
		roundData.Speed = 70
	} else if roundData.player.Score >= 600 {
		roundData.BonusFactor = 100
		roundData.BombFactor = 1
		roundData.Speed = 80
	} else if roundData.player.Score >= 400 {
		roundData.BonusFactor = 10
		roundData.BombFactor = 5
	} else if roundData.player.Score >= 200 {
		roundData.BonusFactor = 5
		roundData.Speed = 100
	} else if roundData.player.Score >= 50 {
		roundData.Speed = 150
	}

}

func checkPosition(conf *Config, conn net.Conn, roundData *RoundData, gameData *GameData) bool {
	if roundData.CarPosition.X < 1 || roundData.CarPosition.X > road_width-car_width-1 || roundData.CarPosition.Y < 1 || roundData.CarPosition.Y > road_lenght-car_lenght-1 {
		// Hit the wall
		gameOver(conf, conn, roundData, gameData)
		return false
	} else if roundData.CarPosition.X <= roundData.bombPosition.X && roundData.CarPosition.X+car_width-1 > roundData.bombPosition.X &&
		roundData.CarPosition.Y <= roundData.bombPosition.Y && roundData.CarPosition.Y+car_lenght-1 > roundData.bombPosition.Y {
		// Hit the bomb
		gameOver(conf, conn, roundData, gameData)
		return false
	} else if roundData.CarPosition.X <= roundData.bonusPosition.X && roundData.CarPosition.X+car_width-1 > roundData.bonusPosition.X &&
		roundData.CarPosition.Y <= roundData.bonusPosition.Y && roundData.CarPosition.Y+car_lenght-1 > roundData.bonusPosition.Y {
		// Get the bonus
		roundData.player.Score += 10
		roundData.bonusPosition = Point{road_width, road_lenght}
	}
	return true
}

func round(conf *Config, conn net.Conn, gameData *GameData) {
	defer conn.Close()

	roundData := RoundData{}
	roundData.CarPosition = Point{road_width/2 - car_width/2, road_lenght - car_lenght - 1}
	roundData.bombPosition = Point{road_width, road_lenght}
	roundData.bonusPosition = Point{road_width, road_lenght}
	roundData.GameOver, _ = getAcid(conf, "game_over.txt")

	roundData.BombFactor = 10
	roundData.BonusFactor = 10
	roundData.Speed = 200

	name, err := readName(conf, conn, gameData)
	if err != nil {
		return
	}
	roundData.player.Name = name
	go updateScore(&roundData)
	go updatePosition(conn, &roundData.CarPosition)

	for {
		if !checkPosition(conf, conn, &roundData, gameData) {
			return
		}

		for i := range gameData.Roads {
			data := make([]byte, len(gameData.Roads[i]))
			copy(data, gameData.Roads[i])

			// Moving cursor at the beginning
			_, err := conn.Write(gameData.Clear)
			if err != nil {
				return
			}

			// Checking and updating complexity
			checkComplexity(&roundData)

			// Applying the bonus
			if roundData.bonusPosition.Y < road_lenght {
				data[roundData.bonusPosition.Y*road_width+roundData.bonusPosition.X] = byte('$')
				roundData.bonusPosition.Y++
			} else if rand.Int()%roundData.BonusFactor == 0 {
				roundData.bonusPosition.X, roundData.bonusPosition.Y = rand.Intn(road_width-3)+1, 0
			}

			// Applying the bomb
			if roundData.bombPosition.Y < road_lenght {
				data[roundData.bombPosition.Y*road_width+roundData.bombPosition.X] = byte('X')
				roundData.bombPosition.Y++
			} else if rand.Int()%roundData.BombFactor == 0 {
				roundData.bombPosition.X, roundData.bombPosition.Y = rand.Intn(road_width-3)+1, 0
			}

			// Applying the Car
			for line := 0; line < car_lenght; line++ {
				copy(data[((roundData.CarPosition.Y+line)*road_width+roundData.CarPosition.X):((roundData.CarPosition.Y+line)*road_width+roundData.CarPosition.X)+car_width-1],
					gameData.Car[line*car_width:line*car_width+car_width-1])
			}

			// Applying the score
			scoreStr := fmt.Sprintf("Score: %d", roundData.player.Score)
			for i := range scoreStr {
				data[(road_lenght-1)*road_width+i] = byte(scoreStr[i])
			}
			// Applying the speed
			speedStr := fmt.Sprintf("Speed: %d km/h", speed_factor/roundData.Speed)
			for i := range speedStr {
				data[road_lenght*road_width-len(speedStr)-1+i] = byte(speedStr[i])
			}

			_, err = conn.Write(data)
			if err != nil {
				return
			}
			time.Sleep(time.Duration(roundData.Speed) * time.Millisecond)
		}
	}
}

func main() {
	var logFile string
	conf := &Config{}

	flag.StringVar(&logFile, "l", "/var/log/race.log", "Log file")
	flag.StringVar(&conf.AcidPath, "a", "/Users/leoleovich/go/src/github.com/leoleovich/race/artifacts", "Artifacts location")
	flag.StringVar(&conf.ScorePath, "s", "/Users/leoleovich/go/src/github.com/leoleovich/race/artifacts", "Score location")
	flag.Parse()

	logfile, err := os.OpenFile(logFile, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0600)
	conf.Log = log.New(logfile, "", log.Ldate|log.Lmicroseconds|log.Lshortfile)

	l, err := net.Listen("tcp", ":4242")
	if err != nil {
		conf.Log.Println(err)
		os.Exit(2)
	}
	defer l.Close()

	gameData := GameData{}
	gameData.Roads = generateRoads(3)
	gameData.Car, _ = getAcid(conf, "car.txt")
	gameData.Clear, _ = getAcid(conf, "clear.txt")
	gameData.Splash, _ = getAcid(conf, "splash.txt")
	scoreData, _ := getAcid(conf, "score.json")
	err = json.Unmarshal(scoreData, &gameData.Top)

	for {
		conn, err := l.Accept()
		if err != nil {
			conf.Log.Println("Failed to accept request", err)
		}
		go round(conf, conn, &gameData)
	}
}
<|endoftext|>


<commit_before>// Copyright (c) 2015 Uber Technologies, Inc.

// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

package tchannel

import (
	"math/rand"
	"sync"
)

// lockedSource allows a random number generator to be used by multiple goroutines concurrently.
// The code is very similar to math/rand.lockedSource, which is unfortunately not exposed.
type lockedSource struct {
	mut sync.Mutex
	src rand.Source
}

// NewRand returns a rand.Rand that is threadsafe.
func NewRand(seed int64) *rand.Rand {
	return rand.New(&lockedSource{src: rand.NewSource(seed)})
}

func (r *lockedSource) Int63() (n int64) {
	r.mut.Lock()
	n = r.src.Int63()
	r.mut.Unlock()
	return
}

func (r *lockedSource) Seed(seed int64) {
	r.mut.Lock()
	r.src.Seed(seed)
	r.mut.Unlock()
}
<commit_msg>Embed mutex in lockedSource<commit_after>// Copyright (c) 2015 Uber Technologies, Inc.

// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

package tchannel

import (
	"math/rand"
	"sync"
)

// lockedSource allows a random number generator to be used by multiple goroutines concurrently.
// The code is very similar to math/rand.lockedSource, which is unfortunately not exposed.
type lockedSource struct {
	sync.Mutex

	src rand.Source
}

// NewRand returns a rand.Rand that is threadsafe.
func NewRand(seed int64) *rand.Rand {
	return rand.New(&lockedSource{src: rand.NewSource(seed)})
}

func (r *lockedSource) Int63() (n int64) {
	r.Lock()
	n = r.src.Int63()
	r.Unlock()
	return
}

func (r *lockedSource) Seed(seed int64) {
	r.Lock()
	r.src.Seed(seed)
	r.Unlock()
}
<|endoftext|>


<commit_before>package gorest

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"io/ioutil"
	"net/http"
	"net/url"
	"strings"
	"time"
)

const (
	ContentType     = "Content-Type"
	JsonContentType = "application/json"
	TextContentType = "application/text"
	XmlContentType  = "application/xml"
	timeOutSeconds  = 10
)

type Rest struct {
	httpClient  http.Client
	baseurl     string
	verb        string
	headers     http.Header
	uriparams   []string
	url         string
	queryvalues url.Values
	payload     io.Reader
}

func New() *Rest {
	return &Rest{
		httpClient:  http.Client{Timeout: time.Second * timeOutSeconds},
		headers:     make(map[string][]string),
		queryvalues: make(url.Values),
	}
}

func (client *Rest) WithHeader(key, value string) *Rest {
	client.headers.Add(key, value)
	return client
}

func (client *Rest) Path(param string) *Rest {
	if client.baseurl == "" {
		panic("BASE URL Not Present")
	}
	client.uriparams = append(client.uriparams, param)
	return client
}

func (client *Rest) Base(baseurl string) *Rest {
	v, err := url.Parse(baseurl)
	if err != nil {
		panic("Url is incorrect")
	}
	client.baseurl = v.String()
	return client
}

func (client *Rest) Get() *Rest {
	client.verb = "GET"
	return client
}

func (client *Rest) Post(payload interface{}) *Rest {
	client.verb = "POST"
	if payload != nil {
		client.WithPayload(payload)
	}
	return client
}

func (client *Rest) Put(payload interface{}) *Rest {
	client.verb = "PUT"
	if payload != nil {
		client.WithPayload(payload)
	}
	return client
}

func (client *Rest) Delete(payload interface{}) *Rest {
	client.verb = "DELETE"
	if payload != nil {
		client.WithPayload(payload)
	}
	return client
}

func (client *Rest) Patch(payload interface{}) *Rest {
	client.verb = "PATCH"
	if payload != nil {
		client.WithPayload(payload)
	}
	return client
}

func (client *Rest) Head() *Rest {
	client.verb = "HEAD"
	return client
}

func (client *Rest) Option(payload interface{}) *Rest {
	client.verb = "OPTIONS"
	if payload != nil {
		client.WithPayload(payload)
	}
	return client
}

func (client *Rest) Copy() *Rest {
	client.verb = "COPY"
	return client
}

func (client *Rest) WithPayload(payload interface{}) {
	var b []byte
	b, _ = json.Marshal(payload)
	client.payload = bytes.NewBuffer(b)
}

func (client *Rest) Request(authoptions ...interface{}) (*http.Request, error) {
	//Add all URI params to baseurl
	if !strings.HasSuffix(client.baseurl, "/") {
		client.baseurl = client.baseurl + "/"
	}

	client.url = client.baseurl
	params := strings.Join(client.uriparams, "/")
	client.url = client.baseurl + params
	v, err := url.Parse(client.url)
	if err != nil {
		panic("Complete URL is not correct")
	}

	client.url = v.String()

	//Adding Query String
	var requrl url.URL
	requrl.Path = client.url
	requrl.RawQuery = client.queryvalues.Encode()
	fmt.Println(requrl.String())

	req, err := http.NewRequest(client.verb, requrl.String(), client.payload)
	if err != nil {
		panic("Request Object is not proper")
	}

	//Add headers to the Request
	for key, values := range client.headers {
		for _, value := range values {
			req.Header.Add(key, value)
		}

	}

	for _, opt := range authoptions {
		switch v := opt.(type) {
		case *BasicAuth:
			req.SetBasicAuth(v.Username, v.Password)
		case *OAuth2: //TODO
		}
	}
	return req, err
}

func (client *Rest) Query(options ...interface{}) *Rest {
	if len(options) > 0 {
		qry, ok := options[0].(map[string]string)
		if ok {
			for k, v := range qry {
				client.queryvalues.Set(k, v)
			}
		}
	}
	return client
}

func (client *Rest) Send(req *http.Request) (*http.Response, error) {
	response, err := client.httpClient.Do(req)
	if err != nil {
		panic("Send request Failed")
	}
	return response, err
}

func ResponseBodyString(response *http.Response, st interface{}) string {
	responsedata, _ := ioutil.ReadAll(response.Body)
	return string(responsedata)
}

func ResponseStructure(response *http.Response, responsestruct, errorstruct interface{}) error {
	var err error
	if code := response.StatusCode; 200 <= code && code <= 399 {
		err = json.NewDecoder(response.Body).Decode(responsestruct)
	} else {
		err = json.NewDecoder(response.Body).Decode(errorstruct)
	}
	return err
}
<commit_msg>Form Data<commit_after>package gorest

import (
	"bytes"
	"encoding/json"
	"io"
	"io/ioutil"
	"net/http"
	"net/url"
	"strings"
	"time"
)

const (
	ContentType     = "Content-Type"
	JsonContentType = "application/json"
	TextContentType = "application/text"
	XmlContentType  = "application/xml"
	timeOutSeconds  = 10
)

type Rest struct {
	httpClient  http.Client
	baseurl     string
	verb        string
	headers     http.Header
	uriparams   []string
	url         string
	queryvalues url.Values
	payload     io.Reader
	formdata    url.Values
}

func New() *Rest {
	return &Rest{
		httpClient:  http.Client{Timeout: time.Second * timeOutSeconds},
		headers:     make(map[string][]string),
		queryvalues: make(url.Values),
	}
}

func (client *Rest) WithHeader(key, value string) *Rest {
	client.headers.Add(key, value)
	return client
}

func (client *Rest) Path(param string) *Rest {
	if client.baseurl == "" {
		panic("BASE URL Not Present")
	}
	client.uriparams = append(client.uriparams, param)
	return client
}

func (client *Rest) Base(baseurl string) *Rest {
	v, err := url.Parse(baseurl)
	if err != nil {
		panic("Url is incorrect")
	}
	client.baseurl = v.String()
	return client
}

func (client *Rest) Get() *Rest {
	client.verb = "GET"
	return client
}

func (client *Rest) Post(payload interface{}) *Rest {
	client.verb = "POST"
	if payload != nil {
		client.WithPayload(payload)
	}
	return client
}

func (client *Rest) Put(payload interface{}) *Rest {
	client.verb = "PUT"
	if payload != nil {
		client.WithPayload(payload)
	}
	return client
}

func (client *Rest) Delete(payload interface{}) *Rest {
	client.verb = "DELETE"
	if payload != nil {
		client.WithPayload(payload)
	}
	return client
}

func (client *Rest) Patch(payload interface{}) *Rest {
	client.verb = "PATCH"
	if payload != nil {
		client.WithPayload(payload)
	}
	return client
}

func (client *Rest) Head() *Rest {
	client.verb = "HEAD"
	return client
}

func (client *Rest) Option(payload interface{}) *Rest {
	client.verb = "OPTIONS"
	if payload != nil {
		client.WithPayload(payload)
	}
	return client
}

func (client *Rest) Copy() *Rest {
	client.verb = "COPY"
	return client
}

func (client *Rest) WithFormData(data map[string]string) *Rest {
	form := url.Values{}
	for k, v := range data {
		form.Add(k, v)
	}
	client.formdata = form
	client.WithHeader("Content-Type", "application/x-www-form-urlencoded")
	return client
}

func (client *Rest) WithPayload(payload interface{}) {
	var b []byte
	b, _ = json.Marshal(payload)
	client.payload = bytes.NewBuffer(b)
}

func (client *Rest) Request(authoptions ...interface{}) (*http.Request, error) {
	//Add all URI params to baseurl
	if !strings.HasSuffix(client.baseurl, "/") {
		client.baseurl = client.baseurl + "/"
	}

	client.url = client.baseurl
	params := strings.Join(client.uriparams, "/")
	client.url = client.baseurl + params
	v, err := url.Parse(client.url)
	if err != nil {
		panic("Complete URL is not correct")
	}

	client.url = v.String()

	//Adding Query String
	var requrl url.URL
	requrl.Path = client.url
	requrl.RawQuery = client.queryvalues.Encode()
	var req *http.Request
	if client.formdata != nil {
		req, err = http.NewRequest(client.verb, requrl.String(), strings.NewReader(client.formdata.Encode()))
	} else {
		req, err = http.NewRequest(client.verb, requrl.String(), client.payload)
	}
	if err != nil {
		panic("Request Object is not proper")
	}

	//Add headers to the Request
	for key, values := range client.headers {
		for _, value := range values {
			req.Header.Add(key, value)
		}

	}

	for _, opt := range authoptions {
		switch v := opt.(type) {
		case *BasicAuth:
			req.SetBasicAuth(v.Username, v.Password)
		case *OAuth2: //TODO
		}
	}
	return req, err
}

func (client *Rest) Query(options ...interface{}) *Rest {
	if len(options) > 0 {
		qry, ok := options[0].(map[string]string)
		if ok {
			for k, v := range qry {
				client.queryvalues.Set(k, v)
			}
		}
	}
	return client
}

func (client *Rest) Send(req *http.Request) (*http.Response, error) {
	response, err := client.httpClient.Do(req)
	if err != nil {
		panic("Send request Failed")
	}
	return response, err
}

func ResponseBodyString(response *http.Response, st interface{}) string {
	responsedata, _ := ioutil.ReadAll(response.Body)
	return string(responsedata)
}

func ResponseStructure(response *http.Response, responsestruct, errorstruct interface{}) error {
	var err error
	if code := response.StatusCode; 200 <= code && code <= 399 {
		err = json.NewDecoder(response.Body).Decode(responsestruct)
	} else {
		err = json.NewDecoder(response.Body).Decode(errorstruct)
	}
	return err
}
<|endoftext|>


<commit_before>// A simple Circular Buffer (ring buffer) for bytes in Go.
package ring

import (
	"io"
)

// A Ring buffer containing a ring of bytes
type RingBuffer struct {
	b     []byte
	start int
	end   int
}

// Return true if the ring buffer is full, false otherwise.
func (rb *RingBuffer) IsFull() bool {
	return (rb.end+1)%len(rb.b) == rb.start
}

// Return true if the ring buffer is empty, false otherwise.
func (rb *RingBuffer) IsEmpty() bool {
	return rb.end == rb.start
}

func (rb *RingBuffer) WriteByte(c byte) error {
	rb.b[rb.end] = c
	rb.end = (rb.end + 1) % len(rb.b)
	if rb.end == rb.start {
		rb.start = (rb.start + 1) % len(rb.b)
	}
	return nil
}

func (rb *RingBuffer) ReadByte() (c byte, err error) {
	if rb.IsEmpty() {
		return rb.b[rb.start], io.EOF
	}
	c = rb.b[rb.start]
	rb.start = (rb.start + 1) % len(rb.b)
	return c, nil
}

func (rb *RingBuffer) Read(p []byte) (n int, err error) {
    n = 0
    for var i = 0; i < len(p); i++ {
        b, err := rb.ReadByte()
        if err != nil {
            return
        }
        p[i] = b
        n++
    }
    return
}

// Returns the content of the buffer without changing the next read byte.
func (rb *RingBuffer) ReadAhead() (p []byte, n int, err error) {
    start := rb.start
    p := make([]byte, len(rb.b))
    n, err := rb.Read(p)
    rb.start = start
    return p, n, err
}

func (rb *RingBuffer) Write(p []byte) (n int, err error) {
    for b := range p {
        rb.WriteByte(b)
    }
    return len(p), nil
}

// Create a new RingBuffer of the specified size.
func NewRingBuffer(size int) *RingBuffer {
	rb := new(RingBuffer)
	rb.b = make([]byte, size+1)
    rb.start = 0
    rb.end = 0
	return rb
}
<commit_msg>Fix compilation<commit_after>// A simple Circular Buffer (ring buffer) for bytes in Go.
package ring

import (
	"io"
)

// A Ring buffer containing a ring of bytes
type RingBuffer struct {
	b     []byte
	start int
	end   int
}

// Return true if the ring buffer is full, false otherwise.
func (rb *RingBuffer) IsFull() bool {
	return (rb.end+1)%len(rb.b) == rb.start
}

// Return true if the ring buffer is empty, false otherwise.
func (rb *RingBuffer) IsEmpty() bool {
	return rb.end == rb.start
}

func (rb *RingBuffer) WriteByte(c byte) error {
	rb.b[rb.end] = c
	rb.end = (rb.end + 1) % len(rb.b)
	if rb.end == rb.start {
		rb.start = (rb.start + 1) % len(rb.b)
	}
	return nil
}

func (rb *RingBuffer) ReadByte() (c byte, err error) {
	if rb.IsEmpty() {
		return rb.b[rb.start], io.EOF
	}
	c = rb.b[rb.start]
	rb.start = (rb.start + 1) % len(rb.b)
	return c, nil
}

func (rb *RingBuffer) Read(p []byte) (n int, err error) {
    n = 0
    for i := 0; i < len(p); i++ {
        b, err := rb.ReadByte()
        if err != nil {
            return 0, err
        }
        p[i] = b
        n++
    }
    return
}

// Returns the content of the buffer without changing the next read byte.
func (rb *RingBuffer) ReadAhead() (p []byte, n int, err error) {
    start := rb.start
    p = make([]byte, len(rb.b))
    n, err = rb.Read(p)
    rb.start = start
    return p, n, err
}

func (rb *RingBuffer) Write(p []byte) (n int, err error) {
    for _, b := range p {
        rb.WriteByte(b)
    }
    return len(p), nil
}

// Create a new RingBuffer of the specified size.
func NewRingBuffer(size int) *RingBuffer {
	rb := new(RingBuffer)
	rb.b = make([]byte, size+1)
    rb.start = 0
    rb.end = 0
	return rb
}
<|endoftext|>


<commit_before>package hackyslack

import (
	"fmt"
	"math/rand"
	"regexp"
	"strconv"
	"time"
)

func init() {
	Register("roll", roll)
}

var dice = regexp.MustCompile(`(\d{1,3})d(\d{1,4})`)

func roll(args Args) D {
	rand.Seed(time.Now().UnixNano())
	m := dice.FindStringSubmatch(args.Text)
	num := 2
	sides := 6
	if len(m) > 2 {
		num, _ = strconv.Atoi(m[1])
		sides, _ = strconv.Atoi(m[2])
	}
	if num > 100 {
		num = 100
	}
	if sides < 1 {
		sides = 1
	}
	if sides > 1000 {
		sides = 1000
	}
	total := 0
	rolls := []int{}
	for i := 0; i < num; i++ {
		n := rand.Intn(sides) + 1
		total += n
		rolls = append(rolls, n)
	}

	max := num * sides
	rollText := fmt.Sprint(rolls)
	var color string
	if total > max/2 {
		color = "good"
	} else {
		color = "danger"
	}

	return D{
		"response_type": "in_channel",
		"attachments": []D{
			D{
				"fallback": fmt.Sprint("@", args.UserName, " rolled ", total),
				"text":     fmt.Sprint("@", args.UserName, " rolled *", total, "*"),
				"color":    color,
				"fields": []D{
					D{
						"title": "Dice",
						"value": fmt.Sprint(num, "d", sides),
						"short": true,
					},
					D{
						"title": "Rolls",
						"value": rollText[1 : len(rollText)-1],
						"short": true,
					},
				},
				"mrkdwn_in": []string{"text"},
			},
		},
	}
}
<commit_msg>Add modifier.<commit_after>package hackyslack

import (
	"fmt"
	"math/rand"
	"regexp"
	"strconv"
	"time"
)

func init() {
	Register("roll", roll)
}

var dice = regexp.MustCompile(`(\d{1,3})d(\d{1,4})([+-]\d{1,4})?`)

func roll(args Args) D {
	rand.Seed(time.Now().UnixNano())
	m := dice.FindStringSubmatch(args.Text)
	num := 2
	sides := 6
	if len(m) > 2 {
		num, _ = strconv.Atoi(m[1])
		sides, _ = strconv.Atoi(m[2])
	}
	add := 0
	if len(m) > 3 {
		add, _ = strconv.Atoi(m[3])
	}
	if num > 100 {
		num = 100
	}
	if sides < 1 {
		sides = 1
	}
	if sides > 1000 {
		sides = 1000
	}
	total := 0
	rolls := []int{}
	for i := 0; i < num; i++ {
		n := rand.Intn(sides) + 1
		total += n
		rolls = append(rolls, n)
	}

	max := num * sides
	rollText := fmt.Sprint(rolls)
	var color string
	if total > max/2 {
		color = "good"
	} else {
		color = "danger"
	}
	total += add
	return D{
		"response_type": "in_channel",
		"attachments": []D{
			D{
				"fallback": fmt.Sprint("@", args.UserName, " rolled ", total),
				"text":     fmt.Sprint("@", args.UserName, " rolled *", total, "*"),
				"color":    color,
				"fields": []D{
					D{
						"title": "Dice",
						"value": fmt.Sprint(num, "d", sides),
						"short": true,
					},
					D{
						"title": "Rolls",
						"value": rollText[1 : len(rollText)-1],
						"short": true,
					},
				},
				"mrkdwn_in": []string{"text"},
			},
		},
	}
}
<|endoftext|>


<commit_before>package dnsr

var root = `
;       This file holds the information on root name servers needed to
;       initialize cache of Internet domain name servers
;       (e.g. reference this file in the "cache  .  <file>"
;       configuration file of BIND domain name servers).
;
;       This file is made available by InterNIC
;       under anonymous FTP as
;           file                /domain/named.cache
;           on server           FTP.INTERNIC.NET
;       -OR-                    RS.INTERNIC.NET
;
;       last update:     July 16, 2020
;       related version of root zone:     2020071603
;
; FORMERLY NS.INTERNIC.NET
;
.                        3600000      NS    A.ROOT-SERVERS.NET.
A.ROOT-SERVERS.NET.      3600000      A     198.41.0.4
A.ROOT-SERVERS.NET.      3600000      AAAA  2001:503:ba3e::2:30
;
; FORMERLY NS1.ISI.EDU
;
.                        3600000      NS    B.ROOT-SERVERS.NET.
B.ROOT-SERVERS.NET.      3600000      A     199.9.14.201
B.ROOT-SERVERS.NET.      3600000      AAAA  2001:500:200::b
;
; FORMERLY C.PSI.NET
;
.                        3600000      NS    C.ROOT-SERVERS.NET.
C.ROOT-SERVERS.NET.      3600000      A     192.33.4.12
C.ROOT-SERVERS.NET.      3600000      AAAA  2001:500:2::c
;
; FORMERLY TERP.UMD.EDU
;
.                        3600000      NS    D.ROOT-SERVERS.NET.
D.ROOT-SERVERS.NET.      3600000      A     199.7.91.13
D.ROOT-SERVERS.NET.      3600000      AAAA  2001:500:2d::d
;
; FORMERLY NS.NASA.GOV
;
.                        3600000      NS    E.ROOT-SERVERS.NET.
E.ROOT-SERVERS.NET.      3600000      A     192.203.230.10
E.ROOT-SERVERS.NET.      3600000      AAAA  2001:500:a8::e
;
; FORMERLY NS.ISC.ORG
;
.                        3600000      NS    F.ROOT-SERVERS.NET.
F.ROOT-SERVERS.NET.      3600000      A     192.5.5.241
F.ROOT-SERVERS.NET.      3600000      AAAA  2001:500:2f::f
;
; FORMERLY NS.NIC.DDN.MIL
;
.                        3600000      NS    G.ROOT-SERVERS.NET.
G.ROOT-SERVERS.NET.      3600000      A     192.112.36.4
G.ROOT-SERVERS.NET.      3600000      AAAA  2001:500:12::d0d
;
; FORMERLY AOS.ARL.ARMY.MIL
;
.                        3600000      NS    H.ROOT-SERVERS.NET.
H.ROOT-SERVERS.NET.      3600000      A     198.97.190.53
H.ROOT-SERVERS.NET.      3600000      AAAA  2001:500:1::53
;
; FORMERLY NIC.NORDU.NET
;
.                        3600000      NS    I.ROOT-SERVERS.NET.
I.ROOT-SERVERS.NET.      3600000      A     192.36.148.17
I.ROOT-SERVERS.NET.      3600000      AAAA  2001:7fe::53
;
; OPERATED BY VERISIGN, INC.
;
.                        3600000      NS    J.ROOT-SERVERS.NET.
J.ROOT-SERVERS.NET.      3600000      A     192.58.128.30
J.ROOT-SERVERS.NET.      3600000      AAAA  2001:503:c27::2:30
;
; OPERATED BY RIPE NCC
;
.                        3600000      NS    K.ROOT-SERVERS.NET.
K.ROOT-SERVERS.NET.      3600000      A     193.0.14.129
K.ROOT-SERVERS.NET.      3600000      AAAA  2001:7fd::1
;
; OPERATED BY ICANN
;
.                        3600000      NS    L.ROOT-SERVERS.NET.
L.ROOT-SERVERS.NET.      3600000      A     199.7.83.42
L.ROOT-SERVERS.NET.      3600000      AAAA  2001:500:9f::42
;
; OPERATED BY WIDE
;
.                        3600000      NS    M.ROOT-SERVERS.NET.
M.ROOT-SERVERS.NET.      3600000      A     202.12.27.33
M.ROOT-SERVERS.NET.      3600000      AAAA  2001:dc3::35
; End of file`
<commit_msg>auto-update<commit_after>package dnsr

var root = `
;       This file holds the information on root name servers needed to
;       initialize cache of Internet domain name servers
;       (e.g. reference this file in the "cache  .  <file>"
;       configuration file of BIND domain name servers).
;
;       This file is made available by InterNIC
;       under anonymous FTP as
;           file                /domain/named.cache
;           on server           FTP.INTERNIC.NET
;       -OR-                    RS.INTERNIC.NET
;
;       last update:     August 12, 2020
;       related version of root zone:     2020081201
;
; FORMERLY NS.INTERNIC.NET
;
.                        3600000      NS    A.ROOT-SERVERS.NET.
A.ROOT-SERVERS.NET.      3600000      A     198.41.0.4
A.ROOT-SERVERS.NET.      3600000      AAAA  2001:503:ba3e::2:30
;
; FORMERLY NS1.ISI.EDU
;
.                        3600000      NS    B.ROOT-SERVERS.NET.
B.ROOT-SERVERS.NET.      3600000      A     199.9.14.201
B.ROOT-SERVERS.NET.      3600000      AAAA  2001:500:200::b
;
; FORMERLY C.PSI.NET
;
.                        3600000      NS    C.ROOT-SERVERS.NET.
C.ROOT-SERVERS.NET.      3600000      A     192.33.4.12
C.ROOT-SERVERS.NET.      3600000      AAAA  2001:500:2::c
;
; FORMERLY TERP.UMD.EDU
;
.                        3600000      NS    D.ROOT-SERVERS.NET.
D.ROOT-SERVERS.NET.      3600000      A     199.7.91.13
D.ROOT-SERVERS.NET.      3600000      AAAA  2001:500:2d::d
;
; FORMERLY NS.NASA.GOV
;
.                        3600000      NS    E.ROOT-SERVERS.NET.
E.ROOT-SERVERS.NET.      3600000      A     192.203.230.10
E.ROOT-SERVERS.NET.      3600000      AAAA  2001:500:a8::e
;
; FORMERLY NS.ISC.ORG
;
.                        3600000      NS    F.ROOT-SERVERS.NET.
F.ROOT-SERVERS.NET.      3600000      A     192.5.5.241
F.ROOT-SERVERS.NET.      3600000      AAAA  2001:500:2f::f
;
; FORMERLY NS.NIC.DDN.MIL
;
.                        3600000      NS    G.ROOT-SERVERS.NET.
G.ROOT-SERVERS.NET.      3600000      A     192.112.36.4
G.ROOT-SERVERS.NET.      3600000      AAAA  2001:500:12::d0d
;
; FORMERLY AOS.ARL.ARMY.MIL
;
.                        3600000      NS    H.ROOT-SERVERS.NET.
H.ROOT-SERVERS.NET.      3600000      A     198.97.190.53
H.ROOT-SERVERS.NET.      3600000      AAAA  2001:500:1::53
;
; FORMERLY NIC.NORDU.NET
;
.                        3600000      NS    I.ROOT-SERVERS.NET.
I.ROOT-SERVERS.NET.      3600000      A     192.36.148.17
I.ROOT-SERVERS.NET.      3600000      AAAA  2001:7fe::53
;
; OPERATED BY VERISIGN, INC.
;
.                        3600000      NS    J.ROOT-SERVERS.NET.
J.ROOT-SERVERS.NET.      3600000      A     192.58.128.30
J.ROOT-SERVERS.NET.      3600000      AAAA  2001:503:c27::2:30
;
; OPERATED BY RIPE NCC
;
.                        3600000      NS    K.ROOT-SERVERS.NET.
K.ROOT-SERVERS.NET.      3600000      A     193.0.14.129
K.ROOT-SERVERS.NET.      3600000      AAAA  2001:7fd::1
;
; OPERATED BY ICANN
;
.                        3600000      NS    L.ROOT-SERVERS.NET.
L.ROOT-SERVERS.NET.      3600000      A     199.7.83.42
L.ROOT-SERVERS.NET.      3600000      AAAA  2001:500:9f::42
;
; OPERATED BY WIDE
;
.                        3600000      NS    M.ROOT-SERVERS.NET.
M.ROOT-SERVERS.NET.      3600000      A     202.12.27.33
M.ROOT-SERVERS.NET.      3600000      AAAA  2001:dc3::35
; End of file`
<|endoftext|>


<commit_before>package cmd

import (
	"fmt"
	"net/http"
	"os"

	"github.com/auth0/go-jwt-middleware"
	"github.com/dgrijalva/jwt-go"
	"github.com/gorilla/mux"
	// postgres driver for migrate
	_ "github.com/mattes/migrate/driver/postgres"
	"github.com/nuveo/prest/config"
	"github.com/nuveo/prest/controllers"
	"github.com/spf13/cobra"
	"github.com/urfave/negroni"
)

var cfgFile string
var prestConfig config.Prest

// RootCmd represents the base command when called without any subcommands
var RootCmd = &cobra.Command{
	Use:   "prest",
	Short: "Serve a RESTful API from any PostgreSQL database",
	Long:  `Serve a RESTful API from any PostgreSQL database, start HTTP server`,
	Run: func(cmd *cobra.Command, args []string) {
		app()
	},
}

// Execute adds all child commands to the root command sets flags appropriately.
// This is called by main.main(). It only needs to happen once to the rootCmd.
func Execute() {
	if err := RootCmd.Execute(); err != nil {
		fmt.Println(err)
		os.Exit(-1)
	}
}

func init() {
	config.InitConf()
}

func app() {
	cfg := config.Prest{}
	config.Parse(&cfg)

	n := negroni.Classic()
	n.Use(negroni.HandlerFunc(handlerSet))
	if cfg.JWTKey != "" {
		n.Use(jwtMiddleware(cfg.JWTKey))
	}
	r := mux.NewRouter()
	r.HandleFunc("/databases", controllers.GetDatabases).Methods("GET")
	r.HandleFunc("/schemas", controllers.GetSchemas).Methods("GET")
	r.HandleFunc("/tables", controllers.GetTables).Methods("GET")
	r.HandleFunc("/{database}/{schema}", controllers.GetTablesByDatabaseAndSchema).Methods("GET")
	r.HandleFunc("/{database}/{schema}/{table}", controllers.SelectFromTables).Methods("GET")
	r.HandleFunc("/{database}/{schema}/{table}", controllers.InsertInTables).Methods("POST")
	r.HandleFunc("/{database}/{schema}/{table}", controllers.DeleteFromTable).Methods("DELETE")
	r.HandleFunc("/{database}/{schema}/{table}", controllers.UpdateTable).Methods("PUT", "PATCH")
	r.HandleFunc("/_VIEW/{database}/{schema}/{view}", controllers.SelectFromViews).Methods("GET")

	n.UseHandler(r)
	n.Run(fmt.Sprintf(":%v", cfg.HTTPPort))
}

func handlerSet(w http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
	w.Header().Set("Content-Type", "application/json")
	next(w, r)
}

func jwtMiddleware(key string) negroni.Handler {
	jwtMiddleware := jwtmiddleware.New(jwtmiddleware.Options{
		ValidationKeyGetter: func(token *jwt.Token) (interface{}, error) {
			return []byte(key), nil
		},
		SigningMethod: jwt.SigningMethodHS256,
	})
	return negroni.HandlerFunc(jwtMiddleware.HandlerWithNext)
}
<commit_msg>[WIP] Change Access Control verification (#80)<commit_after>package cmd

import (
	"fmt"
	"os"

	"github.com/gorilla/mux"
	// postgres driver for migrate
	_ "github.com/mattes/migrate/driver/postgres"
	"github.com/nuveo/prest/config"
	"github.com/nuveo/prest/controllers"
	"github.com/nuveo/prest/middlewares"
	"github.com/spf13/cobra"
	"github.com/urfave/negroni"
)

var cfgFile string
var prestConfig config.Prest

// RootCmd represents the base command when called without any subcommands
var RootCmd = &cobra.Command{
	Use:   "prest",
	Short: "Serve a RESTful API from any PostgreSQL database",
	Long:  `Serve a RESTful API from any PostgreSQL database, start HTTP server`,
	Run: func(cmd *cobra.Command, args []string) {
		app()
	},
}

// Execute adds all child commands to the root command sets flags appropriately.
// This is called by main.main(). It only needs to happen once to the rootCmd.
func Execute() {
	if err := RootCmd.Execute(); err != nil {
		fmt.Println(err)
		os.Exit(-1)
	}
}

func init() {
	config.InitConf()
}

func app() {
	cfg := config.Prest{}
	config.Parse(&cfg)

	n := negroni.Classic()
	n.Use(negroni.HandlerFunc(middlewares.HandlerSet))
	n.Use(negroni.HandlerFunc(middlewares.AccessControl))
	if cfg.JWTKey != "" {
		n.Use(middlewares.JwtMiddleware(cfg.JWTKey))
	}
	r := mux.NewRouter()
	r.HandleFunc("/databases", controllers.GetDatabases).Methods("GET")
	r.HandleFunc("/schemas", controllers.GetSchemas).Methods("GET")
	r.HandleFunc("/tables", controllers.GetTables).Methods("GET")
	r.HandleFunc("/{database}/{schema}", controllers.GetTablesByDatabaseAndSchema).Methods("GET")
	r.HandleFunc("/{database}/{schema}/{table}", controllers.SelectFromTables).Methods("GET")
	r.HandleFunc("/{database}/{schema}/{table}", controllers.InsertInTables).Methods("POST")
	r.HandleFunc("/{database}/{schema}/{table}", controllers.DeleteFromTable).Methods("DELETE")
	r.HandleFunc("/{database}/{schema}/{table}", controllers.UpdateTable).Methods("PUT", "PATCH")
	r.HandleFunc("/_VIEW/{database}/{schema}/{view}", controllers.SelectFromViews).Methods("GET")

	n.UseHandler(r)
	n.Run(fmt.Sprintf(":%v", cfg.HTTPPort))
}
<|endoftext|>


<commit_before>package dnsr

var root = `
;       This file holds the information on root name servers needed to
;       initialize cache of Internet domain name servers
;       (e.g. reference this file in the "cache  .  <file>"
;       configuration file of BIND domain name servers).
;
;       This file is made available by InterNIC
;       under anonymous FTP as
;           file                /domain/named.cache
;           on server           FTP.INTERNIC.NET
;       -OR-                    RS.INTERNIC.NET
;
;       last update:     January 31, 2022
;       related version of root zone:     2022013101
;
; FORMERLY NS.INTERNIC.NET
;
.                        3600000      NS    A.ROOT-SERVERS.NET.
A.ROOT-SERVERS.NET.      3600000      A     198.41.0.4
A.ROOT-SERVERS.NET.      3600000      AAAA  2001:503:ba3e::2:30
;
; FORMERLY NS1.ISI.EDU
;
.                        3600000      NS    B.ROOT-SERVERS.NET.
B.ROOT-SERVERS.NET.      3600000      A     199.9.14.201
B.ROOT-SERVERS.NET.      3600000      AAAA  2001:500:200::b
;
; FORMERLY C.PSI.NET
;
.                        3600000      NS    C.ROOT-SERVERS.NET.
C.ROOT-SERVERS.NET.      3600000      A     192.33.4.12
C.ROOT-SERVERS.NET.      3600000      AAAA  2001:500:2::c
;
; FORMERLY TERP.UMD.EDU
;
.                        3600000      NS    D.ROOT-SERVERS.NET.
D.ROOT-SERVERS.NET.      3600000      A     199.7.91.13
D.ROOT-SERVERS.NET.      3600000      AAAA  2001:500:2d::d
;
; FORMERLY NS.NASA.GOV
;
.                        3600000      NS    E.ROOT-SERVERS.NET.
E.ROOT-SERVERS.NET.      3600000      A     192.203.230.10
E.ROOT-SERVERS.NET.      3600000      AAAA  2001:500:a8::e
;
; FORMERLY NS.ISC.ORG
;
.                        3600000      NS    F.ROOT-SERVERS.NET.
F.ROOT-SERVERS.NET.      3600000      A     192.5.5.241
F.ROOT-SERVERS.NET.      3600000      AAAA  2001:500:2f::f
;
; FORMERLY NS.NIC.DDN.MIL
;
.                        3600000      NS    G.ROOT-SERVERS.NET.
G.ROOT-SERVERS.NET.      3600000      A     192.112.36.4
G.ROOT-SERVERS.NET.      3600000      AAAA  2001:500:12::d0d
;
; FORMERLY AOS.ARL.ARMY.MIL
;
.                        3600000      NS    H.ROOT-SERVERS.NET.
H.ROOT-SERVERS.NET.      3600000      A     198.97.190.53
H.ROOT-SERVERS.NET.      3600000      AAAA  2001:500:1::53
;
; FORMERLY NIC.NORDU.NET
;
.                        3600000      NS    I.ROOT-SERVERS.NET.
I.ROOT-SERVERS.NET.      3600000      A     192.36.148.17
I.ROOT-SERVERS.NET.      3600000      AAAA  2001:7fe::53
;
; OPERATED BY VERISIGN, INC.
;
.                        3600000      NS    J.ROOT-SERVERS.NET.
J.ROOT-SERVERS.NET.      3600000      A     192.58.128.30
J.ROOT-SERVERS.NET.      3600000      AAAA  2001:503:c27::2:30
;
; OPERATED BY RIPE NCC
;
.                        3600000      NS    K.ROOT-SERVERS.NET.
K.ROOT-SERVERS.NET.      3600000      A     193.0.14.129
K.ROOT-SERVERS.NET.      3600000      AAAA  2001:7fd::1
;
; OPERATED BY ICANN
;
.                        3600000      NS    L.ROOT-SERVERS.NET.
L.ROOT-SERVERS.NET.      3600000      A     199.7.83.42
L.ROOT-SERVERS.NET.      3600000      AAAA  2001:500:9f::42
;
; OPERATED BY WIDE
;
.                        3600000      NS    M.ROOT-SERVERS.NET.
M.ROOT-SERVERS.NET.      3600000      A     202.12.27.33
M.ROOT-SERVERS.NET.      3600000      AAAA  2001:dc3::35
; End of file`
<commit_msg>Automatic update for Thu Feb 17 08:20:04 UTC 2022<commit_after>package dnsr

var root = `
;       This file holds the information on root name servers needed to
;       initialize cache of Internet domain name servers
;       (e.g. reference this file in the "cache  .  <file>"
;       configuration file of BIND domain name servers).
;
;       This file is made available by InterNIC
;       under anonymous FTP as
;           file                /domain/named.cache
;           on server           FTP.INTERNIC.NET
;       -OR-                    RS.INTERNIC.NET
;
;       last update:     February 16, 2022
;       related version of root zone:     2022021601
;
; FORMERLY NS.INTERNIC.NET
;
.                        3600000      NS    A.ROOT-SERVERS.NET.
A.ROOT-SERVERS.NET.      3600000      A     198.41.0.4
A.ROOT-SERVERS.NET.      3600000      AAAA  2001:503:ba3e::2:30
;
; FORMERLY NS1.ISI.EDU
;
.                        3600000      NS    B.ROOT-SERVERS.NET.
B.ROOT-SERVERS.NET.      3600000      A     199.9.14.201
B.ROOT-SERVERS.NET.      3600000      AAAA  2001:500:200::b
;
; FORMERLY C.PSI.NET
;
.                        3600000      NS    C.ROOT-SERVERS.NET.
C.ROOT-SERVERS.NET.      3600000      A     192.33.4.12
C.ROOT-SERVERS.NET.      3600000      AAAA  2001:500:2::c
;
; FORMERLY TERP.UMD.EDU
;
.                        3600000      NS    D.ROOT-SERVERS.NET.
D.ROOT-SERVERS.NET.      3600000      A     199.7.91.13
D.ROOT-SERVERS.NET.      3600000      AAAA  2001:500:2d::d
;
; FORMERLY NS.NASA.GOV
;
.                        3600000      NS    E.ROOT-SERVERS.NET.
E.ROOT-SERVERS.NET.      3600000      A     192.203.230.10
E.ROOT-SERVERS.NET.      3600000      AAAA  2001:500:a8::e
;
; FORMERLY NS.ISC.ORG
;
.                        3600000      NS    F.ROOT-SERVERS.NET.
F.ROOT-SERVERS.NET.      3600000      A     192.5.5.241
F.ROOT-SERVERS.NET.      3600000      AAAA  2001:500:2f::f
;
; FORMERLY NS.NIC.DDN.MIL
;
.                        3600000      NS    G.ROOT-SERVERS.NET.
G.ROOT-SERVERS.NET.      3600000      A     192.112.36.4
G.ROOT-SERVERS.NET.      3600000      AAAA  2001:500:12::d0d
;
; FORMERLY AOS.ARL.ARMY.MIL
;
.                        3600000      NS    H.ROOT-SERVERS.NET.
H.ROOT-SERVERS.NET.      3600000      A     198.97.190.53
H.ROOT-SERVERS.NET.      3600000      AAAA  2001:500:1::53
;
; FORMERLY NIC.NORDU.NET
;
.                        3600000      NS    I.ROOT-SERVERS.NET.
I.ROOT-SERVERS.NET.      3600000      A     192.36.148.17
I.ROOT-SERVERS.NET.      3600000      AAAA  2001:7fe::53
;
; OPERATED BY VERISIGN, INC.
;
.                        3600000      NS    J.ROOT-SERVERS.NET.
J.ROOT-SERVERS.NET.      3600000      A     192.58.128.30
J.ROOT-SERVERS.NET.      3600000      AAAA  2001:503:c27::2:30
;
; OPERATED BY RIPE NCC
;
.                        3600000      NS    K.ROOT-SERVERS.NET.
K.ROOT-SERVERS.NET.      3600000      A     193.0.14.129
K.ROOT-SERVERS.NET.      3600000      AAAA  2001:7fd::1
;
; OPERATED BY ICANN
;
.                        3600000      NS    L.ROOT-SERVERS.NET.
L.ROOT-SERVERS.NET.      3600000      A     199.7.83.42
L.ROOT-SERVERS.NET.      3600000      AAAA  2001:500:9f::42
;
; OPERATED BY WIDE
;
.                        3600000      NS    M.ROOT-SERVERS.NET.
M.ROOT-SERVERS.NET.      3600000      A     202.12.27.33
M.ROOT-SERVERS.NET.      3600000      AAAA  2001:dc3::35
; End of file`
<|endoftext|>


<commit_before>// (C)Tylor Arndt 2014, Mozilla Public License (MPL) Version 2.0
// See LICENSE file for details.
// For other licensing options please contact the author.

package sema

import (
	"time"
)

//A binary semaphore supports an operation to gain and release control of
// exclusive execution used to protect one or more critical sections.
//The orginal terminology P (aka. signal/acquire) and V (aka. wait/release)
// are used given by they Semaphore inventor Edsger Dijkstra in 1965.
type Semaphore interface {
	P() bool
	V() bool
}

//A CountingSema is a semaphores which allows an arbitrary resource count.
// Wait/Signal are used for the mult-P / multi-V operations.
type CountingSema interface {
	Semaphore
	Wait(units uint) bool
	Signal(units uint) bool
}

//A TimeoutCountingSema further extends a semaphore to provide the ability to
// timeout while waiting to gain access to a critical section.
type TimeoutCountingSema interface {
	CountingSema
	PTO(timeout time.Duration) bool
	VTO(timeout time.Duration) bool
	WaitTO(units uint, timeout time.Duration) bool
	SignalTO(units uint, timeout time.Duration) bool
}

/* Provided default implementations based on benchmarking:
BenchmarkP_condSema	      100000000  18.6 ns/op  0 B/op  0 allocs/op
BenchmarkP_chanSema	      100000000  22.3 ns/op  0 B/op	 0 allocs/op
BenchmarkV_condSema	      100000000  18.5 ns/op  0 B/op	 0 allocs/op
BenchmarkV_chanSema	      100000000  22.8 ns/op  0 B/op	 0 allocs/op
BenchmarkWake_condSema	      100000000  18.4 ns/op  0 B/op	 0 allocs/op
BenchmarkWake_chanSema	      100000000  23.1 ns/op  0 B/op	 0 allocs/op
BenchmarkWakeTimeout_condSema 100000000  25.9 ns/op  0 B/op	 0 allocs/op
BenchmarkWakeTimeout_chanSema  50000000   36.1 ns/op  0 B/op	 0 allocs/op */
var (
	NewSemaphore    = NewCondSema
	NewCountingSema = NewCondSemaCount
	NewTimeoutSema  = NewCondSemaTimeout
)

//UseChannelBasedImpl sets the default exported Semaphore variant
// implementations to be channel based
func UseChannelBasedImpl() {
	NewSemaphore = NewChanSema
	NewCountingSema = NewChanSemaCount
	NewTimeoutSema = NewChanSemaTimeout
}

//UseChannelBasedImpl sets the default exported Semaphore variant
// implementations to be channel based
func UseConditionBasedImpl() {
	NewSemaphore = NewCondSema
	NewCountingSema = NewCondSemaCount
	NewTimeoutSema = NewCondSemaTimeout
}
<commit_msg>Update sema.go<commit_after>// (C)Tylor Arndt 2014, Mozilla Public License (MPL) Version 2.0
// See LICENSE file for details.
// For other licensing options please contact the author.

package sema

import (
	"time"
)

//A binary semaphore supports an operation to gain and release control of
// exclusive execution used to protect one or more critical sections.
//The orginal terminology P (aka. signal/acquire) and V (aka. wait/release)
// are used given by they Semaphore inventor Edsger Dijkstra in 1965.
type Semaphore interface {
	P() bool
	V() bool
}

//A CountingSema is a semaphores which allows an arbitrary resource count.
// Wait/Signal are used for the mult-P / multi-V operations.
type CountingSema interface {
	Semaphore
	Wait(units uint) bool
	Signal(units uint) bool
}

//A TimeoutCountingSema further extends a semaphore to provide the ability to
// timeout while waiting to gain access to a critical section.
type TimeoutCountingSema interface {
	CountingSema
	PTO(timeout time.Duration) bool
	VTO(timeout time.Duration) bool
	WaitTO(units uint, timeout time.Duration) bool
	SignalTO(units uint, timeout time.Duration) bool
}

/* Provided default implementations based on benchmarking:
BenchmarkP_condSema	      100000000  18.6 ns/op  0 B/op  0 allocs/op
BenchmarkP_chanSema	      100000000  22.3 ns/op  0 B/op	 0 allocs/op
BenchmarkV_condSema	      100000000  18.5 ns/op  0 B/op	 0 allocs/op
BenchmarkV_chanSema	      100000000  22.8 ns/op  0 B/op	 0 allocs/op
BenchmarkWake_condSema	      100000000  18.4 ns/op  0 B/op	 0 allocs/op
BenchmarkWake_chanSema	      100000000  23.1 ns/op  0 B/op	 0 allocs/op
BenchmarkWakeTimeout_condSema 100000000  25.9 ns/op  0 B/op	 0 allocs/op
BenchmarkWakeTimeout_chanSema  50000000  36.1 ns/op  0 B/op	 0 allocs/op */
var (
	NewSemaphore    = NewCondSema
	NewCountingSema = NewCondSemaCount
	NewTimeoutSema  = NewCondSemaTimeout
)

//UseChannelBasedImpl sets the default exported Semaphore variant
// implementations to be channel based
func UseChannelBasedImpl() {
	NewSemaphore = NewChanSema
	NewCountingSema = NewChanSemaCount
	NewTimeoutSema = NewChanSemaTimeout
}

//UseChannelBasedImpl sets the default exported Semaphore variant
// implementations to be channel based
func UseConditionBasedImpl() {
	NewSemaphore = NewCondSema
	NewCountingSema = NewCondSemaCount
	NewTimeoutSema = NewCondSemaTimeout
}
<|endoftext|>