<commit_before>package redlot

import (
	"bytes"
	"testing"
)

func TestEncodeHashKey(t *testing.T) {
	name := []byte("name")
	key := []byte("key")
	expect := []byte{0x68, 0x00, 0x00, 0x00, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x6b, 0x65, 0x79}
	encoded := encodeHashKey(name, key)
	if !bytes.Equal(expect, encoded) {
		t.Logf("\nexcept: \n\t %v \nencoded: \n\t %v\n", expect, encoded)
		t.Fail()
	}
}

func TestDecodeHashKey(t *testing.T) {
	raw := []byte{0x68, 0x00, 0x00, 0x00, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x6b, 0x65, 0x79}
	name, key := decodeHashKey(raw)
	t.Logf("\nexcept: \n\t 0x6e 0x61 0x6d 0x65 \t 0x6b 0x65 0x79 \ndecoded: \n\t % #x \t % #x\n", name, key)
	if !bytes.Equal(name, []byte("name")) || !bytes.Equal(key, []byte("key")) {
		t.Logf("\nexcept: \n\t name \t key \ndecoded: \n\t %v \t %v\n", name, key)
		t.Fail()
	}
}

func TestEncodeHsizeKey(t *testing.T) {
	name := []byte("name")
	expect := []byte{0x48, 0x6e, 0x61, 0x6d, 0x65}
	encoded := encodeHsizeKey(name)
	if !bytes.Equal(expect, encoded) {
		t.Logf("\nexcept: \n\t %v \nencoded: \n\t %v\n", expect, encoded)
		t.Fail()
	}
}

func TestDecodeHsizeKey(t *testing.T) {
	raw := []byte{0x48, 0x6e, 0x61, 0x6d, 0x65}
	name := decodeHsizeKey(raw)
	if !bytes.Equal([]byte("name"), name) {
		t.Logf("\nexcept: \n\t 0x6e 0x61 0x6d 0x65 \ndecoded: \n\t % #x\n", name)
		t.Fail()
	}
}

func TestHashFuncsArgs(t *testing.T) {
	zeroByte := make([][]byte, 0)
	oneByte := make([][]byte, 1)
	twoBytes := make([][]byte, 2)
	threeBytes := make([][]byte, 3)
	// fourByte := make([][]byte, 4)

	// one args methods
	if _, e := Hsize(zeroByte); e != errNosArgs {
		t.Fail()
	}
	if _, e := Hgetall(zeroByte); e != errNosArgs {
		t.Fail()
	}
	if _, e := Hclear(zeroByte); e != errNosArgs {
		t.Fail()
	}

	// two args methods
	if _, e := Hget(oneByte); e != errNosArgs {
		t.Fail()
	}
	if _, e := Hincr(oneByte); e != errNosArgs {
		t.Fail()
	}
	if _, e := Hdel(oneByte); e != errNosArgs {
		t.Fail()
	}
	if _, e := Hexists(oneByte); e != errNosArgs {
		t.Fail()
	}
	if _, e := MultiHget(oneByte); e != errNosArgs {
		t.Fail()
	}
	if _, e := MultiHdel(oneByte); e != errNosArgs {
		t.Fail()
	}

	// theree args methods
	if _, e := Hset(twoBytes); e != errNosArgs {
		t.Fail()
	}
	if _, e := Hlist(twoBytes); e != errNosArgs {
		t.Fail()
	}
	if _, e := Hrlist(twoBytes); e != errNosArgs {
		t.Fail()
	}

	// four args methods
	if _, e := Hkeys(threeBytes); e != errNosArgs {
		t.Fail()
	}
	if _, e := Hscan(threeBytes); e != errNosArgs {
		t.Fail()
	}
	if _, e := Hrscan(threeBytes); e != errNosArgs {
		t.Fail()
	}

}

func TestHashSizeIncr(t *testing.T) {
	name := []byte("hash")

	db.Delete(encodeHsizeKey(name), nil)

	hashSizeIncr(name, 1)
	if b, err := db.Get(encodeHsizeKey(name), nil); bytesToUint32(b) != 1 || err != nil {
		t.Logf("expect hisize is 1, but get: %d\n", bytesToUint32(b))
		t.Fail()
	}

	hashSizeIncr(name, -1)
	if b, err := db.Get(encodeHsizeKey(name), nil); len(b) != 0 || err == nil {
		t.Log("expect hisize is deleted")
		t.Fail()
	}

}
<commit_msg>Test multi functions.<commit_after>package redlot

import (
	"bytes"
	"testing"
)

func TestEncodeHashKey(t *testing.T) {
	name := []byte("name")
	key := []byte("key")
	expect := []byte{0x68, 0x00, 0x00, 0x00, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x6b, 0x65, 0x79}
	encoded := encodeHashKey(name, key)
	if !bytes.Equal(expect, encoded) {
		t.Logf("\nexcept: \n\t %v \nencoded: \n\t %v\n", expect, encoded)
		t.Fail()
	}
}

func TestDecodeHashKey(t *testing.T) {
	raw := []byte{0x68, 0x00, 0x00, 0x00, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x6b, 0x65, 0x79}
	name, key := decodeHashKey(raw)
	t.Logf("\nexcept: \n\t 0x6e 0x61 0x6d 0x65 \t 0x6b 0x65 0x79 \ndecoded: \n\t % #x \t % #x\n", name, key)
	if !bytes.Equal(name, []byte("name")) || !bytes.Equal(key, []byte("key")) {
		t.Logf("\nexcept: \n\t name \t key \ndecoded: \n\t %v \t %v\n", name, key)
		t.Fail()
	}
}

func TestEncodeHsizeKey(t *testing.T) {
	name := []byte("name")
	expect := []byte{0x48, 0x6e, 0x61, 0x6d, 0x65}
	encoded := encodeHsizeKey(name)
	if !bytes.Equal(expect, encoded) {
		t.Logf("\nexcept: \n\t %v \nencoded: \n\t %v\n", expect, encoded)
		t.Fail()
	}
}

func TestDecodeHsizeKey(t *testing.T) {
	raw := []byte{0x48, 0x6e, 0x61, 0x6d, 0x65}
	name := decodeHsizeKey(raw)
	if !bytes.Equal([]byte("name"), name) {
		t.Logf("\nexcept: \n\t 0x6e 0x61 0x6d 0x65 \ndecoded: \n\t % #x\n", name)
		t.Fail()
	}
}

func TestHashFuncsArgs(t *testing.T) {
	zeroByte := make([][]byte, 0)
	oneByte := make([][]byte, 1)
	twoBytes := make([][]byte, 2)
	threeBytes := make([][]byte, 3)
	// fourByte := make([][]byte, 4)

	// one args methods
	if _, e := Hsize(zeroByte); e != errNosArgs {
		t.Fail()
	}
	if _, e := Hgetall(zeroByte); e != errNosArgs {
		t.Fail()
	}
	if _, e := Hclear(zeroByte); e != errNosArgs {
		t.Fail()
	}

	// two args methods
	if _, e := Hget(oneByte); e != errNosArgs {
		t.Fail()
	}
	if _, e := Hincr(oneByte); e != errNosArgs {
		t.Fail()
	}
	if _, e := Hdel(oneByte); e != errNosArgs {
		t.Fail()
	}
	if _, e := Hexists(oneByte); e != errNosArgs {
		t.Fail()
	}
	if _, e := MultiHget(oneByte); e != errNosArgs {
		t.Fail()
	}
	if _, e := MultiHdel(oneByte); e != errNosArgs {
		t.Fail()
	}

	// theree args methods
	if _, e := Hset(twoBytes); e != errNosArgs {
		t.Fail()
	}
	if _, e := Hlist(twoBytes); e != errNosArgs {
		t.Fail()
	}
	if _, e := Hrlist(twoBytes); e != errNosArgs {
		t.Fail()
	}

	// four args methods
	if _, e := Hkeys(threeBytes); e != errNosArgs {
		t.Fail()
	}
	if _, e := Hscan(threeBytes); e != errNosArgs {
		t.Fail()
	}
	if _, e := Hrscan(threeBytes); e != errNosArgs {
		t.Fail()
	}

}

func TestHashSizeIncr(t *testing.T) {
	name := []byte("hash")

	db.Delete(encodeHsizeKey(name), nil)

	hashSizeIncr(name, 1)
	if b, err := db.Get(encodeHsizeKey(name), nil); bytesToUint32(b) != 1 || err != nil {
		t.Logf("expect hisize is 1, but get: %d\n", bytesToUint32(b))
		t.Fail()
	}

	hashSizeIncr(name, -1)
	if b, err := db.Get(encodeHsizeKey(name), nil); len(b) != 0 || err == nil {
		t.Log("expect hisize is deleted")
		t.Fail()
	}

}

func TestHashFuncs(t *testing.T) {

	Tom := [][]byte{[]byte("Member"), []byte("Tom"), []byte("1001")}
	Amy := [][]byte{[]byte("Member"), []byte("Amy"), []byte("1002")}

	// test hset
	if r, e := Hset(Tom); r != nil || e != nil {
		t.Logf("reply: %v, error: %v\n", r, e)
		t.Fail()
	} else {
		// test hget
		if r, e := Hget(Tom); r.(string) != "1001" || e != nil {
			t.Logf("Hget [Tom] expect 1001, but: %v, error: %v\n", r, e)
			t.Fail()
		}
		// test hsize
		if r, e := Hsize(Tom); r.(int64) != 1 || e != nil {
			t.Logf("Hsize expect 1, but: %d, error: %v\n", r, e)
			t.Fail()
		}
	}

	// test hsize when set same key field.
	Hset(Tom)
	if r, e := Hsize(Tom); r.(int64) != 1 || e != nil {
		t.Logf("Hsize expect 1, but: %d, error: %v\n", r, e)
		t.Fail()
	}

	if r, e := Hset(Amy); r != nil || e != nil {
		t.Logf("reply: %v, error: %v\n", r, e)
		t.Fail()
	} else {
		if r, e := Hget(Amy); r.(string) != "1002" || e != nil {
			t.Logf("Hget [Amy] expect 1002, but: %v, error: %v\n", r, e)
			t.Fail()
		}
		// test hsize when set different field in same hash.
		if r, e := Hsize(Amy); r.(int64) != 2 || e != nil {
			t.Logf("Hsize expect 1, but: %d, error: %v\n", r, e)
			t.Fail()
		}
	}

	// test hdel and hexists
	if r, e := Hexists(Amy); r.(int64) != 1 || e != nil {
		t.Logf("Hexists [Amy] expect 1, but: %d, error: %v\n", r, e)
		t.Fail()
	}
	Hdel(Tom)
	if r, e := Hexists(Tom); r.(int64) != 0 || e != nil {
		t.Logf("Hexists [Tom] expect 0, but: %d, error: %v\n", r, e)
		t.Fail()
	}
	Hdel(Amy)
	if r, e := Hsize(Amy); r.(int64) != -1 || e != nil {
		t.Logf("Hsize expect -1, but: %d, error: %v\n", r, e)
	}

}
<|endoftext|>


<commit_before>// 28 july 2014

package ui

import (
	"fmt"
	"unsafe"
	"reflect"
)

// #include "winapi_windows.h"
import "C"

type table struct {
	*tablebase
	_hwnd		C.HWND
	noautosize	bool
	colcount		C.int
}

func finishNewTable(b *tablebase, ty reflect.Type) Table {
	t := &table{
		_hwnd:		C.newControl(C.xWC_LISTVIEW,
			C.LVS_REPORT | C.LVS_OWNERDATA | C.LVS_NOSORTHEADER | C.LVS_SHOWSELALWAYS | C.WS_HSCROLL | C.WS_VSCROLL,
			C.WS_EX_CLIENTEDGE),		// WS_EX_CLIENTEDGE without WS_BORDER will show the canonical visual styles border (thanks to MindChild in irc.efnet.net/#winprog)
		tablebase:		b,
	}
	C.setTableSubclass(t._hwnd, unsafe.Pointer(t))
	// LVS_EX_FULLROWSELECT gives us selection across the whole row, not just the leftmost column; this makes the list view work like on other platforms
	// LVS_EX_SUBITEMIMAGES gives us images in subitems, which will be important when both images and checkboxes are added
	C.tableAddExtendedStyles(t._hwnd, C.LVS_EX_FULLROWSELECT | C.LVS_EX_SUBITEMIMAGES)
	for i := 0; i < ty.NumField(); i++ {
		C.tableAppendColumn(t._hwnd, C.int(i), toUTF16(ty.Field(i).Name))
	}
	t.colcount = C.int(ty.NumField())
	return t
}

func (t *table) Unlock() {
	t.unlock()
	// there's a possibility that user actions can happen at this point, before the view is updated
	// alas, this is something we have to deal with, because Unlock() can be called from any thread
	go func() {
		Do(func() {
			t.RLock()
			defer t.RUnlock()
			C.tableUpdate(t._hwnd, C.int(reflect.Indirect(reflect.ValueOf(t.data)).Len()))
		})
	}()
}

//export tableGetCellText
func tableGetCellText(data unsafe.Pointer, row C.int, col C.int, str *C.LPWSTR) {
	t := (*table)(data)
	t.RLock()
	defer t.RUnlock()
	d := reflect.Indirect(reflect.ValueOf(t.data))
	datum := d.Index(int(row)).Field(int(col))
	s := fmt.Sprintf("%v", datum)
	*str = toUTF16(s)
}

//export tableStopColumnAutosize
func tableStopColumnAutosize(data unsafe.Pointer) {
	t := (*table)(data)
	t.noautosize = true
}

//export tableAutosizeColumns
func tableAutosizeColumns(data unsafe.Pointer) C.BOOL {
	t := (*table)(data)
	if t.noautosize {
		return C.FALSE
	}
	return C.TRUE
}

//export tableColumnCount
func tableColumnCount(data unsafe.Pointer) C.int {
	t := (*table)(data)
	return t.colcount
}

