<commit_before>package main

import (
	"fmt"
	"github.com/minaguib/berlingo"
	"math/rand"
)

/*
This example mimicks the functionality in the berlin-ai demo ruby gem at:
https://github.com/thirdside/berlin-ai/
*/

type AI1 struct{}

func (ai *AI1) GameStart(game *berlingo.Game) {
}

func (ai *AI1) Turn(game *berlingo.Game) {
	for _, node := range game.Map.ControlledNodes() {
		for _, other_node := range node.Paths_Outbound {
			soldiers := rand.Intn(node.Available_Soldiers)
			fmt.Println("Moving", soldiers, "soldiers from node", node.Id, "to node", other_node.Id)
			if err := game.AddMove(node, other_node, soldiers); err != nil {
				fmt.Println("Error moving:", err)
			}
		}
	}
}

func (ai *AI1) GameOver(game *berlingo.Game) {
}

func (ai *AI1) Ping(game *berlingo.Game) {
}
<commit_msg>Fix occasional crash due to calling rand.Intn(0)<commit_after>package main

import (
	"fmt"
	"github.com/minaguib/berlingo"
	"math/rand"
)

/*
This example mimicks the functionality in the berlin-ai demo ruby gem at:
https://github.com/thirdside/berlin-ai/
*/

type AI1 struct{}

func (ai *AI1) GameStart(game *berlingo.Game) {
}

func (ai *AI1) Turn(game *berlingo.Game) {
	for _, node := range game.Map.ControlledNodes() {
		for _, other_node := range node.Paths_Outbound {
			if node.Available_Soldiers < 1 {
				continue
			}
			soldiers := rand.Intn(node.Available_Soldiers)
			fmt.Println("Moving", soldiers, "soldiers from node", node.Id, "to node", other_node.Id)
			if err := game.AddMove(node, other_node, soldiers); err != nil {
				fmt.Println("Error moving:", err)
			}
		}
	}
}

func (ai *AI1) GameOver(game *berlingo.Game) {
}

func (ai *AI1) Ping(game *berlingo.Game) {
}
<|endoftext|>


<commit_before>// Copyright 2017 The StudyGolang Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// http://studygolang.com
// Author: polaris	polaris@studygolang.com

package controller

import (
	"fmt"
	"net/http"
	"regexp"
	"strings"
	"time"

	"github.com/studygolang/studygolang/context"
	"github.com/studygolang/studygolang/logic"
	"github.com/studygolang/studygolang/model"

	echo "github.com/labstack/echo/v4"
	"github.com/polaris1119/config"
)

const GoStoragePrefix = "https://dl.google.com/go/"

type DownloadController struct{}

// 注册路由
func (self DownloadController) RegisterRoute(g *echo.Group) {
	g.GET("/dl", self.GoDl)
	g.GET("/dl/golang/:filename", self.FetchGoInstallPackage)
	g.GET("/dl/add_new_version", self.AddNewDownload)
}

// GoDl Go 语言安装包下载
func (DownloadController) GoDl(ctx echo.Context) error {
	downloads := logic.DefaultDownload.FindAll(context.EchoContext(ctx))

	featured := make([]*model.Download, 0, 4)
	stables := make(map[string][]*model.Download)
	stableVersions := make([]string, 0, 2)
	unstables := make(map[string][]*model.Download)
	archiveds := make(map[string][]*model.Download)
	archivedVersions := make([]string, 0, 20)

	for _, download := range downloads {
		version := download.Version
		if download.Category == model.DLStable {
			if _, ok := stables[version]; !ok {
				stableVersions = append(stableVersions, version)
				stables[version] = make([]*model.Download, 0, 15)
			}
			stables[version] = append(stables[version], download)

			if download.IsRecommend && len(featured) < 4 {
				featured = append(featured, download)
			}
		} else if download.Category == model.DLUnstable {
			if _, ok := unstables[version]; !ok {
				unstables[version] = make([]*model.Download, 0, 15)
			}
			unstables[version] = append(unstables[version], download)
		} else if download.Category == model.DLArchived {
			if _, ok := archiveds[version]; !ok {
				archivedVersions = append(archivedVersions, version)
				archiveds[version] = make([]*model.Download, 0, 15)
			}
			archiveds[version] = append(archiveds[version], download)
		}
	}

	data := map[string]interface{}{
		"activeDl":          "active",
		"featured":          featured,
		"stables":           stables,
		"stable_versions":   stableVersions,
		"unstables":         unstables,
		"archiveds":         archiveds,
		"archived_versions": archivedVersions,
	}

	return render(ctx, "download/go.html", data)
}

var filenameReg = regexp.MustCompile(`\d+\.\d[a-z\.]*\d+`)

func (self DownloadController) FetchGoInstallPackage(ctx echo.Context) error {
	filename := ctx.Param("filename")

	go logic.DefaultDownload.RecordDLTimes(context.EchoContext(ctx), filename)

	officalUrl := GoStoragePrefix + filename
	resp, err := self.headWithTimeout(officalUrl)
	if err == nil && resp.StatusCode == http.StatusOK {
		resp.Body.Close()
		return ctx.Redirect(http.StatusSeeOther, officalUrl)
	}
	if err == nil {
		resp.Body.Close()
	}

	goVersion := filenameReg.FindString(filename)
	filePath := fmt.Sprintf("go/%s/%s", goVersion, filename)

	dlUrls := strings.Split(config.ConfigFile.MustValue("download", "dl_urls"), ",")
	for _, dlUrl := range dlUrls {
		dlUrl += filePath
		resp, err = self.headWithTimeout(dlUrl)
		if err == nil && resp.StatusCode == http.StatusOK {
			resp.Body.Close()
			return ctx.Redirect(http.StatusSeeOther, dlUrl)
		}
		if err == nil {
			resp.Body.Close()
		}
	}

	getLogger(ctx).Infoln("download:", filename, "from the site static directory")

	return ctx.Redirect(http.StatusSeeOther, "/static/"+filePath)
}

func (DownloadController) AddNewDownload(ctx echo.Context) error {
	version := ctx.QueryParam("version")
	selector := ctx.QueryParam("selector")

	if version == "" {
		return fail(ctx, 1, "version is empty")
	}

	if selector == "" {
		selector = ".toggleVisible"
	}

	err := logic.DefaultDownload.AddNewDownload(context.EchoContext(ctx), version, selector)
	if err != nil {
		return fail(ctx, 1, err.Error())
	}

	return success(ctx, nil)
}

func (DownloadController) headWithTimeout(dlUrl string) (*http.Response, error) {
	client := http.Client{
		Timeout: 5 * time.Second,
	}

	return client.Head(dlUrl)
}
<commit_msg>修改 download<commit_after>// Copyright 2017 The StudyGolang Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// http://studygolang.com
// Author: polaris	polaris@studygolang.com

package controller

import (
	"fmt"
	"net/http"
	"regexp"
	"strings"
	"time"

	"github.com/studygolang/studygolang/context"
	"github.com/studygolang/studygolang/logic"
	"github.com/studygolang/studygolang/model"

	echo "github.com/labstack/echo/v4"
	"github.com/polaris1119/config"
)

const GoStoragePrefix = "https://golang.google.cn/dl/"

type DownloadController struct{}

// 注册路由
func (self DownloadController) RegisterRoute(g *echo.Group) {
	g.GET("/dl", self.GoDl)
	g.GET("/dl/golang/:filename", self.FetchGoInstallPackage)
	g.GET("/dl/add_new_version", self.AddNewDownload)
}

// GoDl Go 语言安装包下载
func (DownloadController) GoDl(ctx echo.Context) error {
	downloads := logic.DefaultDownload.FindAll(context.EchoContext(ctx))

	featured := make([]*model.Download, 0, 4)
	stables := make(map[string][]*model.Download)
	stableVersions := make([]string, 0, 2)
	unstables := make(map[string][]*model.Download)
	archiveds := make(map[string][]*model.Download)
	archivedVersions := make([]string, 0, 20)

	for _, download := range downloads {
		version := download.Version
		if download.Category == model.DLStable {
			if _, ok := stables[version]; !ok {
				stableVersions = append(stableVersions, version)
				stables[version] = make([]*model.Download, 0, 15)
			}
			stables[version] = append(stables[version], download)

			if download.IsRecommend && len(featured) < 4 {
				featured = append(featured, download)
			}
		} else if download.Category == model.DLUnstable {
			if _, ok := unstables[version]; !ok {
				unstables[version] = make([]*model.Download, 0, 15)
			}
			unstables[version] = append(unstables[version], download)
		} else if download.Category == model.DLArchived {
			if _, ok := archiveds[version]; !ok {
				archivedVersions = append(archivedVersions, version)
				archiveds[version] = make([]*model.Download, 0, 15)
			}
			archiveds[version] = append(archiveds[version], download)
		}
	}

	data := map[string]interface{}{
		"activeDl":          "active",
		"featured":          featured,
		"stables":           stables,
		"stable_versions":   stableVersions,
		"unstables":         unstables,
		"archiveds":         archiveds,
		"archived_versions": archivedVersions,
	}

	return render(ctx, "download/go.html", data)
}

var filenameReg = regexp.MustCompile(`\d+\.\d[a-z\.]*\d+`)

func (self DownloadController) FetchGoInstallPackage(ctx echo.Context) error {
	filename := ctx.Param("filename")

	go logic.DefaultDownload.RecordDLTimes(context.EchoContext(ctx), filename)

	officalUrl := GoStoragePrefix + filename
	resp, err := self.headWithTimeout(officalUrl)
	if err == nil && resp.StatusCode == http.StatusOK {
		resp.Body.Close()
		return ctx.Redirect(http.StatusSeeOther, officalUrl)
	}
	if err == nil {
		resp.Body.Close()
	}

	goVersion := filenameReg.FindString(filename)
	filePath := fmt.Sprintf("go/%s/%s", goVersion, filename)

	dlUrls := strings.Split(config.ConfigFile.MustValue("download", "dl_urls"), ",")
	for _, dlUrl := range dlUrls {
		dlUrl += filePath
		resp, err = self.headWithTimeout(dlUrl)
		if err == nil && resp.StatusCode == http.StatusOK {
			resp.Body.Close()
			return ctx.Redirect(http.StatusSeeOther, dlUrl)
		}
		if err == nil {
			resp.Body.Close()
		}
	}

	getLogger(ctx).Infoln("download:", filename, "from the site static directory")

	return ctx.Redirect(http.StatusSeeOther, "/static/"+filePath)
}

func (DownloadController) AddNewDownload(ctx echo.Context) error {
	version := ctx.QueryParam("version")
	selector := ctx.QueryParam("selector")

	if version == "" {
		return fail(ctx, 1, "version is empty")
	}

	if selector == "" {
		selector = ".toggleVisible"
	}

	err := logic.DefaultDownload.AddNewDownload(context.EchoContext(ctx), version, selector)
	if err != nil {
		return fail(ctx, 1, err.Error())
	}

	return success(ctx, nil)
}

func (DownloadController) headWithTimeout(dlUrl string) (*http.Response, error) {
	client := http.Client{
		Timeout: 5 * time.Second,
	}

	return client.Head(dlUrl)
}
<|endoftext|>


<commit_before>package goboots

import (
	"labix.org/v2/mgo/bson"
	"log"
	"reflect"
	"time"
)

