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

// Package internal provides support for the maps packages.
//
// Users should not import this package directly.
package internal

import (
	"fmt"
	"net/http"
	"strings"
	"sync"

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

type contextKey struct{}

// WithContext is the internal constructor for mapsContext.
func WithContext(parent context.Context, apiKey string, c *http.Client, baseURL, roadsBaseURL string) context.Context {
	if c == nil {
		panic("nil *http.Client passed to WithContext")
	}
	if apiKey == "" {
		panic("empty API Key passed to WithContext")
	}
	if !strings.HasPrefix(apiKey, "AIza") {
		panic("invalid API Key passed to WithContext")
	}
	if baseURL == "" {
		panic("invalid base URL passed to WithContext")
	}
	return context.WithValue(parent, contextKey{}, &mapsContext{
		APIKey:       apiKey,
		HTTPClient:   c,
		BaseURL:      baseURL,
		RoadsBaseURL: roadsBaseURL,
	})
}

const userAgent = "gmaps-golang/0.1"

type mapsContext struct {
	APIKey       string
	HTTPClient   *http.Client
	BaseURL      string
	RoadsBaseURL string

	mu  sync.Mutex             // guards svc
	svc map[string]interface{} // e.g. "storage" => *rawStorage.Service
}

// Service returns the result of the fill function if it's never been
// called before for the given name (which is assumed to be an API
// service name, like "directions"). If it has already been cached, the fill
// func is not run.
// It's safe for concurrent use by multiple goroutines.
func Service(ctx context.Context, name string, fill func(*http.Client) interface{}) interface{} {
	return mc(ctx).service(name, fill)
}

func (c *mapsContext) service(name string, fill func(*http.Client) interface{}) interface{} {
	c.mu.Lock()
	defer c.mu.Unlock()

	if c.svc == nil {
		c.svc = make(map[string]interface{})
	} else if v, ok := c.svc[name]; ok {
		return v
	}
	v := fill(c.HTTPClient)
	c.svc[name] = v
	return v
}

// Transport is an http.RoundTripper that appends
// Google Cloud client's user-agent to the original
// request's user-agent header.
type Transport struct {
	// Base represents the actual http.RoundTripper
	// the requests will be delegated to.
	Base http.RoundTripper
}

// RoundTrip appends a user-agent to the existing user-agent
// header and delegates the request to the base http.RoundTripper.
func (t *Transport) RoundTrip(req *http.Request) (*http.Response, error) {
	req = cloneRequest(req)
	ua := req.Header.Get("User-Agent")
	if ua == "" {
		ua = userAgent
	} else {
		ua = fmt.Sprintf("%s;%s", ua, userAgent)
	}
	req.Header.Set("User-Agent", ua)
	return t.Base.RoundTrip(req)
}

// cloneRequest returns a clone of the provided *http.Request.
// The clone is a shallow copy of the struct and its Header map.
func cloneRequest(r *http.Request) *http.Request {
	// shallow copy of the struct
	r2 := new(http.Request)
	*r2 = *r
	// deep copy of the Header
	r2.Header = make(http.Header)
	for k, s := range r.Header {
		r2.Header[k] = s
	}
	return r2
}

// APIKey retrieval for mapsContext
func APIKey(ctx context.Context) string {
	return mc(ctx).APIKey
}

// HTTPClient retrieval for mapsContext
func HTTPClient(ctx context.Context) *http.Client {
	return mc(ctx).HTTPClient
}

// BaseURL retrieval for mapsContext
func BaseURL(ctx context.Context) string {
	return mc(ctx).BaseURL
}

// RoadsBaseURL retrieval for mapsContext
func RoadsBaseURL(ctx context.Context) string {
	return mc(ctx).RoadsBaseURL
}

// mc returns the internal *mapsContext (cc) state for a context.Context.
// It panics if the user did it wrong.
func mc(ctx context.Context) *mapsContext {
	if c, ok := ctx.Value(contextKey{}).(*mapsContext); ok {
		return c
	}
	panic("invalid context.Context type; it should be created with maps.NewContext")
}
<commit_msg>Making userAgent consistent with other libs<commit_after>// Copyright 2015 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// Package internal provides support for the maps packages.
//
// Users should not import this package directly.
package internal

import (
	"fmt"
	"net/http"
	"strings"
	"sync"

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

type contextKey struct{}

// WithContext is the internal constructor for mapsContext.
func WithContext(parent context.Context, apiKey string, c *http.Client, baseURL, roadsBaseURL string) context.Context {
	if c == nil {
		panic("nil *http.Client passed to WithContext")
	}
	if apiKey == "" {
		panic("empty API Key passed to WithContext")
	}
	if !strings.HasPrefix(apiKey, "AIza") {
		panic("invalid API Key passed to WithContext")
	}
	if baseURL == "" {
		panic("invalid base URL passed to WithContext")
	}
	return context.WithValue(parent, contextKey{}, &mapsContext{
		APIKey:       apiKey,
		HTTPClient:   c,
		BaseURL:      baseURL,
		RoadsBaseURL: roadsBaseURL,
	})
}

const userAgent = "GoogleGeoApiClientGo/0.1"

type mapsContext struct {
	APIKey       string
	HTTPClient   *http.Client
	BaseURL      string
	RoadsBaseURL string

	mu  sync.Mutex             // guards svc
	svc map[string]interface{} // e.g. "storage" => *rawStorage.Service
}

// Service returns the result of the fill function if it's never been
// called before for the given name (which is assumed to be an API
// service name, like "directions"). If it has already been cached, the fill
// func is not run.
// It's safe for concurrent use by multiple goroutines.
func Service(ctx context.Context, name string, fill func(*http.Client) interface{}) interface{} {
	return mc(ctx).service(name, fill)
}

func (c *mapsContext) service(name string, fill func(*http.Client) interface{}) interface{} {
	c.mu.Lock()
	defer c.mu.Unlock()

	if c.svc == nil {
		c.svc = make(map[string]interface{})
	} else if v, ok := c.svc[name]; ok {
		return v
	}
	v := fill(c.HTTPClient)
	c.svc[name] = v
	return v
}

// Transport is an http.RoundTripper that appends
// Google Cloud client's user-agent to the original
// request's user-agent header.
type Transport struct {
	// Base represents the actual http.RoundTripper
	// the requests will be delegated to.
	Base http.RoundTripper
}

// RoundTrip appends a user-agent to the existing user-agent
// header and delegates the request to the base http.RoundTripper.
func (t *Transport) RoundTrip(req *http.Request) (*http.Response, error) {
	req = cloneRequest(req)
	ua := req.Header.Get("User-Agent")
	if ua == "" {
		ua = userAgent
	} else {
		ua = fmt.Sprintf("%s;%s", ua, userAgent)
	}
	req.Header.Set("User-Agent", ua)
	return t.Base.RoundTrip(req)
}

// cloneRequest returns a clone of the provided *http.Request.
// The clone is a shallow copy of the struct and its Header map.
func cloneRequest(r *http.Request) *http.Request {
	// shallow copy of the struct
	r2 := new(http.Request)
	*r2 = *r
	// deep copy of the Header
	r2.Header = make(http.Header)
	for k, s := range r.Header {
		r2.Header[k] = s
	}
	return r2
}

// APIKey retrieval for mapsContext
func APIKey(ctx context.Context) string {
	return mc(ctx).APIKey
}

// HTTPClient retrieval for mapsContext
func HTTPClient(ctx context.Context) *http.Client {
	return mc(ctx).HTTPClient
}

// BaseURL retrieval for mapsContext
func BaseURL(ctx context.Context) string {
	return mc(ctx).BaseURL
}

// RoadsBaseURL retrieval for mapsContext
func RoadsBaseURL(ctx context.Context) string {
	return mc(ctx).RoadsBaseURL
}

// mc returns the internal *mapsContext (cc) state for a context.Context.
// It panics if the user did it wrong.
func mc(ctx context.Context) *mapsContext {
	if c, ok := ctx.Value(contextKey{}).(*mapsContext); ok {
		return c
	}
	panic("invalid context.Context type; it should be created with maps.NewContext")
}
<|endoftext|>


<commit_before>// Copyright 2011 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// +build windows

package winfsnotify

import (
	"os"
	"testing"
	"time"
)

func expect(t *testing.T, eventstream <-chan *Event, name string, mask uint32) {
	t.Logf(`expected: "%s": 0x%x`, name, mask)
	select {
	case event := <-eventstream:
		if event == nil {
			t.Fatal("nil event received")
		}
		t.Logf("received: %s", event)
		if event.Name != name || event.Mask != mask {
			t.Fatal("did not receive expected event")
		}
	case <-time.After(1 * time.Second):
		t.Fatal("timed out waiting for event")
	}
}

func TestNotifyEvents(t *testing.T) {
	watcher, err := NewWatcher()
	if err != nil {
		t.Fatalf("NewWatcher() failed: %s", err)
	}

	testDir := "TestNotifyEvents.testdirectory"
	testFile := testDir + "/TestNotifyEvents.testfile"
	testFile2 := testFile + ".new"
	const mask = FS_ALL_EVENTS & ^(FS_ATTRIB|FS_CLOSE) | FS_IGNORED

	// Add a watch for testDir
	os.RemoveAll(testDir)
	if err = os.Mkdir(testDir, 0777); err != nil {
		t.Fatalf("Failed to create test directory: %s", err)
	}
	defer os.RemoveAll(testDir)
	err = watcher.AddWatch(testDir, mask)
	if err != nil {
		t.Fatalf("Watcher.Watch() failed: %s", err)
	}

	// Receive errors on the error channel on a separate goroutine
	go func() {
		for err := range watcher.Error {
			t.Fatalf("error received: %s", err)
		}
	}()

	// Create a file
	file, err := os.Create(testFile)
	if err != nil {
		t.Fatalf("creating test file failed: %s", err)
	}
	expect(t, watcher.Event, testFile, FS_CREATE)

	err = watcher.AddWatch(testFile, mask)
	if err != nil {
		t.Fatalf("Watcher.Watch() failed: %s", err)
	}

	if _, err = file.WriteString("hello, world"); err != nil {
		t.Fatalf("failed to write to test file: %s", err)
	}
	if err = file.Close(); err != nil {
		t.Fatalf("failed to close test file: %s", err)
	}
	expect(t, watcher.Event, testFile, FS_MODIFY)
	expect(t, watcher.Event, testFile, FS_MODIFY)

	if err = os.Rename(testFile, testFile2); err != nil {
		t.Fatalf("failed to rename test file: %s", err)
	}
	expect(t, watcher.Event, testFile, FS_MOVED_FROM)
	expect(t, watcher.Event, testFile2, FS_MOVED_TO)
	expect(t, watcher.Event, testFile, FS_MOVE_SELF)

	if err = os.RemoveAll(testDir); err != nil {
		t.Fatalf("failed to remove test directory: %s", err)
	}
	expect(t, watcher.Event, testFile2, FS_DELETE_SELF)
	expect(t, watcher.Event, testFile2, FS_IGNORED)
	expect(t, watcher.Event, testFile2, FS_DELETE)
	expect(t, watcher.Event, testDir, FS_DELETE_SELF)
	expect(t, watcher.Event, testDir, FS_IGNORED)

	t.Log("calling Close()")
	if err = watcher.Close(); err != nil {
		t.Fatalf("failed to close watcher: %s", err)
	}
}

func TestNotifyClose(t *testing.T) {
	watcher, _ := NewWatcher()
	watcher.Close()

	done := false
	go func() {
		watcher.Close()
		done = true
	}()

	time.Sleep(50 * time.Millisecond)
	if !done {
		t.Fatal("double Close() test failed: second Close() call didn't return")
	}

	dir, err := ioutil.TempDir("", "wininotify")
	if err != nil {
		t.Fatalf("TempDir failed: %s", err)
	}
	defer os.RemoveAll(dir)

	err = watcher.Watch(dir)
	if err == nil {
		t.Fatal("expected error on Watch() after Close(), got nil")
	}
}
<commit_msg>windows: fix build<commit_after>// Copyright 2011 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// +build windows

package winfsnotify

import (
	"io/ioutil"
	"os"
	"testing"
	"time"
)

func expect(t *testing.T, eventstream <-chan *Event, name string, mask uint32) {
	t.Logf(`expected: "%s": 0x%x`, name, mask)
	select {
	case event := <-eventstream:
		if event == nil {
			t.Fatal("nil event received")
		}
		t.Logf("received: %s", event)
		if event.Name != name || event.Mask != mask {
			t.Fatal("did not receive expected event")
		}
	case <-time.After(1 * time.Second):
		t.Fatal("timed out waiting for event")
	}
}

func TestNotifyEvents(t *testing.T) {
	watcher, err := NewWatcher()
	if err != nil {
		t.Fatalf("NewWatcher() failed: %s", err)
	}

	testDir := "TestNotifyEvents.testdirectory"
	testFile := testDir + "/TestNotifyEvents.testfile"
	testFile2 := testFile + ".new"
	const mask = FS_ALL_EVENTS & ^(FS_ATTRIB|FS_CLOSE) | FS_IGNORED

	// Add a watch for testDir
	os.RemoveAll(testDir)
	if err = os.Mkdir(testDir, 0777); err != nil {
		t.Fatalf("Failed to create test directory: %s", err)
	}
	defer os.RemoveAll(testDir)
	err = watcher.AddWatch(testDir, mask)
	if err != nil {
		t.Fatalf("Watcher.Watch() failed: %s", err)
	}

	// Receive errors on the error channel on a separate goroutine
	go func() {
		for err := range watcher.Error {
			t.Fatalf("error received: %s", err)
		}
	}()

	// Create a file
	file, err := os.Create(testFile)
	if err != nil {
		t.Fatalf("creating test file failed: %s", err)
	}
	expect(t, watcher.Event, testFile, FS_CREATE)

	err = watcher.AddWatch(testFile, mask)
	if err != nil {
		t.Fatalf("Watcher.Watch() failed: %s", err)
	}

	if _, err = file.WriteString("hello, world"); err != nil {
		t.Fatalf("failed to write to test file: %s", err)
	}
	if err = file.Close(); err != nil {
		t.Fatalf("failed to close test file: %s", err)
	}
	expect(t, watcher.Event, testFile, FS_MODIFY)
	expect(t, watcher.Event, testFile, FS_MODIFY)

	if err = os.Rename(testFile, testFile2); err != nil {
		t.Fatalf("failed to rename test file: %s", err)
	}
	expect(t, watcher.Event, testFile, FS_MOVED_FROM)
	expect(t, watcher.Event, testFile2, FS_MOVED_TO)
	expect(t, watcher.Event, testFile, FS_MOVE_SELF)

	if err = os.RemoveAll(testDir); err != nil {
		t.Fatalf("failed to remove test directory: %s", err)
	}
	expect(t, watcher.Event, testFile2, FS_DELETE_SELF)
	expect(t, watcher.Event, testFile2, FS_IGNORED)
	expect(t, watcher.Event, testFile2, FS_DELETE)
	expect(t, watcher.Event, testDir, FS_DELETE_SELF)
	expect(t, watcher.Event, testDir, FS_IGNORED)

	t.Log("calling Close()")
	if err = watcher.Close(); err != nil {
		t.Fatalf("failed to close watcher: %s", err)
	}
}

func TestNotifyClose(t *testing.T) {
	watcher, _ := NewWatcher()
	watcher.Close()

	done := false
	go func() {
		watcher.Close()
		done = true
	}()

	time.Sleep(50 * time.Millisecond)
	if !done {
		t.Fatal("double Close() test failed: second Close() call didn't return")
	}

	dir, err := ioutil.TempDir("", "wininotify")
	if err != nil {
		t.Fatalf("TempDir failed: %s", err)
	}
	defer os.RemoveAll(dir)

	err = watcher.Watch(dir)
	if err == nil {
		t.Fatal("expected error on Watch() after Close(), got nil")
	}
}
<|endoftext|>


<commit_before>package chess

import (
	"errors"
	"fmt"
	"io"
	"io/ioutil"
)

const (
	startFEN = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1"
)

// A Outcome is the result of a game.
type Outcome string

const (
	// NoOutcome indicates that a game is in progress or ended without a result.
	NoOutcome Outcome = "*"
	// WhiteWon indicates that white won the game.
	WhiteWon Outcome = "1-0"
	// BlackWon indicates that black won the game.
	BlackWon Outcome = "0-1"
	// Draw indicates that game was a draw.
	Draw Outcome = "1/2-1/2"
)

// A Method is the way in which the outcome occured.
type Method int

const (
	// NoMethod indicates that an outcome hasn't occured or that the method can't be determined.
	NoMethod Method = iota
	// Checkmate indicates that the game was won by a playing being checkmated.
	Checkmate
	// Resignation indicates that the game was won by player resigning.
	Resignation
	// DrawOffer indicates that the game was drawn by player agreeing to a draw offer.
	DrawOffer
	// Stalemate indicates that the game was drawn by player being stalemated.
	Stalemate
	// ThreefoldRepetition indicates that the game was drawn when the game
	// state was repeated three times and a player requested a draw.
	ThreefoldRepetition
	// FivefoldRepetition indicates that the game was automatically drawn
	// by the game state being repeated five times.
	FivefoldRepetition
	// FiftyMoveRule indicates that the game was drawn by the half
	// move clock being fifty or greater when a player requested a draw.
	FiftyMoveRule
	// SeventyFiveMoveRule indicates that the game was automatically drawn
	// when the half move clock was seventy five or greater.
	SeventyFiveMoveRule
	// InsufficientMaterial indicates that the game was automatically drawn
	// because there was insufficent material for checkmate.
	InsufficientMaterial
)

// TagPair represents metadata in a key value pairing.
type TagPair struct {
	Key   string
	Value string
}

// A Game represents a single chess game.
type Game struct {
	tagPairs []*TagPair
	moves    []*Move
	state    *GameState
	outcome  Outcome
	method   Method
}

// PGN takes a reader and returns a function that updates
// the game to reflect the PGN data.  The returned function
// is designed to be used in the NewGame constructor.  An
// error is returned if there is a problem parsing the PGN
// data.
func PGN(r io.Reader) (func(*Game), error) {
	b, err := ioutil.ReadAll(r)
	if err != nil {
		return nil, err
	}
	game, err := decodePGN(string(b))
	if err != nil {
		return nil, err
	}
	return func(g *Game) {
		g.copy(game)
	}, nil
}

// FEN takes a reader and returns a function that updates
// the game to reflect the FEN data.  Since FEN doesn't include
// prior moves, the move list will be empty.  The returned
// function is designed to be used in the NewGame constructor.
// An error is returned if there is a problem parsing the FEN data.
func FEN(r io.Reader) (func(*Game), error) {
	b, err := ioutil.ReadAll(r)
	if err != nil {
		return nil, err
	}
	state, err := decodeFEN(string(b))
	if err != nil {
		return nil, err
	}
	return func(g *Game) {
		g.updateState(state)
	}, nil
}

// TagPairs returns a function that sets the tag pairs
// to the given value.  The returned function is designed
// to be used in the NewGame constructor.
func TagPairs(tagPairs []*TagPair) func(*Game) {
	return func(g *Game) {
		g.tagPairs = append([]*TagPair(nil), tagPairs...)
	}
}

// NewGame defaults to returning a game in the standard
// opening position.  Options can be given to change
// the game's initial state.
func NewGame(options ...func(*Game)) *Game {
	state, _ := decodeFEN(startFEN)
	game := &Game{
		moves:   []*Move{},
		state:   state,
		outcome: NoOutcome,
		method:  NoMethod,
	}
	for _, f := range options {
		f(game)
	}
	return game
}

// Move updates the game with the given move.  An error is returned
// if the move is invalid or the game has already been completed.
func (g *Game) Move(m *Move) error {
	if g.outcome != NoOutcome {
		return fmt.Errorf("chess: invalid move %s game %s by %s", m, g.Outcome(), g.Method())
	}
	if !m.isValid() {
		return fmt.Errorf("chess: invalid move %s", m)
	}
	g.moves = append(g.moves, m)
	g.updateState(m.postMoveState())
	return nil
}

// MoveSq moves the piece at s1 to s2, applies the given
// promotion, and updates the game.  An error is returned
// if the move is invalid or the game has already been completed.
func (g *Game) MoveSq(s1, s2 *Square, promo PieceType) error {
	move := &Move{
		s1:    s1,
		s2:    s2,
		promo: promo,
		state: g.state,
	}
	return g.Move(move)
}

// MoveAlg decodes the given string in algebraic notation
// and calls the Move function.  An error is returned if
// the move can't be decoded, the move is invalid, or the
// game has already been completed.
func (g *Game) MoveAlg(alg string) error {
	move, err := decodeMove(g.State(), alg)
	if err != nil {
		return err
	}
	return g.MoveSq(move.S1(), move.S2(), move.Promo())
}

// ValidMoves returns a list of valid moves in the
// current position.
func (g *Game) ValidMoves() []*Move {
	return g.state.validMoves()
}

// States returns the state history of the game.
func (g *Game) States() []*GameState {
	states := []*GameState{}
	for _, m := range g.moves {
		states = append(states, m.PreMoveState())
	}
	states = append(states, g.state)
	return states
}

// Moves returns the move history of the game.
func (g *Game) Moves() []*Move {
	return append([]*Move(nil), g.moves...)
}

// TagPairs returns the game's tag pairs.
func (g *Game) TagPairs() []*TagPair {
	return append([]*TagPair(nil), g.tagPairs...)
}

// State returns the game's current state.
func (g *Game) State() *GameState {
	return g.state
}

// Outcome returns the game outcome.
func (g *Game) Outcome() Outcome {
	return g.outcome
}

// Method returns the method in which the outcome occured.
func (g *Game) Method() Method {
	return g.method
}

// TakeBack returns a copy of the game with the most recent
// n moves removed.  If n is greater than the number of moves
// or is negative then the game is set back to its initial state.
func (g *Game) TakeBack(n int) *Game {
	cp := &Game{}
	cp.copy(g)
	if len(cp.moves) == 0 {
		return cp
	}
	var state *GameState
	if len(cp.moves) < n || n < 0 {
		state = cp.moves[0].PreMoveState()
		cp.moves = []*Move{}
	} else {
		i := len(cp.moves) - n
		state = cp.moves[i].PreMoveState()
		cp.moves = g.moves[:i]
	}
	cp.updateState(state)
	return cp
}

// FEN returns the FEN notation of the current state.
func (g *Game) FEN() string {
	return g.State().String()
}

// String implements the fmt.Stringer interface and returns
// the game's PGN.
func (g *Game) String() string {
	return encodePGN(g)
}

// MarshalText implements the encoding.TextMarshaler interface and
// encodes the game's PGN.
func (g *Game) MarshalText() (text []byte, err error) {
	return []byte(encodePGN(g)), nil
}

// UnmarshalText implements the encoding.TextUnarshaler interface and
// assumes the data is in the PGN format.
func (g *Game) UnmarshalText(text []byte) error {
	game, err := decodePGN(string(text))
	if err != nil {
		return err
	}
	g.copy(game)
	return nil
}

// Draw attempts to draw the game by the given method.  If the
// method is valid, then the game is updated to a draw by that
// method.  If the method isn't valid then an error is returned.
func (g *Game) Draw(method Method) error {
	switch method {
	case ThreefoldRepetition:
		if g.numOfRepitions() < 3 {
			return errors.New("chess: draw by ThreefoldRepetition requires at least three repetitions of the current board state")
		}
	case FiftyMoveRule:
		if g.state.halfMoveClock < 50 {
			return fmt.Errorf("chess: draw by FiftyMoveRule requires the half move clock to be at 50 or greater but is %d", g.state.halfMoveClock)
		}
	case DrawOffer:
	default:
		return fmt.Errorf("chess: unsupported draw method %s", method)
	}
	g.outcome = Draw
	g.method = method
	return nil
}

// Resign resigns the game for the given color.  If the game has
// already been completed then the game is not updated.
func (g *Game) Resign(color Color) {
	if g.outcome != NoOutcome || color == NoColor {
		return
	}
	if color == White {
		g.outcome = BlackWon
	} else {
		g.outcome = WhiteWon
	}
	g.method = Resignation
}

func (g *Game) copy(game *Game) {
	g.tagPairs = game.tagPairs
	g.moves = game.moves
	g.state = game.state
	g.outcome = game.outcome
	g.method = game.method
}

func (g *Game) updateState(state *GameState) {
	g.state = state
	outcome, method := state.getOutcome()
	g.outcome = outcome
	g.method = method

	// five fold rep creates automatic draw
	if g.numOfRepitions() >= 5 {
		g.outcome = Draw
		g.method = FivefoldRepetition
	}

	// 75 move rule creates automatic draw
	if g.state.halfMoveClock >= 75 && g.method != Checkmate {
		g.outcome = Draw
		g.method = SeventyFiveMoveRule
	}

	// insufficent material creates automatic draw
	if !g.state.board.hasSufficientMaterial() {
		g.outcome = Draw
		g.method = InsufficientMaterial
	}
}

func (g *Game) numOfRepitions() int {
	count := 0
	for _, gs := range g.States() {
		if g.state.samePosition(gs) {
			count++
		}
	}
	return count
}
<commit_msg>added method on game to return the list of eligible drawing methods<commit_after>package chess

import (
	"errors"
	"fmt"
	"io"
	"io/ioutil"
)

const (
	startFEN = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1"
)

// A Outcome is the result of a game.
type Outcome string

const (
	// NoOutcome indicates that a game is in progress or ended without a result.
	NoOutcome Outcome = "*"
	// WhiteWon indicates that white won the game.
	WhiteWon Outcome = "1-0"
	// BlackWon indicates that black won the game.
	BlackWon Outcome = "0-1"
	// Draw indicates that game was a draw.
	Draw Outcome = "1/2-1/2"
)

// A Method is the way in which the outcome occured.
type Method int

const (
	// NoMethod indicates that an outcome hasn't occured or that the method can't be determined.
	NoMethod Method = iota
	// Checkmate indicates that the game was won by a playing being checkmated.
	Checkmate
	// Resignation indicates that the game was won by player resigning.
	Resignation
	// DrawOffer indicates that the game was drawn by player agreeing to a draw offer.
	DrawOffer
	// Stalemate indicates that the game was drawn by player being stalemated.
	Stalemate
	// ThreefoldRepetition indicates that the game was drawn when the game
	// state was repeated three times and a player requested a draw.
	ThreefoldRepetition
	// FivefoldRepetition indicates that the game was automatically drawn
	// by the game state being repeated five times.
	FivefoldRepetition
	// FiftyMoveRule indicates that the game was drawn by the half
	// move clock being fifty or greater when a player requested a draw.
	FiftyMoveRule
	// SeventyFiveMoveRule indicates that the game was automatically drawn
	// when the half move clock was seventy five or greater.
	SeventyFiveMoveRule
	// InsufficientMaterial indicates that the game was automatically drawn
	// because there was insufficent material for checkmate.
	InsufficientMaterial
)

// TagPair represents metadata in a key value pairing.
type TagPair struct {
	Key   string
	Value string
}

// A Game represents a single chess game.
type Game struct {
	tagPairs []*TagPair
	moves    []*Move
	state    *GameState
	outcome  Outcome
	method   Method
}

// PGN takes a reader and returns a function that updates
// the game to reflect the PGN data.  The returned function
// is designed to be used in the NewGame constructor.  An
// error is returned if there is a problem parsing the PGN
// data.
func PGN(r io.Reader) (func(*Game), error) {
	b, err := ioutil.ReadAll(r)
	if err != nil {
		return nil, err
	}
	game, err := decodePGN(string(b))
	if err != nil {
		return nil, err
	}
	return func(g *Game) {
		g.copy(game)
	}, nil
}

// FEN takes a reader and returns a function that updates
// the game to reflect the FEN data.  Since FEN doesn't include
// prior moves, the move list will be empty.  The returned
// function is designed to be used in the NewGame constructor.
// An error is returned if there is a problem parsing the FEN data.
func FEN(r io.Reader) (func(*Game), error) {
	b, err := ioutil.ReadAll(r)
	if err != nil {
		return nil, err
	}
	state, err := decodeFEN(string(b))
	if err != nil {
		return nil, err
	}
	return func(g *Game) {
		g.updateState(state)
	}, nil
}

// TagPairs returns a function that sets the tag pairs
// to the given value.  The returned function is designed
// to be used in the NewGame constructor.
func TagPairs(tagPairs []*TagPair) func(*Game) {
	return func(g *Game) {
		g.tagPairs = append([]*TagPair(nil), tagPairs...)
	}
}

// NewGame defaults to returning a game in the standard
// opening position.  Options can be given to change
// the game's initial state.
func NewGame(options ...func(*Game)) *Game {
	state, _ := decodeFEN(startFEN)
	game := &Game{
		moves:   []*Move{},
		state:   state,
		outcome: NoOutcome,
		method:  NoMethod,
	}
	for _, f := range options {
		f(game)
	}
	return game
}

// Move updates the game with the given move.  An error is returned
// if the move is invalid or the game has already been completed.
func (g *Game) Move(m *Move) error {
	if g.outcome != NoOutcome {
		return fmt.Errorf("chess: invalid move %s game %s by %s", m, g.Outcome(), g.Method())
	}
	if !m.isValid() {
		return fmt.Errorf("chess: invalid move %s", m)
	}
	g.moves = append(g.moves, m)
	g.updateState(m.postMoveState())
	return nil
}

// MoveSq moves the piece at s1 to s2, applies the given
// promotion, and updates the game.  An error is returned
// if the move is invalid or the game has already been completed.
func (g *Game) MoveSq(s1, s2 *Square, promo PieceType) error {
	move := &Move{
		s1:    s1,
		s2:    s2,
		promo: promo,
		state: g.state,
	}
	return g.Move(move)
}

// MoveAlg decodes the given string in algebraic notation
// and calls the Move function.  An error is returned if
// the move can't be decoded, the move is invalid, or the
// game has already been completed.
func (g *Game) MoveAlg(alg string) error {
	move, err := decodeMove(g.State(), alg)
	if err != nil {
		return err
	}
	return g.MoveSq(move.S1(), move.S2(), move.Promo())
}

// ValidMoves returns a list of valid moves in the
// current position.
func (g *Game) ValidMoves() []*Move {
	return g.state.validMoves()
}

// States returns the state history of the game.
func (g *Game) States() []*GameState {
	states := []*GameState{}
	for _, m := range g.moves {
		states = append(states, m.PreMoveState())
	}
	states = append(states, g.state)
	return states
}

// Moves returns the move history of the game.
func (g *Game) Moves() []*Move {
	return append([]*Move(nil), g.moves...)
}

// TagPairs returns the game's tag pairs.
func (g *Game) TagPairs() []*TagPair {
	return append([]*TagPair(nil), g.tagPairs...)
}

// State returns the game's current state.
func (g *Game) State() *GameState {
	return g.state
}

// Outcome returns the game outcome.
func (g *Game) Outcome() Outcome {
	return g.outcome
}

// Method returns the method in which the outcome occured.
func (g *Game) Method() Method {
	return g.method
}

// TakeBack returns a copy of the game with the most recent
// n moves removed.  If n is greater than the number of moves
// or is negative then the game is set back to its initial state.
func (g *Game) TakeBack(n int) *Game {
	cp := &Game{}
	cp.copy(g)
	if len(cp.moves) == 0 {
		return cp
	}
	var state *GameState
	if len(cp.moves) < n || n < 0 {
		state = cp.moves[0].PreMoveState()
		cp.moves = []*Move{}
	} else {
		i := len(cp.moves) - n
		state = cp.moves[i].PreMoveState()
		cp.moves = g.moves[:i]
	}
	cp.updateState(state)
	return cp
}

// FEN returns the FEN notation of the current state.
func (g *Game) FEN() string {
	return g.State().String()
}

// String implements the fmt.Stringer interface and returns
// the game's PGN.
func (g *Game) String() string {
	return encodePGN(g)
}

// MarshalText implements the encoding.TextMarshaler interface and
// encodes the game's PGN.
func (g *Game) MarshalText() (text []byte, err error) {
	return []byte(encodePGN(g)), nil
}

// UnmarshalText implements the encoding.TextUnarshaler interface and
// assumes the data is in the PGN format.
func (g *Game) UnmarshalText(text []byte) error {
	game, err := decodePGN(string(text))
	if err != nil {
		return err
	}
	g.copy(game)
	return nil
}

// Draw attempts to draw the game by the given method.  If the
// method is valid, then the game is updated to a draw by that
// method.  If the method isn't valid then an error is returned.
func (g *Game) Draw(method Method) error {
	switch method {
	case ThreefoldRepetition:
		if g.numOfRepitions() < 3 {
			return errors.New("chess: draw by ThreefoldRepetition requires at least three repetitions of the current board state")
		}
	case FiftyMoveRule:
		if g.state.halfMoveClock < 50 {
			return fmt.Errorf("chess: draw by FiftyMoveRule requires the half move clock to be at 50 or greater but is %d", g.state.halfMoveClock)
		}
	case DrawOffer:
	default:
		return fmt.Errorf("chess: unsupported draw method %s", method)
	}
	g.outcome = Draw
	g.method = method
	return nil
}

// Resign resigns the game for the given color.  If the game has
// already been completed then the game is not updated.
func (g *Game) Resign(color Color) {
	if g.outcome != NoOutcome || color == NoColor {
		return
	}
	if color == White {
		g.outcome = BlackWon
	} else {
		g.outcome = WhiteWon
	}
	g.method = Resignation
}

// EligibleDraws returns the draw methods that eligible for game's
// Draw method.
func (g *Game) EligibleDraws() []Method {
	draws := []Method{DrawOffer}
	if g.numOfRepitions() >= 3 {
		draws = append(draws, ThreefoldRepetition)
	}
	if g.state.halfMoveClock < 50 {
		draws = append(draws, FiftyMoveRule)
	}
	return draws
}

func (g *Game) copy(game *Game) {
	g.tagPairs = game.tagPairs
	g.moves = game.moves
	g.state = game.state
	g.outcome = game.outcome
	g.method = game.method
}

func (g *Game) updateState(state *GameState) {
	g.state = state
	outcome, method := state.getOutcome()
	g.outcome = outcome
	g.method = method

	// five fold rep creates automatic draw
	if g.numOfRepitions() >= 5 {
		g.outcome = Draw
		g.method = FivefoldRepetition
	}

	// 75 move rule creates automatic draw
	if g.state.halfMoveClock >= 75 && g.method != Checkmate {
		g.outcome = Draw
		g.method = SeventyFiveMoveRule
	}

	// insufficent material creates automatic draw
	if !g.state.board.hasSufficientMaterial() {
		g.outcome = Draw
		g.method = InsufficientMaterial
	}
}

func (g *Game) numOfRepitions() int {
	count := 0
	for _, gs := range g.States() {
		if g.state.samePosition(gs) {
			count++
		}
	}
	return count
}
<|endoftext|>


<commit_before>package jantar

import (
	"fmt"
	"math"
	"net/http"
	"net/url"
	"reflect"
	"regexp"
	"time"
)

/* TODO: allow custom cookie name */

type validation struct {
	rw        http.ResponseWriter
	hasErrors bool
	errors    map[string][]string
}

type validationError struct {
	validation *validation
	name       string
	index      int
}

func newvalidation(rw http.ResponseWriter) *validation {
	return &validation{rw, false, make(map[string][]string)}
}

func (v *validation) SaveErrors() {
	if v.hasErrors {
		values := url.Values{}
		for key, array := range v.errors {
			for _, val := range array {
				values.Add(key, val)
			}
		}

		http.SetCookie(v.rw, &http.Cookie{Name: "JANTAR_ERRORS", Value: values.Encode(), Secure: false, HttpOnly: true, Path: "/"})
	}
}

func (v *validation) HasErrors() bool {
	return v.hasErrors
}

func (v *validation) addError(name string, message string) *validationError {
	result := &validationError{v, name, -1}

	v.hasErrors = true
	v.errors[name] = append(v.errors[name], message)
	result.index = len(v.errors[name]) - 1

	return result
}

func (vr *validationError) Message(msg string) *validationError {
	if vr != nil && vr.index != -1 {
		vr.validation.errors[vr.name][vr.index] = msg
	}

	return vr
}

func (v *validation) Required(name string, obj interface{}) *validationError {
	valid := false
	defaultMessage := "Required"

	switch value := obj.(type) {
	case nil:
		valid = false
	case int:
		valid = value != 0
	case string:
		valid = len(value) > 0
	case time.Time:
		valid = value.IsZero()
	default:
		v := reflect.ValueOf(value)
		if v.Kind() == reflect.Slice {
			valid = v.Len() > 0
		}
	}

	if !valid {
		return v.addError(name, defaultMessage)
	}

	return nil
}

func (v *validation) Min(name string, obj interface{}, min int) *validationError {
	valid := false
	defaultMessage := fmt.Sprintf("Must be larger than %d", min)

	switch value := obj.(type) {
	case nil:
		valid = false
	case int:
		valid = value >= min
	case string:
		valid = len(value) >= min
	default:
		v := reflect.ValueOf(obj)
		if v.Kind() == reflect.Slice {
			valid = v.Len() >= min
		}
	}

	if !valid {
		return v.addError(name, defaultMessage)
	}

	return nil
}

func (v *validation) Max(name string, obj interface{}, max int) *validationError {
	valid := false
	defaultMessage := fmt.Sprintf("Must be smaller than %d", max)

	switch value := obj.(type) {
	case nil:
		valid = false
	case int:
		valid = value <= max
	case string:
		valid = len(value) <= max
	default:
		v := reflect.ValueOf(obj)
		if v.Kind() == reflect.Slice {
			valid = v.Len() <= max
		}
	}

	if !valid {
		return v.addError(name, defaultMessage)
	}

	return nil
}

func (v *validation) MinMax(name string, obj interface{}, min int, max int) *validationError {
	valid := false
	defaultMessage := fmt.Sprintf("Must be larger %d and smaller %d", min, max)

	switch value := obj.(type) {
	case nil:
		valid = false
	case int:
		valid = value >= min && value <= max
	case string:
		valid = len(value) >= min && len(value) <= max
	default:
		v := reflect.ValueOf(obj)
		if v.Kind() == reflect.Slice {
			valid = v.Len() >= min && v.Len() <= max
		}
	}

	if !valid {
		return v.addError(name, defaultMessage)
	}

	return nil
}

func (v *validation) Length(name string, obj interface{}, length int) *validationError {
	valid := false
	defaultMessage := fmt.Sprintf("Must be %d symbols long", length)

	switch value := obj.(type) {
	case nil:
		valid = false
	case int:
		valid = int(math.Ceil(math.Log10(float64(value)))) == length
	case string:
		valid = len(value) == length
	default:
		v := reflect.ValueOf(obj)
		if v.Kind() == reflect.Slice {
			valid = v.Len() == length
		}
	}

	if !valid {
		return v.addError(name, defaultMessage)
	}

	return nil
}

func (v *validation) Equals(name string, obj interface{}, obj2 interface{}) *validationError {
	defaultMessage := fmt.Sprintf("%v does not equal %v", obj, obj2)

	if obj == nil || obj2 == nil || !reflect.DeepEqual(obj, obj2) {
		return v.addError(name, defaultMessage)
	}

	return nil
}

func (v *validation) MatchRegex(name string, obj interface{}, pattern string) *validationError {
	valid := true
	defaultMessage := fmt.Sprintf("Must match regex %s", pattern)

	if obj == nil {
		valid = false
	} else {
		match, err := regexp.MatchString(pattern, reflect.ValueOf(obj).String())
		if err != nil || !match {
			valid = false
		}
	}

	if !valid {
		return v.addError(name, defaultMessage)
	}

	return nil
}

func (v *validation) Custom(name string, match bool, message string) *validationError {
	if match {
		return v.addError(name, message)
	}

	return nil
}
<commit_msg>fixed typo in validation.go<commit_after>package jantar

import (
	"fmt"
	"math"
	"net/http"
	"net/url"
	"reflect"
	"regexp"
	"time"
)

/* TODO: allow custom cookie name */

type validation struct {
	rw        http.ResponseWriter
	hasErrors bool
	errors    map[string][]string
}

type validationError struct {
	validation *validation
	name       string
	index      int
}

func newValidation(rw http.ResponseWriter) *validation {
	return &validation{rw, false, make(map[string][]string)}
}

func (v *validation) SaveErrors() {
	if v.hasErrors {
		values := url.Values{}
		for key, array := range v.errors {
			for _, val := range array {
				values.Add(key, val)
			}
		}

		http.SetCookie(v.rw, &http.Cookie{Name: "JANTAR_ERRORS", Value: values.Encode(), Secure: false, HttpOnly: true, Path: "/"})
	}
}

func (v *validation) HasErrors() bool {
	return v.hasErrors
}

func (v *validation) addError(name string, message string) *validationError {
	result := &validationError{v, name, -1}

	v.hasErrors = true
	v.errors[name] = append(v.errors[name], message)
	result.index = len(v.errors[name]) - 1

	return result
}

func (vr *validationError) Message(msg string) *validationError {
	if vr != nil && vr.index != -1 {
		vr.validation.errors[vr.name][vr.index] = msg
	}

	return vr
}

func (v *validation) Required(name string, obj interface{}) *validationError {
	valid := false
	defaultMessage := "Required"

	switch value := obj.(type) {
	case nil:
		valid = false
	case int:
		valid = value != 0
	case string:
		valid = len(value) > 0
	case time.Time:
		valid = value.IsZero()
	default:
		v := reflect.ValueOf(value)
		if v.Kind() == reflect.Slice {
			valid = v.Len() > 0
		}
	}

	if !valid {
		return v.addError(name, defaultMessage)
	}

	return nil
}

func (v *validation) Min(name string, obj interface{}, min int) *validationError {
	valid := false
	defaultMessage := fmt.Sprintf("Must be larger than %d", min)

	switch value := obj.(type) {
	case nil:
		valid = false
	case int:
		valid = value >= min
	case string:
		valid = len(value) >= min
	default:
		v := reflect.ValueOf(obj)
		if v.Kind() == reflect.Slice {
			valid = v.Len() >= min
		}
	}

	if !valid {
		return v.addError(name, defaultMessage)
	}

	return nil
}

func (v *validation) Max(name string, obj interface{}, max int) *validationError {
	valid := false
	defaultMessage := fmt.Sprintf("Must be smaller than %d", max)

	switch value := obj.(type) {
	case nil:
		valid = false
	case int:
		valid = value <= max
	case string:
		valid = len(value) <= max
	default:
		v := reflect.ValueOf(obj)
		if v.Kind() == reflect.Slice {
			valid = v.Len() <= max
		}
	}

	if !valid {
		return v.addError(name, defaultMessage)
	}

	return nil
}

func (v *validation) MinMax(name string, obj interface{}, min int, max int) *validationError {
	valid := false
	defaultMessage := fmt.Sprintf("Must be larger %d and smaller %d", min, max)

	switch value := obj.(type) {
	case nil:
		valid = false
	case int:
		valid = value >= min && value <= max
	case string:
		valid = len(value) >= min && len(value) <= max
	default:
		v := reflect.ValueOf(obj)
		if v.Kind() == reflect.Slice {
			valid = v.Len() >= min && v.Len() <= max
		}
	}

	if !valid {
		return v.addError(name, defaultMessage)
	}

	return nil
}

func (v *validation) Length(name string, obj interface{}, length int) *validationError {
	valid := false
	defaultMessage := fmt.Sprintf("Must be %d symbols long", length)

	switch value := obj.(type) {
	case nil:
		valid = false
	case int:
		valid = int(math.Ceil(math.Log10(float64(value)))) == length
	case string:
		valid = len(value) == length
	default:
		v := reflect.ValueOf(obj)
		if v.Kind() == reflect.Slice {
			valid = v.Len() == length
		}
	}

	if !valid {
		return v.addError(name, defaultMessage)
	}

	return nil
}

func (v *validation) Equals(name string, obj interface{}, obj2 interface{}) *validationError {
	defaultMessage := fmt.Sprintf("%v does not equal %v", obj, obj2)

	if obj == nil || obj2 == nil || !reflect.DeepEqual(obj, obj2) {
		return v.addError(name, defaultMessage)
	}

	return nil
}

func (v *validation) MatchRegex(name string, obj interface{}, pattern string) *validationError {
	valid := true
	defaultMessage := fmt.Sprintf("Must match regex %s", pattern)

	if obj == nil {
		valid = false
	} else {
		match, err := regexp.MatchString(pattern, reflect.ValueOf(obj).String())
		if err != nil || !match {
			valid = false
		}
	}

	if !valid {
		return v.addError(name, defaultMessage)
	}

	return nil
}

func (v *validation) Custom(name string, match bool, message string) *validationError {
	if match {
		return v.addError(name, message)
	}

	return nil
}
<|endoftext|>


<commit_before>package messages

func HandleOIP041Edit(o Oip041, txid string, block int) error {

	return nil
}
<commit_msg>Adjust function signature<commit_after>package messages

import "database/sql"

func HandleOIP041Edit(o Oip041, txid string, block int, dbtx *sql.Tx) error {

	return nil
}
<|endoftext|>


<commit_before>package memio

import (
	"io"
	"testing"
)

func TestRead(t *testing.T) {
	data := []byte("Hello, World!")
	reader := Open(data)
	toRead := make([]byte, 5)
	if n, err := reader.Read(toRead); n != 5 {
		t.Errorf("expecting to read 5 bytes, read %d", n)
		return
	} else if err != nil {
		t.Errorf("got error: %q", err.Error())
		return
	} else if string(toRead) != "Hello" {
		t.Errorf("expecting %q, got %q", "Hello", string(toRead))
		return
	}
	if n, err := reader.Read(toRead); n != 5 {
		t.Errorf("expecting to read 5 bytes, read %d", n)
		return
	} else if err != nil {
		t.Errorf("got error: %q", err.Error())
		return
	} else if string(toRead) != ", Wor" {
		t.Errorf("expecting %q, got %q", ", Wor", string(toRead))
		return
	}
	if n, err := reader.Read(toRead); n != 3 {
		t.Errorf("expecting to read 3 bytes, read %d", n)
		return
	} else if err != nil {
		t.Errorf("got error: %q", err.Error())
		return
	} else if string(toRead) != "ld!or" {
		t.Errorf("expecting %q, got %q", "ld!or", string(toRead))
		return
	}
	if n, err := reader.Read(toRead); n != 0 {
		t.Errorf("expecting to read 0 bytes, read %d", n)
		return
	} else if err != io.EOF {
		t.Errorf("expecting EOF")
	}
	if pos, err := reader.Seek(2, 0); pos != 2 {
		t.Errorf("expected to be at postion 2, got %d", pos)
		return
	} else if err != nil {
		t.Errorf("got error: %q", err.Error())
		return
	} else if n, err := reader.Read(toRead); n != 5 {
		t.Errorf("expecting to read 5 bytes, read %d", n)
		return
	} else if err != nil {
		t.Errorf("got error: %q", err.Error())
		return
	} else if string(toRead) != "llo, " {
		t.Errorf("expecting %q, got %q", "llo, ", string(toRead))
		return
	}
	if pos, err := reader.Seek(2, 1); pos != 9 {
		t.Errorf("expected to be at postion 9, got %d", pos)
		return
	} else if err != nil {
		t.Errorf("got error: %q", err.Error())
		return
	} else if n, err := reader.Read(toRead); n != 4 {
		t.Errorf("expecting to read 4 bytes, read %d", n)
		return
	} else if err != nil {
		t.Errorf("got error: %q", err.Error())
		return
	} else if string(toRead) != "rld! " {
		t.Errorf("expecting %q, got %q", "rld! ", string(toRead))
		return
	}
	if pos, err := reader.Seek(6, 2); pos != 7 {
		t.Errorf("expected to be at postion 7, got %d", pos)
		return
	} else if err != nil {
		t.Errorf("got error: %q", err.Error())
		return
	} else if n, err := reader.Read(toRead); n != 5 {
		t.Errorf("expecting to read 5 bytes, read %d", n)
		return
	} else if err != nil {
		t.Errorf("got error: %q", err.Error())
		return
	} else if string(toRead) != "World" {
		t.Errorf("expecting %q, got %q", "World", string(toRead))
		return
	}
	if _, err := reader.Seek(1, 0); err != nil {
		t.Errorf("got error: %q", err.Error())
		return
	}
	reader.Close()
	_, err := reader.Seek(1, 0)
	if _, ok := err.(*Closed); !ok {
		t.Errorf("expecting close error")
		return
	}
	_, err = reader.Read(toRead)
	if _, ok := err.(*Closed); !ok {
		t.Errorf("expecting close error")
		return
	}
}

func TestWrite(t *testing.T) {
	data := []byte("Beep")
	writer := Create(&data)
	if n, err := writer.Write([]byte("J")); n != 1 {
		t.Errorf("expecting to write 1 byte, wrote %d", n)
		return
	} else if err != nil {
		t.Errorf("got error: %q", err.Error())
		return
	} else if string(data) != "Jeep" {
		t.Errorf("expecting %q, got %q", "Jeep", string(data))
		return
	}
	if n, err := writer.Write([]byte("ohn")); n != 3 {
		t.Errorf("expecting to write 3 bytes, wrote %d", n)
		return
	} else if err != nil {
		t.Errorf("got error: %q", err.Error())
		return
	} else if string(data) != "John" {
		t.Errorf("expecting %q, got %q", "John", string(data))
		return
	}
	if n, err := writer.Write([]byte("ny")); n != 2 {
		t.Errorf("expecting to write 2 bytes, wrote %d", n)
		return
	} else if err != nil {
		t.Errorf("got error: %q", err.Error())
		return
	} else if string(data) != "Johnny" {
		t.Errorf("expecting %q, got %q", "Johnny", string(data))
		return
	}
	if pos, err := writer.Seek(0, 0); pos != 0 {
		t.Errorf("expected to be at postion 0, got %d", pos)
	} else if err != nil {
		t.Errorf("got error: %q", err.Error())
		return
	} else if n, err := writer.Write([]byte("Edmund")); n != 6 {
		t.Errorf("expecting to write 6 bytes, wrote %d", n)
		return
	} else if err != nil {
		t.Errorf("got error: %q", err.Error())
		return
	} else if string(data) != "Edmund" {
		t.Errorf("expecting %q, got %q", "Edmund", string(data))
		return
	}
	if pos, err := writer.Seek(4, 2); pos != 2 {
		t.Errorf("expected to be at postion 0, got %d", pos)
	} else if err != nil {
		t.Errorf("got error: %q", err.Error())
		return
	} else if n, err := writer.Write([]byte("war")); n != 3 {
		t.Errorf("expecting to write 3 bytes, wrote %d", n)
		return
	} else if err != nil {
		t.Errorf("got error: %q", err.Error())
		return
	} else if string(data) != "Edward" {
		t.Errorf("expecting %q, got %q", "Edward", string(data))
		return
	}
	if pos, err := writer.Seek(1, 1); pos != 6 {
		t.Errorf("expected to be at postion 6, got %d", pos)
	} else if err != nil {
		t.Errorf("got error: %q", err.Error())
		return
	} else if n, err := writer.Write([]byte("o")); n != 1 {
		t.Errorf("expecting to write 1 bytes, wrote %d", n)
		return
	} else if err != nil {
		t.Errorf("got error: %q", err.Error())
		return
	} else if string(data) != "Edwardo" {
		t.Errorf("expecting %q, got %q", "Edwardo", string(data))
		return
	}
	writer.Close()
	_, err := writer.Seek(0, 0)
	if _, ok := err.(*Closed); !ok {
		t.Errorf("expecting close error")
		return
	}
	_, err = writer.Write([]byte("Beep"))
	if _, ok := err.(*Closed); !ok {
		t.Errorf("expecting close error")
		return
	}
}

func TestNewWrite(t *testing.T) {
	var data []byte
	writer := Create(&data)
	if n, err := writer.Write([]byte("Hello")); err != nil {
		t.Errorf("got error: %q", err.Error())
	} else if n != 5 {
		t.Errorf("expecting to write 5 bytes, wrote %d", n)
	} else if len(data) != 5 {
		t.Errorf("expecting buf to have 5 bytes, has %d", n)
	} else if string(data) != "Hello" {
		t.Errorf("expecting %q, got %q", "Hello", string(data))
	}
}
<commit_msg>Added simple type checking tests<commit_after>package memio

import (
	"io"
	"testing"
)

var (
	_ io.Reader     = new(readMem)
	_ io.Closer     = new(readMem)
	_ io.Seeker     = new(readMem)
	_ io.WriterTo   = new(readMem)
	_ io.ByteReader = new(readMem)
	_ io.ReaderAt   = new(readMem)

	_ io.Writer     = new(writeMem)
	_ io.Closer     = new(writeMem)
	_ io.Seeker     = new(writeMem)
	_ io.ReaderFrom = new(writeMem)
	_ io.ByteWriter = new(writeMem)
	_ io.WriterAt   = new(writeMem)
)

func TestRead(t *testing.T) {
	data := []byte("Hello, World!")
	reader := Open(data)
	toRead := make([]byte, 5)
	if n, err := reader.Read(toRead); n != 5 {
		t.Errorf("expecting to read 5 bytes, read %d", n)
		return
	} else if err != nil {
		t.Errorf("got error: %q", err.Error())
		return
	} else if string(toRead) != "Hello" {
		t.Errorf("expecting %q, got %q", "Hello", string(toRead))
		return
	}
	if n, err := reader.Read(toRead); n != 5 {
		t.Errorf("expecting to read 5 bytes, read %d", n)
		return
	} else if err != nil {
		t.Errorf("got error: %q", err.Error())
		return
	} else if string(toRead) != ", Wor" {
		t.Errorf("expecting %q, got %q", ", Wor", string(toRead))
		return
	}
	if n, err := reader.Read(toRead); n != 3 {
		t.Errorf("expecting to read 3 bytes, read %d", n)
		return
	} else if err != nil {
		t.Errorf("got error: %q", err.Error())
		return
	} else if string(toRead) != "ld!or" {
		t.Errorf("expecting %q, got %q", "ld!or", string(toRead))
		return
	}
	if n, err := reader.Read(toRead); n != 0 {
		t.Errorf("expecting to read 0 bytes, read %d", n)
		return
	} else if err != io.EOF {
		t.Errorf("expecting EOF")
	}
	if pos, err := reader.Seek(2, 0); pos != 2 {
		t.Errorf("expected to be at postion 2, got %d", pos)
		return
	} else if err != nil {
		t.Errorf("got error: %q", err.Error())
		return
	} else if n, err := reader.Read(toRead); n != 5 {
		t.Errorf("expecting to read 5 bytes, read %d", n)
		return
	} else if err != nil {
		t.Errorf("got error: %q", err.Error())
		return
	} else if string(toRead) != "llo, " {
		t.Errorf("expecting %q, got %q", "llo, ", string(toRead))
		return
	}
	if pos, err := reader.Seek(2, 1); pos != 9 {
		t.Errorf("expected to be at postion 9, got %d", pos)
		return
	} else if err != nil {
		t.Errorf("got error: %q", err.Error())
		return
	} else if n, err := reader.Read(toRead); n != 4 {
		t.Errorf("expecting to read 4 bytes, read %d", n)
		return
	} else if err != nil {
		t.Errorf("got error: %q", err.Error())
		return
	} else if string(toRead) != "rld! " {
		t.Errorf("expecting %q, got %q", "rld! ", string(toRead))
		return
	}
	if pos, err := reader.Seek(6, 2); pos != 7 {
		t.Errorf("expected to be at postion 7, got %d", pos)
		return
	} else if err != nil {
		t.Errorf("got error: %q", err.Error())
		return
	} else if n, err := reader.Read(toRead); n != 5 {
		t.Errorf("expecting to read 5 bytes, read %d", n)
		return
	} else if err != nil {
		t.Errorf("got error: %q", err.Error())
		return
	} else if string(toRead) != "World" {
		t.Errorf("expecting %q, got %q", "World", string(toRead))
		return
	}
	if _, err := reader.Seek(1, 0); err != nil {
		t.Errorf("got error: %q", err.Error())
		return
	}
	reader.Close()
	_, err := reader.Seek(1, 0)
	if _, ok := err.(*Closed); !ok {
		t.Errorf("expecting close error")
		return
	}
	_, err = reader.Read(toRead)
	if _, ok := err.(*Closed); !ok {
		t.Errorf("expecting close error")
		return
	}
}

func TestWrite(t *testing.T) {
	data := []byte("Beep")
	writer := Create(&data)
	if n, err := writer.Write([]byte("J")); n != 1 {
		t.Errorf("expecting to write 1 byte, wrote %d", n)
		return
	} else if err != nil {
		t.Errorf("got error: %q", err.Error())
		return
	} else if string(data) != "Jeep" {
		t.Errorf("expecting %q, got %q", "Jeep", string(data))
		return
	}
	if n, err := writer.Write([]byte("ohn")); n != 3 {
		t.Errorf("expecting to write 3 bytes, wrote %d", n)
		return
	} else if err != nil {
		t.Errorf("got error: %q", err.Error())
		return
	} else if string(data) != "John" {
		t.Errorf("expecting %q, got %q", "John", string(data))
		return
	}
	if n, err := writer.Write([]byte("ny")); n != 2 {
		t.Errorf("expecting to write 2 bytes, wrote %d", n)
		return
	} else if err != nil {
		t.Errorf("got error: %q", err.Error())
		return
	} else if string(data) != "Johnny" {
		t.Errorf("expecting %q, got %q", "Johnny", string(data))
		return
	}
	if pos, err := writer.Seek(0, 0); pos != 0 {
		t.Errorf("expected to be at postion 0, got %d", pos)
	} else if err != nil {
		t.Errorf("got error: %q", err.Error())
		return
	} else if n, err := writer.Write([]byte("Edmund")); n != 6 {
		t.Errorf("expecting to write 6 bytes, wrote %d", n)
		return
	} else if err != nil {
		t.Errorf("got error: %q", err.Error())
		return
	} else if string(data) != "Edmund" {
		t.Errorf("expecting %q, got %q", "Edmund", string(data))
		return
	}
	if pos, err := writer.Seek(4, 2); pos != 2 {
		t.Errorf("expected to be at postion 0, got %d", pos)
	} else if err != nil {
		t.Errorf("got error: %q", err.Error())
		return
	} else if n, err := writer.Write([]byte("war")); n != 3 {
		t.Errorf("expecting to write 3 bytes, wrote %d", n)
		return
	} else if err != nil {
		t.Errorf("got error: %q", err.Error())
		return
	} else if string(data) != "Edward" {
		t.Errorf("expecting %q, got %q", "Edward", string(data))
		return
	}
	if pos, err := writer.Seek(1, 1); pos != 6 {
		t.Errorf("expected to be at postion 6, got %d", pos)
	} else if err != nil {
		t.Errorf("got error: %q", err.Error())
		return
	} else if n, err := writer.Write([]byte("o")); n != 1 {
		t.Errorf("expecting to write 1 bytes, wrote %d", n)
		return
	} else if err != nil {
		t.Errorf("got error: %q", err.Error())
		return
	} else if string(data) != "Edwardo" {
		t.Errorf("expecting %q, got %q", "Edwardo", string(data))
		return
	}
	writer.Close()
	_, err := writer.Seek(0, 0)
	if _, ok := err.(*Closed); !ok {
		t.Errorf("expecting close error")
		return
	}
	_, err = writer.Write([]byte("Beep"))
	if _, ok := err.(*Closed); !ok {
		t.Errorf("expecting close error")
		return
	}
}

func TestNewWrite(t *testing.T) {
	var data []byte
	writer := Create(&data)
	if n, err := writer.Write([]byte("Hello")); err != nil {
		t.Errorf("got error: %q", err.Error())
	} else if n != 5 {
		t.Errorf("expecting to write 5 bytes, wrote %d", n)
	} else if len(data) != 5 {
		t.Errorf("expecting buf to have 5 bytes, has %d", n)
	} else if string(data) != "Hello" {
		t.Errorf("expecting %q, got %q", "Hello", string(data))
	}
}
<|endoftext|>


<commit_before>// Package https is the supplement of the standard library `http`,
// not the protocal `https`.
package https

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

// HTTPError stands for a HTTP error.
type HTTPError struct {
	// The error information
	Err error

	// The status code
	Code int

	// You can place data into it to carry in an error.
	Data map[string]interface{}
}

// NewHTTPError returns a new HTTPError.
func NewHTTPError(code int, err interface{}) error {
	switch err.(type) {
	case error:
	case []byte:
		err = fmt.Errorf("%s", string(err.([]byte)))
	default:
		err = fmt.Errorf("%v", err)
	}
	return HTTPError{Code: code, Err: err.(error)}
}

func (e HTTPError) Error() string {
	return fmt.Sprintf("status=%d, err=%s", e.Code, e.Err)
}

// ErrorLogFunc handles the http error log in ErrorHandler and
// ErrorHandlerWithStatusCode.
//
// Notice: The caller doesn't append the new line, so the function should
// append the new line.
var ErrorLogFunc func(format string, args ...interface{})

func init() {
	ErrorLogFunc = func(format string, args ...interface{}) {
		fmt.Fprintf(os.Stderr, format+"\n", args...)
	}
}

// ErrorHandler handles the error and responds it the client.
func ErrorHandler(f func(http.ResponseWriter, *http.Request) error) http.HandlerFunc {
	return ErrorHandlerWithStatusCode(func(w http.ResponseWriter,
		r *http.Request) (int, error) {
		return 0, f(w, r)
	})
}

// ErrorHandlerWithStatusCode handles the error and responds it the client
// with the status code.
func ErrorHandlerWithStatusCode(f func(http.ResponseWriter, *http.Request) (
	int, error)) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		if code, err := f(w, r); err != nil {
			if code == 0 {
				if _err, ok := err.(HTTPError); ok {
					code = _err.Code
				} else {
					code = http.StatusInternalServerError
				}
			}
			http.Error(w, err.Error(), code)
			ErrorLogFunc("Handling %q: status=%d, err=%v", r.RequestURI, code, err)
		}
	}
}
<commit_msg>Add the http handler wrapper.<commit_after>// Package https is the supplement of the standard library `http`,
// not the protocal `https`.
package https