func (t *table) hwnd() C.HWND {
	return t._hwnd
}

func (t *table) setParent(p *controlParent) {
	basesetParent(t, p)
}

func (t *table) allocate(x int, y int, width int, height int, d *sizing) []*allocation {
	return baseallocate(t, x, y, width, height, d)
}

const (
	// from C++ Template 05 in http://msdn.microsoft.com/en-us/library/windows/desktop/bb226818%28v=vs.85%29.aspx as this is the best I can do for now
	// there IS a message LVM_APPROXIMATEVIEWRECT that can do calculations, but it doesn't seem to work right when asked to base its calculations on the current width/height on Windows and wine...
	tableWidth = 183
	tableHeight = 50
)

func (t *table) preferredSize(d *sizing) (width, height int) {
	return fromdlgunitsX(tableWidth, d), fromdlgunitsY(tableHeight, d)
}

func (t *table) commitResize(a *allocation, d *sizing) {
	basecommitResize(t, a, d)
}

func (t *table) getAuxResizeInfo(d *sizing) {
	basegetAuxResizeInfo(t, d)
}
<commit_msg>Made Tables tab stops on Windows.<commit_after>// 28 july 2014

package ui

import (
	"fmt"
	"unsafe"
	"reflect"
)

// #include "winapi_windows.h"
import "C"

type table struct {
	*tablebase
	_hwnd		C.HWND
	noautosize	bool
	colcount		C.int
}

func finishNewTable(b *tablebase, ty reflect.Type) Table {
	t := &table{
		_hwnd:		C.newControl(C.xWC_LISTVIEW,
			C.LVS_REPORT | C.LVS_OWNERDATA | C.LVS_NOSORTHEADER | C.LVS_SHOWSELALWAYS | C.WS_HSCROLL | C.WS_VSCROLL | C.WS_TABSTOP,
			C.WS_EX_CLIENTEDGE),		// WS_EX_CLIENTEDGE without WS_BORDER will show the canonical visual styles border (thanks to MindChild in irc.efnet.net/#winprog)
		tablebase:		b,
	}
	C.setTableSubclass(t._hwnd, unsafe.Pointer(t))
	// LVS_EX_FULLROWSELECT gives us selection across the whole row, not just the leftmost column; this makes the list view work like on other platforms
	// LVS_EX_SUBITEMIMAGES gives us images in subitems, which will be important when both images and checkboxes are added
	C.tableAddExtendedStyles(t._hwnd, C.LVS_EX_FULLROWSELECT | C.LVS_EX_SUBITEMIMAGES)
	for i := 0; i < ty.NumField(); i++ {
		C.tableAppendColumn(t._hwnd, C.int(i), toUTF16(ty.Field(i).Name))
	}
	t.colcount = C.int(ty.NumField())
	return t
}

func (t *table) Unlock() {
	t.unlock()
	// there's a possibility that user actions can happen at this point, before the view is updated
	// alas, this is something we have to deal with, because Unlock() can be called from any thread
	go func() {
		Do(func() {
			t.RLock()
			defer t.RUnlock()
			C.tableUpdate(t._hwnd, C.int(reflect.Indirect(reflect.ValueOf(t.data)).Len()))
		})
	}()
}

//export tableGetCellText
func tableGetCellText(data unsafe.Pointer, row C.int, col C.int, str *C.LPWSTR) {
	t := (*table)(data)
	t.RLock()
	defer t.RUnlock()
	d := reflect.Indirect(reflect.ValueOf(t.data))
	datum := d.Index(int(row)).Field(int(col))
	s := fmt.Sprintf("%v", datum)
	*str = toUTF16(s)
}

//export tableStopColumnAutosize
func tableStopColumnAutosize(data unsafe.Pointer) {
	t := (*table)(data)
	t.noautosize = true
}

//export tableAutosizeColumns
func tableAutosizeColumns(data unsafe.Pointer) C.BOOL {
	t := (*table)(data)
	if t.noautosize {
		return C.FALSE
	}
	return C.TRUE
}

//export tableColumnCount
func tableColumnCount(data unsafe.Pointer) C.int {
	t := (*table)(data)
	return t.colcount
}

func (t *table) hwnd() C.HWND {
	return t._hwnd
}

func (t *table) setParent(p *controlParent) {
	basesetParent(t, p)
}

func (t *table) allocate(x int, y int, width int, height int, d *sizing) []*allocation {
	return baseallocate(t, x, y, width, height, d)
}

const (
	// from C++ Template 05 in http://msdn.microsoft.com/en-us/library/windows/desktop/bb226818%28v=vs.85%29.aspx as this is the best I can do for now
	// there IS a message LVM_APPROXIMATEVIEWRECT that can do calculations, but it doesn't seem to work right when asked to base its calculations on the current width/height on Windows and wine...
	tableWidth = 183
	tableHeight = 50
)

func (t *table) preferredSize(d *sizing) (width, height int) {
	return fromdlgunitsX(tableWidth, d), fromdlgunitsY(tableHeight, d)
}

func (t *table) commitResize(a *allocation, d *sizing) {
	basecommitResize(t, a, d)
}

func (t *table) getAuxResizeInfo(d *sizing) {
	basegetAuxResizeInfo(t, d)
}
<|endoftext|>


<commit_before>package redsync_test

import (
	"math/rand"
	"net"
	"os"
	"strings"
	"testing"
	"time"

	"github.com/hjr265/redsync.go/redsync"
	"github.com/stvp/tempredis"
)

var addrs = []net.Addr{
	&net.TCPAddr{Port: 63790},
	&net.TCPAddr{Port: 63791},
	&net.TCPAddr{Port: 63792},
	&net.TCPAddr{Port: 63793},
}

var servers []*tempredis.Server

func TestMain(m *testing.M) {
	servers = make([]*tempredis.Server, len(addrs))
	for i, addr := range addrs {
		parts := strings.Split(addr.String(), ":")
		port := parts[1]
		server, err := tempredis.Start(tempredis.Config{"port": port})
		if err != nil {
			panic(err)
		}
		defer server.Kill()
		servers[i] = server
	}
	result := m.Run()
	for _, server := range servers {
		server.Kill()
	}
	os.Exit(result)
}

func TestMutex(t *testing.T) {
	done := make(chan bool)
	chErr := make(chan error)

	for i := 0; i < 4; i++ {
		go func() {
			m, err := redsync.NewMutex("RedsyncMutex", addrs)
			if err != nil {
				chErr <- err
				return
			}

			f := 0
			for j := 0; j < 32; j++ {
				err := m.Lock()
				if err == redsync.ErrFailed {
					f++
					if f > 2 {
						chErr <- err
						return
					}
					continue
				}
				if err != nil {
					chErr <- err
					return
				}

				time.Sleep(1 * time.Millisecond)

				m.Unlock()

				time.Sleep(time.Duration(rand.Int31n(128)) * time.Millisecond)
			}
			done <- true
		}()
	}
	for i := 0; i < 4; i++ {
		select {
		case <-done:
		case err := <-chErr:
			t.Fatal(err)
		}
	}
}
<commit_msg>Gracefully shutdown redis test servers<commit_after>package redsync_test

import (
	"math/rand"
	"net"
	"os"
	"strings"
	"testing"
	"time"

	"github.com/hjr265/redsync.go/redsync"
	"github.com/stvp/tempredis"
)

var addrs = []net.Addr{
	&net.TCPAddr{Port: 63790},
	&net.TCPAddr{Port: 63791},
	&net.TCPAddr{Port: 63792},
	&net.TCPAddr{Port: 63793},
}

var servers []*tempredis.Server

func TestMain(m *testing.M) {
	servers = make([]*tempredis.Server, len(addrs))
	for i, addr := range addrs {
		parts := strings.Split(addr.String(), ":")
		port := parts[1]
		server, err := tempredis.Start(tempredis.Config{"port": port})
		if err != nil {
			panic(err)
		}
		defer server.Term()
		servers[i] = server
	}
	result := m.Run()
	for _, server := range servers {
		server.Term()
	}
	os.Exit(result)
}

func TestMutex(t *testing.T) {
	done := make(chan bool)
	chErr := make(chan error)

	for i := 0; i < 4; i++ {
		go func() {
			m, err := redsync.NewMutex("RedsyncMutex", addrs)
			if err != nil {
				chErr <- err
				return
			}

			f := 0
			for j := 0; j < 32; j++ {
				err := m.Lock()
				if err == redsync.ErrFailed {
					f++
					if f > 2 {
						chErr <- err
						return
					}
					continue
				}
				if err != nil {
					chErr <- err
					return
				}

				time.Sleep(1 * time.Millisecond)

				m.Unlock()

				time.Sleep(time.Duration(rand.Int31n(128)) * time.Millisecond)
			}
			done <- true
		}()
	}
	for i := 0; i < 4; i++ {
		select {
		case <-done:
		case err := <-chErr:
			t.Fatal(err)
		}
	}
}
<|endoftext|>


<commit_before>package render

import (
	"errors"
	"fmt"
	"github.com/extrame/goblet/error"
	"html/template"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"path/filepath"
	"reflect"
	"strconv"
	"strings"
)

type HtmlRender struct {
	root     *template.Template
	dir      string
	models   map[string]*template.Template
	suffix   string
	saveTemp bool
}

func (h *HtmlRender) PrepareInstance(ctx RenderContext) (instance RenderInstance, err error) {
	var layout, yield *template.Template

	err = errors.New("")

	var root *template.Template

	if !h.saveTemp {
		root, _ = h.root.Clone()
		h.initGlobalTemplate(root, h.dir)
	} else {
		root = h.root
	}

	if ctx.StatusCode() >= 300 {
		layout, err = h.getTemplate(root, "layout/"+"error"+h.suffix, filepath.Join("layout", "error"+h.suffix))
		if err != nil {
			layout, err = h.getTemplate(root, "layout/"+ctx.Layout()+h.suffix, filepath.Join("layout", ctx.Layout()+h.suffix))
		}
		yield, err = h.getTemplate(root, strconv.Itoa(ctx.StatusCode())+h.suffix, filepath.Join(strconv.Itoa(ctx.StatusCode())+h.suffix))
		if err != nil {
			log.Println("Find Err Code Fail, ", err)
		}
	}
	if err != nil {
		switch ctx.BlockOptionType() {

		case "Html":
			layout, err = h.getTemplate(root, "layout/"+ctx.Layout()+h.suffix, filepath.Join("layout", ctx.Layout()+h.suffix))
			if err == nil {
				yield, err = h.getTemplate(root, ctx.Method()+h.suffix)
			}
		case "Rest":
			if layout, err = h.getTemplate(root, "layout/"+ctx.Layout()+h.suffix, filepath.Join(ctx.TemplatePath(), "layout", ctx.Layout()+h.suffix)); err != nil {
				layout, err = h.getTemplate(root, "layout/"+ctx.Layout()+h.suffix, filepath.Join("layout", ctx.Layout()+h.suffix))
			}
			if err == nil {
				h.initModelTemplate(layout, ctx.TemplatePath())
				yield, err = h.getTemplate(root, ctx.TemplatePath()+"/"+ctx.Method()+h.suffix)
			}
		case "Group":
			if layout, err = h.getTemplate(root, "layout/"+ctx.Layout()+h.suffix, filepath.Join(ctx.TemplatePath(), "layout", ctx.Layout()+h.suffix)); err != nil {
				layout, err = h.getTemplate(root, "layout/"+ctx.Layout()+h.suffix, filepath.Join("layout", ctx.Layout()+h.suffix))
			}
			if err == nil {
				h.initModelTemplate(layout, ctx.TemplatePath())
				yield, err = h.getTemplate(root, ctx.TemplatePath()+"/"+ctx.Method()+h.suffix)
			}
		case "Static":
			if layout, err = h.getTemplate(root, "layout/"+ctx.Layout()+h.suffix, filepath.Join(ctx.TemplatePath(), "layout", ctx.Layout()+h.suffix)); err != nil {
				layout, err = h.getTemplate(root, "layout/"+ctx.Layout()+h.suffix, filepath.Join("layout", ctx.Layout()+h.suffix))
			}
			if err == nil {
				h.initModelTemplate(layout, ctx.TemplatePath())
				yield, err = h.getTemplate(root, ctx.TemplatePath()+"/"+ctx.Method()+h.suffix)
			}
		}
	}
	if err == nil {
		return &HttpRenderInstance{layout, yield}, nil
	}

	return
}

func (h *HtmlRender) Init(s RenderServer) {
	h.root = template.New("REST_HTTP_ROOT")
	h.root.Funcs(template.FuncMap{"raw": RawHtml, "yield": RawHtml, "status": RawHtml, "slice": Slice, "mask": RawHtml, "repeat": Repeat})
	h.dir = s.WwwRoot()
	h.suffix = ".html"
	h.models = make(map[string]*template.Template)
	h.saveTemp = (s.Env() == "production")
	if h.saveTemp {
		h.initGlobalTemplate(h.root, h.dir)
	}
}

func (f *HtmlRender) initGlobalTemplate(root *template.Template, dir string) {
	f.root.New("")
	//scan for the helpers
	filepath.Walk(filepath.Join(f.dir, dir, "helper"), func(path string, info os.FileInfo, err error) error {
		if err == nil && (!info.IsDir()) && strings.HasSuffix(info.Name(), f.suffix) {
			fmt.Println("Parse helper:", path)
			name := strings.TrimSuffix(info.Name(), f.suffix)
			e := parseFileWithName(root, "global/"+name, path)
			if e != nil {
				fmt.Printf("ERROR template.ParseFile: %v", e)
			}
		}
		return nil
	})
}