const (
	QueryOpEq                  = "$eq"
	QueryOpLessOrEq            = "$lte"
	QueryOpGreaterOrEq         = "$gte"
	QueryOpLess                = "$lt"
	QueryOpGreater             = "$gt"
	QueryOpNotEqual            = "$ne"
	QueryOpInsideSlice         = "$in"
	QueryOpContainsAllElements = "$all"
	QueryOpNotContainsElements = "$nin"
)

var (
	//typeBinary         = reflect.TypeOf(Binary{})
	//typeObjectId       = reflect.TypeOf(ObjectId(""))
	//typeSymbol         = reflect.TypeOf(Symbol(""))
	//typeMongoTimestamp = reflect.TypeOf(MongoTimestamp(0))
	//typeOrderKey       = reflect.TypeOf(MinKey)
	//typeDocElem        = reflect.TypeOf(DocElem{})
	//typeRaw            = reflect.TypeOf(Raw{})
	//typeURL            = reflect.TypeOf(url.URL{})
	typeTime = reflect.TypeOf(time.Time{})
)

type M2 bson.M

type IModel interface {
	GetId() bson.ObjectId
	GetCollectionName() string
}

type Model struct {
	Id bson.ObjectId `bson:"_id,omitempty"`
}

func (m *Model) GetId() bson.ObjectId {
	return m.Id
}

func (m *Model) SetIdHex(idHex string) error {
	if !bson.IsObjectIdHex(idHex) {
		return &AppError{-1, "ObjectId Hex '" + idHex + "' is not valid!"}
	}
	m.Id = bson.ObjectIdHex(idHex)
	return nil
}

func (m *Model) GenerateId() {
	m.Id = bson.NewObjectId()
}

func (m *Model) RemoveById() {
	log.Println("catson"+reflect.TypeOf(m).Name(), reflect.TypeOf(m))
}

func (m *Model) FindOne(input interface{}, output IModel, omitEmpty bool) error {
	bs, _ := bson.Marshal(input)
	mp := bson.M{}
	bson.Unmarshal(bs, mp)
	if omitEmpty {
		for k, v := range mp {
			vv := reflect.ValueOf(v)
			if isZero(vv) {
				delete(mp, k)
			}
		}
	}
	return DB.C(output.GetCollectionName()).Find(mp).One(output)
}

func (m *Model) Query(input IModel, omitEmpty bool) *M2 {
	bs, _ := bson.Marshal(input)
	mp := M2{}
	bson.Unmarshal(bs, mp)
	if omitEmpty {
		for k, v := range mp {
			vv := reflect.ValueOf(v)
			if isZero(vv) {
				delete(mp, k)
			}
		}
	}
	mp["_8cname9__"] = input.GetCollectionName()
	return &mp
}

func (m *M2) Where(name string, signal string, value interface{}) *M2 {
	mm := *m
	mm[name] = bson.M{signal: value}
	return &mm
}

func (m *M2) One(result IModel) error {
	mm := *m
	cname, _ := mm["_8cname9__"].(string)
	delete(mm, "_8cname9__")
	return DB.C(cname).Find(mm).One(result)
}

func (m *M2) All(result interface{}) error {
	mm := *m
	cname, _ := mm["_8cname9__"].(string)
	delete(mm, "_8cname9__")
	return DB.C(cname).Find(mm).All(result)
}

func isZero(v reflect.Value) bool {
	switch v.Kind() {
	case reflect.String:
		return len(v.String()) == 0
	case reflect.Ptr, reflect.Interface:
		return v.IsNil()
	case reflect.Slice:
		return v.Len() == 0
	case reflect.Map:
		return v.Len() == 0
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
		return v.Int() == 0
	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
		return v.Uint() == 0
	case reflect.Float32, reflect.Float64:
		return v.Float() == 0
	case reflect.Bool:
		return !v.Bool()
	case reflect.Struct:
		if v.Type() == typeTime {
			return v.Interface().(time.Time).IsZero()
		}
	}
	return false
}
<commit_msg>Model bson/json<commit_after>package goboots

import (
	"labix.org/v2/mgo/bson"
	"log"
	"reflect"
	"time"
)

const (
	QueryOpEq                  = "$eq"
	QueryOpLessOrEq            = "$lte"
	QueryOpGreaterOrEq         = "$gte"
	QueryOpLess                = "$lt"
	QueryOpGreater             = "$gt"
	QueryOpNotEqual            = "$ne"
	QueryOpInsideSlice         = "$in"
	QueryOpContainsAllElements = "$all"
	QueryOpNotContainsElements = "$nin"
)

var (
	//typeBinary         = reflect.TypeOf(Binary{})
	//typeObjectId       = reflect.TypeOf(ObjectId(""))
	//typeSymbol         = reflect.TypeOf(Symbol(""))
	//typeMongoTimestamp = reflect.TypeOf(MongoTimestamp(0))
	//typeOrderKey       = reflect.TypeOf(MinKey)
	//typeDocElem        = reflect.TypeOf(DocElem{})
	//typeRaw            = reflect.TypeOf(Raw{})
	//typeURL            = reflect.TypeOf(url.URL{})
	typeTime = reflect.TypeOf(time.Time{})
)

type M2 bson.M

type IModel interface {
	GetId() bson.ObjectId
	GetCollectionName() string
}

type Model struct {
	Id bson.ObjectId `bson:"_id,omitempty" json:"id"`
}

func (m *Model) GetId() bson.ObjectId {
	return m.Id
}

func (m *Model) SetIdHex(idHex string) error {
	if !bson.IsObjectIdHex(idHex) {
		return &AppError{-1, "ObjectId Hex '" + idHex + "' is not valid!"}
	}
	m.Id = bson.ObjectIdHex(idHex)
	return nil
}

func (m *Model) GenerateId() {
	m.Id = bson.NewObjectId()
}

func (m *Model) RemoveById() {
	log.Println("catson"+reflect.TypeOf(m).Name(), reflect.TypeOf(m))
}

func (m *Model) FindOne(input interface{}, output IModel, omitEmpty bool) error {
	bs, _ := bson.Marshal(input)
	mp := bson.M{}
	bson.Unmarshal(bs, mp)
	if omitEmpty {
		for k, v := range mp {
			vv := reflect.ValueOf(v)
			if isZero(vv) {
				delete(mp, k)
			}
		}
	}
	return DB.C(output.GetCollectionName()).Find(mp).One(output)
}

func (m *Model) Query(input IModel, omitEmpty bool) *M2 {
	bs, _ := bson.Marshal(input)
	mp := M2{}
	bson.Unmarshal(bs, mp)
	if omitEmpty {
		for k, v := range mp {
			vv := reflect.ValueOf(v)
			if isZero(vv) {
				delete(mp, k)
			}
		}
	}
	mp["_8cname9__"] = input.GetCollectionName()
	return &mp
}

func (m *M2) Where(name string, signal string, value interface{}) *M2 {
	mm := *m
	mm[name] = bson.M{signal: value}
	return &mm
}

func (m *M2) One(result IModel) error {
	mm := *m
	cname, _ := mm["_8cname9__"].(string)
	delete(mm, "_8cname9__")
	return DB.C(cname).Find(mm).One(result)
}

func (m *M2) All(result interface{}) error {
	mm := *m
	cname, _ := mm["_8cname9__"].(string)
	delete(mm, "_8cname9__")
	return DB.C(cname).Find(mm).All(result)
}

func isZero(v reflect.Value) bool {
	switch v.Kind() {
	case reflect.String:
		return len(v.String()) == 0
	case reflect.Ptr, reflect.Interface:
		return v.IsNil()
	case reflect.Slice:
		return v.Len() == 0
	case reflect.Map:
		return v.Len() == 0
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
		return v.Int() == 0
	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
		return v.Uint() == 0
	case reflect.Float32, reflect.Float64:
		return v.Float() == 0
	case reflect.Bool:
		return !v.Bool()
	case reflect.Struct:
		if v.Type() == typeTime {
			return v.Interface().(time.Time).IsZero()
		}
	}
	return false
}
<|endoftext|>


<commit_before>package parser

import (
	"reflect"
	"testing"

	"github.com/galexrt/srcds_exporter/models"
)

var parseHostnameTests = []struct {
	request  string
	expected string
}{
	{
		`hostname: Example server`,
		"Example server",
	},
	{
		`hostname: [TEST] ÜÄÖÜ server`,
		"[TEST] ÜÄÖÜ server",
	},
}

func TestParseHostname(t *testing.T) {
	for _, tt := range parseHostnameTests {
		actual := parseHostname(tt.request)
		if actual != tt.expected {
			t.Errorf("Parse(%s): expected %s, actual %s", tt.request, tt.expected, actual)
		}
	}
}

var parseVersionTests = []struct {
	request  string
	expected string
}{
	{
		`version : 16.12.01/24 6729 secure`,
		"16.12.01/24 6729 secure",
	},
}

func TestParseVersion(t *testing.T) {
	for _, tt := range parseVersionTests {
		actual := parseVersion(tt.request)
		if actual != tt.expected {
			t.Errorf("Parse(%s): expected %s, actual %s", tt.request, tt.expected, actual)
		}
	}
}

var parseMapTests = []struct {
	request  string
	expected string
}{
	{
		`map     : rp_retribution_v2 at: 0 x, 0 y, 0 z`,
		"rp_retribution_v2",
	},
}

func TestParseMap(t *testing.T) {
	for _, tt := range parseMapTests {
		actual := parseMap(tt.request)
		if actual != tt.expected {
			t.Errorf("Parse(%s): expected %s, actual %s", tt.request, tt.expected, actual)
		}
	}
}

var parsePlayerCountTests = []struct {
	request  string
	expected models.PlayerCount
}{
	{
		`players : 1 (64 max)`,
		*&models.PlayerCount{
			Current: 1,
			Max:     64,
		},
	},
}

func TestParsePlayerCount(t *testing.T) {
	for _, tt := range parsePlayerCountTests {
		actual := *parsePlayerCount(tt.request)
		if !reflect.DeepEqual(actual, tt.expected) {
			t.Errorf("Parse(%s): expected %v, actual %v", tt.request, tt.expected, actual)
		}
	}
}

var parserTests = []struct {
	name     string
	request  string
	expected *models.Status
}{
	{
		"gmod",
		`hostname: Example server
version : 16.12.01/24 6729 secure
udp/ip  : 1.1.1.1:27015  (public ip: 1.1.1.1)
map     : rp_retribution_v2 at: 0 x, 0 y, 0 z
players : 1 (64 max)

# userid name                uniqueid            connected ping loss state  adr
#    218 "TestUser1"      STEAM_0:0:1015738 07:36       65    0 active 10.10.220.12:27005`,
		&models.Status{
			Hostname: "Example server",
			Version:  "16.12.01/24 6729 secure",
			Map:      "rp_retribution_v2",
			PlayerCount: *&models.PlayerCount{
				Max:     64,
				Current: 1,
			},
			Players: map[int]models.Player{
				218: *&models.Player{
					Username: "TestUser1",
					SteamID:  "STEAM_0:0:1015738",
					Ping:     65,
					Loss:     0,
					State:    "active",
					IP:       "10.10.220.12",
					ConnPort: 27005,
				},
			},
		},
	},
}