import (
	"bytes"
	"fmt"
	"io"
	"net/http"
	"os"
)

// HTTPError stands for a HTTP error.
type HTTPError struct {
	// The error information
	Err error

	// The status code
	Code int

	// You can place data into it to carry in an error.
	Data map[string]interface{}
}

// NewHTTPError returns a new HTTPError.
func NewHTTPError(code int, err interface{}) error {
	switch err.(type) {
	case error:
	case []byte:
		err = fmt.Errorf("%s", string(err.([]byte)))
	default:
		err = fmt.Errorf("%v", err)
	}
	return HTTPError{Code: code, Err: err.(error)}
}

func (e HTTPError) Error() string {
	return e.Err.Error()
}

// ErrorLogFunc handles the http error log in ErrorHandler and
// ErrorHandlerWithStatusCode.
//
// Notice: The caller doesn't append the new line, so the function should
// append the new line.
var ErrorLogFunc func(format string, args ...interface{})

func init() {
	ErrorLogFunc = func(format string, args ...interface{}) {
		fmt.Fprintf(os.Stderr, format+"\n", args...)
	}
}

// ErrorHandler handles the error and responds it the client.
func ErrorHandler(f func(http.ResponseWriter, *http.Request) error) http.HandlerFunc {
	return ErrorHandlerWithStatusCode(func(w http.ResponseWriter,
		r *http.Request) (int, error) {
		return 0, f(w, r)
	})
}

