<commit_before>// Copyright 2014 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.

// Package debug provides GL-based debugging tools for apps.
package debug // import "golang.org/x/mobile/exp/app/debug"

import (
	"image"
	"image/color"
	"image/draw"
	"sync"
	"time"

	"golang.org/x/mobile/event"
	"golang.org/x/mobile/exp/gl/glutil"
	"golang.org/x/mobile/geom"
)

var lastDraw = time.Now()

var fps struct {
	mu sync.Mutex
	c  event.Config
	m  *glutil.Image
}

// DrawFPS draws the per second framerate in the bottom-left of the screen.
func DrawFPS(c event.Config) {
	fps.mu.Lock()
	if fps.c != c || fps.m == nil {
		fps.c = c
		fps.m = glutil.NewImage(7*(fontWidth+1)+1, fontHeight+2)
	}
	fps.mu.Unlock()

	display := [7]byte{
		4: 'F',
		5: 'P',
		6: 'S',
	}
	now := time.Now()
	f := 0
	if dur := now.Sub(lastDraw); dur > 0 {
		f = int(time.Second / dur)
	}
	display[2] = '0' + byte((f/1e0)%10)
	display[1] = '0' + byte((f/1e1)%10)
	display[0] = '0' + byte((f/1e2)%10)
	draw.Draw(fps.m.RGBA, fps.m.RGBA.Bounds(), image.White, image.Point{}, draw.Src)
	for i, c := range display {
		glyph := glyphs[c]
		if len(glyph) != fontWidth*fontHeight {
			continue
		}
		for y := 0; y < fontHeight; y++ {
			for x := 0; x < fontWidth; x++ {
				if glyph[fontWidth*y+x] == ' ' {
					continue
				}
				fps.m.RGBA.SetRGBA((fontWidth+1)*i+x+1, y+1, color.RGBA{A: 0xff})
			}
		}
	}

	fps.m.Upload()
	fps.m.Draw(
		c,
		geom.Point{0, c.Height - 12},
		geom.Point{50, c.Height - 12},
		geom.Point{0, c.Height},
		fps.m.Bounds(),
	)

	lastDraw = now
}

const (
	fontWidth  = 5
	fontHeight = 7
)

// glyphs comes from the 6x10 fixed font from the plan9port:
// https://github.com/9fans/plan9port/tree/master/font/fixed
//
// 6x10 becomes 5x7 because each glyph has a 1-pixel margin plus space for
// descenders.
//
// Its README file says that those fonts were converted from XFree86, and are
// in the public domain.
var glyphs = [256]string{
	'0': "" +
		"  X  " +
		" X X " +
		"X   X" +
		"X   X" +
		"X   X" +
		" X X " +
		"  X  ",
	'1': "" +
		"  X  " +
		" XX  " +
		"X X  " +
		"  X  " +
		"  X  " +
		"  X  " +
		"XXXXX",
	'2': "" +
		" XXX " +
		"X   X" +
		"    X" +
		"  XX " +
		" X   " +
		"X    " +
		"XXXXX",
	'3': "" +
		"XXXXX" +
		"    X" +
		"   X " +
		"  XX " +
		"    X" +
		"X   X" +
		" XXX ",
	'4': "" +
		"   X " +
		"  XX " +
		" X X " +
		"X  X " +
		"XXXXX" +
		"   X " +
		"   X ",
	'5': "" +
		"XXXXX" +
		"X    " +
		"X XX " +
		"XX  X" +
		"    X" +
		"X   X" +
		" XXX ",
	'6': "" +
		"  XX " +
		" X   " +
		"X    " +
		"X XX " +
		"XX  X" +
		"X   X" +
		" XXX ",
	'7': "" +
		"XXXXX" +
		"    X" +
		"   X " +
		"   X " +
		"  X  " +
		" X   " +
		" X   ",
	'8': "" +
		" XXX " +
		"X   X" +
		"X   X" +
		" XXX " +
		"X   X" +
		"X   X" +
		" XXX ",
	'9': "" +
		" XXX " +
		"X   X" +
		"X  XX" +
		" XX X" +
		"    X" +
		"   X " +
		" XX  ",
	'F': "" +
		"XXXXX" +
		"X    " +
		"X    " +
		"XXXX " +
		"X    " +
		"X    " +
		"X    ",
	'P': "" +
		"XXXX " +
		"X   X" +
		"X   X" +
		"XXXX " +
		"X    " +
		"X    " +
		"X    ",
	'S': "" +
		" XXX " +
		"X   X" +
		"X    " +
		" XXX " +
		"    X" +
		"X   X" +
		" XXX ",
}
<commit_msg>exp/app/debug: fit the FPS counter's aspect ratio to the backing image.<commit_after>// Copyright 2014 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.

// Package debug provides GL-based debugging tools for apps.
package debug // import "golang.org/x/mobile/exp/app/debug"

import (
	"image"
	"image/color"
	"image/draw"
	"sync"
	"time"

	"golang.org/x/mobile/event"
	"golang.org/x/mobile/exp/gl/glutil"
	"golang.org/x/mobile/geom"
)

var lastDraw = time.Now()

var fps struct {
	mu sync.Mutex
	c  event.Config
	m  *glutil.Image
}

// DrawFPS draws the per second framerate in the bottom-left of the screen.
func DrawFPS(c event.Config) {
	const imgW, imgH = 7*(fontWidth+1) + 1, fontHeight + 2

	fps.mu.Lock()
	if fps.c != c || fps.m == nil {
		fps.c = c
		fps.m = glutil.NewImage(imgW, imgH)
	}
	fps.mu.Unlock()

	display := [7]byte{
		4: 'F',
		5: 'P',
		6: 'S',
	}
	now := time.Now()
	f := 0
	if dur := now.Sub(lastDraw); dur > 0 {
		f = int(time.Second / dur)
	}
	display[2] = '0' + byte((f/1e0)%10)
	display[1] = '0' + byte((f/1e1)%10)
	display[0] = '0' + byte((f/1e2)%10)
	draw.Draw(fps.m.RGBA, fps.m.RGBA.Bounds(), image.White, image.Point{}, draw.Src)
	for i, c := range display {
		glyph := glyphs[c]
		if len(glyph) != fontWidth*fontHeight {
			continue
		}
		for y := 0; y < fontHeight; y++ {
			for x := 0; x < fontWidth; x++ {
				if glyph[fontWidth*y+x] == ' ' {
					continue
				}
				fps.m.RGBA.SetRGBA((fontWidth+1)*i+x+1, y+1, color.RGBA{A: 0xff})
			}
		}
	}

	fps.m.Upload()
	fps.m.Draw(
		c,
		geom.Point{0, c.Height - imgH},
		geom.Point{imgW, c.Height - imgH},
		geom.Point{0, c.Height},
		fps.m.Bounds(),
	)

	lastDraw = now
}

const (
	fontWidth  = 5
	fontHeight = 7
)

// glyphs comes from the 6x10 fixed font from the plan9port:
// https://github.com/9fans/plan9port/tree/master/font/fixed
//
// 6x10 becomes 5x7 because each glyph has a 1-pixel margin plus space for
// descenders.
//
// Its README file says that those fonts were converted from XFree86, and are
// in the public domain.
var glyphs = [256]string{
	'0': "" +
		"  X  " +
		" X X " +
		"X   X" +
		"X   X" +
		"X   X" +
		" X X " +
		"  X  ",
	'1': "" +
		"  X  " +
		" XX  " +
		"X X  " +
		"  X  " +
		"  X  " +
		"  X  " +
		"XXXXX",
	'2': "" +
		" XXX " +
		"X   X" +
		"    X" +
		"  XX " +
		" X   " +
		"X    " +
		"XXXXX",
	'3': "" +
		"XXXXX" +
		"    X" +
		"   X " +
		"  XX " +
		"    X" +
		"X   X" +
		" XXX ",
	'4': "" +
		"   X " +
		"  XX " +
		" X X " +
		"X  X " +
		"XXXXX" +
		"   X " +
		"   X ",
	'5': "" +
		"XXXXX" +
		"X    " +
		"X XX " +
		"XX  X" +
		"    X" +
		"X   X" +
		" XXX ",
	'6': "" +
		"  XX " +
		" X   " +
		"X    " +
		"X XX " +
		"XX  X" +
		"X   X" +
		" XXX ",
	'7': "" +
		"XXXXX" +
		"    X" +
		"   X " +
		"   X " +
		"  X  " +
		" X   " +
		" X   ",
	'8': "" +
		" XXX " +
		"X   X" +
		"X   X" +
		" XXX " +
		"X   X" +
		"X   X" +
		" XXX ",
	'9': "" +
		" XXX " +
		"X   X" +
		"X  XX" +
		" XX X" +
		"    X" +
		"   X " +
		" XX  ",
	'F': "" +
		"XXXXX" +
		"X    " +
		"X    " +
		"XXXX " +
		"X    " +
		"X    " +
		"X    ",
	'P': "" +
		"XXXX " +
		"X   X" +
		"X   X" +
		"XXXX " +
		"X    " +
		"X    " +
		"X    ",
	'S': "" +
		" XXX " +
		"X   X" +
		"X    " +
		" XXX " +
		"    X" +
		"X   X" +
		" XXX ",
}
<|endoftext|>


<commit_before>package primes

import (
	"math"
	"testing"

	. "github.com/smartystreets/goconvey/convey"
)

func TestEratosthenes(t *testing.T) {
	Convey("Eratosthene algorithm should work", t, func() {
		max := uint64(10000)
		s := NewEratosthenes(max)
		So(s.Len(), ShouldEqual, 1251)
		numPrimes := 0
		for i := uint64(0); i <= max; i++ {
			if s.IsPrime(i) {
				numPrimes++
				So(isPrime(i), ShouldBeTrue)
			} else {
				So(isPrime(i), ShouldBeFalse)
			}
		}
		So(numPrimes, ShouldEqual, 1229)
	})
}

// a very naïve approach to testing for primes
func isPrime(val uint64) bool {
	if val == 0 || val == 1 {
		return false
	}

	if val == 2 {
		return true
	}

	for i := uint64(2); i <= uint64(math.Sqrt(float64(val))); i++ {
		if val%i == 0 {
			return false
		}
	}

	return true
}
<commit_msg>add more tests<commit_after>package primes

import (
	"math"
	"testing"

	. "github.com/smartystreets/goconvey/convey"
)

func TestEratosthenes(t *testing.T) {
	Convey("Eratosthene algorithm should work", t, func() {
		max := uint64(10000)
		s := NewEratosthenes(max)
		So(s.Len(), ShouldEqual, 1251)
		numPrimes := 0
		for i := uint64(0); i <= max; i++ {
			if s.IsPrime(i) {
				numPrimes++
				So(isPrime(i), ShouldBeTrue)
			} else {
				So(isPrime(i), ShouldBeFalse)
			}
		}
		So(numPrimes, ShouldEqual, 1229)
		ps := s.ListPrimes()
		So(len(ps), ShouldEqual, 1230)
		for _, p := range ps {
			So(isPrime(p), ShouldBeTrue)
		}
	})
}

// a very naïve approach to testing for primes
func isPrime(val uint64) bool {
	if val == 0 || val == 1 {
		return false
	}

	if val == 2 {
		return true
	}

	for i := uint64(2); i <= uint64(math.Sqrt(float64(val))); i++ {
		if val%i == 0 {
			return false
		}
	}

	return true
}
<|endoftext|>


<commit_before>// Tor websocket server transport plugin.
//
// Usage:
// ServerTransportPlugin websocket exec ./websocket-server --port 9901

package main

import (
	"encoding/base64"
	"errors"
	"flag"
	"fmt"
	"io"
	"net"
	"net/http"
	"os"
	"os/signal"
	"sync"
	"time"
)

var logFile = os.Stderr

var ptInfo PtServerInfo

// When a connection handler starts, +1 is written to this channel; when it
// ends, -1 is written.
var handlerChan = make(chan int)

var logMutex sync.Mutex

func Log(format string, v ...interface{}) {
	dateStr := time.Now().Format("2006-01-02 15:04:05")
	logMutex.Lock()
	defer logMutex.Unlock()
	msg := fmt.Sprintf(format, v...)
	fmt.Fprintf(logFile, "%s %s\n", dateStr, msg)
}

// An abstraction that makes an underlying WebSocket connection look like an
// io.ReadWriteCloser. It internally takes care of things like base64 encoding and
// decoding.
type websocketConn struct {
	Ws         *Websocket
	Base64     bool
	messageBuf []byte
}

// Implements io.Reader.
func (conn *websocketConn) Read(b []byte) (n int, err error) {
	for len(conn.messageBuf) == 0 {
		var m WebsocketMessage
		m, err = conn.Ws.ReadMessage()
		if err != nil {
			return
		}
		if m.Opcode == 8 {
			err = io.EOF
			return
		}
		if conn.Base64 {
			if m.Opcode != 1 {
				err = errors.New(fmt.Sprintf("got non-text opcode %d with the base64 subprotocol", m.Opcode))
				return
			}
			conn.messageBuf = make([]byte, base64.StdEncoding.DecodedLen(len(m.Payload)))
			var num int
			num, err = base64.StdEncoding.Decode(conn.messageBuf, m.Payload)
			if err != nil {
				return
			}
			conn.messageBuf = conn.messageBuf[:num]
		} else {
			if m.Opcode != 2 {
				err = errors.New(fmt.Sprintf("got non-binary opcode %d with no subprotocol", m.Opcode))
				return
			}
			conn.messageBuf = m.Payload
		}
	}

	n = copy(b, conn.messageBuf)
	conn.messageBuf = conn.messageBuf[n:]

	return
}