func (h *HtmlRender) initModelTemplate(layout *template.Template, dir string) {
	layout.New("")
	//scan for the helpers
	filepath.Walk(filepath.Join(h.dir, dir, "helper"), func(path string, info os.FileInfo, err error) error {
		if err == nil && (!info.IsDir()) && strings.HasSuffix(info.Name(), h.suffix) {
			fmt.Println("Parse helper:", path)
			name := strings.TrimSuffix(info.Name(), h.suffix)
			e := parseFileWithName(layout, "model/"+name, path)
			if e != nil {
				fmt.Printf("ERROR template.ParseFile: %v", e)
			}
		}
		return nil
	})
}

func (h *HtmlRender) getTemplate(root *template.Template, args ...string) (*template.Template, error) {
	var name, file string
	if len(args) == 1 {
		name = args[0]
		file = args[0]
	} else {
		name = args[1]
		file = args[1]
	}
	file = filepath.FromSlash(file)
	t := h.models[name]

	if t == nil {
		cloned_rest_model, err := root.Clone()

		if err == nil {

			err = parseFileWithName(cloned_rest_model, name, filepath.Join(h.dir, file))
			if err == nil {
				t = cloned_rest_model.Lookup(name)
				if h.saveTemp {
					h.models[name] = t
				}
			} else {
				if os.IsNotExist(err) {
					return nil, ge.NOSUCHROUTER
				} else {
					return nil, err
				}
			}
		}
	}
	return t, nil
}

type HttpRenderInstance struct {
	layout *template.Template
	yield  *template.Template
}

func (h *HttpRenderInstance) Render(wr http.ResponseWriter, data interface{}, status int) error {
	var mask_map = make(map[string]bool)

	funcMap := template.FuncMap{
		"yield": func() (template.HTML, error) {
			err := h.yield.Execute(wr, data)
			// return safe html here since we are rendering our own template
			return template.HTML(""), err
		},
		"status": func() int {
			return status
		},
		"mask": func(tag string) string {
			if _, ok := mask_map[tag]; ok {
				return "true"
			} else {
				mask_map[tag] = true
			}
			return ""
		},
	}
	h.layout.Funcs(funcMap)
	h.yield.Funcs(funcMap)

	if h.layout != nil {
		return h.layout.Execute(wr, data)
	} else if h.yield != nil {
		return h.yield.Execute(wr, data)
	}
	return nil
}

func parseFileWithName(parent *template.Template, name string, filepath string) error {
	b, err := ioutil.ReadFile(filepath)
	if err != nil {
		return err
	}
	s := string(b)
	// First template becomes return value if not already defined,
	// and we use that one for subsequent New calls to associate
	// all the templates together. Also, if this file has the same name
	// as t, this file becomes the contents of t, so
	//  t, err := New(name).Funcs(xxx).ParseFiles(name)
	// works. Otherwise we create a new template associated with t.
	var tmpl *template.Template
	if name == parent.Name() || name == "" {
		tmpl = parent
	} else {
		tmpl = parent.New(name)
	}
	_, err = tmpl.Parse(s)
	if err != nil {
		return err
	}
	return nil
}

func RawHtml(text string) template.HTML { return template.HTML(text) }

func Slice(obj interface{}, leng int) interface{} {
	slice := reflect.ValueOf(obj)
	new_leng := slice.Len() / leng

	if slice.Len()%leng != 0 {
		new_leng++
	}
	new_array := reflect.MakeSlice(reflect.SliceOf(slice.Type()), new_leng, new_leng)
	for i := 0; i < new_leng; i++ {
		end := (i + 1) * leng
		if end > slice.Len() {
			end = slice.Len()
		}
		item_array_in_new_array := slice.Slice(i*leng, end)
		new_array.Index(i).Set(item_array_in_new_array)
	}
	return new_array.Interface()
}

func Repeat(count int) []int {
	res := make([]int, count)
	for i := 0; i < count; i++ {
		res[i] = i
	}
	return res
}
<commit_msg>little change init template method<commit_after>package render

import (
	"errors"
	"fmt"
	"github.com/extrame/goblet/error"
	"html/template"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"path/filepath"
	"reflect"
	"strconv"
	"strings"
)

type HtmlRender struct {
	root     *template.Template
	dir      string
	models   map[string]*template.Template
	suffix   string
	saveTemp bool
}

func (h *HtmlRender) PrepareInstance(ctx RenderContext) (instance RenderInstance, err error) {
	var layout, yield *template.Template

	err = errors.New("")

	var root *template.Template

	if !h.saveTemp {
		root, _ = h.root.Clone()
		h.initGlobalTemplate(root, h.dir)
	} else {
		root = h.root
	}

	if ctx.StatusCode() >= 300 {
		layout, err = h.getTemplate(root, "layout/"+"error"+h.suffix, filepath.Join("layout", "error"+h.suffix))
		if err != nil {
			layout, err = h.getTemplate(root, "layout/"+ctx.Layout()+h.suffix, filepath.Join("layout", ctx.Layout()+h.suffix))
		}
		yield, err = h.getTemplate(root, strconv.Itoa(ctx.StatusCode())+h.suffix, filepath.Join(strconv.Itoa(ctx.StatusCode())+h.suffix))
		if err != nil {
			log.Println("Find Err Code Fail, ", err)
		}
	}
	if err != nil {
		switch ctx.BlockOptionType() {

		case "Html":
			layout, err = h.getTemplate(root, "layout/"+ctx.Layout()+h.suffix, filepath.Join("layout", ctx.Layout()+h.suffix))
			if err == nil {
				yield, err = h.getTemplate(root, ctx.Method()+h.suffix)
			}
		case "Rest":
			if layout, err = h.getTemplate(root, "layout/"+ctx.Layout()+h.suffix, filepath.Join(ctx.TemplatePath(), "layout", ctx.Layout()+h.suffix)); err != nil {
				layout, err = h.getTemplate(root, "layout/"+ctx.Layout()+h.suffix, filepath.Join("layout", ctx.Layout()+h.suffix))
			}
			if err == nil {
				h.initModelTemplate(layout, ctx.TemplatePath())
				yield, err = h.getTemplate(root, ctx.TemplatePath()+"/"+ctx.Method()+h.suffix)
			}
		case "Group":
			if layout, err = h.getTemplate(root, "layout/"+ctx.Layout()+h.suffix, filepath.Join(ctx.TemplatePath(), "layout", ctx.Layout()+h.suffix)); err != nil {
				layout, err = h.getTemplate(root, "layout/"+ctx.Layout()+h.suffix, filepath.Join("layout", ctx.Layout()+h.suffix))
			}
			if err == nil {
				h.initModelTemplate(layout, ctx.TemplatePath())
				yield, err = h.getTemplate(root, ctx.TemplatePath()+"/"+ctx.Method()+h.suffix)
			}
		case "Static":
			if layout, err = h.getTemplate(root, "layout/"+ctx.Layout()+h.suffix, filepath.Join(ctx.TemplatePath(), "layout", ctx.Layout()+h.suffix)); err != nil {
				layout, err = h.getTemplate(root, "layout/"+ctx.Layout()+h.suffix, filepath.Join("layout", ctx.Layout()+h.suffix))
			}
			if err == nil {
				h.initModelTemplate(layout, ctx.TemplatePath())
				yield, err = h.getTemplate(root, ctx.TemplatePath()+"/"+ctx.Method()+h.suffix)
			}
		}
	}
	if err == nil {
		return &HttpRenderInstance{layout, yield}, nil
	}

	return
}

func (h *HtmlRender) Init(s RenderServer) {
	h.root = template.New("REST_HTTP_ROOT")
	h.root.Funcs(template.FuncMap{"raw": RawHtml, "yield": RawHtml, "status": RawHtml, "slice": Slice, "mask": RawHtml, "repeat": Repeat})
	h.dir = s.WwwRoot()
	h.suffix = ".html"
	h.models = make(map[string]*template.Template)
	h.saveTemp = (s.Env() == "production")
	if h.saveTemp {
		h.initGlobalTemplate(h.root, h.dir)
	}
}

func (h *HtmlRender) initTemplate(parent *template.Template, dir string, typ string) {
	parent.New("")
	//scan for the helpers
	filepath.Walk(filepath.Join(h.dir, dir, "helper"), func(path string, info os.FileInfo, err error) error {
		if err == nil && (!info.IsDir()) && strings.HasSuffix(info.Name(), h.suffix) {
			name := strings.TrimSuffix(info.Name(), h.suffix)
			log.Printf("Parse helper:%s(%s)", typ+"/"+name, path)
			e := parseFileWithName(parent, typ+"/"+name, path)
			if e != nil {
				fmt.Printf("ERROR template.ParseFile: %v", e)
			}
		}
		return nil
	})
}

func (h *HtmlRender) initGlobalTemplate(parent *template.Template, dir string) {
	h.initTemplate(parent, dir, "global")
}

func (h *HtmlRender) initModelTemplate(parent *template.Template, dir string) {
	h.initTemplate(parent, dir, "model")
}

func (h *HtmlRender) getTemplate(root *template.Template, args ...string) (*template.Template, error) {
	var name, file string
	if len(args) == 1 {
		name = args[0]
		file = args[0]
	} else {
		name = args[1]
		file = args[1]
	}
	file = filepath.FromSlash(file)
	t := h.models[name]

	if t == nil {
		cloned_rest_model, err := root.Clone()

		if err == nil {

			err = parseFileWithName(cloned_rest_model, name, filepath.Join(h.dir, file))
			if err == nil {
				t = cloned_rest_model.Lookup(name)
				if h.saveTemp {
					h.models[name] = t
				}
			} else {
				if os.IsNotExist(err) {
					return nil, ge.NOSUCHROUTER
				} else {
					return nil, err
				}
			}
		}
	}
	return t, nil
}

type HttpRenderInstance struct {
	layout *template.Template
	yield  *template.Template
}

func (h *HttpRenderInstance) Render(wr http.ResponseWriter, data interface{}, status int) error {
	var mask_map = make(map[string]bool)

	funcMap := template.FuncMap{
		"yield": func() (template.HTML, error) {
			err := h.yield.Execute(wr, data)
			// return safe html here since we are rendering our own template
			return template.HTML(""), err
		},
		"status": func() int {
			return status
		},
		"mask": func(tag string) string {
			if _, ok := mask_map[tag]; ok {
				return "true"
			} else {
				mask_map[tag] = true
			}
			return ""
		},
	}
	h.layout.Funcs(funcMap)
	h.yield.Funcs(funcMap)

	if h.layout != nil {
		return h.layout.Execute(wr, data)
	} else if h.yield != nil {
		return h.yield.Execute(wr, data)
	}
	return nil
}

func parseFileWithName(parent *template.Template, name string, filepath string) error {
	b, err := ioutil.ReadFile(filepath)
	if err != nil {
		return err
	}
	s := string(b)
	// First template becomes return value if not already defined,
	// and we use that one for subsequent New calls to associate
	// all the templates together. Also, if this file has the same name
	// as t, this file becomes the contents of t, so
	//  t, err := New(name).Funcs(xxx).ParseFiles(name)
	// works. Otherwise we create a new template associated with t.
	var tmpl *template.Template
	if name == parent.Name() || name == "" {
		tmpl = parent
	} else {
		tmpl = parent.New(name)
	}
	_, err = tmpl.Parse(s)
	if err != nil {
		return err
	}
	return nil
}

func RawHtml(text string) template.HTML { return template.HTML(text) }

func Slice(obj interface{}, leng int) interface{} {
	slice := reflect.ValueOf(obj)
	new_leng := slice.Len() / leng

	if slice.Len()%leng != 0 {
		new_leng++
	}
	new_array := reflect.MakeSlice(reflect.SliceOf(slice.Type()), new_leng, new_leng)
	for i := 0; i < new_leng; i++ {
		end := (i + 1) * leng
		if end > slice.Len() {
			end = slice.Len()
		}
		item_array_in_new_array := slice.Slice(i*leng, end)
		new_array.Index(i).Set(item_array_in_new_array)
	}
	return new_array.Interface()
}

func Repeat(count int) []int {
	res := make([]int, count)
	for i := 0; i < count; i++ {
		res[i] = i
	}
	return res
}
<|endoftext|>


<commit_before>package algorithms

import (
	"math/rand"
	"reflect"
	"testing"
	"time"
)

// https://golang.org/doc/effective_go.html#init
func init() {
	seed := time.Now().Unix()
	rand.Seed(seed)
}

func perm(n int) (out []int) {
	for _, v := range rand.Perm(n) {
		out = append(out, v)
	}
	return
}

// Skriv "benchmark"-tester for benchmarkBSortModified funksjonen
// Skriv en ny testfunksjon benchmarkBSortModified

func BenchmarkBSort100(b *testing.B) {
	benchmarkBSort(100, b)
}

func BenchmarkBSort1000(b *testing.B) {
	benchmarkBSort(1000, b)
}

func BenchmarkBSort10000(b *testing.B) {
	benchmarkBSort(10000, b)
}

func benchmarkBSort(i int, b *testing.B) {
	for j := 0; j < b.N; j++ {
		b.StopTimer()
		values := perm(i)
		b.StartTimer()
		Bubble_sort(values)
	}
}
func BenchmarkBSortModified100(b *testing.B) {
 benchmarkBSortModified(100, b)
}

	func BenchmarkBSortModified1000(b *testing.B) {
		benchmarkBSortModified(1000, b)
	}

		func BenchmarkBSortModified10000(b *testing.B) {
			benchmarkBSortModified(10000, b)
		}

func benchmarkBSortModified(i int, b *testing.B) {
	for j := 0; j < b.N; j++ {
		b.StopTimer()
		values := perm(i)
		b.StartTimer()
		Bubble_sort_modified(values)
  }
}
func BenchmarkBSortModifieder100(b *testing.B) {
 benchmarkBSortModifieder(100, b)
}

func benchmarkBSortModifieder(i int, b *testing.B) {
	for j := 0; j < b.N; j++ {
		b.StopTimer()
		values := perm(i)
		b.StartTimer()
		Bubble_sort_modifieder(values)
	}
}