func TestParser(t *testing.T) {
	for _, tt := range parserTests {
		actual := Parse(tt.request)
		if !reflect.DeepEqual(actual, tt.expected) {
			t.Errorf("Parse(%s): expected %v, actual %v", tt.name, tt.expected, actual)
		}
	}
}
<commit_msg>Added test for parsePlayers<commit_after>package parser

import (
	"reflect"
	"testing"

	"github.com/galexrt/srcds_exporter/models"
)

var parseHostnameTests = []struct {
	request  string
	expected string
}{
	{
		`hostname: Example server`,
		"Example server",
	},
	{
		`hostname: [TEST] ÜÄÖÜ server`,
		"[TEST] ÜÄÖÜ server",
	},
}

func TestParseHostname(t *testing.T) {
	for _, tt := range parseHostnameTests {
		actual := parseHostname(tt.request)
		if actual != tt.expected {
			t.Errorf("parseHostname(%s): expected %s, actual %s", tt.request, tt.expected, actual)
		}
	}
}

var parseVersionTests = []struct {
	request  string
	expected string
}{
	{
		`version : 16.12.01/24 6729 secure`,
		"16.12.01/24 6729 secure",
	},
}

func TestParseVersion(t *testing.T) {
	for _, tt := range parseVersionTests {
		actual := parseVersion(tt.request)
		if actual != tt.expected {
			t.Errorf("parseVersion(%s): expected %s, actual %s", tt.request, tt.expected, actual)
		}
	}
}

var parseMapTests = []struct {
	request  string
	expected string
}{
	{
		`map     : rp_retribution_v2 at: 0 x, 0 y, 0 z`,
		"rp_retribution_v2",
	},
}

func TestParseMap(t *testing.T) {
	for _, tt := range parseMapTests {
		actual := parseMap(tt.request)
		if actual != tt.expected {
			t.Errorf("parseMap(%s): expected %s, actual %s", tt.request, tt.expected, actual)
		}
	}
}

var parsePlayerCountTests = []struct {
	request  string
	expected *models.PlayerCount
}{
	{
		`players : 1 (64 max)`,
		&models.PlayerCount{
			Current: 1,
			Max:     64,
		},
	},
}

func TestParsePlayerCount(t *testing.T) {
	for _, tt := range parsePlayerCountTests {
		actual := parsePlayerCount(tt.request)
		if !reflect.DeepEqual(actual, tt.expected) {
			t.Errorf("parsePlayerCount(%s): expected %v, actual %v", tt.request, tt.expected, actual)
		}
	}
}

var parsePlayersTests = []struct {
	request  string
	expected map[int]models.Player
}{
	{
		`#    218 "TestUser1"      STEAM_0:0:1015738 07:36       65    0 active 10.10.220.12:27005`,
		map[int]models.Player{
			218: *&models.Player{
				Username: "TestUser1",
				SteamID:  "STEAM_0:0:1015738",
				Ping:     65,
				Loss:     0,
				State:    "active",
				IP:       "10.10.220.12",
				ConnPort: 27005,
			},
		},
	},
}

func TestParsePlayers(t *testing.T) {
	for _, tt := range parsePlayersTests {
		actual := parsePlayers([]string{tt.request})
		if !reflect.DeepEqual(actual, tt.expected) {
			t.Errorf("parsePlayers(%s): expected %v, actual %v", tt.request, tt.expected, actual)
		}
	}
}

var parserTests = []struct {
	name     string
	request  string
	expected *models.Status
}{
	{
		"gmod",
		`hostname: Example server
version : 16.12.01/24 6729 secure
udp/ip  : 1.1.1.1:27015  (public ip: 1.1.1.1)
map     : rp_retribution_v2 at: 0 x, 0 y, 0 z
players : 1 (64 max)

# userid name                uniqueid            connected ping loss state  adr
#    218 "TestUser1"      STEAM_0:0:1015738 07:36       65    0 active 10.10.220.12:27005`,
		&models.Status{
			Hostname: "Example server",
			Version:  "16.12.01/24 6729 secure",
			Map:      "rp_retribution_v2",
			PlayerCount: *&models.PlayerCount{
				Max:     64,
				Current: 1,
			},
			Players: map[int]models.Player{
				218: *&models.Player{
					Username: "TestUser1",
					SteamID:  "STEAM_0:0:1015738",
					Ping:     65,
					Loss:     0,
					State:    "active",
					IP:       "10.10.220.12",
					ConnPort: 27005,
				},
			},
		},
	},
}

func TestParser(t *testing.T) {
	for _, tt := range parserTests {
		actual := Parse(tt.request)
		if !reflect.DeepEqual(actual, tt.expected) {
			t.Errorf("Parse(%s): expected %v, actual %v", tt.name, tt.expected, actual)
		}
	}
}
<|endoftext|>


<commit_before>// Package persistent contains a wrapper for guac.realtime to enable automatic
// connection retries and reconnection on failure.
package persistent

import (
	"fmt"
	"log"
	"sync"

	"github.com/doozr/guac/realtime"
	"github.com/doozr/guac/web"
	"github.com/doozr/jot"
)

type reconnect struct {
	id          string
	name        string
	client      web.Client
	receiveChan chan []byte
	sendChan    chan asyncEvent
	done        chan struct{}
	wg          *sync.WaitGroup
}

type asyncEvent struct {
	event    []byte
	callback chan error
}

// New connection to the Slack RealTime API.
func New(client web.Client) (conn realtime.Connection) {
	reconn := &reconnect{
		client:      client,
		receiveChan: make(chan []byte),
		sendChan:    make(chan asyncEvent),
		done:        make(chan struct{}),
		wg:          &sync.WaitGroup{},
	}

	reconn.wg.Add(1)
	ready := make(chan struct{})
	go reconn.run(ready)
	<-ready

	conn = reconn
	return
}

// run the persistent listener.
//
// An infinite loop terminated only by closing the `done` channel. Open a
// real time connection and consume from it until it dies, and immediately
// create a new one. Repeat ad infinitum.
//
// Terminate by closing the `c.done` channel and waiting on `c.wg`.
func (c reconnect) run(ready chan struct{}) {
	jot.Print("persistent.run: started")
	defer func() {
		jot.Print("persistent.run: done")
		c.wg.Done()
	}()

	for {
		select {
		case <-c.done:
			return
		default:
		}

		jot.Print("persistent.run: connecting to Slack")
		r, ok := mustConnect(c.client, c.done)
		if ok {
			// If we are connected, set the ID and name
			c.id = r.ID()
			c.name = r.Name()
			log.Print("persistent.run: connected as ", r.Name())

			// Only close ready if it's open
			select {
			case <-ready:
			default:
				jot.Print("persistent.run: initial connection ready")
				close(ready)
			}

			jot.Print("persistent.run: listening for events")
			listen(r, c.receiveChan, c.sendChan, c.done)
		}
	}
}

// ID of the connected bot.
func (c reconnect) ID() string {
	return c.id
}

// Name of the connected bot.
func (c reconnect) Name() string {
	return c.name
}

// Close the persistent connection loop immediately.
func (c reconnect) Close() {
	jot.Print("persistent.wrapper: closing down connections")
	close(c.done)
	c.wg.Wait()

	jot.Print("persistent.wrapper: closing down internal channels")
	close(c.sendChan)
	close(c.receiveChan)
}

// Send an asynchronous event and wait for confirmation.
func (c reconnect) Send(raw []byte) (err error) {
	callback := make(chan error)
	a := asyncEvent{
		event:    raw,
		callback: callback,
	}

	jot.Print("persistent.Send sending async event: ", a)
	c.sendChan <- a

	jot.Print("persistent.Send awaiting callback")
	err = <-callback

	jot.Print("persistent.Send callback received")
	close(callback)
	return err
}

// Receive an incoming event.
func (c reconnect) Receive() (raw []byte, err error) {
	jot.Print("persistent.Receive: awaiting event")
	raw, ok := <-c.receiveChan
	if !ok {
		jot.Print("persistent.Receive: error")
		err = fmt.Errorf("Channel closed")
		return
	}

	jot.Print("persistent.Receive: event ", string(raw))
	return
}
<commit_msg>More useful logging of async sends<commit_after>// Package persistent contains a wrapper for guac.realtime to enable automatic
// connection retries and reconnection on failure.
package persistent

import (
	"fmt"
	"log"
	"sync"

	"github.com/doozr/guac/realtime"
	"github.com/doozr/guac/web"
	"github.com/doozr/jot"
)

type reconnect struct {
	id          string
	name        string
	client      web.Client
	receiveChan chan []byte
	sendChan    chan asyncEvent
	done        chan struct{}
	wg          *sync.WaitGroup
}

type asyncEvent struct {
	event    []byte
	callback chan error
}

// New connection to the Slack RealTime API.
func New(client web.Client) (conn realtime.Connection) {
	reconn := &reconnect{
		client:      client,
		receiveChan: make(chan []byte),
		sendChan:    make(chan asyncEvent),
		done:        make(chan struct{}),
		wg:          &sync.WaitGroup{},
	}

	reconn.wg.Add(1)
	ready := make(chan struct{})
	go reconn.run(ready)
	<-ready

	conn = reconn
	return
}

// run the persistent listener.
//
// An infinite loop terminated only by closing the `done` channel. Open a
// real time connection and consume from it until it dies, and immediately
// create a new one. Repeat ad infinitum.
//
// Terminate by closing the `c.done` channel and waiting on `c.wg`.
func (c reconnect) run(ready chan struct{}) {
	jot.Print("persistent.run: started")
	defer func() {
		jot.Print("persistent.run: done")
		c.wg.Done()
	}()

	for {
		select {
		case <-c.done:
			return
		default:
		}

		jot.Print("persistent.run: connecting to Slack")
		r, ok := mustConnect(c.client, c.done)
		if ok {
			// If we are connected, set the ID and name
			c.id = r.ID()
			c.name = r.Name()
			log.Print("persistent.run: connected as ", r.Name())

			// Only close ready if it's open
			select {
			case <-ready:
			default:
				jot.Print("persistent.run: initial connection ready")
				close(ready)
			}

			jot.Print("persistent.run: listening for events")
			listen(r, c.receiveChan, c.sendChan, c.done)
		}
	}
}

// ID of the connected bot.
func (c reconnect) ID() string {
	return c.id
}

// Name of the connected bot.
func (c reconnect) Name() string {
	return c.name
}

// Close the persistent connection loop immediately.
func (c reconnect) Close() {
	jot.Print("persistent.wrapper: closing down connections")
	close(c.done)
	c.wg.Wait()

	jot.Print("persistent.wrapper: closing down internal channels")
	close(c.sendChan)
	close(c.receiveChan)
}

// Send an asynchronous event and wait for confirmation.
func (c reconnect) Send(raw []byte) (err error) {
	callback := make(chan error)
	a := asyncEvent{
		event:    raw,
		callback: callback,
	}

	jot.Print("persistent.Send sending async event: ", string(raw))
	c.sendChan <- a

	jot.Print("persistent.Send awaiting callback")
	err = <-callback

	jot.Print("persistent.Send callback received")
	close(callback)
	return err
}

