<commit_before>package main

import (
	"log"
	"net/http"
	"time"

	"github.com/gorilla/websocket"
)

const (
	// Time allowed to write a message to the peer.
	writeWait = 10 * time.Second

	// Time allowed to read the next pong message from the peer.
	pongWait = 60 * time.Second

	// Send pings to peer with this period. Must be less than pongWait.
	pingPeriod = (pongWait * 9) / 10

	// Maximum message size allowed from peer.
	maxMessageSize = 1024
)

type NamedWebSocket struct {
	serviceName string

	// The current websocket connection instances to this named websocket
	connections []*Connection

	// Buffered channel of outbound service messages.
	broadcastBuffer chan *Message

	// Buffered channel of outbound connect/disconnect messages
	controlBuffer chan *Message

	// Attached DNS-SD discovery registration and browser for this Named Web Socket
	discoveryClient *DiscoveryClient
}

type Connection struct {
	ws      *websocket.Conn
	isProxy bool
}

type Message struct {
	source  *Connection
	payload []byte
}

var upgrader = websocket.Upgrader{
	ReadBufferSize:  2048,
	WriteBufferSize: 2048,
	CheckOrigin: func(r *http.Request) bool {
		return true // allow all origins
	},
}

// Create a new NamedWebSocket instance (local or broadcast-based) with a given service type
func NewNamedWebSocket(serviceName string, isBroadcast bool) *NamedWebSocket {
	scope := "broadcast"
	if isBroadcast == false {
		scope = "local"
	}

	sock := &NamedWebSocket{
		serviceName:     serviceName,
		connections:     make([]*Connection, 0),
		broadcastBuffer: make(chan *Message, 512),
		controlBuffer:   make(chan *Message, 512),
	}

	go sock.messageDispatcher()

	log.Print("New " + scope + " web socket '" + serviceName + "' created.")

	if isBroadcast {
		go sock.advertise()
	}

	return sock
}

func (sock *NamedWebSocket) advertise() {
	if sock.discoveryClient == nil {
		// Advertise new socket type on the local network
		sock.discoveryClient = NewDiscoveryClient(sock.serviceName)
	}
}

// Set up a new web socket connection
func (sock *NamedWebSocket) serve(w http.ResponseWriter, r *http.Request) {
	if r.Method != "GET" {
		http.Error(w, "Method not allowed", 405)
		return
	}

	isProxy := false
	proxyHeader := r.Header.Get("X-BroadcastWebSocket-Proxy")
	if proxyHeader == "true" {
		isProxy = true
	}

	ws, err := upgrader.Upgrade(w, r, map[string][]string{
		"Access-Control-Allow-Origin":      []string{"*"},
		"Access-Control-Allow-Credentials": []string{"true"},
		"Access-Control-Allow-Headers":     []string{"content-type"},
	})
	if err != nil {
		if _, ok := err.(websocket.HandshakeError); !ok {
			log.Println(err)
		}
		return
	}

	conn := &Connection{
		ws:      ws,
		isProxy: isProxy,
	}

	sock.addConnection(conn)

	go sock.writeConnectionPump(conn)
	sock.readConnectionPump(conn)

}

// readConnectionPump pumps messages from an individual websocket connection to the dispatcher
func (sock *NamedWebSocket) readConnectionPump(conn *Connection) {
	defer func() {
		conn.ws.Close()
		sock.removeConnection(conn)
	}()
	conn.ws.SetReadLimit(maxMessageSize)
	conn.ws.SetReadDeadline(time.Now().Add(pongWait))
	conn.ws.SetPongHandler(func(string) error { conn.ws.SetReadDeadline(time.Now().Add(pongWait)); return nil })
	for {
		_, message, err := conn.ws.ReadMessage()
		if err != nil {
			break
		}
		wsBroadcast := &Message{
			source:  conn,
			payload: message,
		}
		sock.broadcastBuffer <- wsBroadcast
	}
}

// writeConnectionPump keeps an individual websocket connection alive
func (sock *NamedWebSocket) writeConnectionPump(conn *Connection) {
	ticker := time.NewTicker(pingPeriod)
	defer func() {
		ticker.Stop()
		conn.ws.Close()
		sock.removeConnection(conn)
	}()
	for {
		select {
		case <-ticker.C:
			sock.write(conn, websocket.PingMessage, []byte{})
		}
	}
}

// Handle broadcast of control and service messaging on NamedWebSocket connections
func (sock *NamedWebSocket) messageDispatcher() {
	for {
		select {
		case wsConnect, ok := <-sock.controlBuffer:
			if !ok {
				sock.write(wsConnect.source, websocket.CloseMessage, []byte{})
				return
			}
			sock.broadcast(wsConnect)
		case wsBroadcast, ok := <-sock.broadcastBuffer:
			if !ok {
				sock.write(wsBroadcast.source, websocket.CloseMessage, []byte{})
				return
			}
			sock.broadcast(wsBroadcast)
		}
	}
}

// Set up a new NamedWebSocket connection instance
func (sock *NamedWebSocket) addConnection(conn *Connection) {

	connectPayload := []byte("____connect")

	// Notify new websocket connection of existing websocket connections
	for _, oConn := range sock.connections {
		if !conn.isProxy || (conn.isProxy && !oConn.isProxy) {
			sock.write(conn, websocket.TextMessage, connectPayload)
		}
	}

	if !conn.isProxy {
		// Connect message
		wsConnect := &Message{
			source:  conn,
			payload: []byte("____connect"),
		}

		// Broadcast new connect event to all existing named websocket connections
		sock.controlBuffer <- wsConnect
	}

	// Add this websocket instance to connections
	sock.connections = append(sock.connections, conn)
}

// Send a message to the target websocket connection
func (sock *NamedWebSocket) write(conn *Connection, mt int, payload []byte) {
	conn.ws.SetWriteDeadline(time.Now().Add(writeWait))
	conn.ws.WriteMessage(mt, payload)
}

// Broadcast a message to all websocket connections for this NamedWebSocket
// instance (except to the src websocket connection)
func (sock *NamedWebSocket) broadcast(broadcast *Message) {
	for _, conn := range sock.connections {
		if conn.ws != broadcast.source.ws {
			// don't relay messages infinitely between proxy connections
			if conn.isProxy && broadcast.source.isProxy {
				continue
			}
			sock.write(conn, websocket.TextMessage, broadcast.payload)
		}
	}
}

// Tear down an existing NamedWebSocket connection instance
func (sock *NamedWebSocket) removeConnection(conn *Connection) {
	for i, oConn := range sock.connections {
		if oConn.ws == conn.ws {
			sock.connections = append(sock.connections[:i], sock.connections[i+1:]...)
			break
		}
	}

	if !conn.isProxy {
		// Broadcast new disconnect event to all existing named websocket connections
		wsDisconnect := &Message{
			source:  conn,
			payload: []byte("____disconnect"),
		}

		sock.controlBuffer <- wsDisconnect
	}
}
<commit_msg>Simplify circular proxy messaging deadlock checks<commit_after>package main

import (
	"log"
	"net/http"
	"time"

	"github.com/gorilla/websocket"
)

const (
	// Time allowed to write a message to the peer.
	writeWait = 10 * time.Second

	// Time allowed to read the next pong message from the peer.
	pongWait = 60 * time.Second

	// Send pings to peer with this period. Must be less than pongWait.
	pingPeriod = (pongWait * 9) / 10

	// Maximum message size allowed from peer.
	maxMessageSize = 1024
)

type NamedWebSocket struct {
	serviceName string

	// The current websocket connection instances to this named websocket
	connections []*Connection

	// Buffered channel of outbound service messages.
	broadcastBuffer chan *Message

	// Buffered channel of outbound connect/disconnect messages
	controlBuffer chan *Message

	// Attached DNS-SD discovery registration and browser for this Named Web Socket
	discoveryClient *DiscoveryClient
}

type Connection struct {
	ws      *websocket.Conn
	isProxy bool
}

type Message struct {
	source  *Connection
	payload []byte
}

var upgrader = websocket.Upgrader{
	ReadBufferSize:  2048,
	WriteBufferSize: 2048,
	CheckOrigin: func(r *http.Request) bool {
		return true // allow all origins
	},
}

// Create a new NamedWebSocket instance (local or broadcast-based) with a given service type
func NewNamedWebSocket(serviceName string, isBroadcast bool) *NamedWebSocket {
	scope := "broadcast"
	if isBroadcast == false {
		scope = "local"
	}

	sock := &NamedWebSocket{
		serviceName:     serviceName,
		connections:     make([]*Connection, 0),
		broadcastBuffer: make(chan *Message, 512),
		controlBuffer:   make(chan *Message, 512),
	}

	go sock.messageDispatcher()

	log.Print("New " + scope + " web socket '" + serviceName + "' created.")

	if isBroadcast {
		go sock.advertise()
	}

	return sock
}

func (sock *NamedWebSocket) advertise() {
	if sock.discoveryClient == nil {
		// Advertise new socket type on the local network
		sock.discoveryClient = NewDiscoveryClient(sock.serviceName)
	}
}

// Set up a new web socket connection
func (sock *NamedWebSocket) serve(w http.ResponseWriter, r *http.Request) {
	if r.Method != "GET" {
		http.Error(w, "Method not allowed", 405)
		return
	}

	isProxy := false
	proxyHeader := r.Header.Get("X-BroadcastWebSocket-Proxy")
	if proxyHeader == "true" {
		isProxy = true
	}

	ws, err := upgrader.Upgrade(w, r, map[string][]string{
		"Access-Control-Allow-Origin":      []string{"*"},
		"Access-Control-Allow-Credentials": []string{"true"},
		"Access-Control-Allow-Headers":     []string{"content-type"},
	})
	if err != nil {
		if _, ok := err.(websocket.HandshakeError); !ok {
			log.Println(err)
		}
		return
	}

	conn := &Connection{
		ws:      ws,
		isProxy: isProxy,
	}

	sock.addConnection(conn)

	go sock.writeConnectionPump(conn)
	sock.readConnectionPump(conn)

}

// readConnectionPump pumps messages from an individual websocket connection to the dispatcher
func (sock *NamedWebSocket) readConnectionPump(conn *Connection) {
	defer func() {
		conn.ws.Close()
		sock.removeConnection(conn)
	}()
	conn.ws.SetReadLimit(maxMessageSize)
	conn.ws.SetReadDeadline(time.Now().Add(pongWait))
	conn.ws.SetPongHandler(func(string) error { conn.ws.SetReadDeadline(time.Now().Add(pongWait)); return nil })
	for {
		_, message, err := conn.ws.ReadMessage()
		if err != nil {
			break
		}
		wsBroadcast := &Message{
			source:  conn,
			payload: message,
		}
		sock.broadcastBuffer <- wsBroadcast
	}
}