// Implementasjon av testfunksjoner for Quicksort algoritmen
func TestQSort(t *testing.T) {
	values := []int{9, 1, 20, 3, 6, 7}
	expected := []int{1, 3, 6, 7, 9, 20}

	QSort(values)

	if !reflect.DeepEqual(values, expected) {
		t.Fatalf("expected %d, actual is %d", 1, values[0])
	}
}

func BenchmarkQSort100(b *testing.B) {
	benchmarkQSort(100, b)
}

func BenchmarkQSort1000(b *testing.B) {
	benchmarkQSort(1000, b)
}

func BenchmarkQSort10000(b *testing.B) {
	benchmarkQSort(10000, b)
}

func benchmarkQSort(i int, b *testing.B) {
	for j := 0; j < b.N; j++ {
		b.StopTimer()
		values := perm(i)
		b.StartTimer()
		QSort(values)
	}
}
<commit_msg>la til 1000 og 10000 tester for bubblesortmodifieder<commit_after>package algorithms

import (
	"math/rand"
	"reflect"
	"testing"
	"time"
)

// https://golang.org/doc/effective_go.html#init
func init() {
	seed := time.Now().Unix()
	rand.Seed(seed)
}

func perm(n int) (out []int) {
	for _, v := range rand.Perm(n) {
		out = append(out, v)
	}
	return
}

// Skriv "benchmark"-tester for benchmarkBSortModified funksjonen
// Skriv en ny testfunksjon benchmarkBSortModified

func BenchmarkBSort100(b *testing.B) {
	benchmarkBSort(100, b)
}

func BenchmarkBSort1000(b *testing.B) {
	benchmarkBSort(1000, b)
}

func BenchmarkBSort10000(b *testing.B) {
	benchmarkBSort(10000, b)
}

func benchmarkBSort(i int, b *testing.B) {
	for j := 0; j < b.N; j++ {
		b.StopTimer()
		values := perm(i)
		b.StartTimer()
		Bubble_sort(values)
	}
}
func BenchmarkBSortModified100(b *testing.B) {
 benchmarkBSortModified(100, b)
}

	func BenchmarkBSortModified1000(b *testing.B) {
		benchmarkBSortModified(1000, b)
	}

		func BenchmarkBSortModified10000(b *testing.B) {
			benchmarkBSortModified(10000, b)
		}

func benchmarkBSortModified(i int, b *testing.B) {
	for j := 0; j < b.N; j++ {
		b.StopTimer()
		values := perm(i)
		b.StartTimer()
		Bubble_sort_modified(values)
  }
}
func BenchmarkBSortModifieder100(b *testing.B) {
 benchmarkBSortModifieder(100, b)
}

func BenchmarkBSortModifieder1000(b *testing.B) {
 benchmarkBSortModifieder(1000, b)
}

func BenchmarkBSortModifieder10000(b *testing.B) {
 benchmarkBSortModifieder(10000, b)
}

func benchmarkBSortModifieder(i int, b *testing.B) {
	for j := 0; j < b.N; j++ {
		b.StopTimer()
		values := perm(i)
		b.StartTimer()
		Bubble_sort_modifieder(values)
	}
}

// Implementasjon av testfunksjoner for Quicksort algoritmen
func TestQSort(t *testing.T) {
	values := []int{9, 1, 20, 3, 6, 7}
	expected := []int{1, 3, 6, 7, 9, 20}

	QSort(values)

	if !reflect.DeepEqual(values, expected) {
		t.Fatalf("expected %d, actual is %d", 1, values[0])
	}
}

func BenchmarkQSort100(b *testing.B) {
	benchmarkQSort(100, b)
}

func BenchmarkQSort1000(b *testing.B) {
	benchmarkQSort(1000, b)
}

func BenchmarkQSort10000(b *testing.B) {
	benchmarkQSort(10000, b)
}

func benchmarkQSort(i int, b *testing.B) {
	for j := 0; j < b.N; j++ {
		b.StopTimer()
		values := perm(i)
		b.StartTimer()
		QSort(values)
	}
}
<|endoftext|>


<commit_before>// Package mail implements a parser for electronic mail messages as specified
// in RFC5322.
//
// We allow both CRLF and LF to be used in the input, possibly mixed.
package mail

import (
	"bytes"
	"errors"
	"strings"
)

type Message struct {
	FullHeaders []Header // all headers
	OptHeaders  []Header // unprocessed headers

	Id          string
	Subject     string
	Comments    []string
	Keywords    []string

	Text        string
}

type Header struct {
	Key, Value string
}

func Parse(s []byte) (m Message, e error) {
	r, e := ParseRaw(s)
	if e != nil {
		return
	}
	return Process(r)
}

func Process(r RawMessage) (m Message, e error) {
	m.FullHeaders = []Header{}
	m.OptHeaders = []Header{}
	m.Text = string(r.Body) // TODO mime
	for _, rh := range r.RawHeaders {
		h := Header{string(rh.Key), string(rh.Value)}
		m.FullHeaders = append(m.FullHeaders, h)
		switch string(rh.Key) {
		case `Message-ID`:
			m.Id = string(rh.Value)
		case `Subject`:
			m.Subject = string(rh.Value)
		case `Comments`:
			m.Comments = append(m.Comments, string(rh.Value))
		case `Keywords`:
			ks := strings.Split(string(rh.Value), ",")
			for _, k := range ks {
				m.Keywords = append(m.Keywords, strings.TrimSpace(k))
			}
		default:
			m.OptHeaders = append(m.OptHeaders, h)
		}
	}
	return
}

type RawHeader struct {
	Key, Value []byte
}

type RawMessage struct {
	RawHeaders []RawHeader
	Body       []byte
}

func isWSP(b byte) bool {
	return b == ' ' || b == '\t'
}

func ParseRaw(s []byte) (m RawMessage, e error) {
	// parser states
	const (
		READY = iota
		HKEY
		HVWS
		HVAL
	)

	const (
		CR = '\r'
		LF = '\n'
	)
	CRLF := []byte{CR, LF}

	state := READY
	kstart, kend, vstart := 0, 0, 0
	done := false

	m.RawHeaders = []RawHeader{}

	for i := 0; i < len(s); i++ {
		b := s[i]
		switch state {
		case READY:
			if b == CR && i < len(s)-1 && s[i+1] == LF {
				// we are at the beginning of an empty header
				m.Body = s[i+2:]
				done = true
				goto Done
			}
			if b == LF {
				m.Body = s[i+1:]
				done = true
				goto Done
			}
			// otherwise this character is the first in a header
			// key
			kstart = i
			state = HKEY
		case HKEY:
			if b == ':' {
				kend = i
				state = HVWS
			}
		case HVWS:
			if !isWSP(b) {
				vstart = i
				state = HVAL
			}
		case HVAL:
			if b == CR && i < len(s)-2 && s[i+1] == LF && !isWSP(s[i+2]) {
				v := bytes.Replace(s[vstart:i], CRLF, nil, -1)
				hdr := RawHeader{s[kstart:kend], v}
				m.RawHeaders = append(m.RawHeaders, hdr)
				state = READY
				i++
			} else if b == LF && i < len(s)-1 && !isWSP(s[i+1]) {
				v := bytes.Replace(s[vstart:i], CRLF, nil, -1)
				hdr := RawHeader{s[kstart:kend], v}
				m.RawHeaders = append(m.RawHeaders, hdr)
				state = READY
			}
		}
	}
Done:
	if !done {
		e = errors.New("unexpected EOF")
	}
	return
}
<commit_msg>Using base64 encoding of Message-Id in Id field<commit_after>// Package mail implements a parser for electronic mail messages as specified
// in RFC5322.
//
// We allow both CRLF and LF to be used in the input, possibly mixed.
package mail

import (
	"bytes"
	"encoding/base64"
	"errors"
	"strings"
)

var benc = base64.URLEncoding

type Message struct {
	FullHeaders []Header // all headers
	OptHeaders  []Header // unprocessed headers

	MessageId   string
	Id          string
	Subject     string
	Comments    []string
	Keywords    []string

	Text        string
}

type Header struct {
	Key, Value string
}

func Parse(s []byte) (m Message, e error) {
	r, e := ParseRaw(s)
	if e != nil {
		return
	}
	return Process(r)
}

func Process(r RawMessage) (m Message, e error) {
	m.FullHeaders = []Header{}
	m.OptHeaders = []Header{}
	m.Text = string(r.Body) // TODO mime
	for _, rh := range r.RawHeaders {
		h := Header{string(rh.Key), string(rh.Value)}
		m.FullHeaders = append(m.FullHeaders, h)
		switch string(rh.Key) {
		case `Message-ID`:
			m.MessageId = string(rh.Value)
			m.Id = benc.EncodeToString(rh.Value)
		case `Subject`:
			m.Subject = string(rh.Value)
		case `Comments`:
			m.Comments = append(m.Comments, string(rh.Value))
		case `Keywords`:
			ks := strings.Split(string(rh.Value), ",")
			for _, k := range ks {
				m.Keywords = append(m.Keywords, strings.TrimSpace(k))
			}
		default:
			m.OptHeaders = append(m.OptHeaders, h)
		}
	}
	return
}

type RawHeader struct {
	Key, Value []byte
}

type RawMessage struct {
	RawHeaders []RawHeader
	Body       []byte
}

func isWSP(b byte) bool {
	return b == ' ' || b == '\t'
}

func ParseRaw(s []byte) (m RawMessage, e error) {
	// parser states
	const (
		READY = iota
		HKEY
		HVWS
		HVAL
	)

	const (
		CR = '\r'
		LF = '\n'
	)
	CRLF := []byte{CR, LF}

	state := READY
	kstart, kend, vstart := 0, 0, 0
	done := false

	m.RawHeaders = []RawHeader{}

	for i := 0; i < len(s); i++ {
		b := s[i]
		switch state {
		case READY:
			if b == CR && i < len(s)-1 && s[i+1] == LF {
				// we are at the beginning of an empty header
				m.Body = s[i+2:]
				done = true
				goto Done
			}
			if b == LF {
				m.Body = s[i+1:]
				done = true
				goto Done
			}
			// otherwise this character is the first in a header
			// key
			kstart = i
			state = HKEY
		case HKEY:
			if b == ':' {
				kend = i
				state = HVWS
			}
		case HVWS:
			if !isWSP(b) {
				vstart = i
				state = HVAL
			}
		case HVAL:
			if b == CR && i < len(s)-2 && s[i+1] == LF && !isWSP(s[i+2]) {
				v := bytes.Replace(s[vstart:i], CRLF, nil, -1)
				hdr := RawHeader{s[kstart:kend], v}
				m.RawHeaders = append(m.RawHeaders, hdr)
				state = READY
				i++
			} else if b == LF && i < len(s)-1 && !isWSP(s[i+1]) {
				v := bytes.Replace(s[vstart:i], CRLF, nil, -1)
				hdr := RawHeader{s[kstart:kend], v}
				m.RawHeaders = append(m.RawHeaders, hdr)
				state = READY
			}
		}
	}
Done:
	if !done {
		e = errors.New("unexpected EOF")
	}
	return
}
<|endoftext|>


<commit_before>/*
 *
 * k6 - a next-generation load testing tool
 * Copyright (C) 2016 Load Impact
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 */

package main

import (
	log "github.com/Sirupsen/logrus"
	"gopkg.in/urfave/cli.v1"
	"os"
)

func main() {
	// This won't be needed in cli v2
	cli.VersionFlag.Name = "version"
	cli.HelpFlag.Name = "help"
	cli.HelpFlag.Hidden = true

	app := cli.NewApp()
	app.Name = "k6"
	app.Usage = "a next generation load generator"
	app.Version = "0.7.0"
	app.Commands = []cli.Command{
		commandRun,
		commandInspect,
		commandStatus,
		commandStats,
		commandScale,
		commandPause,
		commandResume,
	}
	app.Flags = []cli.Flag{
		cli.BoolFlag{
			Name:  "verbose, v",
			Usage: "show debug messages",
		},
		cli.StringFlag{
			Name:  "address, a",
			Usage: "address for the API",
			Value: "127.0.0.1:6565",
		},
	}
	app.Before = func(cc *cli.Context) error {
		if cc.Bool("verbose") {
			log.SetLevel(log.DebugLevel)
		}

		return nil
	}
	if err := app.Run(os.Args); err != nil {
		os.Exit(1)
	}
}
<commit_msg>v0.8.0<commit_after>/*
 *
 * k6 - a next-generation load testing tool
 * Copyright (C) 2016 Load Impact
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 */

package main

import (
	log "github.com/Sirupsen/logrus"
	"gopkg.in/urfave/cli.v1"
	"os"
)