// Implements io.Writer.
func (conn *websocketConn) Write(b []byte) (n int, err error) {
	if conn.Base64 {
		buf := make([]byte, base64.StdEncoding.EncodedLen(len(b)))
		base64.StdEncoding.Encode(buf, b)
		err = conn.Ws.WriteMessage(1, buf)
		if err != nil {
			return
		}
		n = len(b)
	} else {
		err = conn.Ws.WriteMessage(2, b)
		n = len(b)
	}
	return
}

// Implements io.Closer.
func (conn *websocketConn) Close() (err error) {
	err = conn.Ws.WriteFrame(8, nil)
	if err != nil {
		conn.Ws.Conn.Close()
		return
	}
	err = conn.Ws.Conn.Close()
	return
}

// Create a new websocketConn.
func NewWebsocketConn(ws *Websocket) websocketConn {
	var conn websocketConn
	conn.Ws = ws
	conn.Base64 = (ws.Subprotocol == "base64")
	return conn
}

// Copy from WebSocket to socket and vice versa.
func proxy(local *net.TCPConn, conn *websocketConn) {
	var wg sync.WaitGroup

	wg.Add(2)

	go func() {
		_, err := io.Copy(conn, local)
		if err != nil {
			Log("error copying ORPort to WebSocket: " + err.Error())
		}
		local.CloseRead()
		conn.Close()
		wg.Done()
	}()

	go func() {
		_, err := io.Copy(local, conn)
		if err != nil {
			Log("error copying WebSocket to ORPort: " + err.Error())
		}
		local.CloseWrite()
		conn.Close()
		wg.Done()
	}()

	wg.Wait()
}

func websocketHandler(ws *Websocket) {
	conn := NewWebsocketConn(ws)

	handlerChan <- 1
	defer func() {
		handlerChan <- -1
	}()

	s, err := PtConnectOr(&ptInfo, ws.Conn)
	if err != nil {
		Log("Failed to connect to ORPort: " + err.Error())
		return
	}

	proxy(s, &conn)
}

func startListener(addr *net.TCPAddr) (*net.TCPListener, error) {
	ln, err := net.ListenTCP("tcp", addr)
	if err != nil {
		return nil, err
	}
	go func() {
		var config WebsocketConfig
		config.Subprotocols = []string{"base64"}
		// 16 kilobytes, possibly base64-encoded.
		config.MaxMessageSize = 16 * 1024 * 4 / 3 + 1
		http.Handle("/", config.Handler(websocketHandler))
		err = http.Serve(ln, nil)
		if err != nil {
			Log("http.Serve: " + err.Error())
		}
	}()
	return ln, nil
}

func main() {
	const ptMethodName = "websocket"
	var defaultPort int
	var logFilename string

	flag.IntVar(&defaultPort, "port", 0, "port to listen on if unspecified by Tor")
	flag.StringVar(&logFilename, "log", "", "log file to write to")
	flag.Parse()

	if logFilename != "" {
		f, err := os.OpenFile(logFilename, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0600)
		if err != nil {
			fmt.Fprintf(os.Stderr, "Can't open log file %q: %s.\n", logFilename, err.Error())
			os.Exit(1)
		}
		logFile = f
	}

	Log("starting")
	ptInfo = PtServerSetup([]string{ptMethodName})

	listeners := make([]*net.TCPListener, 0)
	for _, bindAddr := range ptInfo.BindAddrs {
		// Override tor's requested port (which is 0 if this transport
		// has not been run before) with the one requested by the --port
		// option.
		if defaultPort != 0 {
			bindAddr.Addr.Port = defaultPort
		}

		ln, err := startListener(bindAddr.Addr)
		if err != nil {
			PtSmethodError(bindAddr.MethodName, err.Error())
		}
		PtSmethod(bindAddr.MethodName, ln.Addr())
		Log("listening on %s", ln.Addr().String())
		listeners = append(listeners, ln)
	}
	PtSmethodsDone()

	var numHandlers int = 0

	signalChan := make(chan os.Signal, 1)
	signal.Notify(signalChan, os.Interrupt)
	var sigint bool = false
	for !sigint {
		select {
		case n := <-handlerChan:
			numHandlers += n
		case <-signalChan:
			Log("SIGINT")
			sigint = true
		}
	}

	for _, ln := range listeners {
		ln.Close()
	}

	sigint = false
	for numHandlers != 0 && !sigint {
		select {
		case n := <-handlerChan:
			numHandlers += n
		case <-signalChan:
			Log("SIGINT")
			sigint = true
		}
	}
}
<commit_msg>Ignore errors that may happen while trying to write a Close frame.<commit_after>// Tor websocket server transport plugin.
//
// Usage:
// ServerTransportPlugin websocket exec ./websocket-server --port 9901

package main

import (
	"encoding/base64"
	"errors"
	"flag"
	"fmt"
	"io"
	"net"
	"net/http"
	"os"
	"os/signal"
	"sync"
	"time"
)

var logFile = os.Stderr

var ptInfo PtServerInfo

// When a connection handler starts, +1 is written to this channel; when it
// ends, -1 is written.
var handlerChan = make(chan int)

var logMutex sync.Mutex

func Log(format string, v ...interface{}) {
	dateStr := time.Now().Format("2006-01-02 15:04:05")
	logMutex.Lock()
	defer logMutex.Unlock()
	msg := fmt.Sprintf(format, v...)
	fmt.Fprintf(logFile, "%s %s\n", dateStr, msg)
}

// An abstraction that makes an underlying WebSocket connection look like an
// io.ReadWriteCloser. It internally takes care of things like base64 encoding and
// decoding.
type websocketConn struct {
	Ws         *Websocket
	Base64     bool
	messageBuf []byte
}

// Implements io.Reader.
func (conn *websocketConn) Read(b []byte) (n int, err error) {
	for len(conn.messageBuf) == 0 {
		var m WebsocketMessage
		m, err = conn.Ws.ReadMessage()
		if err != nil {
			return
		}
		if m.Opcode == 8 {
			err = io.EOF
			return
		}
		if conn.Base64 {
			if m.Opcode != 1 {
				err = errors.New(fmt.Sprintf("got non-text opcode %d with the base64 subprotocol", m.Opcode))
				return
			}
			conn.messageBuf = make([]byte, base64.StdEncoding.DecodedLen(len(m.Payload)))
			var num int
			num, err = base64.StdEncoding.Decode(conn.messageBuf, m.Payload)
			if err != nil {
				return
			}
			conn.messageBuf = conn.messageBuf[:num]
		} else {
			if m.Opcode != 2 {
				err = errors.New(fmt.Sprintf("got non-binary opcode %d with no subprotocol", m.Opcode))
				return
			}
			conn.messageBuf = m.Payload
		}
	}

	n = copy(b, conn.messageBuf)
	conn.messageBuf = conn.messageBuf[n:]

	return
}

// Implements io.Writer.
func (conn *websocketConn) Write(b []byte) (n int, err error) {
	if conn.Base64 {
		buf := make([]byte, base64.StdEncoding.EncodedLen(len(b)))
		base64.StdEncoding.Encode(buf, b)
		err = conn.Ws.WriteMessage(1, buf)
		if err != nil {
			return
		}
		n = len(b)
	} else {
		err = conn.Ws.WriteMessage(2, b)
		n = len(b)
	}
	return
}

// Implements io.Closer.
func (conn *websocketConn) Close() error {
	// Ignore any error in trying to write a Close frame.
	_ = conn.Ws.WriteFrame(8, nil)
	return conn.Ws.Conn.Close()
}

// Create a new websocketConn.
func NewWebsocketConn(ws *Websocket) websocketConn {
	var conn websocketConn
	conn.Ws = ws
	conn.Base64 = (ws.Subprotocol == "base64")
	return conn
}

// Copy from WebSocket to socket and vice versa.
func proxy(local *net.TCPConn, conn *websocketConn) {
	var wg sync.WaitGroup

	wg.Add(2)

	go func() {
		_, err := io.Copy(conn, local)
		if err != nil {
			Log("error copying ORPort to WebSocket: " + err.Error())
		}
		local.CloseRead()
		conn.Close()
		wg.Done()
	}()

	go func() {
		_, err := io.Copy(local, conn)
		if err != nil {
			Log("error copying WebSocket to ORPort: " + err.Error())
		}
		local.CloseWrite()
		conn.Close()
		wg.Done()
	}()

	wg.Wait()
}

func websocketHandler(ws *Websocket) {
	conn := NewWebsocketConn(ws)

	handlerChan <- 1
	defer func() {
		handlerChan <- -1
	}()

	s, err := PtConnectOr(&ptInfo, ws.Conn)
	if err != nil {
		Log("Failed to connect to ORPort: " + err.Error())
		return
	}

	proxy(s, &conn)
}

func startListener(addr *net.TCPAddr) (*net.TCPListener, error) {
	ln, err := net.ListenTCP("tcp", addr)
	if err != nil {
		return nil, err
	}
	go func() {
		var config WebsocketConfig
		config.Subprotocols = []string{"base64"}
		// 16 kilobytes, possibly base64-encoded.
		config.MaxMessageSize = 16 * 1024 * 4 / 3 + 1
		http.Handle("/", config.Handler(websocketHandler))
		err = http.Serve(ln, nil)
		if err != nil {
			Log("http.Serve: " + err.Error())
		}
	}()
	return ln, nil
}

func main() {
	const ptMethodName = "websocket"
	var defaultPort int
	var logFilename string

	flag.IntVar(&defaultPort, "port", 0, "port to listen on if unspecified by Tor")
	flag.StringVar(&logFilename, "log", "", "log file to write to")
	flag.Parse()

	if logFilename != "" {
		f, err := os.OpenFile(logFilename, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0600)
		if err != nil {
			fmt.Fprintf(os.Stderr, "Can't open log file %q: %s.\n", logFilename, err.Error())
			os.Exit(1)
		}
		logFile = f
	}

	Log("starting")
	ptInfo = PtServerSetup([]string{ptMethodName})

	listeners := make([]*net.TCPListener, 0)
	for _, bindAddr := range ptInfo.BindAddrs {
		// Override tor's requested port (which is 0 if this transport
		// has not been run before) with the one requested by the --port
		// option.
		if defaultPort != 0 {
			bindAddr.Addr.Port = defaultPort
		}

		ln, err := startListener(bindAddr.Addr)
		if err != nil {
			PtSmethodError(bindAddr.MethodName, err.Error())
		}
		PtSmethod(bindAddr.MethodName, ln.Addr())
		Log("listening on %s", ln.Addr().String())
		listeners = append(listeners, ln)
	}
	PtSmethodsDone()

	var numHandlers int = 0

	signalChan := make(chan os.Signal, 1)
	signal.Notify(signalChan, os.Interrupt)
	var sigint bool = false
	for !sigint {
		select {
		case n := <-handlerChan:
			numHandlers += n
		case <-signalChan:
			Log("SIGINT")
			sigint = true
		}
	}

	for _, ln := range listeners {
		ln.Close()
	}

	sigint = false
	for numHandlers != 0 && !sigint {
		select {
		case n := <-handlerChan:
			numHandlers += n
		case <-signalChan:
			Log("SIGINT")
			sigint = true
		}
	}
}
<|endoftext|>


<commit_before>/* gorcon/track version 14.1.12 (lee8oi)

This Source Code Form is subject to the terms of the Mozilla Public
License, v. 2.0. If a copy of the MPL was not distributed with this
file, You can obtain one at http://mozilla.org/MPL/2.0/.

gorcon/track package contains the PlayerList types and the Tracker methods
needed to track player connections & stats.

*/
package track

import (
	"fmt"
	"github.com/lee8oi/gorcon"
	"strconv"
	"strings"
	"time"
)

type Player struct {
	Pid, Name, Profileid, Team, Level, Kit, Score,
	Kills, Deaths, Alive, Connected, Vip, Nucleus,
	Ping, Suicides string
	Joined time.Time
}

//PlayerList contains a maximum of 16 player 'slots' as per game server limits.
type PlayerList [16]Player

//Tracker uses an Rcon connection to monitor player connection changes and keeps
//current player list updated. Uses 'bf2cc pl' rcon command to request player data.
func (pl *PlayerList) Tracker(r *gorcon.Rcon) {
	for {
		str, err := r.Send("bf2cc pl")
		if err != nil {
			fmt.Println("main 36 error: ", err)
			break
		}
		list := pl.new(str)
		pl.track(&list)
		pl.updateall(list)
		time.Sleep(1 * time.Second)
	}
}