// Receive an incoming event.
func (c reconnect) Receive() (raw []byte, err error) {
	jot.Print("persistent.Receive: awaiting event")
	raw, ok := <-c.receiveChan
	if !ok {
		jot.Print("persistent.Receive: error")
		err = fmt.Errorf("Channel closed")
		return
	}

	jot.Print("persistent.Receive: event ", string(raw))
	return
}
<|endoftext|>


<commit_before>// Package messageq provides a reliable pub/sub bus for long term listeners job queuing
package messageq

import (
	"github.com/Rafflecopter/golang-relyq/relyq"
	"github.com/garyburd/redigo/redis"
	"github.com/yanatan16/gowaiter"
	"io"
	"time"
)

// -- Types --

// A message queue object.
type MessageQueue struct {
	Errors      chan error
	pool        *redis.Pool
	cfg         *Config
	prefix      string
	queues      map[string]*queue
	discovery   Discovery
	subscribers *subscribersMemo
}

// Interface for discovery backend's to implement
type Discovery interface {
	// Register an endpoint as listening on a channel
	Register(channel, endpoint string) error
	// Unregister an endpoint as listening on a channel
	Unregister(channel, endpiont string) error
	// List subscribers to a channel
	Subscribers(channel string) ([]string, error)

	io.Closer
}

// A message in MessageQueue must have the Id() function required by tasks in RelyQueue
type Message interface {
	relyq.Ider
}

type RelyQConfig relyq.Config

type Config struct {
	*RelyQConfig

	// Subscribers cache decay duration
	SubscriberListDecay time.Duration
}

// -- Functions and Methods --

func New(pool *redis.Pool, disco Discovery, cfg *Config) *MessageQueue {
	cfg.Defaults()
	mq := &MessageQueue{
		Errors:      make(chan error),
		pool:        pool,
		cfg:         cfg,
		queues:      make(map[string]*queue),
		discovery:   disco,
		subscribers: memoizeSubscriberser(disco, cfg.SubscriberListDecay),
	}

	return mq
}

// Subscribe on a channel. Returns the channel of messages
func (mq *MessageQueue) Subscribe(channel string, example Message) (chan Message, error) {
	name, q := mq.endpoint(channel)
	err := mq.discovery.Register(channel, name)

	return q.Messages(mq.Errors, example), err
}

// Publish a message on a channel
func (mq *MessageQueue) Publish(channel string, message Message) error {
	list, err := mq.subscribers.Subscribers(channel)
	if err != nil {
		return err
	}

	for _, endp := range list {
		if err2 := mq.send(endp, message); err != nil {
			err = err2
		}
	}

	return err
}

// Unsubscribe from a channel
func (mq *MessageQueue) Unsubscribe(channel string) error {
	name := mq.getEndpoint(channel)
	w := waiter.New(2)

	if q, ok := mq.queues[name]; ok {
		delete(mq.queues, name)

		w.Close(q)
	} else {
		w.Bypass()
	}

	go func() {
		w.Wrap(mq.discovery.Unregister(channel, name))
	}()

	return w.Wait()
}

func (mq *MessageQueue) Close() error {
	w := waiter.New(len(mq.queues) + 1)
	w.Close(mq.discovery)
	for _, q := range mq.queues {
		w.Close(q)
	}
	err := w.Wait()
	close(mq.Errors)
	return err
}

// -- helpers --

func (mq *MessageQueue) endpoint(channel string) (string, *queue) {
	endpoint := mq.getEndpoint(channel)
	return endpoint, mq.getQueue(endpoint)
}

func (mq *MessageQueue) getEndpoint(channel string) string {
	return mq.cfg.Prefix + mq.cfg.Delimiter + channel
}

func (mq *MessageQueue) getQueue(endpoint string) *queue {
	q, ok := mq.queues[endpoint]
	if !ok {
		q = mq.newQueue(endpoint)
		mq.queues[endpoint] = q
	}
	return q
}

func (mq *MessageQueue) send(endpoint string, message Message) error {
	q := mq.getQueue(endpoint)
	return q.q.Push(message)
}

func (rqc *RelyQConfig) Defaults() {
	cfg := new(relyq.Config)
	*cfg = relyq.Config(*rqc)
	cfg.Defaults()
	*rqc = RelyQConfig(*cfg)
}

func (cfg *Config) Defaults() {
	cfg.RelyQConfig.Defaults()

	if cfg.SubscriberListDecay == 0 {
		cfg.SubscriberListDecay = 5 * time.Minute
	}
}
<commit_msg>Small fix for nil.Defaults()<commit_after>// Package messageq provides a reliable pub/sub bus for long term listeners job queuing
package messageq

import (
	"github.com/Rafflecopter/golang-relyq/relyq"
	"github.com/garyburd/redigo/redis"
	"github.com/yanatan16/gowaiter"
	"io"
	"time"
)

// -- Types --

// A message queue object.
type MessageQueue struct {
	Errors      chan error
	pool        *redis.Pool
	cfg         *Config
	prefix      string
	queues      map[string]*queue
	discovery   Discovery
	subscribers *subscribersMemo
}

// Interface for discovery backend's to implement
type Discovery interface {
	// Register an endpoint as listening on a channel
	Register(channel, endpoint string) error
	// Unregister an endpoint as listening on a channel
	Unregister(channel, endpiont string) error
	// List subscribers to a channel
	Subscribers(channel string) ([]string, error)

	io.Closer
}

// A message in MessageQueue must have the Id() function required by tasks in RelyQueue
type Message interface {
	relyq.Ider
}

type RelyQConfig relyq.Config

type Config struct {
	*RelyQConfig

	// Subscribers cache decay duration
	SubscriberListDecay time.Duration
}

// -- Functions and Methods --

func New(pool *redis.Pool, disco Discovery, cfg *Config) *MessageQueue {
	cfg.Defaults()
	mq := &MessageQueue{
		Errors:      make(chan error),
		pool:        pool,
		cfg:         cfg,
		queues:      make(map[string]*queue),
		discovery:   disco,
		subscribers: memoizeSubscriberser(disco, cfg.SubscriberListDecay),
	}

	return mq
}

// Subscribe on a channel. Returns the channel of messages
func (mq *MessageQueue) Subscribe(channel string, example Message) (chan Message, error) {
	name, q := mq.endpoint(channel)
	err := mq.discovery.Register(channel, name)

	return q.Messages(mq.Errors, example), err
}

// Publish a message on a channel
func (mq *MessageQueue) Publish(channel string, message Message) error {
	list, err := mq.subscribers.Subscribers(channel)
	if err != nil {
		return err
	}

	for _, endp := range list {
		if err2 := mq.send(endp, message); err != nil {
			err = err2
		}
	}

	return err
}

// Unsubscribe from a channel
func (mq *MessageQueue) Unsubscribe(channel string) error {
	name := mq.getEndpoint(channel)
	w := waiter.New(2)

	if q, ok := mq.queues[name]; ok {
		delete(mq.queues, name)

		w.Close(q)
	} else {
		w.Bypass()
	}

	go func() {
		w.Wrap(mq.discovery.Unregister(channel, name))
	}()

	return w.Wait()
}

func (mq *MessageQueue) Close() error {
	w := waiter.New(len(mq.queues) + 1)
	w.Close(mq.discovery)
	for _, q := range mq.queues {
		w.Close(q)
	}
	err := w.Wait()
	close(mq.Errors)
	return err
}

// -- helpers --

func (mq *MessageQueue) endpoint(channel string) (string, *queue) {
	endpoint := mq.getEndpoint(channel)
	return endpoint, mq.getQueue(endpoint)
}

func (mq *MessageQueue) getEndpoint(channel string) string {
	return mq.cfg.Prefix + mq.cfg.Delimiter + channel
}

func (mq *MessageQueue) getQueue(endpoint string) *queue {
	q, ok := mq.queues[endpoint]
	if !ok {
		q = mq.newQueue(endpoint)
		mq.queues[endpoint] = q
	}
	return q
}

func (mq *MessageQueue) send(endpoint string, message Message) error {
	q := mq.getQueue(endpoint)
	return q.q.Push(message)
}

func (rqc *RelyQConfig) Defaults() {
	cfg := new(relyq.Config)
	if rqc != nil {
		*cfg = relyq.Config(*rqc)
	}
	cfg.Defaults()
	*rqc = RelyQConfig(*cfg)
}

func (cfg *Config) Defaults() {
	cfg.RelyQConfig.Defaults()

	if cfg.SubscriberListDecay == 0 {
		cfg.SubscriberListDecay = 5 * time.Minute
	}
}
<|endoftext|>


<commit_before>package metadata

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"os"
	"reflect"
	"time"

	"github.com/mackerelio/mackerel-agent/config"
	"github.com/mackerelio/mackerel-agent/logging"
)

var logger = logging.GetLogger("metadata")

// Generator generates metadata
type Generator struct {
	Name         string
	Config       *config.MetadataPlugin
	Tempfile     string
	PrevMetadata interface{}
}

// Fetch invokes the command and returns the result
func (g *Generator) Fetch() (interface{}, error) {
	message, stderr, exitCode, err := g.Config.Run()

	if err != nil {
		logger.Warningf("Error occurred while executing a metadata plugin %q: %s", g.Name, err.Error())
		return nil, err
	}

	if stderr != "" {
		logger.Warningf("metadata plugin %q outputs stderr: %s", g.Name, stderr)
		// metadata plugin can output message to stderr for debugging and json to stdout
	}

	if exitCode != 0 {
		return nil, fmt.Errorf("exits with: %d", exitCode)
	}

	var metadata interface{}
	if err := json.Unmarshal([]byte(message), &metadata); err != nil {
		return nil, fmt.Errorf("outputs invalid JSON: %v", message)
	}

	return metadata, nil
}

// Differs returns whether the metadata has been changed or not
func (g *Generator) Differs(metadata interface{}) bool {
	if g.PrevMetadata == nil {
		g.LoadFromFile()
	}
	return !reflect.DeepEqual(g.PrevMetadata, metadata)
}

// LoadFromFile loads the previous metadata from file
func (g *Generator) LoadFromFile() {
	data, err := ioutil.ReadFile(g.Tempfile)
	if err != nil { // maybe initial state
		return
	}
	var metadata interface{}
	if err := json.Unmarshal(data, &metadata); err != nil {
		logger.Warningf("metadata plugin %q detected a invalid json in temporary file: %s", g.Name, string(data))
		return
	}
	g.PrevMetadata = metadata
}

// Save stores the metadata locally
func (g *Generator) Save(metadata interface{}) error {
	g.PrevMetadata = metadata
	data, err := json.Marshal(metadata)
	if err != nil {
		return fmt.Errorf("failed to marshal the metadata to json: %v %s", metadata, err.Error())
	}
	if g.Tempfile == "" {
		return fmt.Errorf("specify the name of temporary file")
	}
	if err = writeFileAtomically(g.Tempfile, data); err != nil {
		return fmt.Errorf("failed to write the metadata to temporary file: %v %s", metadata, err.Error())
	}
	return nil
}

// Clear destroys the metadata cache
func (g *Generator) Clear() error {
	g.PrevMetadata = nil
	return os.Remove(g.Tempfile)
}

func writeFileAtomically(f string, contents []byte) error {
	tmpf, err := ioutil.TempFile("", "")
	if err != nil {
		return err
	}
	defer os.Remove(tmpf.Name())
	_, err = tmpf.Write(contents)
	if err != nil {
		return err
	}
	tmpf.Close()
	return os.Rename(tmpf.Name(), f)
}