func main() {
	// This won't be needed in cli v2
	cli.VersionFlag.Name = "version"
	cli.HelpFlag.Name = "help"
	cli.HelpFlag.Hidden = true

	app := cli.NewApp()
	app.Name = "k6"
	app.Usage = "a next generation load generator"
	app.Version = "0.8.0"
	app.Commands = []cli.Command{
		commandRun,
		commandInspect,
		commandStatus,
		commandStats,
		commandScale,
		commandPause,
		commandResume,
	}
	app.Flags = []cli.Flag{
		cli.BoolFlag{
			Name:  "verbose, v",
			Usage: "show debug messages",
		},
		cli.StringFlag{
			Name:  "address, a",
			Usage: "address for the API",
			Value: "127.0.0.1:6565",
		},
	}
	app.Before = func(cc *cli.Context) error {
		if cc.Bool("verbose") {
			log.SetLevel(log.DebugLevel)
		}

		return nil
	}
	if err := app.Run(os.Args); err != nil {
		os.Exit(1)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/csv"
	"encoding/json"
	"flag"
	"fmt"
	"io"
	"log"
	"os"
	"path/filepath"
	"sort"
	"strings"

	"github.com/icza/screp/rep"
	"github.com/icza/screp/repparser"
	"github.com/marianogappa/raszagal/analyzer"
)

func main() {
	var (
		_analyzers = map[string]analyzer.Analyzer{
			(&analyzer.MyAPM{}).Name():                      &analyzer.MyAPM{},
			(&analyzer.MyRace{}).Name():                     &analyzer.MyRace{},
			(&analyzer.DateTime{}).Name():                   &analyzer.DateTime{},
			(&analyzer.DurationMinutes{}).Name():            &analyzer.DurationMinutes{},
			(&analyzer.MyName{}).Name():                     &analyzer.MyName{},
			(&analyzer.IsThereARace{}).Name():               &analyzer.IsThereARace{},
			(&analyzer.MyRaceIsZerg{}).Name():               &analyzer.MyRaceIsZerg{},
			(&analyzer.MyRaceIsTerran{}).Name():             &analyzer.MyRaceIsTerran{},
			(&analyzer.MyRaceIsProtoss{}).Name():            &analyzer.MyRaceIsProtoss{},
			(&analyzer.ReplayName{}).Name():                 &analyzer.ReplayName{},
			(&analyzer.ReplayPath{}).Name():                 &analyzer.ReplayPath{},
			(&analyzer.MyWin{}).Name():                      &analyzer.MyWin{},
			(&analyzer.MyGame{}).Name():                     &analyzer.MyGame{},
			(&analyzer.MapName{}).Name():                    &analyzer.MapName{},
			(&analyzer.MyFirstSpecificUnitSeconds{}).Name(): &analyzer.MyFirstSpecificUnitSeconds{},
		}
		boolFlags               = map[string]*bool{}
		stringFlags             = map[string]*string{}
		fReplay                 = flag.String("replay", "", "(>= 1 replays required) path to replay file")
		fReplays                = flag.String("replays", "", "(>= 1 replays required) comma-separated paths to replay files")
		fReplayDir              = flag.String("replay-dir", "", "(>= 1 replays required) path to folder with replays (recursive)")
		fMe                     = flag.String("me", "", "comma-separated list of player names to identify as the main player")
		fJSON                   = flag.Bool("json", false, "outputs a JSON instead of the default CSV")
		fCopyToIfMatchesFilters = flag.String("copy-to-if-matches-filters", "",
			"copy replay files matched by -filter-- and not matched by -filter--not-- filters to specified directory")
	)
	for name, a := range _analyzers {
		if a.IsStringFlag() {
			stringFlags[name] = flag.String(name, "", a.Description())
		} else {
			boolFlags[name] = flag.Bool(name, false, a.Description())
		}
		if a.IsBooleanResult() {
			boolFlags["filter--"+name] = flag.Bool("filter--"+name, false, "Filter for: "+a.Description())
			boolFlags["filter-not--"+name] = flag.Bool("filter-not--"+name, false, "Filter-Not for: "+a.Description())
		}
	}
	flag.Parse()
	var (
		analyzers                  = map[string]analyzer.Analyzer{}
		filters                    = map[string]struct{}{}
		filterNots                 = map[string]struct{}{}
		fieldNames                 = []string{} // TODO add filename
		shouldCopyToOutputLocation = true
	)
	if ok, err := isDirExist(*fCopyToIfMatchesFilters); *fCopyToIfMatchesFilters == "" || !ok || err != nil {
		shouldCopyToOutputLocation = false
		if *fCopyToIfMatchesFilters != "" && !ok {
			log.Printf("Output directory doesn't exist: %v\n", *fCopyToIfMatchesFilters)
		}
		if *fCopyToIfMatchesFilters != "" && err != nil {
			log.Printf("Error locating output directory (%v): %v\n", *fCopyToIfMatchesFilters, err)
		}
	}
	for name, f := range boolFlags {
		if *f {
			if strings.HasPrefix(name, "filter--") {
				name = name[len("filter--"):] // side-effect so that the analyzer runs
				filters[name] = struct{}{}
			} else if strings.HasPrefix(name, "filter-not--") {
				name = name[len("filter-not--"):] // side-effect so that the analyzer runs
				filterNots[name[len("filter-not--"):]] = struct{}{}
			}
			analyzers[name] = _analyzers[name]
			fieldNames = append(fieldNames, name)
		}
	}
	for name, f := range stringFlags {
		if *f != "" {
			a := _analyzers[name]
			if err := a.SetArguments(unmarshalArguments(*f)); err != nil {
				log.Printf("Invalid arguments '%v' for Analyzer %v: %v", *f, name, err)
				continue
			}
			analyzers[name] = _analyzers[name]
			fieldNames = append(fieldNames, name)
		}
	}

	// TODO implement library for programmatic use
	// Prepares for CSV output
	sort.Strings(fieldNames)
	w := csv.NewWriter(os.Stdout)
	if !*fJSON {
		w.Write(fieldNames)
	}

	// Prepares for JSON output
	firstJSONRow := true
	if *fJSON {
		fmt.Println("[")
	}

	// Prepares AnalyzerContext
	ctx := analyzer.AnalyzerContext{Me: map[string]struct{}{}}
	if fMe != nil && len(*fMe) > 0 {
		for _, name := range strings.Split(*fMe, ",") {
			ctx.Me[strings.TrimSpace(name)] = struct{}{}
		}
	}

	// Parse replay filename flags
	var replays = map[string]struct{}{}
	*fReplay = strings.TrimSpace(*fReplay)
	if len(*fReplay) >= 5 && (*fReplay)[len(*fReplay)-4:] == ".rep" {
		replays[*fReplay] = struct{}{}
	}
	if *fReplays != "" {
		for _, r := range strings.Split(*fReplays, ",") {
			r = strings.TrimSpace(r)
			if len(r) >= 5 && r[len(r)-4:] == ".rep" {
				replays[r] = struct{}{}
			}
		}
	}
	if *fReplayDir != "" {
		e := filepath.Walk(*fReplayDir, func(path string, info os.FileInfo, err error) error {
			if err == nil && len(info.Name()) >= 5 && info.Name()[len(info.Name())-4:] == ".rep" {
				r := path
				replays[r] = struct{}{}
			}
			return nil
		})
		if e != nil {
			log.Fatal(e)
		}
	}

	// Main loop parsing replays
	// TODO break if there are no Analyzers at the beginning or after an iteration
	for replay := range replays {
		analyzerInstances := make(map[string]analyzer.Analyzer, len(analyzers))
		for n, a := range analyzers {
			analyzerInstances[n] = a
		}

		r, err := repparser.ParseFile(replay)
		if err != nil {
			log.Printf("Failed to parse replay: %v\n", err)
			continue
		}
		tryCompute(r)

		var results = map[string]string{}
		for name, a := range analyzerInstances {
			err, done := a.StartReadingReplay(r, ctx, replay)
			if err != nil {
				log.Printf("Error beginning to read replay %v with Analyzer %v: %v\n", replay, a.Name(), err)
			}
			if done {
				results[name], _ = a.IsDone()
			}
			if done || err != nil {
				delete(analyzerInstances, name)
			}
		}
		for _, c := range r.Commands.Cmds { // N.B. This is the expensive loop in the algorithm; optimize here!
			if len(analyzerInstances) == 0 {
				break // Optimization: don't loop over commands if there's nothing to do!
			}
			for name, a := range analyzerInstances {
				err, done := a.ProcessCommand(c)
				if err != nil {
					log.Printf("Error reading command on replay %v with Analyzer %v: %v\n", replay, a.Name(), err)
				}
				if done {
					results[name], _ = a.IsDone()
				}
				if done || err != nil { // Optimization: delete Analyzers that finished or errored out
					delete(analyzerInstances, name)
				}
			}
		}

		// Decides if this replay should be output based on filter flags
		shouldShowBasedOnFilterNots := true
		for filterNot := range filterNots {
			if res, ok := results[filterNot]; ok && res == "true" {
				shouldShowBasedOnFilterNots = false
			}
		}
		shouldShowBasedOnFilters := true
		for filter := range filters {
			if res, ok := results[filter]; !ok || res != "true" {
				shouldShowBasedOnFilters = false
			}
		}

		// Outputs a line of result (i.e. results for one replay)
		if shouldShowBasedOnFilterNots && shouldShowBasedOnFilters {
			if shouldCopyToOutputLocation {
				err := copyFile(replay, fmt.Sprintf("%v/%v", *fCopyToIfMatchesFilters, filepath.Base(replay)))
				if err != nil {
					log.Printf("Error copying replay with path %v to %v: %v\n", replay, *fCopyToIfMatchesFilters, err)
				}
			}
			if *fJSON {
				if !firstJSONRow {
					fmt.Println(",")
				}
				firstJSONRow = false
				row := map[string]string{}
				for _, field := range fieldNames {
					row[field] = results[field]
				}
				bs, _ := json.Marshal(row)
				fmt.Printf("%s", bs)
			} else {
				csvRow := make([]string, 0, len(fieldNames))
				for _, field := range fieldNames {
					csvRow = append(csvRow, results[field])
				}
				w.Write(csvRow)
			}
		}
	}
	w.Flush()
	if err := w.Error(); err != nil {
		log.Fatal(err)
	}

	if *fJSON {
		fmt.Println("\n]")
	}
}

func tryCompute(r *rep.Replay) {
	defer func() {
		if r := recover(); r != nil {
			log.Printf("Recovered panic: %v", r)
		}
	}()
	r.Compute()
}

func unmarshalArguments(s string) []string {
	ss := []string{}
	for _, _si := range strings.Split(s, ",") {
		si := strings.TrimSpace(_si)
		if si != "" {
			ss = append(ss, si)
		}
	}
	return ss
}

// CopyFile copies a file from src to dst. If src and dst files exist, and are
// the same, then return success. Otherise, attempt to create a hard link
// between the two files. If that fail, copy the file contents from src to dst.
func copyFile(src, dst string) (err error) {
	sfi, err := os.Stat(src)
	if err != nil {
		return
	}
	if !sfi.Mode().IsRegular() {
		// cannot copy non-regular files (e.g., directories,
		// symlinks, devices, etc.)
		return fmt.Errorf("CopyFile: non-regular source file %s (%q)", sfi.Name(), sfi.Mode().String())
	}
	dfi, err := os.Stat(dst)
	if err != nil {
		if !os.IsNotExist(err) {
			return
		}
	} else {
		if !(dfi.Mode().IsRegular()) {
			return fmt.Errorf("CopyFile: non-regular destination file %s (%q)", dfi.Name(), dfi.Mode().String())
		}
		if os.SameFile(sfi, dfi) {
			return
		}
	}
	err = copyFileContents(src, dst)
	return
}

// https://stackoverflow.com/questions/21060945/simple-way-to-copy-a-file-in-golang
// copyFileContents copies the contents of the file named src to the file named
// by dst. The file will be created if it does not already exist. If the
// destination file exists, all it's contents will be replaced by the contents
// of the source file.
func copyFileContents(src, dst string) (err error) {
	in, err := os.Open(src)
	if err != nil {
		return
	}
	defer in.Close()
	out, err := os.Create(dst)
	if err != nil {
		return
	}
	defer func() {
		cerr := out.Close()
		if err == nil {
			err = cerr
		}
	}()
	if _, err = io.Copy(out, in); err != nil {
		return
	}
	err = out.Sync()
	return
}

// https://stackoverflow.com/questions/10510691/how-to-check-whether-a-file-or-directory-exists
// exists returns whether the given file or directory exists
func isDirExist(path string) (bool, error) {
	_, err := os.Stat(path)
	if err == nil {
		return true, nil
	}
	if os.IsNotExist(err) {
		return false, nil
	}
	return true, err
}
<commit_msg>Fixes bug where filters were added to output fields.<commit_after>package main

import (
	"encoding/csv"
	"encoding/json"
	"flag"
	"fmt"
	"io"
	"log"
	"os"
	"path/filepath"
	"sort"
	"strings"

	"github.com/icza/screp/rep"
	"github.com/icza/screp/repparser"
	"github.com/marianogappa/raszagal/analyzer"
)

func main() {
	var (
		_analyzers = map[string]analyzer.Analyzer{
			(&analyzer.MyAPM{}).Name():                      &analyzer.MyAPM{},
			(&analyzer.MyRace{}).Name():                     &analyzer.MyRace{},
			(&analyzer.DateTime{}).Name():                   &analyzer.DateTime{},
			(&analyzer.DurationMinutes{}).Name():            &analyzer.DurationMinutes{},
			(&analyzer.MyName{}).Name():                     &analyzer.MyName{},
			(&analyzer.IsThereARace{}).Name():               &analyzer.IsThereARace{},
			(&analyzer.MyRaceIsZerg{}).Name():               &analyzer.MyRaceIsZerg{},
			(&analyzer.MyRaceIsTerran{}).Name():             &analyzer.MyRaceIsTerran{},
			(&analyzer.MyRaceIsProtoss{}).Name():            &analyzer.MyRaceIsProtoss{},
			(&analyzer.ReplayName{}).Name():                 &analyzer.ReplayName{},
			(&analyzer.ReplayPath{}).Name():                 &analyzer.ReplayPath{},
			(&analyzer.MyWin{}).Name():                      &analyzer.MyWin{},
			(&analyzer.MyGame{}).Name():                     &analyzer.MyGame{},
			(&analyzer.MapName{}).Name():                    &analyzer.MapName{},
			(&analyzer.MyFirstSpecificUnitSeconds{}).Name(): &analyzer.MyFirstSpecificUnitSeconds{},
		}
		boolFlags               = map[string]*bool{}
		stringFlags             = map[string]*string{}
		fReplay                 = flag.String("replay", "", "(>= 1 replays required) path to replay file")
		fReplays                = flag.String("replays", "", "(>= 1 replays required) comma-separated paths to replay files")
		fReplayDir              = flag.String("replay-dir", "", "(>= 1 replays required) path to folder with replays (recursive)")
		fMe                     = flag.String("me", "", "comma-separated list of player names to identify as the main player")
		fJSON                   = flag.Bool("json", false, "outputs a JSON instead of the default CSV")
		fCopyToIfMatchesFilters = flag.String("copy-to-if-matches-filters", "",
			"copy replay files matched by -filter-- and not matched by -filter--not-- filters to specified directory")
	)
	for name, a := range _analyzers {
		if a.IsStringFlag() {
			stringFlags[name] = flag.String(name, "", a.Description())
		} else {
			boolFlags[name] = flag.Bool(name, false, a.Description())
		}
		if a.IsBooleanResult() {
			boolFlags["filter--"+name] = flag.Bool("filter--"+name, false, "Filter for: "+a.Description())
			boolFlags["filter-not--"+name] = flag.Bool("filter-not--"+name, false, "Filter-Not for: "+a.Description())
		}
	}
	flag.Parse()
	var (
		analyzers                  = map[string]analyzer.Analyzer{}
		filters                    = map[string]struct{}{}
		filterNots                 = map[string]struct{}{}
		fieldNames                 = []string{} // TODO add filename
		shouldCopyToOutputLocation = true
	)
	if ok, err := isDirExist(*fCopyToIfMatchesFilters); *fCopyToIfMatchesFilters == "" || !ok || err != nil {
		shouldCopyToOutputLocation = false
		if *fCopyToIfMatchesFilters != "" && !ok {
			log.Printf("Output directory doesn't exist: %v\n", *fCopyToIfMatchesFilters)
		}
		if *fCopyToIfMatchesFilters != "" && err != nil {
			log.Printf("Error locating output directory (%v): %v\n", *fCopyToIfMatchesFilters, err)
		}
	}
	for name, f := range boolFlags {
		if *f {
			addToFieldNames := true
			if strings.HasPrefix(name, "filter--") {
				name = name[len("filter--"):] // side-effect so that the analyzer runs
				filters[name] = struct{}{}
				addToFieldNames = false
			} else if strings.HasPrefix(name, "filter-not--") {
				name = name[len("filter-not--"):] // side-effect so that the analyzer runs
				filterNots[name[len("filter-not--"):]] = struct{}{}
				addToFieldNames = false
			}
			analyzers[name] = _analyzers[name]
			if addToFieldNames {
				fieldNames = append(fieldNames, name)
			}
		}
	}
	for name, f := range stringFlags {
		if *f != "" {
			a := _analyzers[name]
			if err := a.SetArguments(unmarshalArguments(*f)); err != nil {
				log.Printf("Invalid arguments '%v' for Analyzer %v: %v", *f, name, err)
				continue
			}
			analyzers[name] = _analyzers[name]
			fieldNames = append(fieldNames, name)
		}
	}

	// TODO implement library for programmatic use
	// Prepares for CSV output
	sort.Strings(fieldNames)
	w := csv.NewWriter(os.Stdout)
	if !*fJSON {
		w.Write(fieldNames)
	}

	// Prepares for JSON output
	firstJSONRow := true
	if *fJSON {
		fmt.Println("[")
	}

	// Prepares AnalyzerContext
	ctx := analyzer.AnalyzerContext{Me: map[string]struct{}{}}
	if fMe != nil && len(*fMe) > 0 {
		for _, name := range strings.Split(*fMe, ",") {
			ctx.Me[strings.TrimSpace(name)] = struct{}{}
		}
	}

	// Parse replay filename flags
	var replays = map[string]struct{}{}
	*fReplay = strings.TrimSpace(*fReplay)
	if len(*fReplay) >= 5 && (*fReplay)[len(*fReplay)-4:] == ".rep" {
		replays[*fReplay] = struct{}{}
	}
	if *fReplays != "" {
		for _, r := range strings.Split(*fReplays, ",") {
			r = strings.TrimSpace(r)
			if len(r) >= 5 && r[len(r)-4:] == ".rep" {
				replays[r] = struct{}{}
			}
		}
	}
	if *fReplayDir != "" {
		e := filepath.Walk(*fReplayDir, func(path string, info os.FileInfo, err error) error {
			if err == nil && len(info.Name()) >= 5 && info.Name()[len(info.Name())-4:] == ".rep" {
				r := path
				replays[r] = struct{}{}
			}
			return nil
		})
		if e != nil {
			log.Fatal(e)
		}
	}

	// Main loop parsing replays
	// TODO break if there are no Analyzers at the beginning or after an iteration
	for replay := range replays {
		analyzerInstances := make(map[string]analyzer.Analyzer, len(analyzers))
		for n, a := range analyzers {
			analyzerInstances[n] = a
		}

		r, err := repparser.ParseFile(replay)
		if err != nil {
			log.Printf("Failed to parse replay: %v\n", err)
			continue
		}
		tryCompute(r)

		var results = map[string]string{}
		for name, a := range analyzerInstances {
			err, done := a.StartReadingReplay(r, ctx, replay)
			if err != nil {
				log.Printf("Error beginning to read replay %v with Analyzer %v: %v\n", replay, a.Name(), err)
			}
			if done {
				results[name], _ = a.IsDone()
			}
			if done || err != nil {
				delete(analyzerInstances, name)
			}
		}
		for _, c := range r.Commands.Cmds { // N.B. This is the expensive loop in the algorithm; optimize here!
			if len(analyzerInstances) == 0 {
				break // Optimization: don't loop over commands if there's nothing to do!
			}
			for name, a := range analyzerInstances {
				err, done := a.ProcessCommand(c)
				if err != nil {
					log.Printf("Error reading command on replay %v with Analyzer %v: %v\n", replay, a.Name(), err)
				}
				if done {
					results[name], _ = a.IsDone()
				}
				if done || err != nil { // Optimization: delete Analyzers that finished or errored out
					delete(analyzerInstances, name)
				}
			}
		}

		// Decides if this replay should be output based on filter flags
		shouldShowBasedOnFilterNots := true
		for filterNot := range filterNots {
			if res, ok := results[filterNot]; ok && res == "true" {
				shouldShowBasedOnFilterNots = false
			}
		}
		shouldShowBasedOnFilters := true
		for filter := range filters {
			if res, ok := results[filter]; !ok || res != "true" {
				shouldShowBasedOnFilters = false
			}
		}

		// Outputs a line of result (i.e. results for one replay)
		if shouldShowBasedOnFilterNots && shouldShowBasedOnFilters {
			if shouldCopyToOutputLocation {
				err := copyFile(replay, fmt.Sprintf("%v/%v", *fCopyToIfMatchesFilters, filepath.Base(replay)))
				if err != nil {
					log.Printf("Error copying replay with path %v to %v: %v\n", replay, *fCopyToIfMatchesFilters, err)
				}
			}
			if *fJSON {
				if !firstJSONRow {
					fmt.Println(",")
				}
				firstJSONRow = false
				row := map[string]string{}
				for _, field := range fieldNames {
					row[field] = results[field]
				}
				bs, _ := json.Marshal(row)
				fmt.Printf("%s", bs)
			} else {
				csvRow := make([]string, 0, len(fieldNames))
				for _, field := range fieldNames {
					csvRow = append(csvRow, results[field])
				}
				w.Write(csvRow)
			}
		}
	}
	w.Flush()
	if err := w.Error(); err != nil {
		log.Fatal(err)
	}

	if *fJSON {
		fmt.Println("\n]")
	}
}

func tryCompute(r *rep.Replay) {
	defer func() {
		if r := recover(); r != nil {
			log.Printf("Recovered panic: %v", r)
		}
	}()
	r.Compute()
}

func unmarshalArguments(s string) []string {
	ss := []string{}
	for _, _si := range strings.Split(s, ",") {
		si := strings.TrimSpace(_si)
		if si != "" {
			ss = append(ss, si)
		}
	}
	return ss
}

// CopyFile copies a file from src to dst. If src and dst files exist, and are
// the same, then return success. Otherise, attempt to create a hard link
// between the two files. If that fail, copy the file contents from src to dst.
func copyFile(src, dst string) (err error) {
	sfi, err := os.Stat(src)
	if err != nil {
		return
	}
	if !sfi.Mode().IsRegular() {
		// cannot copy non-regular files (e.g., directories,
		// symlinks, devices, etc.)
		return fmt.Errorf("CopyFile: non-regular source file %s (%q)", sfi.Name(), sfi.Mode().String())
	}
	dfi, err := os.Stat(dst)
	if err != nil {
		if !os.IsNotExist(err) {
			return
		}
	} else {
		if !(dfi.Mode().IsRegular()) {
			return fmt.Errorf("CopyFile: non-regular destination file %s (%q)", dfi.Name(), dfi.Mode().String())
		}
		if os.SameFile(sfi, dfi) {
			return
		}
	}
	err = copyFileContents(src, dst)
	return
}

// https://stackoverflow.com/questions/21060945/simple-way-to-copy-a-file-in-golang
// copyFileContents copies the contents of the file named src to the file named
// by dst. The file will be created if it does not already exist. If the
// destination file exists, all it's contents will be replaced by the contents
// of the source file.
func copyFileContents(src, dst string) (err error) {
	in, err := os.Open(src)
	if err != nil {
		return
	}
	defer in.Close()
	out, err := os.Create(dst)
	if err != nil {
		return
	}
	defer func() {
		cerr := out.Close()
		if err == nil {
			err = cerr
		}
	}()
	if _, err = io.Copy(out, in); err != nil {
		return
	}
	err = out.Sync()
	return
}

// https://stackoverflow.com/questions/10510691/how-to-check-whether-a-file-or-directory-exists
// exists returns whether the given file or directory exists
func isDirExist(path string) (bool, error) {
	_, err := os.Stat(path)
	if err == nil {
		return true, nil
	}
	if os.IsNotExist(err) {
		return false, nil
	}
	return true, err
}
<|endoftext|>


<commit_before>package main

import (
	"html/template"
	"os"
	"strconv"
	"strings"

	"github.com/Sirupsen/logrus"
	"github.com/kataras/iris"
	"github.com/microcosm-cc/bluemonday"
	"github.com/russross/blackfriday"
)

func init() {
	logLevel := os.Getenv("DEBUG")
	logrus.Infof("Logs: %v", logLevel)
	if logLevel != "" {
		logrus.SetLevel(logrus.DebugLevel)
	}
	badgeMinimum, _ = strconv.Atoi(os.Getenv("BADGE_COUNT"))
	if badgeMinimum == 0 {
		badgeMinimum = 3
	}
}

type Badge struct {
	BadgesHTML template.HTML
	Badge      string
}

func main() {
	iris.Static("/badges", "./badges/", 1)
	iris.Get("/github.com/:username/:reponame", func(ctx *iris.Context) {
		username := ctx.Param("username")
		reponame := ctx.Param("reponame")
		queryString := ctx.URI().QueryArgs()
		branch := string(queryString.Peek("branch"))
		debug := string(queryString.Peek("debug"))

		logrus.Debug("branch: %v - debug: %v", branch, debug)
		badges, err := checkBadges(username, reponame, branch)
		if err != nil {
			ctx.Write(err.Error())
			ctx.SetStatusCode(iris.StatusInternalServerError)
		}
		if debug == "true" {
			htmlBadges := blackfriday.MarkdownBasic([]byte(strings.Join(badges[1:], "\n")))
			htmlBadges = bluemonday.UGCPolicy().SanitizeBytes(htmlBadges)
			if len(htmlBadges) == 0 {
				htmlBadges = []byte("
No badges found in README.md
")
			}

			if err := ctx.Render("index.html", Badge{
				BadgesHTML: template.HTML(string(htmlBadges)),
				Badge:      badges[0],
			}); err != nil {
				logrus.Panic(err)
			}
		} else {
			ctx.ServeFile(badges[0], false)
		}
	})

	logrus.Info("Server listening on :8080")
	iris.Listen(":8080")

}
<commit_msg>Added report as the url to hit to show debugging as well<commit_after>package main

import (
	"html/template"
	"os"
	"strconv"
	"strings"

	"github.com/Sirupsen/logrus"
	"github.com/kataras/iris"
	"github.com/microcosm-cc/bluemonday"
	"github.com/russross/blackfriday"
)

func init() {
	logLevel := os.Getenv("DEBUG")
	logrus.Infof("Logs: %v", logLevel)
	if logLevel != "" {
		logrus.SetLevel(logrus.DebugLevel)
	}
	badgeMinimum, _ = strconv.Atoi(os.Getenv("BADGE_COUNT"))
	if badgeMinimum == 0 {
		badgeMinimum = 3
	}
}

type Badge struct {
	BadgesHTML template.HTML
	Badge      string
}

func main() {
	iris.Static("/badges", "./badges/", 1)
	iris.Get("/github.com/:username/:reponame", handleReport)
	iris.Get("/report/github.com/:username/:reponame", handleReport)
	// logrus.Debug("Server listening on :8080")
	iris.Listen(":8080")
}

func handleReport(ctx *iris.Context) {
	username := ctx.Param("username")
	reponame := ctx.Param("reponame")
	queryString := ctx.URI().QueryArgs()
	branch := string(queryString.Peek("branch"))
	debug := string(queryString.Peek("debug"))
	uri := string(ctx.RequestURI())
	pathSlice := strings.Split(uri, "/")
	if pathSlice[1] == "report" {
		debug = "true"
	}

	logrus.Debug("branch: %v - debug: %v", branch, debug)
	badges, err := checkBadges(username, reponame, branch)
	if err != nil {
		ctx.Write(err.Error())
		ctx.SetStatusCode(iris.StatusInternalServerError)
	}
	if debug == "true" {
		htmlBadges := blackfriday.MarkdownBasic([]byte(strings.Join(badges[1:], "\n")))
		htmlBadges = bluemonday.UGCPolicy().SanitizeBytes(htmlBadges)
		if len(htmlBadges) == 0 {
			htmlBadges = []byte("
No badges found in README.md
")
		}

		if err := ctx.Render("index.html", Badge{
			BadgesHTML: template.HTML(string(htmlBadges)),
			Badge:      badges[0],
		}); err != nil {
			logrus.Panic(err)
		}
	} else {
		ctx.ServeFile(badges[0], false)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"flag"
	"fmt"
	"net/http"
	"os"
	"os/exec"
	"path"
	"strings"
	"sync"
)

var usage = `Usage: %s user backupdir

user       github user name to get the repositories from
backupdir  directory path to save the repositories to`

type Repo struct {
	Name   string
	GitUrl string `json:"git_url"`
}

var batchSize = 10

func main() {
	user, backupDir := parseArgs()

	repos := getRepos(fmt.Sprint("https://api.github.com/users/", user, "/repos"))

	fmt.Println("Backup for user", user, "with", len(repos), "repositories")

	batches := len(repos)/batchSize + 1
	for b := 0; b < batches; b++ {
		batchEnd := (b + 1) * batchSize
		if batchEnd >= len(repos) {
			batchEnd = len(repos)
		}
		batch := repos[b*batchSize : batchEnd]

		func() {
			var wg sync.WaitGroup
			for _, repo := range batch {
				wg.Add(1)
				go func(routineRepo Repo) {
					defer wg.Done()
					updateRepo(backupDir, routineRepo)
				}(repo)
			}
			wg.Wait()
		}()
	}
}

// Get the two positional arguments user and backupdir
func parseArgs() (string, string) {
	flag.Parse()
	args := flag.Args()
	if len(args) != 2 {
		fmt.Fprintf(os.Stderr, usage, os.Args[0])
		os.Exit(1)
	}
	return args[0], args[1]
}

// Get repositories from Github.
// Follow "next" links recursivly.
func getRepos(url string) []Repo {
	r, err := http.Get(url)
	if err != nil {
		panic(err)
	}
	defer r.Body.Close()

	if r.StatusCode >= 300 {
		panic(fmt.Sprint("Request to ", url, "with bad status code ", r.StatusCode))
	}

	var repos []Repo
	json.NewDecoder(r.Body).Decode(&repos)

	firstLink := strings.Split(r.Header["Link"][0], ",")[0]
	if strings.Contains(firstLink, "rel=\"next\"") {
		urlInBrackets := strings.Split(firstLink, ";")[0]
		return append(repos, getRepos(urlInBrackets[1:len(urlInBrackets)-1])...)
	}

	return repos
}

// Clone new repo or pull in existing repo
func updateRepo(backupDir string, repo Repo) {
	repoDir := path.Join(backupDir, repo.Name)

	var cmd *exec.Cmd
	if exists(repoDir) {
		defer fmt.Println("Updated repository:", repo.Name)

		cmd = exec.Command("git", "pull")
		cmd.Dir = repoDir
	} else {
		defer fmt.Println("Cloned  repository:", repo.Name)

		cmd = exec.Command("git", "clone", repo.GitUrl, repoDir)
	}

	err := cmd.Run()
	if err != nil {
		fmt.Fprintln(os.Stderr, err)
	}
}

// Check if a file or directory exists
func exists(path string) bool {
	_, err := os.Stat(path)
	if err != nil {
		if os.IsNotExist(err) {
			return false
		} else {
			panic(err)
		}
	}
	return true
}
<commit_msg>efficient parallelism with workers<commit_after>package main

import (
	"encoding/json"
	"flag"
	"fmt"
	"net/http"
	"os"
	"os/exec"
	"path"
	"strings"
)

var usage = `Usage: %s user backupdir

user       github user name to get the repositories from
backupdir  directory path to save the repositories to`

type Repo struct {
	Name   string
	GitUrl string `json:"git_url"`
}

var batchSize = 10

func main() {
	user, backupDir := parseArgs()

	repos := getRepos(fmt.Sprint("https://api.github.com/users/", user, "/repos"))

	fmt.Println("Backup for user", user, "with", len(repos), "repositories")

	jobs := make(chan Repo)
	for w := 0; w < batchSize; w++ {
		go func() {
			for repo := range jobs {
				updateRepo(backupDir, repo)
			}
		}()
	}
	for _, repo := range repos {
		jobs <- repo
	}
}

// Get the two positional arguments user and backupdir
func parseArgs() (string, string) {
	flag.Parse()
	args := flag.Args()
	if len(args) != 2 {
		fmt.Fprintf(os.Stderr, usage, os.Args[0])
		os.Exit(1)
	}
	return args[0], args[1]
}

// Get repositories from Github.
// Follow "next" links recursivly.
func getRepos(url string) []Repo {
	r, err := http.Get(url)
	if err != nil {
		panic(err)
	}
	defer r.Body.Close()

	if r.StatusCode >= 300 {
		panic(fmt.Sprint("Request to ", url, "with bad status code ", r.StatusCode))
	}

	var repos []Repo
	json.NewDecoder(r.Body).Decode(&repos)

	firstLink := strings.Split(r.Header["Link"][0], ",")[0]
	if strings.Contains(firstLink, "rel=\"next\"") {
		urlInBrackets := strings.Split(firstLink, ";")[0]
		return append(repos, getRepos(urlInBrackets[1:len(urlInBrackets)-1])...)
	}

	return repos
}

// Clone new repo or pull in existing repo
func updateRepo(backupDir string, repo Repo) {
	repoDir := path.Join(backupDir, repo.Name)

	var cmd *exec.Cmd
	if exists(repoDir) {
		defer fmt.Println("Updated repository:", repo.Name)

		cmd = exec.Command("git", "pull")
		cmd.Dir = repoDir
	} else {
		defer fmt.Println("Cloned  repository:", repo.Name)

		cmd = exec.Command("git", "clone", repo.GitUrl, repoDir)
	}

	err := cmd.Run()
	if err != nil {
		fmt.Fprintln(os.Stderr, err)
	}
}

// Check if a file or directory exists
func exists(path string) bool {
	_, err := os.Stat(path)
	if err != nil {
		if os.IsNotExist(err) {
			return false
		} else {
			panic(err)
		}
	}
	return true
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/csv"
	"encoding/json"
	"github.com/ActiveState/tail"
	"github.com/prometheus/client_golang/prometheus"
	"log"
	"net/http"
	"os"
	"strconv"
	"strings"
)

var (
	loadEvents = prometheus.NewCounterVec(
		prometheus.CounterOpts{
			Namespace: "datalogger",
			Name:      "rows_loaded",
			Help:      "the number of rows loaded into the database",
		},
		[]string{"site"},
	)
	batteryVoltage = prometheus.NewGaugeVec(prometheus.GaugeOpts{
		Name: "datalogger_battery_voltage",
		Help: "The current battery voltage",
	},
		[]string{"site"},
	)
)

func init() {
	prometheus.MustRegister(loadEvents)
	prometheus.MustRegister(batteryVoltage)
}

type stringSlice []string

func (slice stringSlice) pos(value string) int {
	for p, v := range slice {
		if v == value {
			return p
		}
	}
	return -1
}

type logger struct {
	FileName           string `json:"file-name"`
	Site               string `json:"site"`
	BatteryVariateName string `json:"battery-variate-name"`
}

func readCSVLine(text string) []string {
	reader := csv.NewReader(strings.NewReader(text))
	fields, err := reader.Read()
	if err != nil {
		log.Fatal(err)
	}
	return fields
}

func loadData(logger logger) {

	t, err := tail.TailFile(logger.FileName, tail.Config{
		Follow: true,
		ReOpen: true,
	})
	if err != nil {
		log.Fatal(err)
	}

	var batteryFieldNumber int

	// Read title and variables and units
	skip := 0
	for line := range t.Lines {
		if strings.Contains(line.Text, "TOA5") {
			skip = 4
		}
		if skip == 3 {
			// decode headers
			fields := readCSVLine(line.Text)
			variates := stringSlice(fields)
			batteryFieldNumber = variates.pos(logger.BatteryVariateName)
		}
		if skip > 0 {
			// skip the rest
			skip = skip - 1
			continue
		}
		// Read data
		fields := readCSVLine(line.Text)
		voltage, err := strconv.ParseFloat(fields[batteryFieldNumber], 64)
		if err != nil {
			log.Fatal(err)
		}
		// log.Println(voltage)
		batteryVoltage.WithLabelValues(logger.Site).Set(voltage)
		loadEvents.WithLabelValues(logger.Site).Inc()
	}
}

func main() {

	dec := json.NewDecoder(os.Stdin)

	var loggers []logger
	if err := dec.Decode(&loggers); err != nil {
		log.Println(err)
		return
	}
	for _, lg := range loggers {
		go loadData(lg)
	}

	http.Handle("/metrics", prometheus.Handler())
	http.ListenAndServe(":9094", nil)

}
<commit_msg>log the site and the voltage to the screen<commit_after>package main

import (
	"encoding/csv"
	"encoding/json"
	"fmt"
	"github.com/ActiveState/tail"
	"github.com/prometheus/client_golang/prometheus"
	"log"
	"net/http"
	"os"
	"strconv"
	"strings"
)

var (
	loadEvents = prometheus.NewCounterVec(
		prometheus.CounterOpts{
			Namespace: "datalogger",
			Name:      "rows_loaded",
			Help:      "the number of rows loaded into the database",
		},
		[]string{"site"},
	)
	batteryVoltage = prometheus.NewGaugeVec(prometheus.GaugeOpts{
		Name: "datalogger_battery_voltage",
		Help: "The current battery voltage",
	},
		[]string{"site"},
	)
)

func init() {
	prometheus.MustRegister(loadEvents)
	prometheus.MustRegister(batteryVoltage)
}

type stringSlice []string

func (slice stringSlice) pos(value string) int {
	for p, v := range slice {
		if v == value {
			return p
		}
	}
	return -1
}

type logger struct {
	FileName           string `json:"file-name"`
	Site               string `json:"site"`
	BatteryVariateName string `json:"battery-variate-name"`
}

func readCSVLine(text string) []string {
	reader := csv.NewReader(strings.NewReader(text))
	fields, err := reader.Read()
	if err != nil {
		log.Fatal(err)
	}
	return fields
}

func loadData(logger logger) {

	t, err := tail.TailFile(logger.FileName, tail.Config{
		Follow: true,
		ReOpen: true,
	})
	if err != nil {
		log.Fatal(err)
	}

	var batteryFieldNumber int

	// Read title and variables and units
	skip := 0
	for line := range t.Lines {
		if strings.Contains(line.Text, "TOA5") {
			skip = 4
		}
		if skip == 3 {
			// decode headers
			fields := readCSVLine(line.Text)
			variates := stringSlice(fields)
			batteryFieldNumber = variates.pos(logger.BatteryVariateName)
		}
		if skip > 0 {
			// skip the rest
			skip = skip - 1
			continue
		}
		// Read data
		fields := readCSVLine(line.Text)
		voltage, err := strconv.ParseFloat(fields[batteryFieldNumber], 64)
		if err != nil {
			log.Fatal(err)
		}
		log.Println(fmt.Sprintf("%v: %v", logger.Site, voltage))
		batteryVoltage.WithLabelValues(logger.Site).Set(voltage)
		loadEvents.WithLabelValues(logger.Site).Inc()
	}
}

func main() {

	dec := json.NewDecoder(os.Stdin)

	var loggers []logger
	if err := dec.Decode(&loggers); err != nil {
		log.Println(err)
		return
	}
	for _, lg := range loggers {
		go loadData(lg)
	}

	http.Handle("/metrics", prometheus.Handler())
	http.ListenAndServe(":9094", nil)

}
<|endoftext|>


<commit_before>package main

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

func serve(kill chan bool) {
	log.Println("Serving...")
	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		w.Header()["content-type"] = []string{"text/plain"}
		fmt.Fprint(w, status())
	})

	http.HandleFunc("/diff/", func(w http.ResponseWriter, r *http.Request) {
		w.Header()["content-type"] = []string{"text/plain"}
		d := diff("develop")
		fmt.Fprint(w, d)
	})

	http.HandleFunc("/kill", func(w http.ResponseWriter, r *http.Request) {
		close(kill)
	})

	http.ListenAndServe(":7777", nil)
}

func git(args ...string) string {
	cmd := exec.Command("git", args...)

	output, err := cmd.CombinedOutput()
	if nil != err {
		return err.Error()
	}

	return string(output)
}

func status() string {
	return git("status")
}

func diff(commit string) string {
	return git("diff", "-M", commit)
}

func main() {
	kill := make(chan bool)

	if len(os.Args) == 1 {
		log.Println("No target...")
	}

	commit := os.Args[1]

	go serve(kill)
	go func() {
		addr := fmt.Sprintf("http://localhost:7777/%s", commit)
		log.Printf(`Opening "%s"`+"\n", addr)
		cmd := exec.Command("xdg-open", addr)
		cmd.Start()
	}()

	for _ = range kill {
	}
	log.Println("Ending...")
}
<commit_msg>Reading files<commit_after>package main

import (
	"fmt"
	// "github.com/sergi/go-diff/diffmatchpatch"
	"log"
	"net/http"
	"os"
	"os/exec"
	"strings"
)

func serve(kill chan bool) {
	log.Println("Serving...")
	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		w.Header()["content-type"] = []string{"text/plain"}
		fmt.Fprint(w, status())
		fmt.Fprintln(w)
		fmt.Fprintln(w, "==================")
		fmt.Fprintln(w, gitReadFile("develop", "README.md"))
	})

	http.HandleFunc("/diff/", func(w http.ResponseWriter, r *http.Request) {
		w.Header()["content-type"] = []string{"text/plain"}
		d := diff("develop")
		fmt.Fprint(w, d)
	})

	http.HandleFunc("/kill", func(w http.ResponseWriter, r *http.Request) {
		close(kill)
	})

	log.Println("Listening...")
	err := http.ListenAndServe(":7777", nil)
	if nil != err {
		log.Fatal(err)
	}
}