//track compares current PlayerList to new list, slot by slot, to track player connection changes.
func (pl *PlayerList) track(list *PlayerList) {
	var base time.Time
	for i := 0; i < 16; i++ {
		switch {
		case pl[i].Name == list[i].Name: //connecting or connected
			if pl[i].Connected == "0" && list[i].Connected == "1" {
				if pl[i].Joined == base {
					fmt.Printf("%s: connected\n", list[i].Name)
					t := time.Now()
					pl[i].Joined = t
				}
			}
		case len(pl[i].Name) > 0 && len(list[i].Name) == 0: //disconnected
			if pl[i].Joined != base {
				dur := time.Since(pl[i].Joined)
				fmt.Printf("%s - disconnected (playtime: %s)\n", pl[i].Name, dur.String())
			} else {
				fmt.Printf("%s - disconnected (interrupted)\n", pl[i].Name)
			}
		case len(pl[i].Name) == 0 && len(list[i].Name) > 0: //connecting
			pl.update(i, list[i])
			if pl[i].Connected == "1" && pl[i].Joined == base {
				pl[i].Joined = time.Now()
				fmt.Printf("%s - connection exists\n", list[i].Name)
			}
			if list[i].Connected == "0" {
				fmt.Printf("%s - connecting\n", list[i].Name)
			}
		}
	}
}

//updateall parses new list and updates all player slots.
func (pl *PlayerList) updateall(l PlayerList) {
	for i := 0; i < 16; i++ {
		pl.update(i, l[i])
	}
}

//update uses the p.Pid as a key to update the data in the corresponding player slot.
//Item by item assignment allows tracking elements like '.Joined' to retain existing values.
func (pl *PlayerList) update(key int, p Player) {
	if len(p.Pid) > 0 && pl[key].Pid == p.Pid {
		pl[key].Alive = p.Alive
		pl[key].Connected = p.Connected
		pl[key].Deaths = p.Deaths
		pl[key].Kills = p.Kills
		pl[key].Kit = p.Kit
		pl[key].Level = p.Level
		pl[key].Name = p.Name
		pl[key].Nucleus = p.Nucleus
		pl[key].Pid = p.Pid
		pl[key].Ping = p.Ping
		pl[key].Profileid = p.Profileid
		pl[key].Score = p.Score
		pl[key].Suicides = p.Suicides
		pl[key].Team = p.Team
		pl[key].Vip = p.Vip
		return
	}
	pl[key] = p
}

//new returns a new PlayerList generated from given 'bf2cc pl' data string
func (pl *PlayerList) new(data string) (plist PlayerList) {
	if len(data) > 1 {
		split := strings.Split(data, "\r")
		for _, value := range split {
			var p Player
			splitLine := strings.Split(strings.TrimSpace(value), "\t")
			if len(splitLine) < 48 {
				continue
			}
			kit := "none"
			if splitLine[34] != "none" {
				kit = strings.Split(splitLine[34], "_")[1]
			}
			p = Player{
				Pid:       splitLine[0],
				Name:      splitLine[1],
				Profileid: splitLine[10],
				Team:      splitLine[2],
				Level:     splitLine[39],
				Kit:       kit,
				Score:     splitLine[37],
				Kills:     splitLine[31],
				Deaths:    splitLine[36],
				Alive:     splitLine[8],
				Connected: splitLine[4],
				Vip:       splitLine[46],
				Nucleus:   splitLine[47],
				Ping:      splitLine[3],
				Suicides:  strings.TrimSpace(splitLine[30]),
			}
			key, _ := strconv.Atoi(p.Pid)
			plist[key] = p
		}
		return
	}
	return
}
<commit_msg>Minor code changes.<commit_after>/* gorcon/track version 14.1.12 (lee8oi)

This Source Code Form is subject to the terms of the Mozilla Public
License, v. 2.0. If a copy of the MPL was not distributed with this
file, You can obtain one at http://mozilla.org/MPL/2.0/.

gorcon/track package contains the PlayerList types and the Tracker methods
needed to track player connections & stats.

*/
package track

import (
	"fmt"
	"github.com/lee8oi/gorcon"
	"strconv"
	"strings"
	"time"
)

type Player struct {
	Pid, Name, Profileid, Team, Level, Kit, Score,
	Kills, Deaths, Alive, Connected, Vip, Nucleus,
	Ping, Suicides string
	Joined time.Time
}

//PlayerList contains a maximum of 16 player 'slots' as per game server limits.
type PlayerList [16]Player

//Tracker uses an Rcon connection to monitor player connection changes and keeps
//current player list updated. Uses 'bf2cc pl' rcon command to request player data.
func (pl *PlayerList) Tracker(r *gorcon.Rcon) {
	for {
		str, err := r.Send("bf2cc pl")
		if err != nil {
			fmt.Println("main 36 error: ", err)
			break
		}
		list := pl.new(str)
		pl.track(&list)
		pl.updateall(list)
		time.Sleep(1 * time.Second)
	}
}

//track compares current PlayerList to new list, slot by slot, to track player connection changes.
func (pl *PlayerList) track(list *PlayerList) {
	var base time.Time
	for i := 0; i < 16; i++ {
		switch {
		case pl[i].Name == list[i].Name: //connecting existing
			if pl[i].Connected == "0" && list[i].Connected == "1" {
				if pl[i].Joined == base {
					fmt.Printf("%s: connected\n", list[i].Name)
					t := time.Now()
					pl[i].Joined = t
				}
			}
		case len(pl[i].Name) == 0 && len(list[i].Name) > 0: //connecting new
			pl.update(i, list[i])
			if pl[i].Connected == "1" && pl[i].Joined == base {
				pl[i].Joined = time.Now()
				fmt.Printf("%s - connection exists\n", list[i].Name)
			}
			if list[i].Connected == "0" {
				fmt.Printf("%s - connecting\n", list[i].Name)
			}
		case len(pl[i].Name) > 0 && len(list[i].Name) == 0: //disconnecting
			if pl[i].Joined != base {
				dur := time.Since(pl[i].Joined)
				fmt.Printf("%s - disconnected (playtime: %s)\n", pl[i].Name, dur.String())
			} else {
				fmt.Printf("%s - disconnected (interrupted)\n", pl[i].Name)
			}

		}
	}
}

//updateall parses new list and updates all player slots.
func (pl *PlayerList) updateall(l PlayerList) {
	var base Player
	for i := 0; i < 16; i++ {
		if pl[i] == base && l[i] == base { //skip if current & new are empty
			continue
		}
		pl.update(i, l[i])
	}
}

//update uses the p.Pid as a key to update the data in the corresponding player slot.
//Item by item assignment allows tracking elements like '.Joined' to retain existing values.
func (pl *PlayerList) update(key int, p Player) {
	if len(p.Pid) > 0 && pl[key].Pid == p.Pid {
		pl[key].Alive = p.Alive
		pl[key].Connected = p.Connected
		pl[key].Deaths = p.Deaths
		pl[key].Kills = p.Kills
		pl[key].Kit = p.Kit
		pl[key].Level = p.Level
		pl[key].Name = p.Name
		pl[key].Nucleus = p.Nucleus
		pl[key].Pid = p.Pid
		pl[key].Ping = p.Ping
		pl[key].Profileid = p.Profileid
		pl[key].Score = p.Score
		pl[key].Suicides = p.Suicides
		pl[key].Team = p.Team
		pl[key].Vip = p.Vip
		return
	}
	pl[key] = p
}

//new returns a new PlayerList generated from given 'bf2cc pl' data string
func (pl *PlayerList) new(data string) (plist PlayerList) {
	if len(data) > 1 {
		split := strings.Split(data, "\r")
		for _, value := range split {
			var p Player
			splitLine := strings.Split(strings.TrimSpace(value), "\t")
			if len(splitLine) < 48 {
				continue
			}
			kit := "none"
			if splitLine[34] != "none" {
				kit = strings.Split(splitLine[34], "_")[1]
			}
			p = Player{
				Pid:       splitLine[0],
				Name:      splitLine[1],
				Profileid: splitLine[10],
				Team:      splitLine[2],
				Level:     splitLine[39],
				Kit:       kit,
				Score:     splitLine[37],
				Kills:     splitLine[31],
				Deaths:    splitLine[36],
				Alive:     splitLine[8],
				Connected: splitLine[4],
				Vip:       splitLine[46],
				Nucleus:   splitLine[47],
				Ping:      splitLine[3],
				Suicides:  strings.TrimSpace(splitLine[30]),
			}
			key, _ := strconv.Atoi(p.Pid)
			plist[key] = p
		}
		return
	}
	return
}
<|endoftext|>


<commit_before>package testdata

var X = 2
<commit_msg>debug<commit_after>package testdata

var X = 3
<|endoftext|>


<commit_before>package executor

import (
	"encoding/json"
	"os"

	hclog "github.com/hashicorp/go-hclog"
	log "github.com/hashicorp/go-hclog"
	plugin "github.com/hashicorp/go-plugin"

	"github.com/hashicorp/nomad/plugins/base"
)

// Install a plugin cli handler to ease working with tests
// and external plugins.
// This init() must be initialized last in package required by the child plugin
// process. It's recommended to avoid any other `init()` or inline any necessary calls
// here. See eeaa95d commit message for more details.
func init() {
	if len(os.Args) > 1 && os.Args[1] == "executor" {
		if len(os.Args) != 3 {
			hclog.L().Error("json configuration not provided")
			os.Exit(1)
		}

		config := os.Args[2]
		var executorConfig ExecutorConfig
		if err := json.Unmarshal([]byte(config), &executorConfig); err != nil {
			os.Exit(1)
		}

		f, err := os.OpenFile(executorConfig.LogFile, os.O_CREATE|os.O_RDWR|os.O_APPEND, 0666)
		if err != nil {
			hclog.L().Error(err.Error())
			os.Exit(1)
		}

		// Create the logger
		logger := log.New(&log.LoggerOptions{
			Level:      hclog.LevelFromString(executorConfig.LogLevel),
			JSONFormat: true,
			Output:     f,
		})

		plugin.Serve(&plugin.ServeConfig{
			HandshakeConfig: base.Handshake,
			Plugins: GetPluginMap(
				logger,
				executorConfig.FSIsolation,
			),
			GRPCServer: plugin.DefaultGRPCServer,
			Logger:     logger,
		})
		os.Exit(0)
	}
}
<commit_msg>drivers: remove duplicate import statements.<commit_after>package executor

import (
	"encoding/json"
	"os"

	hclog "github.com/hashicorp/go-hclog"
	plugin "github.com/hashicorp/go-plugin"

	"github.com/hashicorp/nomad/plugins/base"
)

// Install a plugin cli handler to ease working with tests
// and external plugins.
// This init() must be initialized last in package required by the child plugin
// process. It's recommended to avoid any other `init()` or inline any necessary calls
// here. See eeaa95d commit message for more details.
func init() {
	if len(os.Args) > 1 && os.Args[1] == "executor" {
		if len(os.Args) != 3 {
			hclog.L().Error("json configuration not provided")
			os.Exit(1)
		}

		config := os.Args[2]
		var executorConfig ExecutorConfig
		if err := json.Unmarshal([]byte(config), &executorConfig); err != nil {
			os.Exit(1)
		}

		f, err := os.OpenFile(executorConfig.LogFile, os.O_CREATE|os.O_RDWR|os.O_APPEND, 0666)
		if err != nil {
			hclog.L().Error(err.Error())
			os.Exit(1)
		}

		// Create the logger
		logger := hclog.New(&hclog.LoggerOptions{
			Level:      hclog.LevelFromString(executorConfig.LogLevel),
			JSONFormat: true,
			Output:     f,
		})

		plugin.Serve(&plugin.ServeConfig{
			HandshakeConfig: base.Handshake,
			Plugins: GetPluginMap(
				logger,
				executorConfig.FSIsolation,
			),
			GRPCServer: plugin.DefaultGRPCServer,
			Logger:     logger,
		})
		os.Exit(0)
	}
}
<|endoftext|>


<commit_before>// Package artifactory provides a Pipe that push to artifactory
package artifactory

import (
	"bytes"
	"encoding/json"
	"fmt"
	"html/template"
	"io"
	"io/ioutil"
	"net/http"
	"net/url"
	"os"
	"strings"

	"github.com/apex/log"
	"github.com/pkg/errors"
	"golang.org/x/sync/errgroup"

	"github.com/goreleaser/goreleaser/config"
	"github.com/goreleaser/goreleaser/context"
	"github.com/goreleaser/goreleaser/internal/artifact"
	"github.com/goreleaser/goreleaser/pipeline"
)

// artifactoryResponse reflects the response after an upload request
// to Artifactory.
type artifactoryResponse struct {
	Repo              string               `json:"repo,omitempty"`
	Path              string               `json:"path,omitempty"`
	Created           string               `json:"created,omitempty"`
	CreatedBy         string               `json:"createdBy,omitempty"`
	DownloadURI       string               `json:"downloadUri,omitempty"`
	MimeType          string               `json:"mimeType,omitempty"`
	Size              string               `json:"size,omitempty"`
	Checksums         artifactoryChecksums `json:"checksums,omitempty"`
	OriginalChecksums artifactoryChecksums `json:"originalChecksums,omitempty"`
	URI               string               `json:"uri,omitempty"`
}

// artifactoryChecksums reflects the checksums generated by
// Artifactory
type artifactoryChecksums struct {
	SHA1   string `json:"sha1,omitempty"`
	MD5    string `json:"md5,omitempty"`
	SHA256 string `json:"sha256,omitempty"`
}