// writeConnectionPump keeps an individual websocket connection alive
func (sock *NamedWebSocket) writeConnectionPump(conn *Connection) {
	ticker := time.NewTicker(pingPeriod)
	defer func() {
		ticker.Stop()
		conn.ws.Close()
		sock.removeConnection(conn)
	}()
	for {
		select {
		case <-ticker.C:
			sock.write(conn, websocket.PingMessage, []byte{})
		}
	}
}

// Handle broadcast of control and service messaging on NamedWebSocket connections
func (sock *NamedWebSocket) messageDispatcher() {
	for {
		select {
		case wsConnect, ok := <-sock.controlBuffer:
			if !ok {
				sock.write(wsConnect.source, websocket.CloseMessage, []byte{})
				return
			}
			sock.broadcast(wsConnect)
		case wsBroadcast, ok := <-sock.broadcastBuffer:
			if !ok {
				sock.write(wsBroadcast.source, websocket.CloseMessage, []byte{})
				return
			}
			sock.broadcast(wsBroadcast)
		}
	}
}

// Set up a new NamedWebSocket connection instance
func (sock *NamedWebSocket) addConnection(conn *Connection) {

	connectPayload := []byte("____connect")

	// Notify new websocket connection of existing websocket connections
	for _, oConn := range sock.connections {
		// don't relay connect messages infinitely between proxy connections
		if conn.isProxy && oConn.isProxy {
			continue
		}
		sock.write(conn, websocket.TextMessage, connectPayload)
	}

	if !conn.isProxy {
		// Connect message
		wsConnect := &Message{
			source:  conn,
			payload: []byte("____connect"),
		}

		// Broadcast new connect event to all existing named websocket connections
		sock.controlBuffer <- wsConnect
	}

	// Add this websocket instance to connections
	sock.connections = append(sock.connections, conn)
}

// Send a message to the target websocket connection
func (sock *NamedWebSocket) write(conn *Connection, mt int, payload []byte) {
	conn.ws.SetWriteDeadline(time.Now().Add(writeWait))
	conn.ws.WriteMessage(mt, payload)
}

// Broadcast a message to all websocket connections for this NamedWebSocket
// instance (except to the src websocket connection)
func (sock *NamedWebSocket) broadcast(broadcast *Message) {
	for _, conn := range sock.connections {
		if conn.ws != broadcast.source.ws {
			// don't relay broadcast messages infinitely between proxy connections
			if conn.isProxy && broadcast.source.isProxy {
				continue
			}
			sock.write(conn, websocket.TextMessage, broadcast.payload)
		}
	}
}

// Tear down an existing NamedWebSocket connection instance
func (sock *NamedWebSocket) removeConnection(conn *Connection) {
	for i, oConn := range sock.connections {
		if oConn.ws == conn.ws {
			sock.connections = append(sock.connections[:i], sock.connections[i+1:]...)
			break
		}
	}

	if !conn.isProxy {
		// Broadcast new disconnect event to all existing named websocket connections
		wsDisconnect := &Message{
			source:  conn,
			payload: []byte("____disconnect"),
		}

		sock.controlBuffer <- wsDisconnect
	}
}
<|endoftext|>


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

package zmqutil

import (
	zmq "github.com/alecthomas/gozmq"
)

type Socket struct {
	base zmq.Socket
	ctx  *Context
}

func (s *Socket) Close() error {
	return s.base.Close()
}

func (s *Socket) Bind(addr string) error    { return s.base.Bind(addr) }
func (s *Socket) Connect(addr string) error { return s.base.Connect(addr) }

func (s *Socket) Recv(flags zmq.SendRecvOption) ([]byte, error) {
	return s.base.Recv(flags)
}
func (s *Socket) RecvMultipart(flags zmq.SendRecvOption) ([][]byte, error) {
	return s.base.RecvMultipart(flags)
}
func (s *Socket) Send(frame []byte, flags zmq.SendRecvOption) error {
	return s.base.Send(frame, flags)
}
func (s *Socket) SendMultipart(msg [][]byte, flags zmq.SendRecvOption) error {
	return s.base.SendMultipart(msg, flags)
}
<commit_msg>Add MustBind and MustConnect.<commit_after>// Copyright 2013 Joshua Tacoma. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package zmqutil

import (
	zmq "github.com/alecthomas/gozmq"
)

type Socket struct {
	base zmq.Socket
	ctx  *Context
}

func (s *Socket) Close() error {
	return s.base.Close()
}

func (s *Socket) Bind(addr string) error    { return s.base.Bind(addr) }
func (s *Socket) Connect(addr string) error { return s.base.Connect(addr) }

func (s *Socket) MustBind(addr string) {
	if err := s.Bind(addr); err != nil {
		panic(err.Error())
	}
}
func (s *Socket) MustConnect(addr string) {
	if err := s.Connect(addr); err != nil {
		panic(err.Error())
	}
}

func (s *Socket) Recv(flags zmq.SendRecvOption) ([]byte, error) {
	return s.base.Recv(flags)
}
func (s *Socket) RecvMultipart(flags zmq.SendRecvOption) ([][]byte, error) {
	return s.base.RecvMultipart(flags)
}
func (s *Socket) Send(frame []byte, flags zmq.SendRecvOption) error {
	return s.base.Send(frame, flags)
}
func (s *Socket) SendMultipart(msg [][]byte, flags zmq.SendRecvOption) error {
	return s.base.SendMultipart(msg, flags)
}
<|endoftext|>


<commit_before>package utils

import (
	"github.com/gorilla/schema"
	"net/url"
)

func Fill(i interface{}, form url.Values) {
	decoder := schema.NewDecoder()
	err := decoder.Decode(i, form)
	LogError(err)
}
<commit_msg>Change fill signature.<commit_after>package utils

import (
	"github.com/gorilla/schema"
	"net/url"
)

func Fill(i interface{}, form url.Values) error {
	decoder := schema.NewDecoder()
	if err := decoder.Decode(i, form); err != nil {
		return err
	}

	return nil
}
<|endoftext|>


<commit_before>// Copyright (c) 2013 by Michael Dvorkin. All Rights Reserved.
// Use of this source code is governed by a MIT-style license that can
// be found in the LICENSE file.

package donna

import()

// Non-capturing checks.
func (gen *MoveGen) GenerateChecks() *MoveGen {
        color := gen.p.color
        enemy := gen.p.color^1
        square := gen.p.outposts[King(enemy)].first()

        // Non-capturing Knight checks.
        checks := knightMoves[square]
        outposts := gen.p.outposts[Knight(color)]
        for outposts != 0 {
                from := outposts.pop()
                gen.movePiece(from, knightMoves[from] & checks & ^gen.p.board[2])
        }

        // Non-capturing Bishop or Queen checks.
        checks = gen.p.Targets(square, Bishop(enemy))
        outposts = gen.p.outposts[Bishop(color)] | gen.p.outposts[Queen(color)]
        for outposts != 0 {
                from := outposts.pop()
                targets := gen.p.Targets(from, Bishop(enemy)) & checks & ^gen.p.board[enemy]
                for targets != 0 {
                        to := targets.pop()
                        if piece := gen.p.pieces[to]; piece == 0 {
                                //
                                // Empty square: simply move a bishop to check.
                                //
                                gen.add(gen.p.NewMove(from, to))
                        } else if piece.color() == color && maskDiagonal[from][square] != 0 {
                                //
                                // Non-empty square occupied by friendly piece on the same
                                // diagonal: moving the piece away causes discovered check.
                                //
                                switch piece.kind() {
                                case PAWN:
                                        // Block pawn promotions (since they are treated as
                                        // captures) and en-passant captures.
                                        prohibit := maskRank[0] | maskRank[7]
                                        if gen.p.flags.enpassant != 0 {
                                                prohibit.set(gen.p.flags.enpassant)
                                        }
                                        gen.movePawn(to, gen.p.targetsMask(to) & ^gen.p.board[2] & ^prohibit)
                                case KING:
                                        // Make sure the king steps out of attack diaginal.
                                        gen.moveKing(to, gen.p.targetsMask(to) & ^gen.p.board[2] & ^maskBlock[from][square])
                                default:
                                        gen.movePiece(to, gen.p.targetsMask(to) & ^gen.p.board[2])
                                }
                        }
                }
		if gen.p.pieces[from].isQueen() {
			//
			// Queen could move straight as a rook and check diagonally as a bishop
			// or move diagonally as a bishop and check straight as a rook.
			//
			targets = (gen.p.Targets(from, Rook(color)) & checks) |
			          (gen.p.Targets(from, Bishop(color)) & gen.p.Targets(square, Rook(color)))
                        gen.movePiece(from, targets & ^gen.p.board[2])
		}
        }

        // Non-capturing Rook or Queen checks.
        checks = gen.p.Targets(square, Rook(enemy))
        outposts = gen.p.outposts[Rook(color)] | gen.p.outposts[Queen(color)]
        for outposts != 0 {
                from := outposts.pop()
                targets := gen.p.Targets(from, Rook(enemy)) & checks & ^gen.p.board[enemy]
                for targets != 0 {
                        to := targets.pop()
                        if piece := gen.p.pieces[to]; piece == 0 {
                                //
                                // Empty square: simply move a rook to check.
                                //
                                gen.add(gen.p.NewMove(from, to))
                        } else if piece.color() == color {
				sameRow := Row(from) == Row(square)
				sameCol := Col(from) == Col(square)
				if sameRow || sameCol {
	                                //
	                                // Non-empty square occupied by friendly piece on the same
	                                // file or rank: moving the piece away causes discovered check.
	                                //
	                                switch piece.kind() {
	                                case PAWN:
	                                        // Block pawn promotions (since they are treated as
	                                        // captures) and en-passant captures.
	                                        prohibit := maskRank[0] | maskRank[7]
	                                        if gen.p.flags.enpassant != 0 {
	                                                prohibit.set(gen.p.flags.enpassant)
	                                        }
	                                        gen.movePawn(to, gen.p.targetsMask(to) & ^gen.p.board[2] & ^prohibit)
	                                case KING:
	                                        // Make sure the king steps out of attack file or rank.
						prohibit := maskNone
						if sameRow {
							prohibit = maskRank[Row(square)]
						} else {
							prohibit = maskFile[Col(square)]
						}
	                                        gen.moveKing(to, gen.p.targetsMask(to) & ^gen.p.board[2] & ^prohibit)
	                                default:
	                                        gen.movePiece(to, gen.p.targetsMask(to) & ^gen.p.board[2])
	                                }
				}
			}
		}
	}

        // Non-capturing Pawn checks.
        return gen
}
<commit_msg>Minor simplification<commit_after>// Copyright (c) 2013 by Michael Dvorkin. All Rights Reserved.
// Use of this source code is governed by a MIT-style license that can
// be found in the LICENSE file.

package donna

import()