const defaultExecutionInterval = 10 * time.Minute

// Interval calculates the time interval of command execution
func (g *Generator) Interval() time.Duration {
	if g.Config.ExecutionInterval == nil {
		return defaultExecutionInterval
	}
	interval := time.Duration(*g.Config.ExecutionInterval) * time.Minute
	if interval < 1*time.Minute {
		return 1 * time.Minute
	}
	return interval
}
<commit_msg>update comments<commit_after>package metadata

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"os"
	"reflect"
	"time"

	"github.com/mackerelio/mackerel-agent/config"
	"github.com/mackerelio/mackerel-agent/logging"
)

var logger = logging.GetLogger("metadata")

// Generator generates metadata
type Generator struct {
	Name         string
	Config       *config.MetadataPlugin
	Tempfile     string
	PrevMetadata interface{}
}

// Fetch invokes the command and returns the result
func (g *Generator) Fetch() (interface{}, error) {
	message, stderr, exitCode, err := g.Config.Run()

	if err != nil {
		logger.Warningf("Error occurred while executing a metadata plugin %q: %s", g.Name, err.Error())
		return nil, err
	}

	if stderr != "" {
		logger.Warningf("metadata plugin %q outputs stderr: %s", g.Name, stderr)
		// metadata plugin can output message to stderr for debugging and json to stdout
	}

	if exitCode != 0 {
		return nil, fmt.Errorf("exits with: %d", exitCode)
	}

	var metadata interface{}
	if err := json.Unmarshal([]byte(message), &metadata); err != nil {
		return nil, fmt.Errorf("outputs invalid JSON: %v", message)
	}

	return metadata, nil
}

// Differs returns whether the metadata has been changed or not
func (g *Generator) Differs(metadata interface{}) bool {
	if g.PrevMetadata == nil {
		g.LoadFromFile()
	}
	return !reflect.DeepEqual(g.PrevMetadata, metadata)
}

// LoadFromFile loads the previous metadata from file
func (g *Generator) LoadFromFile() {
	data, err := ioutil.ReadFile(g.Tempfile)
	if err != nil { // maybe initial state
		return
	}
	var metadata interface{}
	if err := json.Unmarshal(data, &metadata); err != nil {
		logger.Warningf("metadata plugin %q detected a invalid json in temporary file: %s", g.Name, string(data))
		// ignore errors, the file will be overwritten by Save()
		return
	}
	g.PrevMetadata = metadata
}

// Save stores the metadata locally
func (g *Generator) Save(metadata interface{}) error {
	g.PrevMetadata = metadata
	data, err := json.Marshal(metadata)
	if err != nil {
		return fmt.Errorf("failed to marshal the metadata to json: %v %s", metadata, err.Error())
	}
	if g.Tempfile == "" {
		return fmt.Errorf("specify the name of temporary file")
	}
	if err = writeFileAtomically(g.Tempfile, data); err != nil {
		return fmt.Errorf("failed to write the metadata to temporary file: %v %s", metadata, err.Error())
	}
	return nil
}

// Clear destroys the metadata cache
func (g *Generator) Clear() error {
	g.PrevMetadata = nil
	return os.Remove(g.Tempfile)
}

// writeFileAtomically writes contents to the file atomically
func writeFileAtomically(f string, contents []byte) error {
	tmpf, err := ioutil.TempFile("", "")
	if err != nil {
		return err
	}
	defer os.Remove(tmpf.Name())
	_, err = tmpf.Write(contents)
	if err != nil {
		return err
	}
	tmpf.Close()
	return os.Rename(tmpf.Name(), f)
}

const defaultExecutionInterval = 10 * time.Minute

// Interval calculates the time interval of command execution
func (g *Generator) Interval() time.Duration {
	if g.Config.ExecutionInterval == nil {
		return defaultExecutionInterval
	}
	interval := time.Duration(*g.Config.ExecutionInterval) * time.Minute
	if interval < 1*time.Minute {
		return 1 * time.Minute
	}
	return interval
}
<|endoftext|>


<commit_before>// Copyright 2015 go-swagger maintainers
//
// 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 middleware

import (
	"net/http"
	fpath "path"
	"regexp"
	"strings"

	"github.com/go-openapi/analysis"
	"github.com/go-openapi/errors"
	"github.com/go-openapi/loads"
	"github.com/go-openapi/runtime"
	"github.com/go-openapi/runtime/middleware/denco"
	"github.com/go-openapi/spec"
	"github.com/go-openapi/strfmt"
	"github.com/gorilla/context"
)

// RouteParam is a object to capture route params in a framework agnostic way.
// implementations of the muxer should use these route params to communicate with the
// swagger framework
type RouteParam struct {
	Name  string
	Value string
}

// RouteParams the collection of route params
type RouteParams []RouteParam

// Get gets the value for the route param for the specified key
func (r RouteParams) Get(name string) string {
	vv, _, _ := r.GetOK(name)
	if len(vv) > 0 {
		return vv[len(vv)-1]
	}
	return ""
}

// GetOK gets the value but also returns booleans to indicate if a key or value
// is present. This aids in validation and satisfies an interface in use there
//
// The returned values are: data, has key, has value
func (r RouteParams) GetOK(name string) ([]string, bool, bool) {
	for _, p := range r {
		if p.Name == name {
			return []string{p.Value}, true, p.Value != ""
		}
	}
	return nil, false, false
}

// NewRouter creates a new context aware router middleware
func NewRouter(ctx *Context, next http.Handler) http.Handler {
	if ctx.router == nil {
		ctx.router = DefaultRouter(ctx.spec, ctx.api)
	}

	return http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
		defer context.Clear(r)
		if _, ok := ctx.RouteInfo(r); ok {
			next.ServeHTTP(rw, r)
			return
		}

		// Not found, check if it exists in the other methods first
		if others := ctx.AllowedMethods(r); len(others) > 0 {
			ctx.Respond(rw, r, ctx.analyzer.RequiredProduces(), nil, errors.MethodNotAllowed(r.Method, others))
			return
		}

		ctx.Respond(rw, r, ctx.analyzer.RequiredProduces(), nil, errors.NotFound("path %s was not found", r.URL.EscapedPath()))
	})
}

// RoutableAPI represents an interface for things that can serve
// as a provider of implementations for the swagger router
type RoutableAPI interface {
	HandlerFor(string, string) (http.Handler, bool)
	ServeErrorFor(string) func(http.ResponseWriter, *http.Request, error)
	ConsumersFor([]string) map[string]runtime.Consumer
	ProducersFor([]string) map[string]runtime.Producer
	AuthenticatorsFor(map[string]spec.SecurityScheme) map[string]runtime.Authenticator
	Formats() strfmt.Registry
	DefaultProduces() string
	DefaultConsumes() string
}

// Router represents a swagger aware router
type Router interface {
	Lookup(method, path string) (*MatchedRoute, bool)
	OtherMethods(method, path string) []string
}

type defaultRouteBuilder struct {
	spec     *loads.Document
	analyzer *analysis.Spec
	api      RoutableAPI
	records  map[string][]denco.Record
}

type defaultRouter struct {
	spec    *loads.Document
	api     RoutableAPI
	routers map[string]*denco.Router
}

func newDefaultRouteBuilder(spec *loads.Document, api RoutableAPI) *defaultRouteBuilder {
	return &defaultRouteBuilder{
		spec:     spec,
		analyzer: analysis.New(spec.Spec()),
		api:      api,
		records:  make(map[string][]denco.Record),
	}
}

// DefaultRouter creates a default implemenation of the router
func DefaultRouter(spec *loads.Document, api RoutableAPI) Router {
	builder := newDefaultRouteBuilder(spec, api)
	if spec != nil {
		for method, paths := range builder.analyzer.Operations() {
			for path, operation := range paths {
				fp := fpath.Join(spec.BasePath(), path)
				debugLog("adding route %s %s %q", method, fp, operation.ID)
				builder.AddRoute(method, fp, operation)
			}
		}
	}
	return builder.Build()
}

type routeEntry struct {
	PathPattern    string
	BasePath       string
	Operation      *spec.Operation
	Consumes       []string
	Consumers      map[string]runtime.Consumer
	Produces       []string
	Producers      map[string]runtime.Producer
	Parameters     map[string]spec.Parameter
	Handler        http.Handler
	Formats        strfmt.Registry
	Binder         *untypedRequestBinder
	Authenticators map[string]runtime.Authenticator
	Scopes         map[string][]string
}

// MatchedRoute represents the route that was matched in this request
type MatchedRoute struct {
	routeEntry
	Params   RouteParams
	Consumer runtime.Consumer
	Producer runtime.Producer
}

func (d *defaultRouter) Lookup(method, path string) (*MatchedRoute, bool) {
	mth := strings.ToUpper(method)
	debugLog("looking up route for %s %s", method, path)
	if Debug {
		if len(d.routers) == 0 {
			debugLog("there are no known routers")
		}
		for meth := range d.routers {
			debugLog("got a router for %s", meth)
		}
	}
	if router, ok := d.routers[mth]; ok {
		if m, rp, ok := router.Lookup(path); ok && m != nil {
			if entry, ok := m.(*routeEntry); ok {
				debugLog("found a route for %s %s with %d parameters", method, path, len(entry.Parameters))
				var params RouteParams
				for _, p := range rp {
					params = append(params, RouteParam{Name: p.Name, Value: p.Value})
				}
				return &MatchedRoute{routeEntry: *entry, Params: params}, true
			}
		} else {
			debugLog("couldn't find a route by path for %s %s", method, path)
		}
	} else {
		debugLog("couldn't find a route by method for %s %s", method, path)
	}
	return nil, false
}

func (d *defaultRouter) OtherMethods(method, path string) []string {
	mn := strings.ToUpper(method)
	var methods []string
	for k, v := range d.routers {
		if k != mn {
			if _, _, ok := v.Lookup(path); ok {
				methods = append(methods, k)
				continue
			}
		}
	}
	return methods
}

var pathConverter = regexp.MustCompile(`{(\w+)}`)

func (d *defaultRouteBuilder) AddRoute(method, path string, operation *spec.Operation) {
	mn := strings.ToUpper(method)

	bp := fpath.Clean(d.spec.BasePath())
	if len(bp) > 0 && bp[len(bp)-1] == '/' {
		bp = bp[:len(bp)-1]
	}

	if handler, ok := d.api.HandlerFor(method, strings.TrimPrefix(path, bp)); ok {
		consumes := d.analyzer.ConsumesFor(operation)
		produces := d.analyzer.ProducesFor(operation)
		parameters := d.analyzer.ParamsFor(method, strings.TrimPrefix(path, bp))
		definitions := d.analyzer.SecurityDefinitionsFor(operation)
		requirements := d.analyzer.SecurityRequirementsFor(operation)
		scopes := make(map[string][]string, len(requirements))
		for _, v := range requirements {
			scopes[v.Name] = v.Scopes
		}

		record := denco.NewRecord(pathConverter.ReplaceAllString(path, ":$1"), &routeEntry{
			Operation:      operation,
			Handler:        handler,
			Consumes:       consumes,
			Produces:       produces,
			Consumers:      d.api.ConsumersFor(consumes),
			Producers:      d.api.ProducersFor(produces),
			Parameters:     parameters,
			Formats:        d.api.Formats(),
			Binder:         newUntypedRequestBinder(parameters, d.spec.Spec(), d.api.Formats()),
			Authenticators: d.api.AuthenticatorsFor(definitions),
			Scopes:         scopes,
		})
		d.records[mn] = append(d.records[mn], record)
	}
}