func git(args ...string) string {
	cmd := exec.Command("git", args...)

	output, err := cmd.CombinedOutput()
	if nil != err {
		return err.Error()
	}

	return string(output)
}

func status() string {
	return git("status")
}

func diff(commit string) string {
	return git("diff", "-M", commit)
}

func gitCurrentBranch() string {
	branchInfo := git("branch")

	lines := strings.Split(branchInfo, "\n")
	for _, line := range lines {
		if line[0] == '*' {
			return line[2:]
		}
	}
	return ""
}

func gitReadFile(branch, filename string) string {
	if branch == "" {
		branch = gitCurrentBranch()
	}

	return git("show", fmt.Sprintf("%s:%s", branch, filename))
}

func main() {
	log.Println("Starting...")
	kill := make(chan bool)

	if len(os.Args) == 1 {
		log.Println("No target...")
	}

	commit := os.Args[1]

	go serve(kill)
	go func() {
		addr := fmt.Sprintf("http://localhost:7777/diff/%s", commit)
		log.Printf(`Opening "%s"`+"\n", addr)
		cmd := exec.Command("xdg-open", addr)
		cmd.Start()
	}()

	for _ = range kill {
	}
	log.Println("Ending...")
}
<|endoftext|>


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

package main

import (
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"os/signal"
	"runtime/pprof"
	"syscall"
	"time"

	"golang.org/x/net/context"
	"golang.org/x/oauth2"
	"golang.org/x/oauth2/google"

	"github.com/jacobsa/fuse"
	"github.com/jacobsa/gcloud/gcs"
	"github.com/jacobsa/syncutil"
	"github.com/jgeewax/cli"
)