// ErrorHandlerWithStatusCode handles the error and responds it the client
// with the status code.
func ErrorHandlerWithStatusCode(f func(http.ResponseWriter, *http.Request) (int, error)) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		if code, err := f(w, r); err != nil {
			if code == 0 {
				if _err, ok := err.(HTTPError); ok {
					code = _err.Code
				} else {
					code = http.StatusInternalServerError
				}
			}
			http.Error(w, err.Error(), code)
			ErrorLogFunc("Handling %q: status=%d, err=%v", r.RequestURI, code, err)
		}
	}
}

// HandlerWrapper handles the response result.
func HandlerWrapper(f func(http.ResponseWriter, *http.Request) (int, []byte, error)) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		code, resp, err := f(w, r)

		// Handle the error.
		if err != nil {
			if code == 0 {
				if _err, ok := err.(HTTPError); ok {
					code = _err.Code
				} else {
					code = http.StatusInternalServerError
				}
			}
			http.Error(w, err.Error(), code)
			ErrorLogFunc("Failed to handle %q: %s", r.RequestURI, err)
			return
		}

		// Determine the status code.
		if code == 0 {
			if len(resp) == 0 {
				code = http.StatusNoContent
			} else {
				code = http.StatusOK
			}
		}

		// Send the response result.
		w.WriteHeader(code)
		if _, err = io.CopyN(w, bytes.NewBuffer(resp), int64(len(resp))); err != nil {
			ErrorLogFunc("Failed to send the response of %q: %s", r.RequestURI, err)
		}
	}
}
<|endoftext|>