const (
	modeBinary  = "binary"
	modeArchive = "archive"
)

// Pipe for Artifactory
type Pipe struct{}

// String returns the description of the pipe
func (Pipe) String() string {
	return "releasing to Artifactory"
}

// Default sets the pipe defaults
func (Pipe) Default(ctx *context.Context) error {
	if len(ctx.Config.Artifactories) == 0 {
		return nil
	}

	// Check if a mode was set
	for i := range ctx.Config.Artifactories {
		if ctx.Config.Artifactories[i].Mode == "" {
			ctx.Config.Artifactories[i].Mode = modeArchive
		}
	}

	return nil
}

// Run the pipe
//
// Docs: https://www.jfrog.com/confluence/display/RTF/Artifactory+REST+API#ArtifactoryRESTAPI-Example-DeployinganArtifact
func (Pipe) Run(ctx *context.Context) error {
	if len(ctx.Config.Artifactories) == 0 {
		return pipeline.Skip("artifactory section is not configured")
	}

	// Check requirements for every instance we have configured.
	// If not fulfilled, we can skip this pipeline
	for _, instance := range ctx.Config.Artifactories {
		if instance.Target == "" {
			return pipeline.Skip("artifactory section is not configured properly (missing target)")
		}

		if instance.Username == "" {
			return pipeline.Skip("artifactory section is not configured properly (missing username)")
		}

		if instance.Name == "" {
			return pipeline.Skip("artifactory section is not configured properly (missing name)")
		}

		envName := fmt.Sprintf("ARTIFACTORY_%s_SECRET", strings.ToUpper(instance.Name))
		if _, ok := ctx.Env[envName]; !ok {
			return pipeline.Skip(fmt.Sprintf("missing secret for artifactory instance %s", instance.Name))
		}
	}

	return doRun(ctx)
}

func doRun(ctx *context.Context) error {
	if !ctx.Publish {
		return pipeline.ErrSkipPublish
	}

	// Handle every configured artifactory instance
	for _, instance := range ctx.Config.Artifactories {
		// We support two different modes
		//	- "archive": Upload all artifacts
		//	- "binary": Upload only the raw binaries
		var err error
		switch v := strings.ToLower(instance.Mode); v {
		case modeArchive:
			err = runPipeByFilter(ctx, instance, artifact.ByType(artifact.UploadableArchive))
		case modeBinary:
			err = runPipeByFilter(ctx, instance, artifact.ByType(artifact.UploadableBinary))

		default:
			err = fmt.Errorf("artifactory: mode \"%s\" not supported", v)
			log.WithFields(log.Fields{
				"instance": instance.Name,
				"mode":     v,
			}).Error(err.Error())
		}

		if err != nil {
			return err
		}
	}

	return nil
}

func runPipeByFilter(ctx *context.Context, instance config.Artifactory, filter artifact.Filter) error {
	sem := make(chan bool, ctx.Parallelism)
	var g errgroup.Group
	for _, artifact := range ctx.Artifacts.Filter(filter).List() {
		sem <- true
		artifact := artifact
		g.Go(func() error {
			defer func() {
				<-sem
			}()
			return uploadAsset(ctx, instance, artifact)
		})
	}
	return g.Wait()
}

// uploadAsset uploads file to target and logs all actions
func uploadAsset(ctx *context.Context, instance config.Artifactory, artifact artifact.Artifact) error {
	envName := fmt.Sprintf("ARTIFACTORY_%s_SECRET", strings.ToUpper(instance.Name))
	secret := ctx.Env[envName]

	// Generate the target url
	targetURL, err := resolveTargetTemplate(ctx, instance, artifact)
	if err != nil {
		msg := "artifactory: error while building the target url"
		log.WithField("instance", instance.Name).WithError(err).Error(msg)
		return errors.Wrap(err, msg)
	}

	// Handle the artifact
	file, err := os.Open(artifact.Path)
	if err != nil {
		return err
	}
	defer file.Close() // nolint: errcheck

	// The target url needs to contain the artifact name
	if !strings.HasSuffix(targetURL, "/") {
		targetURL += "/"
	}
	targetURL += artifact.Name

	uploaded, _, err := uploadAssetToArtifactory(ctx, targetURL, instance.Username, secret, file)
	if err != nil {
		msg := "artifactory: upload failed"
		log.WithError(err).WithFields(log.Fields{
			"instance": instance.Name,
			"username": instance.Username,
		}).Error(msg)
		return errors.Wrap(err, msg)
	}

	log.WithFields(log.Fields{
		"instance": instance.Name,
		"mode":     instance.Mode,
		"uri":      uploaded.DownloadURI,
	}).Info("uploaded successful")

	return nil
}

// targetData is used as a template struct for
// Artifactory.Target
type targetData struct {
	Version     string
	Tag         string
	ProjectName string

	// Only supported in mode binary
	Os   string
	Arch string
	Arm  string
}

// resolveTargetTemplate returns the resolved target template with replaced variables
// Those variables can be replaced by the given context, goos, goarch, goarm and more
func resolveTargetTemplate(ctx *context.Context, artifactory config.Artifactory, artifact artifact.Artifact) (string, error) {
	data := targetData{
		Version:     ctx.Version,
		Tag:         ctx.Git.CurrentTag,
		ProjectName: ctx.Config.ProjectName,
	}

	if artifactory.Mode == modeBinary {
		data.Os = replace(ctx.Config.Archive.Replacements, artifact.Goos)
		data.Arch = replace(ctx.Config.Archive.Replacements, artifact.Goarch)
		data.Arm = replace(ctx.Config.Archive.Replacements, artifact.Goarm)
	}

	var out bytes.Buffer
	t, err := template.New(ctx.Config.ProjectName).Parse(artifactory.Target)
	if err != nil {
		return "", err
	}
	err = t.Execute(&out, data)
	return out.String(), err
}

func replace(replacements map[string]string, original string) string {
	result := replacements[original]
	if result == "" {
		return original
	}
	return result
}

// uploadAssetToArtifactory uploads the asset file to target
func uploadAssetToArtifactory(ctx *context.Context, target, username, secret string, file *os.File) (*artifactoryResponse, *http.Response, error) {
	stat, err := file.Stat()
	if err != nil {
		return nil, nil, err
	}
	if stat.IsDir() {
		return nil, nil, errors.New("the asset to upload can't be a directory")
	}

	req, err := newUploadRequest(target, username, secret, file, stat.Size())
	if err != nil {
		return nil, nil, err
	}

	asset := new(artifactoryResponse)
	resp, err := executeHTTPRequest(ctx, req, asset)
	if err != nil {
		return nil, resp, err
	}
	return asset, resp, nil
}

// newUploadRequest creates a new http.Request for uploading
func newUploadRequest(target, username, secret string, reader io.Reader, size int64) (*http.Request, error) {
	u, err := url.Parse(target)
	if err != nil {
		return nil, err
	}
	req, err := http.NewRequest("PUT", u.String(), reader)
	if err != nil {
		return nil, err
	}

	req.ContentLength = size
	req.SetBasicAuth(username, secret)

	return req, err
}

// executeHTTPRequest processes the http call with respect of context ctx
func executeHTTPRequest(ctx *context.Context, req *http.Request, v interface{}) (*http.Response, error) {
	resp, err := http.DefaultClient.Do(req)
	if err != nil {
		// If we got an error, and the context has been canceled,
		// the context's error is probably more useful.
		select {
		case <-ctx.Done():
			return nil, ctx.Err()
		default:
		}

		return nil, err
	}

	defer resp.Body.Close() // nolint: errcheck

	err = checkResponse(resp)
	if err != nil {
		// even though there was an error, we still return the response
		// in case the caller wants to inspect it further
		return resp, err
	}

	err = json.NewDecoder(resp.Body).Decode(v)
	return resp, err
}

// An ErrorResponse reports one or more errors caused by an API request.
type errorResponse struct {
	Response *http.Response // HTTP response that caused this error
	Errors   []Error        `json:"errors"` // more detail on individual errors
}

func (r *errorResponse) Error() string {
	return fmt.Sprintf("%v %v: %d %+v",
		r.Response.Request.Method, r.Response.Request.URL,
		r.Response.StatusCode, r.Errors)
}

// An Error reports more details on an individual error in an ErrorResponse.
type Error struct {
	Status  int    `json:"status"`  // Error code
	Message string `json:"message"` // Message describing the error.
}

// checkResponse checks the API response for errors, and returns them if
// present. A response is considered an error if it has a status code outside
// the 200 range.
// API error responses are expected to have either no response
// body, or a JSON response body that maps to ErrorResponse. Any other
// response body will be silently ignored.
func checkResponse(r *http.Response) error {
	if c := r.StatusCode; 200 <= c && c <= 299 {
		return nil
	}
	errorResponse := &errorResponse{Response: r}
	data, err := ioutil.ReadAll(r.Body)
	if err == nil && data != nil {
		err := json.Unmarshal(data, errorResponse)
		if err != nil {
			return err
		}
	}
	return errorResponse
}
<commit_msg>fix: upload linux artifacts to artifactory<commit_after>// Package artifactory provides a Pipe that push to artifactory
package artifactory

import (
	"bytes"
	"encoding/json"
	"fmt"
	"html/template"
	"io"
	"io/ioutil"
	"net/http"
	"net/url"
	"os"
	"strings"

	"github.com/apex/log"
	"github.com/pkg/errors"
	"golang.org/x/sync/errgroup"

	"github.com/goreleaser/goreleaser/config"
	"github.com/goreleaser/goreleaser/context"
	"github.com/goreleaser/goreleaser/internal/artifact"
	"github.com/goreleaser/goreleaser/pipeline"
)

// artifactoryResponse reflects the response after an upload request
// to Artifactory.
type artifactoryResponse struct {
	Repo              string               `json:"repo,omitempty"`
	Path              string               `json:"path,omitempty"`
	Created           string               `json:"created,omitempty"`
	CreatedBy         string               `json:"createdBy,omitempty"`
	DownloadURI       string               `json:"downloadUri,omitempty"`
	MimeType          string               `json:"mimeType,omitempty"`
	Size              string               `json:"size,omitempty"`
	Checksums         artifactoryChecksums `json:"checksums,omitempty"`
	OriginalChecksums artifactoryChecksums `json:"originalChecksums,omitempty"`
	URI               string               `json:"uri,omitempty"`
}

// artifactoryChecksums reflects the checksums generated by
// Artifactory
type artifactoryChecksums struct {
	SHA1   string `json:"sha1,omitempty"`
	MD5    string `json:"md5,omitempty"`
	SHA256 string `json:"sha256,omitempty"`
}

const (
	modeBinary  = "binary"
	modeArchive = "archive"
)

// Pipe for Artifactory
type Pipe struct{}

// String returns the description of the pipe
func (Pipe) String() string {
	return "releasing to Artifactory"
}

// Default sets the pipe defaults
func (Pipe) Default(ctx *context.Context) error {
	if len(ctx.Config.Artifactories) == 0 {
		return nil
	}

	// Check if a mode was set
	for i := range ctx.Config.Artifactories {
		if ctx.Config.Artifactories[i].Mode == "" {
			ctx.Config.Artifactories[i].Mode = modeArchive
		}
	}

	return nil
}

// Run the pipe
//
// Docs: https://www.jfrog.com/confluence/display/RTF/Artifactory+REST+API#ArtifactoryRESTAPI-Example-DeployinganArtifact
func (Pipe) Run(ctx *context.Context) error {
	if len(ctx.Config.Artifactories) == 0 {
		return pipeline.Skip("artifactory section is not configured")
	}

	// Check requirements for every instance we have configured.
	// If not fulfilled, we can skip this pipeline
	for _, instance := range ctx.Config.Artifactories {
		if instance.Target == "" {
			return pipeline.Skip("artifactory section is not configured properly (missing target)")
		}

		if instance.Username == "" {
			return pipeline.Skip("artifactory section is not configured properly (missing username)")
		}

		if instance.Name == "" {
			return pipeline.Skip("artifactory section is not configured properly (missing name)")
		}

		envName := fmt.Sprintf("ARTIFACTORY_%s_SECRET", strings.ToUpper(instance.Name))
		if _, ok := ctx.Env[envName]; !ok {
			return pipeline.Skip(fmt.Sprintf("missing secret for artifactory instance %s", instance.Name))
		}
	}

	return doRun(ctx)
}

func doRun(ctx *context.Context) error {
	if !ctx.Publish {
		return pipeline.ErrSkipPublish
	}

	// Handle every configured artifactory instance
	for _, instance := range ctx.Config.Artifactories {
		// We support two different modes
		//	- "archive": Upload all artifacts
		//	- "binary": Upload only the raw binaries
		var filter artifact.Filter
		switch v := strings.ToLower(instance.Mode); v {
		case modeArchive:
			filter = artifact.Or(
				artifact.ByType(artifact.UploadableArchive),
				artifact.ByType(artifact.LinuxPackage),
			)
		case modeBinary:
			filter = artifact.ByType(artifact.UploadableBinary)
		default:
			err := fmt.Errorf("artifactory: mode \"%s\" not supported", v)
			log.WithFields(log.Fields{
				"instance": instance.Name,
				"mode":     v,
			}).Error(err.Error())
			return err
		}

		if err := runPipeByFilter(ctx, instance, filter); err != nil {
			return err
		}
	}

	return nil
}