////////////////////////////////////////////////////////////////////////
// Helpers
////////////////////////////////////////////////////////////////////////

func registerSIGINTHandler(mountPoint string) {
	// Register for SIGINT.
	signalChan := make(chan os.Signal, 1)
	signal.Notify(signalChan, os.Interrupt)

	// Start a goroutine that will unmount when the signal is received.
	go func() {
		for {
			<-signalChan
			log.Println("Received SIGINT, attempting to unmount...")

			err := fuse.Unmount(mountPoint)
			if err != nil {
				log.Printf("Failed to unmount in response to SIGINT: %v", err)
			} else {
				log.Printf("Successfully unmounted in response to SIGINT.")
				return
			}
		}
	}()
}

// Dump profiles on SIGHUP, if enabled.
func registerSIGHUPHandler(cpu bool, mem bool) {
	var desc string
	switch {
	case cpu && mem:
		desc = "CPU and memory profiles"

	case cpu:
		desc = "CPU profile"

	case mem:
		desc = "memory profile"

	default:
		return
	}

	const duration = 10 * time.Second
	profileOnce := func() (err error) {
		// CPU
		if cpu {
			var f *os.File
			f, err = os.Create("/tmp/cpu.pprof")
			if err != nil {
				err = fmt.Errorf("Create: %v", err)
				return
			}

			defer func() {
				closeErr := f.Close()
				if err == nil {
					err = closeErr
				}
			}()

			pprof.StartCPUProfile(f)
			defer pprof.StopCPUProfile()
		}

		// Memory
		if mem {
			var f *os.File
			f, err = os.Create("/tmp/mem.pprof")
			if err != nil {
				err = fmt.Errorf("Create: %v", err)
				return
			}

			defer func() {
				closeErr := f.Close()
				if err == nil {
					err = closeErr
				}
			}()

			defer func() {
				pprof.Lookup("heap").WriteTo(f, 0)
			}()
		}

		time.Sleep(duration)
		return
	}

	c := make(chan os.Signal, 1)
	signal.Notify(c, syscall.SIGHUP)

	// Wait for SIGHUP in the background.
	go func() {
		for {
			<-c
			log.Printf("Received SIGHUP. Dumping %s to /tmp...", desc)
			if err := profileOnce(); err != nil {
				log.Printf("Error profiling: %v", err)
			} else {
				log.Println("Done profiling.")
			}
		}
	}()
}