<commit_before>package middleware

import (
	"encoding/base64"
	"github.com/labstack/echo"
	"net/http"
	"net/http/httptest"
	"testing"
)

func TestBasicAuth(t *testing.T) {
	req, _ := http.NewRequest(echo.POST, "/", nil)
	res := &echo.Response{Writer: httptest.NewRecorder()}
	c := echo.NewContext(req, res, echo.New())
	fn := func(u, p string) bool {
		if u == "joe" && p == "secret" {
			return true
		}
		return false
	}
	b := BasicAuth(fn)

	//-------------------
	// Valid credentials
	//-------------------

	auth := Basic + " " + base64.StdEncoding.EncodeToString([]byte("joe:secret"))
	req.Header.Set(echo.Authorization, auth)
	if b(c) != nil {
		t.Error("basic auth should pass")
	}

	// Case insensitive
	auth = "basic " + base64.StdEncoding.EncodeToString([]byte("joe:secret"))
	req.Header.Set(echo.Authorization, auth)
	if b(c) != nil {
		t.Error("basic auth should ignore case and pass")
	}

	//---------------------
	// Invalid credentials
	//---------------------

	auth = Basic + "  " + base64.StdEncoding.EncodeToString([]byte(" joe: secret"))
	req.Header.Set(echo.Authorization, auth)
	b = BasicAuth(fn)
	if b(c) == nil {
		t.Error("basic auth should fail")
	}

	// Invalid scheme
	auth = "Base " + base64.StdEncoding.EncodeToString([]byte(" :secret"))
	req.Header.Set(echo.Authorization, auth)
	b = BasicAuth(fn)
	if b(c) == nil {
		t.Error("basic auth should fail for invalid scheme")
	}

	// Empty auth header
	b = BasicAuth(fn)
	if b(c) == nil {
		t.Error("basic auth should fail for empty auth header")
	}
}
<commit_msg>Invalid auth test case<commit_after>package middleware