func runPipeByFilter(ctx *context.Context, instance config.Artifactory, filter artifact.Filter) error {
	sem := make(chan bool, ctx.Parallelism)
	var g errgroup.Group
	for _, artifact := range ctx.Artifacts.Filter(filter).List() {
		sem <- true
		artifact := artifact
		g.Go(func() error {
			defer func() {
				<-sem
			}()
			return uploadAsset(ctx, instance, artifact)
		})
	}
	return g.Wait()
}

// uploadAsset uploads file to target and logs all actions
func uploadAsset(ctx *context.Context, instance config.Artifactory, artifact artifact.Artifact) error {
	envName := fmt.Sprintf("ARTIFACTORY_%s_SECRET", strings.ToUpper(instance.Name))
	secret := ctx.Env[envName]

	// Generate the target url
	targetURL, err := resolveTargetTemplate(ctx, instance, artifact)
	if err != nil {
		msg := "artifactory: error while building the target url"
		log.WithField("instance", instance.Name).WithError(err).Error(msg)
		return errors.Wrap(err, msg)
	}

	// Handle the artifact
	file, err := os.Open(artifact.Path)
	if err != nil {
		return err
	}
	defer file.Close() // nolint: errcheck

	// The target url needs to contain the artifact name
	if !strings.HasSuffix(targetURL, "/") {
		targetURL += "/"
	}
	targetURL += artifact.Name

	uploaded, _, err := uploadAssetToArtifactory(ctx, targetURL, instance.Username, secret, file)
	if err != nil {
		msg := "artifactory: upload failed"
		log.WithError(err).WithFields(log.Fields{
			"instance": instance.Name,
			"username": instance.Username,
		}).Error(msg)
		return errors.Wrap(err, msg)
	}

	log.WithFields(log.Fields{
		"instance": instance.Name,
		"mode":     instance.Mode,
		"uri":      uploaded.DownloadURI,
	}).Info("uploaded successful")

	return nil
}

// targetData is used as a template struct for
// Artifactory.Target
type targetData struct {
	Version     string
	Tag         string
	ProjectName string

	// Only supported in mode binary
	Os   string
	Arch string
	Arm  string
}

// resolveTargetTemplate returns the resolved target template with replaced variables
// Those variables can be replaced by the given context, goos, goarch, goarm and more
func resolveTargetTemplate(ctx *context.Context, artifactory config.Artifactory, artifact artifact.Artifact) (string, error) {
	data := targetData{
		Version:     ctx.Version,
		Tag:         ctx.Git.CurrentTag,
		ProjectName: ctx.Config.ProjectName,
	}

	if artifactory.Mode == modeBinary {
		data.Os = replace(ctx.Config.Archive.Replacements, artifact.Goos)
		data.Arch = replace(ctx.Config.Archive.Replacements, artifact.Goarch)
		data.Arm = replace(ctx.Config.Archive.Replacements, artifact.Goarm)
	}

	var out bytes.Buffer
	t, err := template.New(ctx.Config.ProjectName).Parse(artifactory.Target)
	if err != nil {
		return "", err
	}
	err = t.Execute(&out, data)
	return out.String(), err
}

func replace(replacements map[string]string, original string) string {
	result := replacements[original]
	if result == "" {
		return original
	}
	return result
}

// uploadAssetToArtifactory uploads the asset file to target
func uploadAssetToArtifactory(ctx *context.Context, target, username, secret string, file *os.File) (*artifactoryResponse, *http.Response, error) {
	stat, err := file.Stat()
	if err != nil {
		return nil, nil, err
	}
	if stat.IsDir() {
		return nil, nil, errors.New("the asset to upload can't be a directory")
	}

	req, err := newUploadRequest(target, username, secret, file, stat.Size())
	if err != nil {
		return nil, nil, err
	}

	asset := new(artifactoryResponse)
	resp, err := executeHTTPRequest(ctx, req, asset)
	if err != nil {
		return nil, resp, err
	}
	return asset, resp, nil
}

// newUploadRequest creates a new http.Request for uploading
func newUploadRequest(target, username, secret string, reader io.Reader, size int64) (*http.Request, error) {
	u, err := url.Parse(target)
	if err != nil {
		return nil, err
	}
	req, err := http.NewRequest("PUT", u.String(), reader)
	if err != nil {
		return nil, err
	}

	req.ContentLength = size
	req.SetBasicAuth(username, secret)

	return req, err
}

// executeHTTPRequest processes the http call with respect of context ctx
func executeHTTPRequest(ctx *context.Context, req *http.Request, v interface{}) (*http.Response, error) {
	resp, err := http.DefaultClient.Do(req)
	if err != nil {
		// If we got an error, and the context has been canceled,
		// the context's error is probably more useful.
		select {
		case <-ctx.Done():
			return nil, ctx.Err()
		default:
		}

		return nil, err
	}

	defer resp.Body.Close() // nolint: errcheck

	err = checkResponse(resp)
	if err != nil {
		// even though there was an error, we still return the response
		// in case the caller wants to inspect it further
		return resp, err
	}

	err = json.NewDecoder(resp.Body).Decode(v)
	return resp, err
}

// An ErrorResponse reports one or more errors caused by an API request.
type errorResponse struct {
	Response *http.Response // HTTP response that caused this error
	Errors   []Error        `json:"errors"` // more detail on individual errors
}

func (r *errorResponse) Error() string {
	return fmt.Sprintf("%v %v: %d %+v",
		r.Response.Request.Method, r.Response.Request.URL,
		r.Response.StatusCode, r.Errors)
}

// An Error reports more details on an individual error in an ErrorResponse.
type Error struct {
	Status  int    `json:"status"`  // Error code
	Message string `json:"message"` // Message describing the error.
}

// checkResponse checks the API response for errors, and returns them if
// present. A response is considered an error if it has a status code outside
// the 200 range.
// API error responses are expected to have either no response
// body, or a JSON response body that maps to ErrorResponse. Any other
// response body will be silently ignored.
func checkResponse(r *http.Response) error {
	if c := r.StatusCode; 200 <= c && c <= 299 {
		return nil
	}
	errorResponse := &errorResponse{Response: r}
	data, err := ioutil.ReadAll(r.Body)
	if err == nil && data != nil {
		err := json.Unmarshal(data, errorResponse)
		if err != nil {
			return err
		}
	}
	return errorResponse
}
<|endoftext|>


<commit_before>// Package mldonkey implements a library to talk to MLDonkey.
package mldonkey

import (
	"errors"
	"fmt"
	"io/ioutil"
	"net/http"
	"net/url"
	"regexp"
	"strconv"
	"strings"

	"github.com/StalkR/goircbot/lib/transport"
)

var (
	downRE  = regexp.MustCompile(`Down: ([\d.]+ .B/s) `)
	upRE    = regexp.MustCompile(`Up: ([\d.]+ .B/s) `)
	totalRE = regexp.MustCompile(`Total\((\d+)\): ([\d.]+.?)/([\d.]+.?) @`)
	linkRE  = regexp.MustCompile(`^ed2k://`)
)

// A Statistics holds generic stats of MLDonkey.
type Statistics struct {
	DL, UL            string
	Count             int
	Downloaded, Total string
}

func (s *Statistics) String() string {
	if s.Count == 0 {
		return fmt.Sprintf("%v DL, %v UL, 0 total", s.DL, s.UL)
	}
	return fmt.Sprintf("%v DL, %v UL, %v total (%v/%v downloaded)",
		s.DL, s.UL, s.Count, s.Downloaded, s.Total)
}

// A Conn represents a connection to MLDonkey.
type Conn struct {
	url    string
	client *http.Client
}

// New prepares an MLDonkey connection by returning a *Conn.
func New(serverURL string) (*Conn, error) {
	client, err := transport.Client(serverURL)
	if err != nil {
		return nil, err
	}
	return &Conn{url: serverURL, client: client}, nil
}

// Stats returns current statistics (speed, total downloads, etc.).
func (c *Conn) Stats() (*Statistics, error) {
	resp, err := c.client.Get(c.url + "/submit?q=bw_stats")
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()
	bw_stats, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return nil, err
	}
	m := downRE.FindSubmatch(bw_stats)
	if m == nil {
		return nil, errors.New("mldonkey: cannot parse download speed")
	}
	DL := string(m[1])
	m = upRE.FindSubmatch(bw_stats)
	if m == nil {
		return nil, errors.New("mldonkey: cannot parse upload speed")
	}
	UL := string(m[1])

	resp, err = c.client.Get(c.url + "/submit?q=vd")
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()
	vd, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return nil, err
	}
	m = totalRE.FindSubmatch(vd)
	if m == nil { // No current download.
		return &Statistics{DL: DL, UL: UL}, nil
	}
	count, err := strconv.Atoi(string(m[1]))
	if err != nil {
		return nil, errors.New("mldonkey: cannot parse total int")
	}
	dled := appendBytesSuffix(string(m[2]))
	total := appendBytesSuffix(string(m[3]))

	return &Statistics{DL: DL, UL: UL, Count: count, Downloaded: dled, Total: total}, nil
}

// appendBytesSuffix appends B suffix if it is a number.
// When large enough, mldk appends suffix like KB, MB, but nothing for bytes.
// Appending B so size cannot be confused with a number.
func appendBytesSuffix(n string) string {
	if _, err := strconv.Atoi(n); err == nil {
		return n + "B"
	}
	return n
}

// Add adds a link by URL.
func (c *Conn) Add(link string) error {
	if !linkRE.MatchString(link) {
		return errors.New("mldonkey: invalid link")
	}
	params := url.Values{}
	params.Set("q", link)
	resp, err := c.client.Get(c.url + "/submit?" + params.Encode())
	if err != nil {
		return err
	}
	defer resp.Body.Close()
	page, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return err
	}
	if !strings.Contains(string(page), "Added link") {
		fmt.Println(string(page))
		return fmt.Errorf("mldonkey: no result")
	}
	return nil
}
<commit_msg>lib/mldonkey: fix lints<commit_after>// Package mldonkey implements a library to talk to MLDonkey.
package mldonkey

import (
	"errors"
	"fmt"
	"io/ioutil"
	"net/http"
	"net/url"
	"regexp"
	"strconv"
	"strings"

	"github.com/StalkR/goircbot/lib/transport"
)

var (
	downRE  = regexp.MustCompile(`Down: ([\d.]+ .B/s) `)
	upRE    = regexp.MustCompile(`Up: ([\d.]+ .B/s) `)
	totalRE = regexp.MustCompile(`Total\((\d+)\): ([\d.]+.?)/([\d.]+.?) @`)
	linkRE  = regexp.MustCompile(`^ed2k://`)
)

// A Statistics holds generic stats of MLDonkey.
type Statistics struct {
	DL, UL            string
	Count             int
	Downloaded, Total string
}

func (s *Statistics) String() string {
	if s.Count == 0 {
		return fmt.Sprintf("%v DL, %v UL, 0 total", s.DL, s.UL)
	}
	return fmt.Sprintf("%v DL, %v UL, %v total (%v/%v downloaded)",
		s.DL, s.UL, s.Count, s.Downloaded, s.Total)
}

// A Conn represents a connection to MLDonkey.
type Conn struct {
	url    string
	client *http.Client
}

// New prepares an MLDonkey connection by returning a *Conn.
func New(serverURL string) (*Conn, error) {
	client, err := transport.Client(serverURL)
	if err != nil {
		return nil, err
	}
	return &Conn{url: serverURL, client: client}, nil
}

// Stats returns current statistics (speed, total downloads, etc.).
func (c *Conn) Stats() (*Statistics, error) {
	resp, err := c.client.Get(c.url + "/submit?q=bw_stats")
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()
	bwStats, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return nil, err
	}
	m := downRE.FindSubmatch(bwStats)
	if m == nil {
		return nil, errors.New("mldonkey: cannot parse download speed")
	}
	DL := string(m[1])
	m = upRE.FindSubmatch(bwStats)
	if m == nil {
		return nil, errors.New("mldonkey: cannot parse upload speed")
	}
	UL := string(m[1])

	resp, err = c.client.Get(c.url + "/submit?q=vd")
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()
	vd, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return nil, err
	}
	m = totalRE.FindSubmatch(vd)
	if m == nil { // No current download.
		return &Statistics{DL: DL, UL: UL}, nil
	}
	count, err := strconv.Atoi(string(m[1]))
	if err != nil {
		return nil, errors.New("mldonkey: cannot parse total int")
	}
	dled := appendBytesSuffix(string(m[2]))
	total := appendBytesSuffix(string(m[3]))

	return &Statistics{DL: DL, UL: UL, Count: count, Downloaded: dled, Total: total}, nil
}

// appendBytesSuffix appends B suffix if it is a number.
// When large enough, mldk appends suffix like KB, MB, but nothing for bytes.
// Appending B so size cannot be confused with a number.
func appendBytesSuffix(n string) string {
	if _, err := strconv.Atoi(n); err == nil {
		return n + "B"
	}
	return n
}