func (d *defaultRouteBuilder) Build() *defaultRouter {
	routers := make(map[string]*denco.Router)
	for method, records := range d.records {
		router := denco.New()
		router.Build(records)
		routers[method] = router
	}
	return &defaultRouter{
		spec:    d.spec,
		routers: routers,
	}
}
<commit_msg>clean path before lookup<commit_after>// Copyright 2015 go-swagger maintainers
//
// 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 middleware

import (
	"net/http"
	fpath "path"
	"regexp"
	"strings"

	"github.com/go-openapi/analysis"
	"github.com/go-openapi/errors"
	"github.com/go-openapi/loads"
	"github.com/go-openapi/runtime"
	"github.com/go-openapi/runtime/middleware/denco"
	"github.com/go-openapi/spec"
	"github.com/go-openapi/strfmt"
	"github.com/gorilla/context"
)

// RouteParam is a object to capture route params in a framework agnostic way.
// implementations of the muxer should use these route params to communicate with the
// swagger framework
type RouteParam struct {
	Name  string
	Value string
}

// RouteParams the collection of route params
type RouteParams []RouteParam

// Get gets the value for the route param for the specified key
func (r RouteParams) Get(name string) string {
	vv, _, _ := r.GetOK(name)
	if len(vv) > 0 {
		return vv[len(vv)-1]
	}
	return ""
}

// GetOK gets the value but also returns booleans to indicate if a key or value
// is present. This aids in validation and satisfies an interface in use there
//
// The returned values are: data, has key, has value
func (r RouteParams) GetOK(name string) ([]string, bool, bool) {
	for _, p := range r {
		if p.Name == name {
			return []string{p.Value}, true, p.Value != ""
		}
	}
	return nil, false, false
}

// NewRouter creates a new context aware router middleware
func NewRouter(ctx *Context, next http.Handler) http.Handler {
	if ctx.router == nil {
		ctx.router = DefaultRouter(ctx.spec, ctx.api)
	}

	return http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
		defer context.Clear(r)
		if _, ok := ctx.RouteInfo(r); ok {
			next.ServeHTTP(rw, r)
			return
		}

		// Not found, check if it exists in the other methods first
		if others := ctx.AllowedMethods(r); len(others) > 0 {
			ctx.Respond(rw, r, ctx.analyzer.RequiredProduces(), nil, errors.MethodNotAllowed(r.Method, others))
			return
		}

		ctx.Respond(rw, r, ctx.analyzer.RequiredProduces(), nil, errors.NotFound("path %s was not found", r.URL.EscapedPath()))
	})
}

// RoutableAPI represents an interface for things that can serve
// as a provider of implementations for the swagger router
type RoutableAPI interface {
	HandlerFor(string, string) (http.Handler, bool)
	ServeErrorFor(string) func(http.ResponseWriter, *http.Request, error)
	ConsumersFor([]string) map[string]runtime.Consumer
	ProducersFor([]string) map[string]runtime.Producer
	AuthenticatorsFor(map[string]spec.SecurityScheme) map[string]runtime.Authenticator
	Formats() strfmt.Registry
	DefaultProduces() string
	DefaultConsumes() string
}

// Router represents a swagger aware router
type Router interface {
	Lookup(method, path string) (*MatchedRoute, bool)
	OtherMethods(method, path string) []string
}

type defaultRouteBuilder struct {
	spec     *loads.Document
	analyzer *analysis.Spec
	api      RoutableAPI
	records  map[string][]denco.Record
}

type defaultRouter struct {
	spec    *loads.Document
	api     RoutableAPI
	routers map[string]*denco.Router
}

func newDefaultRouteBuilder(spec *loads.Document, api RoutableAPI) *defaultRouteBuilder {
	return &defaultRouteBuilder{
		spec:     spec,
		analyzer: analysis.New(spec.Spec()),
		api:      api,
		records:  make(map[string][]denco.Record),
	}
}

// DefaultRouter creates a default implemenation of the router
func DefaultRouter(spec *loads.Document, api RoutableAPI) Router {
	builder := newDefaultRouteBuilder(spec, api)
	if spec != nil {
		for method, paths := range builder.analyzer.Operations() {
			for path, operation := range paths {
				fp := fpath.Join(spec.BasePath(), path)
				debugLog("adding route %s %s %q", method, fp, operation.ID)
				builder.AddRoute(method, fp, operation)
			}
		}
	}
	return builder.Build()
}

type routeEntry struct {
	PathPattern    string
	BasePath       string
	Operation      *spec.Operation
	Consumes       []string
	Consumers      map[string]runtime.Consumer
	Produces       []string
	Producers      map[string]runtime.Producer
	Parameters     map[string]spec.Parameter
	Handler        http.Handler
	Formats        strfmt.Registry
	Binder         *untypedRequestBinder
	Authenticators map[string]runtime.Authenticator
	Scopes         map[string][]string
}

// MatchedRoute represents the route that was matched in this request
type MatchedRoute struct {
	routeEntry
	Params   RouteParams
	Consumer runtime.Consumer
	Producer runtime.Producer
}

func (d *defaultRouter) Lookup(method, path string) (*MatchedRoute, bool) {
	mth := strings.ToUpper(method)
	debugLog("looking up route for %s %s", method, path)
	if Debug {
		if len(d.routers) == 0 {
			debugLog("there are no known routers")
		}
		for meth := range d.routers {
			debugLog("got a router for %s", meth)
		}
	}
	if router, ok := d.routers[mth]; ok {
		if m, rp, ok := router.Lookup(fpath.Clean(path)); ok && m != nil {
			if entry, ok := m.(*routeEntry); ok {
				debugLog("found a route for %s %s with %d parameters", method, path, len(entry.Parameters))
				var params RouteParams
				for _, p := range rp {
					params = append(params, RouteParam{Name: p.Name, Value: p.Value})
				}
				return &MatchedRoute{routeEntry: *entry, Params: params}, true
			}
		} else {
			debugLog("couldn't find a route by path for %s %s", method, path)
		}
	} else {
		debugLog("couldn't find a route by method for %s %s", method, path)
	}
	return nil, false
}

func (d *defaultRouter) OtherMethods(method, path string) []string {
	mn := strings.ToUpper(method)
	var methods []string
	for k, v := range d.routers {
		if k != mn {
			if _, _, ok := v.Lookup(fpath.Clean(path)); ok {
				methods = append(methods, k)
				continue
			}
		}
	}
	return methods
}

var pathConverter = regexp.MustCompile(`{(\w+)}`)

func (d *defaultRouteBuilder) AddRoute(method, path string, operation *spec.Operation) {
	mn := strings.ToUpper(method)

	bp := fpath.Clean(d.spec.BasePath())
	if len(bp) > 0 && bp[len(bp)-1] == '/' {
		bp = bp[:len(bp)-1]
	}

	if handler, ok := d.api.HandlerFor(method, strings.TrimPrefix(path, bp)); ok {
		consumes := d.analyzer.ConsumesFor(operation)
		produces := d.analyzer.ProducesFor(operation)
		parameters := d.analyzer.ParamsFor(method, strings.TrimPrefix(path, bp))
		definitions := d.analyzer.SecurityDefinitionsFor(operation)
		requirements := d.analyzer.SecurityRequirementsFor(operation)
		scopes := make(map[string][]string, len(requirements))
		for _, v := range requirements {
			scopes[v.Name] = v.Scopes
		}

		record := denco.NewRecord(pathConverter.ReplaceAllString(path, ":$1"), &routeEntry{
			Operation:      operation,
			Handler:        handler,
			Consumes:       consumes,
			Produces:       produces,
			Consumers:      d.api.ConsumersFor(consumes),
			Producers:      d.api.ProducersFor(produces),
			Parameters:     parameters,
			Formats:        d.api.Formats(),
			Binder:         newUntypedRequestBinder(parameters, d.spec.Spec(), d.api.Formats()),
			Authenticators: d.api.AuthenticatorsFor(definitions),
			Scopes:         scopes,
		})
		d.records[mn] = append(d.records[mn], record)
	}
}

func (d *defaultRouteBuilder) Build() *defaultRouter {
	routers := make(map[string]*denco.Router)
	for method, records := range d.records {
		router := denco.New()
		router.Build(records)
		routers[method] = router
	}
	return &defaultRouter{
		spec:    d.spec,
		routers: routers,
	}
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"os"
	"strconv"
	"strings"
)

// Input format
const (
	CSV = iota
	LTSV
	JSON
)

// Input is database import
type Input interface {
	firstRead() ([]string, error)
	firstRow([]interface{}) []interface{}
	rowRead([]interface{}) ([]interface{}, error)
}

func (trdsql *TRDSQL) dbimport(db *DDB, sqlstr string) (string, error) {
	var err error
	tablenames := sqlparse(sqlstr)
	if len(tablenames) == 0 {
		// without FROM clause. ex. SELECT 1+1;
		debug.Printf("table not found\n")
	}
	created := make(map[string]bool)
	for _, tablename := range tablenames {
		if created[tablename] {
			debug.Printf("already created \"%s\"\n", tablename)
			continue
		}
		sqlstr, err = trdsql.importTable(db, tablename, sqlstr)
		if err != nil {
			break
		}
		created[tablename] = true
	}
	return sqlstr, err
}

func (trdsql *TRDSQL) importTable(db *DDB, tablename string, sqlstr string) (string, error) {
	file, input, err := trdsql.fileInput(tablename)
	if err != nil {
		debug.Printf("%s\n", err)
		return sqlstr, nil
	}
	defer file.Close()
	skip := make([]interface{}, 1)
	for i := 0; i < trdsql.iskip; i++ {
		r, _ := input.rowRead(skip)
		debug.Printf("Skip row:%s\n", r)
	}
	rtable := db.escapetable(tablename)
	sqlstr = db.rewrite(sqlstr, tablename, rtable)
	var header []string
	header, err = input.firstRead()
	if err != nil {
		return sqlstr, err
	}
	err = db.Create(rtable, header)
	if err != nil {
		return sqlstr, err
	}
	err = db.ImportData(rtable, header, input, trdsql.ifrow)
	return sqlstr, err
}

func (trdsql *TRDSQL) fileInput(tablename string) (*os.File, Input, error) {
	file, err := tableFileOpen(tablename)
	if err != nil {
		return nil, nil, err
	}

	itype := CSV
	if trdsql.icsv {
		itype = CSV
	} else if trdsql.iltsv {
		itype = LTSV
	} else if trdsql.ijson {
		itype = JSON
	} else if trdsql.iguess {
		itype = guessExtension(tablename)
	}

	trdsql.ifrow = false
	var input Input
	switch itype {
	case LTSV:
		trdsql.ifrow = true
		input, err = trdsql.ltsvInputNew(file)
	case JSON:
		trdsql.ifrow = true
		input, err = trdsql.jsonInputNew(file)
	default:
		trdsql.ifrow = !trdsql.ihead
		input, err = trdsql.csvInputNew(file)
	}
	return file, input, err
}