// Create token source from the JSON file at the supplide path.
func newTokenSourceFromPath(
	path string,
	scope string) (ts oauth2.TokenSource, err error) {
	// Read the file.
	contents, err := ioutil.ReadFile(path)
	if err != nil {
		err = fmt.Errorf("ReadFile(%q): %v", path, err)
		return
	}

	// Create a config struct based on its contents.
	jwtConfig, err := google.JWTConfigFromJSON(contents, scope)
	if err != nil {
		err = fmt.Errorf("JWTConfigFromJSON: %v", err)
		return
	}

	// Create the token source.
	ts = jwtConfig.TokenSource(context.Background())

	return
}

func getConn(flags *flagStorage) (c gcs.Conn, err error) {
	// Create the oauth2 token source.
	const scope = gcs.Scope_FullControl

	var tokenSrc oauth2.TokenSource
	if flags.KeyFile != "" {
		tokenSrc, err = newTokenSourceFromPath(flags.KeyFile, scope)
		if err != nil {
			err = fmt.Errorf("newTokenSourceFromPath: %v", err)
			return
		}
	} else {
		tokenSrc, err = google.DefaultTokenSource(context.Background(), scope)
		if err != nil {
			err = fmt.Errorf("DefaultTokenSource: %v", err)
			return
		}
	}

	// Create the connection.
	const userAgent = "gcsfuse/0.0"
	cfg := &gcs.ConnConfig{
		TokenSource: tokenSrc,
		UserAgent:   userAgent,
	}

	if flags.DebugHTTP {
		cfg.HTTPDebugLogger = log.New(os.Stderr, "http: ", 0)
	}

	if flags.DebugGCS {
		cfg.GCSDebugLogger = log.New(os.Stderr, "gcs: ", 0)
	}

	return gcs.NewConn(cfg)
}

////////////////////////////////////////////////////////////////////////
// main function
////////////////////////////////////////////////////////////////////////

func main() {
	// Make logging output better.
	log.SetFlags(log.Ldate | log.Ltime | log.Lmicroseconds)

	app := newApp()
	app.Action = func(c *cli.Context) {
		var err error

		// We should get two arguments exactly. Otherwise error out.
		if len(c.Args()) != 2 {
			fmt.Fprintf(
				os.Stderr,
				"Error: %s takes exactly two arguments.\n\n",
				app.Name)
			cli.ShowAppHelp(c)
			os.Exit(1)
		}

		// Populate and parse flags.
		bucketName := c.Args()[0]
		mountPoint := c.Args()[1]
		flags := populateFlags(c)

		// Enable invariant checking if requested.
		if flags.DebugInvariants {
			syncutil.EnableInvariantChecking()
		}

		// Enable profiling if requested.
		registerSIGHUPHandler(flags.DebugCPUProfile, flags.DebugMemProfile)

		// Grab the connection.
		conn, err := getConn(flags)
		if err != nil {
			log.Fatalf("getConn: %v", err)
		}

		// Mount the file system.
		mfs, err := mount(
			context.Background(),
			bucketName,
			mountPoint,
			flags,
			conn)

		if err != nil {
			log.Fatalf("Mounting file system: %v", err)
		}

		log.Println("File system has been successfully mounted.")

		// Let the user unmount with Ctrl-C (SIGINT).
		registerSIGINTHandler(mfs.Dir())

		// Wait for the file system to be unmounted.
		err = mfs.Join(context.Background())
		if err != nil {
			err = fmt.Errorf("MountedFileSystem.Join: %v", err)
			return
		}

		log.Println("Successfully exiting.")
	}

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

package main

import (
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"os/signal"
	"runtime"
	"runtime/pprof"
	"syscall"
	"time"

	"golang.org/x/net/context"
	"golang.org/x/oauth2"
	"golang.org/x/oauth2/google"

	"github.com/jacobsa/fuse"
	"github.com/jacobsa/gcloud/gcs"
	"github.com/jacobsa/syncutil"
	"github.com/jgeewax/cli"
)

////////////////////////////////////////////////////////////////////////
// Helpers
////////////////////////////////////////////////////////////////////////

func registerSIGINTHandler(mountPoint string) {
	// Register for SIGINT.
	signalChan := make(chan os.Signal, 1)
	signal.Notify(signalChan, os.Interrupt)

	// Start a goroutine that will unmount when the signal is received.
	go func() {
		for {
			<-signalChan
			log.Println("Received SIGINT, attempting to unmount...")

			err := fuse.Unmount(mountPoint)
			if err != nil {
				log.Printf("Failed to unmount in response to SIGINT: %v", err)
			} else {
				log.Printf("Successfully unmounted in response to SIGINT.")
				return
			}
		}
	}()
}

func handleCPUProfileSignals() {
	profileOnce := func(duration time.Duration, path string) (err error) {
		// Set up the file.
		var f *os.File
		f, err = os.Create(path)
		if err != nil {
			err = fmt.Errorf("Create: %v", err)
			return
		}

		defer func() {
			closeErr := f.Close()
			if err == nil {
				err = closeErr
			}
		}()

		// Profile.
		pprof.StartCPUProfile(f)
		time.Sleep(duration)
		pprof.StopCPUProfile()
		return
	}

	c := make(chan os.Signal, 1)
	signal.Notify(c, syscall.SIGUSR1)
	for range c {
		const path = "/tmp/cpu.pprof"
		const duration = 10 * time.Second

		log.Printf("Writing %v CPU profile to %s...", duration, path)

		err := profileOnce(duration, path)
		if err == nil {
			log.Printf("Done writing CPU profile to %s.", path)
		} else {
			log.Printf("Error writing CPU profile: %v", err)
		}
	}
}

func handleMemoryProfileSignals() {
	profileOnce := func(path string) (err error) {
		// Trigger a garbage collection to get up to date information (cf.
		// https://goo.gl/aXVQfL).
		runtime.GC()

		// Open the file.
		var f *os.File
		f, err = os.Create(path)
		if err != nil {
			err = fmt.Errorf("Create: %v", err)
			return
		}

		defer func() {
			closeErr := f.Close()
			if err == nil {
				err = closeErr
			}
		}()

		// Dump to the file.
		err = pprof.Lookup("heap").WriteTo(f, 0)
		if err != nil {
			err = fmt.Errorf("WriteTo: %v", err)
			return
		}

		return
	}

	c := make(chan os.Signal, 1)
	signal.Notify(c, syscall.SIGUSR2)
	for range c {
		const path = "/tmp/mem.pprof"

		err := profileOnce(path)
		if err == nil {
			log.Printf("Wrote memory profile to %s.", path)
		} else {
			log.Printf("Error writing memory profile: %v", err)
		}
	}
}

// Create token source from the JSON file at the supplide path.
func newTokenSourceFromPath(
	path string,
	scope string) (ts oauth2.TokenSource, err error) {
	// Read the file.
	contents, err := ioutil.ReadFile(path)
	if err != nil {
		err = fmt.Errorf("ReadFile(%q): %v", path, err)
		return
	}

	// Create a config struct based on its contents.
	jwtConfig, err := google.JWTConfigFromJSON(contents, scope)
	if err != nil {
		err = fmt.Errorf("JWTConfigFromJSON: %v", err)
		return
	}

	// Create the token source.
	ts = jwtConfig.TokenSource(context.Background())

	return
}

func getConn(flags *flagStorage) (c gcs.Conn, err error) {
	// Create the oauth2 token source.
	const scope = gcs.Scope_FullControl

	var tokenSrc oauth2.TokenSource
	if flags.KeyFile != "" {
		tokenSrc, err = newTokenSourceFromPath(flags.KeyFile, scope)
		if err != nil {
			err = fmt.Errorf("newTokenSourceFromPath: %v", err)
			return
		}
	} else {
		tokenSrc, err = google.DefaultTokenSource(context.Background(), scope)
		if err != nil {
			err = fmt.Errorf("DefaultTokenSource: %v", err)
			return
		}
	}

	// Create the connection.
	const userAgent = "gcsfuse/0.0"
	cfg := &gcs.ConnConfig{
		TokenSource: tokenSrc,
		UserAgent:   userAgent,
	}

	if flags.DebugHTTP {
		cfg.HTTPDebugLogger = log.New(os.Stderr, "http: ", 0)
	}

	if flags.DebugGCS {
		cfg.GCSDebugLogger = log.New(os.Stderr, "gcs: ", 0)
	}

	return gcs.NewConn(cfg)
}

////////////////////////////////////////////////////////////////////////
// main function
////////////////////////////////////////////////////////////////////////

func main() {
	// Make logging output better.
	log.SetFlags(log.Ldate | log.Ltime | log.Lmicroseconds)

	// Set up profiling handlers.
	go handleCPUProfileSignals()
	go handleMemoryProfileSignals()

	app := newApp()
	app.Action = func(c *cli.Context) {
		var err error

		// We should get two arguments exactly. Otherwise error out.
		if len(c.Args()) != 2 {
			fmt.Fprintf(
				os.Stderr,
				"Error: %s takes exactly two arguments.\n\n",
				app.Name)
			cli.ShowAppHelp(c)
			os.Exit(1)
		}

		// Populate and parse flags.
		bucketName := c.Args()[0]
		mountPoint := c.Args()[1]
		flags := populateFlags(c)

		// Enable invariant checking if requested.
		if flags.DebugInvariants {
			syncutil.EnableInvariantChecking()
		}

		// Grab the connection.
		conn, err := getConn(flags)
		if err != nil {
			log.Fatalf("getConn: %v", err)
		}

		// Mount the file system.
		mfs, err := mount(
			context.Background(),
			bucketName,
			mountPoint,
			flags,
			conn)

		if err != nil {
			log.Fatalf("Mounting file system: %v", err)
		}

		log.Println("File system has been successfully mounted.")

		// Let the user unmount with Ctrl-C (SIGINT).
		registerSIGINTHandler(mfs.Dir())

		// Wait for the file system to be unmounted.
		err = mfs.Join(context.Background())
		if err != nil {
			err = fmt.Errorf("MountedFileSystem.Join: %v", err)
			return
		}

		log.Println("Successfully exiting.")
	}

	err := app.Run(os.Args)
	if err != nil {
		log.Fatalln(err)
	}
}
<|endoftext|>