// Add adds a link by URL.
func (c *Conn) Add(link string) error {
	if !linkRE.MatchString(link) {
		return errors.New("mldonkey: invalid link")
	}
	params := url.Values{}
	params.Set("q", link)
	resp, err := c.client.Get(c.url + "/submit?" + params.Encode())
	if err != nil {
		return err
	}
	defer resp.Body.Close()
	page, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return err
	}
	if !strings.Contains(string(page), "Added link") {
		fmt.Println(string(page))
		return fmt.Errorf("mldonkey: no result")
	}
	return nil
}
<|endoftext|>


<commit_before>package cli

import (
	"context"

	"github.com/cosmos/cosmos-sdk/client"
	"github.com/cosmos/cosmos-sdk/client/flags"
	"github.com/spf13/cobra"
	"github.com/zigbee-alliance/distributed-compliance-ledger/x/compliance/types"
)

func CmdListDeviceSoftwareCompliance() *cobra.Command {
	cmd := &cobra.Command{
		Use:   "list-device-software-compliance",
		Short: "list all DeviceSoftwareCompliance",
		RunE: func(cmd *cobra.Command, args []string) error {
			clientCtx := client.GetClientContextFromCmd(cmd)

			pageReq, err := client.ReadPageRequest(cmd.Flags())
			if err != nil {
				return err
			}

			queryClient := types.NewQueryClient(clientCtx)

			params := &types.QueryAllDeviceSoftwareComplianceRequest{
				Pagination: pageReq,
			}

			res, err := queryClient.DeviceSoftwareComplianceAll(context.Background(), params)
			if err != nil {
				return err
			}

			return clientCtx.PrintProto(res)
		},
	}

	flags.AddPaginationFlagsToCmd(cmd, cmd.Use)
	flags.AddQueryFlagsToCmd(cmd)

	return cmd
}

func CmdShowDeviceSoftwareCompliance() *cobra.Command {
	cmd := &cobra.Command{
		Use:   "show-device-software-compliance [cd-certificate-id]",
		Short: "shows a DeviceSoftwareCompliance",
		Args:  cobra.ExactArgs(1),
		RunE: func(cmd *cobra.Command, args []string) (err error) {
			clientCtx := client.GetClientContextFromCmd(cmd)

			queryClient := types.NewQueryClient(clientCtx)

			argCdCertificateId := args[0]

			params := &types.QueryGetDeviceSoftwareComplianceRequest{
				CDCertificateId: argCdCertificateId,
			}

			res, err := queryClient.DeviceSoftwareCompliance(context.Background(), params)
			if err != nil {
				return err
			}

			return clientCtx.PrintProto(res)
		},
	}

	flags.AddQueryFlagsToCmd(cmd)

	return cmd
}
<commit_msg>Add query for the entity DeviceSoftwareCompliance<commit_after>package cli

import (
	"context"

	"github.com/cosmos/cosmos-sdk/client"
	"github.com/cosmos/cosmos-sdk/client/flags"
	"github.com/spf13/cobra"
	"github.com/spf13/viper"
	"github.com/zigbee-alliance/distributed-compliance-ledger/utils/cli"
	"github.com/zigbee-alliance/distributed-compliance-ledger/x/compliance/types"
)

func CmdListDeviceSoftwareCompliance() *cobra.Command {
	cmd := &cobra.Command{
		Use:   "all-device-software-compliance",
		Short: "Query the list of all device software compliances",
		RunE: func(cmd *cobra.Command, args []string) error {
			clientCtx := client.GetClientContextFromCmd(cmd)

			pageReq, err := client.ReadPageRequest(cmd.Flags())
			if err != nil {
				return err
			}

			queryClient := types.NewQueryClient(clientCtx)

			params := &types.QueryAllDeviceSoftwareComplianceRequest{
				Pagination: pageReq,
			}

			res, err := queryClient.DeviceSoftwareComplianceAll(context.Background(), params)
			if err != nil {
				return err
			}

			return clientCtx.PrintProto(res)
		},
	}

	flags.AddPaginationFlagsToCmd(cmd, cmd.Use)
	flags.AddQueryFlagsToCmd(cmd)

	return cmd
}

func CmdShowDeviceSoftwareCompliance() *cobra.Command {
	cmd := &cobra.Command{
		Use:   "device-software-compliance",
		Short: "Query device software compliance for Model (identified by the `cdCertificateId`)",
		Args:  cobra.ExactArgs(0),
		RunE: func(cmd *cobra.Command, args []string) (err error) {
			clientCtx := client.GetClientContextFromCmd(cmd)

			argCDCertificateID := viper.GetString(FlagCDCertificationID)

			var res types.DeviceSoftwareCompliance

			return cli.QueryWithProof(
				clientCtx,
				types.StoreKey,
				types.DeviceSoftwareComplianceKeyPrefix,
				types.DeviceSoftwareComplianceKey(argCDCertificateID),
				&res,
			)
		},
	}

	cmd.Flags().String(FlagCDCertificationID, "", "CD Certification ID of the certification")
	flags.AddQueryFlagsToCmd(cmd)

	_ = cmd.MarkFlagRequired(FlagCDCertificationID)

	return cmd
}
<|endoftext|>


<commit_before>package packet

import (
	"bytes"
	"reflect"
	"testing"

	"github.com/jsimonetti/go-artnet/packet/code"
	"github.com/jsimonetti/go-artnet/version"
)

func TestArtPollPacketMarshal(t *testing.T) {
	tests := []struct {
		name string
		p    ArtPollPacket
		b    []byte
		err  error
	}{
		{
			name: "Empty",
			p: ArtPollPacket{
				Header: Header{
					ID:      ArtNet,
					OpCode:  code.OpPoll,
					Version: version.Bytes(),
				},
			},
			b: []byte{
				0x41, 0x72, 0x74, 0x2d, 0x4e, 0x65, 0x74, 0x00,
				0x00, 0x20, 0x00, 0x0e, 0x00, 0x00,
			},
		},
		{
			name: "WithDiagnosticsPrioLow",
			p: ArtPollPacket{
				Header: Header{
					ID:      ArtNet,
					OpCode:  code.OpPoll,
					Version: version.Bytes(),
				},
				TalkToMe: new(code.TalkToMe).WithDiagnostics(true),
				Priority: code.DpLow,
			},
			b: []byte{
				0x41, 0x72, 0x74, 0x2d, 0x4e, 0x65, 0x74, 0x00,
				0x00, 0x20, 0x00, 0x0e, 0x004, 0x10,
			},
		},
		{
			name: "WithDiagnosticsUniPrioMedium",
			p: ArtPollPacket{
				Header: Header{
					ID:      ArtNet,
					OpCode:  code.OpPoll,
					Version: version.Bytes(),
				},
				TalkToMe: new(code.TalkToMe).WithDiagnostics(true).WithDiagUnicast(true),
				Priority: code.DpMed,
			},
			b: []byte{
				0x41, 0x72, 0x74, 0x2d, 0x4e, 0x65, 0x74, 0x00,
				0x00, 0x20, 0x00, 0x0e, 0x00c, 0x40,
			},
		},
		{
			name: "WithReplyOnChangeVlcPrioVolatile",
			p: ArtPollPacket{
				Header: Header{
					ID:      ArtNet,
					OpCode:  code.OpPoll,
					Version: version.Bytes(),
				},
				TalkToMe: new(code.TalkToMe).WithReplyOnChange(true).WithVLC(true),
				Priority: code.DpVolatile,
			},
			b: []byte{
				0x41, 0x72, 0x74, 0x2d, 0x4e, 0x65, 0x74, 0x00,
				0x00, 0x20, 0x00, 0x0e, 0x12, 0xf0,
			},
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			b, err := tt.p.MarshalBinary()

			if want, got := tt.err, err; want != got {
				t.Fatalf("unexpected error:\n- want: %v\n-  got: %v", want, got)
			}
			if err != nil {
				return
			}

			if want, got := tt.b, b; !bytes.Equal(want, got) {
				t.Fatalf("unexpected Message bytes:\n- want: [%# x]\n-  got: [%# x]", want, got)
			}
		})
	}
}

func TestArtPollPacketUnmarshal(t *testing.T) {
	tests := []struct {
		name string
		p    ArtPollPacket
		b    []byte
		err  error
	}{
		{
			name: "Empty",
			p: ArtPollPacket{
				Header: Header{
					ID:      ArtNet,
					OpCode:  code.OpPoll,
					Version: version.Bytes(),
				},
			},
			b: []byte{
				0x41, 0x72, 0x74, 0x2d, 0x4e, 0x65, 0x74, 0x00,
				0x00, 0x20, 0x00, 0x0e, 0x00, 0x00,
			},
		},
		{
			name: "WithDiagnosticsPrioLow",
			p: ArtPollPacket{
				Header: Header{
					ID:      ArtNet,
					OpCode:  code.OpPoll,
					Version: version.Bytes(),
				},
				TalkToMe: new(code.TalkToMe).WithDiagnostics(true),
				Priority: code.DpLow,
			},
			b: []byte{
				0x41, 0x72, 0x74, 0x2d, 0x4e, 0x65, 0x74, 0x00,
				0x00, 0x20, 0x00, 0x0e, 0x004, 0x10,
			},
		},
		{
			name: "WithDiagnosticsUniPrioMedium",
			p: ArtPollPacket{
				Header: Header{
					ID:      ArtNet,
					OpCode:  code.OpPoll,
					Version: version.Bytes(),
				},
				TalkToMe: new(code.TalkToMe).WithDiagnostics(true).WithDiagUnicast(true),
				Priority: code.DpMed,
			},
			b: []byte{
				0x41, 0x72, 0x74, 0x2d, 0x4e, 0x65, 0x74, 0x00,
				0x00, 0x20, 0x00, 0x0e, 0x00c, 0x40,
			},
		},
		{
			name: "WithReplyOnChangeVlcPrioVolatile",
			p: ArtPollPacket{
				Header: Header{
					ID:      ArtNet,
					OpCode:  code.OpPoll,
					Version: version.Bytes(),
				},
				TalkToMe: new(code.TalkToMe).WithReplyOnChange(true).WithVLC(true),
				Priority: code.DpVolatile,
			},
			b: []byte{
				0x41, 0x72, 0x74, 0x2d, 0x4e, 0x65, 0x74, 0x00,
				0x00, 0x20, 0x00, 0x0e, 0x12, 0xf0,
			},
		},
		{
			name: "LiveCapture",
			p: ArtPollPacket{
				Header: Header{
					ID:      ArtNet,
					OpCode:  code.OpPoll,
					Version: [2]uint8{0x0, 0xe},
				},
				TalkToMe: new(code.TalkToMe).WithReplyOnChange(false),
				Priority: code.DpAll,
			},
			b: []byte{
				0x41, 0x72, 0x74, 0x2d, 0x4e, 0x65, 0x74, 0x00,
				0x00, 0x20, 0x00, 0x0e, 0x00, 0x00,
			},
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			var a ArtPollPacket
			err := a.UnmarshalBinary(tt.b)

			if want, got := tt.err, err; want != got {
				t.Fatalf("unexpected error:\n- want: %v\n-  got: %v", want, got)
			}
			if err != nil {
				return
			}

			if want, got := tt.p, a; !reflect.DeepEqual(want, got) {
				t.Fatalf("unexpected Message bytes:\n- want: [%#v]\n-  got: [%#v]", want, got)
			}
		})
	}
}
<commit_msg>Add ArtPoll testcase<commit_after>package packet

import (
	"bytes"
	"reflect"
	"testing"

	"github.com/jsimonetti/go-artnet/packet/code"
	"github.com/jsimonetti/go-artnet/version"
)