// Output is database export
type Output interface {
	first([]string) error
	rowWrite([]interface{}, []string) error
	last() error
}

func (trdsql *TRDSQL) dbexport(db *DDB, sqlstr string, output Output) error {
	rows, err := db.Select(sqlstr)
	if err != nil {
		return err
	}

	columns, err := rows.Columns()
	if err != nil {
		return err
	}
	defer rows.Close()
	values := make([]interface{}, len(columns))
	scanArgs := make([]interface{}, len(columns))
	for i := range values {
		scanArgs[i] = &values[i]
	}
	err = output.first(columns)
	if err != nil {
		return err
	}
	for rows.Next() {
		err = rows.Scan(scanArgs...)
		if err != nil {
			return err
		}
		err = output.rowWrite(values, columns)
		if err != nil {
			return err
		}
	}
	output.last()
	return nil
}

func guessExtension(tablename string) int {
	pos := strings.LastIndex(tablename, ".")
	if pos > 0 {
		ext := strings.ToLower(tablename[pos:])
		if ext == ".ltsv" {
			debug.Printf("Guess file type as LTSV: [%s]", tablename)
			return LTSV
		} else if ext == ".json" {
			debug.Printf("Guess file type as JSON: [%s]", tablename)
			return JSON
		}
	}
	debug.Printf("Guess file type as CSV: [%s]", tablename)
	return CSV
}

func getSeparator(sepString string) (rune, error) {
	if sepString == "" {
		return 0, nil
	}
	sepRunes, err := strconv.Unquote(`'` + sepString + `'`)
	if err != nil {
		return ',', fmt.Errorf("ERROR getSeparator: %s:%s", err, sepString)
	}
	sepRune := ([]rune(sepRunes))[0]
	return sepRune, err
}

func tableFileOpen(filename string) (*os.File, error) {
	if filename == "-" {
		return os.Stdin, nil
	}
	if filename[0] == '`' {
		filename = strings.Replace(filename, "`", "", 2)
	}
	if filename[0] == '"' {
		filename = strings.Replace(filename, "\"", "", 2)
	}
	return os.Open(filename)
}

func valString(v interface{}) string {
	var str string
	b, ok := v.([]byte)
	if ok {
		str = string(b)
	} else {
		if v == nil {
			str = ""
		} else {
			str = fmt.Sprint(v)
		}
	}
	return str
}
<commit_msg>"stdin" is also standard input<commit_after>package main

import (
	"fmt"
	"os"
	"strconv"
	"strings"
)

// Input format
const (
	CSV = iota
	LTSV
	JSON
)

// Input is database import
type Input interface {
	firstRead() ([]string, error)
	firstRow([]interface{}) []interface{}
	rowRead([]interface{}) ([]interface{}, error)
}

func (trdsql *TRDSQL) dbimport(db *DDB, sqlstr string) (string, error) {
	var err error
	tablenames := sqlparse(sqlstr)
	if len(tablenames) == 0 {
		// without FROM clause. ex. SELECT 1+1;
		debug.Printf("table not found\n")
	}
	created := make(map[string]bool)
	for _, tablename := range tablenames {
		if created[tablename] {
			debug.Printf("already created \"%s\"\n", tablename)
			continue
		}
		sqlstr, err = trdsql.importTable(db, tablename, sqlstr)
		if err != nil {
			break
		}
		created[tablename] = true
	}
	return sqlstr, err
}

func (trdsql *TRDSQL) importTable(db *DDB, tablename string, sqlstr string) (string, error) {
	file, input, err := trdsql.fileInput(tablename)
	if err != nil {
		debug.Printf("%s\n", err)
		return sqlstr, nil
	}
	defer file.Close()
	skip := make([]interface{}, 1)
	for i := 0; i < trdsql.iskip; i++ {
		r, _ := input.rowRead(skip)
		debug.Printf("Skip row:%s\n", r)
	}
	rtable := db.escapetable(tablename)
	sqlstr = db.rewrite(sqlstr, tablename, rtable)
	var header []string
	header, err = input.firstRead()
	if err != nil {
		return sqlstr, err
	}
	err = db.Create(rtable, header)
	if err != nil {
		return sqlstr, err
	}
	err = db.ImportData(rtable, header, input, trdsql.ifrow)
	return sqlstr, err
}

func (trdsql *TRDSQL) fileInput(tablename string) (*os.File, Input, error) {
	file, err := tableFileOpen(tablename)
	if err != nil {
		return nil, nil, err
	}

	itype := CSV
	if trdsql.icsv {
		itype = CSV
	} else if trdsql.iltsv {
		itype = LTSV
	} else if trdsql.ijson {
		itype = JSON
	} else if trdsql.iguess {
		itype = guessExtension(tablename)
	}

	trdsql.ifrow = false
	var input Input
	switch itype {
	case LTSV:
		trdsql.ifrow = true
		input, err = trdsql.ltsvInputNew(file)
	case JSON:
		trdsql.ifrow = true
		input, err = trdsql.jsonInputNew(file)
	default:
		trdsql.ifrow = !trdsql.ihead
		input, err = trdsql.csvInputNew(file)
	}
	return file, input, err
}

// Output is database export
type Output interface {
	first([]string) error
	rowWrite([]interface{}, []string) error
	last() error
}

func (trdsql *TRDSQL) dbexport(db *DDB, sqlstr string, output Output) error {
	rows, err := db.Select(sqlstr)
	if err != nil {
		return err
	}

	columns, err := rows.Columns()
	if err != nil {
		return err
	}
	defer rows.Close()
	values := make([]interface{}, len(columns))
	scanArgs := make([]interface{}, len(columns))
	for i := range values {
		scanArgs[i] = &values[i]
	}
	err = output.first(columns)
	if err != nil {
		return err
	}
	for rows.Next() {
		err = rows.Scan(scanArgs...)
		if err != nil {
			return err
		}
		err = output.rowWrite(values, columns)
		if err != nil {
			return err
		}
	}
	output.last()
	return nil
}

func guessExtension(tablename string) int {
	pos := strings.LastIndex(tablename, ".")
	if pos > 0 {
		ext := strings.ToLower(tablename[pos:])
		if ext == ".ltsv" {
			debug.Printf("Guess file type as LTSV: [%s]", tablename)
			return LTSV
		} else if ext == ".json" {
			debug.Printf("Guess file type as JSON: [%s]", tablename)
			return JSON
		}
	}
	debug.Printf("Guess file type as CSV: [%s]", tablename)
	return CSV
}

func getSeparator(sepString string) (rune, error) {
	if sepString == "" {
		return 0, nil
	}
	sepRunes, err := strconv.Unquote(`'` + sepString + `'`)
	if err != nil {
		return ',', fmt.Errorf("ERROR getSeparator: %s:%s", err, sepString)
	}
	sepRune := ([]rune(sepRunes))[0]
	return sepRune, err
}

func tableFileOpen(filename string) (*os.File, error) {
	if filename == "-" || strings.ToLower(filename) == "stdin" {
		return os.Stdin, nil
	}
	if filename[0] == '`' {
		filename = strings.Replace(filename, "`", "", 2)
	}
	if filename[0] == '"' {
		filename = strings.Replace(filename, "\"", "", 2)
	}
	return os.Open(filename)
}

func valString(v interface{}) string {
	var str string
	b, ok := v.([]byte)
	if ok {
		str = string(b)
	} else {
		if v == nil {
			str = ""
		} else {
			str = fmt.Sprint(v)
		}
	}
	return str
}
<|endoftext|>


<commit_before>// Copyright 2015 Hajime Hoshi
//
// 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 ebiten

import (
	"github.com/hajimehoshi/ebiten/internal/driver"
)

// InputChars return "printable" runes read from the keyboard at the time update is called.
//
// InputChars represents the environment's locale-dependent translation of keyboard
// input to Unicode characters.
//
// IsKeyPressed is based on a mapping of device (US keyboard) codes to input device keys.
// "Control" and modifier keys should be handled with IsKeyPressed.
//
// InputChars is concurrent-safe.
//
// On Android (ebitenmobile), EbitenView must be focusable to enable to handle keyboard keys.
//
// Keyboards don't work on iOS yet (#1090).
func InputChars() []rune {
	rb := uiDriver().Input().RuneBuffer()
	return append(make([]rune, 0, len(rb)), rb...)
}

// IsKeyPressed returns a boolean indicating whether key is pressed.
//
// Known issue: On Edge browser, some keys don't work well:
//
//   - KeyKPEnter and KeyKPEqual are recognized as KeyEnter and KeyEqual.
//   - KeyPrintScreen is only treated at keyup event.
//
// IsKeyPressed is concurrent-safe.
//
// On Android (ebitenmobile), EbitenView must be focusable to enable to handle keyboard keys.
//
// Keyboards don't work on iOS yet (#1090).
func IsKeyPressed(key Key) bool {
	// There are keys that are invalid values as ebiten.Key (e.g., driver.KeyLeftAlt).
	// Skip such values.
	if !key.isValid() {
		return false
	}

	var keys []driver.Key
	switch key {
	case KeyAlt:
		keys = []driver.Key{driver.KeyLeftAlt, driver.KeyRightAlt}
	case KeyControl:
		keys = []driver.Key{driver.KeyLeftControl, driver.KeyRightControl}
	case KeyShift:
		keys = []driver.Key{driver.KeyLeftShift, driver.KeyRightShift}
	default:
		keys = []driver.Key{driver.Key(key)}
	}
	for _, k := range keys {
		if uiDriver().Input().IsKeyPressed(k) {
			return true
		}
	}
	return false
}

// CursorPosition returns a position of a mouse cursor relative to the game screen (window). The cursor position is
// 'logical' position and this considers the scale of the screen.
//
// CursorPosition is concurrent-safe.
func CursorPosition() (x, y int) {
	return uiDriver().Input().CursorPosition()
}

// Wheel returns the x and y offset of the mouse wheel or touchpad scroll.
// It returns 0 if the wheel isn't being rolled.
//
// Wheel is concurrent-safe.
func Wheel() (xoff, yoff float64) {
	return uiDriver().Input().Wheel()
}

// IsMouseButtonPressed returns a boolean indicating whether mouseButton is pressed.
//
// IsMouseButtonPressed is concurrent-safe.
//
// Note that touch events not longer affect IsMouseButtonPressed's result as of 1.4.0-alpha.
// Use Touches instead.
func IsMouseButtonPressed(mouseButton MouseButton) bool {
	return uiDriver().Input().IsMouseButtonPressed(driver.MouseButton(mouseButton))
}

// GamepadSDLID returns a string with the GUID generated in the same way as SDL.
// To detect devices, see also the community project of gamepad devices database: https://github.com/gabomdq/SDL_GameControllerDB
//
// GamepadSDLID always returns an empty string on browsers and mobiles.
//
// GamepadSDLID is concurrent-safe.
func GamepadSDLID(id int) string {
	return uiDriver().Input().GamepadSDLID(id)
}

// GamepadName returns a string with the name.
// This function may vary in how it returns descriptions for the same device across platforms
// for example the following drivers/platforms see a Xbox One controller as the following:
//
//   - Windows: "Xbox Controller"
//   - Chrome: "Xbox 360 Controller (XInput STANDARD GAMEPAD)"
//   - Firefox: "xinput"
//
// GamepadName always returns an empty string on mobiles.
//
// GamepadName is concurrent-safe.
func GamepadName(id int) string {
	return uiDriver().Input().GamepadName(id)
}