// Non-capturing checks.
func (gen *MoveGen) GenerateChecks() *MoveGen {
        color := gen.p.color
        enemy := gen.p.color^1
        square := gen.p.outposts[King(enemy)].first()

        // Non-capturing Knight checks.
        checks := knightMoves[square]
        outposts := gen.p.outposts[Knight(color)]
        for outposts != 0 {
                from := outposts.pop()
                gen.movePiece(from, knightMoves[from] & checks & ^gen.p.board[2])
        }

        // Non-capturing Bishop or Queen checks.
        checks = gen.p.Targets(square, Bishop(enemy))
        outposts = gen.p.outposts[Bishop(color)] | gen.p.outposts[Queen(color)]
        for outposts != 0 {
                from := outposts.pop()
                targets := gen.p.Targets(from, Bishop(enemy)) & checks & ^gen.p.board[enemy]
                for targets != 0 {
                        to := targets.pop()
                        if piece := gen.p.pieces[to]; piece == 0 {
                                //
                                // Empty square: simply move a bishop to check.
                                //
                                gen.add(gen.p.NewMove(from, to))
                        } else if piece.color() == color && maskDiagonal[from][square] != 0 {
                                //
                                // Non-empty square occupied by friendly piece on the same
                                // diagonal: moving the piece away causes discovered check.
                                //
                                switch piece.kind() {
                                case PAWN:
                                        // Block pawn promotions (since they are treated as
                                        // captures) and en-passant captures.
                                        prohibit := maskRank[0] | maskRank[7]
                                        if gen.p.flags.enpassant != 0 {
                                                prohibit.set(gen.p.flags.enpassant)
                                        }
                                        gen.movePawn(to, gen.p.targetsMask(to) & ^gen.p.board[2] & ^prohibit)
                                case KING:
                                        // Make sure the king steps out of attack diaginal.
                                        gen.moveKing(to, gen.p.targetsMask(to) & ^gen.p.board[2] & ^maskBlock[from][square])
                                default:
                                        gen.movePiece(to, gen.p.targetsMask(to) & ^gen.p.board[2])
                                }
                        }
                }
		if gen.p.pieces[from].isQueen() {
			//
			// Queen could move straight as a rook and check diagonally as a bishop
			// or move diagonally as a bishop and check straight as a rook.
			//
			targets = (gen.p.Targets(from, Rook(color)) & checks) |
			          (gen.p.Targets(from, Bishop(color)) & gen.p.Targets(square, Rook(color)))
                        gen.movePiece(from, targets & ^gen.p.board[2])
		}
        }

        // Non-capturing Rook or Queen checks.
        checks = gen.p.Targets(square, Rook(enemy))
        outposts = gen.p.outposts[Rook(color)] | gen.p.outposts[Queen(color)]
        for outposts != 0 {
                from := outposts.pop()
                targets := gen.p.Targets(from, Rook(enemy)) & checks & ^gen.p.board[enemy]
                for targets != 0 {
                        to := targets.pop()
                        if piece := gen.p.pieces[to]; piece == 0 {
                                //
                                // Empty square: simply move a rook to check.
                                //
                                gen.add(gen.p.NewMove(from, to))
                        } else if piece.color() == color {
				if maskStraight[from][square] != 0 {
	                                //
	                                // Non-empty square occupied by friendly piece on the same
	                                // file or rank: moving the piece away causes discovered check.
	                                //
	                                switch piece.kind() {
	                                case PAWN:
	                                        // Block pawn promotions (since they are treated as
	                                        // captures) and en-passant captures.
	                                        prohibit := maskRank[0] | maskRank[7]
	                                        if gen.p.flags.enpassant != 0 {
	                                                prohibit.set(gen.p.flags.enpassant)
	                                        }
	                                        gen.movePawn(to, gen.p.targetsMask(to) & ^gen.p.board[2] & ^prohibit)
	                                case KING:
	                                        // Make sure the king steps out of attack file or rank.
						prohibit := maskNone
						if row := Row(from); row == Row(square) {
							prohibit = maskRank[row]
						} else {
							prohibit = maskFile[Col(square)]
						}
	                                        gen.moveKing(to, gen.p.targetsMask(to) & ^gen.p.board[2] & ^prohibit)
	                                default:
	                                        gen.movePiece(to, gen.p.targetsMask(to) & ^gen.p.board[2])
	                                }
				}
			}
		}
	}

        // Non-capturing Pawn checks.
        return gen
}
<|endoftext|>


<commit_before>package client

import (
	"context"

	"github.com/cloudevents/sdk-go/v2/binding"
	cecontext "github.com/cloudevents/sdk-go/v2/context"
	"github.com/cloudevents/sdk-go/v2/event"
	"github.com/cloudevents/sdk-go/v2/protocol"
)

type Invoker interface {
	Invoke(context.Context, binding.Message, protocol.ResponseFn) error
	IsReceiver() bool
	IsResponder() bool
}

var _ Invoker = (*receiveInvoker)(nil)

func newReceiveInvoker(fn interface{}, fns ...EventDefaulter) (Invoker, error) {
	r := &receiveInvoker{
		eventDefaulterFns: fns,
	}

	if fn, err := receiver(fn); err != nil {
		return nil, err
	} else {
		r.fn = fn
	}

	return r, nil
}

type receiveInvoker struct {
	fn                *receiverFn
	eventDefaulterFns []EventDefaulter
}

func (r *receiveInvoker) Invoke(ctx context.Context, m binding.Message, respFn protocol.ResponseFn) (err error) {
	defer func() {
		err = m.Finish(err)
	}()

	var respMsg binding.Message
	var result protocol.Result

	e, eventErr := binding.ToEvent(ctx, m)
	switch {
	case eventErr != nil && r.fn.hasEventIn:
		return respFn(ctx, nil, protocol.NewReceipt(false, "failed to convert Message to Event: %w", eventErr))
	case r.fn != nil:
		// Check if event is valid before invoking the receiver function
		if e != nil {
			if validationErr := e.Validate(); validationErr != nil {
				return respFn(ctx, nil, protocol.NewReceipt(false, "validation error in incoming event: %w", validationErr))
			}
		}

		// Let's invoke the receiver fn
		var resp *event.Event
		resp, result = r.fn.invoke(ctx, e)

		if respFn == nil {
			break
		}

		// Apply the defaulter chain to the outgoing event.
		if resp != nil && len(r.eventDefaulterFns) > 0 {
			for _, fn := range r.eventDefaulterFns {
				*resp = fn(ctx, *resp)
			}
			// Validate the event conforms to the CloudEvents Spec.
			if vErr := resp.Validate(); vErr != nil {
				cecontext.LoggerFrom(ctx).Errorf("cloudevent validation failed on response event: %w", vErr)
			}
		}

		// because binding.Message is an interface, casting a nil resp
		// here would make future comparisons to nil false
		if resp != nil {
			respMsg = (*binding.EventMessage)(resp)
		}
	}

	if respFn == nil {
		// let the protocol ACK based on the result
		return result
	}

	return respFn(ctx, respMsg, result)
}

func (r *receiveInvoker) IsReceiver() bool {
	return !r.fn.hasEventOut
}