func TestArtPollPacketMarshal(t *testing.T) {
	tests := []struct {
		name string
		p    ArtPollPacket
		b    []byte
		err  error
	}{
		{
			name: "Empty",
			p: ArtPollPacket{
				Header: Header{
					ID:      ArtNet,
					OpCode:  code.OpPoll,
					Version: version.Bytes(),
				},
			},
			b: []byte{
				0x41, 0x72, 0x74, 0x2d, 0x4e, 0x65, 0x74, 0x00,
				0x00, 0x20, 0x00, 0x0e, 0x00, 0x00,
			},
		},
		{
			name: "WithDiagnosticsPrioLow",
			p: ArtPollPacket{
				Header: Header{
					ID:      ArtNet,
					OpCode:  code.OpPoll,
					Version: version.Bytes(),
				},
				TalkToMe: new(code.TalkToMe).WithDiagnostics(true),
				Priority: code.DpLow,
			},
			b: []byte{
				0x41, 0x72, 0x74, 0x2d, 0x4e, 0x65, 0x74, 0x00,
				0x00, 0x20, 0x00, 0x0e, 0x004, 0x10,
			},
		},
		{
			name: "WithDiagnosticsUniPrioMedium",
			p: ArtPollPacket{
				Header: Header{
					ID:      ArtNet,
					OpCode:  code.OpPoll,
					Version: version.Bytes(),
				},
				TalkToMe: new(code.TalkToMe).WithDiagnostics(true).WithDiagUnicast(true),
				Priority: code.DpMed,
			},
			b: []byte{
				0x41, 0x72, 0x74, 0x2d, 0x4e, 0x65, 0x74, 0x00,
				0x00, 0x20, 0x00, 0x0e, 0x00c, 0x40,
			},
		},
		{
			name: "WithReplyOnChangeVlcPrioVolatile",
			p: ArtPollPacket{
				Header: Header{
					ID:      ArtNet,
					OpCode:  code.OpPoll,
					Version: version.Bytes(),
				},
				TalkToMe: new(code.TalkToMe).WithReplyOnChange(true).WithVLC(true),
				Priority: code.DpVolatile,
			},
			b: []byte{
				0x41, 0x72, 0x74, 0x2d, 0x4e, 0x65, 0x74, 0x00,
				0x00, 0x20, 0x00, 0x0e, 0x12, 0xf0,
			},
		},
		{
			name: "ArtNetominator",
			p: ArtPollPacket{
				Header: Header{
					ID:      ArtNet,
					OpCode:  code.OpPoll,
					Version: [2]uint8{0x0, 0xe},
				},
				TalkToMe: new(code.TalkToMe).WithReplyOnChange(false),
				Priority: code.DpAll,
			},
			b: []byte{
				0x41, 0x72, 0x74, 0x2d, 0x4e, 0x65, 0x74, 0x00,
				0x00, 0x20, 0x00, 0x0e, 0x00, 0x00,
			},
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			b, err := tt.p.MarshalBinary()

			if want, got := tt.err, err; want != got {
				t.Fatalf("unexpected error:\n- want: %v\n-  got: %v", want, got)
			}
			if err != nil {
				return
			}

			if want, got := tt.b, b; !bytes.Equal(want, got) {
				t.Fatalf("unexpected Message bytes:\n- want: [%# x]\n-  got: [%# x]", want, got)
			}
		})
	}
}

func TestArtPollPacketUnmarshal(t *testing.T) {
	tests := []struct {
		name string
		p    ArtPollPacket
		b    []byte
		err  error
	}{
		{
			name: "Empty",
			p: ArtPollPacket{
				Header: Header{
					ID:      ArtNet,
					OpCode:  code.OpPoll,
					Version: version.Bytes(),
				},
			},
			b: []byte{
				0x41, 0x72, 0x74, 0x2d, 0x4e, 0x65, 0x74, 0x00,
				0x00, 0x20, 0x00, 0x0e, 0x00, 0x00,
			},
		},
		{
			name: "WithDiagnosticsPrioLow",
			p: ArtPollPacket{
				Header: Header{
					ID:      ArtNet,
					OpCode:  code.OpPoll,
					Version: version.Bytes(),
				},
				TalkToMe: new(code.TalkToMe).WithDiagnostics(true),
				Priority: code.DpLow,
			},
			b: []byte{
				0x41, 0x72, 0x74, 0x2d, 0x4e, 0x65, 0x74, 0x00,
				0x00, 0x20, 0x00, 0x0e, 0x004, 0x10,
			},
		},
		{
			name: "WithDiagnosticsUniPrioMedium",
			p: ArtPollPacket{
				Header: Header{
					ID:      ArtNet,
					OpCode:  code.OpPoll,
					Version: version.Bytes(),
				},
				TalkToMe: new(code.TalkToMe).WithDiagnostics(true).WithDiagUnicast(true),
				Priority: code.DpMed,
			},
			b: []byte{
				0x41, 0x72, 0x74, 0x2d, 0x4e, 0x65, 0x74, 0x00,
				0x00, 0x20, 0x00, 0x0e, 0x00c, 0x40,
			},
		},
		{
			name: "WithReplyOnChangeVlcPrioVolatile",
			p: ArtPollPacket{
				Header: Header{
					ID:      ArtNet,
					OpCode:  code.OpPoll,
					Version: version.Bytes(),
				},
				TalkToMe: new(code.TalkToMe).WithReplyOnChange(true).WithVLC(true),
				Priority: code.DpVolatile,
			},
			b: []byte{
				0x41, 0x72, 0x74, 0x2d, 0x4e, 0x65, 0x74, 0x00,
				0x00, 0x20, 0x00, 0x0e, 0x12, 0xf0,
			},
		},
		{
			name: "ArtNetominator",
			p: ArtPollPacket{
				Header: Header{
					ID:      ArtNet,
					OpCode:  code.OpPoll,
					Version: [2]uint8{0x0, 0xe},
				},
				TalkToMe: new(code.TalkToMe).WithReplyOnChange(false),
				Priority: code.DpAll,
			},
			b: []byte{
				0x41, 0x72, 0x74, 0x2d, 0x4e, 0x65, 0x74, 0x00,
				0x00, 0x20, 0x00, 0x0e, 0x00, 0x00,
			},
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			var a ArtPollPacket
			err := a.UnmarshalBinary(tt.b)

			if want, got := tt.err, err; want != got {
				t.Fatalf("unexpected error:\n- want: %v\n-  got: %v", want, got)
			}
			if err != nil {
				return
			}

			if want, got := tt.p, a; !reflect.DeepEqual(want, got) {
				t.Fatalf("unexpected Message bytes:\n- want: [%#v]\n-  got: [%#v]", want, got)
			}
		})
	}
}
<|endoftext|>


<commit_before>// +build all puzzle integer test

package puzzle

import (
	"fmt"
	"math"
	"testing"

	"github.com/stretchr/testify/assert"
)

// Find2ndLargestTestCase struct
type Find2ndLargestTestCase struct {
	inputs   []int
	expected int
}

// TestFind2ndLargest tests func Find2ndLargest
func TestFind2ndLargest(t *testing.T) {
	var tests = []Find2ndLargestTestCase{
		{[]int{0, 2, 1, 3, 2}, 2},
		{[]int{3, 10, 2, 9, 18, 11, 5}, 11},
		{[]int{9, 9, 9}, 9},
	}
	for index, test := range tests {
		var val = Find2ndLargest(test.inputs)
		var msg = fmt.Sprintf("expecting '%v' in %+v", test.expected, test.inputs)
		t.Logf("Test %2d: %v\n", index+1, msg)
		assert.Equal(t, test.expected, val, msg)
	}
}

// TestTranslate tests Translate function
func TestTranslate(t *testing.T) {
	for idx, test := range []struct {
		number   uint64
		commaStr string
		expected string
	}{
		{
			0, "0", "zero",
		},
		{
			10, "10", "ten",
		},
		{
			100, "100", "one hundred",
		},
		{
			7000000, "7,000,000", "seven millions",
		},
		{
			39000000009, "39,000,000,009", "thirty nine billions nine",
		},
		{
			math.MaxUint32,
			"4,294,967,295",
			"four billions two hundreds ninety four millions nine hundreds sixty seven thousands two hundreds ninety five",
		},
		{
			math.MaxUint64,
			"18,446,744,073,709,551,615",
			"eighteen quintillions four hundreds forty six quadrillions seven hundreds forty four trillions seventy three billions seven hundreds nine millions five hundreds fifty one thousands six hundreds fifteen",
		},
	} {
		result := Translate(test.number)
		msg := fmt.Sprintf("Test %2d: %s ==> [%s] %s\n",
			idx, test.number, test.commaStr, test.expected)
		assert.Equal(t, test.expected, result, msg)
	}
}
<commit_msg>fixed integer formatter in fmt.Sprintf() with go 1.10<commit_after>// +build all puzzle integer test

package puzzle

import (
	"fmt"
	"math"
	"testing"

	"github.com/stretchr/testify/assert"
)

// Find2ndLargestTestCase struct
type Find2ndLargestTestCase struct {
	inputs   []int
	expected int
}

// TestFind2ndLargest tests func Find2ndLargest
func TestFind2ndLargest(t *testing.T) {
	var tests = []Find2ndLargestTestCase{
		{[]int{0, 2, 1, 3, 2}, 2},
		{[]int{3, 10, 2, 9, 18, 11, 5}, 11},
		{[]int{9, 9, 9}, 9},
	}
	for index, test := range tests {
		var val = Find2ndLargest(test.inputs)
		var msg = fmt.Sprintf("expecting '%v' in %+v", test.expected, test.inputs)
		t.Logf("Test %2d: %v\n", index+1, msg)
		assert.Equal(t, test.expected, val, msg)
	}
}

// TestTranslate tests Translate function
func TestTranslate(t *testing.T) {
	for idx, test := range []struct {
		number   uint64
		commaStr string
		expected string
	}{
		{
			0, "0", "zero",
		},
		{
			10, "10", "ten",
		},
		{
			100, "100", "one hundred",
		},
		{
			7000000, "7,000,000", "seven millions",
		},
		{
			39000000009, "39,000,000,009", "thirty nine billions nine",
		},
		{
			math.MaxUint32,
			"4,294,967,295",
			"four billions two hundreds ninety four millions nine hundreds sixty seven thousands two hundreds ninety five",
		},
		{
			math.MaxUint64,
			"18,446,744,073,709,551,615",
			"eighteen quintillions four hundreds forty six quadrillions seven hundreds forty four trillions seventy three billions seven hundreds nine millions five hundreds fifty one thousands six hundreds fifteen",
		},
	} {
		result := Translate(test.number)
		msg := fmt.Sprintf("Test %2d: %d ==> [%s] %s\n",
			idx, test.number, test.commaStr, test.expected)
		assert.Equal(t, test.expected, result, msg)
	}
}
<|endoftext|>


<commit_before>package database

import (
	"database/sql"
	"errors"
	"fmt"
	_ "github.com/alexbrainman/odbc"
	"github.com/blackss2/utility/convert"
	"github.com/cznic/ql"
	_ "github.com/denisenkom/go-mssqldb"
	_ "github.com/go-sql-driver/mysql"
	_ "github.com/ziutek/mymysql/godrv"
	"os"
	"path/filepath"
	"runtime"
	"strings"
)

type Database struct {
	inst        *sql.DB
	instQL      *ql.DB
	connString  string
	driver      string
	postConnect []string
}

func (db *Database) Open(driver string, connString string) error {
	db.driver = driver
	db.connString = connString
	runtime.SetFinalizer(db, func(f interface{}) {
		f.(*Database).Close()
	})
	return db.executeOpen()
}

func (db *Database) executeOpen() error {
	var err error
	if db.driver == "ql" {
		if db.connString == "mem" {
			db.instQL, err = ql.OpenMem()
		} else {
			opt := &ql.Options{}
			opt.CanCreate = true

			filepath.Walk("./", func(path string, fi os.FileInfo, err error) error {
				if !fi.IsDir() && filepath.Dir(path) == "." {
					if len(fi.Name()) == 41 && fi.Name()[0] == '.' {
						os.Remove(path)
					}
				}
				return nil
			})

			db.instQL, err = ql.OpenFile(db.connString, opt)
		}
	} else {
		db.inst, err = sql.Open(db.driver, db.connString)
	}
	if err == nil && len(db.postConnect) > 0 {
		for _, v := range db.postConnect {
			db.TempQuery(v)
		}
	}
	return err
}

func (db *Database) Close() error {
	var err error

	if db.inst != nil {
		err = db.inst.Close()
	} else if db.instQL != nil {
		err = db.instQL.Close()
	}
	return err
}

type Rows struct {
	inst    *sql.Rows
	qlRows  [][]interface{}
	qlIndex int
	isFirst bool
	isNil   bool
	Cols    []string
}

func (db *Database) prepare(queryStr string, retCount int) (*sql.Stmt, error) {
	stmt, err := db.inst.Prepare(queryStr)
	if err != nil {
		db.Close()
		if retCount > 0 {
			db.executeOpen()
			return db.prepare(queryStr, retCount-1)
		}
		return nil, err
	}
	return stmt, err
}

func (db *Database) Query(queryStr string) (*Rows, error) {
	rows := &Rows{nil, nil, 0, true, false, make([]string, 0, 100)}

	QUERYSTR := strings.ToUpper(queryStr)

	if db.inst != nil {
		stmt, err := db.prepare(queryStr, 1)
		if stmt != nil {
			defer stmt.Close()
		}
		if err != nil {
			db.Close()
			db.executeOpen()
			return db.TempQuery(queryStr)
		}
		rows.inst, err = stmt.Query()

		if err != nil {
			if err.Error() != "Stmt did not create a result set" {
				db.Close()
				db.executeOpen()
				return db.TempQuery(queryStr)
			} else {
				runtime.SetFinalizer(rows, func(f interface{}) {
					f.(*Rows).Close()
				})
				return rows, nil
			}
		}

		rows.Cols, err = rows.inst.Columns()

		if !rows.inst.Next() {
			rows.Close()
		} else {
			runtime.SetFinalizer(rows, func(f interface{}) {
				f.(*Rows).Close()
			})
		}
	} else if db.instQL != nil {
		if !strings.Contains(QUERYSTR, "TRANSACTION") && (strings.Contains(QUERYSTR, "INSERT") || strings.Contains(QUERYSTR, "CREATE") || strings.Contains(QUERYSTR, "UPDATE") || strings.Contains(QUERYSTR, "DELETE")) {
			queryStr = fmt.Sprintf(`
				BEGIN TRANSACTION;
					%s;
				COMMIT;
			`, queryStr)
		}

		ctx := ql.NewRWCtx()
		rs, _, err := db.instQL.Run(ctx, queryStr, nil)
		if err != nil {
			println("P1 : ", err.Error(), "\n", queryStr)
			return nil, err
		}

		if len(rs) == 0 {
			rows.isNil = true
			rows.isFirst = false
			return rows, nil
		}

		rows.Cols, err = rs[0].Fields()

		rows.qlRows, err = rs[0].Rows(-1, -1)
		if len(rows.qlRows) == 0 || err != nil {
			rows.Close()
		} else {
			runtime.SetFinalizer(rows, func(f interface{}) {
				f.(*Rows).Close()
			})
		}
	} else {
		return nil, errors.New("db is not initialized")
	}

	if strings.HasPrefix(QUERYSTR, "INSERT") && strings.Contains(QUERYSTR, "OUTPUT") && strings.Contains(QUERYSTR, "INSERTED.") {
		if rows.IsNil() {
			return nil, errors.New("insert.fail")
		}
	}
	return rows, nil
}