import (
	"encoding/base64"
	"github.com/labstack/echo"
	"net/http"
	"net/http/httptest"
	"testing"
)

func TestBasicAuth(t *testing.T) {
	req, _ := http.NewRequest(echo.POST, "/", nil)
	res := &echo.Response{Writer: httptest.NewRecorder()}
	c := echo.NewContext(req, res, echo.New())
	fn := func(u, p string) bool {
		if u == "joe" && p == "secret" {
			return true
		}
		return false
	}
	b := BasicAuth(fn)

	//-------------------
	// Valid credentials
	//-------------------

	auth := Basic + " " + base64.StdEncoding.EncodeToString([]byte("joe:secret"))
	req.Header.Set(echo.Authorization, auth)
	if b(c) != nil {
		t.Error("basic auth should pass")
	}

	// Case insensitive
	auth = "basic " + base64.StdEncoding.EncodeToString([]byte("joe:secret"))
	req.Header.Set(echo.Authorization, auth)
	if b(c) != nil {
		t.Error("basic auth should ignore case and pass")
	}

	//---------------------
	// Invalid credentials
	//---------------------

	auth = Basic + "  " + base64.StdEncoding.EncodeToString([]byte(" joe: secret"))
	req.Header.Set(echo.Authorization, auth)
	b = BasicAuth(fn)
	if b(c) == nil {
		t.Error("basic auth should fail")
	}

	// Invalid header
	auth = base64.StdEncoding.EncodeToString([]byte(" :secret"))
	req.Header.Set(echo.Authorization, auth)
	b = BasicAuth(fn)
	if b(c) == nil {
		t.Error("basic auth should fail for invalid scheme")
	}

	// Invalid scheme
	auth = "Base " + base64.StdEncoding.EncodeToString([]byte(" :secret"))
	req.Header.Set(echo.Authorization, auth)
	b = BasicAuth(fn)
	if b(c) == nil {
		t.Error("basic auth should fail for invalid scheme")
	}

	// Empty auth header
	req.Header.Set(echo.Authorization, "")
	b = BasicAuth(fn)
	if b(c) == nil {
		t.Error("basic auth should fail for empty auth header")
	}
}
<|endoftext|>