// GamepadIDs returns a slice indicating available gamepad IDs.
//
// GamepadIDs is concurrent-safe.
//
// GamepadIDs always returns an empty slice on mobiles.
func GamepadIDs() []int {
	return uiDriver().Input().GamepadIDs()
}

// GamepadAxisNum returns the number of axes of the gamepad (id).
//
// GamepadAxisNum is concurrent-safe.
//
// GamepadAxisNum always returns 0 on mobiles.
func GamepadAxisNum(id int) int {
	return uiDriver().Input().GamepadAxisNum(id)
}

// GamepadAxis returns the float value [-1.0 - 1.0] of the given gamepad (id)'s axis (axis).
//
// GamepadAxis is concurrent-safe.
//
// GamepadAxis always returns 0 on mobiles.
func GamepadAxis(id int, axis int) float64 {
	return uiDriver().Input().GamepadAxis(id, axis)
}

// GamepadButtonNum returns the number of the buttons of the given gamepad (id).
//
// GamepadButtonNum is concurrent-safe.
//
// GamepadButtonNum always returns 0 on mobiles.
func GamepadButtonNum(id int) int {
	return uiDriver().Input().GamepadButtonNum(id)
}

// IsGamepadButtonPressed returns the boolean indicating the given button of the gamepad (id) is pressed or not.
//
// IsGamepadButtonPressed is concurrent-safe.
//
// The relationships between physical buttons and buttion IDs depend on environments.
// There can be differences even between Chrome and Firefox.
//
// IsGamepadButtonPressed always returns false on mobiles.
func IsGamepadButtonPressed(id int, button GamepadButton) bool {
	return uiDriver().Input().IsGamepadButtonPressed(id, driver.GamepadButton(button))
}

// TouchIDs returns the current touch states.
//
// TouchIDs returns nil when there are no touches.
// TouchIDs always returns nil on desktops.
//
// TouchIDs is concurrent-safe.
func TouchIDs() []int {
	return uiDriver().Input().TouchIDs()
}

// TouchPosition returns the position for the touch of the specified ID.
//
// If the touch of the specified ID is not present, TouchPosition returns (0, 0).
//
// TouchPosition is cuncurrent-safe.
func TouchPosition(id int) (int, int) {
	found := false
	for _, i := range uiDriver().Input().TouchIDs() {
		if id == i {
			found = true
			break
		}
	}
	if !found {
		return 0, 0
	}

	return uiDriver().Input().TouchPosition(id)
}

// Touch represents a touch.
//
// Deprecated: (as of 1.7.0). Use TouchPosition instead.
type Touch interface {
	// ID returns an identifier for one stroke.
	ID() int

	// Position returns the position of the touch.
	Position() (x, y int)
}

type touch struct {
	id int
	x  int
	y  int
}

func (t *touch) ID() int {
	return t.id
}

func (t *touch) Position() (x, y int) {
	return t.x, t.y
}

// Touches returns the current touches.
//
// Deprecated: (as of 1.7.0) Use TouchIDs instead.
func Touches() []Touch {
	var ts []Touch
	for _, id := range TouchIDs() {
		x, y := TouchPosition(id)
		ts = append(ts, &touch{
			id: id,
			x:  x,
			y:  y,
		})
	}
	return ts
}
<commit_msg>ebiten: Add inpututil guide comments for Is{Key,MouseButton,Gamepad}Pressed and TouchIDs (#1346)<commit_after>// Copyright 2015 Hajime Hoshi
//
// 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 ebiten

import (
	"github.com/hajimehoshi/ebiten/internal/driver"
)

// InputChars return "printable" runes read from the keyboard at the time update is called.
//
// InputChars represents the environment's locale-dependent translation of keyboard
// input to Unicode characters.
//
// IsKeyPressed is based on a mapping of device (US keyboard) codes to input device keys.
// "Control" and modifier keys should be handled with IsKeyPressed.
//
// InputChars is concurrent-safe.
//
// On Android (ebitenmobile), EbitenView must be focusable to enable to handle keyboard keys.
//
// Keyboards don't work on iOS yet (#1090).
func InputChars() []rune {
	rb := uiDriver().Input().RuneBuffer()
	return append(make([]rune, 0, len(rb)), rb...)
}

// IsKeyPressed returns a boolean indicating whether key is pressed.
//
// If you want to know whether the key started being pressed in the current frame,
// use inpututil.IsKeyJustPressed
//
// Known issue: On Edge browser, some keys don't work well:
//
//   - KeyKPEnter and KeyKPEqual are recognized as KeyEnter and KeyEqual.
//   - KeyPrintScreen is only treated at keyup event.
//
// IsKeyPressed is concurrent-safe.
//
// On Android (ebitenmobile), EbitenView must be focusable to enable to handle keyboard keys.
//
// Keyboards don't work on iOS yet (#1090).
func IsKeyPressed(key Key) bool {
	// There are keys that are invalid values as ebiten.Key (e.g., driver.KeyLeftAlt).
	// Skip such values.
	if !key.isValid() {
		return false
	}

	var keys []driver.Key
	switch key {
	case KeyAlt:
		keys = []driver.Key{driver.KeyLeftAlt, driver.KeyRightAlt}
	case KeyControl:
		keys = []driver.Key{driver.KeyLeftControl, driver.KeyRightControl}
	case KeyShift:
		keys = []driver.Key{driver.KeyLeftShift, driver.KeyRightShift}
	default:
		keys = []driver.Key{driver.Key(key)}
	}
	for _, k := range keys {
		if uiDriver().Input().IsKeyPressed(k) {
			return true
		}
	}
	return false
}

// CursorPosition returns a position of a mouse cursor relative to the game screen (window). The cursor position is
// 'logical' position and this considers the scale of the screen.
//
// CursorPosition is concurrent-safe.
func CursorPosition() (x, y int) {
	return uiDriver().Input().CursorPosition()
}

// Wheel returns the x and y offset of the mouse wheel or touchpad scroll.
// It returns 0 if the wheel isn't being rolled.
//
// Wheel is concurrent-safe.
func Wheel() (xoff, yoff float64) {
	return uiDriver().Input().Wheel()
}

// IsMouseButtonPressed returns a boolean indicating whether mouseButton is pressed.
//
// If you want to know whether the mouseButton started being pressed in the current frame,
// use inpututil.IsMouseButtonJustPressed
//
// IsMouseButtonPressed is concurrent-safe.
//
// Note that touch events not longer affect IsMouseButtonPressed's result as of 1.4.0-alpha.
// Use Touches instead.
func IsMouseButtonPressed(mouseButton MouseButton) bool {
	return uiDriver().Input().IsMouseButtonPressed(driver.MouseButton(mouseButton))
}

// GamepadSDLID returns a string with the GUID generated in the same way as SDL.
// To detect devices, see also the community project of gamepad devices database: https://github.com/gabomdq/SDL_GameControllerDB
//
// GamepadSDLID always returns an empty string on browsers and mobiles.
//
// GamepadSDLID is concurrent-safe.
func GamepadSDLID(id int) string {
	return uiDriver().Input().GamepadSDLID(id)
}

// GamepadName returns a string with the name.
// This function may vary in how it returns descriptions for the same device across platforms
// for example the following drivers/platforms see a Xbox One controller as the following:
//
//   - Windows: "Xbox Controller"
//   - Chrome: "Xbox 360 Controller (XInput STANDARD GAMEPAD)"
//   - Firefox: "xinput"
//
// GamepadName always returns an empty string on mobiles.
//
// GamepadName is concurrent-safe.
func GamepadName(id int) string {
	return uiDriver().Input().GamepadName(id)
}

// GamepadIDs returns a slice indicating available gamepad IDs.
//
// GamepadIDs is concurrent-safe.
//
// GamepadIDs always returns an empty slice on mobiles.
func GamepadIDs() []int {
	return uiDriver().Input().GamepadIDs()
}

// GamepadAxisNum returns the number of axes of the gamepad (id).
//
// GamepadAxisNum is concurrent-safe.
//
// GamepadAxisNum always returns 0 on mobiles.
func GamepadAxisNum(id int) int {
	return uiDriver().Input().GamepadAxisNum(id)
}

// GamepadAxis returns the float value [-1.0 - 1.0] of the given gamepad (id)'s axis (axis).
//
// GamepadAxis is concurrent-safe.
//
// GamepadAxis always returns 0 on mobiles.
func GamepadAxis(id int, axis int) float64 {
	return uiDriver().Input().GamepadAxis(id, axis)
}

// GamepadButtonNum returns the number of the buttons of the given gamepad (id).
//
// GamepadButtonNum is concurrent-safe.
//
// GamepadButtonNum always returns 0 on mobiles.
func GamepadButtonNum(id int) int {
	return uiDriver().Input().GamepadButtonNum(id)
}

// IsGamepadButtonPressed returns the boolean indicating the given button of the gamepad (id) is pressed or not.
//
// If you want to know whether the given button of gamepad (id) started being pressed in the current frame,
// use inpututil.IsGamepadButtonJustPressed
//
// IsGamepadButtonPressed is concurrent-safe.
//
// The relationships between physical buttons and buttion IDs depend on environments.
// There can be differences even between Chrome and Firefox.
//
// IsGamepadButtonPressed always returns false on mobiles.
func IsGamepadButtonPressed(id int, button GamepadButton) bool {
	return uiDriver().Input().IsGamepadButtonPressed(id, driver.GamepadButton(button))
}

// TouchIDs returns the current touch states.
//
// If you want to know whether a touch started being pressed in the current frame,
// use inpututil.JustPressedTouchIDs
//
// TouchIDs returns nil when there are no touches.
// TouchIDs always returns nil on desktops.
//
// TouchIDs is concurrent-safe.
func TouchIDs() []int {
	return uiDriver().Input().TouchIDs()
}

// TouchPosition returns the position for the touch of the specified ID.
//
// If the touch of the specified ID is not present, TouchPosition returns (0, 0).
//
// TouchPosition is cuncurrent-safe.
func TouchPosition(id int) (int, int) {
	found := false
	for _, i := range uiDriver().Input().TouchIDs() {
		if id == i {
			found = true
			break
		}
	}
	if !found {
		return 0, 0
	}

	return uiDriver().Input().TouchPosition(id)
}

// Touch represents a touch.
//
// Deprecated: (as of 1.7.0). Use TouchPosition instead.
type Touch interface {
	// ID returns an identifier for one stroke.
	ID() int

	// Position returns the position of the touch.
	Position() (x, y int)
}

type touch struct {
	id int
	x  int
	y  int
}

func (t *touch) ID() int {
	return t.id
}

func (t *touch) Position() (x, y int) {
	return t.x, t.y
}

// Touches returns the current touches.
//
// Deprecated: (as of 1.7.0) Use TouchIDs instead.
func Touches() []Touch {
	var ts []Touch
	for _, id := range TouchIDs() {
		x, y := TouchPosition(id)
		ts = append(ts, &touch{
			id: id,
			x:  x,
			y:  y,
		})
	}
	return ts
}
<|endoftext|>