func (db *Database) TempQuery(queryStr string) (*Rows, error) {
	rows := &Rows{nil, nil, 0, true, false, make([]string, 0, 100)}

	if db.inst != nil {
		stmt, err := db.prepare(queryStr, 1)
		if stmt != nil {
			defer stmt.Close()
		}
		if err != nil {
			println("P1 : ", err.Error())
			return nil, err
		}
		rows.inst, err = stmt.Query()

		if err != nil {
			if err.Error() != "Stmt did not create a result set" {
				println("P2 : ", err.Error(), "\n", queryStr)
				return nil, err
			} else {
				runtime.SetFinalizer(rows, func(f interface{}) {
					f.(*Rows).Close()
				})
				return rows, nil
			}
		}

		rows.Cols, err = rows.inst.Columns()
		if err != nil {
			println("P2 : ", err.Error(), "\n", queryStr)
			return nil, err
		}

		if !rows.inst.Next() {
			rows.Close()
		} else {
			runtime.SetFinalizer(rows, func(f interface{}) {
				f.(*Rows).Close()
			})
		}
	} else if db.instQL != nil {
		return nil, errors.New("ql not use TempQuery")
	} else {
		return nil, errors.New("db is not initialized")
	}

	QUERYSTR := strings.ToUpper(queryStr)
	if strings.HasPrefix(QUERYSTR, "INSERT") && strings.Contains(QUERYSTR, "OUTPUT") && strings.Contains(QUERYSTR, "INSERTED.") {
		if rows.IsNil() {
			return nil, errors.New("insert.fail")
		}
	}

	return rows, nil
}

func (rows *Rows) Next() bool {
	if !rows.isNil && rows.isFirst {
		rows.isFirst = false
		return true
	}
	if rows.inst != nil {
		if !rows.inst.Next() {
			rows.Close()
		}
	} else if rows.qlRows != nil {
		rows.qlIndex++
		if len(rows.qlRows) <= rows.qlIndex {
			rows.Close()
		}
	} else {
		return false
	}
	return !rows.isNil
}

func (rows *Rows) FetchArray() []interface{} {
	if rows.isNil {
		return nil
	}
	if rows.inst != nil {
		cols, err := rows.inst.Columns()
		if err != nil {
			return nil
		}

		rawResult := make([]*interface{}, len(cols))
		result := make([]interface{}, len(cols))

		dest := make([]interface{}, len(cols))
		for i, _ := range rawResult {
			dest[i] = &rawResult[i]
		}
		rows.inst.Scan(dest...)
		for i, raw := range rawResult {
			if raw != nil {
				v := (*raw)
				switch v.(type) {
				case []byte:
					v = convert.String(v)
				}
				result[i] = v
			} else {
				result[i] = nil
			}
		}
		return result
	} else if rows.qlRows != nil {
		if len(rows.qlRows) <= rows.qlIndex {
			return nil
		}
		return rows.qlRows[rows.qlIndex]
	} else {
		return nil
	}

}

func (rows *Rows) FetchHash() map[string]interface{} {
	if rows.isNil {
		return nil
	}
	cols, err := rows.inst.Columns()
	if err != nil {
		return nil
	}

	result := make(map[string]interface{}, len(cols))

	row := rows.FetchArray()

	for i, v := range row {
		if v != nil {
			switch v.(type) {
			case []byte:
				v = convert.String(v)
			}
		}
		result[cols[i]] = v
		result[strings.ToUpper(cols[i])] = v
		result[strings.ToLower(cols[i])] = v
	}
	return result
}

func (rows *Rows) Close() error {
	if rows != nil {
		rows.isNil = true
		if rows.inst != nil {
			return rows.inst.Close()
		}
	}
	return nil
}

func (rows *Rows) IsNil() bool {
	return rows.isNil
}
<commit_msg>Revert "aa"<commit_after>package database

import (
	"database/sql"
	"errors"
	"fmt"
	_ "github.com/alexbrainman/odbc"
	"github.com/blackss2/utility/convert"
	"github.com/cznic/ql"
	_ "github.com/denisenkom/go-mssqldb"
	_ "github.com/go-sql-driver/mysql"
	_ "github.com/ziutek/mymysql/godrv"
	"os"
	"path/filepath"
	"runtime"
	"strings"
)

type Database struct {
	inst        *sql.DB
	instQL      *ql.DB
	connString  string
	driver      string
	postConnect []string
}

func (db *Database) Open(driver string, connString string) error {
	db.driver = driver
	db.connString = connString
	runtime.SetFinalizer(db, func(f interface{}) {
		f.(*Database).Close()
	})
	return db.executeOpen()
}

func (db *Database) executeOpen() error {
	var err error
	if db.driver == "ql" {
		if db.connString == "mem" {
			db.instQL, err = ql.OpenMem()
		} else {
			opt := &ql.Options{}
			opt.CanCreate = true

			filepath.Walk("./", func(path string, fi os.FileInfo, err error) error {
				if !fi.IsDir() && filepath.Dir(path) == "." {
					if len(fi.Name()) == 41 && fi.Name()[0] == '.' {
						os.Remove(path)
					}
				}
				return nil
			})

			db.instQL, err = ql.OpenFile(db.connString, opt)
		}
	} else {
		db.inst, err = sql.Open(db.driver, db.connString)
	}
	if err == nil && len(db.postConnect) > 0 {
		for _, v := range db.postConnect {
			fmt.Println("run", v)
			db.TempQuery(v)
			fmt.Println("ran", v)
		}
	}
	return err
}

func (db *Database) Close() error {
	var err error

	if db.inst != nil {
		err = db.inst.Close()
	} else if db.instQL != nil {
		err = db.instQL.Close()
	}
	return err
}

type Rows struct {
	inst    *sql.Rows
	qlRows  [][]interface{}
	qlIndex int
	isFirst bool
	isNil   bool
	Cols    []string
}

func (db *Database) prepare(queryStr string, retCount int) (*sql.Stmt, error) {
	stmt, err := db.inst.Prepare(queryStr)
	if err != nil {
		db.Close()
		if retCount > 0 {
			db.executeOpen()
			return db.prepare(queryStr, retCount-1)
		}
		return nil, err
	}
	return stmt, err
}

func (db *Database) Query(queryStr string) (*Rows, error) {
	rows := &Rows{nil, nil, 0, true, false, make([]string, 0, 100)}

	QUERYSTR := strings.ToUpper(queryStr)

	if db.inst != nil {
		stmt, err := db.prepare(queryStr, 1)
		if stmt != nil {
			defer stmt.Close()
		}
		if err != nil {
			db.Close()
			db.executeOpen()
			return db.TempQuery(queryStr)
		}
		rows.inst, err = stmt.Query()

		if err != nil {
			if err.Error() != "Stmt did not create a result set" {
				db.Close()
				db.executeOpen()
				return db.TempQuery(queryStr)
			} else {
				runtime.SetFinalizer(rows, func(f interface{}) {
					f.(*Rows).Close()
				})
				return rows, nil
			}
		}

		rows.Cols, err = rows.inst.Columns()

		if !rows.inst.Next() {
			rows.Close()
		} else {
			runtime.SetFinalizer(rows, func(f interface{}) {
				f.(*Rows).Close()
			})
		}
	} else if db.instQL != nil {
		if !strings.Contains(QUERYSTR, "TRANSACTION") && (strings.Contains(QUERYSTR, "INSERT") || strings.Contains(QUERYSTR, "CREATE") || strings.Contains(QUERYSTR, "UPDATE") || strings.Contains(QUERYSTR, "DELETE")) {
			queryStr = fmt.Sprintf(`
				BEGIN TRANSACTION;
					%s;
				COMMIT;
			`, queryStr)
		}

		ctx := ql.NewRWCtx()
		rs, _, err := db.instQL.Run(ctx, queryStr, nil)
		if err != nil {
			println("P1 : ", err.Error(), "\n", queryStr)
			return nil, err
		}

		if len(rs) == 0 {
			rows.isNil = true
			rows.isFirst = false
			return rows, nil
		}

		rows.Cols, err = rs[0].Fields()

		rows.qlRows, err = rs[0].Rows(-1, -1)
		if len(rows.qlRows) == 0 || err != nil {
			rows.Close()
		} else {
			runtime.SetFinalizer(rows, func(f interface{}) {
				f.(*Rows).Close()
			})
		}
	} else {
		return nil, errors.New("db is not initialized")
	}

	if strings.HasPrefix(QUERYSTR, "INSERT") && strings.Contains(QUERYSTR, "OUTPUT") && strings.Contains(QUERYSTR, "INSERTED.") {
		if rows.IsNil() {
			return nil, errors.New("insert.fail")
		}
	}
	return rows, nil
}

func (db *Database) TempQuery(queryStr string) (*Rows, error) {
	rows := &Rows{nil, nil, 0, true, false, make([]string, 0, 100)}

	if db.inst != nil {
		stmt, err := db.prepare(queryStr, 1)
		if stmt != nil {
			defer stmt.Close()
		}
		if err != nil {
			println("P1 : ", err.Error())
			return nil, err
		}
		rows.inst, err = stmt.Query()

		if err != nil {
			if err.Error() != "Stmt did not create a result set" {
				println("P2 : ", err.Error(), "\n", queryStr)
				return nil, err
			} else {
				runtime.SetFinalizer(rows, func(f interface{}) {
					f.(*Rows).Close()
				})
				return rows, nil
			}
		}

		rows.Cols, err = rows.inst.Columns()
		if err != nil {
			println("P2 : ", err.Error(), "\n", queryStr)
			return nil, err
		}

		if !rows.inst.Next() {
			rows.Close()
		} else {
			runtime.SetFinalizer(rows, func(f interface{}) {
				f.(*Rows).Close()
			})
		}
	} else if db.instQL != nil {
		return nil, errors.New("ql not use TempQuery")
	} else {
		return nil, errors.New("db is not initialized")
	}

	QUERYSTR := strings.ToUpper(queryStr)
	if strings.HasPrefix(QUERYSTR, "INSERT") && strings.Contains(QUERYSTR, "OUTPUT") && strings.Contains(QUERYSTR, "INSERTED.") {
		if rows.IsNil() {
			return nil, errors.New("insert.fail")
		}
	}

	return rows, nil
}

func (rows *Rows) Next() bool {
	if !rows.isNil && rows.isFirst {
		rows.isFirst = false
		return true
	}
	if rows.inst != nil {
		if !rows.inst.Next() {
			rows.Close()
		}
	} else if rows.qlRows != nil {
		rows.qlIndex++
		if len(rows.qlRows) <= rows.qlIndex {
			rows.Close()
		}
	} else {
		return false
	}
	return !rows.isNil
}

func (rows *Rows) FetchArray() []interface{} {
	if rows.isNil {
		return nil
	}
	if rows.inst != nil {
		cols, err := rows.inst.Columns()
		if err != nil {
			return nil
		}

		rawResult := make([]*interface{}, len(cols))
		result := make([]interface{}, len(cols))

		dest := make([]interface{}, len(cols))
		for i, _ := range rawResult {
			dest[i] = &rawResult[i]
		}
		rows.inst.Scan(dest...)
		for i, raw := range rawResult {
			if raw != nil {
				v := (*raw)
				switch v.(type) {
				case []byte:
					v = convert.String(v)
				}
				result[i] = v
			} else {
				result[i] = nil
			}
		}
		return result
	} else if rows.qlRows != nil {
		if len(rows.qlRows) <= rows.qlIndex {
			return nil
		}
		return rows.qlRows[rows.qlIndex]
	} else {
		return nil
	}

}

func (rows *Rows) FetchHash() map[string]interface{} {
	if rows.isNil {
		return nil
	}
	cols, err := rows.inst.Columns()
	if err != nil {
		return nil
	}

	result := make(map[string]interface{}, len(cols))

	row := rows.FetchArray()

	for i, v := range row {
		if v != nil {
			switch v.(type) {
			case []byte:
				v = convert.String(v)
			}
		}
		result[cols[i]] = v
		result[strings.ToUpper(cols[i])] = v
		result[strings.ToLower(cols[i])] = v
	}
	return result
}

func (rows *Rows) Close() error {
	if rows != nil {
		rows.isNil = true
		if rows.inst != nil {
			return rows.inst.Close()
		}
	}
	return nil
}

func (rows *Rows) IsNil() bool {
	return rows.isNil
}
<|endoftext|>