<commit_before>package middleware

import (
	"fmt"

	"github.com/markbates/buffalo"
	newrelic "github.com/newrelic/go-agent"
	"github.com/pkg/errors"
)

// NewRelic returns a piece of buffalo.Middleware that can
// be used to report requests to NewRelic. You must pass in your
// NewRelic key and a name for your application. If the key
// passed in is blank, i.e. loading from an ENV, then the middleware
// is skipped and the chain continues on like normal. Useful
// for development.
func NewRelic(key, name string) buffalo.MiddlewareFunc {
	return func(next buffalo.Handler) buffalo.Handler {
		if key == "" {
			return next
		}
		return func(c buffalo.Context) error {
			fmt.Printf("Setting up New Relic %s\n", key)
			config := newrelic.NewConfig(name, key)
			app, err := newrelic.NewApplication(config)
			if err != nil {
				return errors.WithStack(err)
			}
			tx := app.StartTransaction(c.Request().URL.String(), c.Response(), c.Request())
			defer tx.End()
			return next(c)
		}
	}
}
<commit_msg>reworked NewRelic middleware<commit_after>package middleware

import (
	"fmt"

	"github.com/markbates/buffalo"
	newrelic "github.com/newrelic/go-agent"
)

// NewRelic returns a piece of buffalo.Middleware that can
// be used to report requests to NewRelic. You must pass in your
// NewRelic key and a name for your application. If the key
// passed in is blank, i.e. loading from an ENV, then the middleware
// is skipped and the chain continues on like normal. Useful
// for development.
func NewRelic(key, name string) buffalo.MiddlewareFunc {
	mf := func(next buffalo.Handler) buffalo.Handler {
		return next
	}
	if key == "" {
		return mf
	}
	fmt.Printf("Setting up New Relic %s\n", key)
	config := newrelic.NewConfig(name, key)
	app, err := newrelic.NewApplication(config)
	if err != nil {
		return mf
	}

	return func(next buffalo.Handler) buffalo.Handler {
		return func(c buffalo.Context) error {
			tx := app.StartTransaction(c.Request().URL.String(), c.Response(), c.Request())
			defer tx.End()
			return next(c)
		}
	}
}
<|endoftext|>


<commit_before>package cobe

import (
	"fmt"
	"math/rand"
	"strings"
	"time"
)

type Brain struct {
	graph  *graph
	tok    tokenizer
	scorer scorer
}

const spaceTokenID tokenID = -1

func OpenBrain(path string) (*Brain, error) {
	graph, err := openGraph(path)
	if err != nil {
		return nil, err
	}

	version, err := graph.getInfoString("version")
	if err != nil {
		return nil, err
	}

	if version != "2" {
		return nil, fmt.Errorf("cannot read version %s brain", version)
	}

	tokenizer, err := graph.getInfoString("tokenizer")
	if err != nil {
		return nil, err
	}

	return &Brain{graph, getTokenizer(tokenizer), &cobeScorer{}}, nil
}

func (b *Brain) Close() {
	if b.graph != nil {
		b.graph.close()
		b.graph = nil
	}
}

func getTokenizer(name string) tokenizer {
	switch strings.ToLower(name) {
	case "cobe":
		return newCobeTokenizer()
	case "megahal":
		return newMegaHALTokenizer()
	}

	return nil
}

func (b *Brain) Learn(text string) {
	tokens := b.tok.Split(text)

	// skip learning if too few tokens (but don't count spaces)
	if countGoodTokens(tokens) <= b.graph.order {
		stats.Inc("learn.skip", 1, 1.0)
		return
	}

	stats.Inc("learn", 1, 1.0)

	var tokenIds []tokenID
	for _, text := range tokens {
		var tokenID tokenID
		if text == " " {
			tokenID = spaceTokenID
		} else {
			tokenID = b.graph.getOrCreateToken(text)
		}

		tokenIds = append(tokenIds, tokenID)
	}

	var prevNode nodeID
	b.forEdges(tokenIds, func(prev, next []tokenID, hasSpace bool) {
		if prevNode == 0 {
			prevNode = b.graph.getOrCreateNode(prev)
		}
		nextNode := b.graph.getOrCreateNode(next)

		b.graph.addEdge(prevNode, nextNode, hasSpace)
		prevNode = nextNode
	})
}

func countGoodTokens(tokens []string) int {
	var count int
	for _, token := range tokens {
		if token != " " {
			count++
		}
	}

	return count
}

func (b *Brain) forEdges(tokenIds []tokenID, f func([]tokenID, []tokenID, bool)) {
	// Call f() on every N-gram (N = brain order) in tokenIds.
	order := b.graph.order

	chain := b.toChain(order, tokenIds)
	edges := toEdges(order, chain)

	for _, e := range edges {
		f(e.prev, e.next, e.hasSpace)
	}
}

func (b *Brain) toChain(order int, tokenIds []tokenID) []tokenID {
	var chain []tokenID
	for i := 0; i < order; i++ {
		chain = append(chain, b.graph.endTokenID)
	}

	chain = append(chain, tokenIds...)

	for i := 0; i < order; i++ {
		chain = append(chain, b.graph.endTokenID)
	}

	return chain
}

type edge struct {
	prev     []tokenID
	next     []tokenID
	hasSpace bool
}

func toEdges(order int, tokenIds []tokenID) []edge {
	var tokens []tokenID
	var spaces []int

	// Turn tokenIds (containing some SPACE_TOKEN_ID) into a list
	// of tokens and a list of positions in the tokens slice after
	// which spaces were found.

	for i := 0; i < len(tokenIds); i++ {
		tokens = append(tokens, tokenIds[i])

		if i < len(tokenIds)-1 && tokenIds[i+1] == spaceTokenID {
			spaces = append(spaces, len(tokens))
			i++
		}
	}

	var ret []edge

	prev := tokens[0:order]
	for i := 1; i < len(tokens)-order+1; i++ {
		next := tokens[i : i+order]

		var hasSpace bool
		if len(spaces) > 0 && spaces[0] == i+order-1 {
			hasSpace = true
			spaces = spaces[1:]
		}

		ret = append(ret, edge{prev, next, hasSpace})
		prev = next
	}

	return ret
}

func (b *Brain) Reply(text string) string {
	stats.Inc("reply", 1, 1.0)

	tokens := b.tok.Split(text)
	tokenIds := b.graph.filterPivots(unique(tokens))

	stemTokenIds := b.conflateStems(tokens)
	tokenIds = uniqueIds(append(tokenIds, stemTokenIds...))

	if len(tokenIds) == 0 {
		tokenIds = b.babble()
	}

	if len(tokenIds) == 0 {
		stats.Inc("error", 1, 1.0)
		return "I don't know enough to answer you yet!"
	}

	var count int

	var bestReply *reply
	var bestScore float64 = -1

	stop := make(chan bool)
	replies := b.replySearch(tokenIds, stop)

	timeout := time.After(500 * time.Millisecond)
loop:
	for {
		select {
		case edges := <-replies:
			if edges == nil {
				// Channel was closed: run another search
				replies = b.replySearch(tokenIds, stop)
				continue loop
			}

			reply := newReply(b.graph, edges)
			score := b.scorer.Score(reply)

			if score > bestScore {
				bestReply = reply
				bestScore = score
			}

			count++
		case <-timeout:
			if bestReply != nil {
				break loop
			} else {
				timeout = time.After(500 * time.Millisecond)
			}
		}
	}

	// Tell replies to stop and block until we're sure it has closed.
	close(stop)
	if _, ok := <-replies; ok {
		// Replies got unexpected results after search stop.
		stats.Inc("error", 1, 1.0)
	}

	stats.Inc("reply.candidate", int64(count), 1.0)

	clog.Info("Got %d total replies\n", count)
	if bestReply == nil {
		return "I don't know enough to answer you yet!"
	}

	return bestReply.ToString()
}

func (b *Brain) conflateStems(tokens []string) []tokenID {
	var ret []tokenID

	for _, token := range tokens {
		tokenIds := b.graph.getTokensByStem(token)
		ret = append(ret, tokenIds...)
	}

	return ret
}

func (b *Brain) babble() []tokenID {
	var tokenIds []tokenID

	for i := 0; i < 5; i++ {
		t := b.graph.getRandomToken()
		if t > 0 {
			tokenIds = append(tokenIds, tokenID(t))
		}
	}

	return tokenIds
}

// replySearch combines a forward and a reverse search over the graph
// into a series of replies.
func (b *Brain) replySearch(tokenIds []tokenID, stop <-chan bool) <-chan []edgeID {
	pivotID := b.pickPivot(tokenIds)
	pivotNode := b.graph.getRandomNodeWithToken(pivotID)

	endNode := b.graph.endContextID

	revIter := &history{b.graph.search(pivotNode, endNode, reverse, stop), nil}
	fwdIter := &history{b.graph.search(pivotNode, endNode, forward, stop), nil}

	replies := make(chan []edgeID)

	go func() {
	loop:
		for {
			rev := revIter.next()
			if rev {
				// combine new rev with all fwds
				result := revIter.result()
				for _, f := range fwdIter.h {
					select {
					case replies <- join(result, f):
						// nothing
					case <-stop:
						break loop
					}
				}
			}

			fwd := fwdIter.next()
			if fwd {
				// combine new fwd with all revs
				result := fwdIter.result()
				for _, r := range revIter.h {
					select {
					case replies <- join(r, result):
						// nothing
					case <-stop:
						break loop
					}
				}
			}

			if !rev && !fwd {
				break
			}
		}

		close(replies)
	}()

	return replies
}

type history struct {
	s *search
	h [][]edgeID
}

func (h *history) next() bool {
	ret := h.s.next()
	if ret {
		h.h = append(h.h, h.s.result)
	}

	return ret
}

func (h *history) result() []edgeID {
	return h.s.result
}

func join(rev []edgeID, fwd []edgeID) []edgeID {
	edges := make([]edgeID, 0, len(rev)+len(fwd))

	// rev is a path from the pivot node to the beginning of a
	// reply: join its edges in reverse order.
	for i := len(rev) - 1; i >= 0; i-- {
		edges = append(edges, rev[i])
	}

	return append(edges, fwd...)
}