func (r *receiveInvoker) IsResponder() bool {
	return r.fn.hasEventOut
}
<commit_msg>fix response log formatting (#571)<commit_after>package client

import (
	"context"

	"github.com/cloudevents/sdk-go/v2/binding"
	cecontext "github.com/cloudevents/sdk-go/v2/context"
	"github.com/cloudevents/sdk-go/v2/event"
	"github.com/cloudevents/sdk-go/v2/protocol"
)

type Invoker interface {
	Invoke(context.Context, binding.Message, protocol.ResponseFn) error
	IsReceiver() bool
	IsResponder() bool
}

var _ Invoker = (*receiveInvoker)(nil)

func newReceiveInvoker(fn interface{}, fns ...EventDefaulter) (Invoker, error) {
	r := &receiveInvoker{
		eventDefaulterFns: fns,
	}

	if fn, err := receiver(fn); err != nil {
		return nil, err
	} else {
		r.fn = fn
	}

	return r, nil
}

type receiveInvoker struct {
	fn                *receiverFn
	eventDefaulterFns []EventDefaulter
}

func (r *receiveInvoker) Invoke(ctx context.Context, m binding.Message, respFn protocol.ResponseFn) (err error) {
	defer func() {
		err = m.Finish(err)
	}()

	var respMsg binding.Message
	var result protocol.Result

	e, eventErr := binding.ToEvent(ctx, m)
	switch {
	case eventErr != nil && r.fn.hasEventIn:
		return respFn(ctx, nil, protocol.NewReceipt(false, "failed to convert Message to Event: %w", eventErr))
	case r.fn != nil:
		// Check if event is valid before invoking the receiver function
		if e != nil {
			if validationErr := e.Validate(); validationErr != nil {
				return respFn(ctx, nil, protocol.NewReceipt(false, "validation error in incoming event: %w", validationErr))
			}
		}

		// Let's invoke the receiver fn
		var resp *event.Event
		resp, result = r.fn.invoke(ctx, e)

		if respFn == nil {
			break
		}

		// Apply the defaulter chain to the outgoing event.
		if resp != nil && len(r.eventDefaulterFns) > 0 {
			for _, fn := range r.eventDefaulterFns {
				*resp = fn(ctx, *resp)
			}
			// Validate the event conforms to the CloudEvents Spec.
			if vErr := resp.Validate(); vErr != nil {
				cecontext.LoggerFrom(ctx).Errorf("cloudevent validation failed on response event: %v", vErr)
			}
		}

		// because binding.Message is an interface, casting a nil resp
		// here would make future comparisons to nil false
		if resp != nil {
			respMsg = (*binding.EventMessage)(resp)
		}
	}

	if respFn == nil {
		// let the protocol ACK based on the result
		return result
	}

	return respFn(ctx, respMsg, result)
}

func (r *receiveInvoker) IsReceiver() bool {
	return !r.fn.hasEventOut
}

func (r *receiveInvoker) IsResponder() bool {
	return r.fn.hasEventOut
}
<|endoftext|>


<commit_before>package geo_skeleton

import (
	"fmt"
	"log"
	"math"
	"os"
	"time"
)

import (
	"github.com/paulmach/go.geojson"
	"github.com/sjsafranek/DiffDB/diff_store"
	"github.com/sjsafranek/SkeletonDB"
)

var (
	COMMIT_LOG_FILE string = "geo_skeleton_commit.log"
)

const (
	DEFAULT_PRECISION        int = 8
)

// https://gist.github.com/DavidVaini/10308388
func Round(f float64) float64 {
	return math.Floor(f + .5)
}

func RoundToPrecision(f float64, places int) float64 {
	shift := math.Pow(10, float64(places))
	return Round(f*shift) / shift
}

func NewGeoSkeletonDB(db_file string) Database {
	var geoDb = Database{
		File:  db_file,
		Table: "GeoJsonDatasources",
		DB:    skeleton.Database{File: db_file}}
	geoDb.Init()
	return geoDb
}

// Database strust for application.
type Database struct {
	Table            string
	File             string
	commit_log_queue chan string
	Precision        int
	DB              skeleton.Database
}

func (self Database) Init() {

	self.DB.Init()

	// start commit log
	go self.StartCommitLog()

	// default table
	if "" == self.Table {
		self.Table = "GeoJSONLayers"
	}

	conn := self.DB.Connect()
	defer conn.Close()

	err := self.DB.CreateTable(conn, self.Table)
	if nil != err {
		panic(err)
	}
}

func (self Database) getPrecision() int {
	if 1 > self.Precision {
		return DEFAULT_PRECISION
	}
	return self.Precision
}

// Starts Database commit log
func (self *Database) StartCommitLog() {
	self.commit_log_queue = make(chan string, 10000)
	// open file to write database commit log
	COMMIT_LOG, err := os.OpenFile(COMMIT_LOG_FILE, os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0600)
	if err != nil {
		log.Println(err)
	}
	defer COMMIT_LOG.Close()
	// read from chan and write to file
	for {
		if len(self.commit_log_queue) > 0 {
			line := <-self.commit_log_queue
			if _, err := COMMIT_LOG.WriteString(line + "\n"); err != nil {
				panic(err)
			}
		} else {
			time.Sleep(1000 * time.Millisecond)
		}
	}
}

// CommitQueueLength returns length of database commit_log_queue
// @returns int
func (self *Database) CommitQueueLength() int {
	return len(self.commit_log_queue)
}

// NewLayer creates new datasource layer
// @returns string - datasource id
// @returns Error
// TODO: RENAME TO NewDatasource
func (self *Database) NewLayer() (string, error) {
	// create geojson
	datasource_id, _ := NewUUID()
	geojs := geojson.NewFeatureCollection()
	// convert to bytes
	value, err := geojs.MarshalJSON()
	if err != nil {
		return "", nil
	}
	self.commit_log_queue <- `{"method": "create_datasource", "data": { "datasource": "` + datasource_id + `", "layer": ` + string(value) + `}}`
	// Insert layer into database
	err = self.DB.Insert(self.Table, datasource_id, value)
	if err != nil {
		panic(err)
	}
	return datasource_id, err
}

// InsertLayer inserts layer into database
// @param datasource {string}
// @param geojs {Geojson}
// @returns Error
func (self *Database) InsertLayer(datasource_id string, geojs *geojson.FeatureCollection) error {
	// convert to bytes
	value, err := geojs.MarshalJSON()
	if err != nil {
		return err
	}

	err = self.DB.Insert(self.Table, datasource_id, value)
	if err != nil {
		panic(err)
	}

	go self.UpdateTimeseriesDatasource(datasource_id, value)

	return err
}

// GetLayer returns layer from database
// @param datasource {string}
// @returns Geojson
// @returns Error
func (self *Database) GetLayer(datasource_id string) (*geojson.FeatureCollection, error) {
	val, err := self.DB.Select(self.Table, datasource_id)
	if err != nil {
		return nil, err
	}
	if "" == string(val) {
		return nil, fmt.Errorf("Datasource not found")
	}
	// Read to struct
	geojs, err := geojson.UnmarshalFeatureCollection(val)
	if err != nil {
		return geojs, err
	}
	return geojs, nil
}

// GetLayers returns all datasource_ids from database
// @param datasource {string}
// @returns Geojson
// @returns Error
func (self *Database) GetLayers() ([]string, error) {
	val, err := self.DB.SelectAll(self.Table)
	if err != nil {
		return nil, err
	}
	return val, nil
}

// DeleteLayer deletes layer from database
// @param datasource {string}
// @returns Error
func (self *Database) DeleteLayer(datasource_id string) error {
	self.commit_log_queue <- `{"method": "delete_layer", "data": { "datasource": "` + datasource_id + `"}}`
	err := self.DB.Remove(datasource_id, self.Table)
	return err
}

func (self *Database) normalizeGeometry(feat *geojson.Feature) (*geojson.Feature, error) {
	// FIT TO 7 - 8 DECIMAL PLACES OF PRECISION
	if nil == feat.Geometry {
		return nil, fmt.Errorf("Feature has no geometry!")
	}

	precision := self.getPrecision()

	switch feat.Geometry.Type {

	case geojson.GeometryPoint:
		// []float64
		feat.Geometry.Point[0] = RoundToPrecision(feat.Geometry.Point[0], precision)
		feat.Geometry.Point[1] = RoundToPrecision(feat.Geometry.Point[1], precision)

	case geojson.GeometryMultiPoint:
		// [][]float64
		for i := range feat.Geometry.MultiPoint {
			for j := range feat.Geometry.MultiPoint[i] {
				feat.Geometry.MultiPoint[i][j] = RoundToPrecision(feat.Geometry.MultiPoint[i][j], precision)
			}
		}

	case geojson.GeometryLineString:
		// [][]float64
		for i := range feat.Geometry.LineString {
			for j := range feat.Geometry.LineString[i] {
				feat.Geometry.LineString[i][j] = RoundToPrecision(feat.Geometry.LineString[i][j], precision)
			}
		}

	case geojson.GeometryMultiLineString:
		// [][][]float64
		for i := range feat.Geometry.MultiLineString {
			for j := range feat.Geometry.MultiLineString[i] {
				for k := range feat.Geometry.MultiLineString[i][j] {
					feat.Geometry.MultiLineString[i][j][k] = RoundToPrecision(feat.Geometry.MultiLineString[i][j][k], precision)
				}
			}
		}

	case geojson.GeometryPolygon:
		// [][][]float64
		for i := range feat.Geometry.Polygon {
			for j := range feat.Geometry.Polygon[i] {
				for k := range feat.Geometry.Polygon[i][j] {
					feat.Geometry.Polygon[i][j][k] = RoundToPrecision(feat.Geometry.Polygon[i][j][k], precision)
				}
			}
		}

	case geojson.GeometryMultiPolygon:
		// [][][][]float64
		for i := range feat.Geometry.MultiPolygon {
			log.Printf("%v\n", feat.Geometry.MultiPolygon[i])
		}

	}

	/*
		//case GeometryCollection:
		//	geo.Geometries = g.Geometries
		//	// log.Printf("%v\n", feat.Geometry.Geometries)

	*/
	return feat, nil
}

func (self *Database) normalizeProperties(feat *geojson.Feature, featCollection *geojson.FeatureCollection) *geojson.Feature {

	// check if nil map
	if nil == feat.Properties {
		feat.Properties = make(map[string]interface{})
	}

	if 0 == len(featCollection.Features) {
		return feat
	}
	// Standardize properties for new feature
	for j := range featCollection.Features[0].Properties {
		if _, ok := feat.Properties[j]; !ok {
			feat.Properties[j] = ""
		}
	}

	// Standardize properties for existing features
	for i := range featCollection.Features {
		for j := range feat.Properties {
			if _, ok := featCollection.Features[i].Properties[j]; !ok {
				featCollection.Features[i].Properties[j] = ""
			}
		}
	}

	return feat
}

// InsertFeature adds feature to layer. Updates layer in Database
// @param datasource {string}
// @param feat {Geojson Feature}
// @returns Error
func (self *Database) InsertFeature(datasource_id string, feat *geojson.Feature) error {

	if nil == feat {
		return fmt.Errorf("feature value is <nil>!")
	}

	// Get layer from database
	featCollection, err := self.GetLayer(datasource_id)
	if err != nil {
		return err
	}

	// Apply required columns
	now := time.Now().Unix()

	// check if nil map
	if nil == feat.Properties {
		feat.Properties = make(map[string]interface{})
	}

	feat.Properties["is_active"] = true
	feat.Properties["is_deleted"] = false
	feat.Properties["date_created"] = now
	feat.Properties["date_modified"] = now
	feat.Properties["geo_id"] = fmt.Sprintf("%v", now)

	feat, err = self.normalizeGeometry(feat)
	if nil != err {
		return err
	}

	feat = self.normalizeProperties(feat, featCollection)

	// Write to commit log
	value, err := feat.MarshalJSON()
	if err != nil {
		return err
	}
	self.commit_log_queue <- `{"method": "insert_feature", "data": { "datasource": "` + datasource_id + `", "feature": ` + string(value) + `}}`

	// Add new feature to layer
	featCollection.AddFeature(feat)

	// insert layer
	err = self.InsertLayer(datasource_id, featCollection)
	if err != nil {
		panic(err)
	}
	return err
}

// EditFeature Edits feature in layer. Updates layer in Database
// @param datasource {string}
// @param geo_id {string}
// @param feat {Geojson Feature}
// @returns Error
func (self *Database) EditFeature(datasource_id string, geo_id string, feat *geojson.Feature) error {

	// Get layer from database
	featCollection, err := self.GetLayer(datasource_id)
	if err != nil {
		return err
	}

	feature_exists := false

	for i := range featCollection.Features {
		if geo_id == fmt.Sprintf("%v", featCollection.Features[i].Properties["geo_id"]) {

			now := time.Now().Unix()
			feat.Properties["date_modified"] = now

			feat, err = self.normalizeGeometry(feat)
			if nil != err {
				return err
			}

			feat = self.normalizeProperties(feat, featCollection)
			featCollection.Features[i] = feat
			// Write to commit log
			value, err := feat.MarshalJSON()
			if err != nil {
				return err
			}
			self.commit_log_queue <- `{"method": "edit_feature", "data": { "datasource": "` + datasource_id + `", "geo_id": "` + geo_id + `", "feature": ` + string(value) + `}}`
			feature_exists = true
		}
	}

	if !feature_exists {
		return fmt.Errorf("feature not found!")
	}

	// insert layer
	err = self.InsertLayer(datasource_id, featCollection)
	if err != nil {
		panic(err)
	}
	return err
}

func (self GeoTimeseriesDB) InsertTimeseriesDatasource(datasource_id string, enc []byte) (error) {
	err := self.DB.Insert("GeoTimeseriesData", datasource_id, enc)
	return err
}

func (self Database) SelectTimeseriesDatasource(datasource_id string) ([]byte, error) {
	data, err := self.DB.Select("GeoTimeseriesData", datasource_id)
	return data, err
}

func (self Database) UpdateTimeseriesDatasource(datasource_id string, value []byte) error {

	update_value := string(value)
	var ddata diff_store.DiffStore
	data, err := self.SelectTimeseriesDatasource(datasource_id)
	if nil != err {
		if err.Error() == "Not found" {
			// create new diffstore if key not found in database
			ddata = diff_store.NewDiffStore(datasource_id)
		} else {
			panic(err)
		}
	} else {
		ddata.Decode(data)
	}

	// update diffstore
	ddata.Update(update_value)

	// save to database
	enc, err := ddata.Encode()
	if nil != err {
		panic(err)
	}

	ddata.Name = datasource_id
	err = self.InsertTimeseriesDatasource(string(ddata.Name), enc)

	return err
}<commit_msg>fixed geots<commit_after>package geo_skeleton

import (
	"fmt"
	"log"
	"math"
	"os"
	"time"
)

import (
	"github.com/paulmach/go.geojson"
	"github.com/sjsafranek/DiffDB/diff_store"
	"github.com/sjsafranek/SkeletonDB"
)

var (
	COMMIT_LOG_FILE string = "geo_skeleton_commit.log"
)

const (
	DEFAULT_PRECISION        int = 8
)

// https://gist.github.com/DavidVaini/10308388
func Round(f float64) float64 {
	return math.Floor(f + .5)
}

func RoundToPrecision(f float64, places int) float64 {
	shift := math.Pow(10, float64(places))
	return Round(f*shift) / shift
}

func NewGeoSkeletonDB(db_file string) Database {
	var geoDb = Database{
		File:  db_file,
		Table: "GeoJsonDatasources",
		DB:    skeleton.Database{File: db_file}}
	geoDb.Init()
	return geoDb
}

// Database strust for application.
type Database struct {
	Table            string
	File             string
	commit_log_queue chan string
	Precision        int
	DB              skeleton.Database
}

func (self Database) Init() {

	self.DB.Init()

	// start commit log
	go self.StartCommitLog()

	// default table
	if "" == self.Table {
		self.Table = "GeoJSONLayers"
	}

	conn := self.DB.Connect()
	defer conn.Close()

	err := self.DB.CreateTable(conn, self.Table)
	if nil != err {
		panic(err)
	}
}

func (self Database) getPrecision() int {
	if 1 > self.Precision {
		return DEFAULT_PRECISION
	}
	return self.Precision
}

// Starts Database commit log
func (self *Database) StartCommitLog() {
	self.commit_log_queue = make(chan string, 10000)
	// open file to write database commit log
	COMMIT_LOG, err := os.OpenFile(COMMIT_LOG_FILE, os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0600)
	if err != nil {
		log.Println(err)
	}
	defer COMMIT_LOG.Close()
	// read from chan and write to file
	for {
		if len(self.commit_log_queue) > 0 {
			line := <-self.commit_log_queue
			if _, err := COMMIT_LOG.WriteString(line + "\n"); err != nil {
				panic(err)
			}
		} else {
			time.Sleep(1000 * time.Millisecond)
		}
	}
}

// CommitQueueLength returns length of database commit_log_queue
// @returns int
func (self *Database) CommitQueueLength() int {
	return len(self.commit_log_queue)
}

// NewLayer creates new datasource layer
// @returns string - datasource id
// @returns Error
// TODO: RENAME TO NewDatasource
func (self *Database) NewLayer() (string, error) {
	// create geojson
	datasource_id, _ := NewUUID()
	geojs := geojson.NewFeatureCollection()
	// convert to bytes
	value, err := geojs.MarshalJSON()
	if err != nil {
		return "", nil
	}
	self.commit_log_queue <- `{"method": "create_datasource", "data": { "datasource": "` + datasource_id + `", "layer": ` + string(value) + `}}`
	// Insert layer into database
	err = self.DB.Insert(self.Table, datasource_id, value)
	if err != nil {
		panic(err)
	}
	return datasource_id, err
}

// InsertLayer inserts layer into database
// @param datasource {string}
// @param geojs {Geojson}
// @returns Error
func (self *Database) InsertLayer(datasource_id string, geojs *geojson.FeatureCollection) error {
	// convert to bytes
	value, err := geojs.MarshalJSON()
	if err != nil {
		return err
	}

	err = self.DB.Insert(self.Table, datasource_id, value)
	if err != nil {
		panic(err)
	}

	go self.UpdateTimeseriesDatasource(datasource_id, value)

	return err
}

// GetLayer returns layer from database
// @param datasource {string}
// @returns Geojson
// @returns Error
func (self *Database) GetLayer(datasource_id string) (*geojson.FeatureCollection, error) {
	val, err := self.DB.Select(self.Table, datasource_id)
	if err != nil {
		return nil, err
	}
	if "" == string(val) {
		return nil, fmt.Errorf("Datasource not found")
	}
	// Read to struct
	geojs, err := geojson.UnmarshalFeatureCollection(val)
	if err != nil {
		return geojs, err
	}
	return geojs, nil
}

// GetLayers returns all datasource_ids from database
// @param datasource {string}
// @returns Geojson
// @returns Error
func (self *Database) GetLayers() ([]string, error) {
	val, err := self.DB.SelectAll(self.Table)
	if err != nil {
		return nil, err
	}
	return val, nil
}

// DeleteLayer deletes layer from database
// @param datasource {string}
// @returns Error
func (self *Database) DeleteLayer(datasource_id string) error {
	self.commit_log_queue <- `{"method": "delete_layer", "data": { "datasource": "` + datasource_id + `"}}`
	err := self.DB.Remove(datasource_id, self.Table)
	return err
}

func (self *Database) normalizeGeometry(feat *geojson.Feature) (*geojson.Feature, error) {
	// FIT TO 7 - 8 DECIMAL PLACES OF PRECISION
	if nil == feat.Geometry {
		return nil, fmt.Errorf("Feature has no geometry!")
	}

	precision := self.getPrecision()

	switch feat.Geometry.Type {

	case geojson.GeometryPoint:
		// []float64
		feat.Geometry.Point[0] = RoundToPrecision(feat.Geometry.Point[0], precision)
		feat.Geometry.Point[1] = RoundToPrecision(feat.Geometry.Point[1], precision)

	case geojson.GeometryMultiPoint:
		// [][]float64
		for i := range feat.Geometry.MultiPoint {
			for j := range feat.Geometry.MultiPoint[i] {
				feat.Geometry.MultiPoint[i][j] = RoundToPrecision(feat.Geometry.MultiPoint[i][j], precision)
			}
		}

	case geojson.GeometryLineString:
		// [][]float64
		for i := range feat.Geometry.LineString {
			for j := range feat.Geometry.LineString[i] {
				feat.Geometry.LineString[i][j] = RoundToPrecision(feat.Geometry.LineString[i][j], precision)
			}
		}

	case geojson.GeometryMultiLineString:
		// [][][]float64
		for i := range feat.Geometry.MultiLineString {
			for j := range feat.Geometry.MultiLineString[i] {
				for k := range feat.Geometry.MultiLineString[i][j] {
					feat.Geometry.MultiLineString[i][j][k] = RoundToPrecision(feat.Geometry.MultiLineString[i][j][k], precision)
				}
			}
		}

	case geojson.GeometryPolygon:
		// [][][]float64
		for i := range feat.Geometry.Polygon {
			for j := range feat.Geometry.Polygon[i] {
				for k := range feat.Geometry.Polygon[i][j] {
					feat.Geometry.Polygon[i][j][k] = RoundToPrecision(feat.Geometry.Polygon[i][j][k], precision)
				}
			}
		}

	case geojson.GeometryMultiPolygon:
		// [][][][]float64
		for i := range feat.Geometry.MultiPolygon {
			log.Printf("%v\n", feat.Geometry.MultiPolygon[i])
		}

	}

	/*
		//case GeometryCollection:
		//	geo.Geometries = g.Geometries
		//	// log.Printf("%v\n", feat.Geometry.Geometries)

	*/
	return feat, nil
}

func (self *Database) normalizeProperties(feat *geojson.Feature, featCollection *geojson.FeatureCollection) *geojson.Feature {

	// check if nil map
	if nil == feat.Properties {
		feat.Properties = make(map[string]interface{})
	}

	if 0 == len(featCollection.Features) {
		return feat
	}
	// Standardize properties for new feature
	for j := range featCollection.Features[0].Properties {
		if _, ok := feat.Properties[j]; !ok {
			feat.Properties[j] = ""
		}
	}

	// Standardize properties for existing features
	for i := range featCollection.Features {
		for j := range feat.Properties {
			if _, ok := featCollection.Features[i].Properties[j]; !ok {
				featCollection.Features[i].Properties[j] = ""
			}
		}
	}

	return feat
}

// InsertFeature adds feature to layer. Updates layer in Database
// @param datasource {string}
// @param feat {Geojson Feature}
// @returns Error
func (self *Database) InsertFeature(datasource_id string, feat *geojson.Feature) error {

	if nil == feat {
		return fmt.Errorf("feature value is <nil>!")
	}

	// Get layer from database
	featCollection, err := self.GetLayer(datasource_id)
	if err != nil {
		return err
	}

	// Apply required columns
	now := time.Now().Unix()

	// check if nil map
	if nil == feat.Properties {
		feat.Properties = make(map[string]interface{})
	}

	feat.Properties["is_active"] = true
	feat.Properties["is_deleted"] = false
	feat.Properties["date_created"] = now
	feat.Properties["date_modified"] = now
	feat.Properties["geo_id"] = fmt.Sprintf("%v", now)

	feat, err = self.normalizeGeometry(feat)
	if nil != err {
		return err
	}

	feat = self.normalizeProperties(feat, featCollection)

	// Write to commit log
	value, err := feat.MarshalJSON()
	if err != nil {
		return err
	}
	self.commit_log_queue <- `{"method": "insert_feature", "data": { "datasource": "` + datasource_id + `", "feature": ` + string(value) + `}}`

	// Add new feature to layer
	featCollection.AddFeature(feat)

	// insert layer
	err = self.InsertLayer(datasource_id, featCollection)
	if err != nil {
		panic(err)
	}
	return err
}

// EditFeature Edits feature in layer. Updates layer in Database
// @param datasource {string}
// @param geo_id {string}
// @param feat {Geojson Feature}
// @returns Error
func (self *Database) EditFeature(datasource_id string, geo_id string, feat *geojson.Feature) error {

	// Get layer from database
	featCollection, err := self.GetLayer(datasource_id)
	if err != nil {
		return err
	}

	feature_exists := false

	for i := range featCollection.Features {
		if geo_id == fmt.Sprintf("%v", featCollection.Features[i].Properties["geo_id"]) {

			now := time.Now().Unix()
			feat.Properties["date_modified"] = now

			feat, err = self.normalizeGeometry(feat)
			if nil != err {
				return err
			}

			feat = self.normalizeProperties(feat, featCollection)
			featCollection.Features[i] = feat
			// Write to commit log
			value, err := feat.MarshalJSON()
			if err != nil {
				return err
			}
			self.commit_log_queue <- `{"method": "edit_feature", "data": { "datasource": "` + datasource_id + `", "geo_id": "` + geo_id + `", "feature": ` + string(value) + `}}`
			feature_exists = true
		}
	}

	if !feature_exists {
		return fmt.Errorf("feature not found!")
	}

	// insert layer
	err = self.InsertLayer(datasource_id, featCollection)
	if err != nil {
		panic(err)
	}
	return err
}

func (self *Database) InsertTimeseriesDatasource(datasource_id string, enc []byte) (error) {
	err := self.DB.Insert("GeoTimeseriesData", datasource_id, enc)
	return err
}

func (self *Database) SelectTimeseriesDatasource(datasource_id string) ([]byte, error) {
	data, err := self.DB.Select("GeoTimeseriesData", datasource_id)
	return data, err
}

func (self *Database) UpdateTimeseriesDatasource(datasource_id string, value []byte) error {

	update_value := string(value)
	var ddata diff_store.DiffStore
	data, err := self.SelectTimeseriesDatasource(datasource_id)
	if nil != err {
		if err.Error() == "Not found" {
			// create new diffstore if key not found in database
			ddata = diff_store.NewDiffStore(datasource_id)
		} else {
			panic(err)
		}
	} else {
		ddata.Decode(data)
	}

	// update diffstore
	ddata.Update(update_value)

	// save to database
	enc, err := ddata.Encode()
	if nil != err {
		panic(err)
	}

	ddata.Name = datasource_id
	err = self.InsertTimeseriesDatasource(string(ddata.Name), enc)

	return err
}<|endoftext|>


<commit_before>package sql

import (
	"encoding/xml"
)

// DatabaseServerCreateParams represents the set of possible parameters
// when issuing a database server creation request to Azure.
//
// https://msdn.microsoft.com/en-us/library/azure/dn505699.aspx
type DatabaseServerCreateParams struct {
	XMLName                    xml.Name `xml:"http://schemas.microsoft.com/sqlazure/2010/12/ Server"`
	AdministratorLogin         string
	AdministratorLoginPassword string
	Location                   string
	Version                    string
}

// DatabaseServerCreateResponse represents the response following the creation of
// a database server on Azure.
type DatabaseServerCreateResponse struct {
	ServerName string
}

const (
	DatabaseServerVersion11 = "2.0"
	DatabaseServerVersion12 = "12.0"
)

// DatabaseServer represents the set of data recieved from
// a database server list operation.
//
// https://msdn.microsoft.com/en-us/library/azure/dn505702.aspx
type DatabaseServer struct {
	Name                     string
	AdministratorLogin       string
	Location                 string
	FullyQualifiedDomainName string
	Version                  string
	State                    string
}

type ListServersResponse struct {
	DatabaseServers []DatabaseServer `xml:"Server"`
}

// DatabaseCreateParams represents the set of possible parameters when issuing
// a database creation to Azure, and reading a list response from Azure.
//
// https://msdn.microsoft.com/en-us/library/azure/dn505701.aspx
type DatabaseCreateParams struct {
	XMLName            xml.Name `xml:"http://schemas.microsoft.com/windowsazure ServiceResource"`
	Name               string
	Edition            string `xml:",omitempty"`
	CollationName      string `xml:",omitempty"`
	MaxSizeBytes       int64  `xml:",omitempty"`
	ServiceObjectiveID string `xml:"ServiceObjectiveId,omitempty"`
}

// ServiceResource represents the set of parameters obtained from a database
// get or list call.
//
// https://msdn.microsoft.com/en-us/library/azure/dn505708.aspx
type ServiceResource struct {
	Name               string
	State              string
	SelfLink           string
	Edition            string
	CollationName      string
	MaxSizeBytes       int64
	ServiceObjectiveID string `xml:"ServiceObjectiveId,omitempty"`
}

type ListDatabasesResponse struct {
	ServiceResources []ServiceResource `xml:"ServiceResource"`
}

// ServiceResourceUpdateParams represents the set of parameters available
// for a database service update operation.
//
// https://msdn.microsoft.com/en-us/library/azure/dn505718.aspx
type ServiceResourceUpdateParams struct {
	XMLName       xml.Name `xml:"http://schemas.microsoft.com/windowsazure ServiceResource"`
	Name          string
	Edition       string `xml:",omitempty"`
	CollationName string `xml:",omitempty"`
	MaxSizeBytes  int64  `xml:",omitempty"`
}
<commit_msg>Fixed Database Service update request struct.<commit_after>package sql

import (
	"encoding/xml"
)

// DatabaseServerCreateParams represents the set of possible parameters
// when issuing a database server creation request to Azure.
//
// https://msdn.microsoft.com/en-us/library/azure/dn505699.aspx
type DatabaseServerCreateParams struct {
	XMLName                    xml.Name `xml:"http://schemas.microsoft.com/sqlazure/2010/12/ Server"`
	AdministratorLogin         string
	AdministratorLoginPassword string
	Location                   string
	Version                    string
}

// DatabaseServerCreateResponse represents the response following the creation of
// a database server on Azure.
type DatabaseServerCreateResponse struct {
	ServerName string
}

const (
	DatabaseServerVersion11 = "2.0"
	DatabaseServerVersion12 = "12.0"
)

// DatabaseServer represents the set of data recieved from
// a database server list operation.
//
// https://msdn.microsoft.com/en-us/library/azure/dn505702.aspx
type DatabaseServer struct {
	Name                     string
	AdministratorLogin       string
	Location                 string
	FullyQualifiedDomainName string
	Version                  string
	State                    string
}

type ListServersResponse struct {
	DatabaseServers []DatabaseServer `xml:"Server"`
}

// DatabaseCreateParams represents the set of possible parameters when issuing
// a database creation to Azure, and reading a list response from Azure.
//
// https://msdn.microsoft.com/en-us/library/azure/dn505701.aspx
type DatabaseCreateParams struct {
	XMLName            xml.Name `xml:"http://schemas.microsoft.com/windowsazure ServiceResource"`
	Name               string
	Edition            string `xml:",omitempty"`
	CollationName      string `xml:",omitempty"`
	MaxSizeBytes       int64  `xml:",omitempty"`
	ServiceObjectiveID string `xml:"ServiceObjectiveId,omitempty"`
}

// ServiceResource represents the set of parameters obtained from a database
// get or list call.
//
// https://msdn.microsoft.com/en-us/library/azure/dn505708.aspx
type ServiceResource struct {
	Name               string
	State              string
	SelfLink           string
	Edition            string
	CollationName      string
	MaxSizeBytes       int64
	ServiceObjectiveID string `xml:"ServiceObjectiveId,omitempty"`
}

type ListDatabasesResponse struct {
	ServiceResources []ServiceResource `xml:"ServiceResource"`
}

// ServiceResourceUpdateParams represents the set of parameters available
// for a database service update operation.
//
// https://msdn.microsoft.com/en-us/library/azure/dn505718.aspx
type ServiceResourceUpdateParams struct {
	XMLName            xml.Name `xml:"http://schemas.microsoft.com/windowsazure ServiceResource"`
	Name               string
	Edition            string `xml:",omitempty"`
	MaxSizeBytes       int64  `xml:",omitempty"`
	ServiceObjectiveID string `xml:"ServiceObjectiveId,omitempty"`
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"bytes"
	"flag"
	"fmt"
	"go/build"
	"io"
	"io/ioutil"
	"log"
	"os"
	"os/exec"
	"path/filepath"
	"regexp"
	"strings"
	"sync"

	"github.com/yookoala/realpath"
)

const (
	helpString = `
usage: overalls -project=[path] -covermode[mode] OPTIONS

overalls recursively traverses your projects directory structure
running 'go test -covermode=count -coverprofile=profile.coverprofile'
in each directory with go test files, concatenates them into one
coverprofile in your root directory named 'overalls.coverprofile'

OPTIONS
  -project
	Your project path relative to the '$GOPATH/src' directory
	example: -project=github.com/go-playground/overalls

  -covermode
    Mode to run when testing files.
    default:count

OPTIONAL

  -go-binary
    An alternative 'go' binary to run the tests, for example to use 'richgo' for
		more human-friendly output.
    example: -go-binary=richgo
    default: 'go'

  -ignore
    A comma separated list of directory names to ignore, relative to project path.
    example: -ignore=[.git,.hiddentdir...]
    default: '.git,vendor'

  -debug
    A flag indicating whether to print debug messages.
    example: -debug
    default:false

  -concurrency
    Limit the number of packages being processed at one time.
    The minimum value must be 2 or more when set.
    example: -concurrency=5
    default: unlimited
`
)

const (
	defaultIgnores = ".git,vendor"
	outFilename    = "overalls.coverprofile"
	pkgFilename    = "profile.coverprofile"
)

var (
	modeRegex       = regexp.MustCompile("mode: [a-z]+\n")
	srcPath         string
	projectPath     string
	goBinary        string
	ignoreFlag      string
	projectFlag     string
	coverFlag       string
	helpFlag        bool
	debugFlag       bool
	concurrencyFlag int
	isLimited       bool
	emptyStruct     struct{}
	ignores         = map[string]struct{}{}
	flagArgs        []string
)

func help() {
	fmt.Printf(helpString)
}

func init() {
	flag.StringVar(&goBinary, "go-binary", "go", "Use an alternative test runner such as 'richgo'")
	flag.StringVar(&projectFlag, "project", "", "-project [path]: relative to the '$GOPATH/src' directory")
	flag.StringVar(&coverFlag, "covermode", "count", "Mode to run when testing files")
	flag.StringVar(&ignoreFlag, "ignore", defaultIgnores, "-ignore [dir1,dir2...]: comma separated list of directory names to ignore")
	flag.IntVar(&concurrencyFlag, "concurrency", -1, "-concurrency [int]: number of packages to process concurrently, The minimum value must be 2 or more when set.")
	flag.BoolVar(&debugFlag, "debug", false, "-debug [true|false]")
	flag.BoolVar(&helpFlag, "help", false, "-help")
}

func parseFlags(logger *log.Logger) {

	flag.Parse()

	if helpFlag {
		help()
		os.Exit(0)
	}

	if debugFlag {
		fmt.Println("GOPATH:", os.Getenv("GOPATH"))
	}

	fmt.Println("|", projectFlag)
	projectFlag = filepath.Clean(projectFlag)

	if debugFlag {
		fmt.Println("Project Path:", projectFlag)
	}

	if len(projectFlag) == 0 || projectFlag == "." {
		fmt.Printf("\n**invalid project path '%s'\n", projectFlag)
		help()
		os.Exit(1)
	}

	pkg, err := build.Default.Import(projectFlag, "", build.FindOnly)
	if err != nil {
		fmt.Printf("\n**could not find project path '%s' in GOPATH '%s'\n", projectFlag, os.Getenv("GOPATH"))
		os.Exit(1)
	}
	srcPath = pkg.SrcRoot

	flagArgs = flag.Args()

	switch coverFlag {
	case "set", "atomic":
	case "count":
		for _, flg := range flagArgs {
			if flg == "-race" {
				logger.Println("\n*****\n** WARNING: some common patterns in parallel code can trigger race conditions when using coverprofile=count and the -race flag; in which case coverprofile=atomic should be used.\n*****")
				break
			}
		}
	default:
		fmt.Printf("\n**invalid covermode '%s'\n", coverFlag)
		os.Exit(1)
	}

	arr := strings.Split(ignoreFlag, ",")
	for _, v := range arr {
		ignores[v] = emptyStruct
	}

	isLimited = concurrencyFlag != -1

	if isLimited && concurrencyFlag < 1 {
		fmt.Printf("\n**invalid concurrency value '%d', value must be at least 1\n", concurrencyFlag)
		os.Exit(1)
	}
}

func main() {
	logger := log.New(os.Stdout, "", log.LstdFlags)
	runMain(logger)
}

func runMain(logger *log.Logger) {
	parseFlags(logger)

	var err error
	var wd string

	projectPath = filepath.Join(srcPath, projectFlag)

	if err = os.Chdir(projectPath); err != nil {
		logger.Printf("\n**invalid project path '%s'\n%s\n", projectFlag, err)
		help()
		os.Exit(1)
	}

	if debugFlag {
		wd, err = os.Getwd()
		if err != nil {
			fmt.Println(err)
		}

		logger.Println("Working DIR:", wd)
	}

	testFiles(logger)
}

func scanOutput(r io.ReadCloser, fn func(...interface{})) {
	defer r.Close()
	bs := bufio.NewScanner(r)
	for bs.Scan() {
		fn(bs.Text())
	}
	if err := bs.Err(); err != nil {
		fn(fmt.Sprintf("Scan error: %v", err.Error()))
	}
}

func processDIR(logger *log.Logger, wg *sync.WaitGroup, fullPath, relPath string, out chan<- []byte, semaphore chan struct{}) {
	defer wg.Done()

	if isLimited {
		semaphore <- struct{}{}
	}

	// 1 for "test", 4 for covermode, coverprofile, outputdir, relpath
	args := make([]string, 1, 1+len(flagArgs)+4)
	args[0] = "test"
	// To split '-- <go test arguments> -args <program arguments>'
	for i, arg := range flagArgs {
		if arg == "-args" {
			args = append(args, flagArgs[:i]...)
			flagArgs = flagArgs[i:]
			break
		}
	}
	args = append(args, "-covermode="+coverFlag, "-coverprofile="+pkgFilename, "-outputdir="+fullPath+"/", relPath)
	args = append(args, flagArgs...)
	fmt.Printf("Test args: %+v\n", args)

	cmd := exec.Command(goBinary, args...)
	if debugFlag {
		logger.Println("Processing:", strings.Join(cmd.Args, " "))
	}

	stdout, err := cmd.StdoutPipe()
	if err != nil {
		logger.Fatal("Unable to get process stdout")
	}
	stderr, err := cmd.StderrPipe()
	if err != nil {
		logger.Fatal("Unable to get process stderr")
	}

	if err := cmd.Start(); err != nil {
		logger.Fatal("ERROR:", err)
	}
	scanOutput(stdout, logger.Print)
	scanOutput(stderr, logger.Print)
	if err := cmd.Wait(); err != nil {
		logger.Fatal("ERROR:", err)
	}

	b, err := ioutil.ReadFile(relPath + "/profile.coverprofile")
	if err != nil {
		logger.Fatal("ERROR:", err)
	}

	out <- b

	if isLimited {
		<-semaphore
	}
}

// walk is like filepath.Walk, but it follows symlinks and only calls walkFunc on directories.
func walkDirectories(path string, walkFunc func(path string, info os.FileInfo) error) error {
	seen := make(map[string]bool)

	var walkHelper func(path string) error
	walkHelper = func(path string) error {
		qualifiedPath, err := realpath.Realpath(path)
		if err != nil {
			return err
		}

		// Prevent circular links.
		if seen[qualifiedPath] {
			return nil
		}
		seen[qualifiedPath] = true

		// Skip anything that isn't a directory.
		file, err := os.Stat(path)
		if err != nil {
			return err
		}
		if !file.IsDir() {
			return nil
		}

		err = walkFunc(path, file)
		if err != nil {
			if err == filepath.SkipDir {
				return nil
			}
			return err
		}

		files, err := ioutil.ReadDir(path)
		if err != nil {
			return err
		}

		for _, file := range files {
			err = walkHelper(filepath.Join(path, file.Name()))
			if err != nil {
				return err
			}
		}
		return nil
	}
	return walkHelper(path)
}

func testFiles(logger *log.Logger) {

	var semaphore chan struct{}

	if isLimited {
		semaphore = make(chan struct{}, concurrencyFlag)
	}

	out := make(chan []byte)
	wg := &sync.WaitGroup{}

	walker := func(path string, info os.FileInfo) error {
		rel, err := filepath.Rel(projectPath, path)
		if err != nil {
			logger.Fatalf("Could not make path '%s' relative to project path '%s'", path, projectPath)
		}

		if _, ignore := ignores[rel]; ignore {
			return filepath.SkipDir
		}

		rel = "./" + rel

		if files, err := filepath.Glob(rel + "/*_test.go"); len(files) == 0 || err != nil {

			if err != nil {
				logger.Fatal("Error checking for test files")
			}

			if debugFlag {
				logger.Println("No Go Test files in DIR:", rel, "skipping")
			}

			return nil
		}

		wg.Add(1)

		go processDIR(logger, wg, path, rel, out, semaphore)

		return nil
	}

	if err := walkDirectories(projectPath, walker); err != nil {
		logger.Fatalf("\n**could not walk project path '%s'\n%s\n", projectPath, err)
	}

	go func() {
		wg.Wait()
		close(out)

		if isLimited {
			close(semaphore)
		}
	}()

	buff := bytes.NewBufferString("")

	for cover := range out {
		buff.Write(cover)
	}

	final := buff.String()
	final = modeRegex.ReplaceAllString(final, "")
	final = "mode: " + coverFlag + "\n" + final

	if err := ioutil.WriteFile(outFilename, []byte(final), 0644); err != nil {
		logger.Fatal("ERROR Writing \""+outFilename+"\"", err)
	}
}
<commit_msg>optionally output to file as well as logger<commit_after>package main

import (
	"bufio"
	"bytes"
	"flag"
	"fmt"
	"go/build"
	"io"
	"io/ioutil"
	"log"
	"os"
	"os/exec"
	"path/filepath"
	"regexp"
	"strings"
	"sync"

	"github.com/yookoala/realpath"
)

const (
	helpString = `
usage: overalls -project=[path] -covermode[mode] OPTIONS

overalls recursively traverses your projects directory structure
running 'go test -covermode=count -coverprofile=profile.coverprofile'
in each directory with go test files, concatenates them into one
coverprofile in your root directory named 'overalls.coverprofile'

OPTIONS
  -project
	Your project path relative to the '$GOPATH/src' directory
	example: -project=github.com/go-playground/overalls

  -covermode
    Mode to run when testing files.
    default:count

OPTIONAL

  -go-binary
    An alternative 'go' binary to run the tests, for example to use 'richgo' for
		more human-friendly output.
    example: -go-binary=richgo
    default: 'go'

  -ignore
    A comma separated list of directory names to ignore, relative to project path.
    example: -ignore=[.git,.hiddentdir...]
    default: '.git,vendor'

  -debug
    A flag indicating whether to print debug messages.
    example: -debug
    default:false

  -concurrency
    Limit the number of packages being processed at one time.
    The minimum value must be 2 or more when set.
    example: -concurrency=5
    default: unlimited

  -outfile
   In addition to stdout, write all output to this file.
`
)

const (
	defaultIgnores = ".git,vendor"
	outFilename    = "overalls.coverprofile"
	pkgFilename    = "profile.coverprofile"
)

var (
	modeRegex       = regexp.MustCompile("mode: [a-z]+\n")
	srcPath         string
	projectPath     string
	goBinary        string
	ignoreFlag      string
	projectFlag     string
	coverFlag       string
	outPath         string
	helpFlag        bool
	debugFlag       bool
	concurrencyFlag int
	isLimited       bool
	emptyStruct     struct{}
	ignores         = map[string]struct{}{}
	flagArgs        []string
	outputFunc      func(...interface{})
)

func help() {
	fmt.Printf(helpString)
}

func init() {
	flag.StringVar(&goBinary, "go-binary", "go", "Use an alternative test runner such as 'richgo'")
	flag.StringVar(&projectFlag, "project", "", "-project [path]: relative to the '$GOPATH/src' directory")
	flag.StringVar(&coverFlag, "covermode", "count", "Mode to run when testing files")
	flag.StringVar(&ignoreFlag, "ignore", defaultIgnores, "-ignore [dir1,dir2...]: comma separated list of directory names to ignore")
	flag.StringVar(&outPath, "outfile", "", "write output to this file as well as stdout")
	flag.IntVar(&concurrencyFlag, "concurrency", -1, "-concurrency [int]: number of packages to process concurrently, The minimum value must be 2 or more when set.")
	flag.BoolVar(&debugFlag, "debug", false, "-debug [true|false]")
	flag.BoolVar(&helpFlag, "help", false, "-help")
}

func parseFlags(logger *log.Logger) {

	flag.Parse()

	if helpFlag {
		help()
		os.Exit(0)
	}

	if debugFlag {
		fmt.Println("GOPATH:", os.Getenv("GOPATH"))
	}

	fmt.Println("|", projectFlag)
	projectFlag = filepath.Clean(projectFlag)

	if debugFlag {
		fmt.Println("Project Path:", projectFlag)
	}

	if len(projectFlag) == 0 || projectFlag == "." {
		fmt.Printf("\n**invalid project path '%s'\n", projectFlag)
		help()
		os.Exit(1)
	}

	pkg, err := build.Default.Import(projectFlag, "", build.FindOnly)
	if err != nil {
		fmt.Printf("\n**could not find project path '%s' in GOPATH '%s'\n", projectFlag, os.Getenv("GOPATH"))
		os.Exit(1)
	}
	srcPath = pkg.SrcRoot

	flagArgs = flag.Args()

	switch coverFlag {
	case "set", "atomic":
	case "count":
		for _, flg := range flagArgs {
			if flg == "-race" {
				logger.Println("\n*****\n** WARNING: some common patterns in parallel code can trigger race conditions when using coverprofile=count and the -race flag; in which case coverprofile=atomic should be used.\n*****")
				break
			}
		}
	default:
		fmt.Printf("\n**invalid covermode '%s'\n", coverFlag)
		os.Exit(1)
	}

	arr := strings.Split(ignoreFlag, ",")
	for _, v := range arr {
		ignores[v] = emptyStruct
	}

	isLimited = concurrencyFlag != -1

	if isLimited && concurrencyFlag < 1 {
		fmt.Printf("\n**invalid concurrency value '%d', value must be at least 1\n", concurrencyFlag)
		os.Exit(1)
	}

	outputFunc = createLogfunc(logger)
}

func createLogfunc(logger *log.Logger) func(...interface{}) {
	if outPath == "" {
		return logger.Print
	}
	fd, err := os.Create(outPath)
	if err != nil {
		logger.Printf("unable to open %s for writing", outPath)
		return logger.Print
	}

	return func(args ...interface{}) {
		logger.Print(args...)
		fmt.Fprintln(fd, args...)
	}
}

func main() {
	logger := log.New(os.Stdout, "", log.LstdFlags)
	runMain(logger)
}

func runMain(logger *log.Logger) {
	parseFlags(logger)

	var err error
	var wd string

	projectPath = filepath.Join(srcPath, projectFlag)

	if err = os.Chdir(projectPath); err != nil {
		logger.Printf("\n**invalid project path '%s'\n%s\n", projectFlag, err)
		help()
		os.Exit(1)
	}

	if debugFlag {
		wd, err = os.Getwd()
		if err != nil {
			fmt.Println(err)
		}

		logger.Println("Working DIR:", wd)
	}

	testFiles(logger)
}

func scanOutput(r io.ReadCloser, fn func(...interface{})) {
	defer r.Close()
	bs := bufio.NewScanner(r)
	for bs.Scan() {
		fn(bs.Text())
	}
	if err := bs.Err(); err != nil {
		fn(fmt.Sprintf("Scan error: %v", err.Error()))
	}
}

func processDIR(logger *log.Logger, wg *sync.WaitGroup, fullPath, relPath string, out chan<- []byte, semaphore chan struct{}) {
	defer wg.Done()

	if isLimited {
		semaphore <- struct{}{}
	}

	// 1 for "test", 4 for covermode, coverprofile, outputdir, relpath
	args := make([]string, 1, 1+len(flagArgs)+4)
	args[0] = "test"
	// To split '-- <go test arguments> -args <program arguments>'
	for i, arg := range flagArgs {
		if arg == "-args" {
			args = append(args, flagArgs[:i]...)
			flagArgs = flagArgs[i:]
			break
		}
	}
	args = append(args, "-covermode="+coverFlag, "-coverprofile="+pkgFilename, "-outputdir="+fullPath+"/", relPath)
	args = append(args, flagArgs...)
	fmt.Printf("Test args: %+v\n", args)

	cmd := exec.Command(goBinary, args...)
	if debugFlag {
		logger.Println("Processing:", strings.Join(cmd.Args, " "))
	}

	stdout, err := cmd.StdoutPipe()
	if err != nil {
		logger.Fatal("Unable to get process stdout")
	}
	stderr, err := cmd.StderrPipe()
	if err != nil {
		logger.Fatal("Unable to get process stderr")
	}

	if err := cmd.Start(); err != nil {
		logger.Fatal("ERROR:", err)
	}

	scanOutput(stdout, outputFunc)
	scanOutput(stderr, outputFunc)

	if err := cmd.Wait(); err != nil {
		logger.Fatal("ERROR:", err)
	}

	b, err := ioutil.ReadFile(relPath + "/profile.coverprofile")
	if err != nil {
		logger.Fatal("ERROR:", err)
	}

	out <- b

	if isLimited {
		<-semaphore
	}
}

// walk is like filepath.Walk, but it follows symlinks and only calls walkFunc on directories.
func walkDirectories(path string, walkFunc func(path string, info os.FileInfo) error) error {
	seen := make(map[string]bool)

	var walkHelper func(path string) error
	walkHelper = func(path string) error {
		qualifiedPath, err := realpath.Realpath(path)
		if err != nil {
			return err
		}

		// Prevent circular links.
		if seen[qualifiedPath] {
			return nil
		}
		seen[qualifiedPath] = true

		// Skip anything that isn't a directory.
		file, err := os.Stat(path)
		if err != nil {
			return err
		}
		if !file.IsDir() {
			return nil
		}

		err = walkFunc(path, file)
		if err != nil {
			if err == filepath.SkipDir {
				return nil
			}
			return err
		}

		files, err := ioutil.ReadDir(path)
		if err != nil {
			return err
		}

		for _, file := range files {
			err = walkHelper(filepath.Join(path, file.Name()))
			if err != nil {
				return err
			}
		}
		return nil
	}
	return walkHelper(path)
}

func testFiles(logger *log.Logger) {

	var semaphore chan struct{}

	if isLimited {
		semaphore = make(chan struct{}, concurrencyFlag)
	}

	out := make(chan []byte)
	wg := &sync.WaitGroup{}

	walker := func(path string, info os.FileInfo) error {
		rel, err := filepath.Rel(projectPath, path)
		if err != nil {
			logger.Fatalf("Could not make path '%s' relative to project path '%s'", path, projectPath)
		}

		if _, ignore := ignores[rel]; ignore {
			return filepath.SkipDir
		}

		rel = "./" + rel

		if files, err := filepath.Glob(rel + "/*_test.go"); len(files) == 0 || err != nil {

			if err != nil {
				logger.Fatal("Error checking for test files")
			}

			if debugFlag {
				logger.Println("No Go Test files in DIR:", rel, "skipping")
			}

			return nil
		}

		wg.Add(1)

		go processDIR(logger, wg, path, rel, out, semaphore)

		return nil
	}

	if err := walkDirectories(projectPath, walker); err != nil {
		logger.Fatalf("\n**could not walk project path '%s'\n%s\n", projectPath, err)
	}

	go func() {
		wg.Wait()
		close(out)

		if isLimited {
			close(semaphore)
		}
	}()

	buff := bytes.NewBufferString("")

	for cover := range out {
		buff.Write(cover)
	}

	final := buff.String()
	final = modeRegex.ReplaceAllString(final, "")
	final = "mode: " + coverFlag + "\n" + final

	if err := ioutil.WriteFile(outFilename, []byte(final), 0644); err != nil {
		logger.Fatal("ERROR Writing \""+outFilename+"\"", err)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"os"
	"os/exec"
	"strings"
)

type Result struct {
	Arguments []string `json:"args"`
	About     string   `json:"about"`
	Stdout    string   `json:"stdout"`
	Stderr    string   `json:"stderr"`
	Success   bool     `json:"success"`
}

func Spruce(where string, args ...string) (*Result, error) {
	r := &Result{Arguments: args}

	cmd := exec.Command("spruce", args...)
	stdout, err := cmd.StdoutPipe()
	if err != nil {
		log.Printf("failed to get stdout pipe from command: %s", err)
		return nil, err
	}
	stderr, err := cmd.StderrPipe()
	if err != nil {
		log.Printf("failed to get stderr pipe from command: %s", err)
		return nil, err
	}

	if where != "" {
		err = os.Chdir(where)
		if err != nil {
			log.Printf("failed to chdir to %s: %s", where, err)
			return nil, err
		}
	}
	where, _ = os.Getwd()
	log.Printf("running `spruce %v' in %s", args, where)
	err = cmd.Start()
	if err != nil {
		return nil, err
	}

	output := make(chan string)
	errors := make(chan string)
	drain := func(rd io.Reader, out chan string) {
		var buf []string
		s := bufio.NewScanner(rd)
		for s.Scan() {
			buf = append(buf, s.Text()+"\n")
		}
		out <- strings.Join(buf, "")
		close(out)
	}
	go drain(stdout, output)
	go drain(stderr, errors)

	err = cmd.Wait()
	r.Success = (err != nil)
	r.Stdout = <-output
	r.Stderr = <-errors
	return r, nil
}

type Merge struct {
	Prune []string
	YAML  []struct {
		Filename string
		Contents string
	}

	Debug bool
	Trace bool
}

func SpruceMerge(m Merge) (*Result, error) {
	dir, err := ioutil.TempDir("", "web")
	if err != nil {
		log.Printf("failed to create temporary working directory: %s", err)
		return nil, err
	}
	// defer rm() the dir

	var args []string
	if m.Debug {
		args = append(args, "--debug")
	}
	if m.Trace {
		args = append(args, "--trace")
	}
	args = append(args, "merge")

	if len(m.Prune) > 0 {
		args = append(args, "--prune")
		for _, f := range m.Prune {
			args = append(args, f)
		}
	}
	for _, y := range m.YAML {
		args = append(args, y.Filename)
		ioutil.WriteFile(
			fmt.Sprintf("%s/%s", dir, y.Filename),
			[]byte(y.Contents),
			os.FileMode(0400),
		)
	}

	result, err := Spruce(dir, args...)
	if version, err := Spruce("", "-v"); err == nil {
		result.About = version.Stdout + version.Stderr
	} else {
		log.Printf("failed to determine spruce version information: %s", err)
	}
	return result, err
}
<commit_msg>Handle multiple `--prune' options<commit_after>package main

import (
	"bufio"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"os"
	"os/exec"
	"strings"
)

type Result struct {
	Arguments []string `json:"args"`
	About     string   `json:"about"`
	Stdout    string   `json:"stdout"`
	Stderr    string   `json:"stderr"`
	Success   bool     `json:"success"`
}

func Spruce(where string, args ...string) (*Result, error) {
	r := &Result{Arguments: args}

	cmd := exec.Command("spruce", args...)
	stdout, err := cmd.StdoutPipe()
	if err != nil {
		log.Printf("failed to get stdout pipe from command: %s", err)
		return nil, err
	}
	stderr, err := cmd.StderrPipe()
	if err != nil {
		log.Printf("failed to get stderr pipe from command: %s", err)
		return nil, err
	}

	if where != "" {
		err = os.Chdir(where)
		if err != nil {
			log.Printf("failed to chdir to %s: %s", where, err)
			return nil, err
		}
	}
	where, _ = os.Getwd()
	log.Printf("running `spruce %v' in %s", args, where)
	err = cmd.Start()
	if err != nil {
		return nil, err
	}

	output := make(chan string)
	errors := make(chan string)
	drain := func(rd io.Reader, out chan string) {
		var buf []string
		s := bufio.NewScanner(rd)
		for s.Scan() {
			buf = append(buf, s.Text()+"\n")
		}
		out <- strings.Join(buf, "")
		close(out)
	}
	go drain(stdout, output)
	go drain(stderr, errors)

	err = cmd.Wait()
	r.Success = (err != nil)
	r.Stdout = <-output
	r.Stderr = <-errors
	return r, nil
}

type Merge struct {
	Prune []string
	YAML  []struct {
		Filename string
		Contents string
	}

	Debug bool
	Trace bool
}

func SpruceMerge(m Merge) (*Result, error) {
	dir, err := ioutil.TempDir("", "web")
	if err != nil {
		log.Printf("failed to create temporary working directory: %s", err)
		return nil, err
	}
	// defer rm() the dir

	var args []string
	if m.Debug {
		args = append(args, "--debug")
	}
	if m.Trace {
		args = append(args, "--trace")
	}
	args = append(args, "merge")

	if len(m.Prune) > 0 {
		for _, f := range m.Prune {
			args = append(args, "--prune")
			args = append(args, f)
		}
	}
	for _, y := range m.YAML {
		args = append(args, y.Filename)
		ioutil.WriteFile(
			fmt.Sprintf("%s/%s", dir, y.Filename),
			[]byte(y.Contents),
			os.FileMode(0400),
		)
	}

	result, err := Spruce(dir, args...)
	if version, err := Spruce("", "-v"); err == nil {
		result.About = version.Stdout + version.Stderr
	} else {
		log.Printf("failed to determine spruce version information: %s", err)
	}
	return result, err
}
<|endoftext|>