func (b *Brain) pickPivot(tokenIds []tokenID) tokenID {
	return tokenIds[rand.Intn(len(tokenIds))]
}

func unique(tokens []string) []string {
	// Reduce tokens to a unique set by sending them through a map.
	m := make(map[string]int)
	for _, token := range tokens {
		m[token]++
	}

	ret := make([]string, 0, len(m))
	for token := range m {
		ret = append(ret, token)
	}

	return ret
}

func uniqueIds(ids []tokenID) []tokenID {
	// Reduce token ids to a unique set by sending them through a map.
	m := make(map[tokenID]int)
	for _, id := range ids {
		m[id]++
	}

	ret := make([]tokenID, 0, len(m))
	for id := range m {
		ret = append(ret, id)
	}

	return ret
}

type reply struct {
	graph   *graph
	edges   []edgeID
	hasText bool
	text    string
}

func newReply(graph *graph, edges []edgeID) *reply {
	return &reply{graph, edges, false, ""}
}

func (r *reply) ToString() string {
	if !r.hasText {
		var parts []string

		// Skip any edges that don't contain word nodes.
		wordEdges := r.edges[1 : len(r.edges)-r.graph.order+1]

		for _, edge := range wordEdges {
			word, hasSpace, err := r.graph.getTextByEdge(edge)
			if err != nil {
				stats.Inc("error", 1, 1.0)
				clog.Error("can't get text", err)
			}

			if word == "" {
				stats.Inc("error", 1, 1.0)
				clog.Error("empty node text! %s", r.edges)
			}

			parts = append(parts, word)
			if hasSpace {
				parts = append(parts, " ")
			}
		}

		r.hasText = true
		r.text = strings.Join(parts, "")
	}

	return r.text
}
<commit_msg>Log stats for reply/learn response times<commit_after>package cobe

import (
	"fmt"
	"math/rand"
	"strings"
	"time"
)

type Brain struct {
	graph  *graph
	tok    tokenizer
	scorer scorer
}

const spaceTokenID tokenID = -1

func OpenBrain(path string) (*Brain, error) {
	graph, err := openGraph(path)
	if err != nil {
		return nil, err
	}

	version, err := graph.getInfoString("version")
	if err != nil {
		return nil, err
	}

	if version != "2" {
		return nil, fmt.Errorf("cannot read version %s brain", version)
	}

	tokenizer, err := graph.getInfoString("tokenizer")
	if err != nil {
		return nil, err
	}

	return &Brain{graph, getTokenizer(tokenizer), &cobeScorer{}}, nil
}

func (b *Brain) Close() {
	if b.graph != nil {
		b.graph.close()
		b.graph = nil
	}
}

func getTokenizer(name string) tokenizer {
	switch strings.ToLower(name) {
	case "cobe":
		return newCobeTokenizer()
	case "megahal":
		return newMegaHALTokenizer()
	}

	return nil
}

func (b *Brain) Learn(text string) {
	now := time.Now()

	tokens := b.tok.Split(text)

	// skip learning if too few tokens (but don't count spaces)
	if countGoodTokens(tokens) <= b.graph.order {
		stats.Inc("learn.skip", 1, 1.0)
		return
	}

	stats.Inc("learn", 1, 1.0)

	var tokenIds []tokenID
	for _, text := range tokens {
		var tokenID tokenID
		if text == " " {
			tokenID = spaceTokenID
		} else {
			tokenID = b.graph.getOrCreateToken(text)
		}

		tokenIds = append(tokenIds, tokenID)
	}

	var prevNode nodeID
	b.forEdges(tokenIds, func(prev, next []tokenID, hasSpace bool) {
		if prevNode == 0 {
			prevNode = b.graph.getOrCreateNode(prev)
		}
		nextNode := b.graph.getOrCreateNode(next)

		b.graph.addEdge(prevNode, nextNode, hasSpace)
		prevNode = nextNode
	})

	stats.Timing("learn.response_time", int64(time.Since(now)/time.Millisecond), 1.0)
}

func countGoodTokens(tokens []string) int {
	var count int
	for _, token := range tokens {
		if token != " " {
			count++
		}
	}

	return count
}

func (b *Brain) forEdges(tokenIds []tokenID, f func([]tokenID, []tokenID, bool)) {
	// Call f() on every N-gram (N = brain order) in tokenIds.
	order := b.graph.order

	chain := b.toChain(order, tokenIds)
	edges := toEdges(order, chain)

	for _, e := range edges {
		f(e.prev, e.next, e.hasSpace)
	}
}

func (b *Brain) toChain(order int, tokenIds []tokenID) []tokenID {
	var chain []tokenID
	for i := 0; i < order; i++ {
		chain = append(chain, b.graph.endTokenID)
	}

	chain = append(chain, tokenIds...)

	for i := 0; i < order; i++ {
		chain = append(chain, b.graph.endTokenID)
	}

	return chain
}

type edge struct {
	prev     []tokenID
	next     []tokenID
	hasSpace bool
}

func toEdges(order int, tokenIds []tokenID) []edge {
	var tokens []tokenID
	var spaces []int

	// Turn tokenIds (containing some SPACE_TOKEN_ID) into a list
	// of tokens and a list of positions in the tokens slice after
	// which spaces were found.

	for i := 0; i < len(tokenIds); i++ {
		tokens = append(tokens, tokenIds[i])

		if i < len(tokenIds)-1 && tokenIds[i+1] == spaceTokenID {
			spaces = append(spaces, len(tokens))
			i++
		}
	}

	var ret []edge

	prev := tokens[0:order]
	for i := 1; i < len(tokens)-order+1; i++ {
		next := tokens[i : i+order]

		var hasSpace bool
		if len(spaces) > 0 && spaces[0] == i+order-1 {
			hasSpace = true
			spaces = spaces[1:]
		}

		ret = append(ret, edge{prev, next, hasSpace})
		prev = next
	}

	return ret
}

func (b *Brain) Reply(text string) string {
	now := time.Now()
	stats.Inc("reply", 1, 1.0)

	tokens := b.tok.Split(text)
	tokenIds := b.graph.filterPivots(unique(tokens))

	stemTokenIds := b.conflateStems(tokens)
	tokenIds = uniqueIds(append(tokenIds, stemTokenIds...))

	if len(tokenIds) == 0 {
		tokenIds = b.babble()
	}

	if len(tokenIds) == 0 {
		stats.Inc("error", 1, 1.0)
		return "I don't know enough to answer you yet!"
	}

	var count int

	var bestReply *reply
	var bestScore float64 = -1

	stop := make(chan bool)
	replies := b.replySearch(tokenIds, stop)

	timeout := time.After(500 * time.Millisecond)
loop:
	for {
		select {
		case edges := <-replies:
			if edges == nil {
				// Channel was closed: run another search
				replies = b.replySearch(tokenIds, stop)
				continue loop
			}

			reply := newReply(b.graph, edges)
			score := b.scorer.Score(reply)

			if score > bestScore {
				bestReply = reply
				bestScore = score
			}

			count++
		case <-timeout:
			if bestReply != nil {
				break loop
			} else {
				timeout = time.After(500 * time.Millisecond)
			}
		}
	}

	// Tell replies to stop and block until we're sure it has closed.
	close(stop)
	if _, ok := <-replies; ok {
		// Replies got unexpected results after search stop.
		stats.Inc("error", 1, 1.0)
	}

	stats.Inc("reply.candidate", int64(count), 1.0)

	clog.Info("Got %d total replies\n", count)
	if bestReply == nil {
		return "I don't know enough to answer you yet!"
	}

	ret := bestReply.ToString()
	stats.Timing("reply.response_time", int64(time.Since(now)/time.Millisecond), 1.0)
	return ret
}

func (b *Brain) conflateStems(tokens []string) []tokenID {
	var ret []tokenID

	for _, token := range tokens {
		tokenIds := b.graph.getTokensByStem(token)
		ret = append(ret, tokenIds...)
	}

	return ret
}

func (b *Brain) babble() []tokenID {
	var tokenIds []tokenID

	for i := 0; i < 5; i++ {
		t := b.graph.getRandomToken()
		if t > 0 {
			tokenIds = append(tokenIds, tokenID(t))
		}
	}

	return tokenIds
}

// replySearch combines a forward and a reverse search over the graph
// into a series of replies.
func (b *Brain) replySearch(tokenIds []tokenID, stop <-chan bool) <-chan []edgeID {
	pivotID := b.pickPivot(tokenIds)
	pivotNode := b.graph.getRandomNodeWithToken(pivotID)

	endNode := b.graph.endContextID

	revIter := &history{b.graph.search(pivotNode, endNode, reverse, stop), nil}
	fwdIter := &history{b.graph.search(pivotNode, endNode, forward, stop), nil}

	replies := make(chan []edgeID)

	go func() {
	loop:
		for {
			rev := revIter.next()
			if rev {
				// combine new rev with all fwds
				result := revIter.result()
				for _, f := range fwdIter.h {
					select {
					case replies <- join(result, f):
						// nothing
					case <-stop:
						break loop
					}
				}
			}

			fwd := fwdIter.next()
			if fwd {
				// combine new fwd with all revs
				result := fwdIter.result()
				for _, r := range revIter.h {
					select {
					case replies <- join(r, result):
						// nothing
					case <-stop:
						break loop
					}
				}
			}

			if !rev && !fwd {
				break
			}
		}

		close(replies)
	}()

	return replies
}

type history struct {
	s *search
	h [][]edgeID
}

func (h *history) next() bool {
	ret := h.s.next()
	if ret {
		h.h = append(h.h, h.s.result)
	}

	return ret
}

func (h *history) result() []edgeID {
	return h.s.result
}

func join(rev []edgeID, fwd []edgeID) []edgeID {
	edges := make([]edgeID, 0, len(rev)+len(fwd))

	// rev is a path from the pivot node to the beginning of a
	// reply: join its edges in reverse order.
	for i := len(rev) - 1; i >= 0; i-- {
		edges = append(edges, rev[i])
	}

	return append(edges, fwd...)
}

func (b *Brain) pickPivot(tokenIds []tokenID) tokenID {
	return tokenIds[rand.Intn(len(tokenIds))]
}

func unique(tokens []string) []string {
	// Reduce tokens to a unique set by sending them through a map.
	m := make(map[string]int)
	for _, token := range tokens {
		m[token]++
	}

	ret := make([]string, 0, len(m))
	for token := range m {
		ret = append(ret, token)
	}

	return ret
}

func uniqueIds(ids []tokenID) []tokenID {
	// Reduce token ids to a unique set by sending them through a map.
	m := make(map[tokenID]int)
	for _, id := range ids {
		m[id]++
	}

	ret := make([]tokenID, 0, len(m))
	for id := range m {
		ret = append(ret, id)
	}

	return ret
}

type reply struct {
	graph   *graph
	edges   []edgeID
	hasText bool
	text    string
}

func newReply(graph *graph, edges []edgeID) *reply {
	return &reply{graph, edges, false, ""}
}

func (r *reply) ToString() string {
	if !r.hasText {
		var parts []string

		// Skip any edges that don't contain word nodes.
		wordEdges := r.edges[1 : len(r.edges)-r.graph.order+1]

		for _, edge := range wordEdges {
			word, hasSpace, err := r.graph.getTextByEdge(edge)
			if err != nil {
				stats.Inc("error", 1, 1.0)
				clog.Error("can't get text", err)
			}

			if word == "" {
				stats.Inc("error", 1, 1.0)
				clog.Error("empty node text! %s", r.edges)
			}

			parts = append(parts, word)
			if hasSpace {
				parts = append(parts, " ")
			}
		}

		r.hasText = true
		r.text = strings.Join(parts, "")
	}

	return r.text
}
<|endoftext|>


<commit_before>package bslack

import (
	"fmt"
	"github.com/42wim/matterbridge/bridge/config"
	"github.com/42wim/matterbridge/matterhook"
	log "github.com/Sirupsen/logrus"
	"github.com/nlopes/slack"
	"regexp"
	"strings"
	"time"
)

type MMMessage struct {
	Text     string
	Channel  string
	Username string
	Raw      *slack.MessageEvent
}

type Bslack struct {
	mh       *matterhook.Client
	sc       *slack.Client
	Config   *config.Protocol
	rtm      *slack.RTM
	Plus     bool
	Remote   chan config.Message
	Users    []slack.User
	Account  string
	si       *slack.Info
	channels []slack.Channel
}

var flog *log.Entry
var protocol = "slack"

func init() {
	flog = log.WithFields(log.Fields{"module": protocol})
}

func New(cfg config.Protocol, account string, c chan config.Message) *Bslack {
	b := &Bslack{}
	b.Config = &cfg
	b.Remote = c
	b.Account = account
	return b
}

func (b *Bslack) Command(cmd string) string {
	return ""
}

func (b *Bslack) Connect() error {
	flog.Info("Connecting")
	if !b.Config.UseAPI {
		b.mh = matterhook.New(b.Config.URL,
			matterhook.Config{BindAddress: b.Config.BindAddress})
	} else {
		b.sc = slack.New(b.Config.Token)
		b.rtm = b.sc.NewRTM()
		go b.rtm.ManageConnection()
	}
	flog.Info("Connection succeeded")
	go b.handleSlack()
	return nil
}

func (b *Bslack) Disconnect() error {
	return nil

}

func (b *Bslack) JoinChannel(channel string) error {
	// we can only join channels using the API
	if b.Config.UseAPI {
		_, err := b.sc.JoinChannel(channel)
		if err != nil {
			return err
		}
	}
	return nil
}

func (b *Bslack) Send(msg config.Message) error {
	flog.Debugf("Receiving %#v", msg)
	if msg.Account == b.Account {
		return nil
	}
	nick := msg.Username
	message := msg.Text
	channel := msg.Channel
	if b.Config.PrefixMessagesWithNick {
		message = nick + " " + message
	}
	if !b.Config.UseAPI {
		matterMessage := matterhook.OMessage{IconURL: b.Config.IconURL}
		matterMessage.Channel = channel
		matterMessage.UserName = nick
		matterMessage.Type = ""
		matterMessage.Text = message
		err := b.mh.Send(matterMessage)
		if err != nil {
			flog.Info(err)
			return err
		}
		return nil
	}
	schannel, err := b.getChannelByName(channel)
	if err != nil {
		return err
	}
	np := slack.NewPostMessageParameters()
	if b.Config.PrefixMessagesWithNick == true {
		np.AsUser = true
	}
	np.Username = nick
	np.IconURL = config.GetIconURL(&msg, b.Config)
	if msg.Avatar != "" {
		np.IconURL = msg.Avatar
	}
	b.sc.PostMessage(schannel.ID, message, np)

	/*
	   newmsg := b.rtm.NewOutgoingMessage(message, schannel.ID)
	   b.rtm.SendMessage(newmsg)
	*/

	return nil
}

func (b *Bslack) getAvatar(user string) string {
	var avatar string
	if b.Users != nil {
		for _, u := range b.Users {
			if user == u.Name {
				return u.Profile.Image48
			}
		}
	}
	return avatar
}

func (b *Bslack) getChannelByName(name string) (*slack.Channel, error) {
	if b.channels == nil {
		return nil, fmt.Errorf("%s: channel %s not found (no channels found)", b.Account, name)
	}
	for _, channel := range b.channels {
		if channel.Name == name {
			return &channel, nil
		}
	}
	return nil, fmt.Errorf("%s: channel %s not found", b.Account, name)
}

func (b *Bslack) getChannelByID(ID string) (*slack.Channel, error) {
	if b.channels == nil {
		return nil, fmt.Errorf("%s: channel %s not found (no channels found)", b.Account, ID)
	}
	for _, channel := range b.channels {
		if channel.ID == ID {
			return &channel, nil
		}
	}
	return nil, fmt.Errorf("%s: channel %s not found", b.Account, ID)
}

func (b *Bslack) handleSlack() {
	flog.Debugf("Choosing API based slack connection: %t", b.Config.UseAPI)
	mchan := make(chan *MMMessage)
	if b.Config.UseAPI {
		go b.handleSlackClient(mchan)
	} else {
		go b.handleMatterHook(mchan)
	}
	time.Sleep(time.Second)
	flog.Debug("Start listening for Slack messages")
	for message := range mchan {
		// do not send messages from ourself
		if b.Config.UseAPI && message.Username == b.si.User.Name {
			continue
		}
		texts := strings.Split(message.Text, "\n")
		for _, text := range texts {
			flog.Debugf("Sending message from %s on %s to gateway", message.Username, b.Account)
			b.Remote <- config.Message{Text: text, Username: message.Username, Channel: message.Channel, Account: b.Account, Avatar: b.getAvatar(message.Username)}
		}
	}
}

func (b *Bslack) handleSlackClient(mchan chan *MMMessage) {
	count := 0
	for msg := range b.rtm.IncomingEvents {
		switch ev := msg.Data.(type) {
		case *slack.MessageEvent:
			// ignore first message
			if count > 0 {
				flog.Debugf("Receiving from slackclient %#v", ev)
				// use our own func because rtm.GetChannelInfo doesn't work for private channels
				channel, err := b.getChannelByID(ev.Channel)
				if err != nil {
					continue
				}
				user, err := b.rtm.GetUserInfo(ev.User)
				if err != nil {
					continue
				}
				m := &MMMessage{}
				m.Username = user.Name
				m.Channel = channel.Name
				m.Text = ev.Text
				m.Raw = ev
				m.Text = b.replaceMention(m.Text)
				mchan <- m
			}
			count++
		case *slack.OutgoingErrorEvent:
			flog.Debugf("%#v", ev.Error())
		case *slack.ChannelJoinedEvent:
			b.Users, _ = b.sc.GetUsers()
		case *slack.ConnectedEvent:
			b.channels = ev.Info.Channels
			b.si = ev.Info
			b.Users, _ = b.sc.GetUsers()
			// add private channels
			groups, _ := b.sc.GetGroups(true)
			for _, g := range groups {
				channel := new(slack.Channel)
				channel.ID = g.ID
				channel.Name = g.Name
				b.channels = append(b.channels, *channel)
			}
		case *slack.InvalidAuthEvent:
			flog.Fatalf("Invalid Token %#v", ev)
		default:
		}
	}
}

func (b *Bslack) handleMatterHook(mchan chan *MMMessage) {
	for {
		message := b.mh.Receive()
		flog.Debugf("receiving from matterhook (slack) %#v", message)
		m := &MMMessage{}
		m.Username = message.UserName
		m.Text = message.Text
		m.Text = b.replaceMention(m.Text)
		m.Channel = message.ChannelName
		mchan <- m
	}
}

func (b *Bslack) userName(id string) string {
	for _, u := range b.Users {
		if u.ID == id {
			return u.Name
		}
	}
	return ""
}

func (b *Bslack) replaceMention(text string) string {
	results := regexp.MustCompile(`<@([a-zA-z0-9]+)>`).FindAllStringSubmatch(text, -1)
	for _, r := range results {
		text = strings.Replace(text, "<@"+r[1]+">", "@"+b.userName(r[1]), -1)

	}
	return text
}
<commit_msg>Do not relay slackbot messages (slack). Closes #119<commit_after>package bslack

import (
	"fmt"
	"github.com/42wim/matterbridge/bridge/config"
	"github.com/42wim/matterbridge/matterhook"
	log "github.com/Sirupsen/logrus"
	"github.com/nlopes/slack"
	"regexp"
	"strings"
	"time"
)

type MMMessage struct {
	Text     string
	Channel  string
	Username string
	Raw      *slack.MessageEvent
}

type Bslack struct {
	mh       *matterhook.Client
	sc       *slack.Client
	Config   *config.Protocol
	rtm      *slack.RTM
	Plus     bool
	Remote   chan config.Message
	Users    []slack.User
	Account  string
	si       *slack.Info
	channels []slack.Channel
}

var flog *log.Entry
var protocol = "slack"

func init() {
	flog = log.WithFields(log.Fields{"module": protocol})
}

func New(cfg config.Protocol, account string, c chan config.Message) *Bslack {
	b := &Bslack{}
	b.Config = &cfg
	b.Remote = c
	b.Account = account
	return b
}

func (b *Bslack) Command(cmd string) string {
	return ""
}

func (b *Bslack) Connect() error {
	flog.Info("Connecting")
	if !b.Config.UseAPI {
		b.mh = matterhook.New(b.Config.URL,
			matterhook.Config{BindAddress: b.Config.BindAddress})
	} else {
		b.sc = slack.New(b.Config.Token)
		b.rtm = b.sc.NewRTM()
		go b.rtm.ManageConnection()
	}
	flog.Info("Connection succeeded")
	go b.handleSlack()
	return nil
}

func (b *Bslack) Disconnect() error {
	return nil

}

func (b *Bslack) JoinChannel(channel string) error {
	// we can only join channels using the API
	if b.Config.UseAPI {
		_, err := b.sc.JoinChannel(channel)
		if err != nil {
			return err
		}
	}
	return nil
}

func (b *Bslack) Send(msg config.Message) error {
	flog.Debugf("Receiving %#v", msg)
	if msg.Account == b.Account {
		return nil
	}
	nick := msg.Username
	message := msg.Text
	channel := msg.Channel
	if b.Config.PrefixMessagesWithNick {
		message = nick + " " + message
	}
	if !b.Config.UseAPI {
		matterMessage := matterhook.OMessage{IconURL: b.Config.IconURL}
		matterMessage.Channel = channel
		matterMessage.UserName = nick
		matterMessage.Type = ""
		matterMessage.Text = message
		err := b.mh.Send(matterMessage)
		if err != nil {
			flog.Info(err)
			return err
		}
		return nil
	}
	schannel, err := b.getChannelByName(channel)
	if err != nil {
		return err
	}
	np := slack.NewPostMessageParameters()
	if b.Config.PrefixMessagesWithNick == true {
		np.AsUser = true
	}
	np.Username = nick
	np.IconURL = config.GetIconURL(&msg, b.Config)
	if msg.Avatar != "" {
		np.IconURL = msg.Avatar
	}
	b.sc.PostMessage(schannel.ID, message, np)

	/*
	   newmsg := b.rtm.NewOutgoingMessage(message, schannel.ID)
	   b.rtm.SendMessage(newmsg)
	*/

	return nil
}

func (b *Bslack) getAvatar(user string) string {
	var avatar string
	if b.Users != nil {
		for _, u := range b.Users {
			if user == u.Name {
				return u.Profile.Image48
			}
		}
	}
	return avatar
}

func (b *Bslack) getChannelByName(name string) (*slack.Channel, error) {
	if b.channels == nil {
		return nil, fmt.Errorf("%s: channel %s not found (no channels found)", b.Account, name)
	}
	for _, channel := range b.channels {
		if channel.Name == name {
			return &channel, nil
		}
	}
	return nil, fmt.Errorf("%s: channel %s not found", b.Account, name)
}

func (b *Bslack) getChannelByID(ID string) (*slack.Channel, error) {
	if b.channels == nil {
		return nil, fmt.Errorf("%s: channel %s not found (no channels found)", b.Account, ID)
	}
	for _, channel := range b.channels {
		if channel.ID == ID {
			return &channel, nil
		}
	}
	return nil, fmt.Errorf("%s: channel %s not found", b.Account, ID)
}

func (b *Bslack) handleSlack() {
	flog.Debugf("Choosing API based slack connection: %t", b.Config.UseAPI)
	mchan := make(chan *MMMessage)
	if b.Config.UseAPI {
		go b.handleSlackClient(mchan)
	} else {
		go b.handleMatterHook(mchan)
	}
	time.Sleep(time.Second)
	flog.Debug("Start listening for Slack messages")
	for message := range mchan {
		// do not send messages from ourself
		if b.Config.UseAPI && message.Username == b.si.User.Name {
			continue
		}
		texts := strings.Split(message.Text, "\n")
		for _, text := range texts {
			flog.Debugf("Sending message from %s on %s to gateway", message.Username, b.Account)
			b.Remote <- config.Message{Text: text, Username: message.Username, Channel: message.Channel, Account: b.Account, Avatar: b.getAvatar(message.Username)}
		}
	}
}

func (b *Bslack) handleSlackClient(mchan chan *MMMessage) {
	count := 0
	for msg := range b.rtm.IncomingEvents {
		switch ev := msg.Data.(type) {
		case *slack.MessageEvent:
			// ignore first message
			if count > 0 {
				flog.Debugf("Receiving from slackclient %#v", ev)
				// use our own func because rtm.GetChannelInfo doesn't work for private channels
				channel, err := b.getChannelByID(ev.Channel)
				if err != nil {
					continue
				}
				user, err := b.rtm.GetUserInfo(ev.User)
				if err != nil {
					continue
				}
				m := &MMMessage{}
				m.Username = user.Name
				m.Channel = channel.Name
				m.Text = ev.Text
				m.Raw = ev
				m.Text = b.replaceMention(m.Text)
				mchan <- m
			}
			count++
		case *slack.OutgoingErrorEvent:
			flog.Debugf("%#v", ev.Error())
		case *slack.ChannelJoinedEvent:
			b.Users, _ = b.sc.GetUsers()
		case *slack.ConnectedEvent:
			b.channels = ev.Info.Channels
			b.si = ev.Info
			b.Users, _ = b.sc.GetUsers()
			// add private channels
			groups, _ := b.sc.GetGroups(true)
			for _, g := range groups {
				channel := new(slack.Channel)
				channel.ID = g.ID
				channel.Name = g.Name
				b.channels = append(b.channels, *channel)
			}
		case *slack.InvalidAuthEvent:
			flog.Fatalf("Invalid Token %#v", ev)
		default:
		}
	}
}

func (b *Bslack) handleMatterHook(mchan chan *MMMessage) {
	for {
		message := b.mh.Receive()
		flog.Debugf("receiving from matterhook (slack) %#v", message)
		m := &MMMessage{}
		m.Username = message.UserName
		m.Text = message.Text
		m.Text = b.replaceMention(m.Text)
		m.Channel = message.ChannelName
		if m.Username == "slackbot" {
			continue
		}
		mchan <- m
	}
}

func (b *Bslack) userName(id string) string {
	for _, u := range b.Users {
		if u.ID == id {
			return u.Name
		}
	}
	return ""
}

func (b *Bslack) replaceMention(text string) string {
	results := regexp.MustCompile(`<@([a-zA-z0-9]+)>`).FindAllStringSubmatch(text, -1)
	for _, r := range results {
		text = strings.Replace(text, "<@"+r[1]+">", "@"+b.userName(r[1]), -1)

	}
	return text
}
<|endoftext|>